@astryxdesign/core 0.1.7 → 0.1.8-canary.c5fa19b

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 (190) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +30 -19
  3. package/dist/Avatar/Avatar.d.ts +10 -5
  4. package/dist/Avatar/Avatar.d.ts.map +1 -1
  5. package/dist/Avatar/Avatar.js +12 -8
  6. package/dist/Avatar/AvatarSizeContext.d.ts +1 -1
  7. package/dist/Avatar/AvatarSizeContext.js +1 -1
  8. package/dist/Avatar/AvatarStatusDot.d.ts +2 -2
  9. package/dist/Avatar/AvatarStatusDot.js +2 -2
  10. package/dist/AvatarGroup/AvatarGroup.d.ts +2 -2
  11. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  12. package/dist/AvatarGroup/AvatarGroup.js +2 -2
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  15. package/dist/AvatarGroup/AvatarGroupOverflow.js +16 -14
  16. package/dist/Carousel/Carousel.d.ts +3 -2
  17. package/dist/Carousel/Carousel.d.ts.map +1 -1
  18. package/dist/Carousel/Carousel.js +32 -2
  19. package/dist/Chat/ChatMessage.d.ts +1 -1
  20. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  21. package/dist/Chat/ChatMessage.js +1 -1
  22. package/dist/Citation/Citation.d.ts.map +1 -1
  23. package/dist/Citation/Citation.js +10 -4
  24. package/dist/Collapsible/Collapsible.d.ts +11 -1
  25. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  26. package/dist/Collapsible/Collapsible.js +36 -4
  27. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  28. package/dist/ContextMenu/ContextMenu.js +4 -3
  29. package/dist/ContextMenu/index.d.ts +3 -0
  30. package/dist/ContextMenu/index.d.ts.map +1 -1
  31. package/dist/ContextMenu/index.js +7 -1
  32. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  33. package/dist/DropdownMenu/DropdownMenu.js +8 -4
  34. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +89 -0
  35. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -0
  36. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +170 -0
  37. package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -1
  38. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  39. package/dist/DropdownMenu/DropdownMenuContext.js +18 -0
  40. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +69 -0
  41. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -0
  42. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +70 -0
  43. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +69 -0
  44. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -0
  45. package/dist/DropdownMenu/DropdownMenuRadioItem.js +178 -0
  46. package/dist/DropdownMenu/index.d.ts +5 -1
  47. package/dist/DropdownMenu/index.d.ts.map +1 -1
  48. package/dist/DropdownMenu/index.js +10 -1
  49. package/dist/DropdownMenu/menuItemRoles.d.ts +13 -0
  50. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -0
  51. package/dist/DropdownMenu/menuItemRoles.js +15 -0
  52. package/dist/Icon/Icon.d.ts +43 -13
  53. package/dist/Icon/Icon.d.ts.map +1 -1
  54. package/dist/Icon/Icon.js +62 -27
  55. package/dist/Outline/Outline.d.ts +69 -3
  56. package/dist/Outline/Outline.d.ts.map +1 -1
  57. package/dist/Outline/Outline.js +129 -26
  58. package/dist/Outline/useScrollSpy.d.ts +27 -7
  59. package/dist/Outline/useScrollSpy.d.ts.map +1 -1
  60. package/dist/Outline/useScrollSpy.js +202 -70
  61. package/dist/TabList/Tab.d.ts.map +1 -1
  62. package/dist/TabList/Tab.js +2 -2
  63. package/dist/TabList/TabList.d.ts.map +1 -1
  64. package/dist/TabList/TabList.js +2 -0
  65. package/dist/TabList/TabMenu.d.ts.map +1 -1
  66. package/dist/TabList/TabMenu.js +1 -1
  67. package/dist/Table/Table.d.ts +1 -1
  68. package/dist/Table/Table.js +1 -1
  69. package/dist/Table/index.d.ts +2 -0
  70. package/dist/Table/index.d.ts.map +1 -1
  71. package/dist/Table/index.js +1 -0
  72. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  73. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +24 -2
  74. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  75. package/dist/Table/plugins/sortable/useTableSortable.js +18 -7
  76. package/dist/Table/plugins/tree/index.d.ts +5 -0
  77. package/dist/Table/plugins/tree/index.d.ts.map +1 -0
  78. package/dist/Table/plugins/tree/index.js +4 -0
  79. package/dist/Table/plugins/tree/useTableTreeData.d.ts +38 -0
  80. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -0
  81. package/dist/Table/plugins/tree/useTableTreeData.js +358 -0
  82. package/dist/Table/plugins/tree/useTableTreeState.d.ts +51 -0
  83. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -0
  84. package/dist/Table/plugins/tree/useTableTreeState.js +175 -0
  85. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  86. package/dist/Table/useBaseTablePlugins.js +6 -3
  87. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  88. package/dist/Toolbar/Toolbar.js +8 -1
  89. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  90. package/dist/TreeList/TreeListItem.js +5 -14
  91. package/dist/astryx.css +24 -4
  92. package/dist/astryx.umd.js +54 -54
  93. package/dist/astryx.umd.js.map +4 -4
  94. package/dist/theme/Theme.js +1 -1
  95. package/dist/theme/defineTheme.d.ts +1 -1
  96. package/dist/theme/defineTheme.js +1 -1
  97. package/dist/theme/hct.d.ts +0 -1
  98. package/dist/theme/hct.d.ts.map +1 -1
  99. package/dist/theme/hct.js +0 -3
  100. package/docs.mjs +32 -461
  101. package/locales/en.json +200 -172
  102. package/locales/pseudo.json +21 -0
  103. package/package.json +3 -1
  104. package/scripts/postinstall.mjs +93 -0
  105. package/src/Avatar/Avatar.doc.mjs +6 -6
  106. package/src/Avatar/Avatar.tsx +16 -11
  107. package/src/Avatar/AvatarSizeContext.ts +1 -1
  108. package/src/Avatar/AvatarStatusDot.tsx +2 -2
  109. package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -1
  110. package/src/AvatarGroup/AvatarGroup.test.tsx +17 -3
  111. package/src/AvatarGroup/AvatarGroup.tsx +3 -3
  112. package/src/AvatarGroup/AvatarGroupOverflow.doc.mjs +4 -4
  113. package/src/AvatarGroup/AvatarGroupOverflow.tsx +21 -5
  114. package/src/Carousel/Carousel.doc.mjs +1 -0
  115. package/src/Carousel/Carousel.test.tsx +96 -1
  116. package/src/Carousel/Carousel.tsx +29 -2
  117. package/src/Chat/Chat.doc.mjs +1 -1
  118. package/src/Chat/ChatMessage.tsx +4 -2
  119. package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
  120. package/src/Citation/Citation.test.tsx +51 -0
  121. package/src/Citation/Citation.tsx +8 -2
  122. package/src/Collapsible/Collapsible.doc.mjs +7 -0
  123. package/src/Collapsible/Collapsible.test.tsx +80 -0
  124. package/src/Collapsible/Collapsible.tsx +58 -5
  125. package/src/ContextMenu/ContextMenu.test.tsx +75 -1
  126. package/src/ContextMenu/ContextMenu.tsx +10 -5
  127. package/src/ContextMenu/index.ts +15 -0
  128. package/src/DropdownMenu/DropdownMenu.doc.mjs +23 -0
  129. package/src/DropdownMenu/DropdownMenu.tsx +11 -6
  130. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +95 -0
  131. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +237 -0
  132. package/src/DropdownMenu/DropdownMenuContext.tsx +29 -1
  133. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +7 -1
  134. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +80 -0
  135. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +119 -0
  136. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +80 -0
  137. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +232 -0
  138. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +163 -0
  139. package/src/DropdownMenu/index.ts +23 -3
  140. package/src/DropdownMenu/menuItemRoles.ts +22 -0
  141. package/src/Field/Field.doc.mjs +1 -1
  142. package/src/Field/FieldLabel.doc.mjs +1 -1
  143. package/src/Icon/Icon.doc.mjs +12 -0
  144. package/src/Icon/Icon.test.tsx +142 -0
  145. package/src/Icon/Icon.tsx +98 -30
  146. package/src/Item/Item.doc.mjs +1 -1
  147. package/src/NumberInput/NumberInput.doc.mjs +2 -2
  148. package/src/Outline/Outline.doc.mjs +123 -3
  149. package/src/Outline/Outline.test.tsx +735 -0
  150. package/src/Outline/Outline.tsx +184 -33
  151. package/src/Outline/useScrollSpy.ts +248 -72
  152. package/src/Selector/SelectorOption.doc.mjs +1 -1
  153. package/src/SideNav/SideNavItem.doc.mjs +2 -2
  154. package/src/Switch/Switch.doc.mjs +1 -1
  155. package/src/TabList/Tab.tsx +5 -1
  156. package/src/TabList/TabList.doc.mjs +3 -3
  157. package/src/TabList/TabList.test.tsx +66 -0
  158. package/src/TabList/TabList.tsx +8 -0
  159. package/src/TabList/TabMenu.tsx +4 -1
  160. package/src/Table/Table.doc.mjs +2 -0
  161. package/src/Table/Table.tsx +1 -1
  162. package/src/Table/index.ts +7 -0
  163. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +90 -1
  164. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +37 -5
  165. package/src/Table/plugins/sortable/useTableSortable.test.tsx +95 -9
  166. package/src/Table/plugins/sortable/useTableSortable.tsx +23 -7
  167. package/src/Table/plugins/tree/index.ts +12 -0
  168. package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +163 -0
  169. package/src/Table/plugins/tree/useTableTreeData.test.tsx +594 -0
  170. package/src/Table/plugins/tree/useTableTreeData.tsx +495 -0
  171. package/src/Table/plugins/tree/useTableTreeState.test.tsx +636 -0
  172. package/src/Table/plugins/tree/useTableTreeState.tsx +253 -0
  173. package/src/Table/useBaseTablePlugins.ts +6 -2
  174. package/src/Table/useTableTreeData.doc.mjs +75 -0
  175. package/src/Table/useTableTreeState.doc.mjs +98 -0
  176. package/src/TextArea/TextArea.doc.mjs +1 -1
  177. package/src/TextInput/TextInput.doc.mjs +1 -1
  178. package/src/Toolbar/Toolbar.tsx +10 -3
  179. package/src/TreeList/TreeList.test.tsx +32 -1
  180. package/src/TreeList/TreeListItem.tsx +19 -10
  181. package/src/docs-script.test.mjs +18 -13
  182. package/src/postinstall.test.mjs +71 -0
  183. package/src/theme/Theme.doc.mjs +4 -4
  184. package/src/theme/Theme.tsx +1 -1
  185. package/src/theme/defineTheme.ts +1 -1
  186. package/src/theme/hct.ts +0 -4
  187. package/dist/TreeList/treeListItem.markers.stylex.d.ts +0 -16
  188. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +0 -1
  189. package/dist/TreeList/treeListItem.markers.stylex.js +0 -22
  190. package/src/TreeList/treeListItem.markers.stylex.ts +0 -20
