@duro-app/ui 5.0.0 → 5.2.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 (139) hide show
  1. package/dist/Table-C70zdSkM.js +1419 -0
  2. package/dist/Table-C70zdSkM.js.map +1 -0
  3. package/dist/components/Button/Button.d.ts +11 -2
  4. package/dist/components/Button/Button.d.ts.map +1 -1
  5. package/dist/components/Button/Button.stories.d.ts +1 -0
  6. package/dist/components/Button/Button.stories.d.ts.map +1 -1
  7. package/dist/components/Card/Card.stories.d.ts.map +1 -1
  8. package/dist/components/Combobox/Combobox.d.ts +1 -1
  9. package/dist/components/Combobox/Combobox.d.ts.map +1 -1
  10. package/dist/components/Combobox/styles.css.d.ts +0 -64
  11. package/dist/components/Combobox/styles.css.d.ts.map +1 -1
  12. package/dist/components/Dialog/Dialog.d.ts +11 -3
  13. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  14. package/dist/components/Dialog/Dialog.stories.d.ts +4 -0
  15. package/dist/components/Dialog/Dialog.stories.d.ts.map +1 -1
  16. package/dist/components/Dialog/styles.css.d.ts +1 -0
  17. package/dist/components/Dialog/styles.css.d.ts.map +1 -1
  18. package/dist/components/DragDrop/styles.css.d.ts +10 -2
  19. package/dist/components/DragDrop/styles.css.d.ts.map +1 -1
  20. package/dist/components/Grid/Grid.d.ts +11 -2
  21. package/dist/components/Grid/Grid.d.ts.map +1 -1
  22. package/dist/components/Grid/Grid.stories.d.ts +2 -0
  23. package/dist/components/Grid/Grid.stories.d.ts.map +1 -1
  24. package/dist/components/Grid/styles.css.d.ts +2 -2
  25. package/dist/components/Grid/styles.css.d.ts.map +1 -1
  26. package/dist/components/Input/Input.d.ts +6 -1
  27. package/dist/components/Input/Input.d.ts.map +1 -1
  28. package/dist/components/Input/Input.meta.d.ts.map +1 -1
  29. package/dist/components/Input/Input.stories.d.ts +1 -0
  30. package/dist/components/Input/Input.stories.d.ts.map +1 -1
  31. package/dist/components/Input/styles.css.d.ts +18 -0
  32. package/dist/components/Input/styles.css.d.ts.map +1 -1
  33. package/dist/components/InputGroup/InputGroup.d.ts +6 -1
  34. package/dist/components/InputGroup/InputGroup.d.ts.map +1 -1
  35. package/dist/components/InputGroup/InputGroup.stories.d.ts +1 -0
  36. package/dist/components/InputGroup/InputGroup.stories.d.ts.map +1 -1
  37. package/dist/components/Listbox/Listbox.d.ts +75 -0
  38. package/dist/components/Listbox/Listbox.d.ts.map +1 -0
  39. package/dist/components/Listbox/Listbox.meta.d.ts +3 -0
  40. package/dist/components/Listbox/Listbox.meta.d.ts.map +1 -0
  41. package/dist/components/Listbox/Listbox.stories.d.ts +7 -0
  42. package/dist/components/Listbox/Listbox.stories.d.ts.map +1 -0
  43. package/dist/components/Listbox/styles.css.d.ts +75 -0
  44. package/dist/components/Listbox/styles.css.d.ts.map +1 -0
  45. package/dist/components/Menu/Menu.d.ts +18 -5
  46. package/dist/components/Menu/Menu.d.ts.map +1 -1
  47. package/dist/components/Menu/Menu.meta.d.ts.map +1 -1
  48. package/dist/components/Menu/Menu.stories.d.ts +7 -0
  49. package/dist/components/Menu/Menu.stories.d.ts.map +1 -1
  50. package/dist/components/Menu/MenuContext.d.ts +3 -0
  51. package/dist/components/Menu/MenuContext.d.ts.map +1 -1
  52. package/dist/components/Menu/styles.css.d.ts +24 -15
  53. package/dist/components/Menu/styles.css.d.ts.map +1 -1
  54. package/dist/components/Menu/useMenuRoot.d.ts +14 -1
  55. package/dist/components/Menu/useMenuRoot.d.ts.map +1 -1
  56. package/dist/components/StatusIcon/StatusIcon.stories.d.ts.map +1 -1
  57. package/dist/components/Table/Table.stories.d.ts +1 -0
  58. package/dist/components/Table/Table.stories.d.ts.map +1 -1
  59. package/dist/components/TextLink/TextLink.d.ts +24 -0
  60. package/dist/components/TextLink/TextLink.d.ts.map +1 -0
  61. package/dist/components/TextLink/TextLink.meta.d.ts +3 -0
  62. package/dist/components/TextLink/TextLink.meta.d.ts.map +1 -0
  63. package/dist/components/TextLink/TextLink.stories.d.ts +9 -0
  64. package/dist/components/TextLink/TextLink.stories.d.ts.map +1 -0
  65. package/dist/components/TextLink/styles.css.d.ts +28 -0
  66. package/dist/components/TextLink/styles.css.d.ts.map +1 -0
  67. package/dist/components/ThemeProvider/ThemeProvider.stories.d.ts +1 -0
  68. package/dist/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
  69. package/dist/components/VisuallyHidden/VisuallyHidden.d.ts +14 -0
  70. package/dist/components/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  71. package/dist/components/VisuallyHidden/VisuallyHidden.meta.d.ts +3 -0
  72. package/dist/components/VisuallyHidden/VisuallyHidden.meta.d.ts.map +1 -0
  73. package/dist/components/VisuallyHidden/VisuallyHidden.stories.d.ts +7 -0
  74. package/dist/components/VisuallyHidden/VisuallyHidden.stories.d.ts.map +1 -0
  75. package/dist/docs/FlexGrow.stories.d.ts +7 -0
  76. package/dist/docs/FlexGrow.stories.d.ts.map +1 -0
  77. package/dist/index.css +1 -1
  78. package/dist/index.d.ts +5 -0
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +2986 -2821
  81. package/dist/index.js.map +1 -1
  82. package/dist/index.native.d.ts +1 -0
  83. package/dist/index.native.d.ts.map +1 -1
  84. package/dist/shared/length.d.ts +14 -9
  85. package/dist/shared/length.d.ts.map +1 -1
  86. package/dist/shared/length.typecheck.d.ts +3 -0
  87. package/dist/shared/length.typecheck.d.ts.map +1 -1
  88. package/dist/styles/visually-hidden.css.d.ts +6 -0
  89. package/dist/styles/visually-hidden.css.d.ts.map +1 -1
  90. package/dist/table.js +1 -1
  91. package/package.json +2 -2
  92. package/src/components/Button/Button.stories.tsx +41 -0
  93. package/src/components/Button/Button.tsx +16 -1
  94. package/src/components/Card/Card.stories.tsx +2 -1
  95. package/src/components/Combobox/Combobox.tsx +25 -79
  96. package/src/components/Combobox/styles.css.ts +0 -74
  97. package/src/components/Dialog/Dialog.meta.ts +1 -1
  98. package/src/components/Dialog/Dialog.stories.tsx +109 -3
  99. package/src/components/Dialog/Dialog.tsx +63 -9
  100. package/src/components/Dialog/styles.css.ts +2 -0
  101. package/src/components/DragDrop/styles.css.ts +16 -3
  102. package/src/components/Grid/Grid.meta.ts +1 -1
  103. package/src/components/Grid/Grid.stories.tsx +53 -1
  104. package/src/components/Grid/Grid.tsx +23 -11
  105. package/src/components/Grid/styles.css.ts +3 -2
  106. package/src/components/Input/Input.meta.ts +10 -3
  107. package/src/components/Input/Input.stories.tsx +52 -2
  108. package/src/components/Input/Input.tsx +12 -3
  109. package/src/components/Input/styles.css.ts +29 -0
  110. package/src/components/InputGroup/InputGroup.stories.tsx +20 -0
  111. package/src/components/InputGroup/InputGroup.tsx +20 -2
  112. package/src/components/Listbox/Listbox.meta.ts +52 -0
  113. package/src/components/Listbox/Listbox.stories.tsx +170 -0
  114. package/src/components/Listbox/Listbox.tsx +278 -0
  115. package/src/components/Listbox/styles.css.ts +89 -0
  116. package/src/components/Menu/Menu.meta.ts +2 -1
  117. package/src/components/Menu/Menu.stories.tsx +289 -8
  118. package/src/components/Menu/Menu.tsx +100 -29
  119. package/src/components/Menu/MenuContext.ts +3 -0
  120. package/src/components/Menu/styles.css.ts +31 -15
  121. package/src/components/Menu/useMenuRoot.ts +105 -48
  122. package/src/components/StatusIcon/StatusIcon.stories.tsx +2 -2
  123. package/src/components/Table/Table.stories.tsx +39 -0
  124. package/src/components/TextLink/TextLink.meta.ts +33 -0
  125. package/src/components/TextLink/TextLink.stories.tsx +63 -0
  126. package/src/components/TextLink/TextLink.tsx +46 -0
  127. package/src/components/TextLink/styles.css.ts +58 -0
  128. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +50 -0
  129. package/src/components/VisuallyHidden/VisuallyHidden.meta.ts +19 -0
  130. package/src/components/VisuallyHidden/VisuallyHidden.stories.tsx +30 -0
  131. package/src/components/VisuallyHidden/VisuallyHidden.tsx +22 -0
  132. package/src/docs/FlexGrow.stories.tsx +83 -0
  133. package/src/index.native.ts +1 -0
  134. package/src/index.ts +5 -0
  135. package/src/shared/length.ts +29 -10
  136. package/src/shared/length.typecheck.tsx +9 -0
  137. package/src/styles/visually-hidden.css.ts +8 -0
  138. package/dist/Table-BKN_d-mp.js +0 -1192
  139. package/dist/Table-BKN_d-mp.js.map +0 -1
