@duro-app/ui 4.4.0 → 5.0.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 (273) hide show
  1. package/dist/{Table-JTgcR_Fh.js → Table-BKN_d-mp.js} +506 -410
  2. package/dist/Table-BKN_d-mp.js.map +1 -0
  3. package/dist/components/ActionBar/ActionBar.stories.d.ts.map +1 -1
  4. package/dist/components/ActionBar/styles.css.d.ts +7 -7
  5. package/dist/components/ActionBar/styles.css.d.ts.map +1 -1
  6. package/dist/components/Alert/styles.css.d.ts +2 -2
  7. package/dist/components/Alert/styles.css.d.ts.map +1 -1
  8. package/dist/components/Badge/styles.css.d.ts +2 -2
  9. package/dist/components/Button/styles.css.d.ts +5 -5
  10. package/dist/components/Button/styles.css.d.ts.map +1 -1
  11. package/dist/components/Callout/styles.css.d.ts +1 -1
  12. package/dist/components/Callout/styles.css.d.ts.map +1 -1
  13. package/dist/components/Card/styles.css.d.ts +3 -3
  14. package/dist/components/Card/styles.css.d.ts.map +1 -1
  15. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  16. package/dist/components/Checkbox/styles.css.d.ts +7 -11
  17. package/dist/components/Checkbox/styles.css.d.ts.map +1 -1
  18. package/dist/components/Cluster/Cluster.stories.d.ts.map +1 -1
  19. package/dist/components/ColorInput/styles.css.d.ts +6 -6
  20. package/dist/components/ColorInput/styles.css.d.ts.map +1 -1
  21. package/dist/components/ColorMode/styles.css.d.ts +3 -3
  22. package/dist/components/ColorMode/styles.css.d.ts.map +1 -1
  23. package/dist/components/Combobox/Combobox.d.ts.map +1 -1
  24. package/dist/components/Combobox/Combobox.meta.d.ts.map +1 -1
  25. package/dist/components/Combobox/styles.css.d.ts +3 -3
  26. package/dist/components/Combobox/styles.css.d.ts.map +1 -1
  27. package/dist/components/DetailPanel/DetailPanel.d.ts.map +1 -1
  28. package/dist/components/DetailPanel/DetailPanel.stories.d.ts.map +1 -1
  29. package/dist/components/DetailPanel/styles.css.d.ts +19 -10
  30. package/dist/components/DetailPanel/styles.css.d.ts.map +1 -1
  31. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  32. package/dist/components/Dialog/Dialog.stories.d.ts.map +1 -1
  33. package/dist/components/Dialog/styles.css.d.ts +18 -9
  34. package/dist/components/Dialog/styles.css.d.ts.map +1 -1
  35. package/dist/components/DragDrop/DragDrop.d.ts.map +1 -1
  36. package/dist/components/DragDrop/DragDrop.stories.d.ts.map +1 -1
  37. package/dist/components/DragDrop/styles.css.d.ts +0 -6
  38. package/dist/components/DragDrop/styles.css.d.ts.map +1 -1
  39. package/dist/components/Drawer/Drawer.d.ts.map +1 -1
  40. package/dist/components/Drawer/DrawerScroll.stories.d.ts +13 -0
  41. package/dist/components/Drawer/DrawerScroll.stories.d.ts.map +1 -0
  42. package/dist/components/Drawer/styles.css.d.ts +19 -10
  43. package/dist/components/Drawer/styles.css.d.ts.map +1 -1
  44. package/dist/components/Drawer/useSwipeDismiss.d.ts +7 -2
  45. package/dist/components/Drawer/useSwipeDismiss.d.ts.map +1 -1
  46. package/dist/components/Field/Field.stories.d.ts.map +1 -1
  47. package/dist/components/Field/styles.css.d.ts +1 -1
  48. package/dist/components/Field/styles.css.d.ts.map +1 -1
  49. package/dist/components/Form/Form.stories.d.ts.map +1 -1
  50. package/dist/components/Grid/Grid.d.ts +6 -4
  51. package/dist/components/Grid/Grid.d.ts.map +1 -1
  52. package/dist/components/Grid/Grid.stories.d.ts.map +1 -1
  53. package/dist/components/Grid/styles.css.d.ts +3 -3
  54. package/dist/components/Input/Input.stories.d.ts.map +1 -1
  55. package/dist/components/Input/styles.css.d.ts +3 -3
  56. package/dist/components/Input/styles.css.d.ts.map +1 -1
  57. package/dist/components/InputGroup/InputGroup.d.ts +4 -2
  58. package/dist/components/InputGroup/InputGroup.d.ts.map +1 -1
  59. package/dist/components/InputGroup/InputGroup.stories.d.ts.map +1 -1
  60. package/dist/components/InputGroup/styles.css.d.ts +3 -3
  61. package/dist/components/InputGroup/styles.css.d.ts.map +1 -1
  62. package/dist/components/LinkButton/styles.css.d.ts +1 -1
  63. package/dist/components/LinkButton/styles.css.d.ts.map +1 -1
  64. package/dist/components/List/List.stories.d.ts.map +1 -1
  65. package/dist/components/List/styles.css.d.ts +3 -3
  66. package/dist/components/List/styles.css.d.ts.map +1 -1
  67. package/dist/components/Menu/styles.css.d.ts +4 -4
  68. package/dist/components/Menu/styles.css.d.ts.map +1 -1
  69. package/dist/components/Menu/useMenuRoot.d.ts.map +1 -1
  70. package/dist/components/PageShell/styles.css.d.ts +3 -3
  71. package/dist/components/PageShell/styles.css.d.ts.map +1 -1
  72. package/dist/components/Panel/styles.css.d.ts +3 -3
  73. package/dist/components/Panel/styles.css.d.ts.map +1 -1
  74. package/dist/components/Popover/Popover.d.ts.map +1 -1
  75. package/dist/components/Popover/Popover.meta.d.ts.map +1 -1
  76. package/dist/components/Popover/Popover.stories.d.ts.map +1 -1
  77. package/dist/components/Popover/PopoverLayerContext.d.ts +10 -0
  78. package/dist/components/Popover/PopoverLayerContext.d.ts.map +1 -0
  79. package/dist/components/Popover/PopoverLayers.stories.d.ts +13 -0
  80. package/dist/components/Popover/PopoverLayers.stories.d.ts.map +1 -0
  81. package/dist/components/Popover/styles.css.d.ts +2 -2
  82. package/dist/components/Popover/styles.css.d.ts.map +1 -1
  83. package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -1
  84. package/dist/components/RadioGroup/styles.css.d.ts +5 -9
  85. package/dist/components/RadioGroup/styles.css.d.ts.map +1 -1
  86. package/dist/components/ScrollArea/ScrollArea.d.ts +10 -3
  87. package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  88. package/dist/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  89. package/dist/components/ScrollArea/styles.css.d.ts +8 -8
  90. package/dist/components/ScrollArea/styles.css.d.ts.map +1 -1
  91. package/dist/components/Select/Select.d.ts.map +1 -1
  92. package/dist/components/Select/Select.meta.d.ts.map +1 -1
  93. package/dist/components/Select/styles.css.d.ts +4 -4
  94. package/dist/components/Select/styles.css.d.ts.map +1 -1
  95. package/dist/components/Select/useSelectRoot.d.ts.map +1 -1
  96. package/dist/components/SideNav/styles.css.d.ts +7 -7
  97. package/dist/components/SideNav/styles.css.d.ts.map +1 -1
  98. package/dist/components/Spinner/Spinner.d.ts.map +1 -1
  99. package/dist/components/Spinner/styles.css.d.ts +10 -14
  100. package/dist/components/Spinner/styles.css.d.ts.map +1 -1
  101. package/dist/components/Switch/Switch.d.ts.map +1 -1
  102. package/dist/components/Switch/styles.css.d.ts +10 -14
  103. package/dist/components/Switch/styles.css.d.ts.map +1 -1
  104. package/dist/components/Table/ColumnFilter.d.ts.map +1 -1
  105. package/dist/components/Table/FromTanstack.d.ts +2 -1
  106. package/dist/components/Table/FromTanstack.d.ts.map +1 -1
  107. package/dist/components/Table/Pagination.d.ts.map +1 -1
  108. package/dist/components/Table/SortIndicator.d.ts.map +1 -1
  109. package/dist/components/Table/Table.d.ts +11 -9
  110. package/dist/components/Table/Table.d.ts.map +1 -1
  111. package/dist/components/Table/Table.stories.d.ts.map +1 -1
  112. package/dist/components/Table/styles.css.d.ts +6 -6
  113. package/dist/components/Table/styles.css.d.ts.map +1 -1
  114. package/dist/components/Tabs/styles.css.d.ts +8 -8
  115. package/dist/components/Tabs/styles.css.d.ts.map +1 -1
  116. package/dist/components/Tag/Tag.stories.d.ts.map +1 -1
  117. package/dist/components/Tag/styles.css.d.ts +4 -4
  118. package/dist/components/Tag/styles.css.d.ts.map +1 -1
  119. package/dist/components/TagGroup/TagGroup.d.ts.map +1 -1
  120. package/dist/components/TagGroup/styles.css.d.ts +4 -10
  121. package/dist/components/TagGroup/styles.css.d.ts.map +1 -1
  122. package/dist/components/Textarea/Textarea.stories.d.ts.map +1 -1
  123. package/dist/components/Textarea/styles.css.d.ts +3 -3
  124. package/dist/components/Textarea/styles.css.d.ts.map +1 -1
  125. package/dist/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
  126. package/dist/components/Toast/Toast.stories.d.ts.map +1 -1
  127. package/dist/components/Toast/styles.css.d.ts +12 -12
  128. package/dist/components/Toast/styles.css.d.ts.map +1 -1
  129. package/dist/components/Toggle/Toggle.d.ts.map +1 -1
  130. package/dist/components/Toggle/styles.css.d.ts +14 -4
  131. package/dist/components/Toggle/styles.css.d.ts.map +1 -1
  132. package/dist/components/ToggleGroup/ToggleGroup.d.ts +7 -1
  133. package/dist/components/ToggleGroup/ToggleGroup.d.ts.map +1 -1
  134. package/dist/components/ToggleGroup/ToggleGroup.meta.d.ts.map +1 -1
  135. package/dist/components/ToggleGroup/ToggleGroup.stories.d.ts +4 -0
  136. package/dist/components/ToggleGroup/ToggleGroup.stories.d.ts.map +1 -1
  137. package/dist/components/ToggleGroup/ToggleGroupContext.d.ts +6 -0
  138. package/dist/components/ToggleGroup/ToggleGroupContext.d.ts.map +1 -1
  139. package/dist/components/ToggleGroup/styles.css.d.ts +20 -1
  140. package/dist/components/ToggleGroup/styles.css.d.ts.map +1 -1
  141. package/dist/components/ToggleGroup/useRovingFocus.d.ts +17 -0
  142. package/dist/components/ToggleGroup/useRovingFocus.d.ts.map +1 -0
  143. package/dist/components/Tooltip/styles.css.d.ts +1 -1
  144. package/dist/components/Tooltip/styles.css.d.ts.map +1 -1
  145. package/dist/components/Tree/styles.css.d.ts +4 -4
  146. package/dist/components/Tree/styles.css.d.ts.map +1 -1
  147. package/dist/components/VirtualTable/VirtualTable.d.ts +2 -1
  148. package/dist/components/VirtualTable/VirtualTable.d.ts.map +1 -1
  149. package/dist/components/VirtualTable/VirtualTable.stories.d.ts.map +1 -1
  150. package/dist/components/VirtualTable/styles.css.d.ts +7 -7
  151. package/dist/components/VirtualTable/styles.css.d.ts.map +1 -1
  152. package/dist/docs/Spacing.stories.d.ts.map +1 -1
  153. package/dist/docs/Typography.stories.d.ts.map +1 -1
  154. package/dist/docs/helpers.d.ts.map +1 -1
  155. package/dist/index.css +1 -1
  156. package/dist/index.js +3788 -3515
  157. package/dist/index.js.map +1 -1
  158. package/dist/shared/length.d.ts +24 -0
  159. package/dist/shared/length.d.ts.map +1 -0
  160. package/dist/shared/length.typecheck.d.ts +28 -0
  161. package/dist/shared/length.typecheck.d.ts.map +1 -0
  162. package/dist/styles/visually-hidden.css.d.ts +10 -0
  163. package/dist/styles/visually-hidden.css.d.ts.map +1 -0
  164. package/dist/table.js +166 -166
  165. package/dist/table.js.map +1 -1
  166. package/package.json +2 -2
  167. package/src/components/ActionBar/ActionBar.stories.tsx +4 -2
  168. package/src/components/ActionBar/styles.css.ts +11 -9
  169. package/src/components/Alert/styles.css.ts +4 -3
  170. package/src/components/Badge/styles.css.ts +3 -3
  171. package/src/components/Button/styles.css.ts +8 -7
  172. package/src/components/Callout/styles.css.ts +2 -1
  173. package/src/components/Card/styles.css.ts +4 -3
  174. package/src/components/Checkbox/Checkbox.tsx +2 -1
  175. package/src/components/Checkbox/styles.css.ts +10 -11
  176. package/src/components/Cluster/Cluster.stories.tsx +2 -1
  177. package/src/components/ColorInput/styles.css.ts +9 -7
  178. package/src/components/ColorMode/styles.css.ts +4 -3
  179. package/src/components/Combobox/Combobox.meta.ts +6 -0
  180. package/src/components/Combobox/Combobox.tsx +5 -0
  181. package/src/components/Combobox/styles.css.ts +5 -3
  182. package/src/components/DetailPanel/DetailPanel.stories.tsx +5 -3
  183. package/src/components/DetailPanel/DetailPanel.tsx +3 -0
  184. package/src/components/DetailPanel/styles.css.ts +17 -11
  185. package/src/components/Dialog/Dialog.stories.tsx +2 -1
  186. package/src/components/Dialog/Dialog.tsx +3 -0
  187. package/src/components/Dialog/styles.css.ts +14 -9
  188. package/src/components/DragDrop/DragDrop.stories.tsx +2 -1
  189. package/src/components/DragDrop/DragDrop.tsx +2 -1
  190. package/src/components/DragDrop/styles.css.ts +0 -7
  191. package/src/components/Drawer/Drawer.meta.ts +1 -1
  192. package/src/components/Drawer/Drawer.tsx +15 -2
  193. package/src/components/Drawer/DrawerScroll.stories.tsx +292 -0
  194. package/src/components/Drawer/styles.css.ts +15 -10
  195. package/src/components/Drawer/useSwipeDismiss.ts +53 -8
  196. package/src/components/Field/Field.stories.tsx +3 -2
  197. package/src/components/Field/styles.css.ts +2 -1
  198. package/src/components/Form/Form.stories.tsx +4 -3
  199. package/src/components/Grid/Grid.meta.ts +2 -2
  200. package/src/components/Grid/Grid.stories.tsx +3 -2
  201. package/src/components/Grid/Grid.tsx +8 -6
  202. package/src/components/Grid/styles.css.ts +2 -2
  203. package/src/components/Input/Input.stories.tsx +2 -1
  204. package/src/components/Input/styles.css.ts +4 -3
  205. package/src/components/InputGroup/InputGroup.stories.tsx +3 -2
  206. package/src/components/InputGroup/InputGroup.tsx +5 -3
  207. package/src/components/InputGroup/styles.css.ts +4 -3
  208. package/src/components/LinkButton/styles.css.ts +2 -1
  209. package/src/components/List/List.stories.tsx +4 -2
  210. package/src/components/List/styles.css.ts +6 -4
  211. package/src/components/Menu/styles.css.ts +6 -4
  212. package/src/components/Menu/useMenuRoot.ts +5 -1
  213. package/src/components/PageShell/styles.css.ts +4 -3
  214. package/src/components/Panel/styles.css.ts +4 -3
  215. package/src/components/Popover/Popover.meta.ts +7 -0
  216. package/src/components/Popover/Popover.stories.tsx +6 -4
  217. package/src/components/Popover/Popover.tsx +30 -24
  218. package/src/components/Popover/PopoverLayerContext.ts +20 -0
  219. package/src/components/Popover/PopoverLayers.stories.tsx +234 -0
  220. package/src/components/Popover/styles.css.ts +3 -2
  221. package/src/components/RadioGroup/RadioGroup.tsx +2 -1
  222. package/src/components/RadioGroup/styles.css.ts +8 -9
  223. package/src/components/ScrollArea/ScrollArea.meta.ts +2 -2
  224. package/src/components/ScrollArea/ScrollArea.stories.tsx +7 -5
  225. package/src/components/ScrollArea/ScrollArea.tsx +18 -7
  226. package/src/components/ScrollArea/styles.css.ts +10 -9
  227. package/src/components/Select/Select.meta.ts +6 -0
  228. package/src/components/Select/Select.tsx +8 -1
  229. package/src/components/Select/styles.css.ts +6 -4
  230. package/src/components/Select/useSelectRoot.ts +6 -2
  231. package/src/components/SideNav/styles.css.ts +10 -8
  232. package/src/components/Spinner/Spinner.tsx +2 -1
  233. package/src/components/Spinner/styles.css.ts +14 -14
  234. package/src/components/Switch/Switch.tsx +2 -1
  235. package/src/components/Switch/styles.css.ts +15 -15
  236. package/src/components/Table/ColumnFilter.tsx +5 -4
  237. package/src/components/Table/FromTanstack.tsx +2 -1
  238. package/src/components/Table/Pagination.tsx +6 -4
  239. package/src/components/Table/SortIndicator.tsx +4 -2
  240. package/src/components/Table/Table.stories.tsx +8 -8
  241. package/src/components/Table/Table.tsx +19 -15
  242. package/src/components/Table/styles.css.ts +9 -7
  243. package/src/components/Tabs/styles.css.ts +11 -9
  244. package/src/components/Tag/Tag.stories.tsx +4 -2
  245. package/src/components/Tag/styles.css.ts +6 -5
  246. package/src/components/TagGroup/TagGroup.tsx +2 -1
  247. package/src/components/TagGroup/styles.css.ts +6 -10
  248. package/src/components/Textarea/Textarea.stories.tsx +2 -1
  249. package/src/components/Textarea/styles.css.ts +4 -3
  250. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +7 -5
  251. package/src/components/Toast/Toast.stories.tsx +2 -1
  252. package/src/components/Toast/styles.css.ts +16 -14
  253. package/src/components/Toggle/Toggle.meta.ts +1 -1
  254. package/src/components/Toggle/Toggle.tsx +19 -2
  255. package/src/components/Toggle/styles.css.ts +18 -4
  256. package/src/components/ToggleGroup/ToggleGroup.meta.ts +11 -1
  257. package/src/components/ToggleGroup/ToggleGroup.stories.tsx +157 -0
  258. package/src/components/ToggleGroup/ToggleGroup.tsx +87 -10
  259. package/src/components/ToggleGroup/ToggleGroupContext.ts +6 -0
  260. package/src/components/ToggleGroup/styles.css.ts +32 -2
  261. package/src/components/ToggleGroup/useRovingFocus.ts +121 -0
  262. package/src/components/Tooltip/styles.css.ts +2 -1
  263. package/src/components/Tree/styles.css.ts +8 -6
  264. package/src/components/VirtualTable/VirtualTable.stories.tsx +4 -3
  265. package/src/components/VirtualTable/VirtualTable.tsx +5 -3
  266. package/src/components/VirtualTable/styles.css.ts +9 -8
  267. package/src/docs/Spacing.stories.tsx +11 -10
  268. package/src/docs/Typography.stories.tsx +8 -6
  269. package/src/docs/helpers.tsx +3 -2
  270. package/src/shared/length.ts +51 -0
  271. package/src/shared/length.typecheck.tsx +47 -0
  272. package/src/styles/visually-hidden.css.ts +16 -0
  273. package/dist/Table-JTgcR_Fh.js.map +0 -1
