Skip to content

Cart drawer: the cart slides in as a modal dialog with a close button, an overlay and growing textareas; drawer-core.mjs with node tests (#140) - #149

Merged
Arthurvdv merged 5 commits into
mainfrom
wp16/drawer
Oct 28, 2026
Merged

Arthurvdv merged 5 commits into
mainfrom
wp16/drawer

Conversation

@Arthurvdv

Copy link
Copy Markdown
Member

Closes #140

The cart becomes an off-canvas drawer: partials/cart.html is a modal dialog (role="dialog", aria-modal, labelled by its heading) with a close button and one overlay, both hidden until cart.mjs opens them.

  • Open and close: it opens on an added change (a popover choice or a Release button) and on the Cart button. The close button, Escape, the overlay and the Cart button close it. Focus moves to the close button on open and back to the Cart button on close, and Tab wraps inside. While open, <body> has the class is-open (the body data attributes are unchanged) and the page behind does not scroll. The overlay leaves the header reachable by mouse on purpose: the Cart button toggles the drawer, and aria-modal and the Tab trap still hold.
  • Escape order: Escape is read in the capture phase. While a cell's popover or the menu below 768 px is open, Escape closes that first and the drawer stays open.
  • Focus edge cases: a list redraw (Remove, an axis checkbox) puts the focus back on the close button. When Clear on a page without cells hides the Cart button, closing moves the focus to main#content.
  • drawer-core.mjs: a new pure module with the state machine (transition for add, badge, close, escape and overlay, plus the focus target) and the Tab wrap (tabTarget). tests/site/drawer-core.test.mjs covers it. cart-core.mjs is untouched.
  • Textareas: the justification and the note grow with their content (field-sizing: content, with a script fallback that also runs on resize). Typing updates the cart and the byte count without redrawing the list. A multi-line justification arrives in the issue unchanged (\n in the JSON, %0A in the note), and a new cart-core case checks the URL and the byte count.
  • Layout: 24 rem wide below the header, full width below 768 px. Closed, it takes no room. A new --scrim token colours the overlay.
  • Published assets: js/drawer-core.mjs is published next to js/cart-core.mjs, without a script tag. It is added to the Site suite, the Hugo stub, the CI publish-action check, the Publish.Action staged count (669) and the template counts (97 files, 31 in site/).
  • Docs: docs/dashboard.md (the cart drawer in the shell section), template/docs/dashboard.md sections 3 and 5, docs/reference/testing.md, CONTRIBUTING.md, and the release notes.

Tests: Pester Rulebook.Site 55, Rulebook.Deploy 76, Publish.Action 52, Rulebook.Template 77 and Docs 340, all passed, with the real-Hugo case run. node --test tests/site/*.test.mjs passed 35 of 35. A throwaway Playwright run against the fixture build passed 36 of 36 checks: open and close paths, focus, the Tab trap, textarea growth with and without field-sizing, multi-line text in the issue URL, the byte meter, the Escape order, full width at 390 px, both colour modes, no JavaScript, no outside requests and no page errors. A review pass checked focus after Remove and after an axis checkbox, Escape with the menu open, and focus after Clear on a level page. The screenshots and the deviations are on #140.

Review: Sonnet round 1 found no must-fix. S1 to S4 and the nits are applied, except scrollbar-gutter: stable. With classic scrollbars it left a 15 px empty strip beside the drawer and the header, so the scrollbar shift stays (it happens under the overlay).

🤖 Generated with Claude Code

Arthurvdv and others added 5 commits October 28, 2026 21:44
…wer, with its node suite (#140)

Pure functions, no DOM: transition(state, event) for add, badge, close, escape and overlay gives
the next open state and the focus target (the close button on open, the Cart button on close,
none when nothing changes); tabTarget wraps Tab and Shift+Tab inside the drawer. The cart suite
gains a case for a multi-line justification and note: they arrive in the issue URL unchanged and
the byte count includes every line end.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ose button, an overlay and growing textareas (#140)

cart.html is the dialog (role dialog, aria-modal, labelled by its heading, a close button at the
top right) with one overlay behind it, both hidden until cart.mjs opens them: on an added change
and on the Cart button; the close button, Escape and the overlay close it. The focus moves to the
close button on open and back to the Cart button on close, Tab wraps inside, and body gets the
is-open class (the page behind does not scroll). Escape while a cell's popover is open closes the
popover first. The justification and the note are textareas that grow (field-sizing, with a
script fallback); typing updates the cart and the size without drawing the list again. The
drawer is 24rem wide below the header and the full width below 768 px; closed it takes no room.
drawer-core.mjs is published next to cart-core.mjs without a script tag.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e real build, the template counts (#140)

The Site suite, the Hugo stand-in and the CI publish-action check list js/drawer-core.mjs; the
real-Hugo case asserts the dialog, the close button, the overlay, the note textarea, one module
script tag and the 24rem width and field-sizing in site.css. The staged file count of the Publish
action suite becomes 669, and template/ has 97 files with 31 in site/ (template-content.md,
README.md, CONTRIBUTING.md).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…xtareas and drawer-core.mjs (#140)

docs/dashboard.md: the site tree and the fixed asset paths gain drawer-core.mjs, the shell gets a
"Cart drawer" part (markup, open and close, focus and Tab, Escape order with the popover,
is-open, width and overlay, textareas, line ends in the issue URL), --scrim joins the tokens and
the Cart row of the views table says drawer. The user page, section 3, describes the drawer and
the multi-line fields; section 5 lists --scrim and the overlay among what the cart needs.
CONTRIBUTING names drawer-core.test.mjs; the release notes line under v1.0.0-beta.8.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he menu, focus to main when the Cart button is hidden (#140)

cart.mjs: a list drawn again (Remove, an axis checkbox) that took the focused element puts the
focus on the close button; Escape with the menu below 768 px open (or during an input method
composition) is left to it, like the popover; closing after Clear hid the Cart button on a page
without cells focuses main#content; the textarea fallback grows again on resize. site.css: print
lets an open drawer's page scroll. The Site test asserts the drawer's width, top and
field-sizing one by one; the cart-core comment says the CRLF note is synthetic input;
testing.md names drawer-core.test.mjs; CONTRIBUTING says six assets; docs/dashboard.md the new
focus and Escape cases.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WP16: the cart as an off-canvas drawer with multi-line justification and note

1 participant