@astryxdesign/core 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -3
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts +12 -1
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +44 -15
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +3 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +3 -7
- package/dist/Center/Center.d.ts +23 -16
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +7 -5
- package/dist/CodeBlock/CodeBlock.js +2 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +12 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +12 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +1 -0
- package/dist/Field/InputClearButton.d.ts +2 -2
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +5 -1
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +16 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +12 -1
- package/dist/HoverCard/useHoverCard.js +2 -2
- package/dist/Indicator/CheckboxIndicator.js +2 -2
- package/dist/Indicator/RadioIndicator.js +2 -2
- package/dist/Layer/layerStack.d.ts +10 -0
- package/dist/Layer/layerStack.d.ts.map +1 -1
- package/dist/Layer/layerStack.js +21 -9
- package/dist/Layer/useLayerDismissal.d.ts +2 -3
- package/dist/Layer/useLayerDismissal.d.ts.map +1 -1
- package/dist/Layer/useLayerDismissal.js +2 -3
- package/dist/NavIcon/NavIcon.js +2 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +12 -2
- package/dist/Popover/usePopover.d.ts +3 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +4 -2
- package/dist/ProgressBar/ProgressBar.js +2 -2
- package/dist/ScrollableArea/ScrollableArea.d.ts +79 -0
- package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -0
- package/dist/ScrollableArea/ScrollableArea.js +144 -0
- package/dist/ScrollableArea/index.d.ts +11 -0
- package/dist/ScrollableArea/index.d.ts.map +1 -0
- package/dist/ScrollableArea/index.js +11 -0
- package/dist/StatusDot/StatusDot.js +2 -2
- package/dist/TextArea/TextArea.js +2 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +19 -4
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +12 -2
- package/dist/Typeahead/BaseTypeahead.d.ts +21 -14
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +56 -20
- package/dist/astryx.css +15 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/scrollGeometry.d.ts +24 -0
- package/dist/hooks/scrollGeometry.d.ts.map +1 -0
- package/dist/hooks/scrollGeometry.js +86 -0
- package/dist/hooks/scrollOwnerRegistry.d.ts +15 -0
- package/dist/hooks/scrollOwnerRegistry.d.ts.map +1 -0
- package/dist/hooks/scrollOwnerRegistry.js +24 -0
- package/dist/hooks/useFocusTrap.d.ts +8 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +22 -11
- package/dist/hooks/useScrollableArea.d.ts +51 -0
- package/dist/hooks/useScrollableArea.d.ts.map +1 -0
- package/dist/hooks/useScrollableArea.js +287 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/defineTheme.d.ts +2 -6
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/derivedVarRegistry.js +1 -1
- package/dist/theme/localTokens.d.ts +8 -11
- package/dist/theme/localTokens.d.ts.map +1 -1
- package/dist/theme/localTokens.js +17 -71
- package/dist/theme/themeAdaptations.d.ts.map +1 -1
- package/dist/theme/themeAdaptations.js +4 -4
- package/dist/utils/themeProps.d.ts +10 -10
- package/dist/utils/themeProps.d.ts.map +1 -1
- package/dist/utils/themeProps.js +27 -10
- package/locales/en.json +16 -0
- package/locales/pseudo.json +12 -0
- package/package.json +7 -2
- package/src/AppShell/AppShell.test.tsx +36 -0
- package/src/AppShell/AppShell.tsx +4 -1
- package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
- package/src/Banner/Banner.test.tsx +3 -1
- package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +56 -1
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +211 -0
- package/src/BottomSheet/BottomSheetSwitcher.test.tsx +134 -2
- package/src/BottomSheet/BottomSheetSwitcher.tsx +43 -20
- package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +10 -5
- package/src/Breadcrumbs/BreadcrumbItem.spec.md +225 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +8 -13
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -2
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +49 -2
- package/src/Center/Center.doc.mjs +32 -28
- package/src/Center/Center.spec.md +225 -0
- package/src/Center/Center.test.tsx +42 -4
- package/src/Center/Center.tsx +24 -17
- package/src/Chat/ChatSystemMessage.test.tsx +2 -9
- package/src/CodeBlock/CodeBlock.doc.mjs +2 -2
- package/src/CodeBlock/CodeBlock.tsx +2 -2
- package/src/DateInput/DateInput.test.tsx +4 -4
- package/src/DateInput/DateInput.tsx +15 -4
- package/src/DateRangeInput/DateRangeInput.test.tsx +2 -2
- package/src/DateTimeInput/DateTimeInput.test.tsx +6 -4
- package/src/DateTimeInput/DateTimeInput.tsx +18 -7
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +4 -77
- package/src/Field/Field.test.tsx +42 -0
- package/src/Field/Field.tsx +6 -0
- package/src/Field/InputClearButton.test.tsx +35 -1
- package/src/Field/InputClearButton.tsx +7 -3
- package/src/Field/PanelSearchInput.tsx +21 -8
- package/src/FieldStatus/FieldStatus.spec.md +27 -17
- package/src/FieldStatus/FieldStatus.test.tsx +7 -5
- package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +198 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.known-failures.ts +13 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.renders.tsx +305 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +317 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.test.tsx +155 -0
- package/src/FileInput/FileInput.tsx +10 -1
- package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +3 -3
- package/src/HoverCard/HoverCard.doc.mjs +4 -4
- package/src/HoverCard/useHoverCard.tsx +2 -2
- package/src/Indicator/CheckboxIndicator.tsx +2 -2
- package/src/Indicator/Indicator.doc.mjs +2 -2
- package/src/Indicator/Indicator.test.tsx +1 -1
- package/src/Indicator/RadioIndicator.tsx +2 -2
- package/src/Layer/layerStack.ts +20 -9
- package/src/Layer/useLayerDismissal.ts +2 -3
- package/src/MultiSelector/MultiSelector.test.tsx +4 -4
- package/src/NavIcon/NavIcon.doc.mjs +4 -4
- package/src/NavIcon/NavIcon.tsx +2 -2
- package/src/NumberInput/NumberInput.tsx +18 -7
- package/src/Popover/Popover.doc.mjs +10 -10
- package/src/Popover/Popover.spec.md +55 -65
- package/src/Popover/Popover.test.tsx +29 -0
- package/src/Popover/usePopover.doc.mjs +4 -4
- package/src/Popover/usePopover.tsx +7 -4
- package/src/ProgressBar/ProgressBar.doc.mjs +4 -4
- package/src/ProgressBar/ProgressBar.test.tsx +1 -31
- package/src/ProgressBar/ProgressBar.tsx +2 -2
- package/src/RadioList/RadioList.test.tsx +5 -144
- package/src/RadioList/__tests__/RadioGroup.a11y.chromium.spec.ts +255 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.known-failures.ts +12 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.renders.tsx +232 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.states.ts +503 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.test.tsx +217 -0
- package/src/ScrollableArea/ScrollableArea.doc.mjs +100 -0
- package/src/ScrollableArea/ScrollableArea.spec.md +189 -0
- package/src/ScrollableArea/ScrollableArea.test.tsx +299 -0
- package/src/ScrollableArea/ScrollableArea.tsx +259 -0
- package/src/ScrollableArea/index.ts +26 -0
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +121 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +5 -172
- package/src/Selector/Selector.test.tsx +4 -4
- package/src/Spinner/Spinner.test.tsx +0 -18
- package/src/StatusDot/StatusDot.doc.mjs +4 -4
- package/src/StatusDot/StatusDot.tsx +2 -2
- package/src/TabList/TabList.test.tsx +5 -9
- package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +191 -0
- package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +45 -0
- package/src/TabList/__tests__/Tabs.a11y.renders.tsx +92 -0
- package/src/TabList/__tests__/Tabs.a11y.states.ts +247 -0
- package/src/TabList/__tests__/Tabs.a11y.test.tsx +153 -0
- package/src/Table/Table.doc.mjs +2 -2
- package/src/TextArea/TextArea.doc.mjs +4 -4
- package/src/TextArea/TextArea.tsx +2 -2
- package/src/TextInput/TextInput.doc.mjs +2 -1
- package/src/TextInput/TextInput.test.tsx +94 -0
- package/src/TextInput/TextInput.tsx +22 -6
- package/src/TimeInput/TimeInput.tsx +18 -7
- package/src/Toast/ToastViewport.test.tsx +1 -39
- package/src/Typeahead/BaseTypeahead.doc.mjs +229 -33
- package/src/Typeahead/BaseTypeahead.spec.md +269 -0
- package/src/Typeahead/BaseTypeahead.test.tsx +200 -0
- package/src/Typeahead/BaseTypeahead.tsx +99 -30
- package/src/hooks/index.ts +13 -0
- package/src/hooks/scrollGeometry.ts +155 -0
- package/src/hooks/scrollOwnerRegistry.ts +47 -0
- package/src/hooks/useFocusTrap.ts +22 -11
- package/src/hooks/useFocusTrapEscapeShim.test.tsx +4 -3
- package/src/hooks/useScrollableArea.doc.mjs +108 -0
- package/src/hooks/useScrollableArea.test.tsx +437 -0
- package/src/hooks/useScrollableArea.ts +469 -0
- package/src/index.ts +1 -0
- package/src/theme/defineTheme.test.ts +65 -105
- package/src/theme/defineTheme.ts +3 -9
- package/src/theme/derivedVarRegistry.ts +1 -1
- package/src/theme/localTokens.ts +25 -96
- package/src/theme/publicThemeHelperContract.test.ts +2 -2
- package/src/theme/themeAdaptations.test.ts +16 -42
- package/src/theme/themeAdaptations.ts +6 -9
- package/src/utils/themeProps.test.ts +29 -10
- package/src/utils/themeProps.ts +36 -17
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 3
|
|
3
|
+
template_version: 4
|
|
4
|
+
kind: component
|
|
5
|
+
id: component:Center
|
|
6
|
+
authority: draft
|
|
7
|
+
archive_reason: null
|
|
8
|
+
superseded_by: null
|
|
9
|
+
approved_by: null
|
|
10
|
+
approved_at: null
|
|
11
|
+
owners: [cixzhang]
|
|
12
|
+
review_triggers: [public-api, layout, theming, accessibility]
|
|
13
|
+
verified_by:
|
|
14
|
+
[
|
|
15
|
+
packages/core/src/Center/Center.test.tsx,
|
|
16
|
+
packages/core/src/theme/themingTargets.test.ts,
|
|
17
|
+
apps/storybook/rtl-audit/targets.json,
|
|
18
|
+
scripts/check-knowledge.mjs,
|
|
19
|
+
]
|
|
20
|
+
modules: []
|
|
21
|
+
families: [family:layout-primitives]
|
|
22
|
+
design_specs: []
|
|
23
|
+
architecture:
|
|
24
|
+
[
|
|
25
|
+
architecture:knowledge-contracts,
|
|
26
|
+
architecture:public-component-api,
|
|
27
|
+
architecture:component-theming-surface,
|
|
28
|
+
architecture:container-padding,
|
|
29
|
+
]
|
|
30
|
+
contributing: []
|
|
31
|
+
system_specs: [spec:AST-002, spec:AST-029]
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# Center component contract
|
|
35
|
+
|
|
36
|
+
## Intent
|
|
37
|
+
|
|
38
|
+
Center arranges caller-supplied content at the horizontal center, vertical center,
|
|
39
|
+
or both within its own box. This draft records verified released behavior, the
|
|
40
|
+
objective owned-attribute repair in the accompanying audit, and the existing
|
|
41
|
+
vertical-writing mismatch against current family authority. It does not add public
|
|
42
|
+
API, defaults, responsive behavior, container-bleed participation, or product
|
|
43
|
+
meaning.
|
|
44
|
+
|
|
45
|
+
## Compatibility and migration
|
|
46
|
+
|
|
47
|
+
- Released default preserved: `yes`
|
|
48
|
+
- Compatibility class: defect repair plus additive observational documentation;
|
|
49
|
+
public types, defaults, supported values, DOM element, and theme target remain
|
|
50
|
+
unchanged
|
|
51
|
+
- Controlled/uncontrolled behavior: not applicable
|
|
52
|
+
- Migration decision: none; the inherited vertical-writing mismatch remains
|
|
53
|
+
unchanged and requires a separate runtime correction with DOM, flow, RSC, and
|
|
54
|
+
caller-content compatibility evidence
|
|
55
|
+
|
|
56
|
+
Consumer migration instructions belong in consumer docs and release notes.
|
|
57
|
+
|
|
58
|
+
## Ownership boundary
|
|
59
|
+
|
|
60
|
+
**Owns**
|
|
61
|
+
|
|
62
|
+
- The fixed `div` container and its flex or inline-flex display mode.
|
|
63
|
+
- Centering along the selected public axis or axes.
|
|
64
|
+
- The current box-size inputs and logical padding precedence.
|
|
65
|
+
- The current `center` theme target and its reflected `axis` value.
|
|
66
|
+
|
|
67
|
+
**Does not own / non-goals**
|
|
68
|
+
|
|
69
|
+
- The semantics, paint, interaction, intrinsic size, or reading order of caller
|
|
70
|
+
content.
|
|
71
|
+
- Page or structural-region layout; those remain with Layout, AppShell, and the
|
|
72
|
+
product callsite.
|
|
73
|
+
- Gap between multiple children, responsive breakpoints, overflow, or automatic
|
|
74
|
+
sizing on an axis.
|
|
75
|
+
- Container inset publication or descendant bleed behavior. Center padding remains
|
|
76
|
+
local under `architecture:container-padding`.
|
|
77
|
+
- New visual treatment, public values, or element polymorphism.
|
|
78
|
+
|
|
79
|
+
## Public concepts
|
|
80
|
+
|
|
81
|
+
Consumer syntax remains in `Center.doc.mjs`. This table records observable concepts
|
|
82
|
+
rather than duplicating its prop table.
|
|
83
|
+
|
|
84
|
+
| Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
|
|
85
|
+
| -------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
86
|
+
| Centering axis | `both`, `horizontal`, `vertical` | Selects which physical axis or axes align caller content to the center of Center's box. | Every render. | `both` | `component:Center` | Observed released surface | Values rejected by the public type are outside this draft. |
|
|
87
|
+
| Display mode | flex or inline-flex | Selects a block-level or inline-level flex container without changing centering semantics. | Every axis value. | flex | `component:Center` | Observed released surface | The public boolean type admits only enabled or omitted. |
|
|
88
|
+
| Box size | number or CSS value string for current width/height constraints | Applies the shared `SizeValue` contract to Center's own box. | Every axis and display mode. | Intrinsic/containing-layout result when omitted. | `family:layout-primitives` | Observed released surface | Runtime-invalid CSS follows browser CSS handling; this draft adds no validation. |
|
|
89
|
+
| Local padding | Shared spacing step on uniform, axis, or logical edge inputs | Insets caller content inside Center without publishing container-bleed geometry. | Every axis and display mode; logical edges follow writing mode and direction. | No component padding when omitted. | `family:layout-primitives` | Observed released surface | Values rejected by `SpacingStep` are outside this draft. |
|
|
90
|
+
| DOM extension | Supported BaseProps inputs and ref | Supported DOM, ARIA, data, event, class, style, and StyleX inputs reach the current root; the ref reaches that `div`. | Every render. | No additional inputs. | `architecture:public-component-api` | Observed released surface | Component-owned target reflection remains authoritative when a generic data attribute collides. |
|
|
91
|
+
|
|
92
|
+
## Behavioral and layout contract
|
|
93
|
+
|
|
94
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
95
|
+
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
96
|
+
| FR1 | The current root is one `div`. It renders as flex by default and inline-flex when the current inline flag is enabled. | Released declarations, source, docs, tests, and browser evidence | Verified released behavior; no element or display change decided |
|
|
97
|
+
| FR2 | `both` centers the physical horizontal and vertical axes. `horizontal` and `vertical` are physical-axis aliases under `family:layout-primitives`, independent of writing mode. The current flex implementation satisfies this in horizontal writing but swaps the one-axis results under vertical writing because it maps the names directly to flex main/cross axes. | Current family contract, source, docs, tests, and Chromium vertical-writing evidence | Pre-existing current-authority conformance gap; this audit records the BLOCK and leaves runtime remediation out because a safe fix must preserve DOM, flow, server rendering, and caller content writing mode |
|
|
98
|
+
| FR3 | Current width, height, maximum-width, and minimum-height inputs use `SizeValue`: numbers resolve as CSS pixels and strings pass through as CSS values. | Current family contract, public declarations, docs, source, and browser evidence | Verified released behavior; no sizing API change |
|
|
99
|
+
| FR4 | Padding resolves independently per logical edge: explicit logical edge, then matching axis, then uniform padding. Inline and block edges resolve from writing mode and direction. | `family:layout-primitives/FR1–FR3`, source, tests, RTL audit, and browser evidence | Settled shared behavior; audit coverage completed |
|
|
100
|
+
| FR5 | Center padding remains local. It does not publish the internal container-padding variables that descendants use for bleed compensation. | `family:layout-primitives/FR8` and `architecture:container-padding/INV8` | Verified released boundary; no protocol participation added |
|
|
101
|
+
| FR6 | The root carries the current `center` target and reflects the resolved axis. Supported consumer styling composes on that same element, while a colliding generic `data-axis` value does not replace component-owned target state. | `architecture:public-component-api/INV5–INV6`, current source, docs, target tests, and audit regression | Objective contract restoration in this audit; no target or API addition |
|
|
102
|
+
| FR7 | Center creates no breakpoint, automatic overflow behavior, gap between children, structural region, or content-specific semantic wrapper. | `family:layout-primitives/FR4, FR7, AV3–AV5`, source, and docs | Verified released boundary; no new capability inferred |
|
|
103
|
+
|
|
104
|
+
### Allowed variation
|
|
105
|
+
|
|
106
|
+
- **AV1 — Caller content.** Any renderable caller content may appear inside the
|
|
107
|
+
current root and retains its own semantics, paint, interaction, and theme ownership.
|
|
108
|
+
- **AV2 — Available space.** Parent layout and current size inputs may change the
|
|
109
|
+
box available for centering without changing the axis contract.
|
|
110
|
+
- **AV3 — Consumer styling.** Supported class, style, and StyleX inputs may alter
|
|
111
|
+
the root through the documented escape hatches while the component-owned target
|
|
112
|
+
name and resolved axis reflection remain present.
|
|
113
|
+
|
|
114
|
+
### Representative states
|
|
115
|
+
|
|
116
|
+
| State | Required invariant | Allowed variation |
|
|
117
|
+
| -------------------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
118
|
+
| Both axes | Physical horizontal and vertical alignment are centered in every writing mode. | Caller content and available width/height may vary. |
|
|
119
|
+
| Horizontal only | The physical horizontal axis is centered; Center does not add physical vertical centering. | Height and caller-owned vertical placement may vary. |
|
|
120
|
+
| Vertical only | The physical vertical axis is centered; Center does not add physical horizontal centering. | Width and caller-owned horizontal placement may vary. |
|
|
121
|
+
| Vertical writing | The physical-axis requirements above remain unchanged. Current source reverses the one-axis outcomes. | Writing mode and caller content may vary; the violation does not. |
|
|
122
|
+
| Inline | The root is inline-flex and retains the selected axis behavior. | Surrounding inline content and caller children may vary. |
|
|
123
|
+
| Asymmetric logical padding | Logical start/end values keep their meaning while resolved physical inline-axis edges swap with direction. | Spacing steps, writing mode, and block-edge padding may vary. |
|
|
124
|
+
| Narrow or coarse-pointer context | The passive container preserves its layout contract without adding a breakpoint or interaction mode. | Parent width and caller content may wrap or size themselves. |
|
|
125
|
+
|
|
126
|
+
### Transformation and precedence order
|
|
127
|
+
|
|
128
|
+
- **ORD1 — Layout resolution.** Resolve display mode and preserve the public
|
|
129
|
+
physical-axis meaning across writing modes before applying current box-size inputs.
|
|
130
|
+
Current source instead maps `horizontal` to flex main-axis alignment and `vertical`
|
|
131
|
+
to flex cross-axis alignment, producing the FR2 conformance gap in vertical writing.
|
|
132
|
+
- **ORD2 — Padding resolution.** Resolve each edge from edge input to axis input to
|
|
133
|
+
uniform input, preserving zero as an explicit spacing step.
|
|
134
|
+
- **ORD3 — Root composition.** Combine the `center` target, resolved axis reflection,
|
|
135
|
+
component styles, and supported consumer styling on one root. Forward remaining
|
|
136
|
+
supported DOM inputs without allowing them to replace component-owned target state.
|
|
137
|
+
|
|
138
|
+
### Performance and resources
|
|
139
|
+
|
|
140
|
+
- Center owns no state, Effect, listener, observer, timer, portal, measurement, or
|
|
141
|
+
asynchronous resource. Its current render performs only synchronous prop
|
|
142
|
+
resolution and one DOM render.
|
|
143
|
+
|
|
144
|
+
## Accessibility contract
|
|
145
|
+
|
|
146
|
+
- **AR1 — Passive semantics.** Center adds no interactive role, accessible name,
|
|
147
|
+
state, focus behavior, keyboard handling, or live region. Caller content keeps its
|
|
148
|
+
own semantic and interaction ownership.
|
|
149
|
+
- **AR2 — Supported DOM semantics.** Supported caller ARIA, role, data, event, and
|
|
150
|
+
ref inputs reach the current root unless the attribute is component-owned target
|
|
151
|
+
reflection under FR6.
|
|
152
|
+
- **AR3 — Reading order.** Center renders caller children in caller order and does
|
|
153
|
+
not visually reorder them.
|
|
154
|
+
|
|
155
|
+
## Design relationships
|
|
156
|
+
|
|
157
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
158
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------- | ------------------ |
|
|
159
|
+
| Container | Supplies one- or two-axis alignment and optional local inset without adding a visual surface by default. | Current source, docs, and `family:layout-primitives` | Supporting layout | FR1–FR7 |
|
|
160
|
+
| Content | Retains caller-owned semantics, paint, interaction, and hierarchy inside the container. | Caller-owned content | Context-dependent | AV1, AR1, AR3 |
|
|
161
|
+
|
|
162
|
+
This observational draft records current layout relationships. It does not decide a
|
|
163
|
+
new density, breakpoint, visual treatment, or content hierarchy.
|
|
164
|
+
|
|
165
|
+
### Theming anatomy
|
|
166
|
+
|
|
167
|
+
<!-- anatomy-theming:v1 -->
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"Container": {"target": "center"},
|
|
172
|
+
"Content": {
|
|
173
|
+
"none": {
|
|
174
|
+
"reason": "intentional: Caller-supplied content retains its own theming ownership; Center applies no content target."
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Family and system relationships
|
|
181
|
+
|
|
182
|
+
- `family:layout-primitives` owns the shared `SizeValue`, `SpacingStep`, logical
|
|
183
|
+
padding, padding precedence, and Center arrangement vocabulary.
|
|
184
|
+
- `architecture:container-padding` records that Center's current padding is local
|
|
185
|
+
and does not publish descendant bleed geometry.
|
|
186
|
+
- `architecture:component-theming-surface` owns anatomy qualification, target
|
|
187
|
+
placement, and axis reflection on the current target.
|
|
188
|
+
- `architecture:public-component-api` owns the released subpath, BaseProps
|
|
189
|
+
passthrough, styling composition, ref reachability, and owned-attribute boundary.
|
|
190
|
+
- `architecture:knowledge-contracts` and `spec:AST-029` keep this observational
|
|
191
|
+
draft from settling new behavior and require exact-head owner approval.
|
|
192
|
+
- `spec:AST-002` owns admission for any future public or behavioral delta.
|
|
193
|
+
|
|
194
|
+
## Verification map
|
|
195
|
+
|
|
196
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
197
|
+
| ------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------- |
|
|
198
|
+
| FR1 | `Center.test.tsx`, `Center.stories.tsx`, and receipted Chromium evidence | Block and inline display | Removing a display style changes the public DOM/computed layout and fails focused or browser evidence. | `audit:Center/behavior` |
|
|
199
|
+
| FR2 | Receipted Chromium geometry in horizontal and `vertical-rl` writing modes | Both, horizontal, and vertical axes across writing modes | A one-axis value that centers the opposite physical dimension remains an open BLOCK until runtime behavior conforms. | `audit:Center/behavior` |
|
|
200
|
+
| FR3 | Public declarations, source, focused tests, and browser evidence | Numeric and string width/height constraints | Changing SizeValue lowering or dropping a size input changes the current root's computed box. | `audit:Center/api` |
|
|
201
|
+
| FR4 | `Center.test.tsx`, writing-mode-aware `targets.json` D8, and LTR/RTL browser receipts | Uniform, axis, per-edge, zero, horizontal writing, and vertical writing | Wrong precedence changes functional StyleX output; fixed left/right assumptions fail the vertical-writing D8 self-check. | `audit:Center/layout` |
|
|
202
|
+
| FR5, FR7 | Source review against family and container-padding authority | Padded and narrow containers | Publishing bleed geometry or adding implicit responsive/overflow behavior contradicts the current boundary. | `audit:Center/architecture` |
|
|
203
|
+
| FR6 | `Center.test.tsx` and `themingTargets.test.ts` | Every axis plus a colliding consumer data attribute | Missing target/axis metadata or consumer replacement of component-owned reflection fails focused tests. | `audit:Center/theming` |
|
|
204
|
+
| AR1–AR3 | Source, passthrough tests, component-scoped axe, and browser inspection | Passive content, caller ARIA/role, and multiple children | Added component semantics, dropped supported semantics, or visual reordering becomes observable. | `audit:Center/accessibility` |
|
|
205
|
+
| Documentation and surface | `Center.doc.mjs`, block/docsite checks, export checks, and `scripts/check-knowledge.mjs` | Consumer docs, examples, package entry points, and this draft | Missing or stale docs, exports, required structure, relationships, or anatomy mapping fails repository checks. | `audit:Center/docs` |
|
|
206
|
+
|
|
207
|
+
Current audit scores, screenshots, eligibility, and per-run receipts remain in their
|
|
208
|
+
existing wiki, pull-request, and trusted-check owners rather than this contract.
|
|
209
|
+
|
|
210
|
+
## Decision log
|
|
211
|
+
|
|
212
|
+
None. Current family authority already settles the physical-axis meaning. The
|
|
213
|
+
vertical-writing mismatch is an implementation conformance gap, not an unresolved API
|
|
214
|
+
or design decision; this observational draft neither waives it nor prescribes a risky
|
|
215
|
+
fix.
|
|
216
|
+
|
|
217
|
+
## Open questions
|
|
218
|
+
|
|
219
|
+
None.
|
|
220
|
+
|
|
221
|
+
## Content boundary
|
|
222
|
+
|
|
223
|
+
This file does not duplicate consumer prop tables or examples, current audit scores or
|
|
224
|
+
screenshots, implementation steps, shared layout vocabulary, container-padding
|
|
225
|
+
mechanics, or system API/theming rules. It links to their owners.
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import {describe, it, expect, vi} from 'vitest';
|
|
13
13
|
import {render, screen} from '@testing-library/react';
|
|
14
|
+
import {renderToString} from 'react-dom/server';
|
|
14
15
|
import {Center} from './Center';
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -39,8 +40,11 @@ describe('Center', () => {
|
|
|
39
40
|
const element = screen.getByTestId('center');
|
|
40
41
|
expect(screen.getByText('Centered Content')).toBeInTheDocument();
|
|
41
42
|
expect(element).toBeInTheDocument();
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
expect(element).toHaveStyle({
|
|
44
|
+
display: 'flex',
|
|
45
|
+
alignItems: 'center',
|
|
46
|
+
justifyContent: 'center',
|
|
47
|
+
});
|
|
44
48
|
});
|
|
45
49
|
|
|
46
50
|
it('centers horizontally only', () => {
|
|
@@ -51,7 +55,11 @@ describe('Center', () => {
|
|
|
51
55
|
);
|
|
52
56
|
const element = screen.getByTestId('center');
|
|
53
57
|
expect(screen.getByText('Horizontal Center')).toBeInTheDocument();
|
|
54
|
-
expect(element).toHaveStyle({
|
|
58
|
+
expect(element).toHaveStyle({
|
|
59
|
+
display: 'flex',
|
|
60
|
+
justifyContent: 'center',
|
|
61
|
+
});
|
|
62
|
+
expect(element).not.toHaveStyle({alignItems: 'center'});
|
|
55
63
|
});
|
|
56
64
|
|
|
57
65
|
it('centers vertically only', () => {
|
|
@@ -62,7 +70,11 @@ describe('Center', () => {
|
|
|
62
70
|
);
|
|
63
71
|
const element = screen.getByTestId('center');
|
|
64
72
|
expect(screen.getByText('Vertical Center')).toBeInTheDocument();
|
|
65
|
-
expect(element).toHaveStyle({
|
|
73
|
+
expect(element).toHaveStyle({
|
|
74
|
+
display: 'flex',
|
|
75
|
+
alignItems: 'center',
|
|
76
|
+
});
|
|
77
|
+
expect(element).not.toHaveStyle({justifyContent: 'center'});
|
|
66
78
|
});
|
|
67
79
|
|
|
68
80
|
it('applies height prop', () => {
|
|
@@ -214,6 +226,32 @@ describe('Center', () => {
|
|
|
214
226
|
expect(element).toHaveAttribute('aria-label', 'centered container');
|
|
215
227
|
});
|
|
216
228
|
|
|
229
|
+
it('does not let consumer data attributes override the reflected axis', () => {
|
|
230
|
+
const {container} = render(
|
|
231
|
+
<Center axis="horizontal" data-axis="vertical">
|
|
232
|
+
<div>Content</div>
|
|
233
|
+
</Center>,
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
expect(container.firstElementChild).toHaveAttribute(
|
|
237
|
+
'data-axis',
|
|
238
|
+
'horizontal',
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('renders on the server without a client boundary', () => {
|
|
243
|
+
const html = renderToString(
|
|
244
|
+
<Center axis="horizontal" paddingInlineStart={2}>
|
|
245
|
+
Centered content
|
|
246
|
+
</Center>,
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
expect(html).toContain('<div');
|
|
250
|
+
expect(html).toContain('astryx-center');
|
|
251
|
+
expect(html).toContain('data-axis="horizontal"');
|
|
252
|
+
expect(html).toContain('Centered content');
|
|
253
|
+
});
|
|
254
|
+
|
|
217
255
|
it('renders as div element', () => {
|
|
218
256
|
render(
|
|
219
257
|
<Center data-testid="center">
|
package/src/Center/Center.tsx
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* @file Center.tsx
|
|
5
5
|
* @input Uses React, StyleX for centering styles, Layout padding.stylex for spacing-scale padding
|
|
6
6
|
* @output Exports Center component and CenterProps
|
|
7
|
-
* @position Center component for
|
|
7
|
+
* @position Center component for one- or two-axis flex centering
|
|
8
8
|
*
|
|
9
9
|
* SYNC: When modified, update these files to stay in sync:
|
|
10
10
|
* - /packages/core/src/Center/Center.doc.mjs
|
|
11
|
+
* - /packages/core/src/Center/Center.spec.md
|
|
11
12
|
* - /packages/core/src/Center/Center.test.tsx
|
|
12
13
|
* - /apps/storybook/stories/Center.stories.tsx
|
|
13
14
|
* - /packages/cli/assets/templates/blocks/components/Center/ (showcase blocks)
|
|
@@ -62,10 +63,13 @@ export interface CenterProps extends BaseProps<HTMLDivElement> {
|
|
|
62
63
|
/** Ref forwarded to the root element */
|
|
63
64
|
ref?: React.Ref<HTMLDivElement>;
|
|
64
65
|
/**
|
|
65
|
-
* Center
|
|
66
|
-
* - `both`: Center
|
|
67
|
-
* - `horizontal`: Center
|
|
68
|
-
* - `vertical`: Center
|
|
66
|
+
* Center mode. In horizontal writing:
|
|
67
|
+
* - `both`: Center on the flex main and cross axes (default)
|
|
68
|
+
* - `horizontal`: Center on the flex main/inline axis
|
|
69
|
+
* - `vertical`: Center on the flex cross/block axis
|
|
70
|
+
*
|
|
71
|
+
* In vertical writing, the current single-axis behavior still follows those
|
|
72
|
+
* logical flex axes rather than the physical names. `both` centers both axes.
|
|
69
73
|
* @default 'both'
|
|
70
74
|
*/
|
|
71
75
|
axis?: CenterAxis;
|
|
@@ -103,39 +107,41 @@ export interface CenterProps extends BaseProps<HTMLDivElement> {
|
|
|
103
107
|
padding?: SpacingStep;
|
|
104
108
|
|
|
105
109
|
/**
|
|
106
|
-
*
|
|
110
|
+
* Logical inline-axis padding, using the spacing scale.
|
|
107
111
|
* Overrides `padding` on the inline axis when both are set.
|
|
108
112
|
*/
|
|
109
113
|
paddingInline?: SpacingStep;
|
|
110
114
|
|
|
111
115
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
116
|
+
* Logical inline-start padding, using the spacing scale. The resolved
|
|
117
|
+
* physical edge depends on writing mode and direction.
|
|
114
118
|
* Overrides `paddingInline` and `padding` on that edge only.
|
|
115
119
|
*/
|
|
116
120
|
paddingInlineStart?: SpacingStep;
|
|
117
121
|
|
|
118
122
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
123
|
+
* Logical inline-end padding, using the spacing scale. The resolved
|
|
124
|
+
* physical edge depends on writing mode and direction.
|
|
121
125
|
* Overrides `paddingInline` and `padding` on that edge only.
|
|
122
126
|
*/
|
|
123
127
|
paddingInlineEnd?: SpacingStep;
|
|
124
128
|
|
|
125
129
|
/**
|
|
126
|
-
*
|
|
130
|
+
* Logical block-axis padding, using the spacing scale.
|
|
127
131
|
* Overrides `padding` on the block axis when both are set.
|
|
128
132
|
*/
|
|
129
133
|
paddingBlock?: SpacingStep;
|
|
130
134
|
|
|
131
135
|
/**
|
|
132
|
-
*
|
|
136
|
+
* Logical block-start padding, using the spacing scale. The resolved physical
|
|
137
|
+
* edge depends on writing mode.
|
|
133
138
|
* Overrides `paddingBlock` and `padding` on that edge only.
|
|
134
139
|
*/
|
|
135
140
|
paddingBlockStart?: SpacingStep;
|
|
136
141
|
|
|
137
142
|
/**
|
|
138
|
-
*
|
|
143
|
+
* Logical block-end padding, using the spacing scale. The resolved physical
|
|
144
|
+
* edge depends on writing mode.
|
|
139
145
|
* Overrides `paddingBlock` and `padding` on that edge only.
|
|
140
146
|
*/
|
|
141
147
|
paddingBlockEnd?: SpacingStep;
|
|
@@ -153,10 +159,11 @@ export interface CenterProps extends BaseProps<HTMLDivElement> {
|
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
/**
|
|
156
|
-
* Center component for centering children
|
|
162
|
+
* Center component for centering children on one or both flex axes.
|
|
157
163
|
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
164
|
+
* In horizontal writing, the single-axis names match physical horizontal and
|
|
165
|
+
* vertical dimensions. In vertical writing, the current single-axis behavior
|
|
166
|
+
* follows flex main/cross axes; `both` still centers on both axes.
|
|
160
167
|
*
|
|
161
168
|
* @example
|
|
162
169
|
* ```
|
|
@@ -222,7 +229,7 @@ export function Center({
|
|
|
222
229
|
);
|
|
223
230
|
|
|
224
231
|
return (
|
|
225
|
-
<div ref={ref} {...
|
|
232
|
+
<div ref={ref} {...props} {...stylexProps}>
|
|
226
233
|
{children}
|
|
227
234
|
</div>
|
|
228
235
|
);
|
|
@@ -10,12 +10,6 @@ describe('ChatSystemMessage', () => {
|
|
|
10
10
|
expect(screen.getByText('Conversation started')).toBeTruthy();
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
it('has role="status"', () => {
|
|
14
|
-
render(<ChatSystemMessage data-testid="sys">Notice</ChatSystemMessage>);
|
|
15
|
-
const el = screen.getByTestId('sys');
|
|
16
|
-
expect(el.getAttribute('role')).toBe('status');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
13
|
it('renders default variant without divider lines', () => {
|
|
20
14
|
const {container} = render(<ChatSystemMessage>Hello</ChatSystemMessage>);
|
|
21
15
|
// Divider lines have aria-hidden, so check there are none
|
|
@@ -57,7 +51,7 @@ describe('ChatSystemMessage', () => {
|
|
|
57
51
|
expect(screen.getByTestId('my-sys')).toBeTruthy();
|
|
58
52
|
});
|
|
59
53
|
|
|
60
|
-
it('forwards rest props (data-*, id)
|
|
54
|
+
it('forwards rest props (data-*, id)', () => {
|
|
61
55
|
render(
|
|
62
56
|
<ChatSystemMessage data-testid="sys" data-custom="x" id="sys-1">
|
|
63
57
|
Hello
|
|
@@ -66,7 +60,6 @@ describe('ChatSystemMessage', () => {
|
|
|
66
60
|
const el = screen.getByTestId('sys');
|
|
67
61
|
expect(el).toHaveAttribute('data-custom', 'x');
|
|
68
62
|
expect(el).toHaveAttribute('id', 'sys-1');
|
|
69
|
-
expect(el.getAttribute('role')).toBe('status');
|
|
70
63
|
});
|
|
71
64
|
|
|
72
65
|
it('forwards rest props in the divider variant', () => {
|
|
@@ -77,6 +70,6 @@ describe('ChatSystemMessage', () => {
|
|
|
77
70
|
);
|
|
78
71
|
const el = screen.getByTestId('sys');
|
|
79
72
|
expect(el).toHaveAttribute('data-custom', 'x');
|
|
80
|
-
expect(el.
|
|
73
|
+
expect(el).toHaveAttribute('role', 'status');
|
|
81
74
|
});
|
|
82
75
|
});
|
|
@@ -151,8 +151,8 @@ export const docs = {
|
|
|
151
151
|
{className: 'astryx-code-block-header', visualProps: ['size', 'language', 'container']},
|
|
152
152
|
{className: 'astryx-code-block-title', visualProps: ['size', 'language']},
|
|
153
153
|
{className: 'astryx-code-block-copy-button'},
|
|
154
|
-
//
|
|
155
|
-
//
|
|
154
|
+
// Retained beside the canonical names for backwards compatibility.
|
|
155
|
+
// New themes use the canonical targets above.
|
|
156
156
|
{className: 'astryx-codeblock', visualProps: ['size', 'language', 'container'], deprecatedFor: 'code-block'},
|
|
157
157
|
{className: 'astryx-codeblock-header', visualProps: ['size', 'language', 'container'], deprecatedFor: 'code-block-header'},
|
|
158
158
|
{className: 'astryx-codeblock-title', visualProps: ['size', 'language'], deprecatedFor: 'code-block-title'},
|
|
@@ -930,8 +930,8 @@ export function CodeBlock({
|
|
|
930
930
|
themeProps(
|
|
931
931
|
'code-block',
|
|
932
932
|
{size, language, container},
|
|
933
|
-
// `codeblock` ran the compound name together;
|
|
934
|
-
//
|
|
933
|
+
// `codeblock` ran the compound name together; keep it emitted so
|
|
934
|
+
// existing themes continue to work.
|
|
935
935
|
{legacyNames: ['codeblock']},
|
|
936
936
|
),
|
|
937
937
|
stylex.props(
|
|
@@ -1122,8 +1122,8 @@ describe('DateInput clear icon theme target', () => {
|
|
|
1122
1122
|
// The canonical target lands on the icon element itself (not the button),
|
|
1123
1123
|
// so a theme can restyle just this glyph (color, size, hover) via
|
|
1124
1124
|
// `defineTheme` — a button-level target could not reach the icon's own
|
|
1125
|
-
// color/size. The original per-component name
|
|
1126
|
-
//
|
|
1125
|
+
// color/size. The original per-component name remains as a compatibility
|
|
1126
|
+
// alias.
|
|
1127
1127
|
const icon = getClearIcon();
|
|
1128
1128
|
expect(icon).toHaveClass('astryx-input-clear-icon');
|
|
1129
1129
|
expect(icon).toHaveClass('astryx-date-input-clear-icon');
|
|
@@ -1149,8 +1149,8 @@ describe('DateInput clear icon theme target', () => {
|
|
|
1149
1149
|
it('routes the clear glyph through the shared clear button, keeping the legacy target', () => {
|
|
1150
1150
|
// The clear affordance now composes the shared InputClearButton (a ghost
|
|
1151
1151
|
// Button with a secondary/sm glyph), so the icon carries the canonical
|
|
1152
|
-
// `astryx-input-clear-icon` target
|
|
1153
|
-
//
|
|
1152
|
+
// `astryx-input-clear-icon` target plus the supported compatibility alias
|
|
1153
|
+
// `astryx-date-input-clear-icon`. Aside from those target classes
|
|
1154
1154
|
// it matches the shared button's own `close`/`sm`/`secondary` glyph
|
|
1155
1155
|
// exactly, so the default look is defined in one place.
|
|
1156
1156
|
render(
|
|
@@ -619,10 +619,21 @@ function PointerDateField({
|
|
|
619
619
|
);
|
|
620
620
|
|
|
621
621
|
// Handle clear button click
|
|
622
|
-
const handleClear = useCallback(
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
622
|
+
const handleClear = useCallback(
|
|
623
|
+
(e?: React.MouseEvent<HTMLButtonElement>) => {
|
|
624
|
+
fireChange(undefined);
|
|
625
|
+
if (!e || e.detail === 0) {
|
|
626
|
+
inputRef.current?.focus();
|
|
627
|
+
} else {
|
|
628
|
+
// Defer focus restoration past the button's unmount task so iOS Safari
|
|
629
|
+
// and touch browsers don't jump the page scroll to 0 on tap.
|
|
630
|
+
requestAnimationFrame(() => {
|
|
631
|
+
inputRef.current?.focus({preventScroll: true});
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
[fireChange],
|
|
636
|
+
);
|
|
626
637
|
|
|
627
638
|
// Handle date selection from calendar
|
|
628
639
|
const handleDateSelect = useCallback(
|
|
@@ -628,8 +628,8 @@ describe('DateRangeInput icon theme targets', () => {
|
|
|
628
628
|
// The canonical target lands on the icon element itself (not the button),
|
|
629
629
|
// so a theme can restyle just this glyph (color, size, hover) via
|
|
630
630
|
// defineTheme — a button-level target could not reach the icon's own
|
|
631
|
-
// color/size. The original per-component name
|
|
632
|
-
//
|
|
631
|
+
// color/size. The original per-component name remains as a compatibility
|
|
632
|
+
// alias.
|
|
633
633
|
const icon = iconIn(getButton('Clear Range'));
|
|
634
634
|
expect(icon).toHaveClass('astryx-input-clear-icon');
|
|
635
635
|
expect(icon).toHaveClass('astryx-date-range-input-clear-icon');
|
|
@@ -2346,10 +2346,11 @@ describe('DateTimeInput', () => {
|
|
|
2346
2346
|
});
|
|
2347
2347
|
|
|
2348
2348
|
it('leaves both leading glyphs byte-identical to a plain secondary/sm icon by default', () => {
|
|
2349
|
-
// The targets are purely additive: the stable target class
|
|
2350
|
-
//
|
|
2351
|
-
//
|
|
2352
|
-
//
|
|
2349
|
+
// The targets are purely additive: the stable target class, reflected
|
|
2350
|
+
// state, and released bare-state compatibility class add nothing to the
|
|
2351
|
+
// render until a theme or consumer stylesheet targets them. Guard that by
|
|
2352
|
+
// diffing each glyph's StyleX classes against a standalone secondary/sm
|
|
2353
|
+
// icon, excluding only those additive theme metadata classes.
|
|
2353
2354
|
const {container} = render(
|
|
2354
2355
|
<DateTimeInput label="Meeting" onChange={() => {}} />,
|
|
2355
2356
|
);
|
|
@@ -2368,6 +2369,7 @@ describe('DateTimeInput', () => {
|
|
|
2368
2369
|
const themeTargetClasses = new Set([
|
|
2369
2370
|
'astryx-date-time-input-toggle-icon',
|
|
2370
2371
|
'astryx-date-time-input-clock-icon',
|
|
2372
|
+
'collapsed',
|
|
2371
2373
|
'expanded',
|
|
2372
2374
|
]);
|
|
2373
2375
|
const styleClasses = (el: HTMLElement) =>
|
|
@@ -1520,13 +1520,24 @@ function PointerDateTimeField({
|
|
|
1520
1520
|
);
|
|
1521
1521
|
|
|
1522
1522
|
// --- Clear ---
|
|
1523
|
-
const handleClear = useCallback(
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1523
|
+
const handleClear = useCallback(
|
|
1524
|
+
(e?: React.MouseEvent<HTMLButtonElement>) => {
|
|
1525
|
+
setNativeTimeDraft(undefined);
|
|
1526
|
+
fireChange(undefined);
|
|
1527
|
+
if (!usesNativePicker) {
|
|
1528
|
+
if (!e || e.detail === 0) {
|
|
1529
|
+
dateInputRef.current?.focus();
|
|
1530
|
+
} else {
|
|
1531
|
+
// Defer focus restoration past the button's unmount task so iOS Safari
|
|
1532
|
+
// and touch browsers don't jump the page scroll to 0 on tap.
|
|
1533
|
+
requestAnimationFrame(() => {
|
|
1534
|
+
dateInputRef.current?.focus({preventScroll: true});
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
[fireChange, usesNativePicker],
|
|
1540
|
+
);
|
|
1530
1541
|
|
|
1531
1542
|
// Focus time input when clicking wrapper padding/icon
|
|
1532
1543
|
const {onClick: handleTimeWrapperClick, onMouseUp: handleTimeWrapperMouseUp} =
|