@doscientos/ui 0.1.0

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.js ADDED
@@ -0,0 +1,617 @@
1
+ "use client";
2
+
3
+ // src/hooks/use-autosave.ts
4
+ import { useCallback, useEffect, useRef, useState } from "react";
5
+ function useAutosave({
6
+ data,
7
+ onSave,
8
+ debounceMs = 1e3,
9
+ enabled = true,
10
+ serialize = JSON.stringify
11
+ }) {
12
+ const [status, setStatus] = useState("idle");
13
+ const [error, setError] = useState(null);
14
+ const lastSaved = useRef(null);
15
+ const saveRef = useRef(onSave);
16
+ const serializeRef = useRef(serialize);
17
+ useEffect(() => {
18
+ saveRef.current = onSave;
19
+ serializeRef.current = serialize;
20
+ }, [onSave, serialize]);
21
+ const save = useCallback(async (value) => {
22
+ setStatus("saving");
23
+ setError(null);
24
+ try {
25
+ await saveRef.current(value);
26
+ lastSaved.current = serializeRef.current(value);
27
+ setStatus("saved");
28
+ } catch (cause) {
29
+ setError(cause instanceof Error ? cause : new Error("No se pudo guardar."));
30
+ setStatus("error");
31
+ }
32
+ }, []);
33
+ useEffect(() => {
34
+ if (!enabled) return;
35
+ const snapshot = serializeRef.current(data);
36
+ if (lastSaved.current === null) {
37
+ lastSaved.current = snapshot;
38
+ return;
39
+ }
40
+ if (snapshot === lastSaved.current) return;
41
+ const timeout = window.setTimeout(() => void save(data), debounceMs);
42
+ return () => window.clearTimeout(timeout);
43
+ }, [data, debounceMs, enabled, save]);
44
+ return { status, error, saveNow: () => save(data) };
45
+ }
46
+
47
+ // src/hooks/use-debounced-value.ts
48
+ import { useEffect as useEffect2, useState as useState2 } from "react";
49
+ function useDebouncedValue(value, delay = 250) {
50
+ const [debouncedValue, setDebouncedValue] = useState2(value);
51
+ useEffect2(() => {
52
+ const timeout = window.setTimeout(() => setDebouncedValue(value), delay);
53
+ return () => window.clearTimeout(timeout);
54
+ }, [delay, value]);
55
+ return debouncedValue;
56
+ }
57
+
58
+ // src/hooks/use-form-dirty.ts
59
+ import { useCallback as useCallback2, useRef as useRef2, useState as useState3 } from "react";
60
+ function formSnapshot(form) {
61
+ const entries = Array.from(new FormData(form), ([key, value]) => [key, typeof value === "string" ? value : value.name]);
62
+ entries.sort(([left], [right]) => left.localeCompare(right));
63
+ return JSON.stringify(entries);
64
+ }
65
+ function useFormDirty() {
66
+ const formElement = useRef2(null);
67
+ const baseline = useRef2(null);
68
+ const [isDirty, setIsDirty] = useState3(false);
69
+ const recompute = useCallback2(() => {
70
+ if (formElement.current && baseline.current !== null) {
71
+ setIsDirty(formSnapshot(formElement.current) !== baseline.current);
72
+ }
73
+ }, []);
74
+ const reset = useCallback2(() => {
75
+ if (formElement.current) {
76
+ baseline.current = formSnapshot(formElement.current);
77
+ setIsDirty(false);
78
+ }
79
+ }, []);
80
+ const formRef = useCallback2((form) => {
81
+ if (formElement.current) {
82
+ formElement.current.removeEventListener("input", recompute);
83
+ formElement.current.removeEventListener("change", recompute);
84
+ formElement.current.removeEventListener("reset", recompute);
85
+ }
86
+ formElement.current = form;
87
+ if (form) {
88
+ baseline.current = formSnapshot(form);
89
+ setIsDirty(false);
90
+ form.addEventListener("input", recompute);
91
+ form.addEventListener("change", recompute);
92
+ form.addEventListener("reset", recompute);
93
+ }
94
+ }, [recompute]);
95
+ return { formRef, isDirty, markDirty: () => setIsDirty(true), reset };
96
+ }
97
+
98
+ // src/lib/cn.ts
99
+ import { clsx } from "clsx";
100
+ import { twMerge } from "tailwind-merge";
101
+ function cn(...inputs) {
102
+ return twMerge(clsx(inputs));
103
+ }
104
+
105
+ // src/lib/text-match.ts
106
+ function normalize(value) {
107
+ return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLocaleLowerCase();
108
+ }
109
+ function normalizedTextWithRanges(value) {
110
+ const ranges = [];
111
+ let normalized = "";
112
+ let sourceIndex = 0;
113
+ for (const character of value) {
114
+ const start = sourceIndex;
115
+ sourceIndex += character.length;
116
+ const normalizedCharacter = normalize(character);
117
+ normalized += normalizedCharacter;
118
+ for (let index = 0; index < normalizedCharacter.length; index += 1) {
119
+ ranges.push({ start, end: sourceIndex });
120
+ }
121
+ }
122
+ return { normalized, ranges };
123
+ }
124
+ function getTextMatchParts(text, query) {
125
+ const term = normalize(query.trim());
126
+ if (!term) return [{ text, match: false }];
127
+ const { normalized, ranges } = normalizedTextWithRanges(text);
128
+ const parts = [];
129
+ let sourceCursor = 0;
130
+ let index = normalized.indexOf(term);
131
+ while (index !== -1) {
132
+ const rangeStart = ranges[index]?.start;
133
+ const rangeEnd = ranges[index + term.length - 1]?.end;
134
+ if (rangeStart === void 0 || rangeEnd === void 0) break;
135
+ if (rangeStart > sourceCursor) parts.push({ text: text.slice(sourceCursor, rangeStart), match: false });
136
+ parts.push({ text: text.slice(rangeStart, rangeEnd), match: true });
137
+ sourceCursor = rangeEnd;
138
+ index = normalized.indexOf(term, index + term.length);
139
+ }
140
+ if (sourceCursor < text.length) parts.push({ text: text.slice(sourceCursor), match: false });
141
+ return parts.length ? parts : [{ text, match: false }];
142
+ }
143
+
144
+ // src/ui/badge.tsx
145
+ import { cva } from "class-variance-authority";
146
+ import { jsx } from "react/jsx-runtime";
147
+ var badgeVariants = cva("inline-flex w-fit items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium", {
148
+ variants: {
149
+ variant: {
150
+ default: "bg-primary text-primary-foreground",
151
+ secondary: "bg-secondary text-secondary-foreground",
152
+ neutral: "bg-muted text-muted-foreground",
153
+ success: "bg-success/10 text-success",
154
+ warning: "bg-warning/10 text-warning",
155
+ destructive: "bg-destructive/10 text-destructive",
156
+ outline: "border border-border text-foreground"
157
+ }
158
+ },
159
+ defaultVariants: { variant: "default" }
160
+ });
161
+ function Badge({ className, variant, ...props }) {
162
+ return /* @__PURE__ */ jsx("span", { "data-slot": "badge", className: cn(badgeVariants({ variant }), className), ...props });
163
+ }
164
+
165
+ // src/ui/button.tsx
166
+ import { cva as cva2 } from "class-variance-authority";
167
+ import { Button as AriaButton } from "react-aria-components";
168
+ import { jsx as jsx2 } from "react/jsx-runtime";
169
+ var buttonVariants = cva2(
170
+ "inline-flex shrink-0 items-center justify-center gap-1.5 rounded-lg border border-transparent text-sm font-medium whitespace-nowrap transition-colors outline-none focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
171
+ {
172
+ variants: {
173
+ variant: {
174
+ default: "bg-primary text-primary-foreground hover:bg-primary/85",
175
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
176
+ outline: "border-border bg-background text-foreground hover:bg-muted",
177
+ ghost: "text-foreground hover:bg-muted",
178
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20",
179
+ link: "text-primary underline-offset-4 hover:underline"
180
+ },
181
+ size: {
182
+ xs: "h-6 px-2 text-xs",
183
+ sm: "h-7 px-2.5 text-xs",
184
+ default: "h-8 px-3",
185
+ lg: "h-10 px-4",
186
+ icon: "size-8 p-0"
187
+ }
188
+ },
189
+ defaultVariants: { variant: "default", size: "default" }
190
+ }
191
+ );
192
+ function Button({ className, variant, size, ...props }) {
193
+ return /* @__PURE__ */ jsx2(AriaButton, { "data-slot": "button", className: cn(buttonVariants({ variant, size }), className), ...props });
194
+ }
195
+
196
+ // src/ui/card.tsx
197
+ import { jsx as jsx3 } from "react/jsx-runtime";
198
+ function Card({ className, ...props }) {
199
+ return /* @__PURE__ */ jsx3("section", { "data-slot": "card", className: cn("rounded-xl border border-border bg-card text-foreground shadow-sm", className), ...props });
200
+ }
201
+ function CardHeader({ className, ...props }) {
202
+ return /* @__PURE__ */ jsx3("header", { "data-slot": "card-header", className: cn("flex flex-col gap-1.5 p-5", className), ...props });
203
+ }
204
+ function CardTitle({ className, ...props }) {
205
+ return /* @__PURE__ */ jsx3("h2", { "data-slot": "card-title", className: cn("text-base font-semibold", className), ...props });
206
+ }
207
+ function CardDescription({ className, ...props }) {
208
+ return /* @__PURE__ */ jsx3("p", { "data-slot": "card-description", className: cn("text-sm text-muted-foreground", className), ...props });
209
+ }
210
+ function CardContent({ className, ...props }) {
211
+ return /* @__PURE__ */ jsx3("div", { "data-slot": "card-content", className: cn("p-5 pt-0", className), ...props });
212
+ }
213
+ function CardFooter({ className, ...props }) {
214
+ return /* @__PURE__ */ jsx3("footer", { "data-slot": "card-footer", className: cn("flex items-center gap-2 border-t border-border p-5", className), ...props });
215
+ }
216
+
217
+ // src/ui/checkbox.tsx
218
+ import {
219
+ Checkbox as AriaCheckbox
220
+ } from "react-aria-components";
221
+ import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
222
+ function Checkbox({ className, children, ...props }) {
223
+ return /* @__PURE__ */ jsx4(AriaCheckbox, { "data-slot": "checkbox", className: cn("group inline-flex items-center gap-2 text-sm text-foreground data-disabled:cursor-not-allowed data-disabled:opacity-50", className), ...props, children: (state) => /* @__PURE__ */ jsxs(Fragment, { children: [
224
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", className: "grid size-4 place-items-center rounded border border-border bg-background text-xs text-primary-foreground group-data-selected:border-primary group-data-selected:bg-primary group-data-focus-visible:ring-3 group-data-focus-visible:ring-ring/50", children: "\u2713" }),
225
+ typeof children === "function" ? children(state) : children
226
+ ] }) });
227
+ }
228
+
229
+ // src/ui/combobox.tsx
230
+ import { Fragment as Fragment2 } from "react";
231
+ import {
232
+ ComboBox as AriaComboBox,
233
+ ComboBoxValue,
234
+ Input,
235
+ ListBox,
236
+ ListBoxItem,
237
+ Popover
238
+ } from "react-aria-components";
239
+ import { jsx as jsx5 } from "react/jsx-runtime";
240
+ var Combobox = AriaComboBox;
241
+ function ComboboxInput({ className, ...props }) {
242
+ return /* @__PURE__ */ jsx5(Input, { "data-slot": "combobox-input", className: cn("h-8 w-full rounded-lg border border-border bg-background px-2.5 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-3 focus-visible:ring-ring/50", className), ...props });
243
+ }
244
+ function ComboboxContent({ className, ...props }) {
245
+ return /* @__PURE__ */ jsx5(Popover, { "data-slot": "combobox-content", className: cn("max-h-72 w-(--trigger-width) overflow-hidden rounded-xl border border-border bg-background p-1.5 text-foreground shadow-lg", className), ...props });
246
+ }
247
+ function ComboboxList({ className, emptyState, ...props }) {
248
+ return /* @__PURE__ */ jsx5(ListBox, { "data-slot": "combobox-list", className: cn("max-h-64 overflow-y-auto", className), renderEmptyState: emptyState ? () => emptyState : void 0, ...props });
249
+ }
250
+ function ComboboxItem({ className, children, ...props }) {
251
+ return /* @__PURE__ */ jsx5(ListBoxItem, { "data-slot": "combobox-item", className: cn("flex w-full cursor-default items-center justify-between rounded-md px-2 py-1.5 text-sm outline-none data-focused:bg-muted data-disabled:pointer-events-none data-disabled:opacity-50", className), ...props, children });
252
+ }
253
+ function HighlightMatch({ text, query, className }) {
254
+ return /* @__PURE__ */ jsx5("span", { className, children: getTextMatchParts(text, query).map((part, index) => part.match ? /* @__PURE__ */ jsx5("mark", { className: "rounded bg-accent px-0.5 text-accent-foreground", children: part.text }, `${part.text}-${index}`) : /* @__PURE__ */ jsx5(Fragment2, { children: part.text }, `${part.text}-${index}`)) });
255
+ }
256
+
257
+ // src/ui/dialog.tsx
258
+ import { createContext, useContext } from "react";
259
+ import {
260
+ Dialog as AriaDialog,
261
+ Heading,
262
+ Modal,
263
+ ModalOverlay,
264
+ Text
265
+ } from "react-aria-components";
266
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
267
+ var DialogCloseContext = createContext(null);
268
+ function Dialog({ open, children, ...props }) {
269
+ return /* @__PURE__ */ jsx6(ModalOverlay, { isOpen: open, className: "fixed inset-0 z-50 grid place-items-center bg-black/20 p-4 backdrop-blur-[1px]", ...props, children });
270
+ }
271
+ function DialogClose({ onPress, ...props }) {
272
+ const close = useContext(DialogCloseContext);
273
+ return /* @__PURE__ */ jsx6(Button, { onPress: (event) => {
274
+ onPress?.(event);
275
+ close?.();
276
+ }, ...props });
277
+ }
278
+ function DialogContent({ className, children, showCloseButton = true, ...props }) {
279
+ return /* @__PURE__ */ jsx6(Modal, { className: "w-full max-w-md outline-none", children: /* @__PURE__ */ jsx6(AriaDialog, { "data-slot": "dialog-content", className: cn("relative grid max-h-[calc(100dvh-2rem)] gap-4 overflow-y-auto rounded-xl bg-background p-5 text-foreground shadow-xl outline-none", className), ...props, children: ({ close }) => /* @__PURE__ */ jsxs2(DialogCloseContext.Provider, { value: close, children: [
280
+ typeof children === "function" ? children({ close }) : children,
281
+ showCloseButton && /* @__PURE__ */ jsx6(DialogClose, { "aria-label": "Cerrar di\xE1logo", variant: "ghost", size: "icon", className: "absolute top-2 right-2", children: "\xD7" })
282
+ ] }) }) });
283
+ }
284
+ function DialogHeader({ className, ...props }) {
285
+ return /* @__PURE__ */ jsx6("div", { "data-slot": "dialog-header", className: cn("flex flex-col gap-2", className), ...props });
286
+ }
287
+ function DialogFooter({ className, ...props }) {
288
+ return /* @__PURE__ */ jsx6("div", { "data-slot": "dialog-footer", className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className), ...props });
289
+ }
290
+ function DialogTitle({ className, ...props }) {
291
+ return /* @__PURE__ */ jsx6(Heading, { slot: "title", className: cn("text-base font-semibold", className), ...props });
292
+ }
293
+ function DialogDescription({ className, ...props }) {
294
+ return /* @__PURE__ */ jsx6(Text, { slot: "description", className: cn("text-sm text-muted-foreground", className), ...props });
295
+ }
296
+
297
+ // src/ui/confirm-dialog.tsx
298
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
299
+ function ConfirmDialog({ open, onOpenChange, title, description, confirmLabel = "Confirmar", cancelLabel = "Cancelar", destructive = false, pending = false, onConfirm }) {
300
+ return /* @__PURE__ */ jsx7(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs3(DialogContent, { showCloseButton: false, children: [
301
+ /* @__PURE__ */ jsxs3(DialogHeader, { children: [
302
+ /* @__PURE__ */ jsx7(DialogTitle, { children: title }),
303
+ description && /* @__PURE__ */ jsx7(DialogDescription, { children: description })
304
+ ] }),
305
+ /* @__PURE__ */ jsxs3(DialogFooter, { children: [
306
+ /* @__PURE__ */ jsx7(Button, { variant: "outline", isDisabled: pending, onPress: () => onOpenChange(false), children: cancelLabel }),
307
+ /* @__PURE__ */ jsx7(Button, { variant: destructive ? "destructive" : "default", isDisabled: pending, onPress: onConfirm, children: confirmLabel })
308
+ ] })
309
+ ] }) });
310
+ }
311
+
312
+ // src/ui/empty-state.tsx
313
+ import { jsx as jsx8 } from "react/jsx-runtime";
314
+ function EmptyState({ className, ...props }) {
315
+ return /* @__PURE__ */ jsx8("div", { "data-slot": "empty-state", className: cn("flex min-h-44 w-full flex-col items-center justify-center gap-3 rounded-xl border border-dashed border-border p-6 text-center", className), ...props });
316
+ }
317
+ function EmptyStateTitle({ className, ...props }) {
318
+ return /* @__PURE__ */ jsx8("h3", { "data-slot": "empty-state-title", className: cn("text-sm font-medium text-foreground", className), ...props });
319
+ }
320
+ function EmptyStateDescription({ className, ...props }) {
321
+ return /* @__PURE__ */ jsx8("p", { "data-slot": "empty-state-description", className: cn("max-w-sm text-sm text-muted-foreground", className), ...props });
322
+ }
323
+
324
+ // src/ui/label.tsx
325
+ import { forwardRef } from "react";
326
+ import { Label as LabelPrimitive } from "react-aria-components";
327
+ import { jsx as jsx9 } from "react/jsx-runtime";
328
+ var Label = forwardRef(function Label2({ className, ...props }, ref) {
329
+ return /* @__PURE__ */ jsx9(LabelPrimitive, { ref, "data-slot": "label", className: cn("flex items-center gap-2 text-sm font-medium leading-none select-none", className), ...props });
330
+ });
331
+
332
+ // src/ui/field.tsx
333
+ import { jsx as jsx10 } from "react/jsx-runtime";
334
+ function Field({ className, ...props }) {
335
+ return /* @__PURE__ */ jsx10("div", { "data-slot": "field", className: cn("flex w-full flex-col gap-2", className), ...props });
336
+ }
337
+ function FieldLabel({ className, ...props }) {
338
+ return /* @__PURE__ */ jsx10(Label, { "data-slot": "field-label", className: cn("text-foreground", className), ...props });
339
+ }
340
+ function FieldDescription({ className, ...props }) {
341
+ return /* @__PURE__ */ jsx10("p", { "data-slot": "field-description", className: cn("text-sm text-muted-foreground", className), ...props });
342
+ }
343
+ function FieldError({ className, children, ...props }) {
344
+ if (!children) return null;
345
+ return /* @__PURE__ */ jsx10("p", { role: "alert", "data-slot": "field-error", className: cn("text-sm text-destructive", className), ...props, children });
346
+ }
347
+
348
+ // src/ui/input.tsx
349
+ import { forwardRef as forwardRef2 } from "react";
350
+ import { Input as AriaInput } from "react-aria-components";
351
+ import { jsx as jsx11 } from "react/jsx-runtime";
352
+ var InputImpl = forwardRef2(function Input2({ className, type, ...props }, ref) {
353
+ return /* @__PURE__ */ jsx11(AriaInput, { ref, type, "data-slot": "input", className: cn("h-8 w-full min-w-0 rounded-lg border border-border bg-background px-2.5 py-1 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive", className), ...props });
354
+ });
355
+ var Input3 = InputImpl;
356
+
357
+ // src/ui/kbd.tsx
358
+ import { jsx as jsx12 } from "react/jsx-runtime";
359
+ function Kbd({ className, ...props }) {
360
+ return /* @__PURE__ */ jsx12("kbd", { "data-slot": "kbd", className: cn("pointer-events-none inline-flex h-5 min-w-5 items-center justify-center gap-1 rounded-sm bg-muted px-1 font-sans text-xs font-medium text-muted-foreground select-none", className), ...props });
361
+ }
362
+ function KbdGroup({ className, ...props }) {
363
+ return /* @__PURE__ */ jsx12("span", { "data-slot": "kbd-group", className: cn("inline-flex items-center gap-1", className), ...props });
364
+ }
365
+
366
+ // src/ui/menu.tsx
367
+ import {
368
+ Menu as AriaMenu,
369
+ MenuItem as AriaMenuItem,
370
+ MenuTrigger as AriaMenuTrigger,
371
+ Popover as Popover2
372
+ } from "react-aria-components";
373
+ import { jsx as jsx13 } from "react/jsx-runtime";
374
+ var MenuTrigger = AriaMenuTrigger;
375
+ function MenuContent({ className, ...props }) {
376
+ return /* @__PURE__ */ jsx13(Popover2, { "data-slot": "menu-content", className: cn("min-w-40 overflow-hidden rounded-xl border border-border bg-background p-1.5 text-foreground shadow-lg", className), ...props });
377
+ }
378
+ function Menu({ className, ...props }) {
379
+ return /* @__PURE__ */ jsx13(AriaMenu, { "data-slot": "menu", className: cn("outline-none", className), ...props });
380
+ }
381
+ function MenuItem({ className, children, ...props }) {
382
+ return /* @__PURE__ */ jsx13(AriaMenuItem, { "data-slot": "menu-item", className: cn("flex cursor-default items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none data-focused:bg-muted data-disabled:pointer-events-none data-disabled:opacity-50", className), ...props, children });
383
+ }
384
+
385
+ // src/ui/popover.tsx
386
+ import {
387
+ DialogTrigger as AriaDialogTrigger,
388
+ Popover as AriaPopover
389
+ } from "react-aria-components";
390
+ import { jsx as jsx14 } from "react/jsx-runtime";
391
+ var PopoverTrigger = AriaDialogTrigger;
392
+ function Popover3({ className, ...props }) {
393
+ return /* @__PURE__ */ jsx14(AriaPopover, { "data-slot": "popover", offset: 6, className: cn("min-w-48 rounded-xl border border-border bg-background p-1.5 text-foreground shadow-lg outline-none data-entering:animate-in data-entering:fade-in-0 data-entering:zoom-in-95 data-exiting:animate-out data-exiting:fade-out-0 data-exiting:zoom-out-95", className), ...props });
394
+ }
395
+ var PopoverContent = Popover3;
396
+
397
+ // src/ui/search-field.tsx
398
+ import {
399
+ SearchField as AriaSearchField,
400
+ Button as Button2,
401
+ Input as Input4
402
+ } from "react-aria-components";
403
+ import { jsx as jsx15 } from "react/jsx-runtime";
404
+ var SearchField = AriaSearchField;
405
+ function SearchInput({ className, ...props }) {
406
+ return /* @__PURE__ */ jsx15(Input4, { "data-slot": "search-input", className: cn("h-8 w-full min-w-0 rounded-lg border border-border bg-background px-2.5 py-1 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-3 focus-visible:ring-ring/50", className), ...props });
407
+ }
408
+ function SearchClearButton({ className, children = "\xD7", ...props }) {
409
+ return /* @__PURE__ */ jsx15(Button2, { slot: "clear", "data-slot": "search-clear", className: cn("absolute top-1/2 right-1 -translate-y-1/2 rounded p-1 text-muted-foreground outline-none hover:bg-muted data-focus-visible:ring-2 data-focus-visible:ring-ring", className), ...props, children });
410
+ }
411
+
412
+ // src/ui/select.tsx
413
+ import {
414
+ Button as AriaButton2,
415
+ Select as AriaSelect,
416
+ SelectValue as AriaSelectValue,
417
+ ListBox as ListBox2,
418
+ ListBoxItem as ListBoxItem2,
419
+ Popover as Popover4
420
+ } from "react-aria-components";
421
+ import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs4 } from "react/jsx-runtime";
422
+ var Select = AriaSelect;
423
+ function SelectTrigger({ className, children, ...props }) {
424
+ return /* @__PURE__ */ jsx16(AriaButton2, { "data-slot": "select-trigger", className: cn("flex h-8 w-full min-w-36 items-center gap-2 rounded-lg border border-border bg-background px-2.5 text-left text-sm text-foreground outline-none data-focus-visible:ring-3 data-focus-visible:ring-ring/50 data-disabled:cursor-not-allowed data-disabled:opacity-50", className), ...props, children: (state) => /* @__PURE__ */ jsxs4(Fragment3, { children: [
425
+ typeof children === "function" ? children(state) : children,
426
+ /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "ml-auto text-muted-foreground", children: "\u2304" })
427
+ ] }) });
428
+ }
429
+ function SelectValue({ className, ...props }) {
430
+ return /* @__PURE__ */ jsx16(AriaSelectValue, { "data-slot": "select-value", className: cn("flex-1 truncate data-placeholder:text-muted-foreground", className), ...props });
431
+ }
432
+ function SelectContent({ className, ...props }) {
433
+ return /* @__PURE__ */ jsx16(Popover4, { "data-slot": "select-content", className: cn("w-(--trigger-width) overflow-hidden rounded-xl border border-border bg-background p-1.5 text-foreground shadow-lg", className), ...props });
434
+ }
435
+ function SelectList({ className, ...props }) {
436
+ return /* @__PURE__ */ jsx16(ListBox2, { "data-slot": "select-list", className: cn("max-h-64 overflow-y-auto", className), ...props });
437
+ }
438
+ function SelectItem({ className, children, ...props }) {
439
+ return /* @__PURE__ */ jsx16(ListBoxItem2, { "data-slot": "select-item", className: cn("flex cursor-default items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none data-focused:bg-muted data-selected:bg-muted data-disabled:pointer-events-none data-disabled:opacity-50", className), ...props, children });
440
+ }
441
+
442
+ // src/ui/separator.tsx
443
+ import { Separator as AriaSeparator } from "react-aria-components";
444
+ import { jsx as jsx17 } from "react/jsx-runtime";
445
+ function Separator({ className, orientation = "horizontal", ...props }) {
446
+ return /* @__PURE__ */ jsx17(AriaSeparator, { "data-slot": "separator", orientation, className: cn("shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch", className), ...props });
447
+ }
448
+
449
+ // src/ui/skeleton.tsx
450
+ import { jsx as jsx18 } from "react/jsx-runtime";
451
+ function Skeleton({ className, ...props }) {
452
+ return /* @__PURE__ */ jsx18("div", { "aria-hidden": "true", "data-slot": "skeleton", className: cn("animate-pulse rounded-md bg-muted", className), ...props });
453
+ }
454
+
455
+ // src/ui/switch.tsx
456
+ import {
457
+ Switch as AriaSwitch
458
+ } from "react-aria-components";
459
+ import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
460
+ function Switch({ className, children, ...props }) {
461
+ return /* @__PURE__ */ jsx19(AriaSwitch, { "data-slot": "switch", className: cn("group inline-flex items-center gap-2 text-sm text-foreground data-disabled:cursor-not-allowed data-disabled:opacity-50", className), ...props, children: (state) => /* @__PURE__ */ jsxs5(Fragment4, { children: [
462
+ /* @__PURE__ */ jsx19("span", { "aria-hidden": "true", className: "flex h-5 w-9 items-center rounded-full bg-muted p-0.5 transition-colors group-data-selected:bg-primary group-data-focus-visible:ring-3 group-data-focus-visible:ring-ring/50", children: /* @__PURE__ */ jsx19("span", { className: "size-4 rounded-full bg-background shadow-sm transition-transform group-data-selected:translate-x-4" }) }),
463
+ typeof children === "function" ? children(state) : children
464
+ ] }) });
465
+ }
466
+
467
+ // src/ui/table.tsx
468
+ import { jsx as jsx20 } from "react/jsx-runtime";
469
+ function Table({ className, ...props }) {
470
+ return /* @__PURE__ */ jsx20("div", { "data-slot": "table-container", className: "relative w-full overflow-x-auto", children: /* @__PURE__ */ jsx20("table", { "data-slot": "table", className: cn("w-full caption-bottom text-sm", className), ...props }) });
471
+ }
472
+ function TableHeader({ className, ...props }) {
473
+ return /* @__PURE__ */ jsx20("thead", { "data-slot": "table-header", className: cn("border-b border-border", className), ...props });
474
+ }
475
+ function TableBody({ className, ...props }) {
476
+ return /* @__PURE__ */ jsx20("tbody", { "data-slot": "table-body", className: cn("[&_tr:last-child]:border-0", className), ...props });
477
+ }
478
+ function TableRow({ className, ...props }) {
479
+ return /* @__PURE__ */ jsx20("tr", { "data-slot": "table-row", className: cn("border-b border-border transition-colors hover:bg-muted/50", className), ...props });
480
+ }
481
+ function TableHead({ className, ...props }) {
482
+ return /* @__PURE__ */ jsx20("th", { "data-slot": "table-head", className: cn("h-10 px-3 text-left align-middle text-xs font-medium text-muted-foreground", className), ...props });
483
+ }
484
+ function TableCell({ className, ...props }) {
485
+ return /* @__PURE__ */ jsx20("td", { "data-slot": "table-cell", className: cn("p-3 align-middle", className), ...props });
486
+ }
487
+ function TableCaption({ className, ...props }) {
488
+ return /* @__PURE__ */ jsx20("caption", { "data-slot": "table-caption", className: cn("mt-4 text-sm text-muted-foreground", className), ...props });
489
+ }
490
+
491
+ // src/ui/tabs.tsx
492
+ import {
493
+ Tab as AriaTab,
494
+ TabList as AriaTabList,
495
+ TabPanel as AriaTabPanel,
496
+ TabPanels as AriaTabPanels,
497
+ Tabs as AriaTabs,
498
+ composeRenderProps
499
+ } from "react-aria-components";
500
+ import { jsx as jsx21 } from "react/jsx-runtime";
501
+ function Tabs({ className, ...props }) {
502
+ return /* @__PURE__ */ jsx21(AriaTabs, { "data-slot": "tabs", className: composeRenderProps(className, (value) => cn("flex flex-col gap-2", value)), ...props });
503
+ }
504
+ function TabsList({ className, ...props }) {
505
+ return /* @__PURE__ */ jsx21(AriaTabList, { "data-slot": "tabs-list", className: composeRenderProps(className, (value) => cn("inline-flex w-fit items-center gap-1 rounded-lg bg-muted p-1 text-muted-foreground", value)), ...props });
506
+ }
507
+ function TabsTrigger({ className, ...props }) {
508
+ return /* @__PURE__ */ jsx21(AriaTab, { "data-slot": "tabs-trigger", className: composeRenderProps(className, (value) => cn("inline-flex h-7 items-center justify-center gap-1.5 rounded-md px-2.5 text-sm font-medium outline-none transition-colors data-hovered:text-foreground data-selected:bg-background data-selected:text-foreground data-selected:shadow-sm data-focus-visible:ring-3 data-focus-visible:ring-ring/50 data-disabled:cursor-not-allowed data-disabled:opacity-50", value)), ...props });
509
+ }
510
+ function TabsPanels({ className, ...props }) {
511
+ return /* @__PURE__ */ jsx21(AriaTabPanels, { "data-slot": "tabs-panels", className: cn("min-w-0", className), ...props });
512
+ }
513
+ function TabsContent({ className, ...props }) {
514
+ return /* @__PURE__ */ jsx21(AriaTabPanel, { "data-slot": "tabs-content", className: composeRenderProps(className, (value) => cn("text-sm outline-none data-focus-visible:ring-3 data-focus-visible:ring-ring/50", value)), ...props });
515
+ }
516
+
517
+ // src/ui/textarea.tsx
518
+ import { forwardRef as forwardRef3 } from "react";
519
+ import { TextArea as AriaTextArea } from "react-aria-components";
520
+ import { jsx as jsx22 } from "react/jsx-runtime";
521
+ var TextareaImpl = forwardRef3(function Textarea({ className, ...props }, ref) {
522
+ return /* @__PURE__ */ jsx22(AriaTextArea, { ref, "data-slot": "textarea", className: cn("min-h-20 w-full rounded-lg border border-border bg-background px-2.5 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive", className), ...props });
523
+ });
524
+ var Textarea2 = TextareaImpl;
525
+
526
+ // src/ui/tooltip.tsx
527
+ import {
528
+ Tooltip as AriaTooltip,
529
+ TooltipTrigger as AriaTooltipTrigger
530
+ } from "react-aria-components";
531
+ import { jsx as jsx23 } from "react/jsx-runtime";
532
+ var TooltipTrigger = AriaTooltipTrigger;
533
+ function Tooltip({ className, ...props }) {
534
+ return /* @__PURE__ */ jsx23(AriaTooltip, { "data-slot": "tooltip", offset: 6, className: cn("max-w-xs rounded-md bg-foreground px-2.5 py-1.5 text-xs text-background shadow-md outline-none data-entering:animate-in data-entering:fade-in-0 data-entering:zoom-in-95 data-exiting:animate-out data-exiting:fade-out-0 data-exiting:zoom-out-95", className), ...props });
535
+ }
536
+ var TooltipContent = Tooltip;
537
+ export {
538
+ Badge,
539
+ Button,
540
+ Card,
541
+ CardContent,
542
+ CardDescription,
543
+ CardFooter,
544
+ CardHeader,
545
+ CardTitle,
546
+ Checkbox,
547
+ Combobox,
548
+ ComboboxContent,
549
+ ComboboxInput,
550
+ ComboboxItem,
551
+ ComboboxList,
552
+ ComboBoxValue as ComboboxValue,
553
+ ConfirmDialog,
554
+ Dialog,
555
+ DialogClose,
556
+ DialogContent,
557
+ DialogDescription,
558
+ DialogFooter,
559
+ DialogHeader,
560
+ DialogTitle,
561
+ EmptyState,
562
+ EmptyStateDescription,
563
+ EmptyStateTitle,
564
+ Field,
565
+ FieldDescription,
566
+ FieldError,
567
+ FieldLabel,
568
+ HighlightMatch,
569
+ Input3 as Input,
570
+ Kbd,
571
+ KbdGroup,
572
+ Label,
573
+ Menu,
574
+ MenuContent,
575
+ MenuItem,
576
+ MenuTrigger,
577
+ Popover3 as Popover,
578
+ PopoverContent,
579
+ PopoverTrigger,
580
+ SearchClearButton,
581
+ SearchField,
582
+ SearchInput,
583
+ Select,
584
+ SelectContent,
585
+ SelectItem,
586
+ SelectList,
587
+ SelectTrigger,
588
+ SelectValue,
589
+ Separator,
590
+ Skeleton,
591
+ Switch,
592
+ Table,
593
+ TableBody,
594
+ TableCaption,
595
+ TableCell,
596
+ TableHead,
597
+ TableHeader,
598
+ TableRow,
599
+ Tabs,
600
+ TabsContent,
601
+ TabsList,
602
+ TabsPanels,
603
+ TabsTrigger,
604
+ Textarea2 as Textarea,
605
+ Tooltip,
606
+ TooltipContent,
607
+ TooltipTrigger,
608
+ badgeVariants,
609
+ buttonVariants,
610
+ cn,
611
+ formSnapshot,
612
+ getTextMatchParts,
613
+ useAutosave,
614
+ useDebouncedValue,
615
+ useFormDirty
616
+ };
617
+ //# sourceMappingURL=index.js.map