@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.
Files changed (65) hide show
  1. package/dist/components/atomic/Button/buttonLook.js +18 -0
  2. package/dist/components/atomic/Checkbox/Checkbox.d.ts +11 -0
  3. package/dist/components/atomic/Checkbox/Checkbox.js +32 -0
  4. package/dist/components/atomic/Checkbox/index.d.ts +2 -0
  5. package/dist/components/atomic/ColorInput/ColorInput.d.ts +15 -0
  6. package/dist/components/atomic/ColorInput/ColorInput.js +44 -0
  7. package/dist/components/atomic/ColorInput/colorHex.js +8 -0
  8. package/dist/components/atomic/ColorInput/index.d.ts +2 -0
  9. package/dist/components/atomic/Select/Select.d.ts +18 -0
  10. package/dist/components/atomic/Select/Select.js +47 -0
  11. package/dist/components/atomic/Select/index.d.ts +2 -0
  12. package/dist/components/atomic/Switch/Switch.d.ts +11 -0
  13. package/dist/components/atomic/Switch/Switch.js +32 -0
  14. package/dist/components/atomic/Switch/index.d.ts +2 -0
  15. package/dist/components/atomic/TextArea/TextArea.d.ts +14 -0
  16. package/dist/components/atomic/TextArea/TextArea.js +35 -0
  17. package/dist/components/atomic/TextArea/index.d.ts +2 -0
  18. package/dist/components/atomic/TextInput/TextInput.d.ts +18 -0
  19. package/dist/components/atomic/TextInput/TextInput.js +42 -0
  20. package/dist/components/atomic/TextInput/index.d.ts +2 -0
  21. package/dist/components/atomic/Tooltip/Tooltip.d.ts +14 -0
  22. package/dist/components/atomic/Tooltip/Tooltip.js +14 -0
  23. package/dist/components/atomic/Tooltip/index.d.ts +2 -0
  24. package/dist/components/layout/FormLayout/FormLayout.d.ts +9 -0
  25. package/dist/components/layout/FormLayout/FormLayout.js +15 -0
  26. package/dist/components/layout/FormLayout/index.d.ts +2 -0
  27. package/dist/components/molecule/ConfirmDialog/ConfirmDialog.d.ts +17 -0
  28. package/dist/components/molecule/ConfirmDialog/ConfirmDialog.js +28 -0
  29. package/dist/components/molecule/ConfirmDialog/index.d.ts +2 -0
  30. package/dist/components/molecule/DropdownMenu/DropdownMenu.d.ts +28 -0
  31. package/dist/components/molecule/DropdownMenu/DropdownMenu.js +53 -0
  32. package/dist/components/molecule/DropdownMenu/index.d.ts +2 -0
  33. package/dist/components/molecule/FormField/FormField.d.ts +16 -0
  34. package/dist/components/molecule/FormField/FormField.js +47 -0
  35. package/dist/components/molecule/FormField/index.d.ts +2 -0
  36. package/dist/components/molecule/Modal/Modal.d.ts +22 -0
  37. package/dist/components/molecule/Modal/Modal.js +48 -0
  38. package/dist/components/molecule/Modal/index.d.ts +2 -0
  39. package/dist/components/molecule/Popover/Popover.d.ts +24 -0
  40. package/dist/components/molecule/Popover/Popover.js +38 -0
  41. package/dist/components/molecule/Popover/index.d.ts +2 -0
  42. package/dist/components/molecule/Toaster/Toaster.d.ts +3 -0
  43. package/dist/components/molecule/Toaster/Toaster.js +19 -0
  44. package/dist/components/molecule/Toaster/index.d.ts +3 -0
  45. package/dist/components/molecule/Toaster/toast.d.ts +13 -0
  46. package/dist/components/molecule/Toaster/toast.js +18 -0
  47. package/dist/components/ui/alert-dialog.js +61 -0
  48. package/dist/components/ui/checkbox.js +18 -0
  49. package/dist/components/ui/dialog.js +78 -0
  50. package/dist/components/ui/dropdown-menu.js +42 -0
  51. package/dist/components/ui/field.js +65 -0
  52. package/dist/components/ui/input.js +14 -0
  53. package/dist/components/ui/label.js +12 -0
  54. package/dist/components/ui/popover.js +32 -0
  55. package/dist/components/ui/select.js +75 -0
  56. package/dist/components/ui/switch.js +18 -0
  57. package/dist/components/ui/textarea.js +12 -0
  58. package/dist/components/ui/tooltip.js +39 -0
  59. package/dist/index.d.ts +31 -2
  60. package/dist/index.js +16 -1
  61. package/dist/lib/types.d.ts +19 -1
  62. package/dist/theme/brandTheme.d.ts +1 -1
  63. package/dist/theme/brandTheme.js +10 -8
  64. package/package.json +2 -1
  65. 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,2 @@
1
+ import { FormField, FormFieldControlProps, FormFieldProps } from "./FormField.js";
2
+ export { FormField, type FormFieldControlProps, type FormFieldProps };
@@ -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,2 @@
1
+ import { Modal, ModalProps, ModalSize } from "./Modal.js";
2
+ export { Modal, type ModalProps, type ModalSize };
@@ -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,2 @@
1
+ import { Popover, PopoverProps, PopoverWidth } from "./Popover.js";
2
+ export { Popover, type PopoverProps, type PopoverWidth };
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ /** Mount once at the app root. */
3
+ export declare const Toaster: React.FC;
@@ -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,3 @@
1
+ import { ToastOptions, toast } from "./toast.js";
2
+ import { Toaster } from "./Toaster.js";
3
+ export { type ToastOptions, Toaster, toast };
@@ -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 };