mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-04 12:31:45 +00:00
7f640a9c40
The arm itself, plus the render seam and the browser proof. `renderMarkdownDocument` is a third thin wrapper in FRONT of the shared `marked` pipeline, following `renderMarkedWithAttachments`'s precedent rather than standing up a second renderer. It omits two things deliberately. No wiki-link resolution: an attached `.md` was authored elsewhere, so resolving its `[[brackets]]` against whatever workspace is showing it would silently retarget a foreign document's links at local items — BUG-2830's hazard entered through the front door. No attachment context, and it CLEARS the module-level context for the duration rather than merely leaving it alone: a nested call from a resolver or a `missing` hook that itself renders markdown would otherwise inherit the outer document's workspace and resolver. Save, clear, restore, mirroring the sibling wrapper. Sanitization is inherited, not re-derived, so an attached document is governed by the same allowlist as item content. Plain text does NOT go through the pipeline. A `.txt` renders in a `<pre>` as text, because interpreting a plain-text file's asterisks as formatting would misrepresent its content; Svelte escapes it, so that path emits no HTML at all. THE FALLBACK ARM'S CONDITION CHANGED, and this is the part to check hardest. It read `shownRenderer !== 'raster-image'`, which was correct while the union had one member and would have drawn "No preview available" over every text document the moment it had two. It is now `=== null` — the registry's actual "no renderer claims this" answer — which says what it means and stays correct when 'pdf' lands. INTERACTION, all of it found by review or re-reading rather than by the unit suite: - The wheel handler consumed every wheel before its exclusions, so the card could never scroll. The text exclusion returns BEFORE `preventDefault`, the opposite of every other exclusion there: the others want the wheel swallowed, this one wants it delivered. Scroll chaining to the inert page is stopped by `overscroll-behavior: contain`, so the guarantee the `preventDefault` provided is kept. - The full-bleed layer took `pointer-events: auto`, so a click on the empty area targeted it and backdrop-close was broken for this arm alone. The layer is inert; the CARD is the interactive surface. - `touch-action` INTERSECTS down the ancestor chain, so the card's `pan-y` could never override the stage's `none` and a phone could not scroll at all. The stage gives up its pan claim on this arm only. - The card had no tab stop. The viewer's arrow keys are its own next/previous navigation, so a keyboard-only user could open a document and never reach past its first screen. `tabindex="0"` plus `role="document"` and the filename label; the linter warning is suppressed narrowly with its reason at the site. - The focus-handoff effect tracked `loader.phase` — the IMAGE loader, which this arm disposes, so it never changes there. This is the only arm whose CONTENT is focusable, so a reload unmounted a focused link and stranded focus outside the modal. - `resolvedSize` and `revalidateToken` ride the load key SCOPED to the text arm. The key is shared, so an unconditional append re-ran the effect for the raster arm too and restarted image loads. The token is there because a parent RESTORE drives the image loader through the metadata probe's answer but cannot see a failed text GET's `error` phase — without it, a preview that 404'd while archived stayed permanently errored after the restore that fixed it. E2E, because three of these guarantees are CSS mechanisms and the jsdom suite injects no component styles — `getComputedStyle` there returns the engine default for every element, so two assertions written for them could not fail and were deleted rather than banked as coverage. `web/e2e/attachment-text-preview.spec.ts` covers the render, backdrop close, scrolling with no leak to the surface behind, and selection. Its FIRST RUN is what caught the feature rendering raw source, which the whole green unit suite could not see. CONVE-23 sweep on the prose this falsified: the ADMISSION vs THE ARM block enumerated 'raster-image loads bytes / null is no-bytes' as a two-way split, and the fallback arm described itself as "an entry the viewer cannot draw as an image". Both rewritten, plus a paragraph on why two byte-loading arms leave the no-bytes invariant unchanged in kind. `.pad-e2e-*/` is gitignored: a shared checkout runs concurrent suites, so each seat points `PAD_E2E_DATA_DIR` at its own, and those hold a generated encryption key and a multi-MB WAL. `item-attachment-strip.spec.ts` changes here because it is a CONSEQUENCE of this arm, not a separate concern. Two of its tests uploaded a `text/plain` file and asserted the viewer showed "No preview available" over it — true when written, false by design once text previews. CI caught them; my sweep had not, because I swept the unit tests and stated that boundary nowhere, which reads identically to a complete sweep (CONVE-18's amended half). The fix keeps each test's SUBJECT — both are producer→host wiring tests whose named subject is the fallback arm — and moves the vehicle to PDF, which keeps every property the fixture was chosen for while remaining unclaimed by any renderer. It carries a note saying it will go red again when PLAN-2393 builds the `'pdf'` slot, and that the red is the design: pick the next unclaimed type, never weaken the assertion. Closes #1169