@@ -0,0 +1,70 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file DropdownMenuRadioGroup.tsx
7
+ * @output DropdownMenuRadioGroup — a single-select group of menu items.
8
+ * @position Sub-component; wraps DropdownMenuRadioItem inside a DropdownMenu.
9
+ *
10
+ * Owns single-selection state (value/onChange) for its child
11
+ * DropdownMenuRadioItems and exposes it via context. Renders role="group" with
12
+ * an accessible name so the radios are announced as a set. Keyboard navigation
13
+ * comes from the parent DropdownMenu's useListFocus, which matches
14
+ * menuitemradio rows.
15
+ */
16
+ import { useMemo } from 'react';
17
+ import * as stylex from '@stylexjs/stylex';
18
+ import "../theme/tokens.stylex.js";
19
+ import { spacingVars } from "../theme/tokens.stylex.js";
20
+ import { mergeProps } from "../utils/index.js";
21
+ import { DropdownMenuRadioGroupContext } from "./DropdownMenuContext.js";
22
+ import { jsx as _jsx } from "react/jsx-runtime";
23
+ /**
24
+ * A single-select group of radio menu items (role="group" of menuitemradio).
25
+ *
26
+ * @example
27
+ * ```
28
+ * * import {
29
+ * DropdownMenuRadioGroup,
30
+ * DropdownMenuRadioItem,
31
+ * } from '@astryxdesign/core/DropdownMenu';
32
+ *
33
+ * <DropdownMenu button={{label: 'Sort'}}>
34
+ * <DropdownMenuRadioGroup value={sort} onChange={setSort} aria-label="Sort by">
35
+ * <DropdownMenuRadioItem value="newest" label="Newest" />
36
+ * <DropdownMenuRadioItem value="oldest" label="Oldest" />
37
+ * </DropdownMenuRadioGroup>
38
+ * </DropdownMenu>
39
+ * ```
40
+ */
41
+ export function DropdownMenuRadioGroup({
42
+ value,
43
+ onChange,
44
+ hasCloseOnSelect = true,
45
+ children,
46
+ className,
47
+ style,
48
+ ...rest
49
+ }) {
50
+ const contextValue = useMemo(() => ({
51
+ value,
52
+ onChange,
53
+ hasCloseOnSelect
54
+ }), [value, onChange, hasCloseOnSelect]);
55
+ return /*#__PURE__*/_jsx("div", {
56
+ ...rest,
57
+ role: "group",
58
+ ...mergeProps({
59
+ className: "x78zum5 xdt5ytf x1lsbc85"
60
+ }, {
61
+ className,
62
+ style
63
+ }),
64
+ children: /*#__PURE__*/_jsx(DropdownMenuRadioGroupContext, {
65
+ value: contextValue,
66
+ children: children
67
+ })
68
+ });
69
+ }
70
+ DropdownMenuRadioGroup.displayName = 'DropdownMenuRadioGroup';
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @file DropdownMenuRadioItem.tsx
3
+ * @input React, stylex, Item + Icon + DropdownMenu context + tokens from core
4
+ * @output DropdownMenuRadioItem — a single option in a radio group.
5
+ * @position Sub-component; must be used inside a DropdownMenuRadioGroup.
6
+ *
7
+ * A menu item representing one option in a single-select group
8
+ * (role="menuitemradio"). The row owns the role and aria-checked; there is no
9
+ * nested native <input> (per the WAI-ARIA menuitemradio pattern). Selection
10
+ * state + onChange come from DropdownMenuRadioGroupContext. Keyboard nav +
11
+ * Enter/Space activation come from the parent DropdownMenu.
12
+ *
13
+ * The round radio visual (circle + center dot) is decorative (aria-hidden) —
14
+ * the row owns the checked state. Its size is derived from the menu's item size
15
+ * and it swaps to the inline-end of the row on coarse-pointer (touch) devices
16
+ * via CSS `order`. The dot is a shaped element, not an icon (a filled circle
17
+ * has no registry glyph).
18
+ */
19
+ import { type ReactNode } from 'react';
20
+ import { type IconType } from '../Icon';
21
+ import type { BaseProps } from '../BaseProps';
22
+ export interface DropdownMenuRadioItemProps extends Omit<BaseProps, 'role' | 'aria-checked' | 'tabIndex'> {
23
+ /**
24
+ * The value this item represents within its group. The group's `value`
25
+ * matches against this to determine the checked state.
26
+ */
27
+ value: string;
28
+ /**
29
+ * Primary label text identifying the option.
30
+ */
31
+ label: ReactNode;
32
+ /**
33
+ * Secondary description text displayed below the label.
34
+ */
35
+ description?: ReactNode;
36
+ /**
37
+ * Icon to display before the label. Accepts a semantic icon name (see
38
+ * `npx astryx docs icons`) or a rendered node.
39
+ */
40
+ icon?: ReactNode | IconType;
41
+ /**
42
+ * Whether this individual radio item is disabled. Disabled items stay
43
+ * focusable (via `aria-disabled`) so they remain discoverable by keyboard
44
+ * and assistive technology, but selection is blocked.
45
+ * @default false
46
+ */
47
+ isDisabled?: boolean;
48
+ /**
49
+ * Content to render after the label and description, such as a badge or
50
+ * metadata.
51
+ */
52
+ endContent?: ReactNode;
53
+ }
54
+ /**
55
+ * A single option in a DropdownMenuRadioGroup (role="menuitemradio").
56
+ *
57
+ * @example
58
+ * ```
59
+ * <DropdownMenuRadioGroup value={sort} onChange={setSort} aria-label="Sort by">
60
+ * <DropdownMenuRadioItem value="newest" label="Newest" />
61
+ * <DropdownMenuRadioItem value="oldest" label="Oldest" icon="clock" />
62
+ * </DropdownMenuRadioGroup>
63
+ * ```
64
+ */
65
+ export declare function DropdownMenuRadioItem({ value, label, description, icon, isDisabled, endContent, xstyle, className, style, ...rest }: DropdownMenuRadioItemProps): import("react").JSX.Element;
66
+ export declare namespace DropdownMenuRadioItem {
67
+ var displayName: string;
68
+ }
69
+ //# sourceMappingURL=DropdownMenuRadioItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropdownMenuRadioItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuRadioItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAc,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAElD,OAAO,EAAiB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAWtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAsE5C,MAAM,WAAW,0BAA2B,SAAQ,IAAI,CACtD,SAAS,EACT,MAAM,GAAG,cAAc,GAAG,UAAU,CACrC;IACC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,KAAK,EACL,WAAW,EACX,IAAI,EACJ,UAAkB,EAClB,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,0BAA0B,+BAiE5B;yBA5Ee,qBAAqB"}
@@ -0,0 +1,178 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file DropdownMenuRadioItem.tsx
7
+ * @input React, stylex, Item + Icon + DropdownMenu context + tokens from core
8
+ * @output DropdownMenuRadioItem — a single option in a radio group.
9
+ * @position Sub-component; must be used inside a DropdownMenuRadioGroup.
10
+ *
11
+ * A menu item representing one option in a single-select group
12
+ * (role="menuitemradio"). The row owns the role and aria-checked; there is no
13
+ * nested native <input> (per the WAI-ARIA menuitemradio pattern). Selection
14
+ * state + onChange come from DropdownMenuRadioGroupContext. Keyboard nav +
15
+ * Enter/Space activation come from the parent DropdownMenu.
16
+ *
17
+ * The round radio visual (circle + center dot) is decorative (aria-hidden) —
18
+ * the row owns the checked state. Its size is derived from the menu's item size
19
+ * and it swaps to the inline-end of the row on coarse-pointer (touch) devices
20
+ * via CSS `order`. The dot is a shaped element, not an icon (a filled circle
21
+ * has no registry glyph).
22
+ */
23
+ import { useCallback } from 'react';
24
+ import * as stylex from '@stylexjs/stylex';
25
+ import { renderIconSlot } from "../Icon/index.js";
26
+ import { Item } from "../Item/index.js";
27
+ import { useDropdownMenuContext } from "./DropdownMenuContext.js";
28
+ import "../theme/tokens.stylex.js";
29
+ import { colorVars, spacingVars, durationVars, easeVars, borderVars } from "../theme/tokens.stylex.js";
30
+ import { mergeProps, themeProps } from "../utils/index.js";
31
+ import { useDropdownMenuRadioGroupContext } from "./DropdownMenuContext.js";
32
+ import { jsx as _jsx } from "react/jsx-runtime";
33
+ const styles = {
34
+ root: {
35
+ kzqmXN: "xh8yej3",
36
+ kaIpWk: "x1ws5lxm",
37
+ kMwMTN: "x1tgivj0",
38
+ kWkggS: "xjbqb8w x1c52tdz x1uwx2nv",
39
+ kkrTdU: "x1ypdohk",
40
+ kI3sdo: "x1a2a7pz",
41
+ $$css: true
42
+ },
43
+ disabled: {
44
+ kSiTet: "xbyyjgo",
45
+ kkrTdU: "x1h6gzvc",
46
+ $$css: true
47
+ },
48
+ circle: {
49
+ k1xSpc: "x78zum5",
50
+ kGNEyG: "x6s0dn4",
51
+ kjj79g: "xl56j7k",
52
+ kmuXW: "x2lah0s",
53
+ kB7OPa: "x9f619",
54
+ kMzoRj: "x1litavf",
55
+ ksu8eU: "x1y0btm7",
56
+ kaIpWk: "x16rqkct",
57
+ k1ekBW: "xts7igz",
58
+ kIyJzY: "xuedmi6 x12w9bfk",
59
+ kAMwcw: "xlr8y92",
60
+ kayTVb: "x1g77sc7 xozvky",
61
+ keTefX: "x1lziwak x1jymrmb",
62
+ $$css: true
63
+ },
64
+ unchecked: {
65
+ kVAM5u: "xvy26l8",
66
+ kWkggS: "x10xzikg",
67
+ $$css: true
68
+ },
69
+ checked: {
70
+ kVAM5u: "xad5do",
71
+ kWkggS: "x1ewilqj",
72
+ $$css: true
73
+ },
74
+ dot: {
75
+ kaIpWk: "x16rqkct",
76
+ kWkggS: "x1azo05",
77
+ $$css: true
78
+ }
79
+ };
80
+ const circleSizeStyles = {
81
+ sm: {
82
+ kzqmXN: "x1xp8n7a",
83
+ kZKoxP: "xmix8c7",
84
+ $$css: true
85
+ },
86
+ md: {
87
+ kzqmXN: "x17z2i9w",
88
+ kZKoxP: "x17rw0jw",
89
+ $$css: true
90
+ }
91
+ };
92
+ const dotSizeStyles = {
93
+ sm: {
94
+ kzqmXN: "x1v4s8kt",
95
+ kZKoxP: "xols6we",
96
+ $$css: true
97
+ },
98
+ md: {
99
+ kzqmXN: "x1xc55vz",
100
+ kZKoxP: "xdk7pt",
101
+ $$css: true
102
+ }
103
+ };
104
+ /**
105
+ * A single option in a DropdownMenuRadioGroup (role="menuitemradio").
106
+ *
107
+ * @example
108
+ * ```
109
+ * <DropdownMenuRadioGroup value={sort} onChange={setSort} aria-label="Sort by">
110
+ * <DropdownMenuRadioItem value="newest" label="Newest" />
111
+ * <DropdownMenuRadioItem value="oldest" label="Oldest" icon="clock" />
112
+ * </DropdownMenuRadioGroup>
113
+ * ```
114
+ */
115
+ export function DropdownMenuRadioItem({
116
+ value,
117
+ label,
118
+ description,
119
+ icon,
120
+ isDisabled = false,
121
+ endContent,
122
+ xstyle,
123
+ className,
124
+ style,
125
+ ...rest
126
+ }) {
127
+ const menuCtx = useDropdownMenuContext();
128
+ const groupCtx = useDropdownMenuRadioGroupContext();
129
+ if (!groupCtx) {
130
+ throw new Error('DropdownMenuRadioItem must be used within a DropdownMenuRadioGroup');
131
+ }
132
+ const menuSize = menuCtx?.menuSize ?? 'md';
133
+ const controlSize = menuSize === 'sm' ? 'sm' : 'md';
134
+ const isChecked = groupCtx.value === value;
135
+ const handleClick = useCallback(() => {
136
+ if (isDisabled) {
137
+ return;
138
+ }
139
+ groupCtx.onChange(value);
140
+ if (groupCtx.hasCloseOnSelect) {
141
+ menuCtx?.closeMenu();
142
+ }
143
+ }, [isDisabled, groupCtx, value, menuCtx]);
144
+ return /*#__PURE__*/_jsx(Item, {
145
+ ...rest,
146
+ role: "menuitemradio",
147
+ "aria-checked": isChecked,
148
+ tabIndex: isDisabled ? undefined : -1,
149
+ marker: /*#__PURE__*/_jsx("span", {
150
+ "aria-hidden": "true",
151
+ ...mergeProps(themeProps('dropdown-menu-radio', {
152
+ size: controlSize,
153
+ checked: isChecked ? 'checked' : null,
154
+ disabled: isDisabled ? 'disabled' : null
155
+ }), stylex.props(styles.circle, circleSizeStyles[controlSize], isChecked ? styles.checked : styles.unchecked)),
156
+ children: isChecked && /*#__PURE__*/_jsx("span", {
157
+ ...stylex.props(styles.dot, dotSizeStyles[controlSize])
158
+ })
159
+ }),
160
+ startContent: icon ? renderIconSlot(icon, {
161
+ size: 'sm',
162
+ color: 'secondary'
163
+ }) : undefined,
164
+ label: label,
165
+ description: description,
166
+ endContent: endContent,
167
+ onClick: handleClick,
168
+ isDisabled: isDisabled,
169
+ xstyle: [styles.root, isDisabled && styles.disabled, xstyle],
170
+ ...mergeProps(themeProps('dropdown-menu-item', {
171
+ size: menuSize
172
+ }), {
173
+ className,
174
+ style
175
+ })
176
+ });
177
+ }
178
+ DropdownMenuRadioItem.displayName = 'DropdownMenuRadioItem';
@@ -4,5 +4,9 @@
4
4
  * @position Public API entry point
