@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
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/react'
|
|
2
|
+
import {expect, waitFor, within} from 'storybook/test'
|
|
3
|
+
import {userEvent} from '@testing-library/user-event'
|
|
4
|
+
import {html} from 'react-strict-dom'
|
|
5
|
+
import {Popover} from './Popover'
|
|
6
|
+
import {Select} from '../Select/Select'
|
|
7
|
+
import {Combobox} from '../Combobox/Combobox'
|
|
8
|
+
import {Menu} from '../Menu/Menu'
|
|
9
|
+
import {Stack} from '../Stack/Stack'
|
|
10
|
+
|
|
11
|
+
const meta: Meta = {
|
|
12
|
+
title: 'Components/Popover/Layers',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default meta
|
|
16
|
+
type Story = StoryObj
|
|
17
|
+
|
|
18
|
+
// Nested popups are portalled out of the canvas, so query the document.
|
|
19
|
+
const page = () => within(document.body)
|
|
20
|
+
|
|
21
|
+
const dialog = () => page().queryByRole('dialog', {name: 'Style'})
|
|
22
|
+
|
|
23
|
+
function SelectItems() {
|
|
24
|
+
return (
|
|
25
|
+
<Select.Popup>
|
|
26
|
+
<Select.Item value="primary">
|
|
27
|
+
<Select.ItemText>Primary</Select.ItemText>
|
|
28
|
+
</Select.Item>
|
|
29
|
+
<Select.Item value="secondary">
|
|
30
|
+
<Select.ItemText>Secondary</Select.ItemText>
|
|
31
|
+
</Select.Item>
|
|
32
|
+
</Select.Popup>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function VariantSelect() {
|
|
37
|
+
return (
|
|
38
|
+
<Select.Root defaultValue="primary">
|
|
39
|
+
<Select.Trigger aria-label="Variant">
|
|
40
|
+
<Select.Value />
|
|
41
|
+
<Select.Icon />
|
|
42
|
+
</Select.Trigger>
|
|
43
|
+
<SelectItems />
|
|
44
|
+
</Select.Root>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function FruitCombobox() {
|
|
49
|
+
return (
|
|
50
|
+
<Combobox.Root>
|
|
51
|
+
<Combobox.Input placeholder="Search fruit...">
|
|
52
|
+
<Combobox.Trigger />
|
|
53
|
+
</Combobox.Input>
|
|
54
|
+
<Combobox.Popup>
|
|
55
|
+
<Combobox.Item value="apple">
|
|
56
|
+
<Combobox.ItemText>Apple</Combobox.ItemText>
|
|
57
|
+
</Combobox.Item>
|
|
58
|
+
<Combobox.Item value="banana">
|
|
59
|
+
<Combobox.ItemText>Banana</Combobox.ItemText>
|
|
60
|
+
</Combobox.Item>
|
|
61
|
+
</Combobox.Popup>
|
|
62
|
+
</Combobox.Root>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function Host({children}: {children: React.ReactNode}) {
|
|
67
|
+
return (
|
|
68
|
+
<Stack gap="md">
|
|
69
|
+
<Popover.Root>
|
|
70
|
+
<Popover.Trigger>Style</Popover.Trigger>
|
|
71
|
+
<Popover.Popup label="Style">{children}</Popover.Popup>
|
|
72
|
+
</Popover.Root>
|
|
73
|
+
<html.button type="button">Elsewhere</html.button>
|
|
74
|
+
</Stack>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const SelectOutsideField: Story = {
|
|
79
|
+
render: () => (
|
|
80
|
+
<Host>
|
|
81
|
+
<VariantSelect />
|
|
82
|
+
</Host>
|
|
83
|
+
),
|
|
84
|
+
play: async ({canvas}) => {
|
|
85
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
86
|
+
const trigger = page().getByRole('combobox', {name: 'Variant'})
|
|
87
|
+
await userEvent.click(trigger)
|
|
88
|
+
await userEvent.click(page().getByRole('option', {name: 'Secondary'}))
|
|
89
|
+
await expect(trigger).toHaveTextContent('Secondary')
|
|
90
|
+
await expect(dialog()).toBeInTheDocument()
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const ComboboxOutsideField: Story = {
|
|
95
|
+
render: () => (
|
|
96
|
+
<Host>
|
|
97
|
+
<FruitCombobox />
|
|
98
|
+
</Host>
|
|
99
|
+
),
|
|
100
|
+
play: async ({canvas}) => {
|
|
101
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
102
|
+
const input = page().getByRole('combobox')
|
|
103
|
+
await userEvent.click(input)
|
|
104
|
+
await userEvent.click(await page().findByRole('option', {name: 'Banana'}))
|
|
105
|
+
await waitFor(() => expect(input).toHaveValue('Banana'))
|
|
106
|
+
await expect(dialog()).toBeInTheDocument()
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const SelectBackdropPress: Story = {
|
|
111
|
+
render: () => (
|
|
112
|
+
<Host>
|
|
113
|
+
<VariantSelect />
|
|
114
|
+
</Host>
|
|
115
|
+
),
|
|
116
|
+
play: async ({canvas}) => {
|
|
117
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
118
|
+
const trigger = page().getByRole('combobox', {name: 'Variant'})
|
|
119
|
+
await userEvent.click(trigger)
|
|
120
|
+
await expect(trigger).toHaveAttribute('aria-expanded', 'true')
|
|
121
|
+
|
|
122
|
+
// The backdrop covers the viewport: a press at the corner lands on it.
|
|
123
|
+
const backdrop = document.elementFromPoint(2, 2) as HTMLElement
|
|
124
|
+
await userEvent.click(backdrop)
|
|
125
|
+
await expect(trigger).toHaveAttribute('aria-expanded', 'false')
|
|
126
|
+
await expect(dialog()).toBeInTheDocument()
|
|
127
|
+
|
|
128
|
+
// With the Select closed, an outside press closes the Popover.
|
|
129
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Elsewhere'}))
|
|
130
|
+
await expect(dialog()).not.toBeInTheDocument()
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const SelectOutsidePopover: Story = {
|
|
135
|
+
render: () => (
|
|
136
|
+
<Stack gap="md">
|
|
137
|
+
<Popover.Root>
|
|
138
|
+
<Popover.Trigger>Style</Popover.Trigger>
|
|
139
|
+
<Popover.Popup label="Style">
|
|
140
|
+
<Popover.Close>Done</Popover.Close>
|
|
141
|
+
</Popover.Popup>
|
|
142
|
+
</Popover.Root>
|
|
143
|
+
<VariantSelect />
|
|
144
|
+
</Stack>
|
|
145
|
+
),
|
|
146
|
+
play: async ({canvas}) => {
|
|
147
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
148
|
+
await expect(dialog()).toBeInTheDocument()
|
|
149
|
+
// The Select is not inside the Popover: choosing from it is an outside press.
|
|
150
|
+
await userEvent.click(canvas.getByRole('combobox', {name: 'Variant'}))
|
|
151
|
+
await userEvent.click(page().getByRole('option', {name: 'Secondary'}))
|
|
152
|
+
await expect(dialog()).not.toBeInTheDocument()
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const EscapeInNestedSelect: Story = {
|
|
157
|
+
render: () => (
|
|
158
|
+
<Host>
|
|
159
|
+
<VariantSelect />
|
|
160
|
+
</Host>
|
|
161
|
+
),
|
|
162
|
+
play: async ({canvas}) => {
|
|
163
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
164
|
+
const trigger = page().getByRole('combobox', {name: 'Variant'})
|
|
165
|
+
await userEvent.click(trigger)
|
|
166
|
+
await expect(trigger).toHaveAttribute('aria-expanded', 'true')
|
|
167
|
+
await userEvent.keyboard('{Escape}')
|
|
168
|
+
await expect(trigger).toHaveAttribute('aria-expanded', 'false')
|
|
169
|
+
await expect(dialog()).toBeInTheDocument()
|
|
170
|
+
await userEvent.keyboard('{Escape}')
|
|
171
|
+
await expect(dialog()).not.toBeInTheDocument()
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const EscapeInNestedMenu: Story = {
|
|
176
|
+
render: () => (
|
|
177
|
+
<Host>
|
|
178
|
+
<Menu.Root>
|
|
179
|
+
<Menu.Trigger>Actions</Menu.Trigger>
|
|
180
|
+
<Menu.Popup>
|
|
181
|
+
<Menu.Item>Copy</Menu.Item>
|
|
182
|
+
<Menu.Item>Paste</Menu.Item>
|
|
183
|
+
</Menu.Popup>
|
|
184
|
+
</Menu.Root>
|
|
185
|
+
</Host>
|
|
186
|
+
),
|
|
187
|
+
play: async ({canvas}) => {
|
|
188
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
189
|
+
await userEvent.click(page().getByRole('button', {name: 'Actions'}))
|
|
190
|
+
await expect(await page().findByRole('menu')).toBeVisible()
|
|
191
|
+
await userEvent.keyboard('{Escape}')
|
|
192
|
+
await waitFor(() => expect(page().queryByRole('menu')).not.toBeInTheDocument())
|
|
193
|
+
await expect(dialog()).toBeInTheDocument()
|
|
194
|
+
await userEvent.keyboard('{Escape}')
|
|
195
|
+
await expect(dialog()).not.toBeInTheDocument()
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export const EscapeInNestedCombobox: Story = {
|
|
200
|
+
render: () => (
|
|
201
|
+
<Host>
|
|
202
|
+
<FruitCombobox />
|
|
203
|
+
</Host>
|
|
204
|
+
),
|
|
205
|
+
play: async ({canvas}) => {
|
|
206
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
207
|
+
const input = page().getByRole('combobox')
|
|
208
|
+
await userEvent.click(input)
|
|
209
|
+
await expect(await page().findByRole('listbox')).toBeVisible()
|
|
210
|
+
await userEvent.keyboard('{Escape}')
|
|
211
|
+
await waitFor(() => expect(page().queryByRole('listbox')).not.toBeInTheDocument())
|
|
212
|
+
await expect(dialog()).toBeInTheDocument()
|
|
213
|
+
await userEvent.keyboard('{Escape}')
|
|
214
|
+
await expect(dialog()).not.toBeInTheDocument()
|
|
215
|
+
},
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export const TabFromNestedSelect: Story = {
|
|
219
|
+
render: () => (
|
|
220
|
+
<Host>
|
|
221
|
+
<VariantSelect />
|
|
222
|
+
<html.button type="button">After</html.button>
|
|
223
|
+
</Host>
|
|
224
|
+
),
|
|
225
|
+
play: async ({canvas}) => {
|
|
226
|
+
await userEvent.click(canvas.getByRole('button', {name: 'Style'}))
|
|
227
|
+
const trigger = page().getByRole('combobox', {name: 'Variant'})
|
|
228
|
+
await userEvent.click(trigger)
|
|
229
|
+
await expect(trigger).toHaveAttribute('aria-expanded', 'true')
|
|
230
|
+
await userEvent.tab()
|
|
231
|
+
await expect(trigger).toHaveAttribute('aria-expanded', 'false')
|
|
232
|
+
await waitFor(() => expect(trigger).not.toHaveFocus())
|
|
233
|
+
},
|
|
234
|
+
}
|
|
@@ -4,6 +4,7 @@ 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 {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
7
8
|
|
|
8
9
|
export const styles = css.create({
|
|
9
10
|
trigger: {
|
|
@@ -21,7 +22,7 @@ export const styles = css.create({
|
|
|
21
22
|
default: 'transparent',
|
|
22
23
|
':hover': colors.bgCardHover,
|
|
23
24
|
},
|
|
24
|
-
borderWidth:
|
|
25
|
+
borderWidth: borders.hairline,
|
|
25
26
|
borderStyle: 'solid',
|
|
26
27
|
borderColor: colors.border,
|
|
27
28
|
borderRadius: radii.sm,
|
|
@@ -35,7 +36,7 @@ export const styles = css.create({
|
|
|
35
36
|
left: 0,
|
|
36
37
|
boxSizing: 'border-box',
|
|
37
38
|
backgroundColor: colors.bgCard,
|
|
38
|
-
borderWidth:
|
|
39
|
+
borderWidth: borders.hairline,
|
|
39
40
|
borderStyle: 'solid',
|
|
40
41
|
borderColor: colors.border,
|
|
41
42
|
borderRadius: radii.sm,
|
|
@@ -3,6 +3,7 @@ import {html} from 'react-strict-dom'
|
|
|
3
3
|
import {useControllableValue} from '../../hooks/useControllableValue'
|
|
4
4
|
import {styles} from './styles.css'
|
|
5
5
|
import {useFieldGroupLabelling} from '../Field/FieldContext'
|
|
6
|
+
import {visuallyHidden} from '../../styles/visually-hidden.css'
|
|
6
7
|
|
|
7
8
|
// --- Context ---
|
|
8
9
|
|
|
@@ -100,7 +101,7 @@ function Item({value, disabled: itemDisabled = false, children}: ItemProps) {
|
|
|
100
101
|
checked={isChecked}
|
|
101
102
|
disabled={isDisabled}
|
|
102
103
|
onChange={() => onSelect(value)}
|
|
103
|
-
style={styles.input}
|
|
104
|
+
style={[visuallyHidden.base, styles.input]}
|
|
104
105
|
/>
|
|
105
106
|
<html.span
|
|
106
107
|
style={[styles.circle, isChecked ? styles.circleChecked : styles.circleUnchecked]}
|
|
@@ -3,6 +3,8 @@ 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 {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: {
|
|
@@ -27,9 +29,9 @@ export const styles = css.create({
|
|
|
27
29
|
cursor: 'not-allowed',
|
|
28
30
|
},
|
|
29
31
|
circle: {
|
|
30
|
-
width:
|
|
31
|
-
height:
|
|
32
|
-
borderWidth:
|
|
32
|
+
width: sizes.indicator,
|
|
33
|
+
height: sizes.indicator,
|
|
34
|
+
borderWidth: borders.hairline,
|
|
33
35
|
borderStyle: 'solid',
|
|
34
36
|
borderRadius: radii.full,
|
|
35
37
|
display: 'inline-flex',
|
|
@@ -52,16 +54,13 @@ export const styles = css.create({
|
|
|
52
54
|
borderColor: colors.accent,
|
|
53
55
|
},
|
|
54
56
|
dot: {
|
|
55
|
-
width:
|
|
56
|
-
height:
|
|
57
|
+
width: sizes.indicatorDot,
|
|
58
|
+
height: sizes.indicatorDot,
|
|
57
59
|
borderRadius: radii.full,
|
|
58
60
|
backgroundColor: colors.accent,
|
|
59
61
|
},
|
|
62
|
+
// Layered on visuallyHidden.base: a native input is also made transparent.
|
|
60
63
|
input: {
|
|
61
|
-
position: 'absolute',
|
|
62
|
-
width: 1,
|
|
63
|
-
height: 1,
|
|
64
64
|
opacity: 0,
|
|
65
|
-
overflow: 'hidden',
|
|
66
65
|
},
|
|
67
66
|
})
|
|
@@ -2,7 +2,7 @@ import type {ComponentMeta} from '../component-meta'
|
|
|
2
2
|
|
|
3
3
|
export const meta: ComponentMeta = {
|
|
4
4
|
description:
|
|
5
|
-
'Custom scrollbar region with draggable thumb. Supports vertical and horizontal scrolling. Compound component — Root is required.',
|
|
5
|
+
'Custom scrollbar region with draggable thumb. Supports vertical and horizontal scrolling. Compound component — Root is required. Inside a Drawer, a drag in the viewport scrolls it; the drawer only takes a drag toward its edge from the scroll start.',
|
|
6
6
|
whenToUse: [
|
|
7
7
|
'Custom-styled scrollbars for content overflow areas',
|
|
8
8
|
'Chat logs, code blocks, or long lists with constrained height',
|
|
@@ -15,7 +15,7 @@ export const meta: ComponentMeta = {
|
|
|
15
15
|
required: ['Root', 'Viewport', 'Content', 'Scrollbar', 'Thumb'],
|
|
16
16
|
},
|
|
17
17
|
example: `<ScrollArea.Root>
|
|
18
|
-
<ScrollArea.Viewport maxHeight=
|
|
18
|
+
<ScrollArea.Viewport maxHeight="listMaxH">
|
|
19
19
|
<ScrollArea.Content>
|
|
20
20
|
{/* Long content here */}
|
|
21
21
|
</ScrollArea.Content>
|
|
@@ -5,6 +5,8 @@ import {ScrollArea} from './ScrollArea'
|
|
|
5
5
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
6
6
|
import {typography} from '@duro-app/tokens/tokens/typography.css'
|
|
7
7
|
import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
8
|
+
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
9
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
8
10
|
|
|
9
11
|
const meta: Meta = {
|
|
10
12
|
title: 'Components/ScrollArea',
|
|
@@ -15,8 +17,8 @@ type Story = StoryObj
|
|
|
15
17
|
|
|
16
18
|
const demoStyles = css.create({
|
|
17
19
|
container: {
|
|
18
|
-
width:
|
|
19
|
-
borderWidth:
|
|
20
|
+
width: sizes.gridColMd,
|
|
21
|
+
borderWidth: borders.hairline,
|
|
20
22
|
borderStyle: 'solid',
|
|
21
23
|
borderColor: colors.border,
|
|
22
24
|
borderRadius: radii.sm,
|
|
@@ -26,7 +28,7 @@ const demoStyles = css.create({
|
|
|
26
28
|
paddingBottom: spacing.ms,
|
|
27
29
|
paddingLeft: spacing.md,
|
|
28
30
|
paddingRight: spacing.md,
|
|
29
|
-
borderBottomWidth:
|
|
31
|
+
borderBottomWidth: borders.hairline,
|
|
30
32
|
borderBottomStyle: 'solid',
|
|
31
33
|
borderBottomColor: colors.bgCard,
|
|
32
34
|
fontSize: typography.fontSizeSm,
|
|
@@ -40,7 +42,7 @@ export const Default: Story = {
|
|
|
40
42
|
render: () => (
|
|
41
43
|
<html.div style={demoStyles.container}>
|
|
42
44
|
<ScrollArea.Root>
|
|
43
|
-
<ScrollArea.Viewport maxHeight=
|
|
45
|
+
<ScrollArea.Viewport maxHeight="listMaxH">
|
|
44
46
|
<ScrollArea.Content>
|
|
45
47
|
{items.map((item) => (
|
|
46
48
|
<html.div key={item} style={demoStyles.item}>
|
|
@@ -66,7 +68,7 @@ export const ShortContent: Story = {
|
|
|
66
68
|
render: () => (
|
|
67
69
|
<html.div style={demoStyles.container}>
|
|
68
70
|
<ScrollArea.Root>
|
|
69
|
-
<ScrollArea.Viewport maxHeight=
|
|
71
|
+
<ScrollArea.Viewport maxHeight="listMaxH">
|
|
70
72
|
<ScrollArea.Content>
|
|
71
73
|
<html.div style={demoStyles.item}>Only one item</html.div>
|
|
72
74
|
<html.div style={demoStyles.item}>Two items</html.div>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {type ReactNode, useRef, useCallback} from 'react'
|
|
1
|
+
import {type ComponentProps, type ReactNode, useRef, useCallback} from 'react'
|
|
2
2
|
import {html} from 'react-strict-dom'
|
|
3
3
|
import {styles} from './styles.css'
|
|
4
4
|
import {ScrollAreaContext, useScrollArea} from './ScrollAreaContext'
|
|
5
5
|
import {useScrollAreaRoot} from './useScrollAreaRoot'
|
|
6
|
+
import {resolveLength, type Length} from '../../shared/length'
|
|
6
7
|
|
|
7
8
|
// --- Root ---
|
|
8
9
|
|
|
@@ -24,20 +25,30 @@ function Root({children}: RootProps) {
|
|
|
24
25
|
|
|
25
26
|
interface ViewportProps {
|
|
26
27
|
children: ReactNode
|
|
27
|
-
maxHeight?:
|
|
28
|
+
maxHeight?: Length
|
|
29
|
+
/** Extra styles for the viewport (e.g. a pointer-aware max height). */
|
|
30
|
+
style?: ComponentProps<typeof html.div>['style']
|
|
31
|
+
/** A roving-focus group owns the keyboard: drop the viewport's own tab stop
|
|
32
|
+
* and region role. */
|
|
33
|
+
rovingOwner?: boolean
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
function Viewport({children, maxHeight}: ViewportProps) {
|
|
36
|
+
function Viewport({children, maxHeight, style, rovingOwner = false}: ViewportProps) {
|
|
31
37
|
const {viewportRef, viewportId} = useScrollArea()
|
|
32
38
|
|
|
33
39
|
return (
|
|
34
40
|
<html.div
|
|
35
41
|
ref={viewportRef}
|
|
36
42
|
id={viewportId}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
data-duro-scroll=""
|
|
44
|
+
tabIndex={rovingOwner ? undefined : 0}
|
|
45
|
+
role={rovingOwner ? undefined : 'region'}
|
|
46
|
+
aria-label={rovingOwner ? undefined : 'Scrollable content'}
|
|
47
|
+
style={[
|
|
48
|
+
styles.viewport,
|
|
49
|
+
maxHeight != null && styles.viewportMaxHeight(resolveLength(maxHeight)),
|
|
50
|
+
style,
|
|
51
|
+
]}
|
|
41
52
|
>
|
|
42
53
|
{children}
|
|
43
54
|
</html.div>
|
|
@@ -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 {radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
3
|
+
import {microSpacing, radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
4
4
|
import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
|
|
5
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
5
6
|
|
|
6
7
|
export const styles = css.create({
|
|
7
8
|
root: {
|
|
@@ -34,21 +35,21 @@ export const styles = css.create({
|
|
|
34
35
|
top: 0,
|
|
35
36
|
right: 0,
|
|
36
37
|
bottom: 0,
|
|
37
|
-
width:
|
|
38
|
+
width: sizes.scrollbar,
|
|
38
39
|
flexDirection: 'column',
|
|
39
|
-
paddingTop:
|
|
40
|
-
paddingBottom:
|
|
41
|
-
paddingRight:
|
|
40
|
+
paddingTop: microSpacing.px2,
|
|
41
|
+
paddingBottom: microSpacing.px2,
|
|
42
|
+
paddingRight: microSpacing.px2,
|
|
42
43
|
},
|
|
43
44
|
scrollbarHorizontal: {
|
|
44
45
|
left: 0,
|
|
45
46
|
right: 0,
|
|
46
47
|
bottom: 0,
|
|
47
|
-
height:
|
|
48
|
+
height: sizes.scrollbar,
|
|
48
49
|
flexDirection: 'row',
|
|
49
|
-
paddingLeft:
|
|
50
|
-
paddingRight:
|
|
51
|
-
paddingBottom:
|
|
50
|
+
paddingLeft: microSpacing.px2,
|
|
51
|
+
paddingRight: microSpacing.px2,
|
|
52
|
+
paddingBottom: microSpacing.px2,
|
|
52
53
|
},
|
|
53
54
|
scrollbarHidden: {
|
|
54
55
|
opacity: 0,
|
|
@@ -17,6 +17,12 @@ export const meta: ComponentMeta = {
|
|
|
17
17
|
optional: ['Value', 'Icon', 'ItemText'],
|
|
18
18
|
},
|
|
19
19
|
relatedTo: [
|
|
20
|
+
{
|
|
21
|
+
component: 'Popover',
|
|
22
|
+
kind: 'composition',
|
|
23
|
+
relationship:
|
|
24
|
+
'Inside Popover.Popup a Select keeps the popover open while you choose; its backdrop press and Escape close only the list',
|
|
25
|
+
},
|
|
20
26
|
{
|
|
21
27
|
component: 'Menu',
|
|
22
28
|
kind: 'contrast',
|
|
@@ -6,6 +6,7 @@ import {SelectContext, useSelect} from './SelectContext'
|
|
|
6
6
|
import {useSelectRoot} from './useSelectRoot'
|
|
7
7
|
import {useFieldContext} from '../Field/FieldContext'
|
|
8
8
|
import {usePortalMount} from '../ThemeProvider/ThemeProvider'
|
|
9
|
+
import {usePopoverLayer} from '../Popover/PopoverLayerContext'
|
|
9
10
|
|
|
10
11
|
// --- Root ---
|
|
11
12
|
interface RootProps {
|
|
@@ -141,10 +142,16 @@ function Popup({children}: {children: ReactNode}) {
|
|
|
141
142
|
}
|
|
142
143
|
}, [open, triggerRef])
|
|
143
144
|
|
|
145
|
+
const listboxRef = useRef<HTMLDivElement>(null)
|
|
146
|
+
const backdropRef = useRef<HTMLDivElement>(null)
|
|
147
|
+
usePopoverLayer(listboxRef, {active: open})
|
|
148
|
+
usePopoverLayer(backdropRef, {active: open})
|
|
149
|
+
|
|
144
150
|
const node = (
|
|
145
151
|
<>
|
|
146
|
-
{open && <html.div style={styles.backdrop} onClick={close} />}
|
|
152
|
+
{open && <html.div ref={backdropRef} style={styles.backdrop} onClick={close} />}
|
|
147
153
|
<html.div
|
|
154
|
+
ref={listboxRef}
|
|
148
155
|
id={listboxId}
|
|
149
156
|
role="listbox"
|
|
150
157
|
aria-hidden={!open}
|
|
@@ -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: {
|
|
@@ -23,7 +25,7 @@ export const styles = css.create({
|
|
|
23
25
|
fontSize: typography.fontSizeSm,
|
|
24
26
|
color: colors.text,
|
|
25
27
|
backgroundColor: colors.bgCard,
|
|
26
|
-
borderWidth:
|
|
28
|
+
borderWidth: borders.hairline,
|
|
27
29
|
borderStyle: 'solid',
|
|
28
30
|
borderColor: {
|
|
29
31
|
default: colors.border,
|
|
@@ -64,15 +66,15 @@ export const styles = css.create({
|
|
|
64
66
|
// ancestor with `overflow: hidden` / `transform` (notably inside a Dialog).
|
|
65
67
|
position: 'fixed',
|
|
66
68
|
backgroundColor: colors.bgCard,
|
|
67
|
-
borderWidth:
|
|
69
|
+
borderWidth: borders.hairline,
|
|
68
70
|
borderStyle: 'solid',
|
|
69
71
|
borderColor: colors.border,
|
|
70
72
|
borderRadius: radii.sm,
|
|
71
73
|
boxShadow: shadows.md,
|
|
72
74
|
paddingTop: spacing.xs,
|
|
73
75
|
paddingBottom: spacing.xs,
|
|
74
|
-
minWidth:
|
|
75
|
-
maxHeight:
|
|
76
|
+
minWidth: sizes.labelMinW,
|
|
77
|
+
maxHeight: sizes.listMaxH,
|
|
76
78
|
overflowY: 'auto',
|
|
77
79
|
zIndex: 1050,
|
|
78
80
|
// Re-enable pointer events: the portal mount is pointer-events: none.
|
|
@@ -88,7 +88,12 @@ export function useSelectRoot({
|
|
|
88
88
|
function handleKeyDown(e: KeyboardEvent) {
|
|
89
89
|
const order = orderRef.current
|
|
90
90
|
const items = itemsRef.current
|
|
91
|
-
if (
|
|
91
|
+
if (e.key === 'Escape') {
|
|
92
|
+
e.preventDefault()
|
|
93
|
+
close()
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
if (order.length === 0 && e.key !== 'Tab') return
|
|
92
97
|
|
|
93
98
|
switch (e.key) {
|
|
94
99
|
case 'ArrowDown': {
|
|
@@ -132,7 +137,6 @@ export function useSelectRoot({
|
|
|
132
137
|
})
|
|
133
138
|
break
|
|
134
139
|
}
|
|
135
|
-
case 'Escape':
|
|
136
140
|
case 'Tab': {
|
|
137
141
|
close()
|
|
138
142
|
break
|
|
@@ -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: {
|
|
@@ -80,8 +82,8 @@ export const styles = css.create({
|
|
|
80
82
|
display: 'flex',
|
|
81
83
|
alignItems: 'center',
|
|
82
84
|
gap: spacing.sm,
|
|
83
|
-
paddingTop:
|
|
84
|
-
paddingBottom:
|
|
85
|
+
paddingTop: microSpacing.px6,
|
|
86
|
+
paddingBottom: microSpacing.px6,
|
|
85
87
|
paddingLeft: spacing.md,
|
|
86
88
|
paddingRight: spacing.md,
|
|
87
89
|
fontFamily: typography.fontFamily,
|
|
@@ -104,7 +106,7 @@ export const styles = css.create({
|
|
|
104
106
|
textAlign: 'left' as const,
|
|
105
107
|
outlineWidth: {
|
|
106
108
|
default: 0,
|
|
107
|
-
':focus-visible':
|
|
109
|
+
':focus-visible': borders.focusRing,
|
|
108
110
|
},
|
|
109
111
|
outlineStyle: {
|
|
110
112
|
default: 'none',
|
|
@@ -125,7 +127,7 @@ export const styles = css.create({
|
|
|
125
127
|
position: 'absolute',
|
|
126
128
|
left: 0,
|
|
127
129
|
top: '50%',
|
|
128
|
-
width:
|
|
130
|
+
width: sizes.navMarkerW,
|
|
129
131
|
height: 0,
|
|
130
132
|
transform: 'translateY(-50%)',
|
|
131
133
|
borderTopRightRadius: radii.full,
|
|
@@ -136,15 +138,15 @@ export const styles = css.create({
|
|
|
136
138
|
transitionTimingFunction: easing.standard,
|
|
137
139
|
},
|
|
138
140
|
markerActive: {
|
|
139
|
-
height:
|
|
141
|
+
height: sizes.navMarkerH,
|
|
140
142
|
},
|
|
141
143
|
itemIcon: {
|
|
142
144
|
display: 'inline-flex',
|
|
143
145
|
alignItems: 'center',
|
|
144
146
|
justifyContent: 'center',
|
|
145
147
|
flexShrink: 0,
|
|
146
|
-
width:
|
|
147
|
-
height:
|
|
148
|
+
width: sizes.indicator,
|
|
149
|
+
height: sizes.indicator,
|
|
148
150
|
},
|
|
149
151
|
itemLabel: {
|
|
150
152
|
flexGrow: 1,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {html} from 'react-strict-dom'
|
|
2
2
|
import {styles} from './styles.css'
|
|
3
|
+
import {visuallyHidden} from '../../styles/visually-hidden.css'
|
|
3
4
|
|
|
4
5
|
export type SpinnerSize = 'sm' | 'md' | 'lg'
|
|
5
6
|
|
|
@@ -18,7 +19,7 @@ export function Spinner({size = 'md', label = 'Loading'}: SpinnerProps) {
|
|
|
18
19
|
return (
|
|
19
20
|
<html.div role="status" style={styles.root}>
|
|
20
21
|
<html.div style={[styles.spinner, sizeMap[size]]} aria-hidden />
|
|
21
|
-
<html.span style={styles.srOnly}>{label}</html.span>
|
|
22
|
+
<html.span style={[visuallyHidden.base, styles.srOnly]}>{label}</html.span>
|
|
22
23
|
</html.div>
|
|
23
24
|
)
|
|
24
25
|
}
|