@duro-app/ui 5.1.0 → 5.3.0

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 (233) hide show
  1. package/dist/Table-Cm5cCnZD.js +1524 -0
  2. package/dist/Table-Cm5cCnZD.js.map +1 -0
  3. package/dist/components/ActionBar/styles.css.d.ts +1 -1
  4. package/dist/components/ActionBar/styles.css.d.ts.map +1 -1
  5. package/dist/components/Badge/Badge.d.ts +1 -1
  6. package/dist/components/Badge/Badge.d.ts.map +1 -1
  7. package/dist/components/Badge/Badge.stories.d.ts +3 -0
  8. package/dist/components/Badge/Badge.stories.d.ts.map +1 -1
  9. package/dist/components/Badge/styles.css.d.ts +4 -0
  10. package/dist/components/Badge/styles.css.d.ts.map +1 -1
  11. package/dist/components/Button/Button.d.ts +11 -2
  12. package/dist/components/Button/Button.d.ts.map +1 -1
  13. package/dist/components/Button/Button.stories.d.ts +1 -0
  14. package/dist/components/Button/Button.stories.d.ts.map +1 -1
  15. package/dist/components/ButtonGroup/ButtonGroup.d.ts +9 -2
  16. package/dist/components/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  17. package/dist/components/ButtonGroup/ButtonGroup.meta.d.ts.map +1 -1
  18. package/dist/components/ButtonGroup/ButtonGroup.stories.d.ts +19 -0
  19. package/dist/components/ButtonGroup/ButtonGroup.stories.d.ts.map +1 -1
  20. package/dist/components/ButtonGroup/ButtonGroupContext.d.ts +13 -0
  21. package/dist/components/ButtonGroup/ButtonGroupContext.d.ts.map +1 -0
  22. package/dist/components/ButtonGroup/attached.css.d.ts +34 -0
  23. package/dist/components/ButtonGroup/attached.css.d.ts.map +1 -0
  24. package/dist/components/ButtonGroup/styles.css.d.ts +7 -0
  25. package/dist/components/ButtonGroup/styles.css.d.ts.map +1 -1
  26. package/dist/components/ButtonGroup/useGroupedControl.d.ts +25 -0
  27. package/dist/components/ButtonGroup/useGroupedControl.d.ts.map +1 -0
  28. package/dist/components/Combobox/Combobox.d.ts +1 -1
  29. package/dist/components/Combobox/Combobox.d.ts.map +1 -1
  30. package/dist/components/Combobox/styles.css.d.ts +0 -64
  31. package/dist/components/Combobox/styles.css.d.ts.map +1 -1
  32. package/dist/components/Dialog/Dialog.d.ts +11 -3
  33. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  34. package/dist/components/Dialog/Dialog.stories.d.ts +4 -0
  35. package/dist/components/Dialog/Dialog.stories.d.ts.map +1 -1
  36. package/dist/components/Dialog/styles.css.d.ts +3 -2
  37. package/dist/components/Dialog/styles.css.d.ts.map +1 -1
  38. package/dist/components/DragDrop/DragDrop.d.ts.map +1 -1
  39. package/dist/components/DragDrop/styles.css.d.ts +11 -3
  40. package/dist/components/DragDrop/styles.css.d.ts.map +1 -1
  41. package/dist/components/Drawer/Drawer.d.ts.map +1 -1
  42. package/dist/components/Drawer/styles.css.d.ts +2 -2
  43. package/dist/components/Drawer/styles.css.d.ts.map +1 -1
  44. package/dist/components/Grid/Grid.d.ts +11 -2
  45. package/dist/components/Grid/Grid.d.ts.map +1 -1
  46. package/dist/components/Grid/Grid.stories.d.ts +2 -0
  47. package/dist/components/Grid/Grid.stories.d.ts.map +1 -1
  48. package/dist/components/Input/Input.d.ts +6 -1
  49. package/dist/components/Input/Input.d.ts.map +1 -1
  50. package/dist/components/Input/Input.meta.d.ts.map +1 -1
  51. package/dist/components/Input/Input.stories.d.ts +1 -0
  52. package/dist/components/Input/Input.stories.d.ts.map +1 -1
  53. package/dist/components/Input/styles.css.d.ts +18 -0
  54. package/dist/components/Input/styles.css.d.ts.map +1 -1
  55. package/dist/components/InputGroup/InputGroup.d.ts +6 -1
  56. package/dist/components/InputGroup/InputGroup.d.ts.map +1 -1
  57. package/dist/components/InputGroup/InputGroup.stories.d.ts +1 -0
  58. package/dist/components/InputGroup/InputGroup.stories.d.ts.map +1 -1
  59. package/dist/components/Listbox/Listbox.d.ts +75 -0
  60. package/dist/components/Listbox/Listbox.d.ts.map +1 -0
  61. package/dist/components/Listbox/Listbox.meta.d.ts +3 -0
  62. package/dist/components/Listbox/Listbox.meta.d.ts.map +1 -0
  63. package/dist/components/Listbox/Listbox.stories.d.ts +7 -0
  64. package/dist/components/Listbox/Listbox.stories.d.ts.map +1 -0
  65. package/dist/components/Listbox/styles.css.d.ts +75 -0
  66. package/dist/components/Listbox/styles.css.d.ts.map +1 -0
  67. package/dist/components/Menu/Menu.d.ts +18 -5
  68. package/dist/components/Menu/Menu.d.ts.map +1 -1
  69. package/dist/components/Menu/Menu.meta.d.ts.map +1 -1
  70. package/dist/components/Menu/Menu.stories.d.ts +7 -0
  71. package/dist/components/Menu/Menu.stories.d.ts.map +1 -1
  72. package/dist/components/Menu/MenuContext.d.ts +3 -0
  73. package/dist/components/Menu/MenuContext.d.ts.map +1 -1
  74. package/dist/components/Menu/styles.css.d.ts +24 -15
  75. package/dist/components/Menu/styles.css.d.ts.map +1 -1
  76. package/dist/components/Menu/useMenuRoot.d.ts +14 -1
  77. package/dist/components/Menu/useMenuRoot.d.ts.map +1 -1
  78. package/dist/components/Popover/Popover.d.ts +7 -2
  79. package/dist/components/Popover/Popover.d.ts.map +1 -1
  80. package/dist/components/Popover/styles.css.d.ts +4 -1
  81. package/dist/components/Popover/styles.css.d.ts.map +1 -1
  82. package/dist/components/ScrollArea/styles.css.d.ts +1 -1
  83. package/dist/components/ScrollArea/styles.css.d.ts.map +1 -1
  84. package/dist/components/Select/Select.d.ts.map +1 -1
  85. package/dist/components/Select/Select.stories.d.ts +2 -0
  86. package/dist/components/Select/Select.stories.d.ts.map +1 -1
  87. package/dist/components/Select/styles.css.d.ts +2 -2
  88. package/dist/components/Select/styles.css.d.ts.map +1 -1
  89. package/dist/components/Select/useSelectRoot.d.ts.map +1 -1
  90. package/dist/components/TextLink/TextLink.d.ts +24 -0
  91. package/dist/components/TextLink/TextLink.d.ts.map +1 -0
  92. package/dist/components/TextLink/TextLink.meta.d.ts +3 -0
  93. package/dist/components/TextLink/TextLink.meta.d.ts.map +1 -0
  94. package/dist/components/TextLink/TextLink.stories.d.ts +9 -0
  95. package/dist/components/TextLink/TextLink.stories.d.ts.map +1 -0
  96. package/dist/components/TextLink/styles.css.d.ts +28 -0
  97. package/dist/components/TextLink/styles.css.d.ts.map +1 -0
  98. package/dist/components/ThemeProvider/Layers.stories.d.ts +24 -0
  99. package/dist/components/ThemeProvider/Layers.stories.d.ts.map +1 -0
  100. package/dist/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  101. package/dist/components/ThemeProvider/ThemeProvider.stories.d.ts +1 -0
  102. package/dist/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
  103. package/dist/components/Toast/styles.css.d.ts +1 -0
  104. package/dist/components/Toast/styles.css.d.ts.map +1 -1
  105. package/dist/components/Toggle/Toggle.d.ts.map +1 -1
  106. package/dist/components/Toggle/styles.css.d.ts +3 -0
  107. package/dist/components/Toggle/styles.css.d.ts.map +1 -1
  108. package/dist/components/ToggleGroup/ToggleGroup.d.ts.map +1 -1
  109. package/dist/components/ToggleGroup/styles.css.d.ts +5 -0
  110. package/dist/components/ToggleGroup/styles.css.d.ts.map +1 -1
  111. package/dist/components/Toolbar/ControlContextBoundary.d.ts +10 -0
  112. package/dist/components/Toolbar/ControlContextBoundary.d.ts.map +1 -0
  113. package/dist/components/Toolbar/Toolbar.d.ts +22 -0
  114. package/dist/components/Toolbar/Toolbar.d.ts.map +1 -0
  115. package/dist/components/Toolbar/Toolbar.meta.d.ts +3 -0
  116. package/dist/components/Toolbar/Toolbar.meta.d.ts.map +1 -0
  117. package/dist/components/Toolbar/Toolbar.stories.d.ts +28 -0
  118. package/dist/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
  119. package/dist/components/Toolbar/ToolbarContext.d.ts +10 -0
  120. package/dist/components/Toolbar/ToolbarContext.d.ts.map +1 -0
  121. package/dist/components/Toolbar/styles.css.d.ts +16 -0
  122. package/dist/components/Toolbar/styles.css.d.ts.map +1 -0
  123. package/dist/components/Tooltip/styles.css.d.ts +1 -1
  124. package/dist/components/Tooltip/styles.css.d.ts.map +1 -1
  125. package/dist/components/VirtualTable/styles.css.d.ts +1 -1
  126. package/dist/components/VirtualTable/styles.css.d.ts.map +1 -1
  127. package/dist/components/VisuallyHidden/VisuallyHidden.d.ts +14 -0
  128. package/dist/components/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  129. package/dist/components/VisuallyHidden/VisuallyHidden.meta.d.ts +3 -0
  130. package/dist/components/VisuallyHidden/VisuallyHidden.meta.d.ts.map +1 -0
  131. package/dist/components/VisuallyHidden/VisuallyHidden.stories.d.ts +7 -0
  132. package/dist/components/VisuallyHidden/VisuallyHidden.stories.d.ts.map +1 -0
  133. package/dist/docs/FlexGrow.stories.d.ts +7 -0
  134. package/dist/docs/FlexGrow.stories.d.ts.map +1 -0
  135. package/dist/index.css +1 -1
  136. package/dist/index.d.ts +7 -1
  137. package/dist/index.d.ts.map +1 -1
  138. package/dist/index.js +3768 -3356
  139. package/dist/index.js.map +1 -1
  140. package/dist/index.native.d.ts +1 -0
  141. package/dist/index.native.d.ts.map +1 -1
  142. package/dist/shared/ModalContext.d.ts +14 -0
  143. package/dist/shared/ModalContext.d.ts.map +1 -0
  144. package/dist/shared/mergeRefs.d.ts +4 -0
  145. package/dist/shared/mergeRefs.d.ts.map +1 -0
  146. package/dist/shared/useOrderedRegistry.d.ts +26 -0
  147. package/dist/shared/useOrderedRegistry.d.ts.map +1 -0
  148. package/dist/styles/visually-hidden.css.d.ts +6 -0
  149. package/dist/styles/visually-hidden.css.d.ts.map +1 -1
  150. package/dist/table.js +45 -45
  151. package/dist/table.js.map +1 -1
  152. package/package.json +2 -2
  153. package/src/components/ActionBar/styles.css.ts +2 -1
  154. package/src/components/Badge/Badge.stories.tsx +62 -1
  155. package/src/components/Badge/Badge.tsx +1 -1
  156. package/src/components/Badge/styles.css.ts +5 -0
  157. package/src/components/Button/Button.stories.tsx +41 -0
  158. package/src/components/Button/Button.tsx +22 -1
  159. package/src/components/ButtonGroup/ButtonGroup.meta.ts +14 -1
  160. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +271 -1
  161. package/src/components/ButtonGroup/ButtonGroup.tsx +46 -14
  162. package/src/components/ButtonGroup/ButtonGroupContext.ts +19 -0
  163. package/src/components/ButtonGroup/attached.css.ts +44 -0
  164. package/src/components/ButtonGroup/styles.css.ts +8 -0
  165. package/src/components/ButtonGroup/useGroupedControl.ts +75 -0
  166. package/src/components/Combobox/Combobox.tsx +25 -79
  167. package/src/components/Combobox/styles.css.ts +0 -74
  168. package/src/components/Dialog/Dialog.meta.ts +1 -1
  169. package/src/components/Dialog/Dialog.stories.tsx +109 -3
  170. package/src/components/Dialog/Dialog.tsx +68 -10
  171. package/src/components/Dialog/styles.css.ts +5 -2
  172. package/src/components/DragDrop/DragDrop.tsx +15 -8
  173. package/src/components/DragDrop/styles.css.ts +20 -4
  174. package/src/components/Drawer/Drawer.tsx +5 -1
  175. package/src/components/Drawer/styles.css.ts +3 -2
  176. package/src/components/Grid/Grid.meta.ts +1 -1
  177. package/src/components/Grid/Grid.stories.tsx +53 -1
  178. package/src/components/Grid/Grid.tsx +23 -11
  179. package/src/components/Input/Input.meta.ts +10 -3
  180. package/src/components/Input/Input.stories.tsx +52 -2
  181. package/src/components/Input/Input.tsx +12 -3
  182. package/src/components/Input/styles.css.ts +29 -0
  183. package/src/components/InputGroup/InputGroup.stories.tsx +20 -0
  184. package/src/components/InputGroup/InputGroup.tsx +20 -2
  185. package/src/components/Listbox/Listbox.meta.ts +52 -0
  186. package/src/components/Listbox/Listbox.stories.tsx +170 -0
  187. package/src/components/Listbox/Listbox.tsx +278 -0
  188. package/src/components/Listbox/styles.css.ts +90 -0
  189. package/src/components/Menu/Menu.meta.ts +2 -1
  190. package/src/components/Menu/Menu.stories.tsx +289 -8
  191. package/src/components/Menu/Menu.tsx +107 -29
  192. package/src/components/Menu/MenuContext.ts +3 -0
  193. package/src/components/Menu/styles.css.ts +32 -15
  194. package/src/components/Menu/useMenuRoot.ts +105 -48
  195. package/src/components/Popover/Popover.tsx +26 -5
  196. package/src/components/Popover/styles.css.ts +9 -1
  197. package/src/components/ScrollArea/styles.css.ts +2 -1
  198. package/src/components/Select/Select.stories.tsx +20 -1
  199. package/src/components/Select/Select.tsx +9 -3
  200. package/src/components/Select/styles.css.ts +3 -2
  201. package/src/components/Select/useSelectRoot.ts +17 -0
  202. package/src/components/TextLink/TextLink.meta.ts +33 -0
  203. package/src/components/TextLink/TextLink.stories.tsx +63 -0
  204. package/src/components/TextLink/TextLink.tsx +46 -0
  205. package/src/components/TextLink/styles.css.ts +58 -0
  206. package/src/components/ThemeProvider/Layers.stories.tsx +379 -0
  207. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +50 -0
  208. package/src/components/ThemeProvider/ThemeProvider.tsx +4 -2
  209. package/src/components/Toast/styles.css.ts +3 -0
  210. package/src/components/Toggle/Toggle.tsx +20 -4
  211. package/src/components/Toggle/styles.css.ts +6 -0
  212. package/src/components/ToggleGroup/ToggleGroup.tsx +16 -4
  213. package/src/components/ToggleGroup/styles.css.ts +7 -0
  214. package/src/components/Toolbar/ControlContextBoundary.tsx +16 -0
  215. package/src/components/Toolbar/Toolbar.meta.ts +48 -0
  216. package/src/components/Toolbar/Toolbar.stories.tsx +468 -0
  217. package/src/components/Toolbar/Toolbar.tsx +113 -0
  218. package/src/components/Toolbar/ToolbarContext.ts +15 -0
  219. package/src/components/Toolbar/styles.css.ts +17 -0
  220. package/src/components/Tooltip/styles.css.ts +2 -1
  221. package/src/components/VirtualTable/styles.css.ts +2 -1
  222. package/src/components/VisuallyHidden/VisuallyHidden.meta.ts +19 -0
  223. package/src/components/VisuallyHidden/VisuallyHidden.stories.tsx +30 -0
  224. package/src/components/VisuallyHidden/VisuallyHidden.tsx +22 -0
  225. package/src/docs/FlexGrow.stories.tsx +83 -0
  226. package/src/index.native.ts +1 -0
  227. package/src/index.ts +7 -1
  228. package/src/shared/ModalContext.ts +18 -0
  229. package/src/shared/mergeRefs.ts +11 -0
  230. package/src/shared/useOrderedRegistry.ts +57 -0
  231. package/src/styles/visually-hidden.css.ts +8 -0
  232. package/dist/Table-BkrgH0jb.js +0 -1199
  233. package/dist/Table-BkrgH0jb.js.map +0 -1
