@astryxdesign/core 0.4.3 → 0.4.4-canary.2022d94

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.
Files changed (156) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +79 -45
  3. package/dist/Banner/Banner.d.ts +3 -0
  4. package/dist/Banner/Banner.d.ts.map +1 -1
  5. package/dist/Banner/Banner.js +13 -3
  6. package/dist/BottomSheet/BottomSheet.d.ts +66 -0
  7. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -0
  8. package/dist/BottomSheet/BottomSheet.js +392 -0
  9. package/dist/BottomSheet/BottomSheetPanel.d.ts +60 -0
  10. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -0
  11. package/dist/BottomSheet/BottomSheetPanel.js +398 -0
  12. package/dist/BottomSheet/BottomSheetSwitcher.d.ts +61 -0
  13. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -0
  14. package/dist/BottomSheet/BottomSheetSwitcher.js +410 -0
  15. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts +21 -0
  16. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts.map +1 -0
  17. package/dist/BottomSheet/BottomSheetSwitcherContext.js +13 -0
  18. package/dist/BottomSheet/index.d.ts +11 -0
  19. package/dist/BottomSheet/index.d.ts.map +1 -0
  20. package/dist/BottomSheet/index.js +12 -0
  21. package/dist/BottomSheet/snapOffsets.d.ts +72 -0
  22. package/dist/BottomSheet/snapOffsets.d.ts.map +1 -0
  23. package/dist/BottomSheet/snapOffsets.js +130 -0
  24. package/dist/BottomSheet/useMobileKeyboard.d.ts +35 -0
  25. package/dist/BottomSheet/useMobileKeyboard.d.ts.map +1 -0
  26. package/dist/BottomSheet/useMobileKeyboard.js +373 -0
  27. package/dist/BottomSheet/useSheetGestures.d.ts +180 -0
  28. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -0
  29. package/dist/BottomSheet/useSheetGestures.js +989 -0
  30. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  31. package/dist/Chat/ChatComposerInput.js +3 -4
  32. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  33. package/dist/ComplexSelector/ComplexSelector.js +12 -6
  34. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  35. package/dist/ContextMenu/ContextMenu.js +4 -2
  36. package/dist/DateInput/DateInput.d.ts.map +1 -1
  37. package/dist/DateInput/DateInput.js +9 -1
  38. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  39. package/dist/DateTimeInput/DateTimeInput.js +31 -1
  40. package/dist/Dialog/Dialog.d.ts.map +1 -1
  41. package/dist/Dialog/Dialog.js +2 -1
  42. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  43. package/dist/Lightbox/Lightbox.js +9 -3
  44. package/dist/MobileNav/MobileNav.d.ts +12 -0
  45. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  46. package/dist/MobileNav/MobileNav.js +102 -30
  47. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  48. package/dist/MultiSelector/MultiSelector.js +21 -7
  49. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  50. package/dist/NumberInput/NumberInput.js +9 -1
  51. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  52. package/dist/Selector/Selector.d.ts.map +1 -1
  53. package/dist/Selector/Selector.js +14 -3
  54. package/dist/Switch/Switch.d.ts.map +1 -1
  55. package/dist/Switch/Switch.js +5 -1
  56. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  57. package/dist/TimeInput/TimeInput.js +8 -1
  58. package/dist/Tokenizer/Tokenizer.js +11 -5
  59. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  60. package/dist/Tooltip/useTooltip.js +4 -1
  61. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  62. package/dist/Typeahead/BaseTypeahead.js +5 -3
  63. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  64. package/dist/Typeahead/Typeahead.js +10 -1
  65. package/dist/astryx.css +21 -0
  66. package/dist/hooks/index.d.ts +8 -1
  67. package/dist/hooks/index.d.ts.map +1 -1
  68. package/dist/hooks/index.js +8 -1
  69. package/dist/hooks/useFocusTrap.d.ts +0 -11
  70. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  71. package/dist/hooks/useFocusTrap.js +1 -11
  72. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
  73. package/dist/hooks/useInputStatusIcon.js +1 -0
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +1 -0
  77. package/dist/theme/defineTheme.d.ts +22 -4
  78. package/dist/theme/defineTheme.d.ts.map +1 -1
  79. package/dist/theme/expandColorScale.d.ts +17 -2
  80. package/dist/theme/expandColorScale.d.ts.map +1 -1
  81. package/dist/theme/expandColorScale.js +63 -33
  82. package/dist/utils/ime.d.ts +5 -0
  83. package/dist/utils/ime.d.ts.map +1 -0
  84. package/dist/utils/ime.js +63 -0
  85. package/dist/utils/index.d.ts +1 -0
  86. package/dist/utils/index.d.ts.map +1 -1
  87. package/dist/utils/index.js +2 -1
  88. package/locales/en.json +48 -0
  89. package/locales/pseudo.json +36 -0
  90. package/package.json +9 -8
  91. package/src/Banner/Banner.doc.mjs +3 -3
  92. package/src/Banner/Banner.test.tsx +40 -0
  93. package/src/Banner/Banner.tsx +27 -2
  94. package/src/BottomSheet/BottomSheet.doc.mjs +266 -0
  95. package/src/BottomSheet/BottomSheet.test.tsx +2114 -0
  96. package/src/BottomSheet/BottomSheet.tsx +545 -0
  97. package/src/BottomSheet/BottomSheetPanel.test.tsx +240 -0
  98. package/src/BottomSheet/BottomSheetPanel.tsx +547 -0
  99. package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +219 -0
  100. package/src/BottomSheet/BottomSheetSwitcher.test.tsx +850 -0
  101. package/src/BottomSheet/BottomSheetSwitcher.tsx +628 -0
  102. package/src/BottomSheet/BottomSheetSwitcherContext.ts +51 -0
  103. package/src/BottomSheet/index.ts +15 -0
  104. package/src/BottomSheet/snapOffsets.test.ts +187 -0
  105. package/src/BottomSheet/snapOffsets.ts +159 -0
  106. package/src/BottomSheet/useMobileKeyboard.ts +499 -0
  107. package/src/BottomSheet/useSheetGestures.test.ts +1059 -0
  108. package/src/BottomSheet/useSheetGestures.ts +1459 -0
  109. package/src/Chat/ChatComposerInput.tsx +3 -4
  110. package/src/ComplexSelector/ComplexSelector.tsx +12 -5
  111. package/src/ContextMenu/ContextMenu.tsx +4 -2
  112. package/src/DateInput/DateInput.test.tsx +21 -0
  113. package/src/DateInput/DateInput.tsx +9 -1
  114. package/src/DateTimeInput/DateTimeInput.doc.mjs +4 -0
  115. package/src/DateTimeInput/DateTimeInput.test.tsx +137 -0
  116. package/src/DateTimeInput/DateTimeInput.tsx +39 -2
  117. package/src/Dialog/Dialog.tsx +2 -1
  118. package/src/FileInput/FileInput.test.tsx +53 -9
  119. package/src/Lightbox/Lightbox.test.tsx +49 -28
  120. package/src/Lightbox/Lightbox.tsx +7 -3
  121. package/src/MobileNav/MobileNav.tsx +128 -37
  122. package/src/MobileNav/MobileNavCloseEdgeCases.test.tsx +426 -0
  123. package/src/MobileNav/MobileNavCloseTiming.test.ts +58 -0
  124. package/src/MobileNav/MobileNavCloseVisibility.test.tsx +172 -0
  125. package/src/MultiSelector/MultiSelector.test.tsx +195 -51
  126. package/src/MultiSelector/MultiSelector.tsx +22 -8
  127. package/src/NumberInput/NumberInput.test.tsx +18 -0
  128. package/src/NumberInput/NumberInput.tsx +9 -1
  129. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  130. package/src/Selector/Selector.test.tsx +85 -26
  131. package/src/Selector/Selector.tsx +13 -4
  132. package/src/Switch/Switch.test.tsx +16 -0
  133. package/src/Switch/Switch.tsx +7 -0
  134. package/src/TimeInput/TimeInput.test.tsx +23 -0
  135. package/src/TimeInput/TimeInput.tsx +8 -0
  136. package/src/Tokenizer/Tokenizer.test.tsx +50 -32
  137. package/src/Tokenizer/Tokenizer.tsx +5 -5
  138. package/src/Tooltip/useTooltip.tsx +4 -1
  139. package/src/Typeahead/BaseTypeahead.tsx +10 -3
  140. package/src/Typeahead/Typeahead.test.tsx +116 -7
  141. package/src/Typeahead/Typeahead.tsx +10 -1
  142. package/src/__tests__/stubMatchMedia.test.ts +79 -0
  143. package/src/__tests__/stubMatchMedia.ts +95 -0
  144. package/src/hooks/index.ts +9 -5
  145. package/src/hooks/useFocusTrap.ts +1 -14
  146. package/src/hooks/useInputStatusIcon.test.tsx +19 -0
  147. package/src/hooks/useInputStatusIcon.tsx +7 -0
  148. package/src/index.ts +1 -0
  149. package/src/theme/defineTheme.ts +22 -4
  150. package/src/theme/expandColorScale.test.ts +138 -0
  151. package/src/theme/expandColorScale.ts +89 -44
  152. package/src/utils/ime.test.ts +32 -0
  153. package/src/utils/ime.ts +69 -0
  154. package/src/utils/index.ts +2 -0
  155. package/dist/astryx.umd.js +0 -147
  156. package/dist/astryx.umd.js.map +0 -7
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ export * from "./AvatarGroup/index.js";
20
20
  export * from "./Badge/index.js";
