Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d88563a
spec(family): action groups — press, slide, act on lift, one tracker …
cixzhang Oct 26, 2026
99d6101
spec(family): SegmentedControl is a named exception to action groups
cixzhang Oct 26, 2026
3369b14
spec(family): composed footers (Dialog, Card) get the behavior throug…
cixzhang Oct 26, 2026
f4f87d2
spec(family): any LayoutFooter composes ButtonGroup
cixzhang Oct 26, 2026
5d22a75
spec(AST-094, family): action groups stay on for a fine pointer with …
cixzhang Oct 26, 2026
fda4afb
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
0fb1d04
spec(family, AST-094): FR11 lets action-group controls act at the lif…
cixzhang Oct 27, 2026
271b8b1
spec(family, AST-094): rules stated as behavior; the tracker moves to…
cixzhang Oct 27, 2026
d4e8584
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
357ba25
spec(family, AST-094, interaction-modality): menus keep useMenuPress …
cixzhang Oct 27, 2026
9dfa484
spec(interaction-modality): menus' move onto the shared tracker is pl…
cixzhang Oct 27, 2026
79348c6
Merge main (AST-094 FR19 scroll-edge exception) into spec/ast094-acti…
cixzhang Oct 27, 2026
e97a190
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
e6a49f8
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
b411834
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
5c36360
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
ed9c179
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
deadc3f
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
e53d883
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
0fa4547
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
453f1d5
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
9e3a910
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
4e0bc32
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
bf52725
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
108ec60
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
f45888a
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
9be54dd
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
8548bcc
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
f5c492b
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
a4a07c3
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
af4a2a7
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
1e17099
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
4bb380d
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
2ebd152
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
2b9a08a
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
fe7bf01
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
514dd56
Merge remote-tracking branch 'origin/main' into spec/ast094-action-gr…
cixzhang Oct 27, 2026
63b7b09
Merge main into spec/ast094-action-groups
cixzhang Oct 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions docs/architecture/interaction-modality.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ verified_by:
packages/core/src/Selector/Selector.test.tsx,
packages/core/src/Slider/Slider.test.tsx,
]
deciding_specs: [spec:AST-100/DEC-1]
deciding_specs: [spec:AST-100/DEC-1, spec:AST-094/DEC-17]
---

# Interaction modality architecture
Expand Down Expand Up @@ -188,6 +188,17 @@ work.
path, through the animator or a CSS custom property alike. Scroll snapping and momentum stay native. It adds no
module and is internal (`spec:AST-017` FR21).

