@ashwa-io/ui 0.0.4 → 0.0.6
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/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/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/FacetFilter/FacetFilter.d.ts +14 -0
- package/dist/components/molecule/FacetFilter/FacetFilter.js +30 -0
- package/dist/components/molecule/FacetFilter/FacetList.d.ts +10 -0
- package/dist/components/molecule/FacetFilter/FacetList.js +103 -0
- package/dist/components/molecule/FacetFilter/FacetTrigger.d.ts +2 -0
- package/dist/components/molecule/FacetFilter/FacetTrigger.js +35 -0
- package/dist/components/molecule/FacetFilter/index.d.ts +3 -0
- package/dist/components/molecule/FacetFilterNumber/FacetFilterNumber.d.ts +29 -0
- package/dist/components/molecule/FacetFilterNumber/FacetFilterNumber.js +93 -0
- package/dist/components/molecule/FacetFilterNumber/index.d.ts +2 -0
- package/dist/components/molecule/FacetFilterSelect/FacetFilterSelect.d.ts +15 -0
- package/dist/components/molecule/FacetFilterSelect/FacetFilterSelect.js +41 -0
- package/dist/components/molecule/FacetFilterSelect/index.d.ts +2 -0
- package/dist/components/molecule/FilterMenu/FilterMenu.d.ts +23 -0
- package/dist/components/molecule/FilterMenu/FilterMenu.js +131 -0
- package/dist/components/molecule/FilterMenu/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/combobox.js +78 -0
- package/dist/components/ui/dialog.js +78 -0
- package/dist/components/ui/dropdown-menu.js +42 -0
- package/dist/components/ui/input-group.js +63 -0
- package/dist/components/ui/popover.js +32 -0
- package/dist/components/ui/tooltip.js +39 -0
- package/dist/index.d.ts +24 -2
- package/dist/index.js +12 -1
- package/dist/lib/types.d.ts +4 -0
- 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,131 @@
|
|
|
1
|
+
import { Badge } from "../../atomic/Badge/Badge.js";
|
|
2
|
+
import { Button } from "../../atomic/Button/Button.js";
|
|
3
|
+
import { buttonLook } from "../../atomic/Button/buttonLook.js";
|
|
4
|
+
import { FacetList } from "../FacetFilter/FacetList.js";
|
|
5
|
+
import { Button as Button$1 } from "../../ui/button.js";
|
|
6
|
+
import { Input } from "../../ui/input.js";
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover.js";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { ChevronRightIcon, FilterIcon } from "lucide-react";
|
|
10
|
+
import { useState } from "react";
|
|
11
|
+
// src/components/molecule/FilterMenu/FilterMenu.tsx
|
|
12
|
+
const FilterMenu = (props) => {
|
|
13
|
+
const { categories, value, onChange, label = "Filter", size = "sm", disabled = false, "data-testid": testId } = props;
|
|
14
|
+
const [query, setQuery] = useState("");
|
|
15
|
+
const [openId, setOpenId] = useState(null);
|
|
16
|
+
const selectedCount = (category) => category.options.filter((option) => value[category.id]?.includes(option.value)).length;
|
|
17
|
+
const activeCount = categories.filter((category) => selectedCount(category) > 0).length;
|
|
18
|
+
const look = buttonLook("outline", size, false);
|
|
19
|
+
const needle = query.trim().toLowerCase();
|
|
20
|
+
const visible = categories.filter((category) => category.label.toLowerCase().includes(needle));
|
|
21
|
+
const clearAll = () => onChange({
|
|
22
|
+
...value,
|
|
23
|
+
...Object.fromEntries(categories.map(({ id }) => [id, []]))
|
|
24
|
+
});
|
|
25
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
26
|
+
onOpenChange: (open) => {
|
|
27
|
+
if (open) return;
|
|
28
|
+
setQuery("");
|
|
29
|
+
setOpenId(null);
|
|
30
|
+
},
|
|
31
|
+
children: [/* @__PURE__ */ jsxs(PopoverTrigger, {
|
|
32
|
+
disabled,
|
|
33
|
+
"data-testid": testId,
|
|
34
|
+
render: /* @__PURE__ */ jsx(Button$1, {
|
|
35
|
+
variant: look.variant,
|
|
36
|
+
size: look.size
|
|
37
|
+
}),
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsx(FilterIcon, {
|
|
40
|
+
"data-icon": "inline-start",
|
|
41
|
+
"aria-hidden": true
|
|
42
|
+
}),
|
|
43
|
+
label,
|
|
44
|
+
" ",
|
|
45
|
+
activeCount > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Badge, {
|
|
46
|
+
tone: "brand",
|
|
47
|
+
children: activeCount
|
|
48
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
49
|
+
className: "sr-only",
|
|
50
|
+
children: " active"
|
|
51
|
+
})] })
|
|
52
|
+
]
|
|
53
|
+
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
54
|
+
align: "start",
|
|
55
|
+
"aria-label": label,
|
|
56
|
+
className: "w-60 gap-0 p-0",
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsx("div", {
|
|
59
|
+
className: "border-b p-1",
|
|
60
|
+
children: /* @__PURE__ */ jsx(Input, {
|
|
61
|
+
"aria-label": "Search filters",
|
|
62
|
+
placeholder: "Search",
|
|
63
|
+
value: query,
|
|
64
|
+
onChange: (event) => setQuery(event.target.value)
|
|
65
|
+
})
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ jsxs("div", {
|
|
68
|
+
className: "max-h-60 overflow-y-auto p-1",
|
|
69
|
+
children: [visible.length === 0 && /* @__PURE__ */ jsx("p", {
|
|
70
|
+
className: "text-muted-foreground py-2 text-center text-sm",
|
|
71
|
+
children: "No results"
|
|
72
|
+
}), visible.map((category) => {
|
|
73
|
+
const count = selectedCount(category);
|
|
74
|
+
const multiple = category.multiple !== false;
|
|
75
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
76
|
+
open: openId === category.id,
|
|
77
|
+
onOpenChange: (open) => setOpenId(open ? category.id : null),
|
|
78
|
+
children: [/* @__PURE__ */ jsxs(PopoverTrigger, {
|
|
79
|
+
render: /* @__PURE__ */ jsx("button", {
|
|
80
|
+
type: "button",
|
|
81
|
+
className: "hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent data-popup-open:bg-accent data-popup-open:text-accent-foreground flex w-full cursor-default items-center gap-2 rounded-md px-1.5 py-1 text-sm outline-none"
|
|
82
|
+
}),
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ jsx("span", {
|
|
85
|
+
className: "min-w-0 flex-1 truncate text-left",
|
|
86
|
+
children: category.label
|
|
87
|
+
}),
|
|
88
|
+
count > 0 && /* @__PURE__ */ jsx("span", {
|
|
89
|
+
className: "text-xs tabular-nums",
|
|
90
|
+
children: count
|
|
91
|
+
}),
|
|
92
|
+
/* @__PURE__ */ jsx(ChevronRightIcon, {
|
|
93
|
+
"aria-hidden": true,
|
|
94
|
+
className: "size-4 shrink-0"
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
98
|
+
side: "right",
|
|
99
|
+
align: "start",
|
|
100
|
+
"aria-label": category.label,
|
|
101
|
+
className: "w-60 gap-0 p-0",
|
|
102
|
+
children: /* @__PURE__ */ jsx(FacetList, {
|
|
103
|
+
label: category.label,
|
|
104
|
+
options: category.options,
|
|
105
|
+
value: value[category.id] ?? [],
|
|
106
|
+
onChange: (next) => onChange({
|
|
107
|
+
...value,
|
|
108
|
+
[category.id]: next
|
|
109
|
+
}),
|
|
110
|
+
multiple,
|
|
111
|
+
showSelectAll: multiple
|
|
112
|
+
})
|
|
113
|
+
})]
|
|
114
|
+
}, category.id);
|
|
115
|
+
})]
|
|
116
|
+
}),
|
|
117
|
+
activeCount > 0 && /* @__PURE__ */ jsx("div", {
|
|
118
|
+
className: "border-t p-1",
|
|
119
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
120
|
+
variant: "ghost",
|
|
121
|
+
size: "sm",
|
|
122
|
+
fullWidth: true,
|
|
123
|
+
onClick: clearAll,
|
|
124
|
+
children: "Clear all"
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
]
|
|
128
|
+
})]
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
export { FilterMenu };
|
|
@@ -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,78 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "./input-group.js";
|
|
3
|
+
import { cn } from "cn";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
|
|
6
|
+
import "react";
|
|
7
|
+
import { Combobox } from "@base-ui/react";
|
|
8
|
+
// src/components/ui/combobox.tsx
|
|
9
|
+
const Combobox$1 = Combobox.Root;
|
|
10
|
+
const ComboboxTrigger = ({ className, children, ...props }) => {
|
|
11
|
+
return /* @__PURE__ */ jsxs(Combobox.Trigger, {
|
|
12
|
+
"data-slot": "combobox-trigger",
|
|
13
|
+
className: cn("[&_svg:not([class*='size-'])]:size-4", className),
|
|
14
|
+
...props,
|
|
15
|
+
children: [children, /* @__PURE__ */ jsx(ChevronDownIcon, { className: "text-muted-foreground pointer-events-none size-4" })]
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
const ComboboxClear = ({ className, ...props }) => {
|
|
19
|
+
return /* @__PURE__ */ jsx(Combobox.Clear, {
|
|
20
|
+
"data-slot": "combobox-clear",
|
|
21
|
+
render: /* @__PURE__ */ jsx(InputGroupButton, {
|
|
22
|
+
variant: "ghost",
|
|
23
|
+
size: "icon-xs"
|
|
24
|
+
}),
|
|
25
|
+
className: cn(className),
|
|
26
|
+
...props,
|
|
27
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "pointer-events-none" })
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
const ComboboxInput = ({ className, children, disabled = false, showTrigger = true, showClear = false, ...props }) => {
|
|
31
|
+
return /* @__PURE__ */ jsxs(InputGroup, {
|
|
32
|
+
className: cn("w-auto", className),
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ jsx(Combobox.Input, {
|
|
35
|
+
render: /* @__PURE__ */ jsx(InputGroupInput, { disabled }),
|
|
36
|
+
...props
|
|
37
|
+
}),
|
|
38
|
+
/* @__PURE__ */ jsxs(InputGroupAddon, {
|
|
39
|
+
align: "inline-end",
|
|
40
|
+
children: [showTrigger && /* @__PURE__ */ jsx(InputGroupButton, {
|
|
41
|
+
size: "icon-xs",
|
|
42
|
+
variant: "ghost",
|
|
43
|
+
render: /* @__PURE__ */ jsx(ComboboxTrigger, {}),
|
|
44
|
+
"data-slot": "input-group-button",
|
|
45
|
+
className: "group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent",
|
|
46
|
+
disabled
|
|
47
|
+
}), showClear && /* @__PURE__ */ jsx(ComboboxClear, { disabled })]
|
|
48
|
+
}),
|
|
49
|
+
children
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const ComboboxList = ({ className, ...props }) => {
|
|
54
|
+
return /* @__PURE__ */ jsx(Combobox.List, {
|
|
55
|
+
"data-slot": "combobox-list",
|
|
56
|
+
className: cn("no-scrollbar max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0", className),
|
|
57
|
+
...props
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const ComboboxItem = ({ className, children, ...props }) => {
|
|
61
|
+
return /* @__PURE__ */ jsxs(Combobox.Item, {
|
|
62
|
+
"data-slot": "combobox-item",
|
|
63
|
+
className: cn("data-highlighted:bg-accent data-highlighted:text-accent-foreground not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground relative flex w-full cursor-default items-center gap-2 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
|
|
64
|
+
...props,
|
|
65
|
+
children: [children, /* @__PURE__ */ jsx(Combobox.ItemIndicator, {
|
|
66
|
+
render: /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center" }),
|
|
67
|
+
children: /* @__PURE__ */ jsx(CheckIcon, { className: "pointer-events-none" })
|
|
68
|
+
})]
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
const ComboboxEmpty = ({ className, ...props }) => {
|
|
72
|
+
return /* @__PURE__ */ jsx(Combobox.Empty, {
|
|
73
|
+
"data-slot": "combobox-empty",
|
|
74
|
+
className: cn("text-muted-foreground hidden w-full justify-center py-2 text-center text-sm group-data-empty/combobox-content:flex", className),
|
|
75
|
+
...props
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
export { Combobox$1 as Combobox, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, ComboboxTrigger };
|
|
@@ -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 };
|