@astryxdesign/core 0.1.7-canary.9da0792 → 0.1.7-canary.a82fbd9

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 (103) hide show
  1. package/README.md +30 -19
  2. package/dist/Avatar/Avatar.d.ts +10 -5
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +12 -8
  5. package/dist/Avatar/AvatarSizeContext.d.ts +1 -1
  6. package/dist/Avatar/AvatarSizeContext.js +1 -1
  7. package/dist/Avatar/AvatarStatusDot.d.ts +2 -2
  8. package/dist/Avatar/AvatarStatusDot.js +2 -2
  9. package/dist/AvatarGroup/AvatarGroup.d.ts +2 -2
  10. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  11. package/dist/AvatarGroup/AvatarGroup.js +2 -2
  12. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +16 -14
  15. package/dist/Carousel/Carousel.d.ts +3 -2
  16. package/dist/Carousel/Carousel.d.ts.map +1 -1
  17. package/dist/Carousel/Carousel.js +32 -2
  18. package/dist/Chat/ChatMessage.d.ts +1 -1
  19. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  20. package/dist/Chat/ChatMessage.js +1 -1
  21. package/dist/Icon/Icon.d.ts +26 -1
  22. package/dist/Icon/Icon.d.ts.map +1 -1
  23. package/dist/Icon/Icon.js +34 -7
  24. package/dist/Outline/Outline.d.ts +69 -3
  25. package/dist/Outline/Outline.d.ts.map +1 -1
  26. package/dist/Outline/Outline.js +129 -26
  27. package/dist/Outline/useScrollSpy.d.ts +27 -7
  28. package/dist/Outline/useScrollSpy.d.ts.map +1 -1
  29. package/dist/Outline/useScrollSpy.js +202 -70
  30. package/dist/Table/Table.d.ts +1 -1
  31. package/dist/Table/Table.js +1 -1
  32. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  33. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +24 -2
  34. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  35. package/dist/Table/plugins/sortable/useTableSortable.js +18 -7
  36. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  37. package/dist/Table/plugins/tree/useTableTreeData.js +4 -2
  38. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  39. package/dist/TreeList/TreeListItem.js +5 -14
  40. package/dist/astryx.css +6 -2
  41. package/dist/astryx.umd.js +50 -50
  42. package/dist/astryx.umd.js.map +4 -4
  43. package/dist/theme/Theme.js +1 -1
  44. package/dist/theme/defineTheme.d.ts +1 -1
  45. package/dist/theme/defineTheme.js +1 -1
  46. package/docs.mjs +32 -461
  47. package/locales/en.json +200 -172
  48. package/locales/pseudo.json +21 -0
  49. package/package.json +3 -1
  50. package/scripts/postinstall.mjs +93 -0
  51. package/src/Avatar/Avatar.doc.mjs +6 -6
  52. package/src/Avatar/Avatar.tsx +16 -11
  53. package/src/Avatar/AvatarSizeContext.ts +1 -1
  54. package/src/Avatar/AvatarStatusDot.tsx +2 -2
  55. package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -1
  56. package/src/AvatarGroup/AvatarGroup.test.tsx +17 -3
  57. package/src/AvatarGroup/AvatarGroup.tsx +3 -3
  58. package/src/AvatarGroup/AvatarGroupOverflow.doc.mjs +4 -4
  59. package/src/AvatarGroup/AvatarGroupOverflow.tsx +21 -5
  60. package/src/Carousel/Carousel.doc.mjs +1 -0
  61. package/src/Carousel/Carousel.test.tsx +96 -1
  62. package/src/Carousel/Carousel.tsx +29 -2
  63. package/src/Chat/Chat.doc.mjs +1 -1
  64. package/src/Chat/ChatMessage.tsx +4 -2
  65. package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
  66. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +3 -3
  67. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +1 -1
  68. package/src/Field/Field.doc.mjs +1 -1
  69. package/src/Field/FieldLabel.doc.mjs +1 -1
  70. package/src/Icon/Icon.doc.mjs +12 -0
  71. package/src/Icon/Icon.test.tsx +96 -0
  72. package/src/Icon/Icon.tsx +61 -6
  73. package/src/Item/Item.doc.mjs +1 -1
  74. package/src/NumberInput/NumberInput.doc.mjs +2 -2
  75. package/src/Outline/Outline.doc.mjs +123 -3
  76. package/src/Outline/Outline.test.tsx +735 -0
  77. package/src/Outline/Outline.tsx +184 -33
  78. package/src/Outline/useScrollSpy.ts +248 -72
  79. package/src/Selector/SelectorOption.doc.mjs +1 -1
  80. package/src/SideNav/SideNavItem.doc.mjs +2 -2
  81. package/src/Switch/Switch.doc.mjs +1 -1
  82. package/src/TabList/TabList.doc.mjs +3 -3
  83. package/src/Table/Table.tsx +1 -1
  84. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +90 -1
  85. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +37 -5
  86. package/src/Table/plugins/sortable/useTableSortable.test.tsx +95 -9
  87. package/src/Table/plugins/sortable/useTableSortable.tsx +23 -7
  88. package/src/Table/plugins/tree/useTableTreeData.tsx +8 -2
  89. package/src/Table/useTableTreeData.doc.mjs +1 -1
  90. package/src/Table/useTableTreeState.doc.mjs +3 -3
  91. package/src/TextArea/TextArea.doc.mjs +1 -1
  92. package/src/TextInput/TextInput.doc.mjs +1 -1
  93. package/src/TreeList/TreeList.test.tsx +32 -1
  94. package/src/TreeList/TreeListItem.tsx +19 -10
  95. package/src/docs-script.test.mjs +18 -13
  96. package/src/postinstall.test.mjs +71 -0
  97. package/src/theme/Theme.doc.mjs +4 -4
  98. package/src/theme/Theme.tsx +1 -1
  99. package/src/theme/defineTheme.ts +1 -1
  100. package/dist/TreeList/treeListItem.markers.stylex.d.ts +0 -16
  101. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +0 -1
  102. package/dist/TreeList/treeListItem.markers.stylex.js +0 -22
  103. package/src/TreeList/treeListItem.markers.stylex.ts +0 -20