- **INV13 — Press tracking across a group has one owner.** In

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This record still says it "owns only the cross-cutting modality-path, no-stale-interaction-outcome, and gesture-velocity-source requirements" (lines 237–238) and "Otherwise no separate specification changes this record" (line 245), deciding_specs lists only spec:AST-100/DEC-1, and AST-094's Current-state impact says this record's "invariants are unchanged" (lines 500–501). Suggest adding INV13 to the Owning code sentence (with a line like INV10's), spec:AST-094/DEC-17 to deciding_specs and Deciding specs, and naming INV13 in AST-094's impact line.

`@astryxdesign/core`, one internal module, `actionGroupTracker`, tracks a
held pointer across a group's actions for every `family:action-groups`
member other than menus and Selector's and MultiSelector's options, whose
tracking and public `menuPressStep` belong to
`module:DropdownMenu/useMenuPress` (OQ1; implementation gaps: MultiSelector,
and TopNav's, SideNavHeading's, TopNavHeading's, NavHeadingMenu's,
BreadcrumbItem's and TabMenu's menus,
do not mount it yet). No other member keeps its own copy of the tracking. It is not exported (`spec:AST-017`
FR21).

## Allowed variation

Component families keep their shipped interaction models:
Expand Down Expand Up @@ -252,19 +263,23 @@ is asked to carry a new decision.
- `architecture:react-component-runtime` owns shared lifecycle and resource
mechanisms. This record owns only the cross-cutting modality-path,
no-stale-interaction-outcome, gesture-velocity-source, hover-intent
(INV11), and scroll-progress-source (INV12) requirements.
(INV11), scroll-progress-source (INV12), and group press-tracking (INV13)
requirements.
- The Core velocity tracker and its release filter (INV10) — the one source of
gesture velocity for Core components; not exported.
- The hover recognizer, `HoverGestureRecognizer`, and its `intent` setting
(INV11) — the one source of hover-show timing for Core components; not
exported.
- The native-scroll module's progress and its subscription (INV12) — the one
source of scroll progress for Core components; not exported.
- The action-group tracker (INV13) — the one press tracker for action groups
outside menus and Selector's and MultiSelector's options; not exported.

## Deciding specs

`spec:AST-100/DEC-1` decides one release velocity per kind of surface (INV10).
Otherwise no separate specification changes this record. The last-input rule was approved as
`spec:AST-100/DEC-1` decides one release velocity per kind of surface (INV10),
and `spec:AST-094/DEC-17` decides one press tracking for every action group

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The frontmatter still reads deciding_specs: [spec:AST-100/DEC-1] (line 28), so pnpm specs:for packages/core/src/hooks/actionGroupTracker.ts never lists DEC-17. Suggest adding spec:AST-094/DEC-17 there too.

(INV13). Otherwise no separate specification changes this record. The last-input rule was approved as
a system architecture decision by `cixzhang` on 2026-08-30. Essential-action
reachability, newer-intent precedence, and the evidence/scope guard were approved by
`cixzhang` on 2026-09-10.
Expand All @@ -284,6 +299,7 @@ reachability, newer-intent precedence, and the evidence/scope guard were approve
| INV10 | Source boundary check over Core and Lab, a Lab-to-Core comparison on one recorded stream, and release-filter unit tests over recorded iOS pan and scroll-view streams | A Core component with its own sample buffer, velocity math, or release filter; a Lab component with its own sample buffer, velocity math, or release filter; a Lab component reporting a different velocity than Core for the same stream; an export of the tracker; a non-zero release after a still pause |
| INV11 | Evidence gap: not implemented yet; the shared hover recognizer and its adopters' move onto it are pending. Then: unit tests of the hover recognizer's intent and browser tests of its adopters with a mouse, a pen, a finger, and the keyboard | A show without the owner's entry delay, a missed handoff within a group, a delayed keyboard show, a hover-shown surface that closes before the pointer reaches it, a finger served by it, or a second hover-timing implementation fails |
| INV12 | Unit tests of native scroll's progress and real-browser proofs of its adopters | Progress routed through React state, a missing edge, travel under Reduce Motion, use where native scroll-driven animation is supported, or a public export fails |
| INV13 | Source boundary check over Core and each family member's pointer-stream tests | A member outside menus and Selector's and MultiSelector's options that tracks a held pointer across its actions with its own code, or a public export of the tracker, fails |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this row lost its padding in the merge from main, so prettier --check now flags the file (it passes on main), and the lint-staged prettier --write hook will re-pad the whole row as churn in the next commit that touches it. Running Prettier on the file fixes it.


Real-browser evidence is required when the behavior depends on
`:focus-visible`, pointer capability, touch or pen synthesis, rendered focus
Expand All @@ -297,3 +313,8 @@ indicator on pointer press, and keeping internal action focus owned by the
action. The benchmark also verifies programmatic editor focus after both
keyboard and pointer input before the behavior is treated as complete. A
benchmark demonstrates the invariants; it does not carry authority for them.

## Open questions

- **OQ1 — When do menus and Selector's and MultiSelector's options move onto
the shared tracker?** (`engineering`) Open.
219 changes: 219 additions & 0 deletions docs/families/action-groups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
---
schema_version: 1
template_version: 1
kind: family
id: family:action-groups
authority: current
archive_reason: null
superseded_by: null
approved_by: cixzhang
approved_at: 2026-10-26
owners: [cixzhang]
review_triggers: [behavior, interaction, accessibility]
verified_by:
[
packages/core/src/hooks/useMenuPress.test.tsx,
packages/core/src/hooks/menuPressGesture.test.ts,
]
Comment on lines +13 to +17

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: verified_by lists only the menu tests. packages/core/src/hooks/actionGroupTracker.test.ts and actionGroupTracker.exports.test.ts back the verification map's "Shared-implementation tests" and INV13's "It is not exported", so they could be linked here or under architecture:interaction-modality.

members:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: none of these member records lists family:action-groups in its families: frontmatter yet (for example Selector.spec.md, TimeInput.spec.md, ButtonGroup.spec.md, ToggleButtonGroup.spec.md and Banner.spec.md), while every member record of family:buttons and family:input-fields lists its family; spec:AST-094's affects_families also names only family:buttons. Consider adding the backlinks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

members still lists only the original 14 components, but lines 67–68 add the navigation menus of TopNav (TopNavMenu), SideNav's collapsed rail (SideNavHeading) and NavHeadingMenu as members. pnpm specs:for follows members, so at this revision it never ties this family to TopNavMenu.tsx, SideNavHeading.tsx or NavHeadingMenu.tsx. Please add component:TopNavMenu, component:SideNavHeading and component:NavHeadingMenu.

[
component:DropdownMenu,
component:DropdownMenuSubMenu,
component:ContextMenu,
component:Selector,
component:MultiSelector,
component:DateInput,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The membership rule names the date wheels of DateInput and DateTimeInput (lines 66–67), but only component:DateInput is listed. pnpm specs:for routes this family to DateInput and the shared Wheel.tsx, while DateTimeInput.tsx and TouchDateTimeField.tsx get only the five global FR routes; TimeInput's TouchTimeField.tsx mounts the same Wheel and is neither listed nor excluded. Separately, a wheel is a scroll container whose mouse drag scrolls it (usePointerDragScroll.ts), which FR1 and FR2 under FR5 would turn into tracking; consider an allowed variation (a drag scrolls, a tap acts) or moving the wheels to the exclusions.

component:DateTimeInput,
component:TimeInput,
component:AlertDialog,
component:ButtonGroup,
component:ToggleButtonGroup,
component:Toolbar,
component:Banner,
component:Toast,
component:TopNavMenu,
component:SideNavHeading,
component:TopNavHeading,
component:TabMenu,
component:DateRangeInput,
component:NavHeadingMenu,
component:BreadcrumbItem,
]
architecture: [architecture:interaction-modality]
contributing: []
deciding_specs: [spec:AST-094/DEC-17]
---

# Action groups contract

<!-- review-applicability:v1 -->

```json
{
"scope": "global",
"triggers": {
"interaction": ["FR1", "FR2", "FR3", "FR4", "FR5"]
}
}
```

## Intent

A person can press one action in a group of sibling actions, slide across the
others while the highlight follows, and act on the one they lift on, the same
way in every group, with SegmentedControl as the one named exception. Every
member gets the behavior from one shared implementation, or menus and
Selector's and MultiSelector's options from the menu press model, so no member builds its own.

## Membership rule

A component is a member when it renders a set of two or more sibling
momentary, toggle, or option actions that a person chooses one of. Members
today:
Comment on lines +70 to +72

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rule also covers existing option lists and menus that neither the members list below nor the exclusions name, and none of them mounts useMenuPress: Typeahead's listbox (packages/core/src/Typeahead/BaseTypeahead.tsx lines 1247–1275, also rendered by Tokenizer), CommandPalette's options (CommandPalette/CommandPaletteItem.tsx line 196), the chat composer's trigger menu (Chat/useTriggerMenu.tsx line 977), and the TopNav, SideNav and NavHeadingMenu menus (TopNav/TopNavMenu.tsx line 578, SideNav/SideNavHeading.tsx line 536, NavMenu/NavHeadingMenu.tsx line 197). The family routes FR1–FR5 globally, so pnpm specs:for already hands them to Typeahead. Suggest naming each as a member, with an adoption row and its place in INV13's scope, or as an exclusion with its reason, as Pagination and Stepper are.

Comment on lines +70 to +72

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three current components meet this rule and appear neither in the list below nor under "These are not members": TabMenu's role="menu" of menuitemradio options (packages/core/src/TabList/TabMenu.spec.md FR4, TabMenu.tsx lines 405 and 425), DateRangeInput's presets, "an independent button in one labeled group" (DateRangeInput.spec.md FR2), and SideNavItem's collapsed-rail flyout (SideNavItem.spec.md FR9). pnpm specs:for packages/core/src/TabList/TabMenu.tsx does not reach this family. Suggest naming each as a member (with members, its adoption row and INV13's gap note where it applies) or excluding it with a reason, as was done for TopNavHeading and TopNavMegaMenu.


