@dxos/react-ui-searchlist 0.8.4-main.84f28bd → 0.8.4-main.ae835ea
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/lib/browser/index.mjs +285 -139
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +285 -139
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Combobox/Combobox.d.ts +44 -0
- package/dist/types/src/components/Combobox/Combobox.d.ts.map +1 -0
- package/dist/types/src/components/Combobox/Combobox.stories.d.ts +21 -0
- package/dist/types/src/components/Combobox/Combobox.stories.d.ts.map +1 -0
- package/dist/types/src/components/Combobox/index.d.ts +2 -0
- package/dist/types/src/components/Combobox/index.d.ts.map +1 -0
- package/dist/types/src/components/Listbox/Listbox.d.ts +31 -0
- package/dist/types/src/components/Listbox/Listbox.d.ts.map +1 -0
- package/dist/types/src/components/Listbox/Listbox.stories.d.ts +21 -0
- package/dist/types/src/components/Listbox/Listbox.stories.d.ts.map +1 -0
- package/dist/types/src/components/Listbox/index.d.ts +2 -0
- package/dist/types/src/components/Listbox/index.d.ts.map +1 -0
- package/dist/types/src/components/{SearchList.d.ts → SearchList/SearchList.d.ts} +7 -27
- package/dist/types/src/components/SearchList/SearchList.d.ts.map +1 -0
- package/dist/types/src/components/SearchList/SearchList.stories.d.ts +25 -0
- package/dist/types/src/components/SearchList/SearchList.stories.d.ts.map +1 -0
- package/dist/types/src/components/SearchList/index.d.ts +2 -0
- package/dist/types/src/components/SearchList/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +2 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -16
- package/src/components/Combobox/Combobox.stories.tsx +57 -0
- package/src/components/Combobox/Combobox.tsx +335 -0
- package/src/components/Combobox/index.ts +5 -0
- package/src/components/Listbox/Listbox.stories.tsx +53 -0
- package/src/components/Listbox/Listbox.tsx +209 -0
- package/src/components/Listbox/index.ts +5 -0
- package/src/components/SearchList/SearchList.stories.tsx +64 -0
- package/src/components/SearchList/SearchList.tsx +163 -0
- package/src/components/SearchList/index.ts +5 -0
- package/src/components/index.ts +2 -0
- package/src/index.ts +0 -1
- package/src/translations.ts +3 -1
- package/dist/types/src/components/SearchList.d.ts.map +0 -1
- package/dist/types/src/components/SearchList.stories.d.ts +0 -15
- package/dist/types/src/components/SearchList.stories.d.ts.map +0 -1
- package/dist/types/src/composites/PopoverCombobox.d.ts +0 -32
- package/dist/types/src/composites/PopoverCombobox.d.ts.map +0 -1
- package/dist/types/src/composites/PopoverCombobox.stories.d.ts +0 -28
- package/dist/types/src/composites/PopoverCombobox.stories.d.ts.map +0 -1
- package/dist/types/src/composites/index.d.ts +0 -2
- package/dist/types/src/composites/index.d.ts.map +0 -1
- package/src/components/SearchList.stories.tsx +0 -47
- package/src/components/SearchList.tsx +0 -250
- package/src/composites/PopoverCombobox.stories.tsx +0 -44
- package/src/composites/PopoverCombobox.tsx +0 -186
- package/src/composites/index.ts +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-searchlist",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.ae835ea",
|
|
4
4
|
"description": "A themed ⌘K-style combobox component, triggered by a button (or keyboard shortcut), where values are queried only within the invoked modal.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
+
"source": "./src/index.ts",
|
|
13
14
|
"types": "./dist/types/src/index.d.ts",
|
|
14
15
|
"browser": "./dist/lib/browser/index.mjs",
|
|
15
16
|
"node": "./dist/lib/node-esm/index.mjs"
|
|
@@ -24,29 +25,29 @@
|
|
|
24
25
|
"src"
|
|
25
26
|
],
|
|
26
27
|
"dependencies": {
|
|
28
|
+
"@fluentui/react-tabster": "^9.24.2",
|
|
27
29
|
"@preact-signals/safe-react": "^0.9.0",
|
|
30
|
+
"@radix-ui/react-compose-refs": "1.1.1",
|
|
28
31
|
"@radix-ui/react-context": "1.1.1",
|
|
29
32
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
30
33
|
"cmdk": "^0.2.0"
|
|
31
34
|
},
|
|
32
35
|
"devDependencies": {
|
|
33
|
-
"@
|
|
34
|
-
"@types/react": "~
|
|
35
|
-
"
|
|
36
|
-
"react": "~
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/storybook-utils": "0.8.4-main.84f28bd"
|
|
36
|
+
"@types/react": "~19.2.2",
|
|
37
|
+
"@types/react-dom": "~19.2.2",
|
|
38
|
+
"react": "~19.2.0",
|
|
39
|
+
"react-dom": "~19.2.0",
|
|
40
|
+
"vite": "7.1.9",
|
|
41
|
+
"@dxos/random": "0.8.4-main.ae835ea",
|
|
42
|
+
"@dxos/react-ui": "0.8.4-main.ae835ea",
|
|
43
|
+
"@dxos/react-ui-theme": "0.8.4-main.ae835ea",
|
|
44
|
+
"@dxos/storybook-utils": "0.8.4-main.ae835ea"
|
|
43
45
|
},
|
|
44
46
|
"peerDependencies": {
|
|
45
|
-
"
|
|
46
|
-
"react": "
|
|
47
|
-
"react-
|
|
48
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
49
|
-
"@dxos/react-ui-theme": "0.8.4-main.84f28bd"
|
|
47
|
+
"react": "^19.0.0",
|
|
48
|
+
"react-dom": "^19.0.0",
|
|
49
|
+
"@dxos/react-ui": "0.8.4-main.ae835ea",
|
|
50
|
+
"@dxos/react-ui-theme": "0.8.4-main.ae835ea"
|
|
50
51
|
},
|
|
51
52
|
"publishConfig": {
|
|
52
53
|
"access": "public"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { faker } from '@dxos/random';
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
|
|
11
|
+
import { translations } from '../../translations';
|
|
12
|
+
|
|
13
|
+
import { Combobox } from './Combobox';
|
|
14
|
+
|
|
15
|
+
faker.seed(1234);
|
|
16
|
+
|
|
17
|
+
const items = faker.helpers.uniqueArray(faker.commerce.productName, 16).sort();
|
|
18
|
+
|
|
19
|
+
const DefaultStory = () => {
|
|
20
|
+
return (
|
|
21
|
+
<Combobox.Root
|
|
22
|
+
placeholder='Nothing selected'
|
|
23
|
+
onValueChange={(value) => {
|
|
24
|
+
console.log('[Combobox.Root.onValueChange]', value);
|
|
25
|
+
}}
|
|
26
|
+
>
|
|
27
|
+
<Combobox.Trigger />
|
|
28
|
+
<Combobox.Content filter={(value, search) => (value.includes(search) ? 1 : 0)}>
|
|
29
|
+
<Combobox.Input placeholder='Search...' />
|
|
30
|
+
<Combobox.List>
|
|
31
|
+
{items.map((value) => (
|
|
32
|
+
<Combobox.Item key={value}>{value}</Combobox.Item>
|
|
33
|
+
))}
|
|
34
|
+
</Combobox.List>
|
|
35
|
+
<Combobox.Arrow />
|
|
36
|
+
</Combobox.Content>
|
|
37
|
+
</Combobox.Root>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const meta = {
|
|
42
|
+
title: 'ui/react-ui-searchlist/Combobox',
|
|
43
|
+
component: Combobox.Root as any,
|
|
44
|
+
render: DefaultStory,
|
|
45
|
+
decorators: [withTheme, withLayout({ container: 'column', classNames: 'p-2' })],
|
|
46
|
+
parameters: {
|
|
47
|
+
translations,
|
|
48
|
+
},
|
|
49
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
50
|
+
|
|
51
|
+
export default meta;
|
|
52
|
+
|
|
53
|
+
type Story = StoryObj<typeof meta>;
|
|
54
|
+
|
|
55
|
+
export const Default: Story = {
|
|
56
|
+
args: {},
|
|
57
|
+
};
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createContext } from '@radix-ui/react-context';
|
|
6
|
+
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
7
|
+
import React, { type PropsWithChildren, forwardRef, useCallback } from 'react';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
Button,
|
|
11
|
+
type ButtonProps,
|
|
12
|
+
Icon,
|
|
13
|
+
Popover,
|
|
14
|
+
type PopoverArrowProps,
|
|
15
|
+
type PopoverContentProps,
|
|
16
|
+
type PopoverVirtualTriggerProps,
|
|
17
|
+
} from '@dxos/react-ui';
|
|
18
|
+
import { useId } from '@dxos/react-ui';
|
|
19
|
+
import { mx, staticPlaceholderText } from '@dxos/react-ui-theme';
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
SearchList,
|
|
23
|
+
type SearchListContentProps,
|
|
24
|
+
type SearchListEmptyProps,
|
|
25
|
+
type SearchListInputProps,
|
|
26
|
+
type SearchListItemProps,
|
|
27
|
+
type SearchListRootProps,
|
|
28
|
+
} from '../SearchList';
|
|
29
|
+
|
|
30
|
+
const COMBOBOX_NAME = 'Combobox';
|
|
31
|
+
const COMBOBOX_CONTENT_NAME = 'ComboboxContent';
|
|
32
|
+
const COMBOBOX_ITEM_NAME = 'ComboboxItem';
|
|
33
|
+
const COMBOBOX_TRIGGER_NAME = 'ComboboxTrigger';
|
|
34
|
+
|
|
35
|
+
//
|
|
36
|
+
// Context
|
|
37
|
+
//
|
|
38
|
+
|
|
39
|
+
type ComboboxContextValue = {
|
|
40
|
+
modalId: string;
|
|
41
|
+
isCombobox: true;
|
|
42
|
+
placeholder?: string;
|
|
43
|
+
open: boolean;
|
|
44
|
+
onOpenChange: (nextOpen: boolean) => void;
|
|
45
|
+
value: string;
|
|
46
|
+
onValueChange: (nextValue: string) => void;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const [ComboboxProvider, useComboboxContext] = createContext<Partial<ComboboxContextValue>>(COMBOBOX_NAME, {});
|
|
50
|
+
|
|
51
|
+
//
|
|
52
|
+
// Root
|
|
53
|
+
//
|
|
54
|
+
|
|
55
|
+
type ComboboxRootProps = PropsWithChildren<
|
|
56
|
+
Partial<ComboboxContextValue & { modal: boolean; defaultOpen: boolean; defaultValue: string; placeholder: string }>
|
|
57
|
+
>;
|
|
58
|
+
|
|
59
|
+
const ComboboxRoot = ({
|
|
60
|
+
modal,
|
|
61
|
+
modalId: propsModalId,
|
|
62
|
+
open: propsOpen,
|
|
63
|
+
defaultOpen,
|
|
64
|
+
onOpenChange: propsOnOpenChange,
|
|
65
|
+
value: propsValue,
|
|
66
|
+
defaultValue,
|
|
67
|
+
onValueChange: propsOnValueChange,
|
|
68
|
+
placeholder,
|
|
69
|
+
children,
|
|
70
|
+
}: ComboboxRootProps) => {
|
|
71
|
+
const modalId = useId(COMBOBOX_NAME, propsModalId);
|
|
72
|
+
const [open = false, onOpenChange] = useControllableState({
|
|
73
|
+
prop: propsOpen,
|
|
74
|
+
onChange: propsOnOpenChange,
|
|
75
|
+
defaultProp: defaultOpen,
|
|
76
|
+
});
|
|
77
|
+
const [value = '', onValueChange] = useControllableState({
|
|
78
|
+
prop: propsValue,
|
|
79
|
+
onChange: propsOnValueChange,
|
|
80
|
+
defaultProp: defaultValue,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<Popover.Root open={open} onOpenChange={onOpenChange} modal={modal}>
|
|
85
|
+
<ComboboxProvider
|
|
86
|
+
isCombobox
|
|
87
|
+
modalId={modalId}
|
|
88
|
+
placeholder={placeholder}
|
|
89
|
+
open={open}
|
|
90
|
+
onOpenChange={onOpenChange}
|
|
91
|
+
value={value}
|
|
92
|
+
onValueChange={onValueChange}
|
|
93
|
+
>
|
|
94
|
+
{children}
|
|
95
|
+
</ComboboxProvider>
|
|
96
|
+
</Popover.Root>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
//
|
|
101
|
+
// ContentProps
|
|
102
|
+
//
|
|
103
|
+
|
|
104
|
+
type ComboboxContentProps = SearchListRootProps & PopoverContentProps;
|
|
105
|
+
|
|
106
|
+
const ComboboxContent = forwardRef<HTMLDivElement, ComboboxContentProps>(
|
|
107
|
+
(
|
|
108
|
+
{
|
|
109
|
+
side = 'bottom',
|
|
110
|
+
collisionPadding = 48,
|
|
111
|
+
sideOffset,
|
|
112
|
+
align,
|
|
113
|
+
alignOffset,
|
|
114
|
+
avoidCollisions,
|
|
115
|
+
collisionBoundary,
|
|
116
|
+
arrowPadding,
|
|
117
|
+
sticky,
|
|
118
|
+
hideWhenDetached,
|
|
119
|
+
onOpenAutoFocus,
|
|
120
|
+
onCloseAutoFocus,
|
|
121
|
+
onEscapeKeyDown,
|
|
122
|
+
onPointerDownOutside,
|
|
123
|
+
onFocusOutside,
|
|
124
|
+
onInteractOutside,
|
|
125
|
+
forceMount,
|
|
126
|
+
children,
|
|
127
|
+
classNames,
|
|
128
|
+
...props
|
|
129
|
+
},
|
|
130
|
+
forwardedRef,
|
|
131
|
+
) => {
|
|
132
|
+
const { modalId } = useComboboxContext(COMBOBOX_CONTENT_NAME);
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<Popover.Content
|
|
136
|
+
{...{
|
|
137
|
+
side,
|
|
138
|
+
sideOffset,
|
|
139
|
+
align,
|
|
140
|
+
alignOffset,
|
|
141
|
+
avoidCollisions,
|
|
142
|
+
collisionBoundary,
|
|
143
|
+
collisionPadding,
|
|
144
|
+
arrowPadding,
|
|
145
|
+
sticky,
|
|
146
|
+
hideWhenDetached,
|
|
147
|
+
onOpenAutoFocus,
|
|
148
|
+
onCloseAutoFocus,
|
|
149
|
+
onEscapeKeyDown,
|
|
150
|
+
onPointerDownOutside,
|
|
151
|
+
onFocusOutside,
|
|
152
|
+
onInteractOutside,
|
|
153
|
+
forceMount,
|
|
154
|
+
}}
|
|
155
|
+
classNames={[
|
|
156
|
+
'is-[--radix-popover-trigger-width] max-bs-[--radix-popover-content-available-height] grid grid-rows-[min-content_1fr]',
|
|
157
|
+
classNames,
|
|
158
|
+
]}
|
|
159
|
+
id={modalId}
|
|
160
|
+
ref={forwardedRef}
|
|
161
|
+
>
|
|
162
|
+
<SearchList.Root {...props} classNames='contents density-fine' role='none'>
|
|
163
|
+
{children}
|
|
164
|
+
</SearchList.Root>
|
|
165
|
+
</Popover.Content>
|
|
166
|
+
);
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
ComboboxContent.displayName = COMBOBOX_CONTENT_NAME;
|
|
171
|
+
|
|
172
|
+
//
|
|
173
|
+
// Trigger
|
|
174
|
+
//
|
|
175
|
+
|
|
176
|
+
type ComboboxTriggerProps = ButtonProps;
|
|
177
|
+
|
|
178
|
+
const ComboboxTrigger = forwardRef<HTMLButtonElement, ComboboxTriggerProps>(
|
|
179
|
+
({ children, onClick, ...props }, forwardedRef) => {
|
|
180
|
+
const { modalId, open, onOpenChange, placeholder, value } = useComboboxContext(COMBOBOX_TRIGGER_NAME);
|
|
181
|
+
const handleClick = useCallback(
|
|
182
|
+
(event: Parameters<Exclude<ButtonProps['onClick'], undefined>>[0]) => {
|
|
183
|
+
onClick?.(event);
|
|
184
|
+
onOpenChange?.(true);
|
|
185
|
+
},
|
|
186
|
+
[onClick, onOpenChange],
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<Popover.Trigger asChild>
|
|
191
|
+
<Button
|
|
192
|
+
{...props}
|
|
193
|
+
role='combobox'
|
|
194
|
+
aria-expanded={open}
|
|
195
|
+
aria-controls={modalId}
|
|
196
|
+
aria-haspopup='dialog'
|
|
197
|
+
onClick={handleClick}
|
|
198
|
+
ref={forwardedRef}
|
|
199
|
+
>
|
|
200
|
+
{children ?? (
|
|
201
|
+
<>
|
|
202
|
+
<span
|
|
203
|
+
className={mx('font-normal text-start flex-1 min-is-0 truncate mie-2', !value && staticPlaceholderText)}
|
|
204
|
+
>
|
|
205
|
+
{value || placeholder}
|
|
206
|
+
</span>
|
|
207
|
+
<Icon icon='ph--caret-down--bold' size={3} />
|
|
208
|
+
</>
|
|
209
|
+
)}
|
|
210
|
+
</Button>
|
|
211
|
+
</Popover.Trigger>
|
|
212
|
+
);
|
|
213
|
+
},
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
ComboboxTrigger.displayName = COMBOBOX_TRIGGER_NAME;
|
|
217
|
+
|
|
218
|
+
//
|
|
219
|
+
// VirtualTrigger
|
|
220
|
+
//
|
|
221
|
+
|
|
222
|
+
type ComboboxVirtualTriggerProps = PopoverVirtualTriggerProps;
|
|
223
|
+
|
|
224
|
+
const ComboboxVirtualTrigger = Popover.VirtualTrigger;
|
|
225
|
+
|
|
226
|
+
//
|
|
227
|
+
// Input
|
|
228
|
+
//
|
|
229
|
+
|
|
230
|
+
type ComboboxInputProps = SearchListInputProps;
|
|
231
|
+
|
|
232
|
+
const ComboboxInput = forwardRef<HTMLInputElement, ComboboxInputProps>(({ classNames, ...props }, forwardedRef) => {
|
|
233
|
+
return (
|
|
234
|
+
<SearchList.Input
|
|
235
|
+
{...props}
|
|
236
|
+
classNames={[
|
|
237
|
+
'mli-cardSpacingChrome mbs-cardSpacingChrome mbe-0 is-[calc(100%-2*var(--dx-cardSpacingChrome))]',
|
|
238
|
+
classNames,
|
|
239
|
+
]}
|
|
240
|
+
ref={forwardedRef}
|
|
241
|
+
/>
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
//
|
|
246
|
+
// List
|
|
247
|
+
//
|
|
248
|
+
|
|
249
|
+
type ComboboxListProps = SearchListContentProps;
|
|
250
|
+
|
|
251
|
+
const ComboboxList = forwardRef<HTMLDivElement, ComboboxListProps>(({ classNames, ...props }, forwardedRef) => {
|
|
252
|
+
return (
|
|
253
|
+
<SearchList.Content
|
|
254
|
+
{...props}
|
|
255
|
+
classNames={['min-bs-0 overflow-y-auto plb-cardSpacingChrome', classNames]}
|
|
256
|
+
ref={forwardedRef}
|
|
257
|
+
/>
|
|
258
|
+
);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
//
|
|
262
|
+
// Item
|
|
263
|
+
//
|
|
264
|
+
|
|
265
|
+
type ComboboxItemProps = SearchListItemProps;
|
|
266
|
+
|
|
267
|
+
const ComboboxItem = forwardRef<HTMLDivElement, ComboboxItemProps>(
|
|
268
|
+
({ classNames, onSelect, ...props }, forwardedRef) => {
|
|
269
|
+
const { onValueChange, onOpenChange } = useComboboxContext(COMBOBOX_ITEM_NAME);
|
|
270
|
+
const handleSelect = useCallback<NonNullable<SearchListItemProps['onSelect']>>(
|
|
271
|
+
(nextValue) => {
|
|
272
|
+
onSelect?.(nextValue);
|
|
273
|
+
onValueChange?.(nextValue);
|
|
274
|
+
onOpenChange?.(false);
|
|
275
|
+
},
|
|
276
|
+
[onSelect, onValueChange, onOpenChange],
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<SearchList.Item
|
|
281
|
+
{...props}
|
|
282
|
+
classNames={['mli-cardSpacingChrome pli-cardSpacingChrome', classNames]}
|
|
283
|
+
onSelect={handleSelect}
|
|
284
|
+
ref={forwardedRef}
|
|
285
|
+
/>
|
|
286
|
+
);
|
|
287
|
+
},
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
ComboboxItem.displayName = COMBOBOX_ITEM_NAME;
|
|
291
|
+
|
|
292
|
+
//
|
|
293
|
+
// Arrow
|
|
294
|
+
//
|
|
295
|
+
|
|
296
|
+
type ComboboxArrowProps = PopoverArrowProps;
|
|
297
|
+
|
|
298
|
+
const ComboboxArrow = Popover.Arrow;
|
|
299
|
+
|
|
300
|
+
//
|
|
301
|
+
// Empty
|
|
302
|
+
//
|
|
303
|
+
|
|
304
|
+
type ComboboxEmptyProps = SearchListEmptyProps;
|
|
305
|
+
|
|
306
|
+
const ComboboxEmpty = SearchList.Empty;
|
|
307
|
+
|
|
308
|
+
//
|
|
309
|
+
// Combobox
|
|
310
|
+
// https://www.w3.org/WAI/ARIA/apg/patterns/combobox
|
|
311
|
+
//
|
|
312
|
+
|
|
313
|
+
export const Combobox = {
|
|
314
|
+
Root: ComboboxRoot,
|
|
315
|
+
Content: ComboboxContent,
|
|
316
|
+
Trigger: ComboboxTrigger,
|
|
317
|
+
VirtualTrigger: ComboboxVirtualTrigger,
|
|
318
|
+
Input: ComboboxInput,
|
|
319
|
+
List: ComboboxList,
|
|
320
|
+
Item: ComboboxItem,
|
|
321
|
+
Arrow: ComboboxArrow,
|
|
322
|
+
Empty: ComboboxEmpty,
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
export type {
|
|
326
|
+
ComboboxRootProps,
|
|
327
|
+
ComboboxContentProps,
|
|
328
|
+
ComboboxTriggerProps,
|
|
329
|
+
ComboboxVirtualTriggerProps,
|
|
330
|
+
ComboboxInputProps,
|
|
331
|
+
ComboboxListProps,
|
|
332
|
+
ComboboxItemProps,
|
|
333
|
+
ComboboxArrowProps,
|
|
334
|
+
ComboboxEmptyProps,
|
|
335
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React, { useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { faker } from '@dxos/random';
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
|
|
11
|
+
import { translations } from '../../translations';
|
|
12
|
+
|
|
13
|
+
import { Listbox } from './Listbox';
|
|
14
|
+
|
|
15
|
+
faker.seed(1234);
|
|
16
|
+
|
|
17
|
+
type StoryItem = { value: string; label: string };
|
|
18
|
+
|
|
19
|
+
const options: StoryItem[] = faker.helpers.multiple(
|
|
20
|
+
() => ({ value: faker.string.uuid(), label: faker.commerce.productName() }) satisfies StoryItem,
|
|
21
|
+
{ count: 16 },
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const DefaultStory = () => {
|
|
25
|
+
const [selectedValue, setSelectedValue] = useState<string>();
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Listbox.Root value={selectedValue} onValueChange={setSelectedValue}>
|
|
29
|
+
{options.map((option) => (
|
|
30
|
+
<Listbox.Option key={option.value} value={option.value}>
|
|
31
|
+
<Listbox.OptionLabel>{option.label}</Listbox.OptionLabel>
|
|
32
|
+
<Listbox.OptionIndicator />
|
|
33
|
+
</Listbox.Option>
|
|
34
|
+
))}
|
|
35
|
+
</Listbox.Root>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const meta = {
|
|
40
|
+
title: 'ui/react-ui-searchlist/Listbox',
|
|
41
|
+
component: Listbox.Root,
|
|
42
|
+
render: DefaultStory,
|
|
43
|
+
decorators: [withTheme, withLayout({ container: 'column', classNames: 'p-2' })],
|
|
44
|
+
parameters: {
|
|
45
|
+
translations,
|
|
46
|
+
},
|
|
47
|
+
} satisfies Meta<typeof Listbox.Root>;
|
|
48
|
+
|
|
49
|
+
export default meta;
|
|
50
|
+
|
|
51
|
+
type Story = StoryObj<typeof meta>;
|
|
52
|
+
|
|
53
|
+
export const Default: Story = {};
|