5
5
  */
6
6
  export { DropdownMenu, type DropdownMenuProps, type DropdownMenuButtonProps, type DropdownMenuItemData, type DropdownMenuDivider, type DropdownMenuSection, type DropdownMenuOption, } from './DropdownMenu';
7
- export { DropdownMenuItem, type DropdownMenuItemProps, } from './DropdownMenuItem';
7
+ export { DropdownMenuItem, type DropdownMenuItemProps } from './DropdownMenuItem';
8
+ export { DropdownMenuCheckboxItem, type DropdownMenuCheckboxItemProps, } from './DropdownMenuCheckboxItem';
9
+ export { DropdownMenuRadioGroup, type DropdownMenuRadioGroupProps, } from './DropdownMenuRadioGroup';
10
+ export { DropdownMenuRadioItem, type DropdownMenuRadioItemProps, } from './DropdownMenuRadioItem';
11
+ export { DropdownMenuContext, useDropdownMenuContext, type DropdownMenuContextValue, type DropdownMenuSize, } from './DropdownMenuContext';
8
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAC,gBAAgB,EAAE,KAAK,qBAAqB,EAAC,MAAM,oBAAoB,CAAC;AAGhF,OAAO,EACL,wBAAwB,EACxB,KAAK,6BAA6B,GACnC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,sBAAsB,EACtB,KAAK,2BAA2B,GACjC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC"}
@@ -8,4 +8,13 @@
8
8
  * @position Public API entry point