- menus: DropdownMenu, ContextMenu, and their sub-menus, the navigation
menus of TopNav (TopNavMenu), SideNavHeading, TopNavHeading, and
NavHeadingMenu; and
BreadcrumbItem's `menu`, which renders DropdownMenu items;
- TabMenu's menu of tab options;
- option lists: Selector's and MultiSelector's options, and the wheels of
DateInput, DateTimeInput, and TimeInput;
- AlertDialog's actions;
- ButtonGroup and ToggleButtonGroup;
- DateRangeInput's presets, one labeled group of preset buttons;
- Toolbar's buttons; a field inside a toolbar is skipped;
- the action rows of Banner and Toast when a row has two or more sibling
actions.

Action rows in a Dialog's footer, a Card's footer, or any `LayoutFooter` get
the behavior by composing ButtonGroup.

A component built later that matches the rule joins by the rule, including an
action sheet, a tab bar or navigation bar, a filter-chip group, and a rating.

SegmentedControl is a named exception: this family's rule does not bind it.

These are not members:

- text inputs and InputGroup as a whole, whose input keeps the caret and
selection and whose addons belong to that input rather than forming a group;
- TabList, whose scrollable rows need a drag to scroll and whose tabs switch
views;
- Pagination and Stepper, inline page controls in the page flow rather than a
menu;
- TopNavMegaMenu's panel, a browsing grid of links in a `role="group"`, not a
menu (`component:TopNavMegaMenu` FR5);
- SideNavItem's collapsed-rail flyout, a popover of the item's navigation rows,
not a menu;
- Popover itself, a surface whose content owns its role; a menu inside it
follows its own component;
- Calendar's day grid, a two-dimensional date grid with its own keyboard and
range-selection model, which a slide to commit would break;
- RadioList, CheckboxList, and SelectableCard, whose rows and cards sit in
scrolling lists;
- Token chips, which are removable and have no group control.
- the suggestion lists of Typeahead (also Tokenizer's), CommandPalette, and the
chat composer's trigger menu, whose focus stays in the text input, as a text
input's does.

## Shared owner

One shared, internal implementation gives every member other than menus and
Selector's and MultiSelector's options FR1–FR5
(`architecture:interaction-modality` INV13); those get them from
`module:DropdownMenu/useMenuPress`. No member keeps another copy.

## Canonical concepts

- **Action group:** two or more sibling actions a person chooses one of.
- **Held pointer:** a press that has not lifted, tracked across the group.
- **Lifted action:** the enabled action under the pointer when it lifts.

## Cross-component invariants

- **FR1 — The lift decides.** In a member, a press on an action that slides
across its siblings acts on the action the pointer lifts on, through that
action's own activation; a press that never leaves its action acts on it.
One gesture acts at most once (`spec:AST-094` FR26). After a slide, focus does what
a click on the lifted action does.
- **FR2 — The highlight follows the pointer.** While the pointer is held, the
enabled action under it is highlighted, at most one at a time, and nothing
is highlighted over a disabled action, a gap, or outside the group
(`spec:AST-094` FR27).
- **FR3 — Sliding off cancels.** A press that lifts outside the group acts on
nothing; a cancelled pointer, a second finger, or the window losing focus
ends the gesture with nothing acting (`spec:AST-094` FR28). Whether a
member that opened for the gesture stays open stays with the member.
- **FR4 — A toggle group toggles only the lifted action.** In a toggle group,
only the action lifted on toggles; sliding across never toggles the actions
passed over.
- **FR5 — Every pointer, one target rule.** The behavior applies to every web
pointer, mouse and pen as well as a finger. Under a fine pointer a group
keeps one `pointerdown` listener on its element, cancelable where the member
needs it, adds document listeners only during a press and removes them at
the release, and may arm one per-document click swallower from the release
until that gesture's click; nothing else is idle (`spec:AST-094` FR19,
FR24). The 44 px target is each member's hit
expansion under a coarse pointer only. Keyboard and assistive-technology
behavior is unchanged.