@@ -0,0 +1,30 @@
1
+ import type {Meta, StoryObj} from '@storybook/react'
2
+ import {expect} from 'storybook/test'
3
+ import {VisuallyHidden} from './VisuallyHidden'
4
+ import {Button} from '../Button/Button'
5
+ import {Icon} from '../Icon/Icon'
6
+
7
+ const meta: Meta<typeof VisuallyHidden> = {
8
+ title: 'Components/VisuallyHidden',
9
+ component: VisuallyHidden,
10
+ }
11
+
12
+ export default meta
13
+ type Story = StoryObj<typeof VisuallyHidden>
14
+
15
+ export const NamesAnIconButton: Story = {
16
+ render: () => (
17
+ <Button variant="secondary">
18
+ <Icon name="search" size="sm" />
19
+ <VisuallyHidden>Search</VisuallyHidden>
20
+ </Button>
21
+ ),
22
+ play: async ({canvas}) => {
23
+ const button = canvas.getByRole('button', {name: 'Search'})
24
+ await expect(button).toBeInTheDocument()
25
+ const text = canvas.getByText('Search')
26
+ const box = text.getBoundingClientRect()
27
+ await expect(box.width).toBeLessThanOrEqual(1)
28
+ await expect(box.height).toBeLessThanOrEqual(1)
29
+ },
30
+ }
@@ -0,0 +1,22 @@
1
+ import type {ReactNode} from 'react'
2
+ import {html} from 'react-strict-dom'
3
+ import {visuallyHidden} from '../../styles/visually-hidden.css'
4
+
5
+ interface VisuallyHiddenProps {
6
+ children: ReactNode
7
+ /** For aria-describedby / aria-labelledby to point at. */
8
+ id?: string
9
+ }
10
+
11
+ /**
12
+ * Text for assistive tech only: in the accessibility tree, not on screen. Use
13
+ * it to give an icon-only control or a visual-only cue words — a status a
14
+ * colour shows, "(opens in a new tab)" after a link.
15
+ */
16
+ export function VisuallyHidden({children, id}: VisuallyHiddenProps) {
17
+ return (
18
+ <html.span id={id} style={[visuallyHidden.base, visuallyHidden.text]}>
19
+ {children}
20
+ </html.span>
21
+ )
22
+ }
@@ -0,0 +1,83 @@
1
+ import type {Meta, StoryObj} from '@storybook/react'
2
+ import {expect} from 'storybook/test'
3
+ import {css, html} from 'react-strict-dom'
4
+ import {colors} from '@duro-app/tokens/tokens/colors.css'
5
+ import {sizes} from '@duro-app/tokens/tokens/sizes.css'
6
+ import {spacing} from '@duro-app/tokens/tokens/spacing.css'
7
+
8
+ // The premise of `duro/no-flex-grow-web` was that react-strict-dom's web
9
+ // runtime forces `flex-grow: 0`, so a growing child collapses. These stories
10
+ // hold RSD on web to what it actually does, so the rule follows the evidence.
11
+ const meta: Meta = {
12
+ title: 'Foundations/flexGrow on web',
13
+ }
14
+
15
+ export default meta
16
+ type Story = StoryObj
17
+
18
+ const styles = css.create({
19
+ row: {
20
+ display: 'flex',
21
+ flexDirection: 'row',
22
+ width: sizes.panelLg,
23
+ gap: spacing.sm,
24
+ backgroundColor: colors.bgCard,
25
+ },
26
+ column: {
27
+ display: 'flex',
28
+ flexDirection: 'column',
29
+ height: sizes.panelSm,
30
+ width: sizes.panelSm,
31
+ backgroundColor: colors.bgCard,
32
+ },
33
+ fixed: {
34
+ width: sizes.iconXxl,
35
+ height: sizes.iconXxl,
36
+ flexShrink: 0,
37
+ backgroundColor: colors.border,
38
+ },
39
+ grow: {
40
+ flexGrow: 1,
41
+ backgroundColor: colors.accent,
42
+ },
43
+ growFromZero: {
44
+ flexGrow: 1,
45
+ flexBasis: 0,
46
+ backgroundColor: colors.accent,
47
+ },
48
+ })
49
+
50
+ export const GrowInRow: Story = {
51
+ render: () => (
52
+ <html.div style={styles.row} role="group" aria-label="row">
53
+ <html.div style={styles.fixed} />
54
+ <html.div style={styles.grow} role="group" aria-label="grow" />
55
+ <html.div style={styles.growFromZero} role="group" aria-label="grow from zero" />
56
+ </html.div>
57
+ ),
58
+ play: async ({canvas}) => {
59
+ const row = canvas.getByRole('group', {name: 'row'}).getBoundingClientRect().width
60
+ const grow = canvas.getByRole('group', {name: 'grow'})
61
+ const zero = canvas.getByRole('group', {name: 'grow from zero'})
62
+ await expect(getComputedStyle(grow).flexGrow).toBe('1')
63
+ await expect(getComputedStyle(zero).flexGrow).toBe('1')
64
+ // The two growing children share what the fixed one leaves.
65
+ await expect(grow.getBoundingClientRect().width).toBeGreaterThan(row / 3)
66
+ await expect(zero.getBoundingClientRect().width).toBeGreaterThan(row / 3)
67
+ },
68
+ }
69
+
70
+ export const GrowInColumn: Story = {
71
+ render: () => (
72
+ <html.div style={styles.column} role="group" aria-label="column">
73
+ <html.div style={styles.fixed} />
74
+ <html.div style={styles.growFromZero} role="group" aria-label="grow" />
75
+ </html.div>
76
+ ),
77
+ play: async ({canvas}) => {
78
+ const column = canvas.getByRole('group', {name: 'column'}).getBoundingClientRect().height
79
+ const grow = canvas.getByRole('group', {name: 'grow'})
80
+ await expect(getComputedStyle(grow).flexGrow).toBe('1')
81
+ await expect(grow.getBoundingClientRect().height).toBeGreaterThan(column / 2)
82
+ },
83
+ }
@@ -34,6 +34,7 @@ export {Stack, type SpacingKey} from './components/Stack/Stack'
34
34
  export {Inline} from './components/Inline/Inline'