9
9
  */
10
10
  export { DropdownMenu } from "./DropdownMenu.js";
11
- export { DropdownMenuItem } from "./DropdownMenuItem.js";
11
+ export { DropdownMenuItem } from "./DropdownMenuItem.js";
12
+
13
+ // Selectable items — checkbox (independent) and radio (single-select group).
14
+ export { DropdownMenuCheckboxItem } from "./DropdownMenuCheckboxItem.js";
15
+ export { DropdownMenuRadioGroup } from "./DropdownMenuRadioGroup.js";
16
+ export { DropdownMenuRadioItem } from "./DropdownMenuRadioItem.js";
17
+
18
+ // Menu-coordination context — public so consumers can build custom menu items
19
+ // that read the menu size / close the menu.
20
+ export { DropdownMenuContext, useDropdownMenuContext } from "./DropdownMenuContext.js";
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @file menuItemRoles.ts
3
+ * @output Shared menu-item role set + focus selector.
4
+ * @position Internal; used by DropdownMenu and ContextMenu so their
5
+ * roving-focus, typeahead, and Enter/Space activation stay in sync.
6
+ *
7
+ * Includes the selectable items (menuitemradio/menuitemcheckbox) alongside
8
+ * plain menuitem so checkbox/radio rows are reachable by arrow keys, typeahead,
9
+ * and Enter/Space — not just role="menuitem".
10
+ */
11
+ export declare const MENU_ITEM_ROLES: ReadonlySet<string>;
12
+ export declare const MENU_ITEM_SELECTOR: string;
13
+ //# sourceMappingURL=menuItemRoles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menuItemRoles.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/menuItemRoles.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAI9C,CAAC;AAEH,eAAO,MAAM,kBAAkB,EAAE,MAErB,CAAC"}
@@ -0,0 +1,15 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file menuItemRoles.ts
5
+ * @output Shared menu-item role set + focus selector.
6
+ * @position Internal; used by DropdownMenu and ContextMenu so their
7
+ * roving-focus, typeahead, and Enter/Space activation stay in sync.
8
+ *
9
+ * Includes the selectable items (menuitemradio/menuitemcheckbox) alongside
10
+ * plain menuitem so checkbox/radio rows are reachable by arrow keys, typeahead,
11
+ * and Enter/Space — not just role="menuitem".
12
+ */
13
+
14
+ export const MENU_ITEM_ROLES = new Set(['menuitem', 'menuitemradio', 'menuitemcheckbox']);
15
+ export const MENU_ITEM_SELECTOR = [...MENU_ITEM_ROLES].map(role => `[role="${role}"]:not([aria-disabled="true"])`).join(',');
@@ -82,23 +82,28 @@ declare const colorStyles: Readonly<{
82
82
  /**
83
83
  * Size styles for direct SVG icon components.
84
84
  * Uses width/height only — SVG components handle their own viewBox scaling.
85
+ *
86
+ * Sizes are expressed in `rem` (relative to the root font-size) so icons scale
87
+ * in step with text when the document font-size changes, matching the rest of
88
+ * the design system's rem-based type scale. Values are the px-equivalents at a
89
+ * 16px root: 12px → 0.75rem, 16px → 1rem, 20px → 1.25rem, 24px → 1.5rem.
85
90
  */
86
91
  declare const sizeStyles: Readonly<{
87
92
  readonly xsm: Readonly<{
88
- readonly width: stylex.StyleXClassNameFor<"width", 12>;
89
- readonly height: stylex.StyleXClassNameFor<"height", 12>;
93
+ readonly width: stylex.StyleXClassNameFor<"width", "0.75rem">;
94
+ readonly height: stylex.StyleXClassNameFor<"height", "0.75rem">;
90
95
  }>;
91
96
  readonly sm: Readonly<{
92
- readonly width: stylex.StyleXClassNameFor<"width", 16>;
93
- readonly height: stylex.StyleXClassNameFor<"height", 16>;
97
+ readonly width: stylex.StyleXClassNameFor<"width", "1rem">;
98
+ readonly height: stylex.StyleXClassNameFor<"height", "1rem">;
94
99
  }>;
95
100
  readonly md: Readonly<{
96
- readonly width: stylex.StyleXClassNameFor<"width", 20>;
97
- readonly height: stylex.StyleXClassNameFor<"height", 20>;
101
+ readonly width: stylex.StyleXClassNameFor<"width", "1.25rem">;
102
+ readonly height: stylex.StyleXClassNameFor<"height", "1.25rem">;
98
103
  }>;
99
104
  readonly lg: Readonly<{
100
- readonly width: stylex.StyleXClassNameFor<"width", 24>;
101
- readonly height: stylex.StyleXClassNameFor<"height", 24>;
105
+ readonly width: stylex.StyleXClassNameFor<"width", "1.5rem">;
106
+ readonly height: stylex.StyleXClassNameFor<"height", "1.5rem">;
102
107
  }>;
103
108
  }>;
104
109
  export type IconColor = keyof typeof colorStyles;
@@ -128,13 +133,38 @@ export interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'ref' | 'color'
128
133
  color?: IconColor;
129
134
  /**
130
135
  * The size of the icon.
131
- * - 'xsm': 12px
132
- * - 'sm': 16px
133
- * - 'md': 20px
134
- * - 'lg': 24px
136
+ * - 'xsm': 0.75rem (12px at a 16px root)
137
+ * - 'sm': 1rem (16px at a 16px root)
138
+ * - 'md': 1.25rem (20px at a 16px root)
139
+ * - 'lg': 1.5rem (24px at a 16px root)
135
140
  * @default 'md'
136
141
  */
137
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;
138
168
  }
