Skip to content
33 changes: 18 additions & 15 deletions docs/architecture/interaction-modality.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ authority: current
archive_reason: null
superseded_by: null
approved_by: cixzhang
approved_at: 2026-10-24
approved_at: 2026-10-25
owners: [cixzhang]
applies_to:
[
Expand Down Expand Up @@ -157,9 +157,12 @@ work.
previous one; a contact
still for longer than the stillness interval before lifting reads 0. It is not exported. No Core component keeps its own sample
buffer, velocity math, or alternative release filter; a component's flick
threshold compares the tracker's release velocity. Lab cannot import the
tracker; a Lab gesture keeps one local tracker with the same blend and
stillness interval, so it reports the same velocity for the same motion.
threshold compares the tracker's release velocity. Lab reads release
velocity only through Core's recognizers (`velocity()` on a pan, or on a
scroll view's pan for a scrolling surface), from Core's internal gestures

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.

Lab reaches Core only through Core's package exports (a peer dependency, no alias to Core's source). Reading the recognizers "from Core's internal gestures module" therefore needs a Core export, which architecture:public-component-api INV12 makes public, while AST-094 FR4 says this machinery publishes no public API. Please name the supported import path here (and narrow FR4 to match), or keep the sentence under which Lab keeps one local tracker with the same blend.

module; it never imports the tracker and never keeps its own sample buffer,
velocity math, or release filter, so it reports Core's velocity for the same
motion.

## Allowed variation

Expand Down Expand Up @@ -238,17 +241,17 @@ reachability, newer-intent precedence, and the evidence/scope guard were approve

## Verification

| Invariant | Evidence | Failure signal |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| INV1, INV2 | Programmatic-focus cases after keyboard and pointer input in representative component tests | Programmatic focus invents a modality, or pointer history paints the keyboard indicator |
| INV3 | Direct-owner, wrapper-owner, replaceable-indicator, and nested-action cases | No indicator, two indicators, or replacement content can opt out |
| INV4 | Keyboard, mouse, touch, and pen browser paths where applicable | Hover-only behavior, sticky touch hover, or unreachable action |
| INV5 | Disabled, busy, and read-only DOM and activation assertions | Inactive control reacts, eligible control loses focus, or state changes with modality |
| INV6 | Public API review and representative source inspection | A component adds caller-controlled modality without a separate API decision |
| INV7 | Rendered-browser affected-state checks across geometry, clipping, scrolling, hit testing, built-in and custom-renderer paths | At an offered interaction point one modality loses every essential path, or evidence substitutes class equality for reachability/perceptibility |
| INV8 | Owner-defined intent order, pending, close, cancellation, disablement, and unmount mutations | Older work changes current content, selection, status or announcement, visibility, focus, or activation after owner-defined supersession |
| INV9 | Concrete-harm reproduction, representative normal/legacy/no-new-prop paths, and coincident public-delta inventory | Unsupported or aesthetic preference is treated as harm, unaffected behavior changes, or an API, layout, sizing, default, sticky, or exception delta escapes direct authority |
| INV10 | Source boundary check over Core, 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 tracker reporting a different velocity for the same stream; an export of the tracker; a non-zero release after a still pause |
| Invariant | Evidence | Failure signal |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| INV1, INV2 | Programmatic-focus cases after keyboard and pointer input in representative component tests | Programmatic focus invents a modality, or pointer history paints the keyboard indicator |
| INV3 | Direct-owner, wrapper-owner, replaceable-indicator, and nested-action cases | No indicator, two indicators, or replacement content can opt out |
| INV4 | Keyboard, mouse, touch, and pen browser paths where applicable | Hover-only behavior, sticky touch hover, or unreachable action |
| INV5 | Disabled, busy, and read-only DOM and activation assertions | Inactive control reacts, eligible control loses focus, or state changes with modality |
| INV6 | Public API review and representative source inspection | A component adds caller-controlled modality without a separate API decision |
| INV7 | Rendered-browser affected-state checks across geometry, clipping, scrolling, hit testing, built-in and custom-renderer paths | At an offered interaction point one modality loses every essential path, or evidence substitutes class equality for reachability/perceptibility |
| INV8 | Owner-defined intent order, pending, close, cancellation, disablement, and unmount mutations | Older work changes current content, selection, status or announcement, visibility, focus, or activation after owner-defined supersession |
| INV9 | Concrete-harm reproduction, representative normal/legacy/no-new-prop paths, and coincident public-delta inventory | Unsupported or aesthetic preference is treated as harm, unaffected behavior changes, or an API, layout, sizing, default, sticky, or exception delta escapes direct authority |
| INV10 | Source boundary check over Core, 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; an export of the tracker; a non-zero release after a still pause |

Real-browser evidence is required when the behavior depends on
`:focus-visible`, pointer capability, touch or pen synthesis, rendered focus
Expand Down
5 changes: 3 additions & 2 deletions docs/design/user-states.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ surface.
- **DR1 — Press the manipulated surface.** During pointer hold or drag, each
enabled surface in the matrix below MUST paint `--color-overlay-pressed` on
the named visual part. The overlay is transient and MUST clear when the press
or drag ends.
or drag ends. Under a finger, the overlay's timing follows `spec:AST-094` FR11's press profiles.
- **DR2 — Disabled means no response.** A disabled control in the matrix MUST
remain inoperable and MUST NOT gain a pressed visual treatment.
- **DR3 — Persistent selection wins.** A selected SegmentedControl item MUST
keep its raised selected surface during pointer hold; only an unselected item
receives the pressed overlay.
receives the pressed overlay. Under a finger the item keeps that surface, and its press timing follows
`spec:AST-094` FR11.