@@ -3,6 +3,7 @@ import {expect, fn} from 'storybook/test'
3
3
  import {css, html} from 'react-strict-dom'
4
4
  import {Input} from './Input'
5
5
  import {spacing} from '@duro-app/tokens/tokens/spacing.css'
6
+ import {sizes} from '@duro-app/tokens/tokens/sizes.css'
6
7
 
7
8
  const meta: Meta<typeof Input> = {
8
9
  title: 'Components/Input',
@@ -83,7 +84,7 @@ export const Disabled: Story = {
83
84
  }
84
85
 
85
86
  const stackStyles = css.create({
86
- stack: {display: 'flex', flexDirection: 'column', gap: spacing.ms, maxWidth: 320},
87
+ stack: {display: 'flex', flexDirection: 'column', gap: spacing.ms, maxWidth: sizes.panelSm},
87
88
  })
88
89
 
89
90
  export const AllVariants: Story = {
@@ -3,6 +3,7 @@ import {colors} from '@duro-app/tokens/tokens/colors.css'
3
3
  import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {typography} from '@duro-app/tokens/tokens/typography.css'
5
5
  import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
6
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
6
7
 
7
8
  export const styles = css.create({
8
9
  base: {
@@ -16,7 +17,7 @@ export const styles = css.create({
16
17
  lineHeight: typography.lineHeight,
17
18
  color: colors.text,
18
19
  backgroundColor: colors.bg,
19
- borderWidth: 1,
20
+ borderWidth: borders.hairline,
20
21
  borderStyle: 'solid',
21
22
  borderRadius: radii.sm,
22
23
  transitionProperty: 'border-color',
@@ -24,7 +25,7 @@ export const styles = css.create({
24
25
  transitionTimingFunction: easing.standard,
25
26
  outlineWidth: {
26
27
  default: 0,
27
- ':focus-visible': 2,
28
+ ':focus-visible': borders.focusRing,
28
29
  },
29
30
  outlineStyle: {
30
31
  default: 'none',
@@ -36,7 +37,7 @@ export const styles = css.create({
36
37
  },
37
38
  outlineOffset: {
38
39
  default: 0,
39
- ':focus-visible': 1,
40
+ ':focus-visible': borders.focusOffsetSm,
40
41
  },
41
42
  },
42
43
  default: {
@@ -5,6 +5,7 @@ import {InputGroup} from './InputGroup'
5
5
  import {Input} from '../Input/Input'
6
6
  import {Icon} from '../Icon/Icon'
7
7
  import {spacing} from '@duro-app/tokens/tokens/spacing.css'
8
+ import {sizes} from '@duro-app/tokens/tokens/sizes.css'
8
9
 
9
10
  const meta: Meta = {
10
11
  title: 'Components/InputGroup',
@@ -115,8 +116,8 @@ export const StandaloneInput: Story = {
115
116
  }
116
117
 
117
118
  const layoutStyles = css.create({
118
- container: {maxWidth: 400},
119
- stack: {display: 'flex', flexDirection: 'column', gap: spacing.md, maxWidth: 400},
119
+ container: {maxWidth: sizes.dialogSm},
120
+ stack: {display: 'flex', flexDirection: 'column', gap: spacing.md, maxWidth: sizes.dialogSm},
120
121
  })
121
122
 
122
123
  export const AllVariants: Story = {
@@ -4,6 +4,7 @@ import {css, html} from 'react-strict-dom'
4
4
  import {isNative} from '../../platform'
5
5
  import {InputGroupContext} from './InputGroupContext'
6
6
  import {styles} from './styles.css'
7
+ import {resolveLength, type Length} from '../../shared/length'
7
8
 
8
9
  // --- Root ---
9
10
  interface RootProps {
@@ -29,8 +30,9 @@ interface AddonProps {
29
30
  position?: 'start' | 'end'
30
31
  onClick?: () => void
31
32
  disabled?: boolean
32
- /** Optional minimum width to prevent layout shift (e.g. Copy → Copied!) */
33
- minWidth?: number | string
33
+ /** Optional minimum width to prevent layout shift (e.g. Copy → Copied!): a
34
+ * size token key or a relative length. */
35
+ minWidth?: Length
34
36
  children: ReactNode
35
37
  }
36
38
 
@@ -42,7 +44,7 @@ function Addon({position = 'end', onClick, disabled, minWidth, children}: AddonP
42
44
  positionStyle,
43
45
  onClick && !disabled && styles.addonClickable,
44
46
  disabled && styles.addonDisabled,
45
- minWidth != null && dynamicStyles.minWidth(minWidth),
47
+ minWidth != null && dynamicStyles.minWidth(resolveLength(minWidth)),
46
48
  ]
47
49
 
48
50
  if (onClick) {
@@ -3,12 +3,13 @@ import {colors} from '@duro-app/tokens/tokens/colors.css'
3
3
  import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {typography} from '@duro-app/tokens/tokens/typography.css'
5
5
  import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
6
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
6
7
 
7
8
  export const styles = css.create({
8
9
  wrapper: {
9
10
  display: 'flex',
10
11
  alignItems: 'stretch',
11
- borderWidth: 1,
12
+ borderWidth: borders.hairline,
12
13
  borderStyle: 'solid',
13
14
  borderColor: {
14
15
  default: colors.border,
@@ -35,12 +36,12 @@ export const styles = css.create({
35
36
  borderWidth: 0,
36
37
  },
37
38
  addonStart: {
38
- borderRightWidth: 1,
39
+ borderRightWidth: borders.hairline,
39
40
  borderRightStyle: 'solid',
40
41
  borderRightColor: colors.border,
41
42
  },
42
43
  addonEnd: {
43
- borderLeftWidth: 1,
44
+ borderLeftWidth: borders.hairline,
44
45
  borderLeftStyle: 'solid',
45
46
  borderLeftColor: colors.border,
46
47
  },
@@ -3,6 +3,7 @@ import {colors} from '@duro-app/tokens/tokens/colors.css'
3
3
  import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {typography} from '@duro-app/tokens/tokens/typography.css'
5
5
  import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
6
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
6
7
 
7
8
  export const styles = css.create({
8
9
  base: {
@@ -46,7 +47,7 @@ export const styles = css.create({
46
47
  default: 'transparent',
47
48
  ':hover': colors.bgCardHover,
48
49
  },
49
- borderWidth: 1,
50
+ borderWidth: borders.hairline,
50
51
  borderStyle: 'solid',
51
52
  borderColor: colors.border,
52
53
  color: colors.textMuted,
@@ -8,6 +8,8 @@ import {Button} from '../Button/Button'
8
8
  import {Checkbox} from '../Checkbox/Checkbox'
9
9
  import {colors} from '@duro-app/tokens/tokens/colors.css'
10
10
  import {radii} from '@duro-app/tokens/tokens/spacing.css'
11
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
12
+ import {sizes} from '@duro-app/tokens/tokens/sizes.css'
11
13
 
12
14
  const meta: Meta = {
13
15
  title: 'Components/List',
@@ -73,8 +75,8 @@ export const Default: Story = {
73
75
 
74
76
  const narrowContainer = css.create({
75
77
  box: {
76
- maxWidth: 360,
77
- borderWidth: 1,
78
+ maxWidth: sizes.panelSm,
79
+ borderWidth: borders.hairline,
78
80
  borderStyle: 'solid',
79
81
  borderColor: colors.border,
80
82
  borderRadius: radii.sm,
@@ -1,7 +1,9 @@
1
1
  import {css} from 'react-strict-dom'
2
2
  import {colors} from '@duro-app/tokens/tokens/colors.css'
3
- import {spacing} from '@duro-app/tokens/tokens/spacing.css'
3
+ import {microSpacing, spacing} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {typography} from '@duro-app/tokens/tokens/typography.css'
5
+ import {duration} from '@duro-app/tokens/tokens/motion.css'
6
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
5
7
 
6
8
  export const styles = css.create({
7
9
  // --- Root ---
@@ -21,7 +23,7 @@ export const styles = css.create({
21
23
  paddingBottom: spacing.sm,
22
24
  paddingLeft: spacing.ms,
23
25
  paddingRight: spacing.ms,
24
- borderBottomWidth: 1,
26
+ borderBottomWidth: borders.hairline,
25
27
  borderBottomStyle: 'solid',
26
28
  borderBottomColor: colors.border,
27
29
  backgroundColor: {
@@ -29,7 +31,7 @@ export const styles = css.create({
29
31
  ':hover': colors.bgCardHover,
30
32
  },
31
33
  transitionProperty: 'background-color',
32
- transitionDuration: '120ms',
34
+ transitionDuration: duration.quick,
33
35
  cursor: 'default',
34
36
  },
35
37
  itemSelected: {
@@ -51,7 +53,7 @@ export const styles = css.create({
51
53
  flex: 1,
52
54
  display: 'flex',
53
55
  flexDirection: 'column',
54
- gap: 2,
56
+ gap: microSpacing.px2,
55
57
  minWidth: 0,
56
58
  },
57
59
 
@@ -4,6 +4,8 @@ import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {typography} from '@duro-app/tokens/tokens/typography.css'
5
5
  import {shadows} from '@duro-app/tokens/tokens/shadows.css'
6
6
  import {duration} from '@duro-app/tokens/tokens/motion.css'
7
+ import {sizes} from '@duro-app/tokens/tokens/sizes.css'
8
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
7
9
 
8
10
  export const styles = css.create({
9
11
  root: {
@@ -25,7 +27,7 @@ export const styles = css.create({
25
27
  default: 'transparent',
26
28
  ':hover': colors.bgCardHover,
27
29
  },
28
- borderWidth: 1,
30
+ borderWidth: borders.hairline,
29
31
  borderStyle: 'solid',
30
32
  borderColor: colors.border,
31
33
  borderRadius: radii.sm,
@@ -47,14 +49,14 @@ export const styles = css.create({
47
49
  left: 0,
48
50
  marginTop: spacing.xs,
49
51
  backgroundColor: colors.bgCard,
50
- borderWidth: 1,
52
+ borderWidth: borders.hairline,
51
53
  borderStyle: 'solid',
52
54
  borderColor: colors.border,
53
55
  borderRadius: radii.sm,
54
56
  boxShadow: shadows.md,
55
57
  paddingTop: spacing.xs,
56
58
  paddingBottom: spacing.xs,
57
- minWidth: 160,
59
+ minWidth: sizes.popupMinW,
58
60
  zIndex: 50,
59
61
  },
60
62
  popupEnd: {
@@ -84,7 +86,7 @@ export const styles = css.create({
84
86
  height: 0,
85
87
  marginTop: spacing.xs,
86
88
  marginBottom: spacing.xs,
87
- borderTopWidth: 1,
89
+ borderTopWidth: borders.hairline,
88
90
  borderTopStyle: 'solid',
89
91
  borderTopColor: colors.border,
90
92
  },
@@ -109,7 +109,11 @@ export function useMenuRoot() {
109
109
  })
110
110
  break
111
111
  }
112
- case 'Escape':
112
+ case 'Escape': {
113
+ e.preventDefault()
114
+ close()
115
+ break
116
+ }
113
117
  case 'Tab': {
114
118
  close()
115
119
  break
@@ -1,6 +1,7 @@
1
1
  import {css} from 'react-strict-dom'
2
2
  import {layoutSpacing} from '@duro-app/tokens/tokens/layout-spacing.css'
3
3
  import {spacing} from '@duro-app/tokens/tokens/spacing.css'
4
+ import {sizes} from '@duro-app/tokens/tokens/sizes.css'
4
5
 
5
6
  export const styles = css.create({
6
7
  root: {
@@ -12,9 +13,9 @@ export const styles = css.create({
12
13
  marginRight: 'auto',
13
14
  },
14
15
  // Max-width presets
15
- maxSm: {maxWidth: 600},
16
- maxMd: {maxWidth: 800},
17
- maxLg: {maxWidth: 1200},
16
+ maxSm: {maxWidth: sizes.pageSm},
17
+ maxMd: {maxWidth: sizes.pageMd},
18
+ maxLg: {maxWidth: sizes.pageLg},
18
19
  // Horizontal padding
19
20
  padSm: {paddingLeft: layoutSpacing.containerSm, paddingRight: layoutSpacing.containerSm},
20
21
  padMd: {paddingLeft: layoutSpacing.containerMd, paddingRight: layoutSpacing.containerMd},
@@ -1,6 +1,7 @@
1
1
  import {css} from 'react-strict-dom'
2
2
  import {colors} from '@duro-app/tokens/tokens/colors.css'
3
3
  import {spacing} from '@duro-app/tokens/tokens/spacing.css'
4
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
4
5
 
5
6
  export const styles = css.create({
6
7
  root: {
@@ -9,7 +10,7 @@ export const styles = css.create({
9
10
  backgroundColor: colors.bgCard,
10
11
  },
11
12
  bordered: {
12
- borderWidth: 1,
13
+ borderWidth: borders.hairline,
13
14
  borderStyle: 'solid',
14
15
  borderColor: colors.border,
15
16
  },
@@ -23,7 +24,7 @@ export const styles = css.create({
23
24
  paddingRight: spacing.lg,
24
25
  paddingBottom: spacing.lg,
25
26
  gap: spacing.md,
26
- borderBottomWidth: 1,
27
+ borderBottomWidth: borders.hairline,
27
28
  borderBottomStyle: 'solid',
28
29
  borderBottomColor: colors.border,
29
30
  },
@@ -53,7 +54,7 @@ export const styles = css.create({
53
54
  paddingBottom: spacing.md,
54
55
  paddingLeft: spacing.lg,
55
56
  paddingRight: spacing.lg,
56
- borderTopWidth: 1,
57
+ borderTopWidth: borders.hairline,
57
58
  borderTopStyle: 'solid',
58
59
  borderTopColor: colors.border,
59
60
  },
@@ -6,6 +6,7 @@ export const meta: ComponentMeta = {
6
6
  whenToUse: [
7
7
  'A small form or controls tied to one element that stay open while you work in them',
8
8
  'Anchoring to a spot that is not a button (a canvas point, a text selection) with a virtual anchor',
9
+ 'Holding a Select or Combobox: their portalled list counts as inside the popover, so choosing an item keeps it open; Escape closes an open Select, Combobox or Menu before the popover',
9
10
  ],
10
11
  whenNotToUse: [
11
12
  'A list of actions — use Menu',
@@ -47,6 +48,12 @@ export const meta: ComponentMeta = {
47
48
  relationship:
48
49
  'Drawer is the modal edge panel for phone width; Popover is anchored and non-modal',
49
50
  },
51
+ {
52
+ component: 'Select',
53
+ kind: 'composition',
54
+ relationship:
55
+ 'A Select or Combobox inside Popover.Popup keeps the popover open while you choose; a Select backdrop press closes only its list',
56
+ },
50
57
  {
51
58
  component: 'Field',
52
59
  kind: 'composition',
@@ -10,6 +10,8 @@ import {Field} from '../Field/Field'
10
10
  import {Input} from '../Input/Input'
11
11
  import {Select} from '../Select/Select'
12
12
  import {Stack} from '../Stack/Stack'
13
+ import {borders} from '@duro-app/tokens/tokens/borders.css'
14
+ import {sizes} from '@duro-app/tokens/tokens/sizes.css'
13
15
 
14
16
  const meta: Meta = {
15
17
  title: 'Components/Popover',
@@ -24,8 +26,8 @@ const page = () => within(document.body)
24
26
  const styles = css.create({
25
27
  stage: {
26
28
  position: 'relative',
27
- height: 320,
28
- borderWidth: 1,
29
+ height: sizes.panelSm,
30
+ borderWidth: borders.hairline,
29
31
  borderStyle: 'dashed',
30
32
  borderColor: colors.border,
31
33
  padding: spacing.md,
@@ -34,9 +36,9 @@ const styles = css.create({
34
36
  position: 'absolute',
35
37
  top: 120,
36
38
  left: 160,
37
- width: 120,
39
+ width: sizes.labelMinW,
38
40
  padding: spacing.sm,
39
- borderWidth: 1,
41
+ borderWidth: borders.hairline,
40
42
  borderStyle: 'solid',
41
43
  borderColor: colors.accent,
42
44
  },
@@ -8,6 +8,7 @@ import {
8
8
  useId,
9
9
  useImperativeHandle,
10
10
  useLayoutEffect,
11
+ useMemo,
11
12
  useRef,
12
13
  useState,
13
14
  } from 'react'
@@ -17,6 +18,7 @@ import {usePortalMount} from '../ThemeProvider/ThemeProvider'
17
18
  import {styles} from './styles.css'
18
19
  import {computePopoverPosition, type PopoverAlign, type PopoverSide} from './position'
19
20
  import {isOutsidePress} from './outside'
21
+ import {PopoverLayerContext, type PopoverLayerContextValue} from './PopoverLayerContext'
20
22
 
21
23
  // --- Context ---
22
24
 
@@ -47,27 +49,6 @@ const FOCUSABLE =
47
49
 
48
50
  const OFFSET = 4 // `xs` token
49
51
 
50
- /**
51
- * Whether a nested popup control owns this Escape: a Select, Menu or
52
- * Combobox inside the popup closes on Esc without preventing default, and
53
- * that Esc must close only it. Only controls that open a popup count — an
54
- * expanded trigger that declares one (`aria-haspopup`), an expanded combobox,
55
- * or focus inside a listbox or menu — never a plain disclosure, and never
56
- * this popover's own Trigger.
57
- *
58
- * holds-until: Duro's Select, Menu and Combobox call preventDefault on the
59
- * Escape they consume; the defaultPrevented check alone then suffices and
60
- * this selector goes.
61
- */
62
- const NESTED_POPUP_OWNER =
63
- '[aria-expanded="true"][aria-haspopup], [role="combobox"][aria-expanded="true"], [role="listbox"], [role="menu"]'
64
-
65
- function nestedOwnsEscape(target: EventTarget | null, ownTrigger: Element | null): boolean {
66
- if (!(target instanceof Element)) return false
67
- const owner = target.closest(NESTED_POPUP_OWNER)
68
- return owner !== null && owner !== ownTrigger
69
- }
70
-
71
52
  // --- Root ---
72
53
 
73
54
  export interface PopoverHandle {
@@ -148,7 +129,6 @@ function Root({
148
129
 
149
130
  function onKeyDown(e: KeyboardEvent) {
150
131
  if (e.key !== 'Escape' || e.defaultPrevented) return
151
- if (nestedOwnsEscape(e.target, triggerRef.current)) return
152
132
  e.preventDefault()
153
133
  setOpen(false)
154
134
  }
@@ -157,7 +137,7 @@ function Root({
157
137
  const ignored = (ignoreRef.current ?? []).map((entry) =>
158
138
  typeof entry === 'function' ? entry() : entry,
159
139
  )
160
- const inside = [popupRef.current, triggerRef.current, ...ignored]
140
+ const inside = [popupRef.current, triggerRef.current, ...ignored, ...layersRef.current]
161
141
  if (isOutsidePress(e.target as Node | null, inside)) setOpen(false)
162
142
  }
163
143
 
@@ -169,6 +149,28 @@ function Root({
169
149
  }
170
150
  }, [open, setOpen])
171
151
 
152
+ const layersRef = useRef(new Set<Element>())
153
+ // A nested Popover's layers are inside its parent too.
154
+ const parentLayer = useContext(PopoverLayerContext)
155
+ const layerCtx = useMemo<PopoverLayerContextValue>(
156
+ () => ({
157
+ register: (el) => {
158
+ layersRef.current.add(el)
159
+ const unregisterParent = parentLayer?.register(el)
160
+ return () => {
161
+ layersRef.current.delete(el)
162
+ unregisterParent?.()
163
+ }
164
+ },
165
+ }),
166
+ [parentLayer],
167
+ )
168
+ useLayoutEffect(() => {
169
+ const popup = popupRef.current
170
+ if (!open || !popup) return
171
+ return parentLayer?.register(popup)
172
+ }, [open, parentLayer])
173
+
172
174
  const ctx: PopoverContextValue = {
173
175
  open,
174
176
  setOpen,
@@ -181,7 +183,11 @@ function Root({
181
183
  repositionRef,
182
184
  }
183
185
 
184
- return <PopoverContext.Provider value={ctx}>{children}</PopoverContext.Provider>
186
+ return (
187
+ <PopoverContext.Provider value={ctx}>
188
+ <PopoverLayerContext.Provider value={layerCtx}>{children}</PopoverLayerContext.Provider>
189
+ </PopoverContext.Provider>
190
+ )
185
191
  }
186
192
 
187
193
  // --- Trigger ---
@@ -0,0 +1,20 @@
1
+ import {type RefObject, createContext, useContext, useLayoutEffect} from 'react'
2
+
3
+ // A Popover's nested popups (a Select listbox, a Combobox listbox, a child
4
+ // Popover) are portalled out of its DOM subtree. They register here so a press
5
+ // on them counts as inside the Popover.
6
+ export interface PopoverLayerContextValue {
7
+ register: (el: Element) => () => void
8
+ }
9
+
10
+ export const PopoverLayerContext = createContext<PopoverLayerContextValue | null>(null)
11
+
12
+ /** Register the ref's element as part of the enclosing Popover's layer while `active`. */
13
+ export function usePopoverLayer(ref: RefObject<Element | null>, {active}: {active: boolean}) {
14
+ const layer = useContext(PopoverLayerContext)
15
+ useLayoutEffect(() => {
16
+ const el = ref.current
17
+ if (!layer || !active || !el) return
18
+ return layer.register(el)
19
+ }, [layer, active, ref])
20
+ }