139
169
  /**
140
170
  * Renders an icon from the icon registry or a custom SVG component.
@@ -144,7 +174,7 @@ export interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'ref' | 'color'
144
174
  * <Icon icon="close" size="md" color="primary" />
145
175
  * ```
146
176
  */
147
- 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;
148
178
  export declare namespace Icon {
149
179
  var displayName: string;
150
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;;;GAGG;AACH,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;EAiBd,CAAC;AAiCH,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
@@ -128,26 +128,31 @@ const colorStyles = {
128
128
  /**
129
129
  * Size styles for direct SVG icon components.
130
130
  * Uses width/height only — SVG components handle their own viewBox scaling.
131
+ *
132
+ * Sizes are expressed in `rem` (relative to the root font-size) so icons scale
133
+ * in step with text when the document font-size changes, matching the rest of
134
+ * the design system's rem-based type scale. Values are the px-equivalents at a
135
+ * 16px root: 12px → 0.75rem, 16px → 1rem, 20px → 1.25rem, 24px → 1.5rem.
131
136
  */
132
137
  const sizeStyles = {
133
138
  xsm: {
134
- kzqmXN: "xsmyaan",
135
- kZKoxP: "x1kpxq89",
139
+ kzqmXN: "x1jw3ynk",
140
+ kZKoxP: "xvle69y",
136
141
  $$css: true
137
142
  },
138
143
  sm: {
139
- kzqmXN: "x1kky2od",
140
- kZKoxP: "xlup9mm",
144
+ kzqmXN: "xcdlrvm",
145
+ kZKoxP: "x1l36t39",
141
146
  $$css: true
142
147
  },
143
148
  md: {
144
- kzqmXN: "xw4jnvo",
145
- kZKoxP: "x1qx5ct2",
149
+ kzqmXN: "xwqq7k2",
150
+ kZKoxP: "xmll18r",
146
151
  $$css: true
147
152
  },
148
153
  lg: {
149
- kzqmXN: "xvy4d1p",
150
- kZKoxP: "xxk0z11",
154
+ kzqmXN: "xp8d6y2",
155
+ kZKoxP: "xam5rvr",
151
156
  $$css: true
152
157
  }
153
158
  };
@@ -155,30 +160,33 @@ const sizeStyles = {
155
160
  /**
156
161
  * Size styles for string-based (registry) icons.
157
162
  * Includes fontSize so that 1em-based icons from the registry scale correctly.
163
+ *
164
+ * Expressed in `rem` for the same reason as {@link sizeStyles} — icons track the
165
+ * root font-size instead of being locked to absolute pixels.
158
166
  */
159
167
  const spanSizeStyles = {
160
168
  xsm: {
161
- kzqmXN: "xsmyaan",
162
- kZKoxP: "x1kpxq89",
163
- kGuDYH: "xfifm61",
169
+ kzqmXN: "x1jw3ynk",
170
+ kZKoxP: "xvle69y",
171
+ kGuDYH: "xboafo0",
164
172
  $$css: true
165
173
  },
166
174
  sm: {
167
- kzqmXN: "x1kky2od",
168
- kZKoxP: "xlup9mm",
169
- kGuDYH: "x1j61zf2",
175
+ kzqmXN: "xcdlrvm",
176
+ kZKoxP: "x1l36t39",
177
+ kGuDYH: "x1jchvi3",
170
178
  $$css: true
171
179
  },
172
180
  md: {
173
- kzqmXN: "xw4jnvo",
174
- kZKoxP: "x1qx5ct2",
175
- kGuDYH: "xwsyq91",
181
+ kzqmXN: "xwqq7k2",
182
+ kZKoxP: "xmll18r",
183
+ kGuDYH: "x1603h9y",
176
184
  $$css: true
177
185
  },
178
186
  lg: {
179
- kzqmXN: "xvy4d1p",
180
- kZKoxP: "xxk0z11",
181
- kGuDYH: "x1pvqxga",
187
+ kzqmXN: "xp8d6y2",
188
+ kZKoxP: "xam5rvr",
189
+ kGuDYH: "xngnso2",
182
190
  $$css: true
183
191
  }
184
192
  };
@@ -197,6 +205,26 @@ const spanSizeStyles = {
197
205
  * Extends SVGProps to allow passing additional SVG attributes (used when icon is a component).
198
206
  */
199
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
+
200
228
  // =============================================================================
201
229
  // Component
202
230
  // =============================================================================
@@ -213,15 +241,21 @@ export function Icon({
213
241
  icon,
214
242
  color = 'inherit',
215
243
  size = 'md',
244
+ label,
216
245
  ref,
217
246
  ...props
218
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
+
219
252
  // String mode: resolve from icon registry, wrap in styled span
220
253
  if (typeof icon === 'string') {
221
254
  return /*#__PURE__*/_jsx(IconFromRegistry, {
222
255
  name: icon,
223
256
  color: color,
224
257
  size: size,
258
+ a11yProps: a11yProps,
225
259
  spanProps: props
226
260
  });
227
261
  }
@@ -229,8 +263,12 @@ export function Icon({
229
263
  // Component mode: render SVG component directly with ref forwarding
230
264
  const IconComponent = icon;
231
265
  return /*#__PURE__*/_jsx(IconComponent, {
232
- ref: ref,
233
- "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,
234
272
  ...mergeProps(themeProps('icon', {
235
273
  size,
236
274
  color
@@ -255,6 +293,7 @@ function IconFromRegistry({
255
293
  name,
256
294
  color,
257
295
  size,
296
+ a11yProps,
258
297
  spanProps
259
298
  }) {
260
299
  const resolvedIcon = getIcon(name);
@@ -262,11 +301,7 @@ function IconFromRegistry({
262
301
  return null;
263
302
  }
264
303
  return /*#__PURE__*/_jsx("span", {
265
- // Decorative by default, but placed BEFORE the prop spread so consumers
266
- // can override it (e.g. `aria-hidden={false}` + `role="img"` +
267
- // `aria-label`) to expose a meaningful standalone icon. This matches
268
- // component-mode Icon, which already sets aria-hidden before its spread.
269
- "aria-hidden": "true",
304
+ ...a11yProps,
270
305
  ...spanProps,
271
306
  ...mergeProps(themeProps('icon', {
272
307
  size,