@a-type/ui 4.0.9 → 4.1.0-beta.2
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/cjs/components/autocomplete/Autocomplete.d.ts +112 -0
- package/dist/cjs/components/autocomplete/Autocomplete.js +119 -0
- package/dist/cjs/components/autocomplete/Autocomplete.js.map +1 -0
- package/dist/cjs/components/autocomplete/Autocomplete.stories.d.ts +52 -0
- package/dist/cjs/components/autocomplete/Autocomplete.stories.js +93 -0
- package/dist/cjs/components/autocomplete/Autocomplete.stories.js.map +1 -0
- package/dist/cjs/components/chip/Chip.d.ts +3 -4
- package/dist/cjs/components/chip/Chip.js +1 -1
- package/dist/cjs/components/chip/Chip.js.map +1 -1
- package/dist/cjs/components/chip/Chip.stories.js +1 -1
- package/dist/cjs/components/chip/Chip.stories.js.map +1 -1
- package/dist/cjs/components/dialog/Dialog.js +7 -7
- package/dist/cjs/components/dialog/Dialog.js.map +1 -1
- package/dist/cjs/components/dropdownMenu/DropdownMenu.js +11 -44
- package/dist/cjs/components/dropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/cjs/components/index.d.ts +2 -0
- package/dist/cjs/components/index.js +2 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/components/input/Input.d.ts +7 -2
- package/dist/cjs/components/input/Input.js +26 -12
- package/dist/cjs/components/input/Input.js.map +1 -1
- package/dist/cjs/components/input/Input.stories.d.ts +5 -1
- package/dist/cjs/components/input/Input.stories.js +6 -2
- package/dist/cjs/components/input/Input.stories.js.map +1 -1
- package/dist/cjs/components/layouts/PageNowPlaying.d.ts +1 -2
- package/dist/cjs/components/layouts/PageNowPlaying.js +2 -4
- package/dist/cjs/components/layouts/PageNowPlaying.js.map +1 -1
- package/dist/cjs/components/popover/Popover.js +6 -5
- package/dist/cjs/components/popover/Popover.js.map +1 -1
- package/dist/cjs/components/primitives/menus.d.ts +5 -0
- package/dist/cjs/components/primitives/menus.js +14 -0
- package/dist/cjs/components/primitives/menus.js.map +1 -0
- package/dist/cjs/components/quickAction/QuickAction.d.ts +17 -0
- package/dist/cjs/components/quickAction/QuickAction.js +63 -0
- package/dist/cjs/components/quickAction/QuickAction.js.map +1 -0
- package/dist/cjs/components/quickAction/QuickAction.stories.d.ts +22 -0
- package/dist/cjs/components/quickAction/QuickAction.stories.js +61 -0
- package/dist/cjs/components/quickAction/QuickAction.stories.js.map +1 -0
- package/dist/cjs/systems/inputs.d.ts +3 -0
- package/dist/cjs/systems/inputs.js +14 -0
- package/dist/cjs/systems/inputs.js.map +1 -0
- package/dist/cjs/uno/preflights/layers.js +1 -1
- package/dist/cjs/uno/preflights/layers.js.map +1 -1
- package/dist/css/main.css +7 -6
- package/dist/esm/components/autocomplete/Autocomplete.d.ts +112 -0
- package/dist/esm/components/autocomplete/Autocomplete.js +113 -0
- package/dist/esm/components/autocomplete/Autocomplete.js.map +1 -0
- package/dist/esm/components/autocomplete/Autocomplete.stories.d.ts +52 -0
- package/dist/esm/components/autocomplete/Autocomplete.stories.js +90 -0
- package/dist/esm/components/autocomplete/Autocomplete.stories.js.map +1 -0
- package/dist/esm/components/chip/Chip.d.ts +3 -4
- package/dist/esm/components/chip/Chip.js +1 -1
- package/dist/esm/components/chip/Chip.js.map +1 -1
- package/dist/esm/components/chip/Chip.stories.js +1 -1
- package/dist/esm/components/chip/Chip.stories.js.map +1 -1
- package/dist/esm/components/dialog/Dialog.js +7 -7
- package/dist/esm/components/dialog/Dialog.js.map +1 -1
- package/dist/esm/components/dropdownMenu/DropdownMenu.js +8 -8
- package/dist/esm/components/dropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/esm/components/index.d.ts +2 -0
- package/dist/esm/components/index.js +2 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/components/input/Input.d.ts +7 -2
- package/dist/esm/components/input/Input.js +29 -14
- package/dist/esm/components/input/Input.js.map +1 -1
- package/dist/esm/components/input/Input.stories.d.ts +5 -1
- package/dist/esm/components/input/Input.stories.js +5 -1
- package/dist/esm/components/input/Input.stories.js.map +1 -1
- package/dist/esm/components/layouts/PageNowPlaying.d.ts +1 -2
- package/dist/esm/components/layouts/PageNowPlaying.js +2 -4
- package/dist/esm/components/layouts/PageNowPlaying.js.map +1 -1
- package/dist/esm/components/popover/Popover.js +6 -5
- package/dist/esm/components/popover/Popover.js.map +1 -1
- package/dist/esm/components/primitives/menus.d.ts +5 -0
- package/dist/esm/components/primitives/menus.js +8 -0
- package/dist/esm/components/primitives/menus.js.map +1 -0
- package/dist/esm/components/quickAction/QuickAction.d.ts +17 -0
- package/dist/esm/components/quickAction/QuickAction.js +56 -0
- package/dist/esm/components/quickAction/QuickAction.js.map +1 -0
- package/dist/esm/components/quickAction/QuickAction.stories.d.ts +22 -0
- package/dist/esm/components/quickAction/QuickAction.stories.js +55 -0
- package/dist/esm/components/quickAction/QuickAction.stories.js.map +1 -0
- package/dist/esm/systems/inputs.d.ts +3 -0
- package/dist/esm/systems/inputs.js +11 -0
- package/dist/esm/systems/inputs.js.map +1 -0
- package/dist/esm/uno/preflights/layers.js +1 -1
- package/dist/esm/uno/preflights/layers.js.map +1 -1
- package/package.json +1 -1
- package/src/components/autocomplete/Autocomplete.stories.tsx +212 -0
- package/src/components/autocomplete/Autocomplete.tsx +336 -0
- package/src/components/chip/Chip.stories.tsx +1 -4
- package/src/components/chip/Chip.tsx +5 -7
- package/src/components/dialog/Dialog.tsx +535 -535
- package/src/components/dropdownMenu/DropdownMenu.tsx +173 -190
- package/src/components/index.ts +2 -0
- package/src/components/input/Input.stories.tsx +14 -1
- package/src/components/input/Input.tsx +107 -74
- package/src/components/layouts/PageNowPlaying.tsx +1 -5
- package/src/components/popover/Popover.tsx +123 -132
- package/src/components/primitives/menus.tsx +44 -0
- package/src/components/quickAction/QuickAction.stories.tsx +106 -0
- package/src/components/quickAction/QuickAction.tsx +107 -0
- package/src/systems/inputs.ts +11 -0
- package/src/uno/preflights/layers.ts +1 -1
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box } from '../box/Box.js';
|
|
4
|
+
import { Icon } from '../icon/Icon.js';
|
|
5
|
+
import { Autocomplete } from './Autocomplete.js';
|
|
6
|
+
|
|
7
|
+
interface Args {
|
|
8
|
+
arrow?: boolean;
|
|
9
|
+
autoHighlight?: boolean;
|
|
10
|
+
keepHighlight?: boolean;
|
|
11
|
+
highlightItemOnHover?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const meta = {
|
|
15
|
+
title: 'Components/Autocomplete',
|
|
16
|
+
argTypes: {
|
|
17
|
+
arrow: {
|
|
18
|
+
control: 'boolean',
|
|
19
|
+
description: 'Whether to show the arrow on the autocomplete popup.',
|
|
20
|
+
defaultValue: false,
|
|
21
|
+
},
|
|
22
|
+
autoHighlight: {
|
|
23
|
+
control: 'boolean',
|
|
24
|
+
description:
|
|
25
|
+
'If true, the first item will be automatically highlighted when the list opens.',
|
|
26
|
+
defaultValue: false,
|
|
27
|
+
},
|
|
28
|
+
keepHighlight: {
|
|
29
|
+
control: 'boolean',
|
|
30
|
+
description:
|
|
31
|
+
'If true, the highlighted item will be kept when the list is reopened.',
|
|
32
|
+
defaultValue: false,
|
|
33
|
+
},
|
|
34
|
+
highlightItemOnHover: {
|
|
35
|
+
control: 'boolean',
|
|
36
|
+
description:
|
|
37
|
+
'If true, items will be highlighted when hovered with the mouse.',
|
|
38
|
+
defaultValue: false,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
args: {
|
|
42
|
+
arrow: false,
|
|
43
|
+
autoHighlight: false,
|
|
44
|
+
keepHighlight: false,
|
|
45
|
+
highlightItemOnHover: true,
|
|
46
|
+
},
|
|
47
|
+
parameters: {
|
|
48
|
+
controls: { expanded: true },
|
|
49
|
+
},
|
|
50
|
+
} satisfies Meta<Args>;
|
|
51
|
+
|
|
52
|
+
export default meta;
|
|
53
|
+
|
|
54
|
+
type Story = StoryObj<Args>;
|
|
55
|
+
|
|
56
|
+
export interface Item {
|
|
57
|
+
id: string;
|
|
58
|
+
label: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const items: Item[] = [
|
|
62
|
+
{ id: 'apple', label: 'Apple' },
|
|
63
|
+
{ id: 'banana', label: 'Banana' },
|
|
64
|
+
{ id: 'cherry', label: 'Cherry' },
|
|
65
|
+
{ id: 'date', label: 'Date' },
|
|
66
|
+
{ id: 'elderberry', label: 'Elderberry' },
|
|
67
|
+
{ id: 'fig', label: 'Fig' },
|
|
68
|
+
{ id: 'grape', label: 'Grape' },
|
|
69
|
+
{ id: 'honeydew', label: 'Honeydew' },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const ExampleAutocomplete = Autocomplete.create<Item>();
|
|
73
|
+
|
|
74
|
+
export const Default: Story = {
|
|
75
|
+
render({ arrow, autoHighlight, keepHighlight, highlightItemOnHover }) {
|
|
76
|
+
const [value, setValue] = useState<string | undefined>(undefined);
|
|
77
|
+
return (
|
|
78
|
+
<ExampleAutocomplete
|
|
79
|
+
value={value}
|
|
80
|
+
onValueChange={setValue}
|
|
81
|
+
items={items}
|
|
82
|
+
autoHighlight={autoHighlight}
|
|
83
|
+
keepHighlight={keepHighlight}
|
|
84
|
+
highlightItemOnHover={highlightItemOnHover}
|
|
85
|
+
>
|
|
86
|
+
<ExampleAutocomplete.Input
|
|
87
|
+
icon={<Icon name="food" />}
|
|
88
|
+
className="w-[200px]"
|
|
89
|
+
/>
|
|
90
|
+
<ExampleAutocomplete.Content arrow={arrow}>
|
|
91
|
+
<ExampleAutocomplete.List>
|
|
92
|
+
{(item) => (
|
|
93
|
+
<ExampleAutocomplete.Item key={item.id} value={item.id}>
|
|
94
|
+
{item.label}
|
|
95
|
+
</ExampleAutocomplete.Item>
|
|
96
|
+
)}
|
|
97
|
+
</ExampleAutocomplete.List>
|
|
98
|
+
<ExampleAutocomplete.Empty>
|
|
99
|
+
No results found.
|
|
100
|
+
</ExampleAutocomplete.Empty>
|
|
101
|
+
</ExampleAutocomplete.Content>
|
|
102
|
+
</ExampleAutocomplete>
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
interface ItemGroup {
|
|
108
|
+
category: string;
|
|
109
|
+
items: Item[];
|
|
110
|
+
}
|
|
111
|
+
const groupedItems: ItemGroup[] = [
|
|
112
|
+
{
|
|
113
|
+
category: 'Fruits',
|
|
114
|
+
items: [
|
|
115
|
+
{ id: 'apple', label: 'Apple' },
|
|
116
|
+
{ id: 'banana', label: 'Banana' },
|
|
117
|
+
{ id: 'cherry', label: 'Cherry' },
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
category: 'Berries',
|
|
122
|
+
items: [
|
|
123
|
+
{ id: 'strawberry', label: 'Strawberry' },
|
|
124
|
+
{ id: 'blueberry', label: 'Blueberry' },
|
|
125
|
+
{ id: 'raspberry', label: 'Raspberry' },
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
const GroupedAutocomplete = Autocomplete.createGrouped<ItemGroup>();
|
|
131
|
+
|
|
132
|
+
export const Grouped: Story = {
|
|
133
|
+
render({ arrow, autoHighlight, keepHighlight, highlightItemOnHover }) {
|
|
134
|
+
const [value, setValue] = useState<string | undefined>(undefined);
|
|
135
|
+
return (
|
|
136
|
+
<GroupedAutocomplete
|
|
137
|
+
value={value}
|
|
138
|
+
onValueChange={setValue}
|
|
139
|
+
items={groupedItems}
|
|
140
|
+
autoHighlight={autoHighlight}
|
|
141
|
+
keepHighlight={keepHighlight}
|
|
142
|
+
highlightItemOnHover={highlightItemOnHover}
|
|
143
|
+
>
|
|
144
|
+
<GroupedAutocomplete.Input />
|
|
145
|
+
<GroupedAutocomplete.Content arrow={arrow}>
|
|
146
|
+
<GroupedAutocomplete.List>
|
|
147
|
+
{(group) => (
|
|
148
|
+
<GroupedAutocomplete.Group key={group.category}>
|
|
149
|
+
<GroupedAutocomplete.GroupLabel>
|
|
150
|
+
{group.category}
|
|
151
|
+
</GroupedAutocomplete.GroupLabel>
|
|
152
|
+
<GroupedAutocomplete.GroupList>
|
|
153
|
+
{group.items.map((item) => (
|
|
154
|
+
<GroupedAutocomplete.Item key={item.id} value={item.id}>
|
|
155
|
+
{item.label}
|
|
156
|
+
</GroupedAutocomplete.Item>
|
|
157
|
+
))}
|
|
158
|
+
</GroupedAutocomplete.GroupList>
|
|
159
|
+
</GroupedAutocomplete.Group>
|
|
160
|
+
)}
|
|
161
|
+
</GroupedAutocomplete.List>
|
|
162
|
+
<GroupedAutocomplete.Empty>
|
|
163
|
+
No results found.
|
|
164
|
+
</GroupedAutocomplete.Empty>
|
|
165
|
+
<GroupedAutocomplete.Separator />
|
|
166
|
+
<div className="p-sm text-xs color-gray-dark">
|
|
167
|
+
Select your favorite fruit or berry.
|
|
168
|
+
</div>
|
|
169
|
+
</GroupedAutocomplete.Content>
|
|
170
|
+
</GroupedAutocomplete>
|
|
171
|
+
);
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export const NotPopover: Story = {
|
|
176
|
+
render({ autoHighlight, keepHighlight, highlightItemOnHover }) {
|
|
177
|
+
const [value, setValue] = useState<string | undefined>(undefined);
|
|
178
|
+
return (
|
|
179
|
+
<GroupedAutocomplete
|
|
180
|
+
value={value}
|
|
181
|
+
onValueChange={setValue}
|
|
182
|
+
items={groupedItems}
|
|
183
|
+
autoHighlight={autoHighlight}
|
|
184
|
+
keepHighlight={keepHighlight}
|
|
185
|
+
highlightItemOnHover={highlightItemOnHover}
|
|
186
|
+
>
|
|
187
|
+
<Box border p surface="white" col>
|
|
188
|
+
<GroupedAutocomplete.Input disableCaret className="w-full" />
|
|
189
|
+
<GroupedAutocomplete.List>
|
|
190
|
+
{(group) => (
|
|
191
|
+
<GroupedAutocomplete.Group key={group.category}>
|
|
192
|
+
<GroupedAutocomplete.GroupLabel>
|
|
193
|
+
{group.category}
|
|
194
|
+
</GroupedAutocomplete.GroupLabel>
|
|
195
|
+
<GroupedAutocomplete.GroupList>
|
|
196
|
+
{group.items.map((item) => (
|
|
197
|
+
<GroupedAutocomplete.Item key={item.id} value={item.id}>
|
|
198
|
+
{item.label}
|
|
199
|
+
</GroupedAutocomplete.Item>
|
|
200
|
+
))}
|
|
201
|
+
</GroupedAutocomplete.GroupList>
|
|
202
|
+
</GroupedAutocomplete.Group>
|
|
203
|
+
)}
|
|
204
|
+
</GroupedAutocomplete.List>
|
|
205
|
+
<GroupedAutocomplete.Empty>
|
|
206
|
+
No results found.
|
|
207
|
+
</GroupedAutocomplete.Empty>
|
|
208
|
+
</Box>
|
|
209
|
+
</GroupedAutocomplete>
|
|
210
|
+
);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AutocompleteArrowProps,
|
|
3
|
+
Autocomplete as BaseAutocomplete,
|
|
4
|
+
AutocompleteGroupProps as BaseAutocompleteGroupProps,
|
|
5
|
+
AutocompleteInputProps as BaseAutocompleteInputProps,
|
|
6
|
+
AutocompleteItemProps as BaseAutocompleteItemProps,
|
|
7
|
+
AutocompleteListProps as BaseAutocompleteListProps,
|
|
8
|
+
AutocompletePopupProps as BaseAutocompletePopupProps,
|
|
9
|
+
AutocompletePositionerProps as BaseAutocompletePositionerProps,
|
|
10
|
+
AutocompleteRootProps as BaseAutocompleteRootProps,
|
|
11
|
+
} from '@base-ui/react/autocomplete';
|
|
12
|
+
import { ButtonProps } from '@base-ui/react/button';
|
|
13
|
+
import {
|
|
14
|
+
ComboboxIconProps as BaseAutocompleteIconProps,
|
|
15
|
+
ComboboxRowProps as BaseAutocompleteRowProps,
|
|
16
|
+
} from '@base-ui/react/combobox';
|
|
17
|
+
import clsx from 'clsx';
|
|
18
|
+
import { createContext, ReactNode, useContext } from 'react';
|
|
19
|
+
import { withClassName } from '../../hooks.js';
|
|
20
|
+
import { PaletteName } from '../../uno/index.js';
|
|
21
|
+
import { Button } from '../button/Button.js';
|
|
22
|
+
import { Chip, ChipProps } from '../chip/Chip.js';
|
|
23
|
+
import { Icon } from '../icon/Icon.js';
|
|
24
|
+
import { Input } from '../input/Input.js';
|
|
25
|
+
import {
|
|
26
|
+
arrowClassName,
|
|
27
|
+
itemClassName,
|
|
28
|
+
itemListClassName,
|
|
29
|
+
popupClassName,
|
|
30
|
+
separatorClassName,
|
|
31
|
+
} from '../primitives/menus.js';
|
|
32
|
+
import { ArrowSvg } from '../utility/ArrowSvg.js';
|
|
33
|
+
import { SlotDiv } from '../utility/SlotDiv.js';
|
|
34
|
+
|
|
35
|
+
const ValueContext = createContext<string | number | readonly string[] | null>(
|
|
36
|
+
null,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const AutocompleteRoot = (props: BaseAutocompleteRootProps<any>) => {
|
|
40
|
+
return (
|
|
41
|
+
<ValueContext.Provider value={props.value || null}>
|
|
42
|
+
<BaseAutocomplete.Root {...props} />
|
|
43
|
+
</ValueContext.Provider>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export interface AutocompleteInputProps extends BaseAutocompleteInputProps {
|
|
48
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
49
|
+
icon?: ReactNode;
|
|
50
|
+
disableCaret?: boolean;
|
|
51
|
+
}
|
|
52
|
+
const AutocompleteInput = ({
|
|
53
|
+
disableCaret,
|
|
54
|
+
icon,
|
|
55
|
+
...props
|
|
56
|
+
}: AutocompleteInputProps) => {
|
|
57
|
+
const valueFromContext = useContext(ValueContext);
|
|
58
|
+
return (
|
|
59
|
+
<BaseAutocomplete.Input
|
|
60
|
+
render={({ ref, className, ...props }, state) => (
|
|
61
|
+
<Input.Border ref={ref} className={className}>
|
|
62
|
+
{icon}
|
|
63
|
+
<Input.Input autoComplete="off" {...props} />
|
|
64
|
+
{(valueFromContext !== null || !disableCaret) && (
|
|
65
|
+
<div className="flex items-center">
|
|
66
|
+
{valueFromContext !== null && <AutocompleteClear />}
|
|
67
|
+
{!disableCaret && (
|
|
68
|
+
<BaseAutocomplete.Trigger
|
|
69
|
+
render={<Button emphasis="ghost" size="small" />}
|
|
70
|
+
>
|
|
71
|
+
<AutocompleteIcon data-open={state.open ? true : undefined} />
|
|
72
|
+
</BaseAutocomplete.Trigger>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
)}
|
|
76
|
+
</Input.Border>
|
|
77
|
+
)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const AutocompleteIcon = withClassName(
|
|
84
|
+
({ className, ...props }: BaseAutocompleteIconProps) => (
|
|
85
|
+
<BaseAutocomplete.Icon
|
|
86
|
+
{...props}
|
|
87
|
+
className={clsx(
|
|
88
|
+
'icon',
|
|
89
|
+
'layer-components:(flex shrink-0 items-center justify-center transition-transform)',
|
|
90
|
+
'layer-components:data-[open]:(rotate-180)',
|
|
91
|
+
className,
|
|
92
|
+
)}
|
|
93
|
+
>
|
|
94
|
+
<Icon name="chevron" />
|
|
95
|
+
</BaseAutocomplete.Icon>
|
|
96
|
+
),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const AutocompletePopup = withClassName(
|
|
100
|
+
BaseAutocomplete.Popup,
|
|
101
|
+
popupClassName,
|
|
102
|
+
'layer-components:(w-[--anchor-width])',
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const AutocompleteBackdrop = withClassName(
|
|
106
|
+
BaseAutocomplete.Backdrop,
|
|
107
|
+
'layer-components:(fixed inset-0)',
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const AutocompleteArrow = ({ className, ...props }: AutocompleteArrowProps) => (
|
|
111
|
+
<BaseAutocomplete.Arrow
|
|
112
|
+
{...props}
|
|
113
|
+
className={clsx(arrowClassName, className)}
|
|
114
|
+
>
|
|
115
|
+
<ArrowSvg />
|
|
116
|
+
</BaseAutocomplete.Arrow>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
export interface AutocompletePopoupProps extends BaseAutocompletePopupProps {
|
|
120
|
+
positioner?: BaseAutocompletePositionerProps;
|
|
121
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
122
|
+
arrow?: boolean;
|
|
123
|
+
}
|
|
124
|
+
const AutocompleteContent = ({
|
|
125
|
+
positioner,
|
|
126
|
+
arrow,
|
|
127
|
+
children,
|
|
128
|
+
...props
|
|
129
|
+
}: AutocompletePopoupProps) => {
|
|
130
|
+
return (
|
|
131
|
+
<BaseAutocomplete.Portal>
|
|
132
|
+
<AutocompleteBackdrop />
|
|
133
|
+
<BaseAutocomplete.Positioner sideOffset={8} {...positioner}>
|
|
134
|
+
<AutocompletePopup {...props}>
|
|
135
|
+
{arrow && <AutocompleteArrow />}
|
|
136
|
+
{children}
|
|
137
|
+
</AutocompletePopup>
|
|
138
|
+
</BaseAutocomplete.Positioner>
|
|
139
|
+
</BaseAutocomplete.Portal>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const AutocompleteList = withClassName(
|
|
144
|
+
BaseAutocomplete.List,
|
|
145
|
+
itemListClassName,
|
|
146
|
+
'layer-components:(flex flex-col overscroll-contain outline-none overflow-y-auto overflow-unstable)',
|
|
147
|
+
'layer-components:empty:(p-0)',
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const AutocompleteEmpty = withClassName(
|
|
151
|
+
BaseAutocomplete.Empty,
|
|
152
|
+
'layer-components:[&:not(:empty)]:(p-sm text-sm color-gray-dark)',
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
export interface AutocompleteItemProps extends BaseAutocompleteItemProps {
|
|
156
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
157
|
+
color?: PaletteName;
|
|
158
|
+
}
|
|
159
|
+
const AutocompleteItem = ({
|
|
160
|
+
className,
|
|
161
|
+
color = 'gray',
|
|
162
|
+
...props
|
|
163
|
+
}: AutocompleteItemProps) => (
|
|
164
|
+
<BaseAutocomplete.Item
|
|
165
|
+
className={clsx(color && `palette-${color}`, itemClassName, className)}
|
|
166
|
+
{...props}
|
|
167
|
+
/>
|
|
168
|
+
);
|
|
169
|
+
const AutocompleteGroup = ({
|
|
170
|
+
className,
|
|
171
|
+
...props
|
|
172
|
+
}: BaseAutocompleteGroupProps & { ref?: React.Ref<HTMLDivElement> }) => {
|
|
173
|
+
return (
|
|
174
|
+
<BaseAutocomplete.Group
|
|
175
|
+
{...props}
|
|
176
|
+
className={clsx(
|
|
177
|
+
'layer-components:(flex flex-col gap-xs overflow-hidden p-sm)',
|
|
178
|
+
className,
|
|
179
|
+
)}
|
|
180
|
+
/>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const AutocompleteGroupItemList = withClassName(
|
|
185
|
+
SlotDiv,
|
|
186
|
+
'layer-components:(flex flex-row flex-wrap gap-xs)',
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const AutocompleteGroupLabel = withClassName(
|
|
190
|
+
BaseAutocomplete.GroupLabel,
|
|
191
|
+
'layer-components:(w-full px-xs text-xs font-medium uppercase color-gray-dark)',
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const AutocompleteRow: React.FC<BaseAutocompleteRowProps> = withClassName(
|
|
195
|
+
BaseAutocomplete.Row,
|
|
196
|
+
'layer-components:(flex items-center gap-xs)',
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const AutocompleteSeparator = withClassName(
|
|
200
|
+
BaseAutocomplete.Separator,
|
|
201
|
+
separatorClassName,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
export interface AutocompleteGroupItemProps
|
|
205
|
+
extends Omit<BaseAutocompleteItemProps, 'render'> {
|
|
206
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
207
|
+
replace?: BaseAutocompleteItemProps['render'];
|
|
208
|
+
render?: ChipProps['render'];
|
|
209
|
+
}
|
|
210
|
+
function AutocompleteGroupItem({
|
|
211
|
+
className,
|
|
212
|
+
replace,
|
|
213
|
+
render,
|
|
214
|
+
...props
|
|
215
|
+
}: AutocompleteGroupItemProps) {
|
|
216
|
+
return (
|
|
217
|
+
<BaseAutocomplete.Item
|
|
218
|
+
render={replace ?? <Button render={<Chip render={render} />} />}
|
|
219
|
+
{...props}
|
|
220
|
+
className={clsx(
|
|
221
|
+
'palette-primary',
|
|
222
|
+
'layer-composed-2:(bg-white)',
|
|
223
|
+
'layer-composed-2:data-[highlighted]:(ring-2 bg-main-wash ring-primary)',
|
|
224
|
+
className,
|
|
225
|
+
)}
|
|
226
|
+
/>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export type AutocompleteClearProps = ButtonProps & {
|
|
231
|
+
ref?: React.Ref<HTMLButtonElement>;
|
|
232
|
+
children?: ReactNode;
|
|
233
|
+
};
|
|
234
|
+
const AutocompleteClear = ({ children, ...props }: AutocompleteClearProps) => (
|
|
235
|
+
<BaseAutocomplete.Clear
|
|
236
|
+
render={<Button emphasis="ghost" size="small" />}
|
|
237
|
+
{...props}
|
|
238
|
+
>
|
|
239
|
+
{children ?? <Icon name="x" />}
|
|
240
|
+
</BaseAutocomplete.Clear>
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const baseSubComponents = {
|
|
244
|
+
useFilter: BaseAutocomplete.useFilter,
|
|
245
|
+
|
|
246
|
+
Input: AutocompleteInput,
|
|
247
|
+
Content: AutocompleteContent,
|
|
248
|
+
Empty: AutocompleteEmpty,
|
|
249
|
+
List: AutocompleteList,
|
|
250
|
+
Item: AutocompleteItem,
|
|
251
|
+
Group: AutocompleteGroup,
|
|
252
|
+
GroupLabel: AutocompleteGroupLabel,
|
|
253
|
+
GroupList: AutocompleteGroupItemList,
|
|
254
|
+
Row: AutocompleteRow,
|
|
255
|
+
Separator: AutocompleteSeparator,
|
|
256
|
+
Clear: AutocompleteClear,
|
|
257
|
+
|
|
258
|
+
Positioner: BaseAutocomplete.Positioner,
|
|
259
|
+
Portal: BaseAutocomplete.Portal,
|
|
260
|
+
Popup: AutocompletePopup,
|
|
261
|
+
Backdrop: AutocompleteBackdrop,
|
|
262
|
+
|
|
263
|
+
ListItem: AutocompleteItem,
|
|
264
|
+
GroupItem: AutocompleteGroupItem,
|
|
265
|
+
|
|
266
|
+
Unstyled: BaseAutocomplete,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
function createAutocomplete<TItem>() {
|
|
270
|
+
function TypedRoot(
|
|
271
|
+
props: Omit<BaseAutocompleteRootProps<TItem>, 'items'> & {
|
|
272
|
+
items: readonly TItem[];
|
|
273
|
+
},
|
|
274
|
+
) {
|
|
275
|
+
return <AutocompleteRoot {...(props as any)} />;
|
|
276
|
+
}
|
|
277
|
+
function TypedList(
|
|
278
|
+
props: Omit<BaseAutocompleteListProps, 'children'> & {
|
|
279
|
+
children?: ReactNode | ((item: TItem, index: number) => ReactNode);
|
|
280
|
+
},
|
|
281
|
+
) {
|
|
282
|
+
return <AutocompleteList {...props} />;
|
|
283
|
+
}
|
|
284
|
+
return Object.assign(TypedRoot, {
|
|
285
|
+
...baseSubComponents,
|
|
286
|
+
Input: AutocompleteInput,
|
|
287
|
+
Content: AutocompleteContent,
|
|
288
|
+
List: TypedList,
|
|
289
|
+
Empty: AutocompleteEmpty,
|
|
290
|
+
Item: AutocompleteItem,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function createAutocompleteGrouped<
|
|
295
|
+
TItemGroup extends { items: readonly any[] },
|
|
296
|
+
>() {
|
|
297
|
+
function TypedRoot(
|
|
298
|
+
props: Omit<
|
|
299
|
+
BaseAutocompleteRootProps<TItemGroup['items'][number]>,
|
|
300
|
+
'items'
|
|
301
|
+
> & {
|
|
302
|
+
items: TItemGroup[];
|
|
303
|
+
},
|
|
304
|
+
) {
|
|
305
|
+
return <AutocompleteRoot {...(props as any)} />;
|
|
306
|
+
}
|
|
307
|
+
function TypedList(
|
|
308
|
+
props: Omit<BaseAutocompleteListProps, 'children'> & {
|
|
309
|
+
children?:
|
|
310
|
+
| ReactNode
|
|
311
|
+
| ((group: TItemGroup, groupIndex: number) => ReactNode);
|
|
312
|
+
},
|
|
313
|
+
) {
|
|
314
|
+
return <AutocompleteList {...props} />;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return Object.assign(TypedRoot, {
|
|
318
|
+
...baseSubComponents,
|
|
319
|
+
Content: AutocompleteContent,
|
|
320
|
+
Item: AutocompleteGroupItem,
|
|
321
|
+
Input: AutocompleteInput,
|
|
322
|
+
List: TypedList,
|
|
323
|
+
Group: AutocompleteGroup,
|
|
324
|
+
GroupLabel: AutocompleteGroupLabel,
|
|
325
|
+
GroupList: AutocompleteGroupItemList,
|
|
326
|
+
Empty: AutocompleteEmpty,
|
|
327
|
+
Row: AutocompleteRow,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export const Autocomplete = Object.assign(AutocompleteRoot, {
|
|
332
|
+
create: createAutocomplete,
|
|
333
|
+
createGrouped: createAutocompleteGrouped,
|
|
334
|
+
|
|
335
|
+
...baseSubComponents,
|
|
336
|
+
});
|
|
@@ -54,10 +54,7 @@ export const AsButton: Story = {
|
|
|
54
54
|
render(args) {
|
|
55
55
|
return (
|
|
56
56
|
<Box gap items="center">
|
|
57
|
-
<Button
|
|
58
|
-
{...args}
|
|
59
|
-
render={<Chip color="primary">Clickable Chip</Chip>}
|
|
60
|
-
/>
|
|
57
|
+
<Button render={<Chip color="primary">Clickable Chip</Chip>} />
|
|
61
58
|
<Chip {...args}>Non-clickable Chip</Chip>
|
|
62
59
|
</Box>
|
|
63
60
|
);
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { UseRenderRenderProp } from '@base-ui/react/use-render';
|
|
2
1
|
import classNames from 'clsx';
|
|
3
|
-
import {
|
|
2
|
+
import { Ref } from 'react';
|
|
4
3
|
import { PaletteName } from '../../uno/index.js';
|
|
5
|
-
import { SlotDiv } from '../utility/SlotDiv.js';
|
|
4
|
+
import { SlotDiv, SlotDivProps } from '../utility/SlotDiv.js';
|
|
6
5
|
|
|
7
|
-
export interface ChipProps extends
|
|
6
|
+
export interface ChipProps extends SlotDivProps {
|
|
8
7
|
color?: PaletteName;
|
|
9
|
-
render?: UseRenderRenderProp;
|
|
10
8
|
ref?: Ref<any>;
|
|
11
9
|
}
|
|
12
10
|
|
|
@@ -15,9 +13,9 @@ export function Chip({ className, color, ...rest }: ChipProps) {
|
|
|
15
13
|
<SlotDiv
|
|
16
14
|
className={classNames(
|
|
17
15
|
color && `palette-${color}`,
|
|
18
|
-
'layer-composed:(inline-flex flex-row items-center gap-1 whitespace-nowrap font-normal)',
|
|
16
|
+
'layer-composed:(inline-flex flex-row items-center gap-1 whitespace-nowrap text-xs font-normal)',
|
|
19
17
|
'layer-composed:(border border-light rounded-lg border-solid color-contrast bg-main-wash)',
|
|
20
|
-
'layer-composed:(px-sm py-xs
|
|
18
|
+
'layer-composed:[&:not(:is(button))]:(px-sm py-xs)',
|
|
21
19
|
className,
|
|
22
20
|
)}
|
|
23
21
|
role={rest.onClick ? 'button' : undefined}
|