35
35
  export {Cluster} from './components/Cluster/Cluster'
36
36
  export {Grid} from './components/Grid/Grid'
37
+ export type {GridTrack} from './shared/length'
37
38
 
38
39
  // Theming — resolves to ThemeProvider.native.tsx on Metro (RN-safe variant:
39
40
  // no display:contents / portal mount; applies the theme to a flex container).
package/src/index.ts CHANGED
@@ -13,7 +13,7 @@ export {Alert, type AlertVariant} from './components/Alert/Alert'
13
13
  export {Icon, type IconName} from './components/Icon'
14
14
  export {Badge, type BadgeVariant, type BadgeSize} from './components/Badge/Badge'
15
15
  export {Button, type ButtonVariant, type ButtonSize} from './components/Button/Button'
16
- export {ButtonGroup} from './components/ButtonGroup/ButtonGroup'
16
+ export {ButtonGroup, type ButtonGroupProps} from './components/ButtonGroup/ButtonGroup'
17
17
  export {Callout, type CalloutVariant} from './components/Callout/Callout'
18
18
  export {Card, type CardVariant, type CardSize} from './components/Card/Card'
19
19
  export {Checkbox} from './components/Checkbox/Checkbox'
@@ -48,6 +48,10 @@ export {Panel} from './components/Panel/Panel'
48
48
  export {RadioGroup} from './components/RadioGroup/RadioGroup'
