@boxcustodia/library 2.0.0-alpha.13 → 2.0.0-alpha.15
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/index.cjs.js +1 -138
- package/dist/index.d.ts +1083 -717
- package/dist/index.es.js +7059 -56179
- package/dist/theme.css +1 -1
- package/package.json +34 -26
- package/src/__doc__/Changelog.mdx +6 -6
- package/src/__doc__/Examples.tsx +1 -1
- package/src/__doc__/Intro.mdx +3 -3
- package/src/__doc__/Tabs.mdx +112 -0
- package/src/__doc__/V2.mdx +1245 -0
- package/src/components/accordion/accordion.stories.tsx +143 -0
- package/src/components/accordion/accordion.tsx +135 -0
- package/src/components/accordion/index.ts +1 -0
- package/src/components/alert/alert.stories.tsx +24 -4
- package/src/components/alert/alert.tsx +17 -9
- package/src/components/alert-dialog/alert-dialog.stories.tsx +24 -0
- package/src/components/alert-dialog/alert-dialog.test.tsx +1 -1
- package/src/components/alert-dialog/alert-dialog.tsx +58 -10
- package/src/components/auto-complete/auto-complete.stories.tsx +615 -200
- package/src/components/auto-complete/auto-complete.tsx +420 -68
- package/src/components/auto-complete/index.ts +0 -1
- package/src/components/avatar/avatar.stories.tsx +162 -21
- package/src/components/avatar/avatar.tsx +79 -20
- package/src/components/button/button.stories.tsx +236 -294
- package/src/components/button/button.test.tsx +10 -17
- package/src/components/button/button.tsx +53 -18
- package/src/components/button/components/base-button.tsx +25 -53
- package/src/components/button/index.ts +0 -1
- package/src/components/calendar/calendar.stories.tsx +1 -1
- package/src/components/calendar/calendar.tsx +4 -4
- package/src/components/card/card.stories.tsx +140 -69
- package/src/components/card/card.tsx +155 -54
- package/src/components/center/center.stories.tsx +22 -39
- package/src/components/checkbox/checkbox.stories.tsx +25 -5
- package/src/components/checkbox/checkbox.tsx +76 -15
- package/src/components/checkbox-group/checkbox-group.stories.tsx +116 -28
- package/src/components/checkbox-group/checkbox-group.tsx +84 -3
- package/src/components/combobox/combobox.stories.tsx +33 -23
- package/src/components/combobox/combobox.tsx +120 -104
- package/src/components/date-picker/date-input.stories.tsx +14 -6
- package/src/components/date-picker/date-input.tsx +3 -3
- package/src/components/date-picker/date-picker.model.ts +13 -4
- package/src/components/date-picker/date-picker.stories.tsx +38 -12
- package/src/components/date-picker/date-picker.tsx +29 -15
- package/src/components/dialog/dialog.stories.tsx +18 -0
- package/src/components/dialog/dialog.test.tsx +1 -1
- package/src/components/dialog/dialog.tsx +51 -20
- package/src/components/divider/divider.stories.tsx +6 -0
- package/src/components/dropzone/dropzone.stories.tsx +70 -90
- package/src/components/dropzone/dropzone.tsx +383 -105
- package/src/components/dropzone/index.ts +0 -1
- package/src/components/empty/empty.stories.tsx +164 -0
- package/src/components/empty/empty.tsx +156 -0
- package/src/components/empty/index.ts +1 -0
- package/src/components/field/field.stories.tsx +226 -3
- package/src/components/field/field.tsx +77 -42
- package/src/components/form/form.stories.tsx +320 -197
- package/src/components/form/form.tsx +3 -23
- package/src/components/index.ts +2 -6
- package/src/components/input/input.stories.tsx +5 -5
- package/src/components/input/input.tsx +5 -5
- package/src/components/kbd/kbd.stories.tsx +1 -0
- package/src/components/label/label.stories.tsx +16 -0
- package/src/components/label/label.tsx +13 -2
- package/src/components/loader/loader.stories.tsx +7 -5
- package/src/components/loader/loader.tsx +8 -3
- package/src/components/menu/menu-primitives.tsx +207 -196
- package/src/components/menu/menu.stories.tsx +275 -146
- package/src/components/menu/menu.tsx +146 -54
- package/src/components/number-input/number-input.stories.tsx +27 -4
- package/src/components/number-input/number-input.test.tsx +2 -2
- package/src/components/number-input/number-input.tsx +29 -33
- package/src/components/otp/index.ts +1 -0
- package/src/components/otp/otp.stories.tsx +209 -0
- package/src/components/otp/otp.tsx +100 -0
- package/src/components/pagination/index.ts +1 -0
- package/src/components/pagination/pagination.model.ts +2 -0
- package/src/components/pagination/pagination.stories.tsx +153 -59
- package/src/components/pagination/pagination.test.tsx +122 -57
- package/src/components/pagination/pagination.tsx +575 -77
- package/src/components/password/password.stories.tsx +18 -3
- package/src/components/password/password.tsx +26 -10
- package/src/components/popover/popover.stories.tsx +26 -5
- package/src/components/popover/popover.tsx +15 -23
- package/src/components/progress/progress.stories.tsx +1 -0
- package/src/components/radio-group/index.ts +1 -0
- package/src/components/radio-group/radio-group.stories.tsx +251 -0
- package/src/components/radio-group/radio-group.tsx +212 -0
- package/src/components/scroll-area/scroll-area.stories.tsx +1 -0
- package/src/components/select/select.stories.tsx +118 -19
- package/src/components/select/select.tsx +67 -62
- package/src/components/skeleton/skeleton.stories.tsx +1 -0
- package/src/components/stack/stack.stories.tsx +179 -89
- package/src/components/stack/stack.tsx +2 -2
- package/src/components/stepper/index.ts +1 -1
- package/src/components/stepper/stepper.stories.tsx +766 -83
- package/src/components/stepper/stepper.test.tsx +18 -18
- package/src/components/stepper/stepper.tsx +554 -0
- package/src/components/switch/switch.stories.tsx +15 -1
- package/src/components/switch/switch.tsx +17 -4
- package/src/components/table/index.ts +0 -2
- package/src/components/table/table.stories.tsx +131 -18
- package/src/components/table/table.test.tsx +1 -1
- package/src/components/table/table.tsx +183 -77
- package/src/components/tabs/tabs.stories.tsx +372 -155
- package/src/components/tabs/tabs.test.tsx +12 -12
- package/src/components/tabs/tabs.tsx +72 -149
- package/src/components/tag/index.ts +0 -1
- package/src/components/tag/tag.stories.tsx +147 -120
- package/src/components/tag/tag.tsx +47 -95
- package/src/components/textarea/textarea.stories.tsx +8 -22
- package/src/components/textarea/textarea.tsx +17 -79
- package/src/components/timeline/timeline.stories.tsx +322 -42
- package/src/components/timeline/timeline.tsx +359 -132
- package/src/components/toast/toast.stories.tsx +1 -0
- package/src/components/tooltip/tooltip.tsx +11 -9
- package/src/components/tree/index.ts +0 -1
- package/src/components/tree/tree.stories.tsx +364 -408
- package/src/components/tree/tree.test.tsx +163 -0
- package/src/components/tree/tree.tsx +212 -36
- package/src/hooks/useAsync/__doc__/useAsync.stories.tsx +5 -5
- package/src/hooks/useClipboard/__doc__/useClipboard.stories.tsx +1 -3
- package/src/hooks/useDebounceCallback/__doc__/useDebouncedCallback.stories.tsx +6 -6
- package/src/hooks/useDocumentTitle/__doc__/useDocumentTitle.stories.tsx +1 -1
- package/src/hooks/useEventListener/__test__/useEventListener.test.tsx +1 -1
- package/src/hooks/useLocalStorage/__doc__/useLocalStorage.stories.tsx +1 -1
- package/src/hooks/usePagination/usePagination.tsx +36 -24
- package/src/styles/theme.css +1 -1
- package/src/utils/form.tsx +69 -37
- package/src/utils/index.ts +1 -1
- package/src/__doc__/Migration.mdx +0 -451
- package/src/components/auto-complete/auto-complete-primitives.tsx +0 -155
- package/src/components/background-image/background-image.stories.tsx +0 -21
- package/src/components/background-image/background-image.test.tsx +0 -29
- package/src/components/background-image/background-image.tsx +0 -23
- package/src/components/background-image/index.ts +0 -1
- package/src/components/button/button.variants.ts +0 -44
- package/src/components/button/components/loader-overlay.tsx +0 -21
- package/src/components/button/components/loading-icon.tsx +0 -47
- package/src/components/dropzone/upload-primitives.tsx +0 -310
- package/src/components/dropzone/use-dropzone.ts +0 -122
- package/src/components/empty-state/empty-state.stories.tsx +0 -56
- package/src/components/empty-state/empty-state.tsx +0 -39
- package/src/components/empty-state/index.ts +0 -1
- package/src/components/heading/heading.stories.tsx +0 -74
- package/src/components/heading/heading.tsx +0 -28
- package/src/components/heading/heading.variants.ts +0 -27
- package/src/components/heading/index.ts +0 -1
- package/src/components/kbd/kbd.variants.ts +0 -26
- package/src/components/menu/util/render-menu-item.tsx +0 -54
- package/src/components/multi-select/hooks/use-multi-select.ts +0 -66
- package/src/components/multi-select/index.ts +0 -1
- package/src/components/multi-select/multi-select.stories.tsx +0 -294
- package/src/components/multi-select/multi-select.tsx +0 -300
- package/src/components/multi-select/multi-select.variants.ts +0 -22
- package/src/components/pagination/components/pagination-option.tsx +0 -27
- package/src/components/show/index.ts +0 -1
- package/src/components/show/show.stories.tsx +0 -197
- package/src/components/show/show.test.tsx +0 -41
- package/src/components/show/show.tsx +0 -16
- package/src/components/stepper/Stepper.tsx +0 -190
- package/src/components/stepper/context/stepper-context.tsx +0 -11
- package/src/components/table/table-primitives.tsx +0 -122
- package/src/components/table/table.model.ts +0 -20
- package/src/components/table-pagination/index.ts +0 -2
- package/src/components/table-pagination/table-pagination.model.ts +0 -2
- package/src/components/table-pagination/table-pagination.stories.tsx +0 -23
- package/src/components/table-pagination/table-pagination.test.tsx +0 -32
- package/src/components/table-pagination/table-pagination.tsx +0 -108
- package/src/components/tabs/context/tabs-context.tsx +0 -14
- package/src/components/tag/tag.variants.ts +0 -31
- package/src/components/timeline/timeline-status.ts +0 -5
- package/src/components/tree/hooks/use-controllable-tree-state.ts +0 -80
- package/src/components/tree/tree-primitives.tsx +0 -126
|
@@ -1,82 +1,434 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete";
|
|
4
|
+
import { ChevronsUpDownIcon, XIcon } from "lucide-react";
|
|
5
|
+
import type React from "react";
|
|
6
|
+
import { cn } from "../../lib";
|
|
7
|
+
import { inputBaseClasses } from "../input";
|
|
8
|
+
import { ScrollArea } from "../scroll-area";
|
|
9
|
+
|
|
10
|
+
export const AutocompleteRoot = AutocompletePrimitive.Root;
|
|
11
|
+
|
|
12
|
+
export function AutocompleteInput({
|
|
13
|
+
className,
|
|
14
|
+
adornment,
|
|
15
|
+
startAddon,
|
|
16
|
+
triggerProps,
|
|
17
|
+
clearProps,
|
|
18
|
+
...props
|
|
19
|
+
}: AutocompletePrimitive.Input.Props & {
|
|
20
|
+
adornment?: "trigger" | "clear";
|
|
21
|
+
startAddon?: React.ReactNode;
|
|
22
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
23
|
+
triggerProps?: AutocompletePrimitive.Trigger.Props;
|
|
24
|
+
clearProps?: AutocompletePrimitive.Clear.Props;
|
|
25
|
+
}): React.ReactElement {
|
|
26
|
+
return (
|
|
27
|
+
<AutocompletePrimitive.InputGroup
|
|
28
|
+
className="relative not-has-[>*.w-full]:w-fit w-full text-foreground has-disabled:opacity-64"
|
|
29
|
+
data-slot="autocomplete-input-group"
|
|
30
|
+
>
|
|
31
|
+
{startAddon && (
|
|
32
|
+
<div
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
className="pointer-events-none absolute inset-y-0 start-px z-10 flex items-center ps-[calc(--spacing(3)-1px)] opacity-80 [&_svg:not([class*='size-'])]:size-4 [&_svg]:-mx-0.5"
|
|
35
|
+
data-slot="autocomplete-start-addon"
|
|
36
|
+
>
|
|
37
|
+
{startAddon}
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
40
|
+
<AutocompletePrimitive.Input
|
|
41
|
+
className={cn(
|
|
42
|
+
inputBaseClasses,
|
|
43
|
+
"focus-visible:border-ring",
|
|
44
|
+
"aria-invalid:border-error focus-visible:aria-invalid:ring-error/20",
|
|
45
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
46
|
+
startAddon && "ps-9",
|
|
47
|
+
adornment && "pe-9",
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
data-slot="autocomplete-input"
|
|
51
|
+
render={<input autoComplete="off" data-slot="input" />}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
{adornment === "clear" ? (
|
|
55
|
+
<AutocompleteClear {...clearProps} />
|
|
56
|
+
) : adornment === "trigger" ? (
|
|
57
|
+
<AutocompleteTrigger {...triggerProps} />
|
|
58
|
+
) : null}
|
|
59
|
+
</AutocompletePrimitive.InputGroup>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function AutocompletePopup({
|
|
64
|
+
className,
|
|
65
|
+
children,
|
|
66
|
+
side = "bottom",
|
|
67
|
+
sideOffset = 4,
|
|
68
|
+
alignOffset,
|
|
69
|
+
align = "start",
|
|
70
|
+
anchor,
|
|
71
|
+
portalProps,
|
|
72
|
+
...props
|
|
73
|
+
}: AutocompletePrimitive.Popup.Props & {
|
|
74
|
+
align?: AutocompletePrimitive.Positioner.Props["align"];
|
|
75
|
+
sideOffset?: AutocompletePrimitive.Positioner.Props["sideOffset"];
|
|
76
|
+
alignOffset?: AutocompletePrimitive.Positioner.Props["alignOffset"];
|
|
77
|
+
side?: AutocompletePrimitive.Positioner.Props["side"];
|
|
78
|
+
anchor?: AutocompletePrimitive.Positioner.Props["anchor"];
|
|
79
|
+
portalProps?: AutocompletePrimitive.Portal.Props;
|
|
80
|
+
}): React.ReactElement {
|
|
81
|
+
return (
|
|
82
|
+
<AutocompletePrimitive.Portal {...portalProps}>
|
|
83
|
+
<AutocompletePrimitive.Positioner
|
|
84
|
+
align={align}
|
|
85
|
+
alignOffset={alignOffset}
|
|
86
|
+
anchor={anchor}
|
|
87
|
+
className="z-50 select-none"
|
|
88
|
+
data-slot="autocomplete-positioner"
|
|
89
|
+
side={side}
|
|
90
|
+
sideOffset={sideOffset}
|
|
91
|
+
>
|
|
92
|
+
<span
|
|
93
|
+
className={cn(
|
|
94
|
+
"relative flex max-h-full min-w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) rounded-lg border bg-popover shadow-lg/5 transition-[scale,opacity]",
|
|
95
|
+
className,
|
|
96
|
+
)}
|
|
97
|
+
>
|
|
98
|
+
<AutocompletePrimitive.Popup
|
|
99
|
+
className="flex max-h-[min(var(--available-height),23rem)] flex-1 flex-col text-foreground"
|
|
100
|
+
data-slot="autocomplete-popup"
|
|
101
|
+
{...props}
|
|
102
|
+
>
|
|
103
|
+
{children}
|
|
104
|
+
</AutocompletePrimitive.Popup>
|
|
105
|
+
</span>
|
|
106
|
+
</AutocompletePrimitive.Positioner>
|
|
107
|
+
</AutocompletePrimitive.Portal>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function AutocompleteList({
|
|
112
|
+
className,
|
|
113
|
+
...props
|
|
114
|
+
}: AutocompletePrimitive.List.Props): React.ReactElement {
|
|
115
|
+
return (
|
|
116
|
+
<ScrollArea scrollbarGutter scrollFade>
|
|
117
|
+
<AutocompletePrimitive.List
|
|
118
|
+
className={cn(
|
|
119
|
+
"not-empty:scroll-py-1 not-empty:p-1 in-data-has-overflow-y:pe-3",
|
|
120
|
+
className,
|
|
121
|
+
)}
|
|
122
|
+
data-slot="autocomplete-list"
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
</ScrollArea>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function AutocompleteItem({
|
|
130
|
+
className,
|
|
131
|
+
children,
|
|
132
|
+
...props
|
|
133
|
+
}: AutocompletePrimitive.Item.Props): React.ReactElement {
|
|
134
|
+
return (
|
|
135
|
+
<AutocompletePrimitive.Item
|
|
136
|
+
className={cn(
|
|
137
|
+
"flex min-h-8 cursor-default select-none items-center rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm",
|
|
138
|
+
className,
|
|
139
|
+
)}
|
|
140
|
+
data-slot="autocomplete-item"
|
|
141
|
+
{...props}
|
|
142
|
+
>
|
|
143
|
+
{children}
|
|
144
|
+
</AutocompletePrimitive.Item>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function AutocompleteSeparator({
|
|
149
|
+
className,
|
|
150
|
+
...props
|
|
151
|
+
}: AutocompletePrimitive.Separator.Props): React.ReactElement {
|
|
152
|
+
return (
|
|
153
|
+
<AutocompletePrimitive.Separator
|
|
154
|
+
className={cn("mx-2 my-1 h-px bg-border last:hidden", className)}
|
|
155
|
+
data-slot="autocomplete-separator"
|
|
156
|
+
{...props}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function AutocompleteGroup({
|
|
162
|
+
className,
|
|
163
|
+
...props
|
|
164
|
+
}: AutocompletePrimitive.Group.Props): React.ReactElement {
|
|
165
|
+
return (
|
|
166
|
+
<AutocompletePrimitive.Group
|
|
167
|
+
className={cn("[[role=group]+&]:mt-1.5", className)}
|
|
168
|
+
data-slot="autocomplete-group"
|
|
169
|
+
{...props}
|
|
170
|
+
/>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function AutocompleteGroupLabel({
|
|
175
|
+
className,
|
|
176
|
+
...props
|
|
177
|
+
}: AutocompletePrimitive.GroupLabel.Props): React.ReactElement {
|
|
178
|
+
return (
|
|
179
|
+
<AutocompletePrimitive.GroupLabel
|
|
180
|
+
className={cn(
|
|
181
|
+
"px-2 py-1.5 font-medium text-muted-foreground text-xs",
|
|
182
|
+
className,
|
|
183
|
+
)}
|
|
184
|
+
data-slot="autocomplete-group-label"
|
|
185
|
+
{...props}
|
|
186
|
+
/>
|
|
187
|
+
);
|
|
16
188
|
}
|
|
17
189
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
190
|
+
export function AutocompleteEmpty({
|
|
191
|
+
className,
|
|
192
|
+
...props
|
|
193
|
+
}: AutocompletePrimitive.Empty.Props): React.ReactElement {
|
|
194
|
+
return (
|
|
195
|
+
<AutocompletePrimitive.Empty
|
|
196
|
+
className={cn(
|
|
197
|
+
"p-2 text-center text-base text-muted-foreground sm:text-sm empty:hidden",
|
|
198
|
+
className,
|
|
199
|
+
)}
|
|
200
|
+
data-slot="autocomplete-empty"
|
|
201
|
+
{...props}
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function AutocompleteTrigger({
|
|
207
|
+
className,
|
|
208
|
+
children,
|
|
209
|
+
...props
|
|
210
|
+
}: AutocompletePrimitive.Trigger.Props): React.ReactElement {
|
|
211
|
+
return (
|
|
212
|
+
<AutocompletePrimitive.Trigger
|
|
213
|
+
className={cn(
|
|
214
|
+
"absolute end-0.5 top-1/2 inline-flex size-8 shrink-0 -translate-y-1/2 cursor-pointer items-center justify-center rounded-md border border-transparent opacity-80 outline-none transition-colors pointer-coarse:after:absolute pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:opacity-100 sm:size-7 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
215
|
+
className,
|
|
216
|
+
)}
|
|
217
|
+
data-slot="autocomplete-trigger"
|
|
218
|
+
{...props}
|
|
219
|
+
>
|
|
220
|
+
{children ?? (
|
|
221
|
+
<AutocompletePrimitive.Icon data-slot="autocomplete-icon">
|
|
222
|
+
<ChevronsUpDownIcon />
|
|
223
|
+
</AutocompletePrimitive.Icon>
|
|
224
|
+
)}
|
|
225
|
+
</AutocompletePrimitive.Trigger>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function AutocompleteClear({
|
|
230
|
+
className,
|
|
231
|
+
children,
|
|
232
|
+
...props
|
|
233
|
+
}: AutocompletePrimitive.Clear.Props): React.ReactElement {
|
|
234
|
+
return (
|
|
235
|
+
<AutocompletePrimitive.Clear
|
|
236
|
+
className={cn(
|
|
237
|
+
"absolute end-0.5 top-1/2 inline-flex size-8 shrink-0 -translate-y-1/2 cursor-pointer items-center justify-center rounded-md border border-transparent opacity-80 outline-none transition-[color,background-color,box-shadow,opacity] pointer-coarse:after:absolute pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:opacity-100 sm:size-7 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
238
|
+
className,
|
|
239
|
+
)}
|
|
240
|
+
data-slot="autocomplete-clear"
|
|
241
|
+
{...props}
|
|
242
|
+
>
|
|
243
|
+
{children ?? <XIcon />}
|
|
244
|
+
</AutocompletePrimitive.Clear>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Groups items into a horizontal row within the list.
|
|
250
|
+
* Use to create multi-column grid layouts (color swatches, icon grids, emoji pickers).
|
|
251
|
+
* Each `AutocompleteItem` inside the row remains fully keyboard-navigable.
|
|
252
|
+
*
|
|
253
|
+
* ```tsx
|
|
254
|
+
* <AutocompleteList>
|
|
255
|
+
* {(row) => (
|
|
256
|
+
* <AutocompleteRow key={row.id}>
|
|
257
|
+
* {row.items.map((item) => (
|
|
258
|
+
* <AutocompleteItem key={item.value} value={item}>
|
|
259
|
+
* {item.label}
|
|
260
|
+
* </AutocompleteItem>
|
|
261
|
+
* ))}
|
|
262
|
+
* </AutocompleteRow>
|
|
263
|
+
* )}
|
|
264
|
+
* </AutocompleteList>
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
export function AutocompleteRow({
|
|
268
|
+
className,
|
|
269
|
+
...props
|
|
270
|
+
}: AutocompletePrimitive.Row.Props): React.ReactElement {
|
|
271
|
+
return (
|
|
272
|
+
<AutocompletePrimitive.Row
|
|
273
|
+
className={className}
|
|
274
|
+
data-slot="autocomplete-row"
|
|
275
|
+
{...props}
|
|
276
|
+
/>
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Renders the selected value's label outside the input element.
|
|
282
|
+
* Useful when building custom trigger-style layouts where the selected item
|
|
283
|
+
* must be displayed independently — e.g., inside a badge, a button, or a custom
|
|
284
|
+
* trigger that replaces the input entirely.
|
|
285
|
+
* Renders nothing when no item is selected.
|
|
286
|
+
*/
|
|
287
|
+
export function AutocompleteValue({
|
|
288
|
+
...props
|
|
289
|
+
}: AutocompletePrimitive.Value.Props): React.ReactElement {
|
|
290
|
+
return (
|
|
291
|
+
<AutocompletePrimitive.Value data-slot="autocomplete-value" {...props} />
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function AutocompleteStatus({
|
|
296
|
+
className,
|
|
297
|
+
...props
|
|
298
|
+
}: AutocompletePrimitive.Status.Props): React.ReactElement {
|
|
299
|
+
return (
|
|
300
|
+
<AutocompletePrimitive.Status
|
|
301
|
+
className={cn(
|
|
302
|
+
"px-3 py-2 font-medium text-muted-foreground text-xs empty:m-0 empty:p-0",
|
|
303
|
+
className,
|
|
304
|
+
)}
|
|
305
|
+
data-slot="autocomplete-status"
|
|
306
|
+
{...props}
|
|
307
|
+
/>
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function AutocompleteCollection({
|
|
312
|
+
...props
|
|
313
|
+
}: AutocompletePrimitive.Collection.Props): React.ReactElement {
|
|
314
|
+
return (
|
|
315
|
+
<AutocompletePrimitive.Collection
|
|
316
|
+
data-slot="autocomplete-collection"
|
|
317
|
+
{...props}
|
|
318
|
+
/>
|
|
319
|
+
);
|
|
29
320
|
}
|
|
30
321
|
|
|
31
|
-
|
|
32
|
-
|
|
322
|
+
export const useAutocompleteFilter: typeof AutocompletePrimitive.useFilter =
|
|
323
|
+
AutocompletePrimitive.useFilter;
|
|
324
|
+
|
|
325
|
+
// ─── Composite ───────────────────────────────────────────────────────────────
|
|
326
|
+
export interface AutocompleteOption {
|
|
327
|
+
value: string;
|
|
328
|
+
label: string;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
interface AutocompleteProps<
|
|
332
|
+
TOption extends AutocompleteOption = AutocompleteOption,
|
|
333
|
+
> {
|
|
334
|
+
items: TOption[];
|
|
335
|
+
value?: TOption | null;
|
|
336
|
+
defaultValue?: TOption | null;
|
|
337
|
+
onValueChange?: (value: TOption | null) => void;
|
|
338
|
+
disabled?: boolean;
|
|
339
|
+
readOnly?: boolean;
|
|
340
|
+
isLoading?: boolean;
|
|
341
|
+
filter?: AutocompletePrimitive.Root.Props<TOption>["filter"];
|
|
342
|
+
autoHighlight?: boolean | "always";
|
|
33
343
|
placeholder?: string;
|
|
34
344
|
emptyMessage?: string;
|
|
35
|
-
|
|
345
|
+
loadingMessage?: string;
|
|
346
|
+
renderOption?: (option: TOption) => React.ReactNode;
|
|
347
|
+
adornment?: "trigger" | "clear";
|
|
348
|
+
startAddon?: React.ReactNode;
|
|
349
|
+
/** Styles the input field. */
|
|
350
|
+
className?: string;
|
|
351
|
+
/** Styles applied to each internal slot. */
|
|
352
|
+
classNames?: {
|
|
353
|
+
/** Dropdown popup container. */
|
|
354
|
+
popup?: string;
|
|
355
|
+
/** Scrollable list inside the popup. */
|
|
356
|
+
list?: string;
|
|
357
|
+
/** Each option item. */
|
|
358
|
+
item?: string;
|
|
359
|
+
/** Empty state message. */
|
|
360
|
+
empty?: string;
|
|
361
|
+
/** Status row (e.g. loading message). */
|
|
362
|
+
status?: string;
|
|
363
|
+
};
|
|
36
364
|
}
|
|
37
365
|
|
|
38
|
-
export
|
|
366
|
+
export function Autocomplete<
|
|
367
|
+
TOption extends AutocompleteOption = AutocompleteOption,
|
|
368
|
+
>({
|
|
39
369
|
items,
|
|
370
|
+
value,
|
|
371
|
+
defaultValue,
|
|
372
|
+
onValueChange,
|
|
373
|
+
disabled,
|
|
374
|
+
readOnly,
|
|
375
|
+
isLoading = false,
|
|
376
|
+
filter,
|
|
377
|
+
autoHighlight,
|
|
40
378
|
placeholder = "Buscar...",
|
|
41
|
-
emptyMessage = "
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
itemClassName,
|
|
50
|
-
itemProps,
|
|
51
|
-
emptyClassName,
|
|
52
|
-
emptyProps,
|
|
53
|
-
}: Props) => {
|
|
379
|
+
emptyMessage = "Sin resultados",
|
|
380
|
+
loadingMessage = "Cargando...",
|
|
381
|
+
renderOption,
|
|
382
|
+
adornment,
|
|
383
|
+
startAddon,
|
|
384
|
+
className,
|
|
385
|
+
classNames,
|
|
386
|
+
}: AutocompleteProps<TOption>): React.ReactElement {
|
|
54
387
|
return (
|
|
55
|
-
<
|
|
56
|
-
|
|
388
|
+
<AutocompleteRoot
|
|
389
|
+
items={items}
|
|
390
|
+
value={value?.label}
|
|
391
|
+
defaultValue={defaultValue?.label}
|
|
392
|
+
onValueChange={(opt) =>
|
|
393
|
+
onValueChange?.((opt as unknown as TOption | undefined) ?? null)
|
|
394
|
+
}
|
|
395
|
+
disabled={disabled}
|
|
396
|
+
readOnly={readOnly}
|
|
397
|
+
filter={filter}
|
|
398
|
+
autoHighlight={autoHighlight}
|
|
399
|
+
itemToStringValue={(opt) => (opt as TOption).label}
|
|
400
|
+
>
|
|
401
|
+
<AutocompleteInput
|
|
402
|
+
adornment={adornment}
|
|
403
|
+
startAddon={startAddon}
|
|
57
404
|
placeholder={placeholder}
|
|
58
|
-
className={
|
|
59
|
-
{...inputProps}
|
|
405
|
+
className={className}
|
|
60
406
|
/>
|
|
61
|
-
<
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
|
|
407
|
+
<AutocompletePopup className={classNames?.popup}>
|
|
408
|
+
<AutocompleteStatus className={classNames?.status}>
|
|
409
|
+
{isLoading ? loadingMessage : undefined}
|
|
410
|
+
</AutocompleteStatus>
|
|
411
|
+
<AutocompleteList className={classNames?.list}>
|
|
412
|
+
{(option) => (
|
|
413
|
+
<AutocompleteItem
|
|
414
|
+
key={(option as TOption).value}
|
|
415
|
+
value={option}
|
|
416
|
+
className={classNames?.item}
|
|
417
|
+
>
|
|
418
|
+
{renderOption
|
|
419
|
+
? renderOption(option as TOption)
|
|
420
|
+
: (option as TOption).label}
|
|
421
|
+
</AutocompleteItem>
|
|
422
|
+
)}
|
|
423
|
+
</AutocompleteList>
|
|
424
|
+
{!isLoading && (
|
|
425
|
+
<AutocompleteEmpty className={classNames?.empty}>
|
|
426
|
+
{emptyMessage}
|
|
427
|
+
</AutocompleteEmpty>
|
|
428
|
+
)}
|
|
429
|
+
</AutocompletePopup>
|
|
430
|
+
</AutocompleteRoot>
|
|
81
431
|
);
|
|
82
|
-
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export { AutocompletePrimitive };
|