@astryxdesign/core 0.5.2-canary.c9c8564 → 0.5.2-canary.e03511b

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 (216) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +3 -1
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +4 -3
  4. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +2 -2
  5. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetEdgeTint.js +7 -10
  7. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  8. package/dist/BottomSheet/BottomSheetSwitcher.js +1 -1
  9. package/dist/Button/Button.d.ts +2 -1
  10. package/dist/Button/Button.d.ts.map +1 -1
  11. package/dist/Button/Button.js +11 -4
  12. package/dist/Carousel/Carousel.d.ts.map +1 -1
  13. package/dist/Carousel/Carousel.js +2 -2
  14. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  15. package/dist/Chat/ChatToolCalls.js +34 -17
  16. package/dist/ContextMenu/ContextMenu.d.ts +14 -3
  17. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  18. package/dist/ContextMenu/ContextMenu.js +149 -26
  19. package/dist/ContextMenu/index.d.ts +1 -0
  20. package/dist/ContextMenu/index.d.ts.map +1 -1
  21. package/dist/DropdownMenu/DropdownMenu.d.ts +24 -5
  22. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  23. package/dist/DropdownMenu/DropdownMenu.js +340 -26
  24. package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -1
  25. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  26. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  27. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  28. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -2
  29. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  30. package/dist/DropdownMenu/DropdownMenuSubMenu.js +43 -14
  31. package/dist/DropdownMenu/MenuBottomSheet.d.ts +20 -0
  32. package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -0
  33. package/dist/DropdownMenu/MenuBottomSheet.js +36 -0
  34. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts +10 -0
  35. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -0
  36. package/dist/DropdownMenu/MenuBottomSheetActionList.js +111 -0
  37. package/dist/DropdownMenu/index.d.ts +2 -1
  38. package/dist/DropdownMenu/index.d.ts.map +1 -1
  39. package/dist/DropdownMenu/menuWidth.d.ts +14 -0
  40. package/dist/DropdownMenu/menuWidth.d.ts.map +1 -0
  41. package/dist/DropdownMenu/menuWidth.js +35 -0
  42. package/dist/DropdownMenu/useMenuOverflow.d.ts +10 -0
  43. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -0
  44. package/dist/DropdownMenu/useMenuOverflow.js +60 -0
  45. package/dist/MoreMenu/MoreMenu.d.ts +8 -2
  46. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  47. package/dist/MoreMenu/MoreMenu.js +2 -0
  48. package/dist/MultiSelector/MultiSelector.d.ts +11 -1
  49. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  50. package/dist/MultiSelector/MultiSelector.js +97 -68
  51. package/dist/MultiSelector/index.d.ts +1 -1
  52. package/dist/MultiSelector/index.d.ts.map +1 -1
  53. package/dist/Popover/Popover.d.ts +10 -6
  54. package/dist/Popover/Popover.d.ts.map +1 -1
  55. package/dist/Popover/Popover.js +141 -16
  56. package/dist/Popover/usePopover.d.ts +4 -0
  57. package/dist/Popover/usePopover.d.ts.map +1 -1
  58. package/dist/Popover/usePopover.js +52 -5
  59. package/dist/Selector/Selector.d.ts +10 -0
  60. package/dist/Selector/Selector.d.ts.map +1 -1
  61. package/dist/Selector/Selector.js +106 -80
  62. package/dist/Selector/SelectorBottomSheet.d.ts +21 -0
  63. package/dist/Selector/SelectorBottomSheet.d.ts.map +1 -0
  64. package/dist/Selector/SelectorBottomSheet.js +83 -0
  65. package/dist/Selector/index.d.ts +1 -1
  66. package/dist/Selector/index.d.ts.map +1 -1
  67. package/dist/Selector/selectorPresentation.stylex.d.ts +16 -0
  68. package/dist/Selector/selectorPresentation.stylex.d.ts.map +1 -0
  69. package/dist/Selector/selectorPresentation.stylex.js +21 -0
  70. package/dist/Selector/useSelectorPresentation.d.ts +32 -0
  71. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -0
  72. package/dist/Selector/useSelectorPresentation.js +90 -0
  73. package/dist/Toast/useToastGesture.d.ts.map +1 -1
  74. package/dist/Toast/useToastGesture.js +46 -9
  75. package/dist/astryx.css +19 -1
  76. package/dist/hooks/useAdaptivePresentation.d.ts +5 -0
  77. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -0
  78. package/dist/hooks/useAdaptivePresentation.js +19 -0
  79. package/dist/hooks/useFocusReturnVisibility.d.ts +7 -0
  80. package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -0
  81. package/dist/hooks/useFocusReturnVisibility.js +35 -0
  82. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  83. package/dist/hooks/useFocusTrap.js +12 -0
  84. package/locales/en.json +20 -0
  85. package/locales/pseudo.json +15 -0
  86. package/package.json +2 -2
  87. package/src/BottomSheet/BottomSheet.doc.mjs +37 -0
  88. package/src/BottomSheet/BottomSheet.spec.md +177 -0
  89. package/src/BottomSheet/BottomSheet.test.tsx +29 -0
  90. package/src/BottomSheet/BottomSheet.tsx +7 -4
  91. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -6
  92. package/src/BottomSheet/BottomSheetEdgeTint.tsx +7 -10
  93. package/src/BottomSheet/BottomSheetSwitcher.tsx +1 -2
  94. package/src/Button/Button.doc.mjs +56 -0
  95. package/src/Button/Button.test.tsx +10 -0
  96. package/src/Button/Button.tsx +13 -5
  97. package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
  98. package/src/Carousel/Carousel.test.tsx +83 -0
  99. package/src/Carousel/Carousel.tsx +8 -2
  100. package/src/Chat/ChatToolCalls.test.tsx +44 -0
  101. package/src/Chat/ChatToolCalls.tsx +36 -15
  102. package/src/CheckboxList/CheckboxList.doc.mjs +172 -31
  103. package/src/CheckboxList/CheckboxList.spec.md +214 -0
  104. package/src/CommandPalette/CommandPalette.doc.mjs +72 -0
  105. package/src/CommandPalette/CommandPalette.spec.md +223 -0
  106. package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
  107. package/src/ComplexSelector/ComplexSelector.spec.md +189 -0
  108. package/src/ContextMenu/ContextMenu.doc.mjs +61 -1
  109. package/src/ContextMenu/ContextMenu.spec.md +206 -0
  110. package/src/ContextMenu/ContextMenu.test.tsx +131 -1
  111. package/src/ContextMenu/ContextMenu.tsx +199 -32
  112. package/src/ContextMenu/index.ts +1 -0
  113. package/src/Divider/Divider.doc.mjs +24 -0
  114. package/src/Divider/Divider.spec.md +150 -0
  115. package/src/DropdownMenu/DropdownMenu.doc.mjs +305 -40
  116. package/src/DropdownMenu/DropdownMenu.spec.md +245 -0
  117. package/src/DropdownMenu/DropdownMenu.test.tsx +518 -7
  118. package/src/DropdownMenu/DropdownMenu.tsx +459 -28
  119. package/src/DropdownMenu/DropdownMenuContext.tsx +1 -1
  120. package/src/DropdownMenu/DropdownMenuItem.tsx +2 -0
  121. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +4 -2
  122. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +124 -0
  123. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +72 -17
  124. package/src/DropdownMenu/MenuBottomSheet.tsx +46 -0
  125. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +141 -0
  126. package/src/DropdownMenu/index.ts +2 -0
  127. package/src/DropdownMenu/menuWidth.ts +51 -0
  128. package/src/DropdownMenu/useMenuOverflow.ts +77 -0
  129. package/src/FieldStatus/FieldStatus.doc.mjs +21 -0
  130. package/src/FieldStatus/FieldStatus.spec.md +212 -0
  131. package/src/Grid/Grid.doc.mjs +19 -0
  132. package/src/Grid/Grid.spec.md +161 -0
  133. package/src/Icon/Icon.doc.mjs +196 -48
  134. package/src/Icon/Icon.spec.md +191 -0
  135. package/src/IconButton/IconButton.doc.mjs +38 -0
  136. package/src/Kbd/Kbd.doc.mjs +18 -0
  137. package/src/Kbd/Kbd.spec.md +141 -0
  138. package/src/Layout/Layout.doc.mjs +32 -0
  139. package/src/Layout/Layout.spec.md +199 -0
  140. package/src/Lightbox/Lightbox.doc.mjs +149 -33
  141. package/src/Lightbox/Lightbox.spec.md +197 -0
  142. package/src/Markdown/Markdown.doc.mjs +60 -0
  143. package/src/Markdown/Markdown.spec.md +200 -0
  144. package/src/MobileNav/MobileNav.doc.mjs +140 -32
  145. package/src/MobileNav/MobileNav.spec.md +208 -0
  146. package/src/MoreMenu/MoreMenu.doc.mjs +59 -0
  147. package/src/MoreMenu/MoreMenu.spec.md +221 -0
  148. package/src/MoreMenu/MoreMenu.test.tsx +47 -0
  149. package/src/MoreMenu/MoreMenu.tsx +13 -1
  150. package/src/MultiSelector/MultiSelector.doc.mjs +128 -0
  151. package/src/MultiSelector/MultiSelector.spec.md +266 -0
  152. package/src/MultiSelector/MultiSelector.test.tsx +127 -0
  153. package/src/MultiSelector/MultiSelector.tsx +121 -73
  154. package/src/MultiSelector/index.ts +1 -0
  155. package/src/NavIcon/NavIcon.doc.mjs +17 -0
  156. package/src/NavIcon/NavIcon.spec.md +133 -0
  157. package/src/NavMenu/NavHeadingMenu.spec.md +205 -0
  158. package/src/NavMenu/NavMenu.doc.mjs +37 -0
  159. package/src/Outline/Outline.doc.mjs +35 -0
  160. package/src/Outline/Outline.spec.md +161 -0
  161. package/src/OverflowList/OverflowList.doc.mjs +24 -0
  162. package/src/OverflowList/OverflowList.spec.md +156 -0
  163. package/src/Pagination/Pagination.doc.mjs +74 -0
  164. package/src/Pagination/Pagination.spec.md +225 -0
  165. package/src/Popover/Popover.doc.mjs +11 -11
  166. package/src/Popover/Popover.test.tsx +397 -2
  167. package/src/Popover/Popover.tsx +228 -21
  168. package/src/Popover/usePopover.tsx +92 -15
  169. package/src/ProgressBar/ProgressBar.doc.mjs +198 -38
  170. package/src/ProgressBar/ProgressBar.spec.md +260 -0
  171. package/src/Resizable/Resizable.doc.mjs +59 -16
  172. package/src/Resizable/Resizable.spec.md +194 -0
  173. package/src/Section/Section.doc.mjs +17 -0
  174. package/src/Section/Section.spec.md +138 -0
  175. package/src/SegmentedControl/SegmentedControl.doc.mjs +83 -0
  176. package/src/SegmentedControl/SegmentedControl.spec.md +151 -0
  177. package/src/Selector/Selector.doc.mjs +12 -0
  178. package/src/Selector/Selector.spec.md +202 -0
  179. package/src/Selector/Selector.test.tsx +135 -0
  180. package/src/Selector/Selector.tsx +141 -82
  181. package/src/Selector/SelectorBottomSheet.tsx +97 -0
  182. package/src/Selector/index.ts +1 -0
  183. package/src/Selector/selectorPresentation.stylex.ts +20 -0
  184. package/src/Selector/useSelectorPresentation.ts +147 -0
  185. package/src/Skeleton/Skeleton.doc.mjs +12 -0
  186. package/src/Skeleton/Skeleton.spec.md +126 -0
  187. package/src/Slider/Slider.doc.mjs +184 -30
  188. package/src/Slider/Slider.spec.md +223 -0
  189. package/src/Stack/Stack.doc.mjs +22 -0
  190. package/src/Stack/Stack.spec.md +154 -0
  191. package/src/StatusDot/StatusDot.doc.mjs +17 -0
  192. package/src/StatusDot/StatusDot.spec.md +137 -0
  193. package/src/Switch/Switch.doc.mjs +40 -0
  194. package/src/Switch/Switch.spec.md +174 -0
  195. package/src/Table/Table.doc.mjs +102 -24
  196. package/src/Table/Table.spec.md +283 -0
  197. package/src/Text/Text.doc.mjs +190 -43
  198. package/src/Text/Text.spec.md +205 -0
  199. package/src/TextArea/TextArea.doc.mjs +255 -45
  200. package/src/TextArea/TextArea.spec.md +204 -0
  201. package/src/Toast/ToastViewport.test.tsx +118 -4
  202. package/src/Toast/useToastGesture.ts +61 -8
  203. package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
  204. package/src/Toolbar/Toolbar.doc.mjs +19 -0
  205. package/src/Toolbar/Toolbar.spec.md +173 -0
  206. package/src/Tooltip/Tooltip.doc.mjs +17 -0
  207. package/src/Tooltip/Tooltip.spec.md +141 -0
  208. package/src/TreeList/TreeList.doc.mjs +58 -0
  209. package/src/TreeList/TreeList.spec.md +220 -0
  210. package/src/Typeahead/Typeahead.doc.mjs +83 -1
  211. package/src/Typeahead/Typeahead.spec.md +250 -0
  212. package/src/hooks/useAdaptivePresentation.ts +35 -0
  213. package/src/hooks/useFocusReturnVisibility.ts +45 -0
  214. package/src/hooks/useFocusTrap.test.tsx +40 -0
  215. package/src/hooks/useFocusTrap.ts +13 -0
  216. package/src/theme/themingTargets.test.ts +91 -25
