@ashwa-io/ui 0.0.3 → 0.0.5
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/components/atomic/Button/buttonLook.js +18 -0
- package/dist/components/atomic/Checkbox/Checkbox.d.ts +11 -0
- package/dist/components/atomic/Checkbox/Checkbox.js +32 -0
- package/dist/components/atomic/Checkbox/index.d.ts +2 -0
- package/dist/components/atomic/ColorInput/ColorInput.d.ts +15 -0
- package/dist/components/atomic/ColorInput/ColorInput.js +44 -0
- package/dist/components/atomic/ColorInput/colorHex.js +8 -0
- package/dist/components/atomic/ColorInput/index.d.ts +2 -0
- package/dist/components/atomic/Select/Select.d.ts +18 -0
- package/dist/components/atomic/Select/Select.js +47 -0
- package/dist/components/atomic/Select/index.d.ts +2 -0
- package/dist/components/atomic/Switch/Switch.d.ts +11 -0
- package/dist/components/atomic/Switch/Switch.js +32 -0
- package/dist/components/atomic/Switch/index.d.ts +2 -0
- package/dist/components/atomic/TextArea/TextArea.d.ts +14 -0
- package/dist/components/atomic/TextArea/TextArea.js +35 -0
- package/dist/components/atomic/TextArea/index.d.ts +2 -0
- package/dist/components/atomic/TextInput/TextInput.d.ts +18 -0
- package/dist/components/atomic/TextInput/TextInput.js +42 -0
- package/dist/components/atomic/TextInput/index.d.ts +2 -0
- package/dist/components/atomic/Tooltip/Tooltip.d.ts +14 -0
- package/dist/components/atomic/Tooltip/Tooltip.js +14 -0
- package/dist/components/atomic/Tooltip/index.d.ts +2 -0
- package/dist/components/layout/FormLayout/FormLayout.d.ts +9 -0
- package/dist/components/layout/FormLayout/FormLayout.js +15 -0
- package/dist/components/layout/FormLayout/index.d.ts +2 -0
- package/dist/components/molecule/ConfirmDialog/ConfirmDialog.d.ts +17 -0
- package/dist/components/molecule/ConfirmDialog/ConfirmDialog.js +28 -0
- package/dist/components/molecule/ConfirmDialog/index.d.ts +2 -0
- package/dist/components/molecule/DropdownMenu/DropdownMenu.d.ts +28 -0
- package/dist/components/molecule/DropdownMenu/DropdownMenu.js +53 -0
- package/dist/components/molecule/DropdownMenu/index.d.ts +2 -0
- package/dist/components/molecule/FormField/FormField.d.ts +16 -0
- package/dist/components/molecule/FormField/FormField.js +47 -0
- package/dist/components/molecule/FormField/index.d.ts +2 -0
- package/dist/components/molecule/Modal/Modal.d.ts +22 -0
- package/dist/components/molecule/Modal/Modal.js +48 -0
- package/dist/components/molecule/Modal/index.d.ts +2 -0
- package/dist/components/molecule/Popover/Popover.d.ts +24 -0
- package/dist/components/molecule/Popover/Popover.js +38 -0
- package/dist/components/molecule/Popover/index.d.ts +2 -0
- package/dist/components/molecule/Toaster/Toaster.d.ts +3 -0
- package/dist/components/molecule/Toaster/Toaster.js +19 -0
- package/dist/components/molecule/Toaster/index.d.ts +3 -0
- package/dist/components/molecule/Toaster/toast.d.ts +13 -0
- package/dist/components/molecule/Toaster/toast.js +18 -0
- package/dist/components/ui/alert-dialog.js +61 -0
- package/dist/components/ui/checkbox.js +18 -0
- package/dist/components/ui/dialog.js +78 -0
- package/dist/components/ui/dropdown-menu.js +42 -0
- package/dist/components/ui/field.js +65 -0
- package/dist/components/ui/input.js +14 -0
- package/dist/components/ui/label.js +12 -0
- package/dist/components/ui/popover.js +32 -0
- package/dist/components/ui/select.js +75 -0
- package/dist/components/ui/switch.js +18 -0
- package/dist/components/ui/textarea.js +12 -0
- package/dist/components/ui/tooltip.js +39 -0
- package/dist/index.d.ts +31 -2
- package/dist/index.js +16 -1
- package/dist/lib/types.d.ts +19 -1
- package/dist/theme/brandTheme.d.ts +1 -1
- package/dist/theme/brandTheme.js +10 -8
- package/package.json +2 -1
- package/src/styles/index.css +45 -43
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Field, FieldContent, FieldDescription, FieldError, FieldLabel } from "../../ui/field.js";
|
|
2
|
+
import { cn } from "../../../lib/utils.js";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useId } from "react";
|
|
5
|
+
// src/components/molecule/FormField/FormField.tsx
|
|
6
|
+
const FormField = (props) => {
|
|
7
|
+
const { children, label, hideLabel = false, description, error, required = false, disabled = false, orientation = "vertical", id: idProp, "data-testid": testId } = props;
|
|
8
|
+
const generatedId = useId();
|
|
9
|
+
const id = idProp ?? generatedId;
|
|
10
|
+
const descriptionId = description ? `${id}-description` : void 0;
|
|
11
|
+
const errorId = error ? `${id}-error` : void 0;
|
|
12
|
+
const control = children({
|
|
13
|
+
id,
|
|
14
|
+
"aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || void 0,
|
|
15
|
+
"aria-invalid": error ? true : void 0,
|
|
16
|
+
"aria-required": required ? true : void 0,
|
|
17
|
+
disabled
|
|
18
|
+
});
|
|
19
|
+
const labelNode = /* @__PURE__ */ jsxs(FieldLabel, {
|
|
20
|
+
htmlFor: id,
|
|
21
|
+
className: cn(hideLabel && "sr-only"),
|
|
22
|
+
children: [label, required && /* @__PURE__ */ jsx("span", {
|
|
23
|
+
"aria-hidden": true,
|
|
24
|
+
className: "text-destructive",
|
|
25
|
+
children: "*"
|
|
26
|
+
})]
|
|
27
|
+
});
|
|
28
|
+
const helpNodes = /* @__PURE__ */ jsxs(Fragment, { children: [description && /* @__PURE__ */ jsx(FieldDescription, {
|
|
29
|
+
id: descriptionId,
|
|
30
|
+
children: description
|
|
31
|
+
}), error && /* @__PURE__ */ jsx(FieldError, {
|
|
32
|
+
id: errorId,
|
|
33
|
+
children: error
|
|
34
|
+
})] });
|
|
35
|
+
return /* @__PURE__ */ jsx(Field, {
|
|
36
|
+
orientation,
|
|
37
|
+
"data-invalid": error ? true : void 0,
|
|
38
|
+
"data-disabled": disabled || void 0,
|
|
39
|
+
"data-testid": testId,
|
|
40
|
+
children: orientation === "horizontal" ? /* @__PURE__ */ jsxs(Fragment, { children: [control, /* @__PURE__ */ jsxs(FieldContent, { children: [labelNode, helpNodes] })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
41
|
+
labelNode,
|
|
42
|
+
control,
|
|
43
|
+
helpNodes
|
|
44
|
+
] })
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
export { FormField };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
3
|
+
export interface ModalProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
/** Names the dialog (required). */
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Body. */
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
/** e.g. Cancel + Save buttons, right-aligned. */
|
|
12
|
+
footer?: React.ReactNode;
|
|
13
|
+
size?: ModalSize;
|
|
14
|
+
/** Fixed height (min(40rem, 85dvh)): the body scrolls, header and footer stay put. */
|
|
15
|
+
fixedHeight?: boolean;
|
|
16
|
+
/** Body without padding, for lists and tables that run edge to edge. */
|
|
17
|
+
flush?: boolean;
|
|
18
|
+
/** false: no close button; Escape and outside clicks do nothing (blocking flows). */
|
|
19
|
+
closable?: boolean;
|
|
20
|
+
'data-testid'?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const Modal: React.FC<ModalProps>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../../ui/dialog.js";
|
|
2
|
+
import { cn } from "../../../lib/utils.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useCallback, useState } from "react";
|
|
5
|
+
// src/components/molecule/Modal/Modal.tsx
|
|
6
|
+
const SIZE = {
|
|
7
|
+
sm: "sm:max-w-md",
|
|
8
|
+
md: "sm:max-w-lg",
|
|
9
|
+
lg: "sm:max-w-xl",
|
|
10
|
+
xl: "sm:max-w-2xl",
|
|
11
|
+
"2xl": "sm:max-w-3xl"
|
|
12
|
+
};
|
|
13
|
+
const FOCUSABLE = "a[href],button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex=\"-1\"])";
|
|
14
|
+
const Modal = (props) => {
|
|
15
|
+
const { open, onClose, title, description, children, footer, size = "md", fixedHeight = false, flush = false, closable = true, "data-testid": testId } = props;
|
|
16
|
+
const [needsTabStop, setNeedsTabStop] = useState(false);
|
|
17
|
+
const bodyRef = useCallback((body) => {
|
|
18
|
+
if (!body) return void 0;
|
|
19
|
+
const check = () => setNeedsTabStop(body.scrollHeight > body.clientHeight && !body.querySelector(FOCUSABLE));
|
|
20
|
+
const observer = new ResizeObserver(check);
|
|
21
|
+
observer.observe(body);
|
|
22
|
+
Array.from(body.children).forEach((child) => observer.observe(child));
|
|
23
|
+
return () => observer.disconnect();
|
|
24
|
+
}, []);
|
|
25
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
26
|
+
open,
|
|
27
|
+
onOpenChange: (next) => {
|
|
28
|
+
if (!next && closable) onClose();
|
|
29
|
+
},
|
|
30
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
31
|
+
showCloseButton: closable,
|
|
32
|
+
"data-testid": testId,
|
|
33
|
+
className: cn("flex max-h-[85dvh] flex-col", SIZE[size], fixedHeight && "h-[min(40rem,85dvh)]"),
|
|
34
|
+
children: [
|
|
35
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), description && /* @__PURE__ */ jsx(DialogDescription, { children: description })] }),
|
|
36
|
+
/* @__PURE__ */ jsx("div", {
|
|
37
|
+
ref: bodyRef,
|
|
38
|
+
"data-slot": "modal-body",
|
|
39
|
+
tabIndex: needsTabStop ? 0 : void 0,
|
|
40
|
+
className: cn("min-h-0 flex-1 overflow-y-auto", flush ? "-m-4" : "-m-1 p-1"),
|
|
41
|
+
children
|
|
42
|
+
}),
|
|
43
|
+
footer && /* @__PURE__ */ jsx(DialogFooter, { children: footer })
|
|
44
|
+
]
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
export { Modal };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "../../atomic/Button/index.js";
|
|
2
|
+
import { ButtonVariant } from "../../atomic/Button/buttonVariant.js";
|
|
3
|
+
import { IconComponent, OverlayAlign, OverlaySide, Size } from "../../../lib/types.js";
|
|
4
|
+
import React from "react";
|
|
5
|
+
export type PopoverWidth = 'sm' | 'md' | 'lg';
|
|
6
|
+
export interface PopoverProps {
|
|
7
|
+
/** Trigger text (the trigger's aria-label when iconOnly); also names the popup. */
|
|
8
|
+
label: string;
|
|
9
|
+
icon?: IconComponent;
|
|
10
|
+
iconOnly?: boolean;
|
|
11
|
+
/** Trigger look. */
|
|
12
|
+
variant?: ButtonVariant;
|
|
13
|
+
size?: Size;
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
/** Pass with onOpenChange to control it; otherwise it manages itself. */
|
|
16
|
+
open?: boolean;
|
|
17
|
+
onOpenChange?: (open: boolean) => void;
|
|
18
|
+
side?: OverlaySide;
|
|
19
|
+
align?: OverlayAlign;
|
|
20
|
+
width?: PopoverWidth;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
'data-testid'?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare const Popover: React.FC<PopoverProps>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { buttonLook } from "../../atomic/Button/buttonLook.js";
|
|
2
|
+
import { Button } from "../../ui/button.js";
|
|
3
|
+
import { Popover as Popover$1, PopoverContent, PopoverTrigger } from "../../ui/popover.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
// src/components/molecule/Popover/Popover.tsx
|
|
6
|
+
const WIDTH = {
|
|
7
|
+
sm: "w-56",
|
|
8
|
+
md: "w-72",
|
|
9
|
+
lg: "w-96"
|
|
10
|
+
};
|
|
11
|
+
const Popover = (props) => {
|
|
12
|
+
const { label, icon: Icon, iconOnly = false, variant = "outline", size = "md", children, open, onOpenChange, side = "bottom", align = "start", width = "md", disabled = false, "data-testid": testId } = props;
|
|
13
|
+
const look = buttonLook(variant, size, iconOnly);
|
|
14
|
+
return /* @__PURE__ */ jsxs(Popover$1, {
|
|
15
|
+
open,
|
|
16
|
+
onOpenChange: (next) => onOpenChange?.(next),
|
|
17
|
+
children: [/* @__PURE__ */ jsxs(PopoverTrigger, {
|
|
18
|
+
disabled,
|
|
19
|
+
"aria-label": iconOnly ? label : void 0,
|
|
20
|
+
"data-testid": testId,
|
|
21
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
22
|
+
variant: look.variant,
|
|
23
|
+
size: look.size
|
|
24
|
+
}),
|
|
25
|
+
children: [Icon && /* @__PURE__ */ jsx(Icon, {
|
|
26
|
+
"data-icon": iconOnly ? void 0 : "inline-start",
|
|
27
|
+
"aria-hidden": true
|
|
28
|
+
}), !iconOnly && label]
|
|
29
|
+
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
30
|
+
side,
|
|
31
|
+
align,
|
|
32
|
+
"aria-label": label,
|
|
33
|
+
className: WIDTH[width],
|
|
34
|
+
children
|
|
35
|
+
})]
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
export { Popover };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Toaster } from "sonner";
|
|
3
|
+
// src/components/molecule/Toaster/Toaster.tsx
|
|
4
|
+
const TOKENS = {
|
|
5
|
+
"--normal-bg": "var(--popover)",
|
|
6
|
+
"--normal-text": "var(--popover-foreground)",
|
|
7
|
+
"--normal-border": "var(--border)",
|
|
8
|
+
"--border-radius": "var(--radius)"
|
|
9
|
+
};
|
|
10
|
+
/** Mount once at the app root. */
|
|
11
|
+
const Toaster$1 = () => /* @__PURE__ */ jsx(Toaster, {
|
|
12
|
+
position: "bottom-right",
|
|
13
|
+
style: TOKENS,
|
|
14
|
+
toastOptions: { classNames: {
|
|
15
|
+
toast: "font-sans",
|
|
16
|
+
description: "text-muted-foreground!"
|
|
17
|
+
} }
|
|
18
|
+
});
|
|
19
|
+
export { Toaster$1 as Toaster };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ToastOptions {
|
|
2
|
+
description?: string;
|
|
3
|
+
duration?: number;
|
|
4
|
+
}
|
|
5
|
+
/** Works anywhere, including outside React (axios interceptors); needs one mounted <Toaster />. */
|
|
6
|
+
export declare const toast: {
|
|
7
|
+
message: (message: string, options?: ToastOptions) => string | number;
|
|
8
|
+
success: (message: string, options?: ToastOptions) => string | number;
|
|
9
|
+
error: (message: string, options?: ToastOptions) => string | number;
|
|
10
|
+
info: (message: string, options?: ToastOptions) => string | number;
|
|
11
|
+
warning: (message: string, options?: ToastOptions) => string | number;
|
|
12
|
+
dismiss: (id?: string | number) => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { toast } from "sonner";
|
|
2
|
+
// src/components/molecule/Toaster/toast.ts
|
|
3
|
+
const show = (notify) => (message, options) => notify(message, {
|
|
4
|
+
description: options?.description,
|
|
5
|
+
duration: options?.duration
|
|
6
|
+
});
|
|
7
|
+
/** Works anywhere, including outside React (axios interceptors); needs one mounted <Toaster />. */
|
|
8
|
+
const toast$1 = {
|
|
9
|
+
message: show(toast.message),
|
|
10
|
+
success: show(toast.success),
|
|
11
|
+
error: show(toast.error),
|
|
12
|
+
info: show(toast.info),
|
|
13
|
+
warning: show(toast.warning),
|
|
14
|
+
dismiss: (id) => {
|
|
15
|
+
toast.dismiss(id);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export { toast$1 as toast };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { cn } from "cn";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import "react";
|
|
4
|
+
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
5
|
+
// src/components/ui/alert-dialog.tsx
|
|
6
|
+
const AlertDialog$1 = ({ ...props }) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(AlertDialog.Root, {
|
|
8
|
+
"data-slot": "alert-dialog",
|
|
9
|
+
...props
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
const AlertDialogPortal = ({ ...props }) => {
|
|
13
|
+
return /* @__PURE__ */ jsx(AlertDialog.Portal, {
|
|
14
|
+
"data-slot": "alert-dialog-portal",
|
|
15
|
+
...props
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
const AlertDialogOverlay = ({ className, ...props }) => {
|
|
19
|
+
return /* @__PURE__ */ jsx(AlertDialog.Backdrop, {
|
|
20
|
+
"data-slot": "alert-dialog-overlay",
|
|
21
|
+
className: cn("data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs", className),
|
|
22
|
+
...props
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const AlertDialogContent = ({ className, size = "default", ...props }) => {
|
|
26
|
+
return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [/* @__PURE__ */ jsx(AlertDialogOverlay, {}), /* @__PURE__ */ jsx(AlertDialog.Popup, {
|
|
27
|
+
"data-slot": "alert-dialog-content",
|
|
28
|
+
"data-size": size,
|
|
29
|
+
className: cn("group/alert-dialog-content bg-popover text-popover-foreground ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl p-4 ring-1 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm", className),
|
|
30
|
+
...props
|
|
31
|
+
})] });
|
|
32
|
+
};
|
|
33
|
+
const AlertDialogHeader = ({ className, ...props }) => {
|
|
34
|
+
return /* @__PURE__ */ jsx("div", {
|
|
35
|
+
"data-slot": "alert-dialog-header",
|
|
36
|
+
className: cn("grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className),
|
|
37
|
+
...props
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const AlertDialogFooter = ({ className, ...props }) => {
|
|
41
|
+
return /* @__PURE__ */ jsx("div", {
|
|
42
|
+
"data-slot": "alert-dialog-footer",
|
|
43
|
+
className: cn("bg-muted/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end", className),
|
|
44
|
+
...props
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const AlertDialogTitle = ({ className, ...props }) => {
|
|
48
|
+
return /* @__PURE__ */ jsx(AlertDialog.Title, {
|
|
49
|
+
"data-slot": "alert-dialog-title",
|
|
50
|
+
className: cn("font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className),
|
|
51
|
+
...props
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
const AlertDialogDescription = ({ className, ...props }) => {
|
|
55
|
+
return /* @__PURE__ */ jsx(AlertDialog.Description, {
|
|
56
|
+
"data-slot": "alert-dialog-description",
|
|
57
|
+
className: cn("text-muted-foreground *:[a]:hover:text-foreground text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3", className),
|
|
58
|
+
...props
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
export { AlertDialog$1 as AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cn } from "cn";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { CheckIcon } from "lucide-react";
|
|
4
|
+
import { Checkbox } from "@base-ui/react/checkbox";
|
|
5
|
+
// src/components/ui/checkbox.tsx
|
|
6
|
+
const Checkbox$1 = ({ className, ...props }) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(Checkbox.Root, {
|
|
8
|
+
"data-slot": "checkbox",
|
|
9
|
+
className: cn("peer border-input group-has-[:focus-visible]/field-label:not-data-checked:border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border transition-colors outline-none group-has-disabled/field:opacity-50 group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3", className),
|
|
10
|
+
...props,
|
|
11
|
+
children: /* @__PURE__ */ jsx(Checkbox.Indicator, {
|
|
12
|
+
"data-slot": "checkbox-indicator",
|
|
13
|
+
className: "grid place-content-center text-current transition-none [&>svg]:size-3.5",
|
|
14
|
+
children: /* @__PURE__ */ jsx(CheckIcon, {})
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
export { Checkbox$1 as Checkbox };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Button } from "./button.js";
|
|
2
|
+
import { cn } from "cn";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { XIcon } from "lucide-react";
|
|
5
|
+
import "react";
|
|
6
|
+
import { Dialog } from "@base-ui/react/dialog";
|
|
7
|
+
// src/components/ui/dialog.tsx
|
|
8
|
+
const Dialog$1 = ({ ...props }) => {
|
|
9
|
+
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
10
|
+
"data-slot": "dialog",
|
|
11
|
+
...props
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
const DialogPortal = ({ ...props }) => {
|
|
15
|
+
return /* @__PURE__ */ jsx(Dialog.Portal, {
|
|
16
|
+
"data-slot": "dialog-portal",
|
|
17
|
+
...props
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
const DialogOverlay = ({ className, ...props }) => {
|
|
21
|
+
return /* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
22
|
+
"data-slot": "dialog-overlay",
|
|
23
|
+
className: cn("data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs", className),
|
|
24
|
+
...props
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const DialogContent = ({ className, children, showCloseButton = true, ...props }) => {
|
|
28
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(Dialog.Popup, {
|
|
29
|
+
"data-slot": "dialog-content",
|
|
30
|
+
className: cn("bg-popover text-popover-foreground ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl p-4 text-sm ring-1 duration-100 outline-none sm:max-w-sm", className),
|
|
31
|
+
...props,
|
|
32
|
+
children: [children, showCloseButton && /* @__PURE__ */ jsxs(Dialog.Close, {
|
|
33
|
+
"data-slot": "dialog-close",
|
|
34
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
35
|
+
variant: "ghost",
|
|
36
|
+
className: "absolute top-2 right-2",
|
|
37
|
+
size: "icon-sm"
|
|
38
|
+
}),
|
|
39
|
+
children: [/* @__PURE__ */ jsx(XIcon, {}), /* @__PURE__ */ jsx("span", {
|
|
40
|
+
className: "sr-only",
|
|
41
|
+
children: "Close"
|
|
42
|
+
})]
|
|
43
|
+
})]
|
|
44
|
+
})] });
|
|
45
|
+
};
|
|
46
|
+
const DialogHeader = ({ className, ...props }) => {
|
|
47
|
+
return /* @__PURE__ */ jsx("div", {
|
|
48
|
+
"data-slot": "dialog-header",
|
|
49
|
+
className: cn("flex flex-col gap-2", className),
|
|
50
|
+
...props
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const DialogFooter = ({ className, showCloseButton = false, children, ...props }) => {
|
|
54
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
55
|
+
"data-slot": "dialog-footer",
|
|
56
|
+
className: cn("bg-muted/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t p-4 sm:flex-row sm:justify-end", className),
|
|
57
|
+
...props,
|
|
58
|
+
children: [children, showCloseButton && /* @__PURE__ */ jsx(Dialog.Close, {
|
|
59
|
+
render: /* @__PURE__ */ jsx(Button, { variant: "outline" }),
|
|
60
|
+
children: "Close"
|
|
61
|
+
})]
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
const DialogTitle = ({ className, ...props }) => {
|
|
65
|
+
return /* @__PURE__ */ jsx(Dialog.Title, {
|
|
66
|
+
"data-slot": "dialog-title",
|
|
67
|
+
className: cn("font-heading text-base leading-none font-medium", className),
|
|
68
|
+
...props
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
const DialogDescription = ({ className, ...props }) => {
|
|
72
|
+
return /* @__PURE__ */ jsx(Dialog.Description, {
|
|
73
|
+
"data-slot": "dialog-description",
|
|
74
|
+
className: cn("text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3", className),
|
|
75
|
+
...props
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
export { Dialog$1 as Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { cn } from "cn";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import "lucide-react";
|
|
4
|
+
import "react";
|
|
5
|
+
import { Menu } from "@base-ui/react/menu";
|
|
6
|
+
// src/components/ui/dropdown-menu.tsx
|
|
7
|
+
const DropdownMenu = ({ ...props }) => {
|
|
8
|
+
return /* @__PURE__ */ jsx(Menu.Root, {
|
|
9
|
+
"data-slot": "dropdown-menu",
|
|
10
|
+
...props
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
const DropdownMenuTrigger = ({ ...props }) => {
|
|
14
|
+
return /* @__PURE__ */ jsx(Menu.Trigger, {
|
|
15
|
+
"data-slot": "dropdown-menu-trigger",
|
|
16
|
+
...props
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const DropdownMenuContent = ({ align = "start", alignOffset = 0, side = "bottom", sideOffset = 4, className, ...props }) => {
|
|
20
|
+
return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
|
|
21
|
+
className: "isolate z-50 outline-none",
|
|
22
|
+
align,
|
|
23
|
+
alignOffset,
|
|
24
|
+
side,
|
|
25
|
+
sideOffset,
|
|
26
|
+
children: /* @__PURE__ */ jsx(Menu.Popup, {
|
|
27
|
+
"data-slot": "dropdown-menu-content",
|
|
28
|
+
className: cn("bg-popover text-popover-foreground ring-foreground/10 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg p-1 shadow-md ring-1 duration-100 outline-none data-closed:overflow-hidden", className),
|
|
29
|
+
...props
|
|
30
|
+
})
|
|
31
|
+
}) });
|
|
32
|
+
};
|
|
33
|
+
const DropdownMenuItem = ({ className, inset, variant = "default", ...props }) => {
|
|
34
|
+
return /* @__PURE__ */ jsx(Menu.Item, {
|
|
35
|
+
"data-slot": "dropdown-menu-item",
|
|
36
|
+
"data-inset": inset,
|
|
37
|
+
"data-variant": variant,
|
|
38
|
+
className: cn("group/dropdown-menu-item focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:*:[svg]:text-destructive relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
|
|
39
|
+
...props
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
export { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Label } from "./label.js";
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { cn } from "cn";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { useMemo } from "react";
|
|
6
|
+
// src/components/ui/field.tsx
|
|
7
|
+
const fieldVariants = cva("group/field flex w-full gap-2 data-[invalid=true]:text-destructive", {
|
|
8
|
+
variants: { orientation: {
|
|
9
|
+
vertical: "flex-col *:w-full [&>.sr-only]:w-auto",
|
|
10
|
+
horizontal: "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
|
|
11
|
+
responsive: "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
|
|
12
|
+
} },
|
|
13
|
+
defaultVariants: { orientation: "vertical" }
|
|
14
|
+
});
|
|
15
|
+
const Field = ({ className, orientation = "vertical", ...props }) => {
|
|
16
|
+
return /* @__PURE__ */ jsx("div", {
|
|
17
|
+
role: "group",
|
|
18
|
+
"data-slot": "field",
|
|
19
|
+
"data-orientation": orientation,
|
|
20
|
+
className: cn(fieldVariants({ orientation }), className),
|
|
21
|
+
...props
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const FieldContent = ({ className, ...props }) => {
|
|
25
|
+
return /* @__PURE__ */ jsx("div", {
|
|
26
|
+
"data-slot": "field-content",
|
|
27
|
+
className: cn("group/field-content flex flex-1 flex-col gap-0.5 leading-snug", className),
|
|
28
|
+
...props
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const FieldLabel = ({ className, ...props }) => {
|
|
32
|
+
return /* @__PURE__ */ jsx(Label, {
|
|
33
|
+
"data-slot": "field-label",
|
|
34
|
+
className: cn("group/field-label peer/field-label has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:not-has-[:disabled,[data-disabled]]:hover:bg-muted/50 has-[>[data-slot=field]]:has-[:focus-visible]:border-ring has-[>[data-slot=field]]:has-[:focus-visible]:ring-ring/50 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10 flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border has-[>[data-slot=field]]:has-[:focus-visible]:ring-3 *:data-[slot=field]:p-2.5", "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col", className),
|
|
35
|
+
...props
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
const FieldDescription = ({ className, ...props }) => {
|
|
39
|
+
return /* @__PURE__ */ jsx("p", {
|
|
40
|
+
"data-slot": "field-description",
|
|
41
|
+
className: cn("text-muted-foreground text-left text-sm leading-normal font-normal group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5", "last:mt-0 nth-last-2:-mt-1", "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4", className),
|
|
42
|
+
...props
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const FieldError = ({ className, children, errors, ...props }) => {
|
|
46
|
+
const content = useMemo(() => {
|
|
47
|
+
if (children) return children;
|
|
48
|
+
if (!errors?.length) return null;
|
|
49
|
+
const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()];
|
|
50
|
+
if (uniqueErrors?.length == 1) return uniqueErrors[0]?.message;
|
|
51
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
52
|
+
className: "ml-4 flex list-disc flex-col gap-1",
|
|
53
|
+
children: uniqueErrors.map((error, index) => error?.message && /* @__PURE__ */ jsx("li", { children: error.message }, index))
|
|
54
|
+
});
|
|
55
|
+
}, [children, errors]);
|
|
56
|
+
if (!content) return null;
|
|
57
|
+
return /* @__PURE__ */ jsx("div", {
|
|
58
|
+
role: "alert",
|
|
59
|
+
"data-slot": "field-error",
|
|
60
|
+
className: cn("text-destructive text-sm font-normal", className),
|
|
61
|
+
...props,
|
|
62
|
+
children: content
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
export { Field, FieldContent, FieldDescription, FieldError, FieldLabel };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { cn } from "cn";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import "react";
|
|
4
|
+
import { Input } from "@base-ui/react/input";
|
|
5
|
+
// src/components/ui/input.tsx
|
|
6
|
+
const Input$1 = ({ className, type, ...props }) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(Input, {
|
|
8
|
+
type,
|
|
9
|
+
"data-slot": "input",
|
|
10
|
+
className: cn("border-input file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 disabled:bg-input/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm", className),
|
|
11
|
+
...props
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
export { Input$1 as Input };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { cn } from "cn";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import "react";
|
|
4
|
+
// src/components/ui/label.tsx
|
|
5
|
+
const Label = ({ className, ...props }) => {
|
|
6
|
+
return /* @__PURE__ */ jsx("label", {
|
|
7
|
+
"data-slot": "label",
|
|
8
|
+
className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className),
|
|
9
|
+
...props
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
export { Label };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { cn } from "cn";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import "react";
|
|
4
|
+
import { Popover } from "@base-ui/react/popover";
|
|
5
|
+
// src/components/ui/popover.tsx
|
|
6
|
+
const Popover$1 = ({ ...props }) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(Popover.Root, {
|
|
8
|
+
"data-slot": "popover",
|
|
9
|
+
...props
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
const PopoverTrigger = ({ ...props }) => {
|
|
13
|
+
return /* @__PURE__ */ jsx(Popover.Trigger, {
|
|
14
|
+
"data-slot": "popover-trigger",
|
|
15
|
+
...props
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
const PopoverContent = ({ className, align = "center", alignOffset = 0, side = "bottom", sideOffset = 4, ...props }) => {
|
|
19
|
+
return /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
|
|
20
|
+
align,
|
|
21
|
+
alignOffset,
|
|
22
|
+
side,
|
|
23
|
+
sideOffset,
|
|
24
|
+
className: "isolate z-50",
|
|
25
|
+
children: /* @__PURE__ */ jsx(Popover.Popup, {
|
|
26
|
+
"data-slot": "popover-content",
|
|
27
|
+
className: cn("bg-popover text-popover-foreground ring-foreground/10 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg p-2.5 text-sm shadow-md ring-1 outline-hidden duration-100", className),
|
|
28
|
+
...props
|
|
29
|
+
})
|
|
30
|
+
}) });
|
|
31
|
+
};
|
|
32
|
+
export { Popover$1 as Popover, PopoverContent, PopoverTrigger };
|