@astryxdesign/core 0.5.1 → 0.5.2-canary.00477a5

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 (270) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/BottomSheet/BottomSheet.d.ts +3 -1
  3. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  4. package/dist/BottomSheet/BottomSheet.js +4 -3
  5. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +2 -2
  6. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -1
  7. package/dist/BottomSheet/BottomSheetEdgeTint.js +7 -10
  8. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  9. package/dist/BottomSheet/BottomSheetSwitcher.js +1 -1
  10. package/dist/Button/Button.d.ts +2 -1
  11. package/dist/Button/Button.d.ts.map +1 -1
  12. package/dist/Button/Button.js +11 -4
  13. package/dist/Carousel/Carousel.d.ts.map +1 -1
  14. package/dist/Carousel/Carousel.js +2 -2
  15. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  16. package/dist/Chat/ChatToolCalls.js +34 -17
  17. package/dist/ContextMenu/ContextMenu.d.ts +14 -3
  18. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  19. package/dist/ContextMenu/ContextMenu.js +149 -26
  20. package/dist/ContextMenu/index.d.ts +1 -0
  21. package/dist/ContextMenu/index.d.ts.map +1 -1
  22. package/dist/DropdownMenu/DropdownMenu.d.ts +24 -5
  23. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  24. package/dist/DropdownMenu/DropdownMenu.js +340 -26
  25. package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -1
  26. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  27. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  28. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  29. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -2
  30. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  31. package/dist/DropdownMenu/DropdownMenuSubMenu.js +43 -14
  32. package/dist/DropdownMenu/MenuBottomSheet.d.ts +20 -0
  33. package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -0
  34. package/dist/DropdownMenu/MenuBottomSheet.js +36 -0
  35. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts +10 -0
  36. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -0
  37. package/dist/DropdownMenu/MenuBottomSheetActionList.js +111 -0
  38. package/dist/DropdownMenu/index.d.ts +2 -1
  39. package/dist/DropdownMenu/index.d.ts.map +1 -1
  40. package/dist/DropdownMenu/menuWidth.d.ts +14 -0
  41. package/dist/DropdownMenu/menuWidth.d.ts.map +1 -0
  42. package/dist/DropdownMenu/menuWidth.js +35 -0
  43. package/dist/DropdownMenu/useMenuOverflow.d.ts +10 -0
  44. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -0
  45. package/dist/DropdownMenu/useMenuOverflow.js +60 -0
  46. package/dist/MoreMenu/MoreMenu.d.ts +8 -2
  47. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  48. package/dist/MoreMenu/MoreMenu.js +2 -0
  49. package/dist/MultiSelector/MultiSelector.d.ts +11 -1
  50. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  51. package/dist/MultiSelector/MultiSelector.js +97 -68
  52. package/dist/MultiSelector/index.d.ts +1 -1
  53. package/dist/MultiSelector/index.d.ts.map +1 -1
  54. package/dist/Popover/Popover.d.ts +10 -6
  55. package/dist/Popover/Popover.d.ts.map +1 -1
  56. package/dist/Popover/Popover.js +141 -16
  57. package/dist/Popover/usePopover.d.ts +4 -0
  58. package/dist/Popover/usePopover.d.ts.map +1 -1
  59. package/dist/Popover/usePopover.js +52 -5
  60. package/dist/Selector/Selector.d.ts +10 -0
  61. package/dist/Selector/Selector.d.ts.map +1 -1
  62. package/dist/Selector/Selector.js +106 -80
  63. package/dist/Selector/SelectorBottomSheet.d.ts +21 -0
  64. package/dist/Selector/SelectorBottomSheet.d.ts.map +1 -0
  65. package/dist/Selector/SelectorBottomSheet.js +83 -0
  66. package/dist/Selector/index.d.ts +1 -1
  67. package/dist/Selector/index.d.ts.map +1 -1
  68. package/dist/Selector/selectorPresentation.stylex.d.ts +16 -0
  69. package/dist/Selector/selectorPresentation.stylex.d.ts.map +1 -0
  70. package/dist/Selector/selectorPresentation.stylex.js +21 -0
  71. package/dist/Selector/useSelectorPresentation.d.ts +32 -0
  72. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -0
  73. package/dist/Selector/useSelectorPresentation.js +90 -0
  74. package/dist/Toast/useToastGesture.d.ts.map +1 -1
  75. package/dist/Toast/useToastGesture.js +46 -9
  76. package/dist/astryx.css +19 -1
  77. package/dist/hooks/useAdaptivePresentation.d.ts +5 -0
  78. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -0
  79. package/dist/hooks/useAdaptivePresentation.js +19 -0
  80. package/dist/hooks/useFocusReturnVisibility.d.ts +7 -0
  81. package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -0
  82. package/dist/hooks/useFocusReturnVisibility.js +35 -0
  83. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  84. package/dist/hooks/useFocusTrap.js +12 -0
  85. package/dist/i18n/InternationalizationContext.d.ts +2 -0
  86. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  87. package/dist/i18n/InternationalizationContext.js +3 -1
  88. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  89. package/dist/i18n/InternationalizationProvider.js +3 -1
  90. package/dist/i18n/resolve.d.ts +1 -1
  91. package/dist/i18n/resolve.d.ts.map +1 -1
  92. package/dist/i18n/resolve.js +37 -38
  93. package/dist/i18n/useTranslator.d.ts.map +1 -1
  94. package/dist/i18n/useTranslator.js +2 -3
  95. package/locales/af-ZA.json +0 -4
  96. package/locales/ar-SA.json +0 -4
  97. package/locales/ca-ES.json +0 -4
  98. package/locales/cs-CZ.json +0 -4
  99. package/locales/da-DK.json +0 -4
  100. package/locales/de-DE.json +0 -4
  101. package/locales/el-GR.json +0 -4
  102. package/locales/en.json +20 -0
  103. package/locales/es-ES.json +0 -4
  104. package/locales/fi-FI.json +0 -4
  105. package/locales/fr-FR.json +0 -4
  106. package/locales/he-IL.json +0 -4
  107. package/locales/hu-HU.json +0 -4
  108. package/locales/it-IT.json +0 -4
  109. package/locales/ja-JP.json +0 -4
  110. package/locales/ko-KR.json +0 -4
  111. package/locales/nl-NL.json +0 -4
  112. package/locales/no-NO.json +0 -4
  113. package/locales/pl-PL.json +0 -4
  114. package/locales/pseudo.json +15 -0
  115. package/locales/pt-BR.json +0 -4
  116. package/locales/pt-PT.json +0 -4
  117. package/locales/ro-RO.json +0 -4
  118. package/locales/ru-RU.json +0 -4
  119. package/locales/sr-SP.json +0 -4
  120. package/locales/sv-SE.json +0 -4
  121. package/locales/tr-TR.json +0 -4
  122. package/locales/uk-UA.json +0 -4
  123. package/locales/vi-VN.json +0 -4
  124. package/locales/zh-CN.json +0 -4
  125. package/locales/zh-TW.json +0 -4
  126. package/package.json +3 -3
  127. package/src/BottomSheet/BottomSheet.doc.mjs +37 -0
  128. package/src/BottomSheet/BottomSheet.spec.md +177 -0
  129. package/src/BottomSheet/BottomSheet.test.tsx +29 -0
  130. package/src/BottomSheet/BottomSheet.tsx +7 -4
  131. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -6
  132. package/src/BottomSheet/BottomSheetEdgeTint.tsx +7 -10
  133. package/src/BottomSheet/BottomSheetSwitcher.tsx +1 -2
  134. package/src/Button/Button.doc.mjs +56 -0
  135. package/src/Button/Button.test.tsx +10 -0
  136. package/src/Button/Button.tsx +13 -5
  137. package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
  138. package/src/Calendar/Calendar.doc.mjs +1 -1
  139. package/src/Carousel/Carousel.test.tsx +83 -0
  140. package/src/Carousel/Carousel.tsx +8 -2
  141. package/src/Chat/ChatToolCalls.test.tsx +44 -0
  142. package/src/Chat/ChatToolCalls.tsx +36 -15
  143. package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
  144. package/src/CheckboxList/CheckboxList.doc.mjs +173 -32
  145. package/src/CheckboxList/CheckboxList.spec.md +214 -0
  146. package/src/CommandPalette/CommandPalette.doc.mjs +72 -0
  147. package/src/CommandPalette/CommandPalette.spec.md +223 -0
  148. package/src/ComplexSelector/ComplexSelector.doc.mjs +44 -2
  149. package/src/ComplexSelector/ComplexSelector.spec.md +189 -0
  150. package/src/ContextMenu/ContextMenu.doc.mjs +13 -1
  151. package/src/ContextMenu/ContextMenu.test.tsx +131 -1
  152. package/src/ContextMenu/ContextMenu.tsx +199 -32
  153. package/src/ContextMenu/index.ts +1 -0
  154. package/src/DateInput/DateInput.doc.mjs +1 -1
  155. package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
  156. package/src/DateTimeInput/DateTimeInput.doc.mjs +1 -1
  157. package/src/Divider/Divider.doc.mjs +24 -0
  158. package/src/Divider/Divider.spec.md +150 -0
  159. package/src/DropdownMenu/DropdownMenu.doc.mjs +201 -40
  160. package/src/DropdownMenu/DropdownMenu.test.tsx +518 -7
  161. package/src/DropdownMenu/DropdownMenu.tsx +459 -28
  162. package/src/DropdownMenu/DropdownMenuContext.tsx +1 -1
  163. package/src/DropdownMenu/DropdownMenuItem.tsx +2 -0
  164. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +4 -2
  165. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +124 -0
  166. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +72 -17
  167. package/src/DropdownMenu/MenuBottomSheet.tsx +46 -0
  168. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +141 -0
  169. package/src/DropdownMenu/index.ts +2 -0
  170. package/src/DropdownMenu/menuWidth.ts +51 -0
  171. package/src/DropdownMenu/useMenuOverflow.ts +77 -0
  172. package/src/Field/Field.doc.mjs +1 -1
  173. package/src/FieldStatus/FieldStatus.doc.mjs +22 -1
  174. package/src/FieldStatus/FieldStatus.spec.md +212 -0
  175. package/src/FileInput/FileInput.doc.mjs +1 -1
  176. package/src/Grid/Grid.doc.mjs +19 -0
  177. package/src/Grid/Grid.spec.md +161 -0
  178. package/src/Icon/Icon.doc.mjs +196 -48
  179. package/src/Icon/Icon.spec.md +191 -0
  180. package/src/IconButton/IconButton.doc.mjs +38 -0
  181. package/src/Indicator/Indicator.doc.mjs +1 -1
  182. package/src/InputGroup/InputGroup.doc.mjs +1 -1
  183. package/src/Kbd/Kbd.doc.mjs +18 -0
  184. package/src/Kbd/Kbd.spec.md +141 -0
  185. package/src/Layout/Layout.doc.mjs +32 -0
  186. package/src/Layout/Layout.spec.md +199 -0
  187. package/src/Lightbox/Lightbox.doc.mjs +149 -33
  188. package/src/Lightbox/Lightbox.spec.md +197 -0
  189. package/src/Markdown/Markdown.doc.mjs +60 -0
  190. package/src/Markdown/Markdown.spec.md +200 -0
  191. package/src/MobileNav/MobileNav.doc.mjs +140 -32
  192. package/src/MobileNav/MobileNav.spec.md +208 -0
  193. package/src/MoreMenu/MoreMenu.doc.mjs +17 -0
  194. package/src/MoreMenu/MoreMenu.test.tsx +47 -0
  195. package/src/MoreMenu/MoreMenu.tsx +13 -1
  196. package/src/MultiSelector/MultiSelector.doc.mjs +129 -1
  197. package/src/MultiSelector/MultiSelector.spec.md +266 -0
  198. package/src/MultiSelector/MultiSelector.test.tsx +127 -0
  199. package/src/MultiSelector/MultiSelector.tsx +121 -73
  200. package/src/MultiSelector/index.ts +1 -0
  201. package/src/NavIcon/NavIcon.doc.mjs +17 -0
  202. package/src/NavIcon/NavIcon.spec.md +133 -0
  203. package/src/NavMenu/NavHeadingMenu.spec.md +205 -0
  204. package/src/NavMenu/NavMenu.doc.mjs +37 -0
  205. package/src/NumberInput/NumberInput.doc.mjs +1 -1
  206. package/src/Outline/Outline.doc.mjs +35 -0
  207. package/src/Outline/Outline.spec.md +161 -0
  208. package/src/OverflowList/OverflowList.doc.mjs +24 -0
  209. package/src/OverflowList/OverflowList.spec.md +156 -0
  210. package/src/Pagination/Pagination.doc.mjs +74 -0
  211. package/src/Pagination/Pagination.spec.md +225 -0
  212. package/src/Popover/Popover.doc.mjs +11 -11
  213. package/src/Popover/Popover.test.tsx +397 -2
  214. package/src/Popover/Popover.tsx +228 -21
  215. package/src/Popover/usePopover.tsx +92 -15
  216. package/src/PowerSearch/PowerSearch.doc.mjs +1 -1
  217. package/src/ProgressBar/ProgressBar.doc.mjs +198 -38
  218. package/src/ProgressBar/ProgressBar.spec.md +260 -0
  219. package/src/RadioList/RadioList.doc.mjs +1 -1
  220. package/src/Resizable/Resizable.doc.mjs +59 -16
  221. package/src/Resizable/Resizable.spec.md +194 -0
  222. package/src/Section/Section.doc.mjs +17 -0
  223. package/src/Section/Section.spec.md +138 -0
  224. package/src/SegmentedControl/SegmentedControl.doc.mjs +83 -0
  225. package/src/SegmentedControl/SegmentedControl.spec.md +151 -0
  226. package/src/Selector/Selector.doc.mjs +13 -1
  227. package/src/Selector/Selector.test.tsx +135 -0
  228. package/src/Selector/Selector.tsx +141 -82
  229. package/src/Selector/SelectorBottomSheet.tsx +97 -0
  230. package/src/Selector/index.ts +1 -0
  231. package/src/Selector/selectorPresentation.stylex.ts +20 -0
  232. package/src/Selector/useSelectorPresentation.ts +147 -0
  233. package/src/Skeleton/Skeleton.doc.mjs +12 -0
  234. package/src/Skeleton/Skeleton.spec.md +126 -0
  235. package/src/Slider/Slider.doc.mjs +186 -32
  236. package/src/Slider/Slider.spec.md +223 -0
  237. package/src/Stack/Stack.doc.mjs +22 -0
  238. package/src/Stack/Stack.spec.md +154 -0
  239. package/src/StatusDot/StatusDot.doc.mjs +17 -0
  240. package/src/StatusDot/StatusDot.spec.md +137 -0
  241. package/src/Switch/Switch.doc.mjs +41 -1
  242. package/src/Switch/Switch.spec.md +174 -0
  243. package/src/Text/Text.doc.mjs +190 -43
  244. package/src/Text/Text.spec.md +205 -0
  245. package/src/TextArea/TextArea.doc.mjs +256 -46
  246. package/src/TextArea/TextArea.spec.md +204 -0
  247. package/src/TextInput/TextInput.doc.mjs +1 -1
  248. package/src/TimeInput/TimeInput.doc.mjs +1 -1
  249. package/src/Toast/ToastViewport.test.tsx +118 -4
  250. package/src/Toast/useToastGesture.ts +61 -8
  251. package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
  252. package/src/Tokenizer/Tokenizer.doc.mjs +1 -1
  253. package/src/Toolbar/Toolbar.doc.mjs +19 -0
  254. package/src/Toolbar/Toolbar.spec.md +173 -0
  255. package/src/Tooltip/Tooltip.doc.mjs +17 -0
  256. package/src/Tooltip/Tooltip.spec.md +141 -0
  257. package/src/TreeList/TreeList.doc.mjs +58 -0
  258. package/src/TreeList/TreeList.spec.md +220 -0
  259. package/src/Typeahead/Typeahead.doc.mjs +84 -2
  260. package/src/Typeahead/Typeahead.spec.md +250 -0
  261. package/src/hooks/useAdaptivePresentation.ts +35 -0
  262. package/src/hooks/useFocusReturnVisibility.ts +45 -0
  263. package/src/hooks/useFocusTrap.test.tsx +40 -0
  264. package/src/hooks/useFocusTrap.ts +13 -0
  265. package/src/i18n/InternationalizationContext.ts +3 -0
  266. package/src/i18n/InternationalizationProvider.tsx +8 -1
  267. package/src/i18n/__tests__/resolve.test.ts +23 -1
  268. package/src/i18n/resolve.ts +46 -49
  269. package/src/i18n/useTranslator.ts +2 -7
  270. package/src/theme/themingTargets.test.ts +91 -25