21
21
  export * from "./Banner/index.js";
22
22
  export * from "./Blockquote/index.js";
23
+ export * from "./BottomSheet/index.js";
23
24
  export * from "./Breadcrumbs/index.js";
24
25
  export * from "./Button/index.js";
25
26
  export * from "./ButtonGroup/index.js";
@@ -194,20 +194,38 @@ export interface DefineThemeInput {
194
194
  */
195
195
  radius?: RadiusScaleConfig;
196
196
  /**
197
- * Color scale configuration. Generates color token overrides from a
198
- * single accent color using the HCT perceptual color model.
197
+ * Color scale configuration. Generates color token overrides from an
198
+ * accent seed using the HCT perceptual color model.
199
199
  *
200
200
  * Only generates tokens derivable from the accent — status colors,
201
201
  * categorical hues, and fixed tokens (on-dark/on-light) use defaults.
202
- * Explicit `tokens` entries always take precedence.
202
+ *
203
+ * `accent` accepts a single hex (same seed for both color schemes) or a
204
+ * `[light, dark]` tuple, matching `TokenValue`. With a tuple, the light
205
+ * scheme's full palette derives from the light seed and the dark
206
+ * scheme's from the dark seed.
203
207
  *
204
208
  * `accent` is optional — omit it for a neutral-only theme, which keeps
205
209
  * the default accent tokens and only themes the neutrals.
206
210
  *
211
+ * Precedence vs `tokens`: explicit `tokens` entries win over generated
212
+ * values, token by token. Because `--color-accent-muted`,
213
+ * `--color-text-accent` and `--color-icon-accent` are generated as
214
+ * `var(--color-accent)` references, a `tokens['--color-accent']`
215
+ * override re-points them at runtime. `--color-on-accent` does NOT
216
+ * follow: it is baked from the `color.accent` seed (a contrast
217
+ * computation CSS cannot express), so overriding the accent through
218
+ * `tokens` without also overriding `--color-on-accent` leaves the two
219
+ * out of sync. To re-seat the whole palette per scheme, prefer a tuple
220
+ * `color.accent` over the `tokens['--color-accent']` workaround.
221
+ *
207
222
  * @example
208
- * ```tsx
223
+ * ```
209
224
  * color: { accent: '#0064E0', neutralStyle: 'cool', contrast: 'standard' }
210
225
  *
226
+ * // Per-scheme accents — light palette from the first seed, dark from the second
227
+ * color: { accent: ['#0064E0', '#48CAE4'] }
228
+ *
211
229
  * // Neutral-only — accent tokens stay at their defaults
212
230
  * color: { neutralStyle: 'warm' }
213
231
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"defineTheme.d.ts","sourceRoot":"","sources":["../../src/theme/defineTheme.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"defineTheme.d.ts","sourceRoot":"","sources":["../../src/theme/defineTheme.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,9 @@
6
6
  * // Minimal — just a seed color
7
7
  * { accent: '#0064E0' }
8
8
  *
9
+ * // Per-scheme seeds: light palettes from '#0064E0', dark from '#48CAE4'
10
+ * { accent: ['#0064E0', '#48CAE4'] }
11
+ *
9
12
  * // With customization
10
13
  * { accent: '#B7410E', neutralStyle: 'warm', contrast: 'high' }
11
14
  *
@@ -15,14 +18,18 @@
15
18
  */
16
19
  export interface ColorScaleConfig {
17
20
  /**
18
- * Seed accent color as hex (#RRGGBB). Everything derives from this.
21
+ * Seed accent color. Everything derives from this.
22
+ *
23
+ * Either a single hex (#RRGGBB) used for both color schemes, or a
24
+ * `[light, dark]` hex tuple: the light scheme's palettes derive from
25
+ * the light seed and the dark scheme's palettes from the dark seed.
19
26
  *
20
27
  * Optional. When omitted, the neutral palettes are seeded from the
21
28
  * default accent's hue and the accent tokens (--color-accent,
22
29
  * --color-accent-muted, --color-on-accent) are not generated — they
23
30
  * fall through to colorDefaults.
24
31
  */
25
- accent?: string;
32
+ accent?: string | [light: string, dark: string];
26
33
  /**
27
34
  * Neutral tone warmth. Controls how much of the seed's hue bleeds
28
35
  * into neutral/background colors.
@@ -56,6 +63,11 @@ export declare function ensureContrastTone(hue: number, chroma: number, startTon
56
63
  * --color-on-dark/on-light) are NOT generated — they fall through
57
64
  * to colorDefaults.
58
65
  *
66
+ * A `[light, dark]` tuple accent seeds each scheme separately: the light
67
+ * half of every generated `light-dark()` pair comes from the light seed's
68
+ * palettes, the dark half from the dark seed's. A string accent seeds both
69
+ * halves from the same palettes, exactly as before tuples were supported.
70
+ *
59
71
  * Without an `accent`, the accent tokens join that fall-through set: the
60
72
  * neutrals are seeded from the default accent's hue, and --color-accent,
61
73
  * --color-accent-muted and --color-on-accent keep their colorDefaults values.
@@ -65,6 +77,9 @@ export declare function ensureContrastTone(hue: number, chroma: number, startTon
65
77
  * const tokens = expandColorScale({ accent: '#0064E0' });
66
78
  * // tokens['--color-accent'] === 'light-dark(#..., #...)'
67
79
  *
80
+ * const perScheme = expandColorScale({ accent: ['#0064E0', '#48CAE4'] });
81
+ * // light half derives from #0064E0, dark half from #48CAE4
82
+ *
68
83
  * const neutralOnly = expandColorScale({ neutralStyle: 'warm' });
69
84
  * // neutralOnly['--color-accent'] === undefined
70
85
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"expandColorScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandColorScale.ts"],"names":[],"mappings":"AAwCA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAE3C;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAyCtD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAYR;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAoI3E"}
1
+ {"version":3,"file":"expandColorScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandColorScale.ts"],"names":[],"mappings":"AAgDA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAEhD;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAE3C;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAyCtD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAYR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CA0J3E"}
@@ -6,8 +6,8 @@
6
6
  * @output Token overrides for derivable color tokens
7
7
  * @position Theme utility; consumed by defineTheme.ts
8
8
  *
9
- * Generates color token overrides from a single accent color using the
10
- * HCT perceptual color model. Only produces tokens that meaningfully
9
+ * Generates color token overrides from an accent seed using the HCT
10
+ * perceptual color model. Only produces tokens that meaningfully
11
11
  * derive from the accent — status colors, categorical hues, and fixed
12
12
  * tokens (on-dark/on-light) fall through to colorDefaults.
13
13
  *
@@ -15,11 +15,19 @@
15
15
  * ramp (seeded from the default accent's hue) while the accent tokens
16
16
  * themselves fall through to colorDefaults, same as the tokens above.
17
17
  *
18
+ * `accent` also accepts a `[light, dark]` tuple (matching `TokenValue` in
19
+ * defineTheme). A tuple seeds each color scheme from its own half: the
20
+ * light side of every generated `light-dark()` pair derives from the light
21
+ * accent's palettes, the dark side from the dark accent's. A plain string
22
+ * seeds both sides identically, token for token the same output as before
23
+ * tuples existed.
24
+ *
18
25
  * WCAG contrast guarantees (asserted in expandColorScale.test.ts):
19
26
  * - Text tones are guaranteed >= 4.5:1 against their surfaces by tone
20
27
  * spacing alone — HCT tone is CIE L*, which fixes relative luminance
21
28
  * regardless of hue/chroma, so the fixed tone assignments hold for any
22
- * accent/neutralStyle (WCAG 1.4.3).
29
+ * accent/neutralStyle (WCAG 1.4.3), and each half of a tuple pairs with
30
+ * surfaces derived from that same seed.
23
31
  * - --color-border-emphasized (form-control boundaries) is tone-bumped
24
32
  * until it reaches >= 3:1 against the generated surface (WCAG 1.4.11).
25
33
  * - --color-border, --color-skeleton, and --color-track are intentionally
@@ -46,6 +54,9 @@ import { hexToHct, hctToHex, tonalPalette, hexWithAlpha } from "./hct.js";
46
54
  * // Minimal — just a seed color
47
55
  * { accent: '#0064E0' }
48
56
  *
57
+ * // Per-scheme seeds: light palettes from '#0064E0', dark from '#48CAE4'
58
+ * { accent: ['#0064E0', '#48CAE4'] }
59
+ *
49
60
  * // With customization
50
61
  * { accent: '#B7410E', neutralStyle: 'warm', contrast: 'high' }
51
62
  *
@@ -126,6 +137,11 @@ export function ensureContrastTone(hue, chroma, startTone, step, background, min
126
137
  * --color-on-dark/on-light) are NOT generated — they fall through
127
138
  * to colorDefaults.
128
139
  *
140
+ * A `[light, dark]` tuple accent seeds each scheme separately: the light
141
+ * half of every generated `light-dark()` pair comes from the light seed's
142
+ * palettes, the dark half from the dark seed's. A string accent seeds both
143
+ * halves from the same palettes, exactly as before tuples were supported.
144
+ *
129
145
  * Without an `accent`, the accent tokens join that fall-through set: the
130
146
  * neutrals are seeded from the default accent's hue, and --color-accent,
131
147
  * --color-accent-muted and --color-on-accent keep their colorDefaults values.
@@ -135,6 +151,9 @@ export function ensureContrastTone(hue, chroma, startTone, step, background, min
135
151
  * const tokens = expandColorScale({ accent: '#0064E0' });
136
152
  * // tokens['--color-accent'] === 'light-dark(#..., #...)'
137
153
  *
154
+ * const perScheme = expandColorScale({ accent: ['#0064E0', '#48CAE4'] });
155
+ * // light half derives from #0064E0, dark half from #48CAE4
156
+ *
138
157
  * const neutralOnly = expandColorScale({ neutralStyle: 'warm' });
139
158
  * // neutralOnly['--color-accent'] === undefined
140
159
  * ```
@@ -145,14 +164,26 @@ export function expandColorScale(config) {
145
164
  neutralStyle = 'cool',
146
165
  contrast = 'standard'
147
166
  } = config;
148
- const seed = hexToHct(accent ?? DEFAULT_ACCENT_SEED);
149
- const seedHue = seed.hue;
150
- const primaryChroma = Math.max(seed.chroma, 48);
167
+
168
+ // Normalize to per-scheme seeds. A string accent (or an absent one) uses
169
+ // the same seed for both halves, which keeps single-seed output identical
170
+ // to the pre-tuple implementation.
171
+ const [lightAccent, darkAccent] = Array.isArray(accent) ? accent : [accent, accent];
172
+ const lightSeed = hexToHct(lightAccent ?? DEFAULT_ACCENT_SEED);
173
+ const sameSeed = darkAccent === lightAccent;
174
+ const darkSeed = sameSeed ? lightSeed : hexToHct(darkAccent ?? DEFAULT_ACCENT_SEED);
151
175
  const neutralChroma = NEUTRAL_CHROMA[neutralStyle] ?? 5;
152
176
  const neutralVariantChroma = NEUTRAL_VARIANT_CHROMA[neutralStyle] ?? 8;
153
- const P = tonalPalette(seedHue, primaryChroma);
154
- const N = tonalPalette(seedHue, neutralChroma);
155
- const NV = tonalPalette(seedHue, neutralVariantChroma);
177
+
178
+ // Palette naming: *L palettes feed the light (first) half of each ld()
179
+ // pair below, *D palettes the dark (second) half. With a single seed the
180
+ // D palettes alias the L ones.
181
+ const PL = tonalPalette(lightSeed.hue, Math.max(lightSeed.chroma, 48));
182
+ const NL = tonalPalette(lightSeed.hue, neutralChroma);
183
+ const NVL = tonalPalette(lightSeed.hue, neutralVariantChroma);
184
+ const PD = sameSeed ? PL : tonalPalette(darkSeed.hue, Math.max(darkSeed.chroma, 48));
185
+ const ND = sameSeed ? NL : tonalPalette(darkSeed.hue, neutralChroma);
186
+ const NVD = sameSeed ? NVL : tonalPalette(darkSeed.hue, neutralVariantChroma);
156
187
  const isHigh = contrast === 'high';
157
188
  const textPrimaryLightTone = isHigh ? 0 : 10;
158
189
  const textPrimaryDarkTone = isHigh ? 99 : 90;
@@ -173,7 +204,7 @@ export function expandColorScale(config) {
173
204
  // contrast starts at 70/30 and walks toward mid-scale only as far as needed.
174
205
  const borderEmphasizedStartLight = isHigh ? 50 : 70;
175
206
  const borderEmphasizedStartDark = isHigh ? 50 : 30;
176
- const borderEmphasized = ld(ensureContrastTone(seedHue, neutralVariantChroma, borderEmphasizedStartLight, -1, N[99], NON_TEXT_MIN_CONTRAST), ensureContrastTone(seedHue, neutralVariantChroma, borderEmphasizedStartDark, 1, N[10], NON_TEXT_MIN_CONTRAST));
207
+ const borderEmphasized = ld(ensureContrastTone(lightSeed.hue, neutralVariantChroma, borderEmphasizedStartLight, -1, NL[99], NON_TEXT_MIN_CONTRAST), ensureContrastTone(darkSeed.hue, neutralVariantChroma, borderEmphasizedStartDark, 1, ND[10], NON_TEXT_MIN_CONTRAST));
177
208
  return {
178
209
  // Core semantic — only with a seed accent. Without one these fall through
179
210
  // to colorDefaults, whose --color-accent is NOT what the default seed
@@ -181,47 +212,46 @@ export function expandColorScale(config) {
181
212
  // recolor every neutral-only theme. Nullish and not truthy, matching the
182
213
  // seed above, so a supplied-but-malformed accent keeps its old behavior.
183
214
  ...(accent != null ? {
184
- '--color-accent': ld(P[40], P[80]),
215
+ '--color-accent': ld(PL[40], PD[80]),
185
216
  // Derived accent tokens reference --color-accent instead of baking its
186
217
  // resolved hex, so a scoped override of the base token re-accents the
187
218
  // whole subtree at runtime. --color-on-accent stays baked: it is a
188
219
  // contrast computation against the accent, which CSS cannot express.
189
220
  '--color-accent-muted': ld(accentWithAlpha(0.2), accentWithAlpha(0.25)),
190
- '--color-on-accent': ld(P[100], P[20])
221
+ '--color-on-accent': ld(PL[100], PD[20])
191
222
  } : null),
192
- '--color-neutral': ld(hexWithAlpha(N[10], 0.1), hexWithAlpha(N[90], 0.2)),
193
- '--color-background-surface': ld(N[99], N[10]),
194
- '--color-background-body': ld(N[95], N[5]),
195
- '--color-overlay': ld(hexWithAlpha(N[10], 0.4), hexWithAlpha(N[10], 0.6)),
196
- '--color-overlay-hover': ld(hexWithAlpha(N[10], 0.05), hexWithAlpha(N[100], 0.05)),
197
- '--color-overlay-pressed': ld(hexWithAlpha(N[10], 0.1), hexWithAlpha(N[100], 0.1)),
198
- '--color-background-muted': ld(hexWithAlpha(N[10], 0.05), hexWithAlpha(N[10], 0.5)),
223
+ '--color-neutral': ld(hexWithAlpha(NL[10], 0.1), hexWithAlpha(ND[90], 0.2)),
224
+ '--color-background-surface': ld(NL[99], ND[10]),
225
+ '--color-background-body': ld(NL[95], ND[5]),
226
+ '--color-overlay': ld(hexWithAlpha(NL[10], 0.4), hexWithAlpha(ND[10], 0.6)),
227
+ '--color-overlay-hover': ld(hexWithAlpha(NL[10], 0.05), hexWithAlpha(ND[100], 0.05)),
228
+ '--color-overlay-pressed': ld(hexWithAlpha(NL[10], 0.1), hexWithAlpha(ND[100], 0.1)),
229
+ '--color-background-muted': ld(hexWithAlpha(NL[10], 0.05), hexWithAlpha(ND[10], 0.5)),
199
230
  // Text
200
- '--color-text-primary': ld(N[textPrimaryLightTone], N[textPrimaryDarkTone]),
201
- '--color-text-secondary': ld(NV[textSecondaryLightTone], NV[textSecondaryDarkTone]),
202
- '--color-text-disabled': ld(NV[60], NV[40]),
231
+ '--color-text-primary': ld(NL[textPrimaryLightTone], ND[textPrimaryDarkTone]),
232
+ '--color-text-secondary': ld(NVL[textSecondaryLightTone], NVD[textSecondaryDarkTone]),
233
+ '--color-text-disabled': ld(NVL[60], NVD[40]),
203
234
  '--color-text-accent': 'var(--color-accent)',
204
235
  // Icon
205
236
  '--color-icon-accent': 'var(--color-accent)',
206
- '--color-icon-primary': ld(N[textPrimaryLightTone], N[textPrimaryDarkTone]),
207
- '--color-icon-secondary': ld(NV[textSecondaryLightTone], NV[textSecondaryDarkTone]),
208
- '--color-icon-disabled': ld(NV[60], NV[40]),
237
+ '--color-icon-primary': ld(NL[textPrimaryLightTone], ND[textPrimaryDarkTone]),
238
+ '--color-icon-secondary': ld(NVL[textSecondaryLightTone], NVD[textSecondaryDarkTone]),
239
+ '--color-icon-disabled': ld(NVL[60], NVD[40]),
209
240
  // Surface variants
210
- '--color-background-card': ld(N[99], N[10]),
211
- '--color-background-popover': ld(N[99], N[20]),
212
- '--color-background-inverted': ld(N[10], N[99]),
213
- // Border
241
+ '--color-background-card': ld(NL[99], ND[10]),
242
+ '--color-background-popover': ld(NL[99], ND[20]),
243
+ '--color-background-inverted': ld(NL[10], ND[99]),
214
244
  // Border
215
245
  // Decorative hairline — not a WCAG 1.4.11 boundary. High contrast
216
246
  // doubles the alpha so structural boundaries stay perceivable.
217
- '--color-border': ld(hexWithAlpha(N[10], borderSubtleAlpha), hexWithAlpha(N[95], borderSubtleAlpha)),
247
+ '--color-border': ld(hexWithAlpha(NL[10], borderSubtleAlpha), hexWithAlpha(ND[95], borderSubtleAlpha)),
218
248
  '--color-border-emphasized': borderEmphasized,
219
249
  // Effects
220
- '--color-skeleton': ld(NV[70], NV[30]),
250
+ '--color-skeleton': ld(NVL[70], NVD[30]),
221
251
  // Channel-on-body surface (ProgressBar/Slider tracks, Switch off-state).
222
252
  // Defaults to the same NV[70]/NV[30] ramp stop as --color-skeleton.
223
- '--color-track': ld(NV[70], NV[30]),
224
- '--color-shadow': ld(hexWithAlpha(N[0], 0.1), hexWithAlpha(N[0], 0.3)),
253
+ '--color-track': ld(NVL[70], NVD[30]),
254
+ '--color-shadow': ld(hexWithAlpha(NL[0], 0.1), hexWithAlpha(ND[0], 0.3)),
225
255
  '--color-tint-hover': ld('black', 'white')
226
256
  };
227
257
  }
@@ -0,0 +1,5 @@
1
+ export declare function isImeKeyEvent(event: {
2
+ isComposing?: boolean;
3
+ keyCode?: number;
4
+ }): boolean;
5
+ //# sourceMappingURL=ime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ime.d.ts","sourceRoot":"","sources":["../../src/utils/ime.ts"],"names":[],"mappings":"AA6DA,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAIV"}
@@ -0,0 +1,63 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file ime.ts
5
+ * @input Receives a keyboard event (React SyntheticEvent's `nativeEvent`, or a
6
+ * native DOM KeyboardEvent) with optional `isComposing` / `keyCode`.
7
+ * @output Exports `isImeKeyEvent`, the canonical predicate for "this keydown is
8
+ * part of an in-progress IME composition and must not be treated as a command".
9
+ * @position Shared low-level utility; consumed by every editable/overlay surface
10
+ * that handles Enter/Escape/arrows in `onKeyDown` (Typeahead, PowerSearch,
11
+ * Dialog, ContextMenu, Tooltip, Chat composer, focus-trap Escape, ...).
12
+ *
13
+ * ── Why this exists (read once, here — do not re-explain at call sites) ──
14
+ *
15
+ * When a CJK user (Korean / Japanese / Chinese) is composing text via an IME,
16
+ * the browser fires a `keydown` event to COMMIT or CANCEL the pending
17
+ * composition (Enter commits the highlighted candidate; Escape cancels it;
18
+ * ArrowUp/Down/Home/End navigate the candidate window). Crucially this
19
+ * `keydown` fires BEFORE the `compositionend` event that actually writes the
20
+ * committed text into the field. So a naive `onKeyDown` handler sees a bare
21
+ * "Enter" or "Escape" and misreads the composition-commit/cancel as an
22
+ * application command — accepting a typeahead suggestion, submitting a chat
23
+ * message, closing a dialog/menu/tooltip, or saving a filter — mid-composition.
24
+ * The fix is to detect the composing keydown and early-return before running
25
+ * any command logic.
26
+ *
27
+ * Two signals, both needed:
28
+ *
29
+ * 1. `event.isComposing === true` — the modern, spec'd signal
30
+ * (https://www.w3.org/TR/uievents/#dom-keyboardevent-iscomposing). This is
31
+ * the primary check and is reliable in current evergreen browsers.
32
+ *
33
+ * 2. `event.keyCode === 229` — the legacy fallback. `229` is the sentinel
34
+ * keyCode browsers report for "the key event is being processed by an IME".
35
+ * It is still load-bearing: some IMEs and older Safari fire the composing
36
+ * `keydown` with `isComposing` NOT yet set to `true`, but DO report
37
+ * keyCode 229. Keeping both makes the guard robust across the browser
38
+ * matrix we support. Do not drop the 229 fallback without a browser-matrix
39
+ * audit.
40
+ *
41
+ * ── Which event object to pass ──
42
+ *
43
+ * React's SyntheticEvent for KeyboardEvent *does* surface `isComposing`, but to
44
+ * avoid any cross-browser normalization gap prefer passing the *native* event
45
+ * (`e.nativeEvent`) from React handlers — that is what BaseTypeahead,
46
+ * PowerSearch, and the Chat composer do. Native DOM listeners (Dialog,
47
+ * ContextMenu, Tooltip, focus-trap) pass the DOM `KeyboardEvent` directly.
48
+ * The parameter is intentionally structurally typed so both shapes are accepted.
49
+ *
50
+ * Note: `keyCode` is deprecated on the DOM `KeyboardEvent` type but is still
51
+ * present at runtime; we read it defensively via the optional structural field.
52
+ */
53
+
54
+ /**
55
+ * The sentinel `keyCode` browsers report while a key event is being processed
56
+ * by an IME (the composing keydown that fires before `compositionend`). See the
57
+ * file header for why this legacy signal is still load-bearing alongside
58
+ * `isComposing`.
59
+ */
60
+ const IME_PROCESSING_KEY_CODE = 229;
61
+ export function isImeKeyEvent(event) {
62
+ return event.isComposing === true || event.keyCode === IME_PROCESSING_KEY_CODE;
63
+ }
@@ -31,4 +31,5 @@ export type { RGBA } from './color';
31
31
  export { devWarn, devError, warnOnce, formatDevMessage } from './devWarning';
32
32
  export { rtlStyles } from './rtlStyles';
33
33
  export { focusOutlineStyles, focusOutlineProps } from './focusOutline.stylex';
34
+ export { isImeKeyEvent } from './ime';
34
35
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,YAAY,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAEvC,YAAY,EAAC,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,aAAa,CAAC;AAEhF,OAAO,EACL,cAAc,EACd,SAAS,EACT,QAAQ,EACR,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,8BAA8B,EAC9B,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,aAAa,EACb,SAAS,EACT,UAAU,EACV,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,MAAM,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAC,MAAM,UAAU,CAAC;AAE5D,OAAO,EAAC,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhF,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,cAAc,CAAC;AAC7D,YAAY,EACV,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,UAAU,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AACtD,YAAY,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAC,aAAa,EAAE,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AACzC,YAAY,EAAC,SAAS,EAAE,mBAAmB,EAAC,MAAM,aAAa,CAAC;AAEhE,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,YAAY,EAAC,IAAI,EAAC,MAAM,SAAS,CAAC;AAElC,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAItC,OAAO,EAAC,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,YAAY,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAEvC,YAAY,EAAC,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,aAAa,CAAC;AAEhF,OAAO,EACL,cAAc,EACd,SAAS,EACT,QAAQ,EACR,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,8BAA8B,EAC9B,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,aAAa,EACb,SAAS,EACT,UAAU,EACV,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,MAAM,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAC,MAAM,UAAU,CAAC;AAE5D,OAAO,EAAC,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhF,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,cAAc,CAAC;AAC7D,YAAY,EACV,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,UAAU,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AACtD,YAAY,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAC,aAAa,EAAE,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AACzC,YAAY,EAAC,SAAS,EAAE,mBAAmB,EAAC,MAAM,aAAa,CAAC;AAEhE,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,YAAY,EAAC,IAAI,EAAC,MAAM,SAAS,CAAC;AAElC,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAItC,OAAO,EAAC,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAE5E,OAAO,EAAC,aAAa,EAAC,MAAM,OAAO,CAAC"}
@@ -28,4 +28,5 @@ export { rtlStyles } from "./rtlStyles.js";
28
28
 
29
29
  // The shared focus ring, exported for @astryxdesign/lab — same reason
30
30
  // rtlStyles is: a style that must be identical across packages, not copied.
31
- export { focusOutlineStyles, focusOutlineProps } from "./focusOutline.stylex.js";
31
+ export { focusOutlineStyles, focusOutlineProps } from "./focusOutline.stylex.js";
32
+ export { isImeKeyEvent } from "./ime.js";
package/locales/en.json CHANGED
@@ -1134,5 +1134,53 @@
1134
1134
  "@astryx.commandPalette.footer.close": {
1135
1135
  "defaultMessage": "Close",
1136
1136
  "description": "Keyboard hint in the CommandPalette footer, paired with the Escape key icon. Tells users Escape dismisses the palette."
1137
+ },
1138
+ "@astryx.multiSelector.selectionCleared": {
1139
+ "defaultMessage": "Selection cleared",
1140
+ "description": "Polite screen-reader announcement after the last selected option in a MultiSelector is deselected. Live-region text, never shown on screen; past participle (\"has been cleared\")."
1141
+ },
1142
+ "@astryx.multiSelector.allSelected": {
1143
+ "defaultMessage": "All selected",
1144
+ "description": "Polite screen-reader announcement after every option in a MultiSelector becomes selected. Live-region text, never shown on screen; \"all\" is a determiner (as in \"all the options\")."
1145
+ },
1146
+ "@astryx.multiSelector.selectionCount": {
1147
+ "defaultMessage": "{count, number} of {total, number} selected",
1148
+ "description": "Polite screen-reader announcement of how many MultiSelector options are selected out of the total, spoken after each toggle. Live-region text, never shown on screen; example: `3 of 12 selected`."
1149
+ },
1150
+ "@astryx.multiSelector.emptySearchResults": {
1151
+ "defaultMessage": "No results found",
1152
+ "description": "Polite screen-reader announcement when a MultiSelector search query matches no options. Live-region text, never shown on screen; neutral tone (not error-y)."
1153
+ },
1154
+ "@astryx.multiSelector.resultCount": {
1155
+ "defaultMessage": "{count, number} {count, plural, one {result} other {results}}",
1156
+ "description": "Polite screen-reader announcement of how many MultiSelector options match the search query, spoken as the user types. Live-region text, never shown on screen; example: `1 result`, `12 results`."
1157
+ },
1158
+ "@astryx.selector.emptySearchResults": {
1159
+ "defaultMessage": "No results found",
1160
+ "description": "Polite screen-reader announcement when a Selector search query matches no options. Live-region text, never shown on screen; neutral tone (not error-y)."
1161
+ },
1162
+ "@astryx.selector.resultCount": {
1163
+ "defaultMessage": "{count, number} {count, plural, one {result} other {results}}",
1164
+ "description": "Polite screen-reader announcement of how many Selector options match the search query, spoken as the user types. Live-region text, never shown on screen; example: `1 result`, `12 results`."
1165
+ },
1166
+ "@astryx.typeahead.resultCount": {
1167
+ "defaultMessage": "{count, number} {count, plural, one {result} other {results}}",
1168
+ "description": "Polite screen-reader announcement of how many suggestions a Typeahead search returned. Live-region text, never shown on screen; example: `1 result`, `12 results`."
1169
+ },
1170
+ "@astryx.tokenizer.tokenAdded": {
1171
+ "defaultMessage": "Added {label}",
1172
+ "description": "Polite screen-reader announcement after a token is added to a Tokenizer, either picked from the suggestions or newly created. Live-region text, never shown on screen; `{label}` is the token's visible text."
1173
+ },
1174
+ "@astryx.tokenizer.tokenRemoved": {
1175
+ "defaultMessage": "Removed {label}",
1176
+ "description": "Polite screen-reader announcement after a token is removed from a Tokenizer, by its × button or by Backspace. Live-region text, never shown on screen; `{label}` is the token's visible text."
1177
+ },
1178
+ "@astryx.lightbox.imagePosition": {
1179
+ "defaultMessage": "Image {index, number} of {total, number}",
1180
+ "description": "Polite screen-reader announcement when a Lightbox moves to a media item that has no alt text. Live-region text, never shown on screen; `{index}` is 1-based, example: `Image 3 of 12`."
1181
+ },
1182
+ "@astryx.lightbox.mediaPosition": {
1183
+ "defaultMessage": "{alt}, {index, number} of {total, number}",
1184
+ "description": "Polite screen-reader announcement when a Lightbox moves to a media item that has alt text, composing that alt with the item's position. Live-region text, never shown on screen; example: `Sunset over the bay, 3 of 12`."
1137
1185
  }
1138
1186
  }
@@ -850,5 +850,41 @@
850
850
  },