49
49
  export {ScrollArea} from './components/ScrollArea/ScrollArea'
50
50
  export {Combobox} from './components/Combobox/Combobox'
51
+ export {Listbox} from './components/Listbox/Listbox'
52
+ export {VisuallyHidden} from './components/VisuallyHidden/VisuallyHidden'
53
+ export {TextLink, type TextLinkVariant} from './components/TextLink/TextLink'
54
+ export type {ListboxAnchorProps, ListboxMaxHeight} from './components/Listbox/Listbox'
51
55
  export {Select} from './components/Select/Select'
52
56
  export {SideNav} from './components/SideNav/SideNav'
53
57
  export {Spinner, type SpinnerSize} from './components/Spinner/Spinner'
@@ -90,6 +94,7 @@ export {Text, type TextVariant, type TextColor} from './components/Text/Text'
90
94
  export {Toggle, type ToggleSize} from './components/Toggle/Toggle'
91
95
  export {ToggleGroup} from './components/ToggleGroup/ToggleGroup'
92
96
  export {Tooltip} from './components/Tooltip/Tooltip'
97
+ export {Toolbar, type ToolbarProps} from './components/Toolbar/Toolbar'
93
98
  export {Popover} from './components/Popover/Popover'
94
99
  export type {PopoverHandle} from './components/Popover/Popover'