## Allowed component variation

- What an action does on activation, and how a member shows its highlight,
stay with the member.
- Menus keep their own opening and handoff (`spec:AST-094` FR29) and their
scrolling rules.
- A wheel is a scroll container: a drag scrolls it, as it does today, and a
tap acts on the option under it; only a press that does not scroll tracks.

## Representative matrix

| Member and state | Shared invariant | Deliberate variation |
| -------------------------------------- | --------------------------------------------------- | ---------------------------------------------- |
| DropdownMenu / slide from row to row | the lifted row acts; one row lit at a time | opening and handoff stay the menu's (FR29) |
| AlertDialog / slide from Cancel | the lifted action runs; a lift outside does nothing | the actions' order and stacking stay local |
| ToggleButtonGroup / slide across three | only the lifted toggle changes | single or multiple selection stays the group's |
| Toolbar with a field / slide across | buttons track; the field is skipped | which controls a toolbar holds stays local |

## Adoption and exceptions

| Components or surface | Required adoption |
| ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Menus and Selector's and MultiSelector's options | Follow FR1–FR5 through `module:DropdownMenu/useMenuPress`. |
| TopNav's, SideNavHeading's, TopNavHeading's, NavHeadingMenu's, BreadcrumbItem's, and TabMenu's menus | Follow FR1–FR5 through `module:DropdownMenu/useMenuPress`, as menus. |
| Date and time wheels | Follow FR1–FR5 through the shared implementation. |
| AlertDialog's actions | Track the actions only. |
| ButtonGroup, ToggleButtonGroup, Toolbar | Track sibling buttons; a field inside is skipped; toggles follow FR4. |
| DateRangeInput's presets | Track the preset buttons only. |
| Banner and Toast action rows | Track only a row with two or more sibling actions. |

