@dxos/react-ui 0.3.7-main.fcec8cd → 0.3.7

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.
@@ -1,82 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import '@dxosTheme';
6
-
7
- import { faker } from '@faker-js/faker';
8
- import React, { type FC, useEffect, useState } from 'react';
9
-
10
- import { ComboBox, type ComboBoxItem } from './ComboBox';
11
-
12
- type TestItem = { id: string; text: string };
13
-
14
- const data: TestItem[] = faker.helpers
15
- .uniqueArray(faker.definitions.animal.fish, 100)
16
- .sort()
17
- .map((text) => ({
18
- id: faker.string.uuid(),
19
- text,
20
- }));
21
-
22
- const ComboBoxStory: FC<{ data: TestItem[] }> = ({ data = [] }) => {
23
- const [filter, setFilter] = useState<string>();
24
- const [items, setItems] = useState<ComboBoxItem[]>([]);
25
- const [selected, setSelected] = useState<ComboBoxItem>();
26
- useEffect(() => {
27
- setItems(() =>
28
- filter?.length
29
- ? data
30
- .filter((item) => item.text?.length && item.text?.toLowerCase().includes(filter.toLowerCase()))
31
- .map((item) => ({ id: item.id, label: item.text, data: item }))
32
- : [],
33
- );
34
- }, [filter]);
35
-
36
- return (
37
- <div className='flex flex-col w-full bg-neutral-100 dark:bg-neutral-800'>
38
- <ComboBox.Root items={items} onChange={setSelected} onInputChange={setFilter}>
39
- <ComboBox.Input placeholder={'Select...'} />
40
- <ComboBox.Content>
41
- {items?.map((item) => (
42
- <ComboBox.Item key={item.id} item={item}>
43
- {item.label}
44
- </ComboBox.Item>
45
- ))}
46
- </ComboBox.Content>
47
- </ComboBox.Root>
48
-
49
- <div className='mt-16 p-2 font-mono text-xs truncate'>
50
- <div>{selected?.label}</div>
51
- </div>
52
- </div>
53
- );
54
- };
55
-
56
- export default {
57
- component: ComboBoxStory,
58
- decorators: [
59
- (Story: any) => (
60
- <div className='flex flex-col items-center h-screen w-full overflow-hidden'>
61
- <div className='flex w-60 m-8 bg-white'>
62
- <Story />
63
- </div>
64
- </div>
65
- ),
66
- ],
67
- parameters: {
68
- layout: 'fullscreen',
69
- },
70
- };
71
-
72
- // TODO(burdon): Test controlled and uncontrolled.
73
-
74
- export const Default = {
75
- args: {
76
- data,
77
- },
78
- };
79
-
80
- export const Empty = {
81
- args: {},
82
- };
@@ -1,218 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import { CaretDown, CaretUp } from '@phosphor-icons/react';
6
- import { createContextScope, type Scope } from '@radix-ui/react-context';
7
- import { createPopperScope } from '@radix-ui/react-popper';
8
- import * as PopperPrimitive from '@radix-ui/react-popper';
9
- import { useCombobox, type UseComboboxReturnValue } from 'downshift';
10
- import React, { forwardRef, type PropsWithChildren } from 'react';
11
-
12
- import { useThemeContext } from '../../hooks';
13
- import { type ThemedClassName } from '../../util';
14
- import { Button } from '../Buttons';
15
- import { Input } from '../Input';
16
-
17
- const COMBOBOX_NAME = 'ComboBox';
18
-
19
- type ScopedProps<P> = P & { __scopeComboBox?: Scope };
20
-
21
- type ComboBoxItem = {
22
- id: string;
23
- label: string;
24
- data?: any;
25
- };
26
-
27
- type ComboBoxContextValue = {
28
- items: ComboBoxItem[];
29
- } & UseComboboxReturnValue<ComboBoxItem>;
30
-
31
- const usePopperScope = createPopperScope();
32
- const [createComboBoxContext] = createContextScope(COMBOBOX_NAME, [createPopperScope]);
33
- const [ComboBoxProvider, useComboBoxContext] = createComboBoxContext<ComboBoxContextValue>(COMBOBOX_NAME);
34
-
35
- type ComboBoxRootProps = ThemedClassName<
36
- ScopedProps<
37
- PropsWithChildren<{
38
- items?: ComboBoxItem[];
39
- value?: ComboBoxItem;
40
- onChange?: (selected: ComboBoxItem | undefined) => void;
41
- onInputChange?: (text?: string) => void;
42
- }>
43
- >
44
- >;
45
-
46
- /**
47
- * Type-ahead combobox.
48
- */
49
- const ComboBoxRoot = ({
50
- __scopeComboBox,
51
- children,
52
- classNames,
53
- items = [],
54
- value,
55
- onChange,
56
- onInputChange,
57
- }: ComboBoxRootProps) => {
58
- const { tx } = useThemeContext();
59
- const popperScope = usePopperScope(__scopeComboBox);
60
-
61
- // TODO(burdon): Remove and implement natively?
62
- // https://www.downshift-js.com/use-combobox
63
- const comboProps = useCombobox<ComboBoxItem>({
64
- items,
65
- itemToString: (selectedItem) => selectedItem?.label ?? '',
66
- onInputValueChange: ({ inputValue }) => onInputChange?.(inputValue),
67
- selectedItem: value ?? null,
68
- onSelectedItemChange: ({ selectedItem }) => onChange?.(selectedItem === null ? undefined : selectedItem),
69
- });
70
-
71
- return (
72
- <ComboBoxProvider scope={__scopeComboBox} items={items} {...comboProps}>
73
- <PopperPrimitive.Root {...popperScope}>
74
- <div className={tx('combobox.root', 'combobox__root', {}, classNames)}>{children}</div>
75
- </PopperPrimitive.Root>
76
- </ComboBoxProvider>
77
- );
78
- };
79
-
80
- //
81
- // Input
82
- //
83
-
84
- const INPUT_NAME = 'ComboBoxInput';
85
-
86
- type ComboBoxInputProps = ThemedClassName<
87
- ScopedProps<
88
- PropsWithChildren<{
89
- placeholder?: string;
90
- }>
91
- >
92
- >;
93
-
94
- const ComboBoxInput = forwardRef<HTMLDivElement, ComboBoxInputProps>(
95
- ({ __scopeComboBox, classNames, placeholder }: ComboBoxInputProps, forwardedRef) => {
96
- const { tx } = useThemeContext();
97
- const popperScope = usePopperScope(__scopeComboBox);
98
- const { getInputProps, getToggleButtonProps, isOpen } = useComboBoxContext(INPUT_NAME, __scopeComboBox);
99
-
100
- // TODO(burdon): Break out input and button.
101
- return (
102
- <PopperPrimitive.Anchor asChild {...popperScope} ref={forwardedRef}>
103
- {/* TODO(burdon): Move class to theme. */}
104
- <div role='none' className='flex items-center gap-1'>
105
- <Input.Root>
106
- <Input.TextInput
107
- {...getInputProps()}
108
- placeholder={placeholder}
109
- variant='subdued'
110
- classNames={tx('combobox.input', 'combobox__input', {}, classNames)}
111
- />
112
- </Input.Root>
113
- <Button
114
- {...getToggleButtonProps()}
115
- aria-label='toggle menu'
116
- variant='ghost'
117
- classNames={tx('combobox.button', 'combobox__button')}
118
- >
119
- {(isOpen && <CaretUp />) || <CaretDown />}
120
- </Button>
121
- </div>
122
- </PopperPrimitive.Anchor>
123
- );
124
- },
125
- );
126
-
127
- //
128
- // Content
129
- //
130
-
131
- const CONTENT_NAME = 'ComboBoxContent';
132
-
133
- type ComboBoxContentProps = ThemedClassName<ScopedProps<PropsWithChildren<{}>>>;
134
-
135
- const ComboBoxContent = forwardRef<HTMLDivElement, ComboBoxContentProps>(
136
- ({ __scopeComboBox, classNames, children }: ComboBoxContentProps, forwardedRef) => {
137
- const { tx } = useThemeContext();
138
- const popperScope = usePopperScope(__scopeComboBox);
139
- const { getMenuProps, isOpen } = useComboBoxContext(CONTENT_NAME, __scopeComboBox);
140
-
141
- return (
142
- <PopperPrimitive.Content
143
- data-state={isOpen}
144
- role='dialog'
145
- {...popperScope}
146
- ref={forwardedRef}
147
- style={
148
- {
149
- // Re-namespace exposed content custom properties.
150
- ...{
151
- '--radix-combobox-content-transform-origin': 'var(--radix-popper-transform-origin)',
152
- '--radix-combobox-content-available-width': 'var(--radix-popper-available-width)',
153
- '--radix-combobox-content-available-height': 'var(--radix-popper-available-height)',
154
- '--radix-combobox-trigger-width': 'var(--radix-popper-anchor-width)',
155
- '--radix-combobox-trigger-height': 'var(--radix-popper-anchor-height)',
156
- },
157
- } as any // TODO(burdon): Why any?
158
- }
159
- >
160
- <ul {...getMenuProps()} className={tx('combobox.content', 'combobox__content', {}, classNames)}>
161
- {isOpen && children}
162
- </ul>
163
- </PopperPrimitive.Content>
164
- );
165
- },
166
- );
167
-
168
- //
169
- // Item
170
- //
171
-
172
- const ITEM_NAME = 'ComboBoxItem';
173
-
174
- type ComboBoxItemProps = ThemedClassName<
175
- ScopedProps<
176
- PropsWithChildren<{
177
- item: ComboBoxItem;
178
- }>
179
- >
180
- >;
181
-
182
- const ComboBoxItem = forwardRef<HTMLLIElement, ComboBoxItemProps>(
183
- ({ __scopeComboBox, classNames, children, item }, forwardedRef) => {
184
- const { tx } = useThemeContext();
185
- const { getItemProps, items, selectedItem, highlightedIndex } = useComboBoxContext(ITEM_NAME, __scopeComboBox);
186
-
187
- return (
188
- <li
189
- ref={forwardedRef}
190
- data-selected={selectedItem?.id === item.id ? 'true' : undefined}
191
- data-highlighted={
192
- highlightedIndex !== undefined && items[highlightedIndex]?.id === item.id ? 'true' : undefined
193
- }
194
- className={tx('combobox.item', 'item', {}, classNames)}
195
- {...getItemProps({ item })}
196
- >
197
- {children}
198
- </li>
199
- );
200
- },
201
- );
202
-
203
- // prettier-ignore
204
- export const ComboBox = {
205
- Root: ComboBoxRoot,
206
- Input: ComboBoxInput,
207
- Content: ComboBoxContent,
208
- Item: ComboBoxItem
209
- };
210
-
211
- // prettier-ignore
212
- export type {
213
- ComboBoxItem,
214
- ComboBoxRootProps,
215
- ComboBoxInputProps,
216
- ComboBoxContentProps,
217
- ComboBoxItemProps
218
- };
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2022 DXOS.org
3
- //
4
-
5
- export * from './ComboBox';