package/README.md CHANGED
@@ -2,18 +2,27 @@
2
2
 
3
3
  Core UI components, theme system, and utilities for the Astryx design system. For project setup, see [Quick Start](#quick-start) below.
4
4
 
5
- > **Building with an AI agent?** Run **`npx astryx init`** first. It installs the Astryx CLI's component index into your `AGENTS.md`/`CLAUDE.md` so your agent discovers components, templates, and design tokens instead of guessing. Without it, agents can't see the CLI — see [XDS CLI](#xds-cli).
5
+ > **Building with an AI agent?** Add the CLI, then run `init`:
6
+ >
7
+ > ```bash
8
+ > npm install -D @astryxdesign/cli # or: pnpm add -D / yarn add -D / bun add -d
9
+ > npx astryx init # resolves to the CLI you just installed
10
+ > ```
11
+ >
12
+ > `init` writes the Astryx component index into your `AGENTS.md`/`CLAUDE.md` so your agent discovers components, templates, and design tokens instead of guessing. Need a single command without installing? Use the scoped package directly — `npx @astryxdesign/cli <cmd>` (or `pnpm dlx`/`bunx @astryxdesign/cli`). Bare `npx astryx` only works once `@astryxdesign/cli` is a dependency; before that npm resolves it to an unrelated package. See [XDS CLI](#xds-cli).
6
13
 
7
14
  ## Component Docs
8
15
 
9
- Look up any component's full API (props, types, best practices, and theming):
16
+ Look up any component's full API (props, variants, examples, best practices, and theming) via the Astryx CLI:
10
17
 
11
18
  ```bash
12
- node node_modules/@astryxdesign/core/docs.mjs Button # full docs for a component
13
- node node_modules/@astryxdesign/core/docs.mjs --list # list all components
14
- node node_modules/@astryxdesign/core/docs.mjs --list --brief # brief summaries
19
+ npx @astryxdesign/cli init # one-time: writes the component guide into AGENTS.md / CLAUDE.md
20
+ npx @astryxdesign/cli component Button # full docs for a component
21
+ npx @astryxdesign/cli component --list # list all components
15
22
  ```
16
23
 
24
+ > Use the scoped `@astryxdesign/cli` to run without installing; bare `npx astryx` only resolves once the CLI is a dependency.
25
+
17
26
  ## Page Layouts
18
27
 
19
28
  Building a full page? Start with a template rather than composing from scratch.
@@ -25,9 +34,9 @@ global navigation.
25
34
  Requires `@astryxdesign/cli` (`npm install -D @astryxdesign/cli`):
26
35
 
27
36
  ```bash
28
- npx astryx template --list # browse all page and block templates
29
- npx astryx template dashboard # emit full page source
30
- npx astryx template settings --skeleton # layout skeleton with spatial annotations
37
+ astryx template --list # browse all page and block templates
38
+ astryx template dashboard # emit full page source
39
+ astryx template settings --skeleton # layout skeleton with spatial annotations
31
40
  ```
32
41
 
33
42
  ## Astryx CLI
@@ -35,19 +44,21 @@ npx astryx template settings --skeleton # layout skeleton with spatial annotatio
35
44
  The CLI (`@astryxdesign/cli`) provides additional tooling:
36
45
 
37
46
  ```bash
38
- npx astryx --help # full listing of all commands
39
- npx astryx component Button # full docs + related block templates
40
- npx astryx docs # reference docs (principles, tokens, theming, styling)
41
- npx astryx docs theme # theming guide (Theme, defineTheme, light/dark)
42
- npx astryx docs tokens # spacing, color, radius, typography token reference
43
- npx astryx init # initialize Astryx in your project
44
- npx astryx theme build # build theme CSS for production
45
- npx astryx swizzle Button # eject component source for customization
46
- npx astryx upgrade --apply # run codemods to migrate between versions
47
- npx astryx discover # discover external Astryx packages
48
- npx astryx gap-report # report a missing capability
47
+ astryx --help # full listing of all commands
48
+ astryx component Button # full docs + related block templates
49
+ astryx docs # reference docs (principles, tokens, theming, styling)
50
+ astryx docs theme # theming guide (Theme, defineTheme, light/dark)
51
+ astryx docs tokens # spacing, color, radius, typography token reference
52
+ astryx init # initialize Astryx in your project
53
+ astryx theme build # build theme CSS for production
54
+ astryx swizzle Button # eject component source for customization
55
+ astryx upgrade --apply # run codemods to migrate between versions
56
+ astryx discover # discover external Astryx packages
57
+ astryx gap-report # report a missing capability
49
58
  ```
50
59
 
60
+ > Prefix these with your runner: `npx astryx …` / `pnpm exec astryx …` once the CLI is installed, or `npx @astryxdesign/cli …` to run without installing.
61
+
51
62
  ## Related Packages
52
63
 
53
64
  | Package | Description |
@@ -13,9 +13,13 @@
13
13
  import { type ReactNode } from 'react';
14
14
  import type { BaseProps } from '../BaseProps';
15
15
  /**
16
- * Named size options
16
+ * Named size options.
17
+ *
18
+ * Avatar uses the same abbreviated scale as Icon (`xsm`/`sm`/`md`/`lg`/`xl`),
19
+ * but the values are larger because avatars align with media rather than
20
+ * glyphs. The tiers match EPS's avatar sizes.
17
21
  */
18
- type AvatarNamedSize = 'tiny' | 'xsmall' | 'small' | 'medium' | 'large';
22
+ type AvatarNamedSize = 'xsm' | 'sm' | 'md' | 'lg' | 'xl';
19
23
  /**
20
24
  * Numeric size options (in pixels)
21
25
  */
@@ -52,8 +56,9 @@ export interface AvatarProps extends BaseProps<HTMLDivElement> {
52
56
  */
53
57
  name?: string;
54
58
  /**
55
- * The size of the avatar.
56
- * @default 'small'
59
+ * The size of the avatar. A named size (`xsm` 20px, `sm` 24px, `md` 36px,
60
+ * `lg` 48px, `xl` 128px) or a specific pixel value.
61
+ * @default 'md'
57
62
  */
58
63
  size?: AvatarSize;
59
64
  /**
@@ -75,7 +80,7 @@ export interface AvatarProps extends BaseProps<HTMLDivElement> {
75
80
  * @example
76
81
  * ```
77
82
  * <Avatar src="/user.jpg" name="John Doe" />
78
- * <Avatar name="Jane Smith" size="large" />
83
+ * <Avatar name="Jane Smith" size="xl" />
79
84
  * <Avatar src="/user.jpg" status={<OnlineIndicator />} />
80
85
  * ```
81
86
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/Avatar/Avatar.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AACxD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAsC5C;;GAEG;AACH,KAAK,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAExE;;GAEG;AACH,KAAK,iBAAiB,GACpB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE7D;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAgBpD;AAqFD,MAAM,WAAW,WAAY,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC5D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAsCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,EACrB,GAAG,EACH,aAAa,EAAE,MAAM,EACrB,WAAW,EACX,IAAI,EACJ,IAAc,EACd,GAAG,EACH,MAAM,EACN,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,WAAW,+BAwFb;yBArGe,MAAM"}
1
+ {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/Avatar/Avatar.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AACxD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAsC5C;;;;;;GAMG;AACH,KAAK,eAAe,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzD;;GAEG;AACH,KAAK,iBAAiB,GACpB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE7D;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAgBpD;AAqFD,MAAM,WAAW,WAAY,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC5D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAsCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,EACrB,GAAG,EACH,aAAa,EAAE,MAAM,EACrB,WAAW,EACX,IAAI,EACJ,IAAW,EACX,GAAG,EACH,MAAM,EACN,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,WAAW,+BAwFb;yBArGe,MAAM"}
@@ -50,7 +50,11 @@ const CIRCLE_EDGE_OFFSET_RATIO = (1 - 1 / Math.SQRT2) / 2;
50
50
  const INITIALS_FONT_SIZE_RATIO = 0.4;
51
51
 
52
52
  /**
53
- * Named size options
53
+ * Named size options.
54
+ *
55
+ * Avatar uses the same abbreviated scale as Icon (`xsm`/`sm`/`md`/`lg`/`xl`),
56
+ * but the values are larger because avatars align with media rather than
57
+ * glyphs. The tiers match EPS's avatar sizes.
54
58
  */
55
59
 
56
60
  /**
@@ -69,15 +73,15 @@ export function resolveSize(size) {
69
73
  return size;
70
74
  }
71
75
  switch (size) {
72
- case 'tiny':
76
+ case 'xsm':
73
77
  return 20;
74
- case 'xsmall':
78
+ case 'sm':
75
79
  return 24;
76
- case 'small':
80
+ case 'md':
77
81
  return 36;
78
- case 'medium':
82
+ case 'lg':
79
83
  return 48;
80
- case 'large':
84
+ case 'xl':
81
85
  return 128;
82
86
  }
83
87
  }
@@ -223,7 +227,7 @@ function DefaultIcon({
223
227
  * @example
224
228
  * ```
225
229
  * <Avatar src="/user.jpg" name="John Doe" />
226
- * <Avatar name="Jane Smith" size="large" />
230
+ * <Avatar name="Jane Smith" size="xl" />
227
231
  * <Avatar src="/user.jpg" status={<OnlineIndicator />} />
228
232
  * ```
229
233
  */
@@ -232,7 +236,7 @@ export function Avatar({
232
236
  'data-testid': testId,
233
237
  fallbackSrc,
234
238
  name,
235
- size = 'small',
239
+ size = 'md',
236
240
  src,
237
241
  status,
238
242
  xstyle,
@@ -2,7 +2,7 @@
2
2
  * Context that provides the resolved numeric avatar size (in pixels)
3
3
  * to child components like AvatarStatusDot.
4
4
  *
5
- * Default value of 36 matches the default 'small' avatar size.
5
+ * Default value of 36 matches the default 'md' avatar size.
6
6
  */
7
7
  export declare const AvatarSizeContext: import("react").Context<number>;
8
8
  //# sourceMappingURL=AvatarSizeContext.d.ts.map
@@ -17,7 +17,7 @@ import { createContext } from 'react';
17
17
  * Context that provides the resolved numeric avatar size (in pixels)
18
18
  * to child components like AvatarStatusDot.
19
19
  *
20
- * Default value of 36 matches the default 'small' avatar size.
20
+ * Default value of 36 matches the default 'md' avatar size.
21
21
  */
22
22
  export const AvatarSizeContext = /*#__PURE__*/createContext(36);
23
23
  AvatarSizeContext.displayName = 'AvatarSizeContext';
@@ -76,12 +76,12 @@ export interface AvatarStatusDotProps extends BaseProps<HTMLDivElement> {
76
76
  * ```
77
77
  * <Avatar
78
78
  * name="John Doe"
79
- * size="medium"
79
+ * size="lg"
80
80
  * status={<AvatarStatusDot variant="success" label="Online" />}
81
81
  * />
82
82
  * <Avatar
83
83
  * name="Jane Smith"
84
- * size="large"
84
+ * size="xl"
85
85
  * status={<AvatarStatusDot variant="success" label="Verified" icon={<CheckIcon />} />}
86
86
  * />
87
87
  * ```
@@ -148,12 +148,12 @@ const variantStyleMap = {
148
148
  * ```
149
149
  * <Avatar
150
150
  * name="John Doe"
151
- * size="medium"
151
+ * size="lg"
152
152
  * status={<AvatarStatusDot variant="success" label="Online" />}
153
153
  * />
154
154
  * <Avatar
155
155
  * name="Jane Smith"
156
- * size="large"
156
+ * size="xl"
157
157
  * status={<AvatarStatusDot variant="success" label="Verified" icon={<CheckIcon />} />}
158
158
  * />
159
159
  * ```
@@ -27,7 +27,7 @@ export interface AvatarGroupProps extends BaseProps<HTMLDivElement> {
27
27
  children: ReactNode;
28
28
  /**
29
29
  * Size applied to all avatars via context.
30
- * @default 'small'
30
+ * @default 'md'
31
31
  */
32
32
  size?: AvatarSize;
33
33
  /**
@@ -45,7 +45,7 @@ export interface AvatarGroupProps extends BaseProps<HTMLDivElement> {
45
45
  *
46
46
  * @example
47
47
  * ```
48
- * <AvatarGroup size="medium">
48
+ * <AvatarGroup size="lg">
49
49
  * {users.slice(0, 3).map(u => (
50
50
  * <Avatar key={u.id} src={u.src} name={u.name} />
51
51
  * ))}
@@ -1 +1 @@
1
- {"version":3,"file":"AvatarGroup.d.ts","sourceRoot":"","sources":["../../src/AvatarGroup/AvatarGroup.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAU,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,WAAW,CAAC;AASvD,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACjE,yCAAyC;IACzC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AASD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,IAAc,EACd,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,kBAAkB,EAChC,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,gBAAgB,GAAG,SAAS,CA6B9B;yBAvCe,WAAW"}
1
+ {"version":3,"file":"AvatarGroup.d.ts","sourceRoot":"","sources":["../../src/AvatarGroup/AvatarGroup.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAU,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,WAAW,CAAC;AASvD,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACjE,yCAAyC;IACzC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AASD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,IAAW,EACX,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,kBAAkB,EAChC,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,gBAAgB,GAAG,SAAS,CA6B9B;yBAvCe,WAAW"}
@@ -44,7 +44,7 @@ const styles = {
44
44
  *
45
45
  * @example
46
46
  * ```
47
- * <AvatarGroup size="medium">
47
+ * <AvatarGroup size="lg">
48
48
  * {users.slice(0, 3).map(u => (
49
49
  * <Avatar key={u.id} src={u.src} name={u.name} />
50
50
  * ))}
@@ -54,7 +54,7 @@ const styles = {
54
54
  */
55
55
  export function AvatarGroup({
56
56
  children,
57
- size = 'small',
57
+ size = 'md',
58
58
  'data-testid': testId,
59
59
  'aria-label': ariaLabelFromProps,
60
60
  xstyle,
@@ -33,7 +33,7 @@ export interface AvatarGroupOverflowProps extends Omit<BaseProps<HTMLElement>, '
33
33
  *
34
34
  * @example
35
35
  * ```
36
- * <AvatarGroup size="medium">
36
+ * <AvatarGroup size="lg">
37
37
  * {users.slice(0, 3).map(u => (
38
38
  * <Avatar key={u.id} src={u.src} name={u.name} />
39
39
  * ))}
@@ -1 +1 @@
1
- {"version":3,"file":"AvatarGroupOverflow.d.ts","sourceRoot":"","sources":["../../src/AvatarGroup/AvatarGroupOverflow.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAU5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAM5C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,SAAS,CAAC,WAAW,CAAC,EACtB,SAAS,CACV;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA6DD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,wBAAwB,GAAG,SAAS,CAwDtC;yBAjEe,mBAAmB"}
1
+ {"version":3,"file":"AvatarGroupOverflow.d.ts","sourceRoot":"","sources":["../../src/AvatarGroup/AvatarGroupOverflow.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAW5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAM5C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,SAAS,CAAC,WAAW,CAAC,EACtB,SAAS,CACV;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA4ED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,wBAAwB,GAAG,SAAS,CAwDtC;yBAjEe,mBAAmB"}
@@ -15,7 +15,7 @@
15
15
  import React from 'react';
16
16
  import * as stylex from '@stylexjs/stylex';
17
17
  import "../theme/tokens.stylex.js";
18
- import { colorVars, typographyVars, fontWeightVars, radiusVars } from "../theme/tokens.stylex.js";
18
+ import { colorVars, typographyVars, fontWeightVars, radiusVars, spacingVars } from "../theme/tokens.stylex.js";
19
19
  import { mergeProps } from "../utils/index.js";
20
20
  import { useAvatarGroup } from "./AvatarGroupContext.js";
21
21
  import { themeProps } from "../utils/themeProps.js";
@@ -37,13 +37,14 @@ const styles = {
37
37
  kMzoRj: "xdh2fpr",
38
38
  ksu8eU: "x1y0btm7",
39
39
  kVAM5u: "x1touxvs",
40
- kB7OPa: "x1afcbsf",
40
+ kB7OPa: "x9f619",
41
+ kg3NbH: "xf314gf",
41
42
  kKwaWg: "x14bno8m",
42
43
  $$css: true
43
44
  },
44
45
  button: {
45
46
  kkrTdU: "x1ypdohk",
46
- kmVPX3: "x1717udv",
47
+ k8WAf4: "xt970qd",
47
48
  kKwaWg: "x14bno8m xbfmc0r x1nocapi",
48
49
  kI3sdo: "x1a2a7pz x17nn4n9",
49
50
  kInvED: "x7s97pk",
@@ -55,26 +56,27 @@ const styles = {
55
56
  }
56
57
  };
57
58
  const _temp = {
58
- kGuDYH: "xdmh292",
59
+ k7Eaqz: "xkj4a21",
60
+ kZKoxP: "x16ye13r",
59
61
  "$$css": true
60
62
  };
61
63
  const _temp2 = {
64
+ kGuDYH: "xdmh292",
65
+ "$$css": true
66
+ };
67
+ const _temp3 = {
62
68
  "--_avatar-group-overlap": "xlz5hwt",
63
69
  "$$css": true
64
70
  };
65
71
  const dynamicStyles = {
66
- size: s => [{
67
- kzqmXN: s != null ? "x5lhr3w" : s,
68
- kZKoxP: s != null ? "x16ye13r" : s,
69
- $$css: true
70
- }, {
71
- "--x-width": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(s),
72
- "--x-height": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(s)
72
+ size: s => [_temp, {
73
+ "--x-minWidth": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(s + BORDER_WIDTH * 2),
74
+ "--x-height": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(s + BORDER_WIDTH * 2)
73
75
  }],
74
- fontSize: s => [_temp, {
76
+ fontSize: s => [_temp2, {
75
77
  "--x-fontSize": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(s * OVERFLOW_FONT_RATIO)
76
78
  }],
77
- overlap: offset => [_temp2, {
79
+ overlap: offset => [_temp3, {
78
80
  "--x---_avatar-group-overlap": `${offset}px` != null ? `${offset}px` : undefined
79
81
  }]
80
82
  };
@@ -85,7 +87,7 @@ const dynamicStyles = {
85
87
  *
86
88
  * @example
87
89
  * ```
88
- * <AvatarGroup size="medium">
90
+ * <AvatarGroup size="lg">
89
91
  * {users.slice(0, 3).map(u => (
90
92
  * <Avatar key={u.id} src={u.src} name={u.name} />
91
93
  * ))}
@@ -3,8 +3,9 @@
3
3
  * @input Uses React, StyleX, useScrollOverflow, useLayer, Button, Icon, theme tokens
4
4
  * @output Exports Carousel component
5
5
  * @position Horizontal scroll container with fade-edge overflow indication,
6
- * optional prev/next buttons on the top layer, scroll-snap, and a 1px
7
- * visual bleed allowance for child selection indicators.
6
+ * optional prev/next buttons on the top layer, scroll-snap, a 1px
7
+ * visual bleed allowance for child selection indicators, and Shift + wheel
8
+ * mapping so mouse users can scroll horizontally.
8
9
  *
9
10
  * SYNC: When modified, update:
10
11
  * - /packages/core/src/Carousel/index.ts (exports)
@@ -1 +1 @@
1
- {"version":3,"file":"Carousel.d.ts","sourceRoot":"","sources":["../../src/Carousel/Carousel.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAC,KAAK,SAAS,EAA2C,MAAM,OAAO,CAAC;AAc/E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAIhD,MAAM,WAAW,aAAc,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC9D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,kEAAkE;IAClE,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAyJD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,QAAQ,EACR,GAAO,EACP,UAAiB,EACjB,WAAkB,EAClB,OAAe,EACf,OAAO,EACP,YAAY,EAAE,kBAAkB,EAChC,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,SAAS,EACb,EAAE,aAAa,+BAmJf;yBAjKe,QAAQ"}
1
+ {"version":3,"file":"Carousel.d.ts","sourceRoot":"","sources":["../../src/Carousel/Carousel.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAC,KAAK,SAAS,EAA2C,MAAM,OAAO,CAAC;AAc/E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAIhD,MAAM,WAAW,aAAc,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC9D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,kEAAkE;IAClE,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAyJD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,QAAQ,EACR,GAAO,EACP,UAAiB,EACjB,WAAkB,EAClB,OAAe,EACf,OAAO,EACP,YAAY,EAAE,kBAAkB,EAChC,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,SAAS,EACb,EAAE,aAAa,+BA6Kf;yBA3Le,QAAQ"}
@@ -7,8 +7,9 @@
7
7
  * @input Uses React, StyleX, useScrollOverflow, useLayer, Button, Icon, theme tokens
8
8
  * @output Exports Carousel component
9
9
  * @position Horizontal scroll container with fade-edge overflow indication,
10
- * optional prev/next buttons on the top layer, scroll-snap, and a 1px
11
- * visual bleed allowance for child selection indicators.
10
+ * optional prev/next buttons on the top layer, scroll-snap, a 1px
11
+ * visual bleed allowance for child selection indicators, and Shift + wheel
12
+ * mapping so mouse users can scroll horizontally.
12
13
  *
13
14
  * SYNC: When modified, update:
14
15
  * - /packages/core/src/Carousel/index.ts (exports)
@@ -234,6 +235,34 @@ export function Carousel({
234
235
  scrollElRef.current = el;
235
236
  scrollRef(el);
236
237
  }, [scrollRef]);
238
+
239
+ // Map Shift + vertical wheel to horizontal scroll. Trackpads emit
240
+ // horizontal deltas natively, but a standard mouse only produces deltaY —
241
+ // so mouse users can't wheel-scroll a horizontal container. Shift + wheel
242
+ // is the long-established convention for horizontal scroll containers; we
243
+ // honor it by translating the vertical delta into a horizontal scroll.
244
+ //
245
+ // Only kicks in when Shift is held and the wheel is purely vertical
246
+ // (deltaX === 0), so native trackpad horizontal scrolling is untouched.
247
+ const handleWheel = useCallback(event => {
248
+ if (!event.shiftKey || event.deltaY === 0 || event.deltaX !== 0) {
249
+ return;
250
+ }
251
+ const el = scrollElRef.current;
252
+ if (!el) {
253
+ return;
254
+ }
255
+ // Nothing to scroll horizontally — let the event fall through so the page
256
+ // can scroll as it normally would.
257
+ if (el.scrollWidth <= el.clientWidth) {
258
+ return;
259
+ }
260
+ event.preventDefault();
261
+ el.scrollBy({
262
+ left: event.deltaY,
263
+ behavior: 'auto'
264
+ });
265
+ }, []);
237
266
  const scrollBy = useCallback(direction => {
238
267
  const el = scrollElRef.current;
239
268
  if (!el) {
@@ -271,6 +300,7 @@ export function Carousel({
271
300
  children: [/*#__PURE__*/_jsx("div", {
272
301
  ref: composedRef,
273
302
  tabIndex: 0,
303
+ onWheel: handleWheel,
274
304
  ...stylex.props(styles.scroller, gapStyles[gap], padding != null && paddingStyles[padding], hasSnap && styles.snap, fadeStyle),
275
305
  children: Children.map(children, child => /*#__PURE__*/_jsx("div", {
276
306
  ...{
@@ -46,7 +46,7 @@ export interface ChatMessageProps extends BaseProps<HTMLElement> {
46
46
  *
47
47
  * @example
48
48
  * ```
49
- * <ChatMessage sender="assistant" name="Navi" avatar={<Avatar name="Navi" size="small" />}>
49
+ * <ChatMessage sender="assistant" name="Navi" avatar={<Avatar name="Navi" size="md" />}>
50
50
  * <ChatMessageBubble>Hello!</ChatMessageBubble>
51
51
  * <ChatMessageMetadata timestamp="2:30 PM" />
52
52
  * </ChatMessage>
@@ -1 +1 @@
1
- {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/Chat/ChatMessage.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAQrD,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,WAAW,CAAC;IAC9D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAoFD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,OAAO,EAAE,WAAW,EACpB,MAAM,EACN,SAAS,EACT,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,GAAG,IAAI,EACR,EAAE,gBAAgB,+BAyFlB;yBAtGe,WAAW"}
1
+ {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/Chat/ChatMessage.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAQrD,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,WAAW,CAAC;IAC9D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAoFD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,OAAO,EAAE,WAAW,EACpB,MAAM,EACN,SAAS,EACT,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,GAAG,IAAI,EACR,EAAE,gBAAgB,+BA2FlB;yBAxGe,WAAW"}
@@ -122,7 +122,7 @@ const styles = {
122
122
  *
123
123
  * @example
124
124
  * ```
125
- * <ChatMessage sender="assistant" name="Navi" avatar={<Avatar name="Navi" size="small" />}>
125
+ * <ChatMessage sender="assistant" name="Navi" avatar={<Avatar name="Navi" size="md" />}>
126
126
  * <ChatMessageBubble>Hello!</ChatMessageBubble>
127
127
  * <ChatMessageMetadata timestamp="2:30 PM" />
128
128
  * </ChatMessage>
@@ -140,6 +140,31 @@ export interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'ref' | 'color'
140
140
  * @default 'md'
141
141
  */
142
142
  size?: IconSize;
143
+ /**
144
+ * Accessible name for the icon. Set this only when the icon is MEANINGFUL on
145
+ * its own — a standalone status glyph or an icon-only indicator with no
146
+ * adjacent text conveying the same information. Providing it exposes the icon
147
+ * to assistive tech as `role="img"` with this string as the accessible name
148
+ * (via `aria-label`) and drops the default `aria-hidden="true"`.
149
+ *
150
+ * Omit it (the default) for decorative icons — the common case, e.g. an icon
151
+ * beside a text label — and the icon stays hidden from assistive tech
152
+ * (`aria-hidden="true"`). An empty string (`''`) is treated the same as
153
+ * omitting it (decorative), since an empty accessible name is meaningless.
154
+ *
155
+ * Don't set `label` when an interactive parent (Button, IconButton, link)
156
+ * already names the control — that produces a duplicate announcement.
157
+ *
158
+ * @example
159
+ * ```
160
+ * // Meaningful, standalone icon
161
+ * <Icon icon="success" label="Completed" />
162
+ *
163
+ * // Decorative icon (default) — omit label
164
+ * <Icon icon="search" />
165
+ * ```
166
+ */
167
+ label?: string;
143
168
  }
144
169
  /**
145
170
  * Renders an icon from the icon registry or a custom SVG component.
@@ -149,7 +174,7 @@ export interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'ref' | 'color'
149
174
  * <Icon icon="close" size="md" color="primary" />
150
175
  * ```
151
176
  */
152
- export declare function Icon({ icon, color, size, ref, ...props }: IconProps): React.JSX.Element;
177
+ export declare function Icon({ icon, color, size, label, ref, ...props }: IconProps): React.JSX.Element;
153
178
  export declare namespace Icon {
154
179
  var displayName: string;
155
180
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../../src/Icon/Icon.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,EAAC,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAC,MAAM,OAAO,CAAC;AAC/D,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAG3C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAqBnD,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2Df,CAAC;AAEH;;;;;;;;GAQG;AACH,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;EAiBd,CAAC;AAyCH,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAC;AACjD,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,UAAU,CAAC;AAE/C;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,SAAU,SAAQ,IAAI,CACrC,QAAQ,CAAC,aAAa,CAAC,EACvB,KAAK,GAAG,OAAO,CAChB;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC/B;;;;OAIG;IACH,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAMD;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,EACnB,IAAI,EACJ,KAAiB,EACjB,IAAW,EACX,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,qBA0BX;yBAhCe,IAAI;;;AAiFpB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,KAAK,CAAC,SAAS,GAAG,QAAQ,EAChC,KAAK,CAAC,EAAE;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAC,GAC3C,KAAK,CAAC,SAAS,CAYjB"}
1
+ {"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../../src/Icon/Icon.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,EAAC,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAC,MAAM,OAAO,CAAC;AAC/D,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAG3C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAqBnD,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2Df,CAAC;AAEH;;;;;;;;GAQG;AACH,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;EAiBd,CAAC;AAyCH,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAC;AACjD,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,UAAU,CAAC;AAE/C;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,SAAU,SAAQ,IAAI,CACrC,QAAQ,CAAC,aAAa,CAAC,EACvB,KAAK,GAAG,OAAO,CAChB;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC/B;;;;OAIG;IACH,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAyBD;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,EACnB,IAAI,EACJ,KAAiB,EACjB,IAAW,EACX,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,SAAS,qBAkCX;yBAzCe,IAAI;;;AA4FpB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,KAAK,CAAC,SAAS,GAAG,QAAQ,EAChC,KAAK,CAAC,EAAE;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAC,GAC3C,KAAK,CAAC,SAAS,CAYjB"}
package/dist/Icon/Icon.js CHANGED
@@ -205,6 +205,26 @@ const spanSizeStyles = {
205
205
  * Extends SVGProps to allow passing additional SVG attributes (used when icon is a component).
206
206
  */
207
207
 
208
+ /**
209
+ * Derives the ARIA attributes for an icon from its `label` prop.
210
+ *
211
+ * - Non-empty `label` → meaningful image: `role="img"` + `aria-label`, and no
212
+ * `aria-hidden` (an `aria-hidden` element is removed from the accessibility
213
+ * tree, so its accessible name would be ignored).
214
+ * - Omitted or empty `label` → decorative default: `aria-hidden="true"`.
215
+ *
216
+ * The result is spread BEFORE `{...props}` in both render modes so an explicit
217
+ * `aria-hidden` / `role` / `aria-label` from the consumer always wins.
218
+ */
219
+ function getIconA11yProps(label) {
220
+ return label != null && label !== '' ? {
221
+ role: 'img',
222
+ 'aria-label': label
223
+ } : {
224
+ 'aria-hidden': 'true'
225
+ };
226
+ }
227
+
208
228
  // =============================================================================
209
229
  // Component
210
230
  // =============================================================================
@@ -221,15 +241,21 @@ export function Icon({
221
241
  icon,
222
242
  color = 'inherit',
223
243
  size = 'md',
244
+ label,
224
245
  ref,
225
246
  ...props
226
247
  }) {
248
+ // Derive ARIA from `label`: decorative (aria-hidden) by default, or a
249
+ // meaningful image (role="img" + aria-label) when `label` is non-empty.
250
+ const a11yProps = getIconA11yProps(label);
251
+
227
252
  // String mode: resolve from icon registry, wrap in styled span
228
253
  if (typeof icon === 'string') {
229
254
  return /*#__PURE__*/_jsx(IconFromRegistry, {
230
255
  name: icon,
231
256
  color: color,
232
257
  size: size,
258
+ a11yProps: a11yProps,
233
259
  spanProps: props
234
260
  });
235
261
  }
@@ -237,8 +263,12 @@ export function Icon({
237
263
  // Component mode: render SVG component directly with ref forwarding
238
264
  const IconComponent = icon;
239
265
  return /*#__PURE__*/_jsx(IconComponent, {
240
- ref: ref,
241
- "aria-hidden": "true",
266
+ ref: ref
267
+ // Derived a11y (decorative default or meaningful `label`) is spread
268
+ // BEFORE {...props} so an explicit aria-hidden/role/aria-label from the
269
+ // consumer still wins as an escape hatch.
270
+ ,
271
+ ...a11yProps,
242
272
  ...mergeProps(themeProps('icon', {
243
273
  size,
244
274
  color
@@ -263,6 +293,7 @@ function IconFromRegistry({
263
293
  name,
264
294
  color,
265
295
  size,
296
+ a11yProps,
266
297
  spanProps
267
298
  }) {
268
299
  const resolvedIcon = getIcon(name);
@@ -270,11 +301,7 @@ function IconFromRegistry({
270
301
  return null;
271
302
  }
272
303
  return /*#__PURE__*/_jsx("span", {
273
- // Decorative by default, but placed BEFORE the prop spread so consumers
274
- // can override it (e.g. `aria-hidden={false}` + `role="img"` +
275
- // `aria-label`) to expose a meaningful standalone icon. This matches
276
- // component-mode Icon, which already sets aria-hidden before its spread.
277
- "aria-hidden": "true",
304
+ ...a11yProps,
278
305
  ...spanProps,
279
306
  ...mergeProps(themeProps('icon', {
280
307
  size,