@@ -1,5 +1,43 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Navigation overlay',
7
+ required: true,
8
+ description:
9
+ 'Full-viewport dialog overlay that hosts the mobile navigation drawer.',
10
+ },
11
+ {
12
+ name: 'Drawer',
13
+ required: true,
14
+ description:
15
+ 'Painted panel that slides in from the resolved viewport edge.',
16
+ },
17
+ {
18
+ name: 'Header',
19
+ required: true,
20
+ description:
21
+ 'Fixed row containing optional header content and the close button.',
22
+ },
23
+ {
24
+ name: 'Content',
25
+ required: true,
26
+ description: 'Scrollable region containing the navigation content.',
27
+ },
28
+ {
29
+ name: 'Close button',
30
+ required: true,
31
+ description: 'Button that closes the navigation drawer.',
32
+ },
33
+ {
34
+ name: 'Toggle button',
35
+ required: false,
36
+ description:
37
+ 'AppShell-aware Button that opens or closes the drawer on mobile viewports.',
38
+ },
39
+ ];
40
+
3
41
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
42
 
5
43
  export const docs = {
@@ -8,12 +46,24 @@ export const docs = {
8
46
  group: 'Navigation',
9
47
  category: 'Navigation',
10
48
  isHiddenFromOverview: true,
11
- keywords: ["mobilenav","drawer","sidebar","navigation","hamburger","menu","offcanvas","slideout","navdrawer","toggle"],
49
+ keywords: [
50
+ 'mobilenav',
51
+ 'drawer',
52
+ 'sidebar',
53
+ 'navigation',
54
+ 'hamburger',
55
+ 'menu',
56
+ 'offcanvas',
57
+ 'slideout',
58
+ 'navdrawer',
59
+ 'toggle',
60
+ ],
12
61
  components: [
13
62
  {
14
63
  name: 'MobileNav',
15
64
  displayName: 'Mobile Nav',
16
- description: 'A slide-out drawer for mobile navigation. Accepts SideNav children.',
65
+ description:
66
+ 'A slide-out drawer for mobile navigation. Accepts SideNav children.',
17
67
  // The drawer opens via showModal() and renders nothing while closed —
18
68
  // overlay mode gives the Properties preview an open trigger instead of
19
69
  // an empty stage (#2706). Declared on this entry (not the directory
@@ -27,7 +77,10 @@ export const docs = {
27
77
  __element: 'SideNavSection',
28
78
  props: {title: 'Main'},
29
79
  children: [
30
- {__element: 'SideNavItem', props: {label: 'Dashboard', isSelected: true}},
80
+ {
81
+ __element: 'SideNavItem',
82
+ props: {label: 'Dashboard', isSelected: true},
83
+ },
31
84
  {__element: 'SideNavItem', props: {label: 'Projects'}},
32
85
  {__element: 'SideNavItem', props: {label: 'Settings'}},
33
86
  ],
@@ -38,7 +91,8 @@ export const docs = {
38
91
  {
39
92
  name: 'isOpen',
40
93
  type: 'boolean',
41
- description: 'Whether the drawer is open. Inside AppShell, this is managed automatically via context. Outside AppShell, provide this prop to control the drawer yourself.',
94
+ description:
95
+ 'Whether the drawer is open. Inside AppShell, this is managed automatically via context. Outside AppShell, provide this prop to control the drawer yourself.',
42
96
  },
43
97
  {
44
98
  name: 'onOpenChange',
@@ -56,7 +110,8 @@ export const docs = {
56
110
  {
57
111
  name: 'header',
58
112
  type: 'ReactNode',
59
- description: 'Header content for the drawer. Rendered next to the close button. Pass a string for a simple text heading, or a ReactNode for custom content (logo, search bar, etc.).',
113
+ description:
114
+ 'Header content for the drawer. Rendered next to the close button. Pass a string for a simple text heading, or a ReactNode for custom content (logo, search bar, etc.).',
60
115
  },
61
116
  {
62
117
  name: 'width',
@@ -77,7 +132,8 @@ export const docs = {
77
132
  {
78
133
  name: 'MobileNavToggle',
79
134
  displayName: 'Mobile Nav Toggle',
80
- description: 'Hamburger button that opens/closes the mobile nav drawer. Reads open state from AppShell context automatically: does NOT accept isOpen or onOpenChange props. Renders nothing above the mobile breakpoint.',
135
+ description:
136
+ 'Hamburger button that opens/closes the mobile nav drawer. Reads open state from AppShell context automatically: does NOT accept isOpen or onOpenChange props. Renders nothing above the mobile breakpoint.',
81
137
  // The toggle renders null unless AppShell mobile context reports an
82
138
  // enabled mobile viewport — the default context outside AppShell never
83
139
  // does, so the Properties preview was an empty stage. appShellMobile
@@ -89,7 +145,8 @@ export const docs = {
89
145
  {
90
146
  name: 'children',
91
147
  type: 'ReactNode',
92
- description: 'Custom content to render instead of the default hamburger icon.',
148
+ description:
149
+ 'Custom content to render instead of the default hamburger icon.',
93
150
  },
94
151
  {
95
152
  name: 'label',
@@ -101,18 +158,33 @@ export const docs = {
101
158
  },
102
159
  ],
103
160
  theming: {
104
- targets: [
105
- {className: 'astryx-mobile-nav', visualProps: ['side']},
106
- ],
161
+ targets: [{className: 'astryx-mobile-nav', visualProps: ['side']}],
107
162
  },
108
163
  usage: {
164
+ anatomy,
109
165
  description:
110
166
  'A slide-out drawer for mobile navigation. MobileNav is the mobile counterpart to SideNav and accepts the same children. Use it on narrow viewports where a persistent sidebar is not practical. Inside AppShell, use MobileNavToggle as the trigger; it reads state from context automatically.',
111
167
  bestPractices: [
112
- { guidance: true, description: 'Share the same nav items between MobileNav and SideNav by extracting them into a variable.' },
113
- { guidance: true, description: 'Provide a header when the drawer\'s purpose is not obvious from its content.' },
114
- { guidance: true, description: 'Inside AppShell, use MobileNavToggle to open the drawer; it reads state from context. Do not pass isOpen/onOpenChange to the toggle.' },
115
- { guidance: false, description: 'Use MobileNav on desktop: use a persistent SideNav instead.' },
168
+ {
169
+ guidance: true,
170
+ description:
171
+ 'Share the same nav items between MobileNav and SideNav by extracting them into a variable.',
172
+ },
173
+ {
174
+ guidance: true,
175
+ description:
176
+ "Provide a header when the drawer's purpose is not obvious from its content.",
177
+ },
178
+ {
179
+ guidance: true,
180
+ description:
181
+ 'Inside AppShell, use MobileNavToggle to open the drawer; it reads state from context. Do not pass isOpen/onOpenChange to the toggle.',
182
+ },
183
+ {
184
+ guidance: false,
185
+ description:
186
+ 'Use MobileNav on desktop: use a persistent SideNav instead.',
187
+ },
116
188
  ],
117
189
  },
118
190
  };
@@ -144,13 +216,13 @@ export const docsZh = {
144
216
  {
145
217
  name: 'header',
146
218
  type: 'ReactNode',
147
- description: '抽屉的头部内容。渲染在关闭按钮旁边。传入字符串作为简单文本标题,或传入 ReactNode 作为自定义内容。',
219
+ description:
220
+ '抽屉的头部内容。渲染在关闭按钮旁边。传入字符串作为简单文本标题,或传入 ReactNode 作为自定义内容。',
148
221
  },
149
222
  {
150
223
  name: 'width',
151
224
  type: 'number',
152
- description:
153
- '抽屉宽度(像素)。上限为 85vw 以防止在小屏幕上溢出。',
225
+ description: '抽屉宽度(像素)。上限为 85vw 以防止在小屏幕上溢出。',
154
226
  default: '320',
155
227
  },
156
228
  {
@@ -162,18 +234,33 @@ export const docsZh = {
162
234
  },
163
235
  ],
164
236
  theming: {
165
- targets: [
166
- {className: 'astryx-mobile-nav', visualProps: ['side']},
167
- ],
237
+ targets: [{className: 'astryx-mobile-nav', visualProps: ['side']}],
168
238
  },
169
239
  usage: {
240
+ anatomy,
170
241
  description:
171
242
  'A slide-out drawer for mobile navigation. MobileNav is the mobile counterpart to SideNav and accepts the same children. Use it on narrow viewports where a persistent sidebar is not practical.',
172
243
  bestPractices: [
173
- { guidance: true, description: 'Share the same nav items between MobileNav and SideNav by extracting them into a variable.' },
174
- { guidance: true, description: 'Provide a header when the drawer\'s purpose is not obvious from its content.' },
175
- { guidance: true, description: 'Inside AppShell, use MobileNavToggle to open the drawer; it reads state from context. Do not pass isOpen/onOpenChange to the toggle.' },
176
- { guidance: false, description: 'Use MobileNav on desktop: use a persistent SideNav instead.' },
244
+ {
245
+ guidance: true,
246
+ description:
247
+ 'Share the same nav items between MobileNav and SideNav by extracting them into a variable.',
248
+ },
249
+ {
250
+ guidance: true,
251
+ description:
252
+ "Provide a header when the drawer's purpose is not obvious from its content.",
253
+ },
254
+ {
255
+ guidance: true,
256
+ description:
257
+ 'Inside AppShell, use MobileNavToggle to open the drawer; it reads state from context. Do not pass isOpen/onOpenChange to the toggle.',
258
+ },
259
+ {
260
+ guidance: false,
261
+ description:
262
+ 'Use MobileNav on desktop: use a persistent SideNav instead.',
263
+ },
177
264
  ],
178
265
  },
179
266
  };
@@ -183,23 +270,42 @@ export const docsDense = {
183
270
  description:
184
271
  'Slide-out drawer overlay for mobile navigation. Mobile counterpart to SideNav; accepts same children (SideNavSection, SideNavItem, or any ReactNode).',
185
272
  usage: {
273
+ anatomy,
186
274
  description:
187
275
  'A slide-out drawer for mobile navigation. MobileNav is the mobile counterpart to SideNav and accepts the same children. Use it on narrow viewports where a persistent sidebar is not practical.',
188
276
  bestPractices: [
189
- { guidance: true, description: 'Share nav items between MobileNav and SideNav by extracting into a variable.' },
190
- { guidance: true, description: 'Provide a header when the drawer purpose is not obvious from content.' },
191
- { guidance: true, description: 'Inside AppShell, use MobileNavToggle to open the drawer; it reads state from context. Do not pass isOpen/onOpenChange to the toggle.' },
192
- { guidance: false, description: 'Use MobileNav on desktop; use a persistent SideNav instead.' },
277
+ {
278
+ guidance: true,
279
+ description:
280
+ 'Share nav items between MobileNav and SideNav by extracting into a variable.',
281
+ },
282
+ {
283
+ guidance: true,
284
+ description:
285
+ 'Provide a header when the drawer purpose is not obvious from content.',
286
+ },
287
+ {
288
+ guidance: true,
289
+ description:
290
+ 'Inside AppShell, use MobileNavToggle to open the drawer; it reads state from context. Do not pass isOpen/onOpenChange to the toggle.',
291
+ },
292
+ {
293
+ guidance: false,
294
+ description:
295
+ 'Use MobileNav on desktop; use a persistent SideNav instead.',
296
+ },
193
297
  ],
194
298
  },
195
299
  components: [
196
300
  {
197
301
  name: 'MobileNav',
198
- description: 'Slide-out drawer for mobile navigation. Accepts SideNav children.',
302
+ description:
303
+ 'Slide-out drawer for mobile navigation. Accepts SideNav children.',
199
304
  },
200
305
  {
201
306
  name: 'MobileNavToggle',
202
- description: 'Hamburger button that opens/closes mobile nav drawer. Reads open state from AppShell context automatically. Renders nothing above mobile breakpoint.',
307
+ description:
308
+ 'Hamburger button that opens/closes mobile nav drawer. Reads open state from AppShell context automatically. Renders nothing above mobile breakpoint.',
203
309
  },
204
310
  ],
205
311
  propDescriptions: {
@@ -208,8 +314,10 @@ export const docsDense = {
208
314
  'called when drawer visibility changes (backdrop click, Escape, close button)',
209
315
  children:
210
316
  'drawer content; typically SideNavSection/SideNavItem or any ReactNode',
211
- header: 'header content (string or ReactNode), rendered next to close button',
212
- width: 'drawer width px; capped at 85vw to prevent overflow on small screens',
317
+ header:
318
+ 'header content (string or ReactNode), rendered next to close button',
319
+ width:
320
+ 'drawer width px; capped at 85vw to prevent overflow on small screens',
213
321
  side: 'slide direction; start=left LTR, right RTL',
214
322
  },
215
323
  };
@@ -0,0 +1,208 @@
1
+ ---
2
+ schema_version: 1
3
+ template_version: 3
4
+ kind: component
5
+ id: component:MobileNav
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, theming, accessibility]
13
+ verified_by:
14
+ [
15
+ packages/core/src/MobileNav/MobileNav.test.tsx,
16
+ packages/core/src/MobileNav/MobileNavToggle.test.tsx,
17
+ packages/core/src/MobileNav/MobileNavCloseEdgeCases.test.tsx,
18
+ packages/core/src/theme/themingTargets.test.ts,
19
+ scripts/check-knowledge.mjs,
20
+ ]
21
+ families: [family:overlay-dismissal]
22
+ design_specs: []
23
+ architecture:
24
+ [
25
+ architecture:component-theming-surface,
26
+ architecture:layer-runtime,
27
+ architecture:public-component-api,
28
+ ]
29
+ contributing: []
30
+ system_specs: []
31
+ ---
32
+
33
+ # MobileNav component contract
34
+
35
+ ## Intent
36
+
37
+ MobileNav presents mobile navigation in a modal drawer and exports an AppShell-
38
+ aware Toggle button for opening and closing it. This draft records the aggregate
39
+ consumer anatomy and theming ownership of both exports without changing runtime
40
+ behavior, styling, targets, or public 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
+ - The Navigation overlay and its current `mobile-nav` target.
57
+ - Drawer placement and motion, the stable Header and Content regions, and the
58
+ connection between AppShell state, MobileNav, and MobileNavToggle.
59
+ - Canonical anatomy for both exported components. `component:MobileNav` is the
60
+ parent owner; MobileNavToggle does not have a separate component contract.
61
+
62
+ **Does not own / non-goals**
63
+
64
+ - The Close and Toggle button surfaces — delegated to `component:Button`.
65
+ - Header or navigation content supplied by the caller.
66
+ - A public target for the painted Drawer, Header, or Content region; none exists
67
+ on current `main`.
68
+ - AppShell responsive policy or shared layer and dismissal policy.
69
+
70
+ ## Public concepts
71
+
72
+ No new public concept is introduced. Consumer props, exports, and usage remain
73
+ documented in `MobileNav.doc.mjs`.
74
+
75
+ ## Behavioral and layout contract
76
+
77
+ | ID | Candidate invariant | Basis | Draft review state |
78
+ | --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | -------------------------------------------------- |
79
+ | FR1 | MobileNav renders one Navigation overlay containing a Drawer with a stable Header, Close button, and scrollable Content region. | Current source, docs, and tests | Verified current behavior; no new behavior decided |
80
+ | FR2 | Navigation overlay carries the current `mobile-nav` target. Drawer, Header, and Content carry no MobileNav public target. | Current source and public docs | Verified current reachability; no target change |
81
+ | FR3 | Close button and the separately exported Toggle button use Button's `button` target; Toggle renders only when AppShell mobile context enables it and references the drawer by ID. | Current source, docs, and tests | Verified current delegation; no ownership change |
82
+
83
+ ### Allowed variation
84
+
85
+ - **AV1 — Drawer edge.** The Drawer may resolve to logical start or end through
86
+ the current explicit or trigger-derived side behavior.
87
+ - **AV2 — Header content.** Header may contain a string rendered through Heading,
88
+ caller-provided content, or only the Close button.
89
+ - **AV3 — Navigation content.** Caller-provided navigation content may vary
90
+ without becoming MobileNav-owned anatomy.
91
+ - **AV4 — Toggle presence.** Toggle button is absent outside an enabled AppShell
92
+ mobile context.
93
+
94
+ ### Representative states
95
+
96
+ | State | Required invariant | Allowed variation |
97
+ | ------------------------ | ---------------------------------------------------------------------- | -------------------------------------------------- |
98
+ | Standalone drawer | Navigation overlay contains Drawer, Header, Close button, and Content. | Caller controls open state and may choose an edge. |
99
+ | AppShell drawer | The same drawer anatomy consumes AppShell mobile state. | Header and navigation content remain caller-owned. |
100
+ | AppShell mobile toggle | Toggle button controls and references the current drawer. | Custom button content may replace the menu glyph. |
101
+ | Non-mobile/disabled host | Toggle button does not render. | MobileNav remains owned by the parent contract. |
102
+
103
+ ### Transformation and precedence order
104
+
105
+ - No new side resolution, open-state, close timing, or styling precedence rule is
106
+ introduced.
107
+
108
+ ### Performance and resources
109
+
110
+ - No new performance or resource rule is introduced.
111
+
112
+ ## Accessibility contract
113
+
114
+ This draft does not change or extend MobileNav's existing dialog naming, focus,
115
+ Toggle relationship, Button labels, modal behavior, or dismissal behavior.
116
+
117
+ ## Design relationships
118
+
119
+ | Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
120
+ | ------------------ | --------------------------------------------------------------------- | ------------------------------ | -------------- | ------------------ |
121
+ | Navigation overlay | Hosts the modal navigation layer and its backdrop. | Current source and public docs | Supporting | FR1, FR2 |
122
+ | Drawer | Paints the sliding mobile navigation surface. | Current source and public docs | Prominent | FR1, FR2 |
123
+ | Header | Arranges optional header content with the persistent Close button. | Current source and public docs | Supporting | FR1, FR2 |
124
+ | Content | Provides the scrolling region for caller-supplied navigation content. | Current source and public docs | Prominent | FR1, FR2 |
125
+ | Close button | Dismisses the current drawer. | `component:Button` | Supporting | FR1, FR3 |
126
+ | Toggle button | Opens or closes the AppShell-owned mobile drawer state. | `component:Button` | Supporting | FR3 |
127
+
128
+ Drawer is the primary painted surface, but the only current MobileNav target is
129
+ on the full-viewport dialog overlay. Its `none` disposition is a factual
130
+ reachability gap, not a decision that the Drawer must remain unthemeable. Header
131
+ and Content likewise have no current local target. Close and Toggle retain Button
132
+ ownership.
133
+
134
+ ### Theming anatomy
135
+
136
+ <!-- anatomy-theming:v1 -->
137
+
138
+ ```json
139
+ {
140
+ "Navigation overlay": {"target": "mobile-nav"},
141
+ "Drawer": {
142
+ "none": {
143
+ "reason": "reachability-gap: No current public target is applied to the painted drawer panel"
144
+ }
145
+ },
146
+ "Header": {
147
+ "none": {
148
+ "reason": "reachability-gap: No current public target is applied to the stable header row"
149
+ }
150
+ },
151
+ "Content": {
152
+ "none": {
153
+ "reason": "reachability-gap: No current public target is applied to the scrollable content region"
154
+ }
155
+ },
156
+ "Close button": {
157
+ "delegatesTo": {"owner": "component:Button", "target": "button"}
158
+ },
159
+ "Toggle button": {
160
+ "delegatesTo": {"owner": "component:Button", "target": "button"}
161
+ }
162
+ }
163
+ ```
164
+
165
+ ## Family and system relationships
166
+
167
+ - `architecture:component-theming-surface` owns anatomy qualification, target
168
+ mapping, delegation, and factual `none` dispositions.
169
+ - `architecture:layer-runtime` owns the current native-dialog host and shared
170
+ layer plumbing; MobileNav retains its current drawer motion and backdrop path.
171
+ - `family:overlay-dismissal` owns shared Escape and platform-close ordering and
172
+ records MobileNav as a current adopter.
173
+ - `architecture:public-component-api` owns the shared API boundary; this draft
174
+ changes neither MobileNav nor MobileNavToggle API.
175
+ - AppShell remains the higher-level responsive owner. This parent component
176
+ record owns the two MobileNav exports' shared anatomy only.
177
+
178
+ ## Verification map
179
+
180
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
181
+ | ------------------- | ----------------------------------------------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------- |
182
+ | FR1 | `MobileNav.test.tsx` content/header/close assertions plus source inspection | Standalone open and closed drawer | Removing dialog content or the Close action fails tests; distinct Drawer/Header/Content wrappers rely on review. | `audit:MobileNav/anatomy` |
183
+ | FR2 | Source inspection and `themingTargets.test.ts` | Overlay, Drawer, Header, and Content | Removing the root target or documenting an unshipped child target fails evidence or inventory. | `audit:MobileNav/theming` |
184
+ | FR3 | `MobileNavToggle.test.tsx`, `MobileNavReopen.test.tsx`, and source inspection | Closed/open AppShell drawer and toggle | Breaking Button delegation or the ID/state relationship fails focused toggle coverage. | `audit:MobileNav/anatomy` |
185
+ | Close lifecycle | `MobileNavCloseEdgeCases.test.tsx` and related close/visibility suites | Escape, backdrop, close, reopen, unmount | Leaving the modal open or disconnecting state fails existing lifecycle assertions. | `audit:MobileNav/behavior` |
186
+ | Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical parent anatomy and current target | Missing, extra, prefixed, stale, or multiply assigned mappings fail repository validation. | `audit:MobileNav/theming` |
187
+
188
+ Current tests find header and navigation content by text and the Close action by
189
+ role, but do not identify the distinct Drawer, Header, or Content elements. Their
190
+ existence and nesting are source-inspected; merging or reordering those wrappers
191
+ currently lacks focused regression evidence.
192
+
193
+ ## Decision log
194
+
195
+ None. This draft records current facts and introduces no component-local design,
196
+ API, theming, responsive, or layer-system decision.
197
+
198
+ ## Open questions
199
+
200
+ - **OQ1 — Should Drawer gain a stable public theming target?** (`human-api`) The
201
+ current target reaches the Navigation overlay rather than the primary painted
202
+ drawer surface; this is an audit gap, not settled intent.
203
+
204
+ ## Content boundary
205
+
206
+ This file does not duplicate consumer prop tables/examples, AppShell responsive
207
+ policy, close-timing mechanics, shared layer rules, current audit results, or
208
+ implementation steps. It links to their owners.
@@ -1,5 +1,45 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Trigger button',
7
+ required: true,
8
+ description:
9
+ 'Icon-only Button that provides the visible overflow-menu entry point.',
10
+ },
11
+ {
12
+ name: 'Icon-resolved trigger icon',
13
+ required: false,
14
+ description:
15
+ 'Default semantic three-dot artwork resolved from the active Icon registry.',
16
+ },
17
+ {
18
+ name: 'Caller-rendered trigger content',
19
+ required: false,
20
+ description:
21
+ 'Arbitrary React content supplied directly as the trigger icon override.',
22
+ },
23
+ {
24
+ name: 'Menu surface',
25
+ required: true,
26
+ description:
27
+ 'DropdownMenu panel that also carries MoreMenu’s current public target.',
28
+ },
29
+ {
30
+ name: 'Pointer action row',
31
+ required: false,
32
+ description:
33
+ 'Action or nested-action trigger row rendered by DropdownMenu in the anchored presentation.',
34
+ },
35
+ {
36
+ name: 'Touch action row',
37
+ required: false,
38
+ description:
39
+ 'ListItem button rendered by DropdownMenu in the BottomSheet presentation.',
40
+ },
41
+ ];
42
+
3
43
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
44
 
5
45
  export const docs = {
@@ -61,6 +101,12 @@ export const docs = {
61
101
  "Alignment along the placement axis. Use 'end' to align the menu with the trigger's trailing edge, which is usually what an overflow menu wants.",
62
102
  default: "'start'",
63
103
  },
104
+ {
105
+ name: 'presentation',
106
+ type: "'popover' | 'bottom-sheet' | 'adaptive'",
107
+ description: 'Presentation policy forwarded to DropdownMenu. `adaptive` keeps the anchored popover on pointer-based layouts and uses a BottomSheet at 768px and below when the primary pointer is coarse.',
108
+ default: "'popover'",
109
+ },
64
110
  {
65
111
  name: 'onOpenChange',
66
112
  type: '(isOpen: boolean) => void',
@@ -88,11 +134,13 @@ export const docs = {
88
134
  ],
89
135
  },
90
136
  usage: {
137
+ anatomy,
91
138
  description:
92
139
  'MoreMenu is a three-dot button that opens a list of actions. Use it for secondary actions that don\'t need to be always visible, like in table rows, card headers, or toolbars.',
93
140
  bestPractices: [
94
141
  { guidance: true, description: 'Use for overflow or secondary actions; keep primary actions visible outside the menu.' },
95
142
  { guidance: true, description: 'Use dividers or sections to group related actions when the menu has many items.' },
143
+ { guidance: true, description: 'Use `presentation="adaptive"` when the visible overflow trigger should open a thumb-reachable BottomSheet on compact touch devices.' },
96
144
  { guidance: false, description: 'Hide primary actions inside a MoreMenu; they should be directly visible.' },
97
145
  ],
98
146
  },
@@ -153,6 +201,12 @@ export const docsZh = {
153
201
  "沿放置轴的对齐方式。使用 'end' 让菜单与触发器的尾部边缘对齐,这通常是溢出菜单所需的效果。",
154
202
  default: "'start'",
155
203
  },
204
+ {
205
+ name: 'presentation',
206
+ type: "'popover' | 'bottom-sheet' | 'adaptive'",
207
+ description: '菜单呈现策略。`adaptive` 在指针布局中使用锚定浮层,在主指针为粗略指针且宽度不超过 768px 时使用 BottomSheet。',
208
+ default: "'popover'",
209
+ },
156
210
  {
157
211
  name: 'xstyle',
158
212
  type: 'StyleXStyles',
@@ -171,6 +225,7 @@ export const docsZh = {
171
225
  bestPractices: [
172
226
  { guidance: true, description: 'Use for overflow or secondary actions; keep primary actions visible outside the menu.' },
173
227
  { guidance: true, description: 'Use dividers or sections to group related actions when the menu has many items.' },
228
+ { guidance: true, description: 'Use `presentation="adaptive"` when the visible overflow trigger should open a thumb-reachable BottomSheet on compact touch devices.' },
174
229
  { guidance: false, description: 'Hide primary actions inside a MoreMenu; they should be directly visible.' },
175
230
  ],
176
231
  },
@@ -181,11 +236,13 @@ export const docsDense = {
181
236
  description:
182
237
  'Overflow menu w/ three-dot icon trigger. Convenience wrapper composing icon-only Button w/ dropdown menu, eliminating boilerplate for state management, positioning, accessibility.',
183
238
  usage: {
239
+ anatomy,
184
240
  description:
185
241
  'MoreMenu is a three-dot button that opens a list of actions. Use it for secondary actions that don\'t need to be always visible, like in table rows, card headers, or toolbars.',
186
242
  bestPractices: [
187
243
  { guidance: true, description: 'Use for overflow or secondary actions; keep primary actions visible outside the menu.' },
188
244
  { guidance: true, description: 'Use dividers or sections to group related actions when the menu has many items.' },
245
+ { guidance: true, description: 'Use `presentation="adaptive"` when the visible overflow trigger should open a thumb-reachable BottomSheet on compact touch devices.' },
189
246
  { guidance: false, description: 'Hide primary actions inside a MoreMenu; they should be directly visible.' },
190
247
  ],
191
248
  },
@@ -199,6 +256,8 @@ export const docsDense = {
199
256
  placement: 'Menu position relative to trigger. Logical (RTL mirrors).',
200
257
  alignment:
201
258
  "Alignment along the placement axis. 'end' aligns with the trigger's trailing edge.",
259
+ presentation:
260
+ 'Popover, BottomSheet, or adaptive compact-touch presentation.',
202
261
  xstyle:
203
262
  'StyleX styles for layout customization (margins, positioning, sizing). Must be stylex.create() value.',
204
263
  },