851
851
  "@astryx.commandPalette.footer.close": {
852
852
  "defaultMessage": "⟦Çłóšé⟧"
853
+ },
854
+ "@astryx.multiSelector.selectionCleared": {
855
+ "defaultMessage": "⟦Šéłéçţíóñ çłéàřéð⟧"
856
+ },
857
+ "@astryx.multiSelector.allSelected": {
858
+ "defaultMessage": "⟦Àłł šéłéçţéð⟧"
859
+ },
860
+ "@astryx.multiSelector.selectionCount": {
861
+ "defaultMessage": "⟦{count, number} óƒ {total, number} šéłéçţéð⟧"
862
+ },
863
+ "@astryx.multiSelector.emptySearchResults": {
864
+ "defaultMessage": "⟦Ñó řéšúłţš ƒóúñð⟧"
865
+ },
866
+ "@astryx.multiSelector.resultCount": {
867
+ "defaultMessage": "⟦{count, number} {count, plural, one {result} other {results}}⟧"
868
+ },
869
+ "@astryx.selector.emptySearchResults": {
870
+ "defaultMessage": "⟦Ñó řéšúłţš ƒóúñð⟧"
871
+ },
872
+ "@astryx.selector.resultCount": {
873
+ "defaultMessage": "⟦{count, number} {count, plural, one {result} other {results}}⟧"
874
+ },
875
+ "@astryx.typeahead.resultCount": {
876
+ "defaultMessage": "⟦{count, number} {count, plural, one {result} other {results}}⟧"
877
+ },
878
+ "@astryx.tokenizer.tokenAdded": {
879
+ "defaultMessage": "⟦Àððéð {label}⟧"
880
+ },
881
+ "@astryx.tokenizer.tokenRemoved": {
882
+ "defaultMessage": "⟦Řéɱóṽéð {label}⟧"
883
+ },
884
+ "@astryx.lightbox.imagePosition": {
885
+ "defaultMessage": "⟦Íɱàĝé {index, number} óƒ {total, number}⟧"
886
+ },
887
+ "@astryx.lightbox.mediaPosition": {
888
+ "defaultMessage": "⟦{alt}, {index, number} óƒ {total, number}⟧"
853
889
  }
