@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.
Files changed (104) hide show
  1. package/dist/cjs/components/autocomplete/Autocomplete.d.ts +112 -0
  2. package/dist/cjs/components/autocomplete/Autocomplete.js +119 -0
  3. package/dist/cjs/components/autocomplete/Autocomplete.js.map +1 -0
  4. package/dist/cjs/components/autocomplete/Autocomplete.stories.d.ts +52 -0
  5. package/dist/cjs/components/autocomplete/Autocomplete.stories.js +93 -0
  6. package/dist/cjs/components/autocomplete/Autocomplete.stories.js.map +1 -0
  7. package/dist/cjs/components/chip/Chip.d.ts +3 -4
  8. package/dist/cjs/components/chip/Chip.js +1 -1
  9. package/dist/cjs/components/chip/Chip.js.map +1 -1
  10. package/dist/cjs/components/chip/Chip.stories.js +1 -1
  11. package/dist/cjs/components/chip/Chip.stories.js.map +1 -1
  12. package/dist/cjs/components/dialog/Dialog.js +7 -7
  13. package/dist/cjs/components/dialog/Dialog.js.map +1 -1
  14. package/dist/cjs/components/dropdownMenu/DropdownMenu.js +11 -44
  15. package/dist/cjs/components/dropdownMenu/DropdownMenu.js.map +1 -1
  16. package/dist/cjs/components/index.d.ts +2 -0
  17. package/dist/cjs/components/index.js +2 -0
  18. package/dist/cjs/components/index.js.map +1 -1
  19. package/dist/cjs/components/input/Input.d.ts +7 -2
  20. package/dist/cjs/components/input/Input.js +26 -12
  21. package/dist/cjs/components/input/Input.js.map +1 -1
  22. package/dist/cjs/components/input/Input.stories.d.ts +5 -1
  23. package/dist/cjs/components/input/Input.stories.js +6 -2
  24. package/dist/cjs/components/input/Input.stories.js.map +1 -1
  25. package/dist/cjs/components/layouts/PageNowPlaying.d.ts +1 -2
  26. package/dist/cjs/components/layouts/PageNowPlaying.js +2 -4
  27. package/dist/cjs/components/layouts/PageNowPlaying.js.map +1 -1
  28. package/dist/cjs/components/popover/Popover.js +6 -5
  29. package/dist/cjs/components/popover/Popover.js.map +1 -1
  30. package/dist/cjs/components/primitives/menus.d.ts +5 -0
  31. package/dist/cjs/components/primitives/menus.js +14 -0
  32. package/dist/cjs/components/primitives/menus.js.map +1 -0
  33. package/dist/cjs/components/quickAction/QuickAction.d.ts +17 -0
  34. package/dist/cjs/components/quickAction/QuickAction.js +63 -0
  35. package/dist/cjs/components/quickAction/QuickAction.js.map +1 -0
  36. package/dist/cjs/components/quickAction/QuickAction.stories.d.ts +22 -0
  37. package/dist/cjs/components/quickAction/QuickAction.stories.js +61 -0
  38. package/dist/cjs/components/quickAction/QuickAction.stories.js.map +1 -0
  39. package/dist/cjs/systems/inputs.d.ts +3 -0
  40. package/dist/cjs/systems/inputs.js +14 -0
  41. package/dist/cjs/systems/inputs.js.map +1 -0
  42. package/dist/cjs/uno/preflights/layers.js +1 -1
  43. package/dist/cjs/uno/preflights/layers.js.map +1 -1
  44. package/dist/css/main.css +7 -6
  45. package/dist/esm/components/autocomplete/Autocomplete.d.ts +112 -0
  46. package/dist/esm/components/autocomplete/Autocomplete.js +113 -0
  47. package/dist/esm/components/autocomplete/Autocomplete.js.map +1 -0
  48. package/dist/esm/components/autocomplete/Autocomplete.stories.d.ts +52 -0
  49. package/dist/esm/components/autocomplete/Autocomplete.stories.js +90 -0
  50. package/dist/esm/components/autocomplete/Autocomplete.stories.js.map +1 -0
  51. package/dist/esm/components/chip/Chip.d.ts +3 -4
  52. package/dist/esm/components/chip/Chip.js +1 -1
  53. package/dist/esm/components/chip/Chip.js.map +1 -1
  54. package/dist/esm/components/chip/Chip.stories.js +1 -1
  55. package/dist/esm/components/chip/Chip.stories.js.map +1 -1
  56. package/dist/esm/components/dialog/Dialog.js +7 -7
  57. package/dist/esm/components/dialog/Dialog.js.map +1 -1
  58. package/dist/esm/components/dropdownMenu/DropdownMenu.js +8 -8
  59. package/dist/esm/components/dropdownMenu/DropdownMenu.js.map +1 -1
  60. package/dist/esm/components/index.d.ts +2 -0
  61. package/dist/esm/components/index.js +2 -0
  62. package/dist/esm/components/index.js.map +1 -1
  63. package/dist/esm/components/input/Input.d.ts +7 -2
  64. package/dist/esm/components/input/Input.js +29 -14
  65. package/dist/esm/components/input/Input.js.map +1 -1
  66. package/dist/esm/components/input/Input.stories.d.ts +5 -1
  67. package/dist/esm/components/input/Input.stories.js +5 -1
  68. package/dist/esm/components/input/Input.stories.js.map +1 -1
  69. package/dist/esm/components/layouts/PageNowPlaying.d.ts +1 -2
  70. package/dist/esm/components/layouts/PageNowPlaying.js +2 -4
  71. package/dist/esm/components/layouts/PageNowPlaying.js.map +1 -1
  72. package/dist/esm/components/popover/Popover.js +6 -5
  73. package/dist/esm/components/popover/Popover.js.map +1 -1
  74. package/dist/esm/components/primitives/menus.d.ts +5 -0
  75. package/dist/esm/components/primitives/menus.js +8 -0
  76. package/dist/esm/components/primitives/menus.js.map +1 -0
  77. package/dist/esm/components/quickAction/QuickAction.d.ts +17 -0
  78. package/dist/esm/components/quickAction/QuickAction.js +56 -0
  79. package/dist/esm/components/quickAction/QuickAction.js.map +1 -0
  80. package/dist/esm/components/quickAction/QuickAction.stories.d.ts +22 -0
  81. package/dist/esm/components/quickAction/QuickAction.stories.js +55 -0
  82. package/dist/esm/components/quickAction/QuickAction.stories.js.map +1 -0
  83. package/dist/esm/systems/inputs.d.ts +3 -0
  84. package/dist/esm/systems/inputs.js +11 -0
  85. package/dist/esm/systems/inputs.js.map +1 -0
  86. package/dist/esm/uno/preflights/layers.js +1 -1
  87. package/dist/esm/uno/preflights/layers.js.map +1 -1
  88. package/package.json +1 -1
  89. package/src/components/autocomplete/Autocomplete.stories.tsx +212 -0
  90. package/src/components/autocomplete/Autocomplete.tsx +336 -0
  91. package/src/components/chip/Chip.stories.tsx +1 -4
  92. package/src/components/chip/Chip.tsx +5 -7
  93. package/src/components/dialog/Dialog.tsx +535 -535
  94. package/src/components/dropdownMenu/DropdownMenu.tsx +173 -190
  95. package/src/components/index.ts +2 -0
  96. package/src/components/input/Input.stories.tsx +14 -1
  97. package/src/components/input/Input.tsx +107 -74
  98. package/src/components/layouts/PageNowPlaying.tsx +1 -5
  99. package/src/components/popover/Popover.tsx +123 -132
  100. package/src/components/primitives/menus.tsx +44 -0
  101. package/src/components/quickAction/QuickAction.stories.tsx +106 -0
  102. package/src/components/quickAction/QuickAction.tsx +107 -0
  103. package/src/systems/inputs.ts +11 -0
  104. 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 { HTMLAttributes, Ref } from 'react';
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 HTMLAttributes<HTMLElement> {
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 text-xs)',
18
+ 'layer-composed:[&:not(:is(button))]:(px-sm py-xs)',
21
19
  className,
22
20
  )}
23
21
  role={rest.onClick ? 'button' : undefined}