## Anatomy and hierarchy

Expand Down
18 changes: 9 additions & 9 deletions docs/families/buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ Membership follows public responsibility, not an import of Button or a rendered

## Canonical concepts

| Concept | Values or states | Default semantics | Stability |
| ---------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------- |
| activation model | momentary action, navigation, persistent press | Button and IconButton activate once; ToggleButton represents retained pressed state | shipped distinction |
| content mode | visible label, custom visible content, icon-only | every control has a required accessible `label`; icon-only hides it visually | shipped family rule |
| size | `sm`, `md`, `lg` | `md`; explicit member size wins over an inherited group size | shipped family axis |
| visual state | rest, hover, focus, active, disabled, loading; pressed where applicable | states preserve control geometry and accessible purpose | shipped family rule |
| async action | absent, fire-once, interruptible persistent action | ordinary actions deduplicate while pending; persistent toggles remain reversible | shipped family distinction |
| elevation | `none`, `low`, `med`, `high` | `none`; the element painting the visible surface owns the shadow | shipped family axis; ToggleButton adoption approved |
| grouping | standalone, spaced set, connected surface | semantics and painted containment decide ownership; grouping alone does not | family rule |
| Concept | Values or states | Default semantics | Stability |
| ---------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| activation model | momentary action, navigation, persistent press | Button and IconButton activate once; ToggleButton represents retained pressed state | shipped distinction |
| content mode | visible label, custom visible content, icon-only | every control has a required accessible `label`; icon-only hides it visually | shipped family rule |
| size | `sm`, `md`, `lg` | `md`; explicit member size wins over an inherited group size | shipped family axis |
| visual state | rest, hover, focus, active, disabled, loading; pressed where applicable | states preserve control geometry and accessible purpose; under a finger, press feedback follows `spec:AST-094` FR11's control profile | shipped family rule |
| async action | absent, fire-once, interruptible persistent action | ordinary actions deduplicate while pending; persistent toggles remain reversible | shipped family distinction |
| elevation | `none`, `low`, `med`, `high` | `none`; the element painting the visible surface owns the shadow | shipped family axis; ToggleButton adoption approved |
| grouping | standalone, spaced set, connected surface | semantics and painted containment decide ownership; grouping alone does not | family rule |

## Cross-component invariants

Expand Down
15 changes: 9 additions & 6 deletions docs/specs/AST-013/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,12 @@ requirements. Assistive-technology evidence remains separately owned.
public [Browser Support guide](../../../packages/cli/assets/docs/browser-support.doc.mjs)
and record their source and refresh date. TypeScript targets, build targets, and
feature tables are not support evidence.
- **FR3 — Two explicit browser support rows are always included.** Independently
- **FR3 — Explicit browser support rows are always included.** Independently
of the generated Baseline coverage, Astryx explicitly supports:
- the latest stable Chrome release on desktop; and
- Safari on the latest stable iOS release.
- the latest stable Chrome release on desktop;
- Safari on the latest stable iOS release; and
- for touch presentations, Chrome on the latest stable Android release
(`spec:AST-094`).

“Latest” means the current stable release identified and refreshed from
authoritative browser release data, not a handwritten version. Other browsers
Expand Down Expand Up @@ -191,23 +193,24 @@ hydrating render can differ from the server's markup.

## Decision log

### DEC-1 — Rolling Baseline tiers plus two official browser rows
### DEC-1 — Rolling Baseline tiers plus official browser rows

**Reference:** `spec:AST-013/DEC-1`
**Decider:** `cixzhang`, `2026-09-01`

Astryx uses current Web Platform Baseline for full support, Baseline minus two
years for reduced fallback, and no promise below that tier. Latest stable Chrome
on desktop and Safari on latest stable iOS are always included as official support
and test rows independently of generated Baseline coverage. Generated compatibility
and test rows independently of generated Baseline coverage, and touch
presentations add Chrome on the latest stable Android (`spec:AST-094`). Generated compatibility
rows and the named official test matrix remain distinct public facts.

### DEC-2 — Explicit support does not require proof on every change

**Reference:** `spec:AST-013/DEC-2`
**Decider:** `cixzhang`, `2026-09-02`

DEC-1's two named browser rows are explicit support rows, not a required automated
DEC-1's named browser rows are explicit support rows, not a required automated
or per-change test matrix. Astryx investigates and fixes defects reproduced in
those browsers, but routine changes do not need to prove every supported browser
before landing. Actual-browser evidence is required when the change makes a
Expand Down
3 changes: 2 additions & 1 deletion docs/specs/AST-025/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ the behavior.
the requested direction. A containment policy MAY stop chaining, but its
`overscroll-behavior` effect MUST be active only on axes that currently overflow.
This avoids dead scroll zones in engines that honor containment on non-overflowing
`overflow: auto` elements.
`overflow: auto` elements. Inside a touch presentation under a finger, who
gets a drag is decided once, when it begins (`spec:AST-094` FR14).
- **FR15 — Native scrollbars are the default presentation.** The default presenter
MUST preserve native scrolling and use standards-based CSS such as
`scrollbar-width`, `scrollbar-color`, and `scrollbar-gutter` where supported.
Expand Down
Loading
Loading