854
890
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.4.3",
3
+ "version": "0.4.4-canary.2022d94",
4
4
  "displayName": "Astryx Core",
5
5
  "description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
6
6
  "author": "Meta Open Source",
@@ -27,8 +27,6 @@
27
27
  "type": "module",
28
28
  "main": "./dist/index.js",
29
29
  "types": "./dist/index.d.ts",
30
- "unpkg": "./dist/astryx.umd.js",
31
- "jsdelivr": "./dist/astryx.umd.js",
32
30
  "sideEffects": [
33
31
  "**/*.stylex.ts",
34
32
  "**/*.stylex.js",
@@ -49,7 +47,6 @@
49
47
  "types": "./src/astryx.css.d.ts",
50
48
  "default": "./dist/astryx.css"
51
49
  },
52
- "./astryx.umd.js": "./dist/astryx.umd.js",
53
50
  "./tailwind-theme.css": {
54
51
  "types": "./src/tailwind-theme.css.d.ts",
55
52
  "default": "./src/tailwind-theme.css"
@@ -122,6 +119,11 @@
122
119
  "types": "./dist/Blockquote/index.d.ts",
123
120
  "default": "./dist/Blockquote/index.js"
124
121
  },
122
+ "./BottomSheet": {
123
+ "source": "./src/BottomSheet/index.ts",
124
+ "types": "./dist/BottomSheet/index.d.ts",
125
+ "default": "./dist/BottomSheet/index.js"
126
+ },
125
127
  "./Breadcrumbs": {
126
128
  "source": "./src/Breadcrumbs/index.ts",
127
129
  "types": "./dist/Breadcrumbs/index.d.ts",
@@ -654,6 +656,7 @@
654
656
  "react-dom": ">=19.0.0"
655
657
  },
