@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
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useArrowNavigationGroup } from '@fluentui/react-tabster';
|
|
6
|
+
import { useComposedRefs } from '@radix-ui/react-compose-refs';
|
|
7
|
+
import { type Scope, createContextScope } from '@radix-ui/react-context';
|
|
8
|
+
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
9
|
+
import React, { type ComponentPropsWithRef, forwardRef, useCallback, useEffect, useRef } from 'react';
|
|
10
|
+
|
|
11
|
+
import { Icon, type IconProps, type ThemedClassName } from '@dxos/react-ui';
|
|
12
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
13
|
+
|
|
14
|
+
import { commandItem, searchListItem } from '../SearchList';
|
|
15
|
+
|
|
16
|
+
const LISTBOX_NAME = 'Listbox';
|
|
17
|
+
const LISTBOX_OPTION_NAME = 'ListboxOption';
|
|
18
|
+
const LISTBOX_OPTION_LABEL_NAME = 'ListboxOptionLabel';
|
|
19
|
+
const LISTBOX_OPTION_INDICATOR_NAME = 'ListboxOptionIndicator';
|
|
20
|
+
|
|
21
|
+
//
|
|
22
|
+
// Context
|
|
23
|
+
//
|
|
24
|
+
|
|
25
|
+
type ListboxScopedProps<P> = P & { __listboxScope?: Scope };
|
|
26
|
+
type ListboxOptionScopedProps<P> = P & { __listboxOptionScope?: Scope };
|
|
27
|
+
|
|
28
|
+
type ListboxOptionProps = ThemedClassName<ComponentPropsWithRef<'li'>> & {
|
|
29
|
+
value: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const [createListboxContext, createListboxScope] = createContextScope(LISTBOX_NAME, []);
|
|
33
|
+
const [createListboxOptionContext, createListboxOptionScope] = createContextScope(LISTBOX_OPTION_NAME, [
|
|
34
|
+
createListboxScope,
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
type ListboxContextValue = {
|
|
38
|
+
selectedValue: string | undefined;
|
|
39
|
+
onValueChange: (value: string) => void;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type ListboxOptionContextValue = {
|
|
43
|
+
value: string;
|
|
44
|
+
isSelected: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const [ListboxProvider, useListboxContext] = createListboxContext<ListboxContextValue>(LISTBOX_NAME);
|
|
48
|
+
const [ListboxOptionProvider, useListboxOptionContext] =
|
|
49
|
+
createListboxOptionContext<ListboxOptionContextValue>(LISTBOX_OPTION_NAME);
|
|
50
|
+
|
|
51
|
+
//
|
|
52
|
+
// Root
|
|
53
|
+
//
|
|
54
|
+
|
|
55
|
+
type ListboxRootProps = ThemedClassName<ComponentPropsWithRef<'ul'>> & {
|
|
56
|
+
value?: string;
|
|
57
|
+
defaultValue?: string;
|
|
58
|
+
onValueChange?: (value: string) => void;
|
|
59
|
+
autoFocus?: boolean;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// TODO(thure): Note that this overlaps significantly with the the `SelectableListbox` story of `List.tsx` in `react-ui`,
|
|
63
|
+
// making this an exemplar of `List` specifying standard `role="listbox"` interactivity, though it is here because it
|
|
64
|
+
// coheres with SearchList’s styles and norms. This can be promoted to `react-ui`, but doing so should involve clearing
|
|
65
|
+
// the technical- and design-debt in its `List` component.
|
|
66
|
+
const ListboxRoot = forwardRef<HTMLUListElement, ListboxRootProps>(
|
|
67
|
+
(props: ListboxScopedProps<ListboxRootProps>, forwardedRef) => {
|
|
68
|
+
const {
|
|
69
|
+
__listboxScope,
|
|
70
|
+
children,
|
|
71
|
+
classNames,
|
|
72
|
+
value: propsValue,
|
|
73
|
+
defaultValue,
|
|
74
|
+
onValueChange,
|
|
75
|
+
autoFocus,
|
|
76
|
+
...rootProps
|
|
77
|
+
} = props;
|
|
78
|
+
|
|
79
|
+
const arrowGroup = useArrowNavigationGroup({ axis: 'vertical' });
|
|
80
|
+
const ref = useRef<HTMLUListElement | null>(null);
|
|
81
|
+
const rootRef = useComposedRefs<HTMLUListElement>(ref, forwardedRef);
|
|
82
|
+
|
|
83
|
+
const [selectedValue, setSelectedValue] = useControllableState({
|
|
84
|
+
prop: propsValue,
|
|
85
|
+
defaultProp: defaultValue,
|
|
86
|
+
onChange: onValueChange,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const handleValueChange = (value: string) => {
|
|
90
|
+
setSelectedValue(value);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
// Autofocus the selected option on mount using querySelector
|
|
95
|
+
(ref.current?.querySelector('[aria-selected="true"]') as HTMLLIElement)?.focus();
|
|
96
|
+
}, [autoFocus]);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<ListboxProvider scope={__listboxScope} selectedValue={selectedValue} onValueChange={handleValueChange}>
|
|
100
|
+
<ul
|
|
101
|
+
role='listbox'
|
|
102
|
+
{...rootProps}
|
|
103
|
+
className={mx('is-full p-cardSpacingChrome', classNames)}
|
|
104
|
+
ref={rootRef}
|
|
105
|
+
{...arrowGroup}
|
|
106
|
+
>
|
|
107
|
+
{children}
|
|
108
|
+
</ul>
|
|
109
|
+
</ListboxProvider>
|
|
110
|
+
);
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
ListboxRoot.displayName = LISTBOX_NAME;
|
|
115
|
+
|
|
116
|
+
//
|
|
117
|
+
// Option
|
|
118
|
+
//
|
|
119
|
+
|
|
120
|
+
const ListboxOption = forwardRef<HTMLLIElement, ListboxOptionProps>(
|
|
121
|
+
(props: ListboxScopedProps<ListboxOptionProps>, forwardedRef) => {
|
|
122
|
+
const { __listboxScope, children, classNames, value, ...rootProps } = props;
|
|
123
|
+
const { selectedValue, onValueChange } = useListboxContext(LISTBOX_OPTION_NAME, __listboxScope);
|
|
124
|
+
|
|
125
|
+
const isSelected = selectedValue === value;
|
|
126
|
+
|
|
127
|
+
const handleSelect = useCallback(() => {
|
|
128
|
+
onValueChange(value);
|
|
129
|
+
}, [value, onValueChange]);
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<ListboxOptionProvider scope={__listboxScope} value={value} isSelected={isSelected}>
|
|
133
|
+
<li
|
|
134
|
+
role='option'
|
|
135
|
+
{...rootProps}
|
|
136
|
+
aria-selected={isSelected}
|
|
137
|
+
tabIndex={0}
|
|
138
|
+
className={mx('dx-focus-ring', commandItem, searchListItem, classNames)}
|
|
139
|
+
onClick={handleSelect}
|
|
140
|
+
onKeyDown={({ key }) => {
|
|
141
|
+
if (['Enter', ' '].includes(key)) {
|
|
142
|
+
handleSelect();
|
|
143
|
+
}
|
|
144
|
+
}}
|
|
145
|
+
ref={forwardedRef}
|
|
146
|
+
>
|
|
147
|
+
{children}
|
|
148
|
+
</li>
|
|
149
|
+
</ListboxOptionProvider>
|
|
150
|
+
);
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
ListboxOption.displayName = LISTBOX_OPTION_NAME;
|
|
155
|
+
|
|
156
|
+
//
|
|
157
|
+
// OptionLabel
|
|
158
|
+
//
|
|
159
|
+
|
|
160
|
+
const ListboxOptionLabel = forwardRef<HTMLDivElement, ThemedClassName<ComponentPropsWithRef<'div'>>>(
|
|
161
|
+
({ children, classNames, ...rootProps }, forwardedRef) => {
|
|
162
|
+
return (
|
|
163
|
+
<span {...rootProps} className={mx('grow truncate', classNames)} ref={forwardedRef}>
|
|
164
|
+
{children}
|
|
165
|
+
</span>
|
|
166
|
+
);
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
ListboxOptionLabel.displayName = LISTBOX_OPTION_LABEL_NAME;
|
|
171
|
+
|
|
172
|
+
type ListboxOptionIndicatorProps = Omit<IconProps, 'icon'> & Partial<Pick<IconProps, 'icon'>>;
|
|
173
|
+
|
|
174
|
+
//
|
|
175
|
+
// OptionIndicator
|
|
176
|
+
//
|
|
177
|
+
|
|
178
|
+
const ListboxOptionIndicator = forwardRef<SVGSVGElement, ListboxOptionIndicatorProps>(
|
|
179
|
+
(props: ListboxOptionScopedProps<ListboxOptionIndicatorProps>, forwardedRef) => {
|
|
180
|
+
const { __listboxOptionScope, classNames, ...rootProps } = props;
|
|
181
|
+
const { isSelected } = useListboxOptionContext(LISTBOX_OPTION_INDICATOR_NAME, __listboxOptionScope);
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<Icon
|
|
185
|
+
icon='ph--check--regular'
|
|
186
|
+
{...rootProps}
|
|
187
|
+
classNames={mx(!isSelected && 'invisible', classNames)}
|
|
188
|
+
ref={forwardedRef}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
ListboxOptionIndicator.displayName = LISTBOX_OPTION_INDICATOR_NAME;
|
|
195
|
+
|
|
196
|
+
//
|
|
197
|
+
// Listbox
|
|
198
|
+
//
|
|
199
|
+
|
|
200
|
+
export const Listbox = {
|
|
201
|
+
Root: ListboxRoot,
|
|
202
|
+
Option: ListboxOption,
|
|
203
|
+
OptionLabel: ListboxOptionLabel,
|
|
204
|
+
OptionIndicator: ListboxOptionIndicator,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export { createListboxScope, useListboxContext };
|
|
208
|
+
|
|
209
|
+
export type { ListboxRootProps, ListboxOptionProps, ListboxScopedProps };
|
|
@@ -0,0 +1,64 @@
|
|
|
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 { SearchList } from './SearchList';
|
|
14
|
+
|
|
15
|
+
faker.seed(1234);
|
|
16
|
+
|
|
17
|
+
type StoryItems = Record<string, string>;
|
|
18
|
+
|
|
19
|
+
const defaultItems: StoryItems = faker.helpers
|
|
20
|
+
.uniqueArray(faker.commerce.productName, 16)
|
|
21
|
+
.sort()
|
|
22
|
+
.reduce((acc: StoryItems, label) => {
|
|
23
|
+
acc[faker.string.uuid()] = label;
|
|
24
|
+
return acc;
|
|
25
|
+
}, {});
|
|
26
|
+
|
|
27
|
+
type StoryProps = {
|
|
28
|
+
items: StoryItems;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const DefaultStory = ({ items = defaultItems }: StoryProps) => {
|
|
32
|
+
return (
|
|
33
|
+
<SearchList.Root filter={(value, search) => (items[value].toLowerCase().includes(search.toLowerCase()) ? 1 : 0)}>
|
|
34
|
+
<SearchList.Input />
|
|
35
|
+
<SearchList.Content>
|
|
36
|
+
{Object.entries(items).map(([value, label]) => (
|
|
37
|
+
<SearchList.Item
|
|
38
|
+
key={value}
|
|
39
|
+
value={value}
|
|
40
|
+
onSelect={(value) => console.log('[SearchList.Item.onSelect]', value)}
|
|
41
|
+
>
|
|
42
|
+
{label}
|
|
43
|
+
</SearchList.Item>
|
|
44
|
+
))}
|
|
45
|
+
</SearchList.Content>
|
|
46
|
+
</SearchList.Root>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const meta = {
|
|
51
|
+
title: 'ui/react-ui-searchlist/SearchList',
|
|
52
|
+
component: SearchList.Root as any,
|
|
53
|
+
render: DefaultStory,
|
|
54
|
+
decorators: [withTheme, withLayout({ container: 'column', classNames: 'p-2' })],
|
|
55
|
+
parameters: {
|
|
56
|
+
translations,
|
|
57
|
+
},
|
|
58
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
59
|
+
|
|
60
|
+
export default meta;
|
|
61
|
+
|
|
62
|
+
type Story = StoryObj<typeof meta>;
|
|
63
|
+
|
|
64
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { CommandEmpty, CommandInput, CommandItem, CommandList, CommandRoot } from 'cmdk';
|
|
6
|
+
import React, { type ComponentPropsWithRef, forwardRef } from 'react';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
type TextInputProps,
|
|
10
|
+
type ThemedClassName,
|
|
11
|
+
useDensityContext,
|
|
12
|
+
useElevationContext,
|
|
13
|
+
useThemeContext,
|
|
14
|
+
useTranslation,
|
|
15
|
+
} from '@dxos/react-ui';
|
|
16
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
17
|
+
|
|
18
|
+
import { translationKey } from '../../translations';
|
|
19
|
+
|
|
20
|
+
const commandItem = 'flex items-center overflow-hidden';
|
|
21
|
+
const searchListItem =
|
|
22
|
+
'plb-1 pli-2 rounded-sm select-none cursor-pointer data-[selected]:bg-hoverOverlay hover:bg-hoverOverlay';
|
|
23
|
+
|
|
24
|
+
const SEARCHLIST_NAME = 'SearchList';
|
|
25
|
+
const SEARCHLIST_ITEM_NAME = 'SearchListItem';
|
|
26
|
+
|
|
27
|
+
//
|
|
28
|
+
// Root
|
|
29
|
+
//
|
|
30
|
+
|
|
31
|
+
type SearchListVariant = 'list' | 'menu' | 'listbox';
|
|
32
|
+
|
|
33
|
+
type SearchListRootProps = ThemedClassName<ComponentPropsWithRef<typeof CommandRoot>> & {
|
|
34
|
+
variant?: SearchListVariant;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const SearchListRoot = forwardRef<HTMLDivElement, SearchListRootProps>(
|
|
38
|
+
({ children, classNames, ...props }, forwardedRef) => {
|
|
39
|
+
return (
|
|
40
|
+
<CommandRoot {...props} className={mx(classNames)} ref={forwardedRef}>
|
|
41
|
+
{children}
|
|
42
|
+
</CommandRoot>
|
|
43
|
+
);
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
SearchListRoot.displayName = SEARCHLIST_NAME;
|
|
48
|
+
|
|
49
|
+
//
|
|
50
|
+
// Input
|
|
51
|
+
//
|
|
52
|
+
|
|
53
|
+
type CommandInputPrimitiveProps = ComponentPropsWithRef<typeof CommandInput>;
|
|
54
|
+
|
|
55
|
+
// TODO: Harmonize with other inputs’ `onChange` prop.
|
|
56
|
+
type SearchListInputProps = Omit<TextInputProps, 'value' | 'defaultValue' | 'onChange'> &
|
|
57
|
+
Pick<CommandInputPrimitiveProps, 'value' | 'defaultValue' | 'onValueChange'>;
|
|
58
|
+
|
|
59
|
+
const SearchListInput = forwardRef<HTMLInputElement, SearchListInputProps>(
|
|
60
|
+
({ classNames, density: propsDensity, elevation: propsElevation, variant, ...props }, forwardedRef) => {
|
|
61
|
+
const { t } = useTranslation(translationKey);
|
|
62
|
+
const placeholder = props.placeholder ?? t('search.placeholder');
|
|
63
|
+
|
|
64
|
+
// TODO(thure): Keep this in-sync with `TextInput`, or submit a PR for `cmdk` to support `asChild` so we don’t have to.
|
|
65
|
+
const { hasIosKeyboard } = useThemeContext();
|
|
66
|
+
const { tx } = useThemeContext();
|
|
67
|
+
const density = useDensityContext(propsDensity);
|
|
68
|
+
const elevation = useElevationContext(propsElevation);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<CommandInput
|
|
72
|
+
{...props}
|
|
73
|
+
placeholder={placeholder}
|
|
74
|
+
className={tx(
|
|
75
|
+
'input.input',
|
|
76
|
+
'input',
|
|
77
|
+
{
|
|
78
|
+
variant,
|
|
79
|
+
disabled: props.disabled,
|
|
80
|
+
density,
|
|
81
|
+
elevation,
|
|
82
|
+
},
|
|
83
|
+
'mbe-cardSpacingBlock',
|
|
84
|
+
classNames,
|
|
85
|
+
)}
|
|
86
|
+
{...(props.autoFocus && !hasIosKeyboard && { autoFocus: true })}
|
|
87
|
+
ref={forwardedRef}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
//
|
|
94
|
+
// Content
|
|
95
|
+
//
|
|
96
|
+
|
|
97
|
+
type SearchListContentProps = ThemedClassName<ComponentPropsWithRef<typeof CommandList>>;
|
|
98
|
+
|
|
99
|
+
const SearchListContent = forwardRef<HTMLDivElement, SearchListContentProps>(
|
|
100
|
+
({ children, classNames, ...props }, forwardedRef) => {
|
|
101
|
+
return (
|
|
102
|
+
<CommandList {...props} className={mx(classNames)} ref={forwardedRef}>
|
|
103
|
+
{children}
|
|
104
|
+
</CommandList>
|
|
105
|
+
);
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
//
|
|
110
|
+
// Empty
|
|
111
|
+
//
|
|
112
|
+
|
|
113
|
+
type SearchListEmptyProps = ThemedClassName<ComponentPropsWithRef<typeof CommandEmpty>>;
|
|
114
|
+
|
|
115
|
+
const SearchListEmpty = forwardRef<HTMLDivElement, SearchListEmptyProps>(
|
|
116
|
+
({ children, classNames, ...props }, forwardedRef) => {
|
|
117
|
+
return (
|
|
118
|
+
<CommandEmpty {...props} className={mx(classNames)} ref={forwardedRef}>
|
|
119
|
+
{children}
|
|
120
|
+
</CommandEmpty>
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
//
|
|
126
|
+
// Item
|
|
127
|
+
//
|
|
128
|
+
|
|
129
|
+
type SearchListItemProps = ThemedClassName<ComponentPropsWithRef<typeof CommandItem>>;
|
|
130
|
+
|
|
131
|
+
const SearchListItem = forwardRef<HTMLDivElement, SearchListItemProps>(
|
|
132
|
+
({ children, classNames, ...props }, forwardedRef) => {
|
|
133
|
+
return (
|
|
134
|
+
<CommandItem {...props} className={mx(searchListItem, classNames)} ref={forwardedRef}>
|
|
135
|
+
{children}
|
|
136
|
+
</CommandItem>
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
SearchListItem.displayName = SEARCHLIST_ITEM_NAME;
|
|
142
|
+
|
|
143
|
+
//
|
|
144
|
+
// SearchList
|
|
145
|
+
//
|
|
146
|
+
|
|
147
|
+
export const SearchList = {
|
|
148
|
+
Root: SearchListRoot,
|
|
149
|
+
Input: SearchListInput,
|
|
150
|
+
Content: SearchListContent,
|
|
151
|
+
Empty: SearchListEmpty,
|
|
152
|
+
Item: SearchListItem,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export type {
|
|
156
|
+
SearchListRootProps,
|
|
157
|
+
SearchListInputProps,
|
|
158
|
+
SearchListContentProps,
|
|
159
|
+
SearchListEmptyProps,
|
|
160
|
+
SearchListItemProps,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export { commandItem, searchListItem };
|
package/src/components/index.ts
CHANGED
package/src/index.ts
CHANGED
package/src/translations.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SearchList.d.ts","sourceRoot":"","sources":["../../../../src/components/SearchList.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AACzF,OAAO,KAAK,EAAE,EAAE,KAAK,qBAAqB,EAAc,KAAK,iBAAiB,EAAe,MAAM,OAAO,CAAC;AAE3G,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EAKrB,MAAM,gBAAgB,CAAC;AAGxB,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAErD,KAAK,mBAAmB,GAAG,eAAe,CAAC,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,GAAG;IACtF,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AASF,KAAK,iBAAiB,GAAG,iBAAiB,CACxC,OAAO,CAAC,oBAAoB,GAAG;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CACpG,CAAC;AAcF,KAAK,0BAA0B,GAAG,qBAAqB,CAAC,OAAO,YAAY,CAAC,CAAC;AAG7E,KAAK,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,cAAc,GAAG,UAAU,CAAC,GACrF,IAAI,CAAC,0BAA0B,EAAE,OAAO,GAAG,eAAe,GAAG,cAAc,CAAC,CAAC;AAgC/E,KAAK,sBAAsB,GAAG,eAAe,CAAC,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC;AAYzF,KAAK,oBAAoB,GAAG,eAAe,CAAC,qBAAqB,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC;AAYxF,KAAK,mBAAmB,GAAG,eAAe,CAAC,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC;AAmEtF,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAuCxC,eAAO,MAAM,UAAU;;;;;;CAMtB,CAAC;AAEF,eAAO,MAAM,QAAQ;;+LA5ElB,iBAAiB;;;;;CAgFnB,CAAC;AAEF,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,GACrB,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import '@dxos-theme';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
type StoryItems = Record<string, string>;
|
|
4
|
-
declare const _default: {
|
|
5
|
-
title: string;
|
|
6
|
-
component: React.FC<{
|
|
7
|
-
items: StoryItems;
|
|
8
|
-
}>;
|
|
9
|
-
decorators: import("@storybook/react").Decorator[];
|
|
10
|
-
};
|
|
11
|
-
export default _default;
|
|
12
|
-
export declare const Default: {
|
|
13
|
-
args: {};
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=SearchList.stories.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SearchList.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/SearchList.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,KAAkB,MAAM,OAAO,CAAC;AAOvC,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;;;eAUN,UAAU;;;;AAe7C,wBAIE;AAEF,eAAO,MAAM,OAAO;;CAEnB,CAAC"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { type PopoverArrowProps, type PopoverContentProps, type PopoverViewportProps, type PopoverVirtualTriggerProps } from '@dxos/react-ui';
|
|
3
|
-
import { type ComboboxRootProps, type ComboboxTriggerProps, type SearchListContentProps, type SearchListEmptyProps, type SearchListInputProps, type SearchListItemProps, type SearchListRootProps } from '../components';
|
|
4
|
-
type PopoverComboboxRootProps = ComboboxRootProps & {
|
|
5
|
-
modal?: boolean;
|
|
6
|
-
};
|
|
7
|
-
type PopoverComboboxContentProps = SearchListRootProps & PopoverContentProps;
|
|
8
|
-
type PopoverComboboxTriggerProps = ComboboxTriggerProps;
|
|
9
|
-
type PopoverComboboxVirtualTriggerProps = PopoverVirtualTriggerProps;
|
|
10
|
-
type PopoverComboboxInputProps = SearchListInputProps;
|
|
11
|
-
type PopoverComboboxListProps = SearchListContentProps & Pick<PopoverViewportProps, 'constrainBlock' | 'constrainInline'>;
|
|
12
|
-
type PopoverComboboxItemProps = SearchListItemProps;
|
|
13
|
-
type PopoverComboboxArrowProps = PopoverArrowProps;
|
|
14
|
-
type PopoverComboboxEmptyProps = SearchListEmptyProps;
|
|
15
|
-
export declare const PopoverCombobox: {
|
|
16
|
-
Root: ({ modal, children, open: propsOpen, onOpenChange: propsOnOpenChange, defaultOpen, ...props }: PopoverComboboxRootProps) => React.JSX.Element;
|
|
17
|
-
Content: React.ForwardRefExoticComponent<Omit<PopoverComboboxContentProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
18
|
-
Trigger: React.ForwardRefExoticComponent<Omit<import("@dxos/react-ui").ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
19
|
-
VirtualTrigger: {
|
|
20
|
-
(props: PopoverVirtualTriggerProps & {
|
|
21
|
-
__scopePopover?: import("@radix-ui/react-context").Scope;
|
|
22
|
-
}): React.JSX.Element;
|
|
23
|
-
displayName: string;
|
|
24
|
-
};
|
|
25
|
-
Input: React.ForwardRefExoticComponent<Omit<SearchListInputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
26
|
-
List: React.ForwardRefExoticComponent<Omit<PopoverComboboxListProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
27
|
-
Item: React.ForwardRefExoticComponent<Omit<SearchListItemProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
28
|
-
Arrow: React.ForwardRefExoticComponent<PopoverArrowProps & React.RefAttributes<SVGSVGElement>>;
|
|
29
|
-
Empty: React.ForwardRefExoticComponent<Omit<SearchListEmptyProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
30
|
-
};
|
|
31
|
-
export type { PopoverComboboxRootProps, PopoverComboboxContentProps, PopoverComboboxTriggerProps, PopoverComboboxVirtualTriggerProps, PopoverComboboxInputProps, PopoverComboboxListProps, PopoverComboboxItemProps, PopoverComboboxArrowProps, PopoverComboboxEmptyProps, };
|
|
32
|
-
//# sourceMappingURL=PopoverCombobox.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PopoverCombobox.d.ts","sourceRoot":"","sources":["../../../../src/composites/PopoverCombobox.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAChC,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAEzB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAEvB,KAAK,wBAAwB,GAAG,iBAAiB,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAwBxE,KAAK,2BAA2B,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAqE7E,KAAK,2BAA2B,GAAG,oBAAoB,CAAC;AAUxD,KAAK,kCAAkC,GAAG,0BAA0B,CAAC;AAIrE,KAAK,yBAAyB,GAAG,oBAAoB,CAAC;AAItD,KAAK,wBAAwB,GAAG,sBAAsB,GACpD,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,GAAG,iBAAiB,CAAC,CAAC;AAYnE,KAAK,wBAAwB,GAAG,mBAAmB,CAAC;AAIpD,KAAK,yBAAyB,GAAG,iBAAiB,CAAC;AAInD,KAAK,yBAAyB,GAAG,oBAAoB,CAAC;AAItD,eAAO,MAAM,eAAe;yGA/HzB,wBAAwB;;;;;;;;;;;;;;CAyI1B,CAAC;AAEF,YAAY,EACV,wBAAwB,EACxB,2BAA2B,EAC3B,2BAA2B,EAC3B,kCAAkC,EAClC,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,GAC1B,CAAC"}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import '@dxos-theme';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
declare const _default: {
|
|
4
|
-
title: string;
|
|
5
|
-
component: {
|
|
6
|
-
Root: ({ modal, children, open: propsOpen, onOpenChange: propsOnOpenChange, defaultOpen, ...props }: import("./PopoverCombobox").PopoverComboboxRootProps) => React.JSX.Element;
|
|
7
|
-
Content: React.ForwardRefExoticComponent<Omit<import("./PopoverCombobox").PopoverComboboxContentProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
-
Trigger: React.ForwardRefExoticComponent<Omit<import("@dxos/react-ui").ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
9
|
-
VirtualTrigger: {
|
|
10
|
-
(props: import("@dxos/react-ui").PopoverVirtualTriggerProps & {
|
|
11
|
-
__scopePopover?: import("@radix-ui/react-context").Scope;
|
|
12
|
-
}): React.JSX.Element;
|
|
13
|
-
displayName: string;
|
|
14
|
-
};
|
|
15
|
-
Input: React.ForwardRefExoticComponent<Omit<import("..").SearchListInputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
16
|
-
List: React.ForwardRefExoticComponent<Omit<import("./PopoverCombobox").PopoverComboboxListProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
17
|
-
Item: React.ForwardRefExoticComponent<Omit<import("..").SearchListItemProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
18
|
-
Arrow: React.ForwardRefExoticComponent<import("@dxos/react-ui").PopoverArrowProps & React.RefAttributes<SVGSVGElement>>;
|
|
19
|
-
Empty: React.ForwardRefExoticComponent<Omit<import("..").SearchListEmptyProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
20
|
-
};
|
|
21
|
-
render: () => React.JSX.Element;
|
|
22
|
-
decorators: import("@storybook/react").Decorator[];
|
|
23
|
-
};
|
|
24
|
-
export default _default;
|
|
25
|
-
export declare const Default: {
|
|
26
|
-
args: {};
|
|
27
|
-
};
|
|
28
|
-
//# sourceMappingURL=PopoverCombobox.stories.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PopoverCombobox.stories.d.ts","sourceRoot":"","sources":["../../../../src/composites/PopoverCombobox.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;AA4B1B,wBAKE;AAEF,eAAO,MAAM,OAAO;;CAEnB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/composites/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
|
-
import React, { type FC } from 'react';
|
|
8
|
-
|
|
9
|
-
import { faker } from '@dxos/random';
|
|
10
|
-
import { withTheme } from '@dxos/storybook-utils';
|
|
11
|
-
|
|
12
|
-
import { SearchList } from './SearchList';
|
|
13
|
-
|
|
14
|
-
type StoryItems = Record<string, string>;
|
|
15
|
-
|
|
16
|
-
const defaultItems: StoryItems = faker.helpers
|
|
17
|
-
.uniqueArray(faker.commerce.productName, 16)
|
|
18
|
-
.sort()
|
|
19
|
-
.reduce((acc: StoryItems, label) => {
|
|
20
|
-
acc[faker.string.uuid()] = label;
|
|
21
|
-
return acc;
|
|
22
|
-
}, {});
|
|
23
|
-
|
|
24
|
-
const SearchListStory: FC<{ items: StoryItems }> = ({ items = defaultItems }) => {
|
|
25
|
-
return (
|
|
26
|
-
<SearchList.Root filter={(value, search) => (items[value].includes(search) ? 1 : 0)}>
|
|
27
|
-
<SearchList.Input placeholder='Search...' />
|
|
28
|
-
<SearchList.Content>
|
|
29
|
-
{Object.entries(items).map(([value, label]) => (
|
|
30
|
-
<SearchList.Item key={value} value={value} onSelect={(value) => console.log('[item select]', value)}>
|
|
31
|
-
{label}
|
|
32
|
-
</SearchList.Item>
|
|
33
|
-
))}
|
|
34
|
-
</SearchList.Content>
|
|
35
|
-
</SearchList.Root>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default {
|
|
40
|
-
title: 'ui/react-ui-searchlist/SearchList',
|
|
41
|
-
component: SearchListStory,
|
|
42
|
-
decorators: [withTheme],
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const Default = {
|
|
46
|
-
args: {},
|
|
47
|
-
};
|