TopNav's, SideNavHeading's, TopNavHeading's, NavHeadingMenu's, BreadcrumbItem's, and TabMenu's menus act on
the browser's click today and track no held pointer across their rows; their
adoption of the menu press model is an implementation gap.

These are required outcomes, not a claim of completed adoption. The excluded
components listed under the membership rule are not exceptions to approve;
they are outside the family.

## Verification map

| Contract | Verification | Representative members and states |
| -------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| FR1–FR3 | Shared-implementation tests and each member's pointer-stream tests | a slide across a menu, AlertDialog's actions, a ButtonGroup; a lift outside |
| FR4 | ToggleButtonGroup pointer-stream tests | a slide across three toggles; only the lifted one toggles |
| FR5 | Member tests with a mouse, a pen, a finger, the keyboard, and a screen reader | a 44 px target under a coarse pointer only; unchanged keyboard and screen-reader paths |

## Decision links

- `spec:AST-094/DEC-17` — every group of sibling actions tracks a held
pointer the same way.

## Open questions

None.

## Content boundary

This file owns action-group membership and the shared press, slide, and lift
behavior. It does not duplicate component prop tables, what each action does,
menu opening, or the shared implementation's thresholds.
4 changes: 3 additions & 1 deletion docs/families/buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ Membership follows public responsibility, not an import of Button or a rendered
- **FR11 — A button-specific group has one accessible owner.** ButtonGroup and
ToggleButtonGroup MUST expose an accessible group label and propagate their
documented size and disabled defaults without removing a member's accessible
name. The group owns only the behavior and surface declared by its group mode.
name. The group owns only the behavior and surface declared by its group
mode, and the press tracking across members that `family:action-groups`
gives it.
A ToggleButtonGroup member identified by `value` MUST derive pressed state and
selection requests from the group, not its standalone `isPressed`,
`onPressedChange`, or `pressedChangeAction`. Member `onPressedChange` and
Expand Down
7 changes: 5 additions & 2 deletions docs/families/layout-regions.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ wrapper, or a header-like visual treatment.

- **FR1 — A region owns structure, not product meaning.** A member establishes a
spatial boundary and renders caller content without adopting the content's
product semantics, state, or component contracts.
product semantics, state, or component contracts. Toolbar's press
tracking across its buttons (`family:action-groups` FR5) is the one
exception.
- **FR2 — Region direction is logical.** Start and end follow writing direction.
Divider placement and panel adjacency use the same logical region position.
- **FR3 — Layout selects geometry from slot presence.** Header, Content, Footer,
Expand Down Expand Up @@ -176,7 +178,8 @@ wrapper, or a header-like visual treatment.
- **AV4 — Size model.** Layout owns fill/auto container height and content-width
propagation; individual regions own applicable height, width, padding, and
scroll props; Section owns its box-size props.
- **AV5 — Interaction.** Toolbar owns roving focus and keyboard hints. Other
- **AV5 — Interaction.** Toolbar owns roving focus, keyboard hints, and the
press tracking `family:action-groups` FR5 gives it across its buttons. Other
members add no toolbar behavior. Resizable owns resize interaction.
- **AV6 — Composition mechanism.** Members may use Stack utilities, direct CSS
layout, contexts, or component composition. The observable region contract is
Expand Down
Loading
Loading