@@ -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
@@ -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'
@@ -99,6 +103,7 @@ export {Stack, type SpacingKey} from './components/Stack/Stack'
99
103
  export {Inline} from './components/Inline/Inline'
100
104
  export {Cluster} from './components/Cluster/Cluster'
101
105
  export {Grid} from './components/Grid/Grid'
106
+ export type {GridTrack} from './shared/length'
102
107
  export {PageShell, type PageShellMaxWidth, type PageShellPadding} from './components/PageShell'
103
108
 
104
109
  // Hooks
@@ -27,16 +27,23 @@ export type RelativeLength =
27
27
  /** A measure prop: a `sizes` token key (`"gridColMd"`) or a relative length. */
28
28
  export type Length = SizeToken | RelativeLength
29
29
 
30
+ /** A Length written as a string, as it appears inside a track function. */
31
+ type LengthString = Exclude<Length, number>
32
+
33
+ /** One argument of `minmax()`: a Length or a fraction. */
34
+ type TrackBreadth = LengthString | `${number}fr`
35
+
30
36
  /**
31
- * A CSS grid track: a Length, a fraction, or a track function. The arguments
32
- * of `minmax()` / `fit-content()` are not checked by the type — pass tokens
33
- * through `resolveLength` or `sizes.*` when building one.
34
- *
35
- * holds-until: a structured track type (`{min: Length, max: GridTrack}`)
36
- * replaces the template-literal functions; a type cannot see inside
37
- * `minmax(${string})`, so a px there is the one measure lint and types miss.
37
+ * A CSS grid track: a Length, a fraction, or a track function whose
38
+ * arguments are themselves Lengths or fractions — `'minmax(gridColSm, 1fr)'`,
39
+ * `'minmax(0, 2fr)'`, `'fit-content(labelMinW)'`. A px inside is a type
40
+ * error, as it is anywhere else. Arguments are separated by `, `.
38
41
  */
