@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/README.md +83 -0
- package/dist/index.cjs +674 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +222 -0
- package/dist/index.d.ts +222 -0
- package/dist/index.js +617 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +2 -0
- package/package.json +69 -0
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
|