@@ -1,5 +1,27 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Handle',
7
+ required: true,
8
+ description:
9
+ 'Focusable separator that owns pointer and keyboard resize interaction.',
10
+ },
11
+ {
12
+ name: 'Grip pill',
13
+ required: false,
14
+ description:
15
+ 'Default visible grip indicator; custom handle content can replace it.',
16
+ },
17
+ {
18
+ name: 'Grab zone',
19
+ required: true,
20
+ description:
21
+ 'Invisible enlarged pointer region aligned with the grip or divider.',
22
+ },
23
+ ];
24
+
3
25
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
26
  export const docs = {
5
27
  name: 'Resizable',
@@ -19,6 +41,7 @@ export const docs = {
19
41
  'grip',
20
42
  ],
21
43
  usage: {
44
+ anatomy,
22
45
  description:
23
46
  'Hook-based resizable panel system. useResizable() manages size state ' +
24
47
  'and ResizeHandle provides the interactive pill-grip separator. ' +
@@ -86,8 +109,7 @@ export const docs = {
86
109
  {
87
110
  name: 'collapsedSize',
88
111
  type: 'number',
89
- description:
90
- 'Pixel threshold that triggers collapse during drag.',
112
+ description: 'Pixel threshold that triggers collapse during drag.',
91
113
  default: '40',
92
114
  },
93
115
  {
@@ -98,13 +120,13 @@ export const docs = {
98
120
  {
99
121
  name: 'shrinkOrder',
100
122
  type: 'number',
101
- description:
102
- 'Cascade priority: lower number shrinks first.',
123
+ description: 'Cascade priority: lower number shrinks first.',
103
124
  },
104
125
  {
105
126
  name: 'autoSaveId',
106
127
  type: 'string',
107
- description: 'Key for persisting sizes and collapse state to localStorage.',
128
+ description:
129
+ 'Key for persisting sizes and collapse state to localStorage.',
108
130
  },
109
131
  ],
110
132
  },
@@ -190,20 +212,35 @@ export const docs = {
190
212
 
191
213
  /** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
192
214
  export const docsDense = {
193
- description: 'Hook-based resizable panel system. useResizable() manages size state; ResizeHandle provides interactive pill-grip separator.',
215
+ description:
216
+ 'Hook-based resizable panel system. useResizable() manages size state; ResizeHandle provides interactive pill-grip separator.',
194
217
  usage: {
218
+ anatomy,
195
219
  description:
196
220
  'Hook-based resizable panel system. useResizable() manages size state; ResizeHandle provides interactive pill-grip separator. Pass resize props to existing layout components via their resizable prop.',
197
221
  bestPractices: [
198
- {guidance: true, description: 'Use useResizable() w/ existing Astryx layout components. Pass returned props to resizable prop on LayoutPanel or SideNav.'},
199
- {guidance: true, description: 'Provide accessible label on each ResizeHandle when multiple handles exist (e.g. "Resize sidebar", "Resize terminal").'},
200
- {guidance: false, description: 'Wrap panels in extra container components for resize. Hook-first architecture avoids extra DOM; use it directly on existing components.'},
222
+ {
223
+ guidance: true,
224
+ description:
225
+ 'Use useResizable() w/ existing Astryx layout components. Pass returned props to resizable prop on LayoutPanel or SideNav.',
226
+ },
227
+ {
228
+ guidance: true,
229
+ description:
230
+ 'Provide accessible label on each ResizeHandle when multiple handles exist (e.g. "Resize sidebar", "Resize terminal").',
231
+ },
232
+ {
233
+ guidance: false,
234
+ description:
235
+ 'Wrap panels in extra container components for resize. Hook-first architecture avoids extra DOM; use it directly on existing components.',
236
+ },
201
237
  ],
202
238
  },
203
239
  components: [
204
240
  {
205
241
  name: 'useResizable',
206
- description: 'Hook managing resize state for one or more panel regions. Returns size, isCollapsed, collapse/expand/resize methods, + props to pass to handles.',
242
+ description:
243
+ 'Hook managing resize state for one or more panel regions. Returns size, isCollapsed, collapse/expand/resize methods, + props to pass to handles.',
207
244
  propDescriptions: {
208
245
  defaultSize: 'initial size in px or % string (e.g. "20%")',
209
246
  minSizePx: 'minimum size in px',
@@ -217,14 +254,20 @@ export const docsDense = {
217
254
  },
218
255
  {
219
256
  name: 'ResizeHandle',
220
- description: 'Draggable separator between panels. Pill-grip: invisible at rest, visible on hover (0.6 opacity), fully opaque during drag (1.0). Keyboard-accessible.',
257
+ description:
258
+ 'Draggable separator between panels. Pill-grip: invisible at rest, visible on hover (0.6 opacity), fully opaque during drag (1.0). Keyboard-accessible.',
221
259
  propDescriptions: {
222
- direction: 'layout direction: determines cursor + indicator orientation',
223
- isReversed: 'reverse drag direction. Use when handle controls panel on end/right/bottom side',
260
+ direction:
261
+ 'layout direction: determines cursor + indicator orientation',
262
+ isReversed:
263
+ 'reverse drag direction. Use when handle controls panel on end/right/bottom side',
224
264
  isDisabled: 'handle interactive?',
225
- hasDivider: 'show full-length 1px divider line through handle. Use when adjacent panels share same background',
226
- isAlwaysVisible: 'show pill grip at rest instead of only on hover. Use when discoverability important',
227
- pillPlacement: 'which side of divider pill sits on. auto = content side (derived from isReversed), flips when collapsed; start = left/top, end = right/bottom, center = centered on divider',
265
+ hasDivider:
266
+ 'show full-length 1px divider line through handle. Use when adjacent panels share same background',
267
+ isAlwaysVisible:
268
+ 'show pill grip at rest instead of only on hover. Use when discoverability important',
269
+ pillPlacement:
270
+ 'which side of divider pill sits on. auto = content side (derived from isReversed), flips when collapsed; start = left/top, end = right/bottom, center = centered on divider',
228
271
  label: 'accessible label for separator',
229
272
  resizable: 'resize props from useResizable: connects handle to panel',
230
273
  },
@@ -0,0 +1,194 @@
1
+ ---
2
+ schema_version: 1
3
+ template_version: 3
4
+ kind: component
5
+ id: component:Resizable
6
+ authority: draft
7
+ archive_reason: null
8
+ superseded_by: null
9
+ approved_by: null
10
+ approved_at: null
11
+ owners: [cixzhang]
12
+ review_triggers: [behavior, layout, theming, accessibility]
13
+ verified_by:
14
+ [
15
+ packages/core/src/Resizable/ResizeHandle.test.tsx,
16
+ packages/core/src/Resizable/useResizable.test.ts,
17
+ packages/core/src/theme/themingTargets.test.ts,
18
+ scripts/check-knowledge.mjs,
19
+ ]
20
+ families: []
21
+ design_specs: []
22
+ architecture:
23
+ [
24
+ architecture:component-theming-surface,
25
+ architecture:interaction-modality,
26
+ architecture:public-component-api,
27
+ ]
28
+ contributing: []
29
+ system_specs: []
30
+ ---
31
+
32
+ # Resizable component contract
33
+
34
+ ## Intent
35
+
36
+ Resizable combines the useResizable state and behavior hook with a focusable
37
+ ResizeHandle. The handle presents a default Grip pill over an enlarged invisible
38
+ Grab zone. This draft records current consumer anatomy and theming ownership
39
+ without changing resize semantics, runtime behavior, styling, targets, or public
40
+ API.
41
+
42
+ ## Compatibility and migration
43
+
44
+ - Released default preserved: `yes`
45
+ - Compatibility class: additive documentation only; runtime, DOM, styling,
46
+ targets, aliases, and public API remain unchanged
47
+ - Controlled/uncontrolled behavior: unchanged
48
+ - Migration decision: none
49
+
50
+ Consumer migration instructions belong in consumer docs and release notes.
51
+
52
+ ## Ownership boundary
53
+
54
+ **Owns**
55
+
56
+ - useResizable size, collapse, snapping, persistence, and resize lifecycle.
57
+ - ResizeHandle's separator semantics, pointer and keyboard interaction, and
58
+ current `resize-handle` target.
59
+ - The default Grip pill and its current `resize-handle-pill` target, plus the
60
+ aligned invisible Grab zone.
61
+
62
+ **Does not own / non-goals**
63
+
64
+ - The structural region being resized — owned by LayoutPanel, SideNav, or another
65
+ caller.
66
+ - Layout-region topology, inset, divider, or scrolling rules.
67
+ - A public target for the Grab zone; none exists on current `main`.
68
+ - Fixing the missing runtime reflection for the documented Handle `direction`
69
+ theming state in this documentation-only change.
70
+
71
+ ## Public concepts
72
+
73
+ No new public concept is introduced. Consumer props, hook outputs, and usage
74
+ remain documented in `Resizable.doc.mjs` and `useResizable.doc.mjs`.
75
+
76
+ ## Behavioral and layout contract
77
+
78
+ | ID | Candidate invariant | Basis | Draft review state |
79
+ | --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------------------------------------- |
80
+ | FR1 | ResizeHandle renders one focusable Handle and one enlarged Grab zone; the default render also contains a Grip pill, while caller-provided children replace that pill. | Current source, docs, and tests | Verified current behavior; no new behavior decided |
81
+ | FR2 | Handle carries `resize-handle`, Grip pill carries `resize-handle-pill`, and Grab zone carries no public target. | Current source and public docs | Verified current target inventory; no target change |
82
+ | FR3 | Pointer, keyboard, collapse, snap, persistence, reversal, and size behavior remain owned by ResizeHandle and useResizable rather than layout-regions collaborators. | Current source, docs, and tests | Verified current ownership; resize semantics remain unchanged |
83
+ | FR4 | Resizable metadata advertises `direction` as a Handle visual state, but current runtime calls `themeProps('resize-handle')` without reflecting that value, so direction selectors cannot match. | Current source and public docs | Verified audit gap; deliberately not fixed in this change |
84
+
85
+ ### Allowed variation
86
+
87
+ - **AV1 — Axis.** Handle may resize along the horizontal or vertical layout axis;
88
+ separator orientation and cursor follow the current implementation.
89
+ - **AV2 — Placement.** Handle may participate inline or overlay its parent, and
90
+ Grip pill may sit at start, end, center, or the current automatic side.
91
+ - **AV3 — Grip content.** Caller-provided children may replace Grip pill without
92
+ changing Handle or Grab zone ownership.
93
+ - **AV4 — Divider.** Handle may paint its current divider treatment; a composing
94
+ region remains responsible for avoiding a duplicate adjacent divider.
95
+
96
+ ### Representative states
97
+
98
+ | State | Required invariant | Allowed variation |
99
+ | ---------------------- | --------------------------------------------------------------------- | -------------------------------------------------- |
100
+ | Default handle | Handle, Grab zone, and Grip pill render. | Divider and always-visible treatment may vary. |
101
+ | Custom handle content | Handle and Grab zone remain; caller content replaces Grip pill. | Caller content remains caller-owned. |
102
+ | Horizontal or vertical | Interaction follows the selected axis and current ARIA orientation. | Size, reversal, and pill placement may vary. |
103
+ | Collapsed or expanded | Handle preserves valid separator value semantics and resize controls. | Grip pill automatic side follows current behavior. |
104
+ | Disabled | Handle remains represented but is removed from interactive tab order. | Painted treatment follows existing styles. |
105
+
106
+ ### Transformation and precedence order
107
+
108
+ - No new clamp, snap, collapse, persistence, reversal, pointer, or keyboard order
109
+ is introduced.
110
+
111
+ ### Performance and resources
112
+
113
+ - No new listener, storage, observer, or render requirement is introduced.
114
+
115
+ ## Accessibility contract
116
+
117
+ This draft does not change or extend ResizeHandle's existing separator role,
118
+ label, orientation, value, collapsed value text, focus, pointer, or keyboard
119
+ behavior.
120
+
121
+ ## Design relationships
122
+
123
+ | Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
124
+ | ---------------- | ----------------------------------------------------------------------- | ------------------------------ | -------------- | ------------------ |
125
+ | Handle | Presents the focusable resize separator and optional divider treatment. | Current source and public docs | Prominent | FR1, FR2, FR3 |
126
+ | Grip pill | Presents the default visible resize affordance. | Current source and public docs | Supporting | FR1, FR2 |
127
+ | Grab zone | Enlarges pointer reach while remaining visually transparent. | Current source and tests | Supporting | FR1, FR2 |
128
+ | Direction state | Selects horizontal or vertical resize presentation. | Current public metadata | Supporting | FR3, FR4 |
129
+
130
+ Grab zone is interaction structure rather than a painted public theming seam. Its
131
+ `none` disposition records factual reachability. The missing Handle direction
132
+ reflection is a separate current audit gap: the target exists, but runtime does
133
+ not emit the documented target state.
134
+
135
+ ### Theming anatomy
136
+
137
+ <!-- anatomy-theming:v1 -->
138
+
139
+ ```json
140
+ {
141
+ "Handle": {"target": "resize-handle"},
142
+ "Grip pill": {"target": "resize-handle-pill"},
143
+ "Grab zone": {
144
+ "none": {
145
+ "reason": "intentional: The invisible pointer hit area is nonvisual interaction structure and has no public target"
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ ## Family and system relationships
152
+
153
+ - `architecture:component-theming-surface` owns anatomy qualification, target
154
+ mapping, and target-state reflection requirements.
155
+ - `architecture:interaction-modality` and `architecture:public-component-api`
156
+ own shared modality and API boundaries; this draft changes neither.
157
+ - `family:layout-regions` lists useResizable and ResizeHandle as collaborators
158
+ that may drive a LayoutPanel's size. Resizable is not a layout-regions member,
159
+ and that family does not own or redefine resize state, snapping, persistence,
160
+ collapse, pointer, or keyboard semantics.
161
+
162
+ ## Verification map
163
+
164
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
165
+ | ------------------- | -------------------------------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------------- |
166
+ | FR1 | `ResizeHandle.test.tsx` plus source inspection | Default, custom, collapsed, disabled, both axes | Handle and Grab zone regressions fail focused tests; custom Grip replacement currently relies on source review. | `audit:Resizable/anatomy` |
167
+ | FR2 | Source inspection and `themingTargets.test.ts` | Handle, Grip pill, and Grab zone | Removing a target or documenting an unshipped Grab zone target fails evidence or inventory. | `audit:Resizable/theming` |
168
+ | FR3 | `ResizeHandle.test.tsx` and `useResizable.test.ts` | Pointer, keyboard, snap, collapse, persistence | Moving resize ownership or changing current transformations fails focused behavior coverage. | `audit:Resizable/behavior` |
169
+ | FR4 | Source and public metadata comparison | Horizontal and vertical Handle | No current test detects that documented `direction` is absent from runtime target-state reflection. | `audit:Resizable/theming` |
170
+ | Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical anatomy and two current targets | Missing, extra, prefixed, stale, or multiply assigned mappings fail repository validation. | `audit:Resizable/theming` |
171
+
172
+ Current tests exercise Handle and Grab zone structure and behavior but do not
173
+ render `children` to prove that custom content replaces Grip pill. That branch is
174
+ source-inspected and lacks focused regression evidence. The documented
175
+ `direction` visual axis is a closed union, so `extensibleAxes.test.ts` does not
176
+ cover its missing runtime reflection; that mismatch is currently unguarded.
177
+
178
+ ## Decision log
179
+
180
+ None. This draft records current facts and introduces no component-local design,
181
+ API, resize, layout-family, or theming decision.
182
+
183
+ ## Open questions
184
+
185
+ - **OQ1 — Which follow-up should add and verify the missing Handle `direction`
186
+ target-state reflection?** (`checkable`)
187
+ - **OQ2 — Which focused test should pin custom content replacing Grip pill?**
188
+ (`checkable`)
189
+
190
+ ## Content boundary
191
+
192
+ This file does not duplicate consumer prop tables/examples, resize algorithms,
193
+ layout-region rules, current audit results, or implementation steps. It links to
194
+ their owners.
@@ -1,5 +1,19 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Section container',
7
+ required: true,
8
+ description: 'Painted container that groups a page region.',
9
+ },
10
+ {
11
+ name: 'Consumer content',
12
+ required: false,
13
+ description: 'Caller-provided content rendered inside the section container.',
14
+ },
15
+ ];
16
+
3
17
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
18
 
5
19
  export const docs = {
@@ -99,6 +113,7 @@ export const docs = {
99
113
  ],
100
114
  },
101
115
  usage: {
116
+ anatomy,
102
117
  description:
103
118
  'Section is the correct way to create page regions and group related content on a page. Use it for settings groups, form sections, sidebar areas, or any time you need visual separation between parts of a page. If you are tempted to use a Card for a page section, use Section instead.',
104
119
  bestPractices: [
@@ -206,6 +221,7 @@ export const docsZh = {
206
221
  ],
207
222
  },
208
223
  usage: {
224
+ anatomy,
209
225
  description:
210
226
  'Section is the correct way to create page regions and group related content on a page. Use it for settings groups, form sections, sidebar areas, or any time you need visual separation between parts of a page. If you are tempted to use a Card for a page section, use Section instead.',
211
227
  bestPractices: [
@@ -223,6 +239,7 @@ export const docsDense = {
223
239
  description:
224
240
  'Page-level container for grouping content into regions. Use INSTEAD of Card for settings panels, form groups, and page sections.',
225
241
  usage: {
242
+ anatomy,
226
243
  description:
227
244
  'Section creates page regions. Use for settings groups, form sections, sidebar areas. If you want to visually separate a part of a page, use Section, not Card. Cards are for discrete items (one profile, one notification).',
228
245
  bestPractices: [
@@ -0,0 +1,138 @@
1
+ ---
2
+ schema_version: 1
3
+ template_version: 3
4
+ kind: component
5
+ id: component:Section
6
+ authority: draft
7
+ archive_reason: null
8
+ superseded_by: null
9
+ approved_by: null
10
+ approved_at: null
11
+ owners: [cixzhang]
12
+ review_triggers: [theming]
13
+ verified_by:
14
+ [packages/core/src/Section/Section.test.tsx, scripts/check-knowledge.mjs]
15
+ families: [family:layout-regions]
16
+ design_specs: []
17
+ architecture:
18
+ [
19
+ architecture:component-theming-surface,
20
+ architecture:container-padding,
21
+ architecture:public-component-api,
22
+ ]
23
+ contributing: []
24
+ system_specs: []
25
+ ---
26
+
27
+ # Section component contract
28
+
29
+ ## Intent
30
+
31
+ Section renders a painted container for a page region and places caller-provided
32
+ content inside it. This draft records current consumer anatomy and theming
33
+ ownership without changing layout, styling, targets, or public API.
34
+
35
+ ## Compatibility and migration
36
+
37
+ - Released default preserved: `yes`
38
+ - Compatibility class: additive documentation only; runtime, DOM, styling,
39
+ targets, and public API remain unchanged
40
+ - Controlled/uncontrolled behavior: not applicable
41
+ - Migration decision: none
42
+
43
+ Consumer migration instructions belong in consumer docs and release notes.
44
+
45
+ ## Ownership boundary
46
+
47
+ **Owns**
48
+
49
+ - The painted section container and its existing `section` theming target.
50
+
51
+ **Does not own / non-goals**
52
+
53
+ - The caller-provided content rendered inside the section.
54
+ - The outer layout wrapper as a consumer-facing anatomy part or theming target.
55
+
56
+ ## Public concepts
57
+
58
+ No new public concept is introduced. Consumer props and usage remain documented
59
+ in `Section.doc.mjs`.
60
+
61
+ ## Behavioral and layout contract
62
+
63
+ | ID | Candidate invariant | Basis | Draft review state |
64
+ | --- | ----------------------------------------------------------------------------------------------------------- | ------------------------------- | -------------------------------------------------- |
65
+ | FR1 | The current render places caller-provided content inside the inner container carrying the `section` target. | Current source, docs, and tests | Verified current behavior; no new behavior decided |
66
+
67
+ ### Allowed variation
68
+
69
+ - Caller-provided content may vary without becoming Section-owned anatomy.
70
+
71
+ ### Representative states
72
+
73
+ - The anatomy and target ownership are unchanged across the documented section
74
+ variants, sizes, dividers, and padding inputs.
75
+
76
+ ### Transformation and precedence order
77
+
78
+ - No new layout or style precedence rule is introduced.
79
+
80
+ ### Performance and resources
81
+
82
+ - No new performance or resource rule is introduced.
83
+
84
+ ## Accessibility contract
85
+
86
+ This draft does not change or extend Section's existing accessibility behavior.
87
+
88
+ ## Design relationships
89
+
90
+ | Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
91
+ | ----------------- | ----------------------------------------------------------- | ------------------------------ | ----------------- | ------------------ |
92
+ | Section container | Presents the current painted page-region container. | Current source and public docs | Supporting | FR1 |
93
+ | Consumer content | Presents content supplied by the caller inside the section. | Caller-supplied content | Context-dependent | FR1 |
94
+
95
+ The outer layout wrapper remains implementation structure and is not listed as
96
+ consumer anatomy.
97
+
98
+ ### Theming anatomy
99
+
100
+ <!-- anatomy-theming:v1 -->
101
+
102
+ ```json
103
+ {
104
+ "Section container": {"target": "section"},
105
+ "Consumer content": {
106
+ "none": {
107
+ "reason": "unsettled: No Section theming target reaches caller-provided content."
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ ## Family and system relationships
114
+
115
+ This draft references the current shared owners without restating their rules:
116
+ `family:layout-regions`, `architecture:component-theming-surface`,
117
+ `architecture:container-padding`, and `architecture:public-component-api`.
118
+
119
+ ## Verification map
120
+
121
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
122
+ | ------------------- | ------------------------------------------ | ------------------------------------ | --------------------------------------------------------------------------------------- | ----------------------- |
123
+ | FR1 | `Section.test.tsx` structure/target suites | Inner container and consumer content | Moving or removing the target or content fails existing structure and class assertions. | `audit:Section/anatomy` |
124
+ | Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical anatomy and current target | Missing, extra, prefixed, or stale mappings fail repository validation. | `audit:Section/theming` |
125
+
126
+ ## Decision log
127
+
128
+ None. This draft records current facts and introduces no component-local design
129
+ decision.
130
+
131
+ ## Open questions
132
+
133
+ None.
134
+
135
+ ## Content boundary
136
+
137
+ This file does not duplicate consumer prop tables, examples, implementation
138
+ steps, or system rules. It links to their owners.
@@ -1,5 +1,29 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Control',
7
+ required: true,
8
+ description: 'Container for the mutually exclusive segment choices.',
9
+ },
10
+ {
11
+ name: 'Segment',
12
+ required: true,
13
+ description: 'Individual choice within the control.',
14
+ },
15
+ {
16
+ name: 'Label',
17
+ required: false,
18
+ description: 'Visible text identifying a segment when its label is not hidden.',
19
+ },
20
+ {
21
+ name: 'Icon',
22
+ required: false,
23
+ description: 'Optional caller-supplied icon shown inside a segment.',
24
+ },
25
+ ];
26
+
3
27
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
28
 
5
29
  export const docs = {
@@ -96,8 +120,65 @@ export const docs = {
96
120
  {name: 'SegmentedControlItem'},
97
121
  ],
98
122
  usage: {
123
+ anatomy,
99
124
  description:
100
125
  'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation.',
126
+ accessibility: [
127
+ {
128
+ name: 'Text label',
129
+ category: 'Color contrast',
130
+ criterion: '1.4.3 Contrast (Minimum)',
131
+ requirement: '4.5:1',
132
+ states: ['Rest', 'Hover', 'Selected'],
133
+ description:
134
+ 'Each label must have at least 4.5:1 contrast with its segment background. Check unselected, Hover, and selected colors as they appear on screen.',
135
+ },
136
+ {
137
+ name: 'Essential icon',
138
+ category: 'Color contrast',
139
+ criterion: '1.4.11 Non-text Contrast',
140
+ requirement: '3:1',
141
+ states: ['Icon only'],
142
+ description:
143
+ 'When a segment has no visible label, its icon must have at least 3:1 contrast with the segment background. An icon beside a visible label does not need its own check.',
144
+ },
145
+ {
146
+ name: 'Selected state indicator',
147
+ category: 'Color contrast',
148
+ criterion: '1.4.11 Non-text Contrast',
149
+ requirement: '3:1 if relied upon',
150
+ states: ['Selected'],
151
+ description:
152
+ 'The selected background must reach 3:1 only when users need it to tell selected from unselected. Label color and weight also show selection.',
153
+ },
154
+ {
155
+ name: 'Visible control boundary',
156
+ category: 'Color contrast',
157
+ criterion: '1.4.11 Non-text Contrast',
158
+ requirement: '3:1 if needed',
159
+ states: ['Rest'],
160
+ description:
161
+ 'The control edge or segment borders need at least 3:1 contrast when users need them to see the choices.',
162
+ },
163
+ {
164
+ name: 'Keyboard focus indicator',
165
+ category: 'Color contrast',
166
+ criterion: '1.4.11 Non-text Contrast',
167
+ requirement: '3:1',
168
+ states: ['Focus visible'],
169
+ description:
170
+ 'The focus outline must have at least 3:1 contrast with the area around the segment. Check it on the track and selected background.',
171
+ },
172
+ {
173
+ name: 'Disabled appearance',
174
+ category: 'Color contrast',
175
+ criterion: '1.4.3 and 1.4.11 exceptions',
176
+ requirement: 'Not required',
177
+ states: ['Disabled'],
178
+ description:
179
+ 'Disabled controls do not need to meet these contrast ratios.',
180
+ },
181
+ ],
101
182
  bestPractices: [
102
183
  {guidance: true, description: 'Use for switching between 2–5 mutually exclusive views or modes where all options should be visible.'},
103
184
  {guidance: true, description: 'Provide a descriptive label for the control to ensure the group is accessible to screen readers.'},
@@ -111,6 +192,7 @@ export const docs = {
111
192
  /** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
112
193
  export const docsZh = {
113
194
  usage: {
195
+ anatomy,
114
196
  description:
115
197
  'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation.',
116
198
  bestPractices: [
@@ -126,6 +208,7 @@ export const docsZh = {
126
208
  /** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
127
209
  export const docsDense = {
128
210
  usage: {
211
+ anatomy,
129
212
  description:
130
213
  'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation.',
131
214
  bestPractices: [