39
- export type GridTrack = Length | `${number}fr` | `minmax(${string})` | `fit-content(${string})`
42
+ export type GridTrack =
43
+ | Length
44
+ | `${number}fr`
45
+ | `minmax(${TrackBreadth}, ${TrackBreadth})`
46
+ | `fit-content(${LengthString})`
40
47
 
41
48
  const sizeKeys: ReadonlySet<string> = new Set(SIZE_KEYS)
42
49
 
@@ -45,7 +52,19 @@ export function resolveLength(value: Length): string | number {
45
52
  return typeof value === 'string' && sizeKeys.has(value) ? sizes[value as SizeToken] : value
46
53
  }
47
54
 
48
- /** The CSS value for a GridTrack: a size token key becomes its variable. */
55
+ /**
56
+ * The CSS value for a GridTrack: a size token key becomes its variable, also
57
+ * as an argument of `minmax()` / `fit-content()`.
58
+ */
49
59
  export function resolveTrack(track: GridTrack): string | number {
50
- return typeof track === 'string' && sizeKeys.has(track) ? sizes[track as SizeToken] : track
60
+ // Read as a plain value: narrowing the template-literal union is more than
61
+ // the checker will represent (TS2590), and the callers only need the CSS.
62
+ const value: string | number = track
63
+ if (typeof value !== 'string') return value
64
+ const fn = /^(minmax|fit-content)\((.*)\)$/.exec(value)
65
+ if (fn) {
66
+ const args = fn[2]!.split(',').map((arg) => String(resolveLength(arg.trim() as Length)))
67
+ return `${fn[1]}(${args.join(', ')})`
68
+ }
69
+ return sizeKeys.has(value) ? sizes[value as SizeToken] : value
51
70
  }
@@ -28,6 +28,15 @@ export const trackForms: Assignable<
28
28
  export const lengthPxString: Assignable<'280px', Length> = false
29
29
  export const lengthPxNumber: Assignable<44, Length> = false
30
30
  export const trackPx: Assignable<'40px', GridTrack> = false
31
+ export const trackMinmaxPx: Assignable<'minmax(40px, 1fr)', GridTrack> = false
32
+ export const trackFitPx: Assignable<'fit-content(120px)', GridTrack> = false
33
+ export const trackMinmaxTokens: Assignable<
34
+ | 'minmax(gridColSm, 1fr)'
35
+ | 'minmax(0, 2fr)'
36
+ | 'minmax(labelMinW, auto)'
37
+ | 'fit-content(labelMinW)',
38
+ GridTrack
39
+ > = true
31
40
 
32
41
  // The props themselves.
33
42
  export const gridMin: Assignable<'280px', Prop<typeof Grid, 'minColumnWidth'>> = false
@@ -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
  })