@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.
- package/dist/{Table-JTgcR_Fh.js → Table-BKN_d-mp.js} +506 -410
- package/dist/Table-BKN_d-mp.js.map +1 -0
- package/dist/components/ActionBar/ActionBar.stories.d.ts.map +1 -1
- package/dist/components/ActionBar/styles.css.d.ts +7 -7
- package/dist/components/ActionBar/styles.css.d.ts.map +1 -1
- package/dist/components/Alert/styles.css.d.ts +2 -2
- package/dist/components/Alert/styles.css.d.ts.map +1 -1
- package/dist/components/Badge/styles.css.d.ts +2 -2
- package/dist/components/Button/styles.css.d.ts +5 -5
- package/dist/components/Button/styles.css.d.ts.map +1 -1
- package/dist/components/Callout/styles.css.d.ts +1 -1
- package/dist/components/Callout/styles.css.d.ts.map +1 -1
- package/dist/components/Card/styles.css.d.ts +3 -3
- package/dist/components/Card/styles.css.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/styles.css.d.ts +7 -11
- package/dist/components/Checkbox/styles.css.d.ts.map +1 -1
- package/dist/components/Cluster/Cluster.stories.d.ts.map +1 -1
- package/dist/components/ColorInput/styles.css.d.ts +6 -6
- package/dist/components/ColorInput/styles.css.d.ts.map +1 -1
- package/dist/components/ColorMode/styles.css.d.ts +3 -3
- package/dist/components/ColorMode/styles.css.d.ts.map +1 -1
- package/dist/components/Combobox/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox/Combobox.meta.d.ts.map +1 -1
- package/dist/components/Combobox/styles.css.d.ts +3 -3
- package/dist/components/Combobox/styles.css.d.ts.map +1 -1
- package/dist/components/DetailPanel/DetailPanel.d.ts.map +1 -1
- package/dist/components/DetailPanel/DetailPanel.stories.d.ts.map +1 -1
- package/dist/components/DetailPanel/styles.css.d.ts +19 -10
- package/dist/components/DetailPanel/styles.css.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.stories.d.ts.map +1 -1
- package/dist/components/Dialog/styles.css.d.ts +18 -9
- package/dist/components/Dialog/styles.css.d.ts.map +1 -1
- package/dist/components/DragDrop/DragDrop.d.ts.map +1 -1
- package/dist/components/DragDrop/DragDrop.stories.d.ts.map +1 -1
- package/dist/components/DragDrop/styles.css.d.ts +0 -6
- package/dist/components/DragDrop/styles.css.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.d.ts.map +1 -1
- package/dist/components/Drawer/DrawerScroll.stories.d.ts +13 -0
- package/dist/components/Drawer/DrawerScroll.stories.d.ts.map +1 -0
- package/dist/components/Drawer/styles.css.d.ts +19 -10
- package/dist/components/Drawer/styles.css.d.ts.map +1 -1
- package/dist/components/Drawer/useSwipeDismiss.d.ts +7 -2
- package/dist/components/Drawer/useSwipeDismiss.d.ts.map +1 -1
- package/dist/components/Field/Field.stories.d.ts.map +1 -1
- package/dist/components/Field/styles.css.d.ts +1 -1
- package/dist/components/Field/styles.css.d.ts.map +1 -1
- package/dist/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/components/Grid/Grid.d.ts +6 -4
- package/dist/components/Grid/Grid.d.ts.map +1 -1
- package/dist/components/Grid/Grid.stories.d.ts.map +1 -1
- package/dist/components/Grid/styles.css.d.ts +3 -3
- package/dist/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/components/Input/styles.css.d.ts +3 -3
- package/dist/components/Input/styles.css.d.ts.map +1 -1
- package/dist/components/InputGroup/InputGroup.d.ts +4 -2
- package/dist/components/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/components/InputGroup/InputGroup.stories.d.ts.map +1 -1
- package/dist/components/InputGroup/styles.css.d.ts +3 -3
- package/dist/components/InputGroup/styles.css.d.ts.map +1 -1
- package/dist/components/LinkButton/styles.css.d.ts +1 -1
- package/dist/components/LinkButton/styles.css.d.ts.map +1 -1
- package/dist/components/List/List.stories.d.ts.map +1 -1
- package/dist/components/List/styles.css.d.ts +3 -3
- package/dist/components/List/styles.css.d.ts.map +1 -1
- package/dist/components/Menu/styles.css.d.ts +4 -4
- package/dist/components/Menu/styles.css.d.ts.map +1 -1
- package/dist/components/Menu/useMenuRoot.d.ts.map +1 -1
- package/dist/components/PageShell/styles.css.d.ts +3 -3
- package/dist/components/PageShell/styles.css.d.ts.map +1 -1
- package/dist/components/Panel/styles.css.d.ts +3 -3
- package/dist/components/Panel/styles.css.d.ts.map +1 -1
- package/dist/components/Popover/Popover.d.ts.map +1 -1
- package/dist/components/Popover/Popover.meta.d.ts.map +1 -1
- package/dist/components/Popover/Popover.stories.d.ts.map +1 -1
- package/dist/components/Popover/PopoverLayerContext.d.ts +10 -0
- package/dist/components/Popover/PopoverLayerContext.d.ts.map +1 -0
- package/dist/components/Popover/PopoverLayers.stories.d.ts +13 -0
- package/dist/components/Popover/PopoverLayers.stories.d.ts.map +1 -0
- package/dist/components/Popover/styles.css.d.ts +2 -2
- package/dist/components/Popover/styles.css.d.ts.map +1 -1
- package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -1
- package/dist/components/RadioGroup/styles.css.d.ts +5 -9
- package/dist/components/RadioGroup/styles.css.d.ts.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.d.ts +10 -3
- package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
- package/dist/components/ScrollArea/styles.css.d.ts +8 -8
- package/dist/components/ScrollArea/styles.css.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.meta.d.ts.map +1 -1
- package/dist/components/Select/styles.css.d.ts +4 -4
- package/dist/components/Select/styles.css.d.ts.map +1 -1
- package/dist/components/Select/useSelectRoot.d.ts.map +1 -1
- package/dist/components/SideNav/styles.css.d.ts +7 -7
- package/dist/components/SideNav/styles.css.d.ts.map +1 -1
- package/dist/components/Spinner/Spinner.d.ts.map +1 -1
- package/dist/components/Spinner/styles.css.d.ts +10 -14
- package/dist/components/Spinner/styles.css.d.ts.map +1 -1
- package/dist/components/Switch/Switch.d.ts.map +1 -1
- package/dist/components/Switch/styles.css.d.ts +10 -14
- package/dist/components/Switch/styles.css.d.ts.map +1 -1
- package/dist/components/Table/ColumnFilter.d.ts.map +1 -1
- package/dist/components/Table/FromTanstack.d.ts +2 -1
- package/dist/components/Table/FromTanstack.d.ts.map +1 -1
- package/dist/components/Table/Pagination.d.ts.map +1 -1
- package/dist/components/Table/SortIndicator.d.ts.map +1 -1
- package/dist/components/Table/Table.d.ts +11 -9
- package/dist/components/Table/Table.d.ts.map +1 -1
- package/dist/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/components/Table/styles.css.d.ts +6 -6
- package/dist/components/Table/styles.css.d.ts.map +1 -1
- package/dist/components/Tabs/styles.css.d.ts +8 -8
- package/dist/components/Tabs/styles.css.d.ts.map +1 -1
- package/dist/components/Tag/Tag.stories.d.ts.map +1 -1
- package/dist/components/Tag/styles.css.d.ts +4 -4
- package/dist/components/Tag/styles.css.d.ts.map +1 -1
- package/dist/components/TagGroup/TagGroup.d.ts.map +1 -1
- package/dist/components/TagGroup/styles.css.d.ts +4 -10
- package/dist/components/TagGroup/styles.css.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.stories.d.ts.map +1 -1
- package/dist/components/Textarea/styles.css.d.ts +3 -3
- package/dist/components/Textarea/styles.css.d.ts.map +1 -1
- package/dist/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
- package/dist/components/Toast/Toast.stories.d.ts.map +1 -1
- package/dist/components/Toast/styles.css.d.ts +12 -12
- package/dist/components/Toast/styles.css.d.ts.map +1 -1
- package/dist/components/Toggle/Toggle.d.ts.map +1 -1
- package/dist/components/Toggle/styles.css.d.ts +14 -4
- package/dist/components/Toggle/styles.css.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +7 -1
- package/dist/components/ToggleGroup/ToggleGroup.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.meta.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.stories.d.ts +4 -0
- package/dist/components/ToggleGroup/ToggleGroup.stories.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupContext.d.ts +6 -0
- package/dist/components/ToggleGroup/ToggleGroupContext.d.ts.map +1 -1
- package/dist/components/ToggleGroup/styles.css.d.ts +20 -1
- package/dist/components/ToggleGroup/styles.css.d.ts.map +1 -1
- package/dist/components/ToggleGroup/useRovingFocus.d.ts +17 -0
- package/dist/components/ToggleGroup/useRovingFocus.d.ts.map +1 -0
- package/dist/components/Tooltip/styles.css.d.ts +1 -1
- package/dist/components/Tooltip/styles.css.d.ts.map +1 -1
- package/dist/components/Tree/styles.css.d.ts +4 -4
- package/dist/components/Tree/styles.css.d.ts.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.d.ts +2 -1
- package/dist/components/VirtualTable/VirtualTable.d.ts.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.stories.d.ts.map +1 -1
- package/dist/components/VirtualTable/styles.css.d.ts +7 -7
- package/dist/components/VirtualTable/styles.css.d.ts.map +1 -1
- package/dist/docs/Spacing.stories.d.ts.map +1 -1
- package/dist/docs/Typography.stories.d.ts.map +1 -1
- package/dist/docs/helpers.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +3788 -3515
- package/dist/index.js.map +1 -1
- package/dist/shared/length.d.ts +24 -0
- package/dist/shared/length.d.ts.map +1 -0
- package/dist/shared/length.typecheck.d.ts +28 -0
- package/dist/shared/length.typecheck.d.ts.map +1 -0
- package/dist/styles/visually-hidden.css.d.ts +10 -0
- package/dist/styles/visually-hidden.css.d.ts.map +1 -0
- package/dist/table.js +166 -166
- package/dist/table.js.map +1 -1
- package/package.json +2 -2
- package/src/components/ActionBar/ActionBar.stories.tsx +4 -2
- package/src/components/ActionBar/styles.css.ts +11 -9
- package/src/components/Alert/styles.css.ts +4 -3
- package/src/components/Badge/styles.css.ts +3 -3
- package/src/components/Button/styles.css.ts +8 -7
- package/src/components/Callout/styles.css.ts +2 -1
- package/src/components/Card/styles.css.ts +4 -3
- package/src/components/Checkbox/Checkbox.tsx +2 -1
- package/src/components/Checkbox/styles.css.ts +10 -11
- package/src/components/Cluster/Cluster.stories.tsx +2 -1
- package/src/components/ColorInput/styles.css.ts +9 -7
- package/src/components/ColorMode/styles.css.ts +4 -3
- package/src/components/Combobox/Combobox.meta.ts +6 -0
- package/src/components/Combobox/Combobox.tsx +5 -0
- package/src/components/Combobox/styles.css.ts +5 -3
- package/src/components/DetailPanel/DetailPanel.stories.tsx +5 -3
- package/src/components/DetailPanel/DetailPanel.tsx +3 -0
- package/src/components/DetailPanel/styles.css.ts +17 -11
- package/src/components/Dialog/Dialog.stories.tsx +2 -1
- package/src/components/Dialog/Dialog.tsx +3 -0
- package/src/components/Dialog/styles.css.ts +14 -9
- package/src/components/DragDrop/DragDrop.stories.tsx +2 -1
- package/src/components/DragDrop/DragDrop.tsx +2 -1
- package/src/components/DragDrop/styles.css.ts +0 -7
- package/src/components/Drawer/Drawer.meta.ts +1 -1
- package/src/components/Drawer/Drawer.tsx +15 -2
- package/src/components/Drawer/DrawerScroll.stories.tsx +292 -0
- package/src/components/Drawer/styles.css.ts +15 -10
- package/src/components/Drawer/useSwipeDismiss.ts +53 -8
- package/src/components/Field/Field.stories.tsx +3 -2
- package/src/components/Field/styles.css.ts +2 -1
- package/src/components/Form/Form.stories.tsx +4 -3
- package/src/components/Grid/Grid.meta.ts +2 -2
- package/src/components/Grid/Grid.stories.tsx +3 -2
- package/src/components/Grid/Grid.tsx +8 -6
- package/src/components/Grid/styles.css.ts +2 -2
- package/src/components/Input/Input.stories.tsx +2 -1
- package/src/components/Input/styles.css.ts +4 -3
- package/src/components/InputGroup/InputGroup.stories.tsx +3 -2
- package/src/components/InputGroup/InputGroup.tsx +5 -3
- package/src/components/InputGroup/styles.css.ts +4 -3
- package/src/components/LinkButton/styles.css.ts +2 -1
- package/src/components/List/List.stories.tsx +4 -2
- package/src/components/List/styles.css.ts +6 -4
- package/src/components/Menu/styles.css.ts +6 -4
- package/src/components/Menu/useMenuRoot.ts +5 -1
- package/src/components/PageShell/styles.css.ts +4 -3
- package/src/components/Panel/styles.css.ts +4 -3
- package/src/components/Popover/Popover.meta.ts +7 -0
- package/src/components/Popover/Popover.stories.tsx +6 -4
- package/src/components/Popover/Popover.tsx +30 -24
- package/src/components/Popover/PopoverLayerContext.ts +20 -0
- package/src/components/Popover/PopoverLayers.stories.tsx +234 -0
- package/src/components/Popover/styles.css.ts +3 -2
- package/src/components/RadioGroup/RadioGroup.tsx +2 -1
- package/src/components/RadioGroup/styles.css.ts +8 -9
- package/src/components/ScrollArea/ScrollArea.meta.ts +2 -2
- package/src/components/ScrollArea/ScrollArea.stories.tsx +7 -5
- package/src/components/ScrollArea/ScrollArea.tsx +18 -7
- package/src/components/ScrollArea/styles.css.ts +10 -9
- package/src/components/Select/Select.meta.ts +6 -0
- package/src/components/Select/Select.tsx +8 -1
- package/src/components/Select/styles.css.ts +6 -4
- package/src/components/Select/useSelectRoot.ts +6 -2
- package/src/components/SideNav/styles.css.ts +10 -8
- package/src/components/Spinner/Spinner.tsx +2 -1
- package/src/components/Spinner/styles.css.ts +14 -14
- package/src/components/Switch/Switch.tsx +2 -1
- package/src/components/Switch/styles.css.ts +15 -15
- package/src/components/Table/ColumnFilter.tsx +5 -4
- package/src/components/Table/FromTanstack.tsx +2 -1
- package/src/components/Table/Pagination.tsx +6 -4
- package/src/components/Table/SortIndicator.tsx +4 -2
- package/src/components/Table/Table.stories.tsx +8 -8
- package/src/components/Table/Table.tsx +19 -15
- package/src/components/Table/styles.css.ts +9 -7
- package/src/components/Tabs/styles.css.ts +11 -9
- package/src/components/Tag/Tag.stories.tsx +4 -2
- package/src/components/Tag/styles.css.ts +6 -5
- package/src/components/TagGroup/TagGroup.tsx +2 -1
- package/src/components/TagGroup/styles.css.ts +6 -10
- package/src/components/Textarea/Textarea.stories.tsx +2 -1
- package/src/components/Textarea/styles.css.ts +4 -3
- package/src/components/ThemeProvider/ThemeProvider.stories.tsx +7 -5
- package/src/components/Toast/Toast.stories.tsx +2 -1
- package/src/components/Toast/styles.css.ts +16 -14
- package/src/components/Toggle/Toggle.meta.ts +1 -1
- package/src/components/Toggle/Toggle.tsx +19 -2
- package/src/components/Toggle/styles.css.ts +18 -4
- package/src/components/ToggleGroup/ToggleGroup.meta.ts +11 -1
- package/src/components/ToggleGroup/ToggleGroup.stories.tsx +157 -0
- package/src/components/ToggleGroup/ToggleGroup.tsx +87 -10
- package/src/components/ToggleGroup/ToggleGroupContext.ts +6 -0
- package/src/components/ToggleGroup/styles.css.ts +32 -2
- package/src/components/ToggleGroup/useRovingFocus.ts +121 -0
- package/src/components/Tooltip/styles.css.ts +2 -1
- package/src/components/Tree/styles.css.ts +8 -6
- package/src/components/VirtualTable/VirtualTable.stories.tsx +4 -3
- package/src/components/VirtualTable/VirtualTable.tsx +5 -3
- package/src/components/VirtualTable/styles.css.ts +9 -8
- package/src/docs/Spacing.stories.tsx +11 -10
- package/src/docs/Typography.stories.tsx +8 -6
- package/src/docs/helpers.tsx +3 -2
- package/src/shared/length.ts +51 -0
- package/src/shared/length.typecheck.tsx +47 -0
- package/src/styles/visually-hidden.css.ts +16 -0
- package/dist/Table-JTgcR_Fh.js.map +0 -1
|
@@ -1,16 +1,46 @@
|
|
|
1
1
|
import {css} from 'react-strict-dom'
|
|
2
2
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
3
|
-
import {radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
3
|
+
import {radii, spacing} from '@duro-app/tokens/tokens/spacing.css'
|
|
4
|
+
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
5
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
4
6
|
|
|
5
7
|
export const styles = css.create({
|
|
6
8
|
root: {
|
|
7
9
|
display: 'inline-flex',
|
|
8
10
|
borderRadius: radii.sm,
|
|
9
|
-
borderWidth:
|
|
11
|
+
borderWidth: borders.hairline,
|
|
10
12
|
borderStyle: 'solid',
|
|
11
13
|
borderColor: colors.border,
|
|
12
14
|
overflow: 'hidden',
|
|
13
15
|
},
|
|
16
|
+
wrap: {
|
|
17
|
+
display: 'flex',
|
|
18
|
+
flexDirection: 'row',
|
|
19
|
+
flexWrap: 'wrap',
|
|
20
|
+
gap: spacing.xs,
|
|
21
|
+
borderWidth: 0,
|
|
22
|
+
borderRadius: 0,
|
|
23
|
+
overflow: 'visible',
|
|
24
|
+
},
|
|
25
|
+
// the scroll content: room for focus rings to draw
|
|
26
|
+
scrollContent: {
|
|
27
|
+
position: 'relative',
|
|
28
|
+
padding: spacing.xs,
|
|
29
|
+
},
|
|
30
|
+
// shows rows + 0.5 rows so the cut-off row hints at more; shorter content
|
|
31
|
+
// sizes itself (max, not fixed). Row heights match the wrapped Toggles.
|
|
32
|
+
maxRowsSmall: (rows: number) => ({
|
|
33
|
+
maxHeight: {
|
|
34
|
+
default: `calc((${rows} + 0.5) * ${sizes.controlSm} + ${rows} * ${spacing.xs} + 2 * ${spacing.xs})`,
|
|
35
|
+
'@media (pointer: coarse)': `calc((${rows} + 0.5) * ${sizes.touchTarget} + ${rows} * ${spacing.xs} + 2 * ${spacing.xs})`,
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
maxRowsDefault: (rows: number) => ({
|
|
39
|
+
maxHeight: {
|
|
40
|
+
default: `calc((${rows} + 0.5) * ${sizes.controlMd} + ${rows} * ${spacing.xs} + 2 * ${spacing.xs})`,
|
|
41
|
+
'@media (pointer: coarse)': `calc((${rows} + 0.5) * ${sizes.touchTarget} + ${rows} * ${spacing.xs} + 2 * ${spacing.xs})`,
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
14
44
|
vertical: {
|
|
15
45
|
flexDirection: 'column',
|
|
16
46
|
},
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {useCallback, useEffect, useLayoutEffect, useRef, useState, type RefObject} from 'react'
|
|
2
|
+
|
|
3
|
+
const ROW_TOLERANCE = 2
|
|
4
|
+
|
|
5
|
+
function sameOrder(a: string[], b: string[]) {
|
|
6
|
+
return a.length === b.length && a.every((v, i) => v === b[i])
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Roving focus for a wrapping ToggleGroup (WAI-ARIA toolbar pattern): one tab
|
|
11
|
+
* stop — the focused item, else the first pressed one, else the first — with
|
|
12
|
+
* arrow keys in reading order, Up/Down by visual row, Home/End.
|
|
13
|
+
*/
|
|
14
|
+
export function useRovingFocus({
|
|
15
|
+
enabled,
|
|
16
|
+
pressed,
|
|
17
|
+
rootRef,
|
|
18
|
+
}: {
|
|
19
|
+
enabled: boolean
|
|
20
|
+
pressed: string[]
|
|
21
|
+
rootRef: RefObject<HTMLElement | null>
|
|
22
|
+
}) {
|
|
23
|
+
const items = useRef(new Map<string, HTMLElement>())
|
|
24
|
+
const [order, setOrder] = useState<string[]>([])
|
|
25
|
+
const [focusedValue, setFocusedValue] = useState<string | null>(null)
|
|
26
|
+
|
|
27
|
+
const sync = useCallback(() => {
|
|
28
|
+
const entries = [...items.current.entries()].sort(([, a], [, b]) =>
|
|
29
|
+
a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1,
|
|
30
|
+
)
|
|
31
|
+
const next = entries.map(([v]) => v)
|
|
32
|
+
setOrder((prev) => (sameOrder(prev, next) ? prev : next))
|
|
33
|
+
}, [])
|
|
34
|
+
|
|
35
|
+
const register = useCallback(
|
|
36
|
+
(value: string, el: HTMLElement) => {
|
|
37
|
+
items.current.set(value, el)
|
|
38
|
+
sync()
|
|
39
|
+
return () => {
|
|
40
|
+
if (items.current.get(value) === el) items.current.delete(value)
|
|
41
|
+
sync()
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
[sync],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
// a focus holder that unmounted no longer holds the tab stop
|
|
48
|
+
useLayoutEffect(() => {
|
|
49
|
+
if (focusedValue !== null && !order.includes(focusedValue)) setFocusedValue(null)
|
|
50
|
+
}, [order, focusedValue])
|
|
51
|
+
|
|
52
|
+
const tabStopValue = !enabled
|
|
53
|
+
? null
|
|
54
|
+
: focusedValue !== null && order.includes(focusedValue)
|
|
55
|
+
? focusedValue
|
|
56
|
+
: (pressed.find((v) => order.includes(v)) ?? order[0] ?? null)
|
|
57
|
+
|
|
58
|
+
// native listener: RSD's onKeyDown event is a reduced shape (as in Tree)
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
const root = rootRef.current
|
|
61
|
+
if (!enabled || !root) return
|
|
62
|
+
function onKeyDown(e: KeyboardEvent) {
|
|
63
|
+
if (e.altKey || e.ctrlKey || e.metaKey) return
|
|
64
|
+
const els = order
|
|
65
|
+
.map((v) => items.current.get(v))
|
|
66
|
+
.filter((el): el is HTMLElement => !!el && !(el as HTMLButtonElement).disabled)
|
|
67
|
+
const i = els.indexOf(e.target as HTMLElement)
|
|
68
|
+
if (i < 0) return
|
|
69
|
+
let target: HTMLElement | undefined
|
|
70
|
+
switch (e.key) {
|
|
71
|
+
case 'ArrowRight':
|
|
72
|
+
target = els[Math.min(i + 1, els.length - 1)]
|
|
73
|
+
break
|
|
74
|
+
case 'ArrowLeft':
|
|
75
|
+
target = els[Math.max(i - 1, 0)]
|
|
76
|
+
break
|
|
77
|
+
case 'Home':
|
|
78
|
+
target = els[0]
|
|
79
|
+
break
|
|
80
|
+
case 'End':
|
|
81
|
+
target = els[els.length - 1]
|
|
82
|
+
break
|
|
83
|
+
case 'ArrowDown':
|
|
84
|
+
case 'ArrowUp': {
|
|
85
|
+
const down = e.key === 'ArrowDown'
|
|
86
|
+
const cur = els[i].getBoundingClientRect()
|
|
87
|
+
const cx = cur.left + cur.width / 2
|
|
88
|
+
const rects = els.map((el) => el.getBoundingClientRect())
|
|
89
|
+
// rows, by distinct top, in the direction of travel
|
|
90
|
+
const tops = [...new Set(rects.map((r) => Math.round(r.top)))].sort((a, b) => a - b)
|
|
91
|
+
const rowIdx = tops.findIndex((t) => Math.abs(t - cur.top) <= ROW_TOLERANCE)
|
|
92
|
+
const nextTop = tops[rowIdx + (down ? 1 : -1)]
|
|
93
|
+
if (nextTop === undefined) break
|
|
94
|
+
let best = Infinity
|
|
95
|
+
rects.forEach((r, k) => {
|
|
96
|
+
if (Math.abs(r.top - nextTop) > ROW_TOLERANCE) return
|
|
97
|
+
const d = Math.abs(r.left + r.width / 2 - cx)
|
|
98
|
+
if (d < best) {
|
|
99
|
+
best = d
|
|
100
|
+
target = els[k]
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
break
|
|
104
|
+
}
|
|
105
|
+
default:
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
e.preventDefault()
|
|
109
|
+
target?.focus()
|
|
110
|
+
}
|
|
111
|
+
root.addEventListener('keydown', onKeyDown)
|
|
112
|
+
return () => root.removeEventListener('keydown', onKeyDown)
|
|
113
|
+
}, [enabled, order, rootRef])
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
tabStopValue,
|
|
117
|
+
register,
|
|
118
|
+
onItemFocus: setFocusedValue,
|
|
119
|
+
items,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -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 {shadows} from '@duro-app/tokens/tokens/shadows.css'
|
|
6
|
+
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
6
7
|
|
|
7
8
|
export const styles = css.create({
|
|
8
9
|
root: {
|
|
@@ -22,7 +23,7 @@ export const styles = css.create({
|
|
|
22
23
|
fontSize: typography.fontSizeXs,
|
|
23
24
|
lineHeight: typography.lineHeight,
|
|
24
25
|
borderRadius: radii.sm,
|
|
25
|
-
borderWidth:
|
|
26
|
+
borderWidth: borders.hairline,
|
|
26
27
|
borderStyle: 'solid',
|
|
27
28
|
borderColor: colors.border,
|
|
28
29
|
boxShadow: shadows.md,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {css} from 'react-strict-dom'
|
|
2
2
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
3
|
-
import {
|
|
3
|
+
import {microSpacing, radii, spacing} 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 {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
7
|
+
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
6
8
|
|
|
7
9
|
export const styles = css.create({
|
|
8
10
|
root: {
|
|
@@ -32,8 +34,8 @@ export const styles = css.create({
|
|
|
32
34
|
display: 'flex',
|
|
33
35
|
alignItems: 'center',
|
|
34
36
|
gap: spacing.xs,
|
|
35
|
-
paddingTop:
|
|
36
|
-
paddingBottom:
|
|
37
|
+
paddingTop: microSpacing.px5,
|
|
38
|
+
paddingBottom: microSpacing.px5,
|
|
37
39
|
paddingRight: spacing.sm,
|
|
38
40
|
fontFamily: typography.fontFamily,
|
|
39
41
|
fontSize: typography.fontSizeSm,
|
|
@@ -53,10 +55,10 @@ export const styles = css.create({
|
|
|
53
55
|
paddingLeft: `calc(${spacing.sm} + ${Math.max(0, level - 1)} * ${spacing.lg})`,
|
|
54
56
|
}),
|
|
55
57
|
rowFocused: {
|
|
56
|
-
outlineWidth:
|
|
58
|
+
outlineWidth: borders.focusRing,
|
|
57
59
|
outlineStyle: 'solid',
|
|
58
60
|
outlineColor: colors.accent,
|
|
59
|
-
outlineOffset: -
|
|
61
|
+
outlineOffset: `calc(-1 * ${borders.focusOffset})`,
|
|
60
62
|
},
|
|
61
63
|
rowSelected: {
|
|
62
64
|
color: colors.accent,
|
|
@@ -67,7 +69,7 @@ export const styles = css.create({
|
|
|
67
69
|
display: 'inline-flex',
|
|
68
70
|
alignItems: 'center',
|
|
69
71
|
justifyContent: 'center',
|
|
70
|
-
width:
|
|
72
|
+
width: sizes.glyphMd,
|
|
71
73
|
flexShrink: 0,
|
|
72
74
|
color: colors.textMuted,
|
|
73
75
|
transitionProperty: 'transform',
|
|
@@ -3,10 +3,11 @@ import {expect, fn, waitFor} from 'storybook/test'
|
|
|
3
3
|
import {createColumnHelper} from '@tanstack/react-table'
|
|
4
4
|
import {css, html} from 'react-strict-dom'
|
|
5
5
|
import {VirtualTable} from './VirtualTable'
|
|
6
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
6
7
|
|
|
7
8
|
const storyStyles = css.create({
|
|
8
9
|
// Phone-width wrapper: below VirtualTable's 640px stackBelow default.
|
|
9
|
-
narrow: {width:
|
|
10
|
+
narrow: {width: sizes.dialogSm},
|
|
10
11
|
})
|
|
11
12
|
|
|
12
13
|
interface Item {
|
|
@@ -49,7 +50,7 @@ export const SmallList: Story = {
|
|
|
49
50
|
export const Virtualized: Story = {
|
|
50
51
|
args: {
|
|
51
52
|
data: makeData(500),
|
|
52
|
-
maxHeight:
|
|
53
|
+
maxHeight: 'listMaxH',
|
|
53
54
|
rangeLabel: ({from, to, total}) => `${from}-${to} of ${total}`,
|
|
54
55
|
onVisiblePageChange: fn(),
|
|
55
56
|
},
|
|
@@ -69,7 +70,7 @@ export const Virtualized: Story = {
|
|
|
69
70
|
export const ScrollReportsPage: Story = {
|
|
70
71
|
args: {
|
|
71
72
|
data: makeData(500),
|
|
72
|
-
maxHeight:
|
|
73
|
+
maxHeight: 'listMaxH',
|
|
73
74
|
pageSize: 50,
|
|
74
75
|
rangeLabel: ({page, pages}) => `page ${page}/${pages}`,
|
|
75
76
|
onVisiblePageChange: fn(),
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
import {useVirtualizer} from '@tanstack/react-virtual'
|
|
14
14
|
import {breakpointsPx, type Breakpoint} from '@duro-app/tokens/tokens/breakpoints.css'
|
|
15
15
|
import {styles} from './styles.css'
|
|
16
|
+
import {SIZES_PX} from '@duro-app/tokens/keys'
|
|
17
|
+
import {resolveLength, type Length} from '../../shared/length'
|
|
16
18
|
|
|
17
19
|
// Measure + commit before paint on the client; no-op-safe on the server.
|
|
18
20
|
const useIsoLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect
|
|
@@ -56,7 +58,7 @@ interface VirtualTableProps<TData> {
|
|
|
56
58
|
/** Estimated row height for the virtualizer. Default 44. */
|
|
57
59
|
estimateRowHeight?: number
|
|
58
60
|
/** Max height of the scroll viewport once virtualized. Default '70vh'. */
|
|
59
|
-
maxHeight?:
|
|
61
|
+
maxHeight?: Length
|
|
60
62
|
/** Render every row (no windowing) at or below this count. Default 150. */
|
|
61
63
|
virtualizeThreshold?: number
|
|
62
64
|
/**
|
|
@@ -94,7 +96,7 @@ export function VirtualTable<TData>({
|
|
|
94
96
|
onVisiblePageChange,
|
|
95
97
|
rangeLabel,
|
|
96
98
|
pageSize = 50,
|
|
97
|
-
estimateRowHeight =
|
|
99
|
+
estimateRowHeight = SIZES_PX.touchTarget,
|
|
98
100
|
maxHeight = '70vh',
|
|
99
101
|
virtualizeThreshold = 150,
|
|
100
102
|
stackBelow = 'sm',
|
|
@@ -288,7 +290,7 @@ export function VirtualTable<TData>({
|
|
|
288
290
|
role="table"
|
|
289
291
|
style={[
|
|
290
292
|
stacked ? styles.stackScroll : styles.scroll,
|
|
291
|
-
virtualize && styles.scrollMax(maxHeight),
|
|
293
|
+
virtualize && styles.scrollMax(resolveLength(maxHeight)),
|
|
292
294
|
]}
|
|
293
295
|
>
|
|
294
296
|
{stacked ? null : (
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {css} from 'react-strict-dom'
|
|
2
2
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
3
|
-
import {
|
|
3
|
+
import {microSpacing, radii, spacing} from '@duro-app/tokens/tokens/spacing.css'
|
|
4
4
|
import {typography} from '@duro-app/tokens/tokens/typography.css'
|
|
5
|
+
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
5
6
|
|
|
6
7
|
export const styles = css.create({
|
|
7
8
|
wrap: {
|
|
@@ -11,7 +12,7 @@ export const styles = css.create({
|
|
|
11
12
|
scroll: {
|
|
12
13
|
position: 'relative',
|
|
13
14
|
width: '100%',
|
|
14
|
-
borderWidth:
|
|
15
|
+
borderWidth: borders.hairline,
|
|
15
16
|
borderStyle: 'solid',
|
|
16
17
|
borderColor: colors.border,
|
|
17
18
|
borderRadius: radii.md,
|
|
@@ -32,7 +33,7 @@ export const styles = css.create({
|
|
|
32
33
|
headRow: {
|
|
33
34
|
display: 'flex',
|
|
34
35
|
flexDirection: 'row',
|
|
35
|
-
borderBottomWidth:
|
|
36
|
+
borderBottomWidth: borders.hairline,
|
|
36
37
|
borderBottomStyle: 'solid',
|
|
37
38
|
borderBottomColor: colors.border,
|
|
38
39
|
},
|
|
@@ -71,7 +72,7 @@ export const styles = css.create({
|
|
|
71
72
|
flexDirection: 'row',
|
|
72
73
|
alignItems: 'center',
|
|
73
74
|
width: '100%',
|
|
74
|
-
borderBottomWidth:
|
|
75
|
+
borderBottomWidth: borders.hairline,
|
|
75
76
|
borderBottomStyle: 'solid',
|
|
76
77
|
borderBottomColor: colors.border,
|
|
77
78
|
},
|
|
@@ -124,7 +125,7 @@ export const styles = css.create({
|
|
|
124
125
|
gap: spacing.xs,
|
|
125
126
|
width: '100%',
|
|
126
127
|
padding: spacing.sm,
|
|
127
|
-
borderWidth:
|
|
128
|
+
borderWidth: borders.hairline,
|
|
128
129
|
borderStyle: 'solid',
|
|
129
130
|
borderColor: colors.border,
|
|
130
131
|
borderRadius: radii.sm,
|
|
@@ -161,13 +162,13 @@ export const styles = css.create({
|
|
|
161
162
|
position: 'absolute',
|
|
162
163
|
right: spacing.sm,
|
|
163
164
|
bottom: spacing.sm,
|
|
164
|
-
paddingTop:
|
|
165
|
-
paddingBottom:
|
|
165
|
+
paddingTop: microSpacing.px3,
|
|
166
|
+
paddingBottom: microSpacing.px3,
|
|
166
167
|
paddingLeft: spacing.sm,
|
|
167
168
|
paddingRight: spacing.sm,
|
|
168
169
|
borderRadius: radii.full,
|
|
169
170
|
backgroundColor: colors.bgCardHover,
|
|
170
|
-
borderWidth:
|
|
171
|
+
borderWidth: borders.hairline,
|
|
171
172
|
borderStyle: 'solid',
|
|
172
173
|
borderColor: colors.border,
|
|
173
174
|
color: colors.textMuted,
|
|
@@ -7,6 +7,8 @@ import {Inline} from '../components/Inline/Inline'
|
|
|
7
7
|
import {useContainerQuery} from '../hooks/useContainerQuery'
|
|
8
8
|
import {TokenTable} from './helpers'
|
|
9
9
|
import {typography, typeScale} from '@duro-app/tokens/tokens/typography.css'
|
|
10
|
+
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
11
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
10
12
|
|
|
11
13
|
const primitiveTokens: Record<string, string> = {
|
|
12
14
|
xs: '4px',
|
|
@@ -33,7 +35,7 @@ export default meta
|
|
|
33
35
|
|
|
34
36
|
const styles = css.create({
|
|
35
37
|
wrapper: {
|
|
36
|
-
maxWidth:
|
|
38
|
+
maxWidth: sizes.panelLg,
|
|
37
39
|
},
|
|
38
40
|
hint: {
|
|
39
41
|
fontSize: typography.fontSizeXs,
|
|
@@ -41,10 +43,10 @@ const styles = css.create({
|
|
|
41
43
|
fontStyle: 'italic',
|
|
42
44
|
},
|
|
43
45
|
baselineRow: {
|
|
44
|
-
height:
|
|
46
|
+
height: sizes.iconLg,
|
|
45
47
|
display: 'flex',
|
|
46
48
|
alignItems: 'center',
|
|
47
|
-
borderBottomWidth:
|
|
49
|
+
borderBottomWidth: borders.hairline,
|
|
48
50
|
borderBottomStyle: 'dashed',
|
|
49
51
|
borderBottomColor: colors.border,
|
|
50
52
|
},
|
|
@@ -52,11 +54,10 @@ const styles = css.create({
|
|
|
52
54
|
fontSize: typography.fontSizeXs,
|
|
53
55
|
fontFamily: 'monospace',
|
|
54
56
|
color: colors.textMuted,
|
|
55
|
-
width:
|
|
57
|
+
width: sizes.iconXxl,
|
|
56
58
|
},
|
|
57
59
|
baselineBlock: {
|
|
58
|
-
|
|
59
|
-
height: 24,
|
|
60
|
+
height: sizes.iconLg,
|
|
60
61
|
backgroundColor: colors.accent,
|
|
61
62
|
opacity: 0.15,
|
|
62
63
|
borderRadius: radii.xs,
|
|
@@ -64,13 +65,13 @@ const styles = css.create({
|
|
|
64
65
|
resizableContainer: {
|
|
65
66
|
resize: 'horizontal',
|
|
66
67
|
overflow: 'auto',
|
|
67
|
-
borderWidth:
|
|
68
|
+
borderWidth: borders.strong,
|
|
68
69
|
borderStyle: 'dashed',
|
|
69
70
|
borderColor: colors.border,
|
|
70
71
|
padding: spacing.md,
|
|
71
|
-
minWidth:
|
|
72
|
+
minWidth: sizes.listMaxHSm,
|
|
72
73
|
maxWidth: '100%',
|
|
73
|
-
width:
|
|
74
|
+
width: sizes.pageSm,
|
|
74
75
|
},
|
|
75
76
|
sizeLabel: {
|
|
76
77
|
fontSize: typography.fontSizeHeading,
|
|
@@ -87,7 +88,7 @@ const styles = css.create({
|
|
|
87
88
|
color: colors.successText,
|
|
88
89
|
},
|
|
89
90
|
mappingRow: {
|
|
90
|
-
borderBottomWidth:
|
|
91
|
+
borderBottomWidth: borders.hairline,
|
|
91
92
|
borderBottomStyle: 'solid',
|
|
92
93
|
borderBottomColor: colors.border,
|
|
93
94
|
fontFamily: 'monospace',
|
|
@@ -8,6 +8,8 @@ import {Text} from '../components/Text/Text'
|
|
|
8
8
|
import {Heading} from '../components/Heading/Heading'
|
|
9
9
|
import {TypeScaleTable} from './helpers'
|
|
10
10
|
import {typography} from '@duro-app/tokens/tokens/typography.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: 'Foundations/Typography',
|
|
@@ -169,7 +171,7 @@ export const TextVariants: StoryObj = {
|
|
|
169
171
|
|
|
170
172
|
const localStyles = css.create({
|
|
171
173
|
wrapper: {
|
|
172
|
-
maxWidth:
|
|
174
|
+
maxWidth: sizes.dialogLg,
|
|
173
175
|
},
|
|
174
176
|
hint: {
|
|
175
177
|
fontSize: typography.fontSizeXs,
|
|
@@ -187,8 +189,8 @@ const localStyles = css.create({
|
|
|
187
189
|
position: 'relative',
|
|
188
190
|
},
|
|
189
191
|
gridLine: {
|
|
190
|
-
height:
|
|
191
|
-
borderBottomWidth:
|
|
192
|
+
height: sizes.iconLg,
|
|
193
|
+
borderBottomWidth: borders.hairline,
|
|
192
194
|
borderBottomStyle: 'dashed',
|
|
193
195
|
borderBottomColor: colors.border,
|
|
194
196
|
},
|
|
@@ -201,12 +203,12 @@ const localStyles = css.create({
|
|
|
201
203
|
resizableContainer: {
|
|
202
204
|
resize: 'horizontal',
|
|
203
205
|
overflow: 'auto',
|
|
204
|
-
borderWidth:
|
|
206
|
+
borderWidth: borders.strong,
|
|
205
207
|
borderStyle: 'dashed',
|
|
206
208
|
borderColor: colors.border,
|
|
207
209
|
padding: spacing.md,
|
|
208
|
-
minWidth:
|
|
210
|
+
minWidth: sizes.gridColMd,
|
|
209
211
|
maxWidth: '100%',
|
|
210
|
-
width:
|
|
212
|
+
width: sizes.dialogLg,
|
|
211
213
|
},
|
|
212
214
|
})
|
package/src/docs/helpers.tsx
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {css, html} from 'react-strict-dom'
|
|
2
2
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
3
|
-
import {typography
|
|
3
|
+
import {typography} from '@duro-app/tokens/tokens/typography.css'
|
|
4
4
|
import {Table} from '../components/Table/Table'
|
|
5
5
|
import {radii, spacing} from '@duro-app/tokens/tokens/spacing.css'
|
|
6
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
6
7
|
|
|
7
8
|
const styles = css.create({
|
|
8
9
|
bar: {
|
|
9
|
-
height:
|
|
10
|
+
height: sizes.glyphSm,
|
|
10
11
|
borderRadius: radii.xs,
|
|
11
12
|
backgroundColor: colors.accent,
|
|
12
13
|
},
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
2
|
+
import {SIZE_KEYS, type SizeToken} from '@duro-app/tokens/keys'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A length a measure prop accepts without a token: zero, a relative unit or a
|
|
6
|
+
* keyword. These are the exemptions of design-system.every-measure-is-a-token
|
|
7
|
+
* (ADR-0027); a px value is not one of them.
|
|
8
|
+
*/
|
|
9
|
+
export type RelativeLength =
|
|
10
|
+
| 0
|
|
11
|
+
| '0'
|
|
12
|
+
| 'auto'
|
|
13
|
+
| 'none'
|
|
14
|
+
| 'min-content'
|
|
15
|
+
| 'max-content'
|
|
16
|
+
| 'fit-content'
|
|
17
|
+
| `${number}%`
|
|
18
|
+
| `${number}vh`
|
|
19
|
+
| `${number}vw`
|
|
20
|
+
| `${number}dvh`
|
|
21
|
+
| `${number}svh`
|
|
22
|
+
| `${number}lvh`
|
|
23
|
+
| `${number}em`
|
|
24
|
+
| `${number}rem`
|
|
25
|
+
| `${number}ch`
|
|
26
|
+
|
|
27
|
+
/** A measure prop: a `sizes` token key (`"gridColMd"`) or a relative length. */
|
|
28
|
+
export type Length = SizeToken | RelativeLength
|
|
29
|
+
|
|
30
|
+
/**
|
|
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.
|
|
38
|
+
*/
|
|
39
|
+
export type GridTrack = Length | `${number}fr` | `minmax(${string})` | `fit-content(${string})`
|
|
40
|
+
|
|
41
|
+
const sizeKeys: ReadonlySet<string> = new Set(SIZE_KEYS)
|
|
42
|
+
|
|
43
|
+
/** The CSS value for a Length: a size token key becomes its variable. */
|
|
44
|
+
export function resolveLength(value: Length): string | number {
|
|
45
|
+
return typeof value === 'string' && sizeKeys.has(value) ? sizes[value as SizeToken] : value
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The CSS value for a GridTrack: a size token key becomes its variable. */
|
|
49
|
+
export function resolveTrack(track: GridTrack): string | number {
|
|
50
|
+
return typeof track === 'string' && sizeKeys.has(track) ? sizes[track as SizeToken] : track
|
|
51
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Compile-only fixtures for measure props (ADR-0027, plan 2c′). `pnpm typecheck`
|
|
2
|
+
// fails if a raw px becomes assignable to a measure prop, or if a token key or
|
|
3
|
+
// a relative length stops being. Never imported at runtime.
|
|
4
|
+
|
|
5
|
+
import type {Grid} from '../components/Grid/Grid'
|
|
6
|
+
import type {InputGroup} from '../components/InputGroup/InputGroup'
|
|
7
|
+
import type {ScrollArea} from '../components/ScrollArea/ScrollArea'
|
|
8
|
+
import type {Table} from '../components/Table/Table'
|
|
9
|
+
import type {VirtualTable} from '../components/VirtualTable/VirtualTable'
|
|
10
|
+
import type {GridTrack, Length} from './length'
|
|
11
|
+
|
|
12
|
+
/** `true` when every member of T is assignable to U. */
|
|
13
|
+
type Assignable<T, U> = [T] extends [U] ? true : false
|
|
14
|
+
|
|
15
|
+
/** The props a function component takes. */
|
|
16
|
+
type PropsOf<C> = C extends (props: infer P) => unknown ? P : never
|
|
17
|
+
type Prop<C, K extends keyof PropsOf<C>> = NonNullable<PropsOf<C>[K]>
|
|
18
|
+
|
|
19
|
+
// Accepted: token keys, zero, relative lengths, keywords.
|
|
20
|
+
export const lengthTokens: Assignable<'gridColMd' | 'touchTarget', Length> = true
|
|
21
|
+
export const lengthRelative: Assignable<0 | '0' | '100%' | '70vh' | '2rem' | 'auto', Length> = true
|
|
22
|
+
export const trackForms: Assignable<
|
|
23
|
+
'iconButton' | '2fr' | 'max-content' | 'minmax(0, 2fr)',
|
|
24
|
+
GridTrack
|
|
25
|
+
> = true
|
|
26
|
+
|
|
27
|
+
// Refused: px as a string or a number.
|
|
28
|
+
export const lengthPxString: Assignable<'280px', Length> = false
|
|
29
|
+
export const lengthPxNumber: Assignable<44, Length> = false
|
|
30
|
+
export const trackPx: Assignable<'40px', GridTrack> = false
|
|
31
|
+
|
|
32
|
+
// The props themselves.
|
|
33
|
+
export const gridMin: Assignable<'280px', Prop<typeof Grid, 'minColumnWidth'>> = false
|
|
34
|
+
export const gridMinToken: Assignable<'gridColMd', Prop<typeof Grid, 'minColumnWidth'>> = true
|
|
35
|
+
export const addonMin: Assignable<80, Prop<typeof InputGroup.Addon, 'minWidth'>> = false
|
|
36
|
+
export const viewportMax: Assignable<300, Prop<typeof ScrollArea.Viewport, 'maxHeight'>> = false
|
|
37
|
+
export const viewportMaxToken: Assignable<
|
|
38
|
+
'listMaxH',
|
|
39
|
+
Prop<typeof ScrollArea.Viewport, 'maxHeight'>
|
|
40
|
+
> = true
|
|
41
|
+
export const tableMin: Assignable<120, Prop<typeof Table.Root, 'minColumnWidth'>> = false
|
|
42
|
+
export const headerWidth: Assignable<'40px', Prop<typeof Table.HeaderCell, 'width'>> = false
|
|
43
|
+
export const headerWidthToken: Assignable<
|
|
44
|
+
'iconButton',
|
|
45
|
+
Prop<typeof Table.HeaderCell, 'width'>
|
|
46
|
+
> = true
|
|
47
|
+
export const virtualMax: Assignable<300, Prop<typeof VirtualTable, 'maxHeight'>> = false
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {css} from 'react-strict-dom'
|
|
2
|
+
|
|
3
|
+
// The visually-hidden technique: a 1×1 box clipped by overflow, still in the
|
|
4
|
+
// accessibility tree and still focusable where the element is. The 1px is the
|
|
5
|
+
// technique, not a design measure, so this module is the one file the
|
|
6
|
+
// every-measure-is-a-token rule exempts (ADR-0027; `exemptFiles` in
|
|
7
|
+
// eslint.config.js). Components layer their own extras on top (`opacity: 0`
|
|
8
|
+
// for a native input, `clip` for a label).
|
|
9
|
+
export const visuallyHidden = css.create({
|
|
10
|
+
base: {
|
|
11
|
+
position: 'absolute',
|
|
12
|
+
width: 1,
|
|
13
|
+
height: 1,
|
|
14
|
+
overflow: 'hidden',
|
|
15
|
+
},
|
|
16
|
+
})
|