95
100
  export {Switch} from './components/Switch/Switch'
@@ -99,6 +104,7 @@ export {Stack, type SpacingKey} from './components/Stack/Stack'
99
104
  export {Inline} from './components/Inline/Inline'
100
105
  export {Cluster} from './components/Cluster/Cluster'
101
106
  export {Grid} from './components/Grid/Grid'
107
+ export type {GridTrack} from './shared/length'
102
108
  export {PageShell, type PageShellMaxWidth, type PageShellPadding} from './components/PageShell'
103
109
 
104
110
  // Hooks
@@ -0,0 +1,18 @@
1
+ import {createContext, useContext} from 'react'
2
+
3
+ /**
4
+ * True inside a Dialog or Drawer. A Popover reads it to pick its layer: inside
5
+ * a modal it must clear that modal (`layers.popover`); outside one it stays at
6
+ * `layers.floating`, so a modal opened later, even from inside the Popover,
7
+ * covers it.
8
+ *
9
+ * holds-until: a Dialog opened from a Popover that itself sits inside a Dialog
10
+ * still renders under that Popover (1000/1001 < 1040). It is fixed when a
11
+ * nested Dialog lifts its layer above its opener, or when the parent Popover
12
+ * closes on a nested modal opening; no consumer needs it yet.
13
+ */
14
+ export const ModalContext = createContext(false)
15
+
16
+ export function useInModal() {
17
+ return useContext(ModalContext)
18
+ }
@@ -0,0 +1,11 @@
1
+ import type {Ref, RefCallback} from 'react'
2
+
3
+ /** One callback ref that sets every ref given (object or callback). */
4
+ export function mergeRefs<T>(...refs: Array<Ref<T> | undefined>): RefCallback<T> {
5
+ return (value) => {
6
+ for (const ref of refs) {
7
+ if (typeof ref === 'function') ref(value)
8
+ else if (ref) (ref as {current: T | null}).current = value
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,57 @@
1
+ import {useCallback, useLayoutEffect, useRef, useState} from 'react'
2
+
3
+ /** A registered control: its id, in DOM order, and whether it is disabled. */
4
+ export interface RegisteredControl {
5
+ id: string
6
+ disabled: boolean
7
+ }
8
+
9
+ function sameEntries(a: RegisteredControl[], b: RegisteredControl[]) {
10
+ return (
11
+ a.length === b.length && a.every((e, i) => e.id === b[i].id && e.disabled === b[i].disabled)
12
+ )
13
+ }
14
+
15
+ /**
16
+ * Controls register their element here and come back in DOM order (the way
17
+ * useRovingFocus orders a wrapping ToggleGroup). A control's place is read
18
+ * from where it sits in the document, not from its parent: a Select or Menu
19
+ * trigger sits inside its own Root, so `:first-child` cannot tell.
20
+ *
21
+ * Registration happens in a layout effect, so server-rendered HTML (and the
22
+ * first client render) sees an empty registry.
23
+ *
24
+ * Keyed children can move without remounting, so the order is also re-read
25
+ * after every commit of the owner; state changes only when the order did.
26
+ */
27
+ export function useOrderedRegistry() {
28
+ const elements = useRef(new Map<string, {el: HTMLElement; disabled: boolean}>())
29
+ const [order, setOrder] = useState<RegisteredControl[]>([])
30
+
31
+ const sync = useCallback(() => {
32
+ const next = [...elements.current.entries()]
33
+ .sort(([, a], [, b]) =>
34
+ a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1,
35
+ )
36
+ .map(([id, {disabled}]) => ({id, disabled}))
37
+ setOrder((prev) => (sameEntries(prev, next) ? prev : next))
38
+ }, [])
39
+
40
+ const register = useCallback(
41
+ (id: string, el: HTMLElement, disabled: boolean) => {
42
+ elements.current.set(id, {el, disabled})
43
+ sync()
44
+ return () => {
45
+ if (elements.current.get(id)?.el === el) elements.current.delete(id)
46
+ sync()
47
+ }
48
+ },
49
+ [sync],
50
+ )
51
+
52
+ useLayoutEffect(() => {
53
+ sync()
54
+ })
55
+
56
+ return {elements, order, register}
57
+ }
@@ -13,4 +13,12 @@ export const visuallyHidden = css.create({
13
13
  height: 1,
14
14
  overflow: 'hidden',
15
15
  },
16
+ // For text (VisuallyHidden): clipped to nothing, kept on one line so a
17
+ // screen reader reads it whole.
18
+ text: {
19
+ clip: 'rect(0, 0, 0, 0)',
20
+ whiteSpace: 'nowrap',
21
+ borderWidth: 0,
22
+ padding: 0,
23
+ },
16
24
  })