Skip to content

fix(ui): deep-review round over the plan-reminder sheet - #2007

Merged
jackwener merged 3 commits into
mainfrom
fix/plan-form-deep-review
Aug 3, 2026
Merged

fix(ui): deep-review round over the plan-reminder sheet#2007
jackwener merged 3 commits into
mainfrom
fix/plan-form-deep-review

Conversation

@jackwener

Copy link
Copy Markdown
Member

Adversarial deep review of #2002/#2004 (independent correctness + design lenses; every finding verified against sources before fixing).

Confirmed regressions, fixed

  • Autofocus was silently broken: raw autoFocus fires at React commit — beforeshowModal() makes the dialog visible — so focus actually landed on the first button (template menu / X). The title input now wears data-autofocus, the hook Astryx Dialog queries after opening. (This is also exactly what plan-reminders.spec.ts asserts.)
  • Title a11y wiring restored: the raw input inside Field now carries aria-required / aria-invalid / aria-describedby → Field's generated status id, and Field gets isRequired back — screen readers hear the validation again (FieldStatus deliberately has no live region; it relies on describedby).
  • Dark-mode backdrop inversion: the scrim derived from --foreground (near-white in dark mode → a whitening veil). Now derives from --background, and the sheet gains a hairline inline-start border (ring before shadow, per dark-restraint).
  • Clipped content: the form's overflow:auto was a no-op inside LayoutContent's overflow:clip — tall variants (cron + bot delivery) clipped Chat ID and Create unreachably. LayoutContent isScrollable is the single scroll region now, between pinned header/footer Layout slots.

Design completions

  • 时间 row: hand-typed YYYY-MM-DDTHH:mmAstryx DateTimeInput (compact, 24h, 5-min step, full-row width); sheet widens 440 → 480 so date+time fit min-content with clean insets.
  • Inset group cards gain a real fill (--muted) — border-on-same-surface read as an outline, not an inset.
  • Borderless title gets a :focus-visible ring (it was the only chrome-free control with no focus cue); placeholder moves to the platform text-secondary token (hand mix was <4.5:1).
  • Group labels step up to the label type role (kicker/label now two distinct tiers); presets role="group"; the sheet slides in from the right (Astryx's center scale-pop detached a 100dvh element from three edges mid-animation).
  • Dead copy keys pruned (eyebrow, cancel, field.delivery, templatesAriaLabel); two classNames that landed on the menu popover instead of the trigger removed.

Verification

typecheck ✅ · check-dead-css ✅ · check-a11y/copy/console ✅ · plan-reminder unit tests 9/9 ✅ · Storybook smoke 74 renders × 3 viewports ✅ · re-rendered screenshot of the open sheet posted in the work thread

Adversarial review of #2002/#2004 (correctness + design lenses, every
finding verified before fixing).
Confirmed regressions, fixed:
- Autofocus was broken: raw `autoFocus` fires at React commit, before
showModal() makes the dialog visible, so focus silently landed on
the first button. The title input now wears `data-autofocus`, the
hook Astryx Dialog actually queries after opening (this is also
what the plan-reminders e2e asserts).
- The raw title input carried none of the a11y wiring TextInput used
to provide — aria-required / aria-invalid / aria-describedby now
point at Field's generated status id, and Field gets isRequired
back, so the validation message is announced again.
- The `::backdrop` override derived its color from --foreground,
which inverts in dark mode (a whitening veil over a dark UI). It
derives from --background now — light wash over light, dark scrim
over dark — and the sheet gains a hairline inline-start border so
dark mode separates by ring before shadow.
- The form's own `overflow: auto` was a no-op inside LayoutContent's
`overflow: clip`; tall variants (cron + bot delivery) clipped the
Chat ID row and Create with no way to scroll. LayoutContent is the
single scroll region now (isScrollable), between the pinned
header and footer Layout slots.
Design-review completions:
- 时间 row: hand-typed `YYYY-MM-DDTHH:mm` TextInput → Astryx
DateTimeInput (compact, 24h, 5-min stepping, full-row width); the
sheet widens 440 → 480 so the date+time pair fits its min-content
with proper insets.
- The inset group cards gain a real fill (--muted) — a border on the
same surface color read as a bare outlined rectangle, not an inset.
- The borderless title gets a :focus-visible ring (it was the one
control with no focus indicator); its placeholder moves to the
platform text-secondary token (the hand mix was below 4.5:1).
- Group labels step up to the label type role so the kicker/label
ladder reads as two tiers; presets keep role="group"; the sheet
slides in from the right (Astryx's center scale-pop detached a
100dvh element from three window edges mid-animation).
- Dead copy keys pruned (eyebrow, cancel, field.delivery,
templatesAriaLabel); two classNames that landed on the menu popover
instead of the trigger removed.
Verified: build, typecheck, check-dead-css, check-a11y/copy/console,
plan-reminder unit tests (9/9), Storybook smoke (74 renders x 3
viewports), rendered screenshot of the open sheet re-checked.
WAWQAQ round 3: the sheet was pinned to the WINDOW edge while the page
content is width-clamped, leaving a dead band between the list and the
form — the reference has none: its create panel sits flush against the
list pane, one divider between, non-modal.
- The form drops the <dialog> overlay entirely. It is an in-page
<aside> now: when open, .maka-plan-panel becomes a two-column grid
(list keeps flowing in column one; the panel takes
minmax(380px, 460px) flush right) with a single hairline seam.
Non-modal role="dialog" + aria-labelledby keeps the accessible name
the e2e locates; Escape closes through the same guarded path via an
onKeyDown at the panel root; the title autofocuses from a mount
effect (the component still remounts per form session).
- The aside is position: sticky with its own pinned header/footer and
the form as the single scroll region between them, so the list can
scroll independently — matching the reference's split behavior.
- The sheet-era CSS (window-pinned dialog, custom ::backdrop) is
retired; the slide-in animation survives on the aside.
Verified: build, typecheck, check-dead-css, check-a11y/copy/console,
plan-reminder unit tests 9/9, Storybook smoke (74 renders x 3
viewports), rendered screenshot re-checked against the reference.
@jackwener
jackwenerforce-pushed the fix/plan-form-deep-review branch from fd637b6 to ebc63c3CompareAugust 3, 2026 12:12
The Astryx Dialog used to capture the focused element at open and
restore it on close; the split-view aside dropped that contract, so
Escape from the edit panel left focus on <body> — caught by the e2e
that expects the row's menu trigger to regain focus. The open effect
now captures the opener (the panel has already re-focused the
triggering row control by then) and its cleanup hands focus back when
the panel closes. Verified locally: both plan-reminders e2e tests pass.
@jackwener
jackwener merged commit cce0aaf into mainAug 3, 2026
9 checks passed
Sign up for freeto 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.

1 participant

@jackwener