656
658
  "devDependencies": {
659
+ "@astryxdesign/cli": "0.4.4-canary.2022d94",
657
660
  "@babel/cli": "^8.0.4",
658
661
  "@babel/core": "^7.29.7",
659
662
  "@babel/preset-react": "^8.0.1",
@@ -662,19 +665,17 @@
662
665
  "@testing-library/dom": "^10.0.0",
663
666
  "@testing-library/jest-dom": "^6.6.0",
664
667
  "@testing-library/react": "^16.3.2",
665
- "rimraf": "^6.0.1",
666
- "@astryxdesign/cli": "0.4.3"
668
+ "rimraf": "^6.0.1"
667
669
  },
668
670
  "dependencies": {
669
671
  "intl-messageformat": "^11.2.9"
670
672
  },
671
673
  "scripts": {
672
674
  "postinstall": "node scripts/postinstall.mjs",
673
- "build": "rimraf dist && pnpm build:i18n && pnpm build:esm && tsc --project tsconfig.build.json && pnpm build:css && pnpm build:umd && node ../../scripts/check-no-dev-jsx.mjs && node ../../scripts/check-fully-specified.mjs",
675
+ "build": "rimraf dist && pnpm build:i18n && pnpm build:esm && tsc --project tsconfig.build.json && pnpm build:css && node ../../scripts/check-no-dev-jsx.mjs && node ../../scripts/check-fully-specified.mjs",
674
676
  "build:i18n": "node scripts/build-pseudo-locale.mjs",
675
677
  "build:esm": "babel src --out-dir dist --extensions .ts,.tsx --out-file-extension .js --ignore \"**/*.test.ts,**/*.test.tsx,**/__tests__/**,**/*.perf.test.*,**/*.doc.mjs,**/*.d.ts,**/*.css,**/*.css.d.ts\" --config-file ./babel.config.json",
676
678
  "build:css": "node ../../scripts/build-css.mjs",
677
- "build:umd": "node ../../scripts/build-umd.mjs",
678
679
  "dev": "babel src --watch --out-dir dist --extensions .ts,.tsx --out-file-extension .js --ignore \"**/*.test.*,**/*.doc.mjs,**/*.d.ts,**/*.css*\" --config-file ./babel.config.json",
679
680
  "test": "vitest run --root ../..",
680
681
  "test:watch": "vitest --root ../..",
@@ -70,7 +70,7 @@ export const docs = {
70
70
  name: 'endContent',
71
71
  type: 'ReactNode',
72
72
  description:
73
- 'Action content rendered in the header area, end-aligned. Typically a button or link.',
73
+ 'Action content rendered in the header area, end-aligned. Wraps to its own row below the text when the header is too narrow to hold both.',
74
74
  slotElements: [
75
75
  {__element: 'Icon', props: {icon: 'chevronDown', size: 'sm'}},
76
76
  {__element: 'Badge', props: {label: '3'}},
@@ -164,7 +164,7 @@ export const docsZh = {
164
164
  {name: 'icon', type: 'ReactNode', description: '覆盖默认的状态图标。'},
165
165
  {name: 'isDismissable', type: 'boolean', description: '横幅是否可被用户关闭。', default: 'false'},
166
166
  {name: 'onDismiss', type: '() => void', description: '点击关闭按钮时调用;无论是否提供此回调,横幅都会自动隐藏。'},
167
- {name: 'endContent', type: 'ReactNode', description: '渲染在头部区域末端对齐的操作内容,通常是按钮或链接。'},
167
+ {name: 'endContent', type: 'ReactNode', description: '渲染在头部区域末端对齐的操作内容,通常是按钮或链接。头部过窄时会整体换行到文本下方,自成一行。'},
168
168
  {name: 'container', type: "'card' | 'section'", description: '视觉变体:card 带圆角;section 无圆角全宽,适用于页面级场景。', default: "'card'"},
169
169
  {name: 'elevation', type: "'none' | 'low' | 'med' | 'high'", description: '静止阴影深度。用于悬浮于内容之上的浮动横幅;none 为默认内联横幅。', default: "'none'"},
170
170
  {name: 'children', type: 'ReactNode', description: '渲染在彩色头部下方卡片背景区域的内容。'},
@@ -238,7 +238,7 @@ export const docsDense = {
238
238
  icon: 'override default status icon',
239
239
  isDismissable: 'user can dismiss banner',
240
240
  onDismiss: 'dismiss callback; banner self-hides regardless',
241
- endContent: 'end-aligned action in header, typically button/link',
241
+ endContent: 'end-aligned action in header, typically button/link; wraps to its own row when the header is too narrow',
242
242
  container: 'card=border-radius; section=full-width no radius for page-level',
243
243
  elevation: 'resting shadow depth: none|low|med|high; raise for a floating banner',
244
244
  children: 'content in card-bg area below colored header',