@revealui/presentation 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +65 -0
- package/dist/Box-DDhRNK02.js +45 -0
- package/dist/Box-DDhRNK02.js.map +1 -0
- package/dist/Text-BIym7IhD.js +425 -0
- package/dist/Text-BIym7IhD.js.map +1 -0
- package/dist/client.d.ts +51 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +2951 -0
- package/dist/client.js.map +1 -0
- package/dist/components/Button.d.ts +12 -0
- package/dist/components/Button.d.ts.map +1 -0
- package/dist/components/Card.d.ts +9 -0
- package/dist/components/Card.d.ts.map +1 -0
- package/dist/components/Checkbox.d.ts +11 -0
- package/dist/components/Checkbox.d.ts.map +1 -0
- package/dist/components/FormLabel.d.ts +8 -0
- package/dist/components/FormLabel.d.ts.map +1 -0
- package/dist/components/Input.d.ts +5 -0
- package/dist/components/Input.d.ts.map +1 -0
- package/dist/components/Label.d.ts +5 -0
- package/dist/components/Label.d.ts.map +1 -0
- package/dist/components/Pagination.d.ts +33 -0
- package/dist/components/Pagination.d.ts.map +1 -0
- package/dist/components/Select.d.ts +31 -0
- package/dist/components/Select.d.ts.map +1 -0
- package/dist/components/Textarea.d.ts +5 -0
- package/dist/components/Textarea.d.ts.map +1 -0
- package/dist/components/accordion.d.ts +12 -0
- package/dist/components/accordion.d.ts.map +1 -0
- package/dist/components/alert.d.ts +30 -0
- package/dist/components/alert.d.ts.map +1 -0
- package/dist/components/auth-layout.d.ts +5 -0
- package/dist/components/auth-layout.d.ts.map +1 -0
- package/dist/components/avatar-group.d.ts +13 -0
- package/dist/components/avatar-group.d.ts.map +1 -0
- package/dist/components/avatar.d.ts +19 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/badge.d.ts +38 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/breadcrumb.d.ts +11 -0
- package/dist/components/breadcrumb.d.ts.map +1 -0
- package/dist/components/button-headless.d.ts +64 -0
- package/dist/components/button-headless.d.ts.map +1 -0
- package/dist/components/callout.d.ts +11 -0
- package/dist/components/callout.d.ts.map +1 -0
- package/dist/components/checkbox-headless.d.ts +44 -0
- package/dist/components/checkbox-headless.d.ts.map +1 -0
- package/dist/components/code-block.d.ts +8 -0
- package/dist/components/code-block.d.ts.map +1 -0
- package/dist/components/combobox.d.ts +26 -0
- package/dist/components/combobox.d.ts.map +1 -0
- package/dist/components/description-list.d.ts +4 -0
- package/dist/components/description-list.d.ts.map +1 -0
- package/dist/components/dialog.d.ts +30 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/divider.d.ts +4 -0
- package/dist/components/divider.d.ts.map +1 -0
- package/dist/components/drawer.d.ts +18 -0
- package/dist/components/drawer.d.ts.map +1 -0
- package/dist/components/dropdown.d.ts +45 -0
- package/dist/components/dropdown.d.ts.map +1 -0
- package/dist/components/empty-state.d.ts +9 -0
- package/dist/components/empty-state.d.ts.map +1 -0
- package/dist/components/fieldset.d.ts +23 -0
- package/dist/components/fieldset.d.ts.map +1 -0
- package/dist/components/heading.d.ts +7 -0
- package/dist/components/heading.d.ts.map +1 -0
- package/dist/components/index.d.ts +40 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/input-headless.d.ts +12 -0
- package/dist/components/input-headless.d.ts.map +1 -0
- package/dist/components/kbd.d.ts +8 -0
- package/dist/components/kbd.d.ts.map +1 -0
- package/dist/components/link.d.ts +5 -0
- package/dist/components/link.d.ts.map +1 -0
- package/dist/components/listbox.d.ts +22 -0
- package/dist/components/listbox.d.ts.map +1 -0
- package/dist/components/navbar.d.ts +19 -0
- package/dist/components/navbar.d.ts.map +1 -0
- package/dist/components/progress.d.ts +12 -0
- package/dist/components/progress.d.ts.map +1 -0
- package/dist/components/radio.d.ts +47 -0
- package/dist/components/radio.d.ts.map +1 -0
- package/dist/components/rating.d.ts +11 -0
- package/dist/components/rating.d.ts.map +1 -0
- package/dist/components/select-headless.d.ts +8 -0
- package/dist/components/select-headless.d.ts.map +1 -0
- package/dist/components/sidebar-layout.d.ts +6 -0
- package/dist/components/sidebar-layout.d.ts.map +1 -0
- package/dist/components/sidebar.d.ts +23 -0
- package/dist/components/sidebar.d.ts.map +1 -0
- package/dist/components/skeleton.d.ts +10 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/slider.d.ts +13 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/stacked-layout.d.ts +6 -0
- package/dist/components/stacked-layout.d.ts.map +1 -0
- package/dist/components/stat.d.ts +17 -0
- package/dist/components/stat.d.ts.map +1 -0
- package/dist/components/stepper.d.ts +13 -0
- package/dist/components/stepper.d.ts.map +1 -0
- package/dist/components/switch.d.ts +43 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/table.d.ts +17 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/tabs.d.ts +23 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/text.d.ts +6 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/textarea-headless.d.ts +8 -0
- package/dist/components/textarea-headless.d.ts.map +1 -0
- package/dist/components/timeline.d.ts +14 -0
- package/dist/components/timeline.d.ts.map +1 -0
- package/dist/components/toast.d.ts +20 -0
- package/dist/components/toast.d.ts.map +1 -0
- package/dist/components/tooltip.d.ts +10 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +15 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/use-click-outside.d.ts +3 -0
- package/dist/hooks/use-click-outside.d.ts.map +1 -0
- package/dist/hooks/use-close-context.d.ts +3 -0
- package/dist/hooks/use-close-context.d.ts.map +1 -0
- package/dist/hooks/use-controllable-state.d.ts +6 -0
- package/dist/hooks/use-controllable-state.d.ts.map +1 -0
- package/dist/hooks/use-data-interactive.d.ts +18 -0
- package/dist/hooks/use-data-interactive.d.ts.map +1 -0
- package/dist/hooks/use-escape-key.d.ts +2 -0
- package/dist/hooks/use-escape-key.d.ts.map +1 -0
- package/dist/hooks/use-field-context.d.ts +38 -0
- package/dist/hooks/use-field-context.d.ts.map +1 -0
- package/dist/hooks/use-focus-trap.d.ts +3 -0
- package/dist/hooks/use-focus-trap.d.ts.map +1 -0
- package/dist/hooks/use-layout-animation.d.ts +32 -0
- package/dist/hooks/use-layout-animation.d.ts.map +1 -0
- package/dist/hooks/use-popover.d.ts +28 -0
- package/dist/hooks/use-popover.d.ts.map +1 -0
- package/dist/hooks/use-roving-tabindex.d.ts +34 -0
- package/dist/hooks/use-roving-tabindex.d.ts.map +1 -0
- package/dist/hooks/use-scroll-lock.d.ts +2 -0
- package/dist/hooks/use-scroll-lock.d.ts.map +1 -0
- package/dist/hooks/use-toggle.d.ts +20 -0
- package/dist/hooks/use-toggle.d.ts.map +1 -0
- package/dist/hooks/use-transition.d.ts +28 -0
- package/dist/hooks/use-transition.d.ts.map +1 -0
- package/dist/hooks/use-type-ahead.d.ts +15 -0
- package/dist/hooks/use-type-ahead.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +85 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives/Box.d.ts +9 -0
- package/dist/primitives/Box.d.ts.map +1 -0
- package/dist/primitives/Flex.d.ts +13 -0
- package/dist/primitives/Flex.d.ts.map +1 -0
- package/dist/primitives/Grid.d.ts +11 -0
- package/dist/primitives/Grid.d.ts.map +1 -0
- package/dist/primitives/Heading.d.ts +10 -0
- package/dist/primitives/Heading.d.ts.map +1 -0
- package/dist/primitives/Slot.d.ts +11 -0
- package/dist/primitives/Slot.d.ts.map +1 -0
- package/dist/primitives/Text.d.ts +12 -0
- package/dist/primitives/Text.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +14 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/server.d.ts +22 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +32 -0
- package/dist/server.js.map +1 -0
- package/dist/tooltip-oH4lAnkn.js +2277 -0
- package/dist/tooltip-oH4lAnkn.js.map +1 -0
- package/dist/utils/cn.d.ts +10 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,2277 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { a as clsx, c as cn, B as Box } from "./Box-DDhRNK02.js";
|
|
3
|
+
import React__default, { useState, useId, useCallback, forwardRef, createContext, useContext, useMemo, useRef, useEffect, useReducer } from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
function Accordion({
|
|
6
|
+
className,
|
|
7
|
+
children
|
|
8
|
+
}) {
|
|
9
|
+
return /* @__PURE__ */ jsx("div", { className: clsx("divide-y divide-zinc-200 dark:divide-zinc-700", className), children });
|
|
10
|
+
}
|
|
11
|
+
function AccordionItem({
|
|
12
|
+
title,
|
|
13
|
+
defaultOpen = false,
|
|
14
|
+
className,
|
|
15
|
+
children
|
|
16
|
+
}) {
|
|
17
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
18
|
+
const id = useId();
|
|
19
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
20
|
+
/* @__PURE__ */ jsxs(
|
|
21
|
+
"button",
|
|
22
|
+
{
|
|
23
|
+
type: "button",
|
|
24
|
+
id: `${id}-trigger`,
|
|
25
|
+
"aria-expanded": open,
|
|
26
|
+
"aria-controls": `${id}-content`,
|
|
27
|
+
onClick: () => setOpen((prev) => !prev),
|
|
28
|
+
className: "flex w-full items-center justify-between gap-4 py-4 text-left text-sm font-medium text-zinc-950 transition-colors hover:text-zinc-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:text-white dark:hover:text-zinc-300",
|
|
29
|
+
children: [
|
|
30
|
+
/* @__PURE__ */ jsx("span", { children: title }),
|
|
31
|
+
/* @__PURE__ */ jsx(
|
|
32
|
+
"svg",
|
|
33
|
+
{
|
|
34
|
+
"aria-hidden": "true",
|
|
35
|
+
viewBox: "0 0 16 16",
|
|
36
|
+
fill: "none",
|
|
37
|
+
className: clsx(
|
|
38
|
+
"size-4 shrink-0 text-zinc-400 transition-transform duration-200",
|
|
39
|
+
open && "rotate-180"
|
|
40
|
+
),
|
|
41
|
+
children: /* @__PURE__ */ jsx(
|
|
42
|
+
"path",
|
|
43
|
+
{
|
|
44
|
+
d: "M4 6l4 4 4-4",
|
|
45
|
+
stroke: "currentColor",
|
|
46
|
+
strokeWidth: "1.5",
|
|
47
|
+
strokeLinecap: "round",
|
|
48
|
+
strokeLinejoin: "round"
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
),
|
|
56
|
+
open && /* @__PURE__ */ jsx(
|
|
57
|
+
"div",
|
|
58
|
+
{
|
|
59
|
+
id: `${id}-content`,
|
|
60
|
+
role: "region",
|
|
61
|
+
"aria-labelledby": `${id}-trigger`,
|
|
62
|
+
className: "pb-4 text-sm text-zinc-600 dark:text-zinc-400",
|
|
63
|
+
children
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
] });
|
|
67
|
+
}
|
|
68
|
+
function useDataInteractive({
|
|
69
|
+
disabled = false
|
|
70
|
+
} = {}) {
|
|
71
|
+
const [hover, setHover] = useState(false);
|
|
72
|
+
const [focus, setFocus] = useState(false);
|
|
73
|
+
const [active, setActive] = useState(false);
|
|
74
|
+
const onPointerEnter = useCallback(() => {
|
|
75
|
+
if (!disabled) setHover(true);
|
|
76
|
+
}, [disabled]);
|
|
77
|
+
const onPointerLeave = useCallback(() => {
|
|
78
|
+
setHover(false);
|
|
79
|
+
setActive(false);
|
|
80
|
+
}, []);
|
|
81
|
+
const onPointerDown = useCallback(() => {
|
|
82
|
+
if (!disabled) setActive(true);
|
|
83
|
+
}, [disabled]);
|
|
84
|
+
const onPointerUp = useCallback(() => {
|
|
85
|
+
setActive(false);
|
|
86
|
+
}, []);
|
|
87
|
+
const onFocus = useCallback(
|
|
88
|
+
(e) => {
|
|
89
|
+
if (!disabled && e.currentTarget.matches(":focus-visible")) {
|
|
90
|
+
setFocus(true);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
[disabled]
|
|
94
|
+
);
|
|
95
|
+
const onBlur = useCallback(() => {
|
|
96
|
+
setFocus(false);
|
|
97
|
+
}, []);
|
|
98
|
+
return {
|
|
99
|
+
"data-hover": hover ? "" : void 0,
|
|
100
|
+
"data-focus": focus ? "" : void 0,
|
|
101
|
+
"data-active": active ? "" : void 0,
|
|
102
|
+
"data-disabled": disabled ? "" : void 0,
|
|
103
|
+
onPointerEnter,
|
|
104
|
+
onPointerLeave,
|
|
105
|
+
onPointerDown,
|
|
106
|
+
onPointerUp,
|
|
107
|
+
onFocus,
|
|
108
|
+
onBlur
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const Link = forwardRef(function Link2(props, ref) {
|
|
112
|
+
const interactiveProps = useDataInteractive();
|
|
113
|
+
return /* @__PURE__ */ jsx("a", { ...props, ...interactiveProps, ref });
|
|
114
|
+
});
|
|
115
|
+
const styles = {
|
|
116
|
+
base: [
|
|
117
|
+
// Base
|
|
118
|
+
"relative isolate inline-flex items-baseline justify-center gap-x-2 rounded-lg border text-base/6 font-semibold",
|
|
119
|
+
// Sizing
|
|
120
|
+
"px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] sm:text-sm/6",
|
|
121
|
+
// Focus
|
|
122
|
+
"focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500",
|
|
123
|
+
// Disabled
|
|
124
|
+
"data-disabled:opacity-50",
|
|
125
|
+
// Icon
|
|
126
|
+
"*:data-[slot=icon]:-mx-0.5 *:data-[slot=icon]:my-0.5 *:data-[slot=icon]:size-5 *:data-[slot=icon]:shrink-0 *:data-[slot=icon]:self-center *:data-[slot=icon]:text-(--btn-icon) sm:*:data-[slot=icon]:my-1 sm:*:data-[slot=icon]:size-4 forced-colors:[--btn-icon:ButtonText] forced-colors:data-hover:[--btn-icon:ButtonText]"
|
|
127
|
+
],
|
|
128
|
+
solid: [
|
|
129
|
+
// Optical border, implemented as the button background to avoid corner artifacts
|
|
130
|
+
"border-transparent bg-(--btn-border)",
|
|
131
|
+
// Dark mode: border is rendered on `after` so background is set to button background
|
|
132
|
+
"dark:bg-(--btn-bg)",
|
|
133
|
+
// Button background, implemented as foreground layer to stack on top of pseudo-border layer
|
|
134
|
+
"before:absolute before:inset-0 before:-z-10 before:rounded-[calc(var(--radius-lg)-1px)] before:bg-(--btn-bg)",
|
|
135
|
+
// Drop shadow, applied to the inset `before` layer so it blends with the border
|
|
136
|
+
"before:shadow-sm",
|
|
137
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
138
|
+
"dark:before:hidden",
|
|
139
|
+
// Dark mode: Subtle white outline is applied using a border
|
|
140
|
+
"dark:border-white/5",
|
|
141
|
+
// Shim/overlay, inset to match button foreground and used for hover state + highlight shadow
|
|
142
|
+
"after:absolute after:inset-0 after:-z-10 after:rounded-[calc(var(--radius-lg)-1px)]",
|
|
143
|
+
// Inner highlight shadow
|
|
144
|
+
"after:shadow-[inset_0_1px_--theme(--color-white/15%)]",
|
|
145
|
+
// White overlay on hover
|
|
146
|
+
"data-active:after:bg-(--btn-hover-overlay) data-hover:after:bg-(--btn-hover-overlay)",
|
|
147
|
+
// Dark mode: `after` layer expands to cover entire button
|
|
148
|
+
"dark:after:-inset-px dark:after:rounded-lg",
|
|
149
|
+
// Disabled
|
|
150
|
+
"data-disabled:before:shadow-none data-disabled:after:shadow-none"
|
|
151
|
+
],
|
|
152
|
+
outline: [
|
|
153
|
+
// Base
|
|
154
|
+
"border-zinc-950/10 text-zinc-950 data-active:bg-zinc-950/2.5 data-hover:bg-zinc-950/2.5",
|
|
155
|
+
// Dark mode
|
|
156
|
+
"dark:border-white/15 dark:text-white dark:[--btn-bg:transparent] dark:data-active:bg-white/5 dark:data-hover:bg-white/5",
|
|
157
|
+
// Icon
|
|
158
|
+
"[--btn-icon:var(--color-zinc-500)] data-active:[--btn-icon:var(--color-zinc-700)] data-hover:[--btn-icon:var(--color-zinc-700)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
|
|
159
|
+
],
|
|
160
|
+
plain: [
|
|
161
|
+
// Base
|
|
162
|
+
"border-transparent text-zinc-950 data-active:bg-zinc-950/5 data-hover:bg-zinc-950/5",
|
|
163
|
+
// Dark mode
|
|
164
|
+
"dark:text-white dark:data-active:bg-white/10 dark:data-hover:bg-white/10",
|
|
165
|
+
// Icon
|
|
166
|
+
"[--btn-icon:var(--color-zinc-500)] data-active:[--btn-icon:var(--color-zinc-700)] data-hover:[--btn-icon:var(--color-zinc-700)] dark:[--btn-icon:var(--color-zinc-500)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
|
|
167
|
+
],
|
|
168
|
+
colors: {
|
|
169
|
+
"dark/zinc": [
|
|
170
|
+
"text-white [--btn-bg:var(--color-zinc-900)] [--btn-border:var(--color-zinc-950)]/90 [--btn-hover-overlay:var(--color-white)]/10",
|
|
171
|
+
"dark:text-white dark:[--btn-bg:var(--color-zinc-600)] dark:[--btn-hover-overlay:var(--color-white)]/5",
|
|
172
|
+
"[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)]"
|
|
173
|
+
],
|
|
174
|
+
light: [
|
|
175
|
+
"text-zinc-950 [--btn-bg:white] [--btn-border:var(--color-zinc-950)]/10 [--btn-hover-overlay:var(--color-zinc-950)]/2.5 data-active:[--btn-border:var(--color-zinc-950)]/15 data-hover:[--btn-border:var(--color-zinc-950)]/15",
|
|
176
|
+
"dark:text-white dark:[--btn-hover-overlay:var(--color-white)]/5 dark:[--btn-bg:var(--color-zinc-800)]",
|
|
177
|
+
"[--btn-icon:var(--color-zinc-500)] data-active:[--btn-icon:var(--color-zinc-700)] data-hover:[--btn-icon:var(--color-zinc-700)] dark:[--btn-icon:var(--color-zinc-500)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
|
|
178
|
+
],
|
|
179
|
+
"dark/white": [
|
|
180
|
+
"text-white [--btn-bg:var(--color-zinc-900)] [--btn-border:var(--color-zinc-950)]/90 [--btn-hover-overlay:var(--color-white)]/10",
|
|
181
|
+
"dark:text-zinc-950 dark:[--btn-bg:white] dark:[--btn-hover-overlay:var(--color-zinc-950)]/5",
|
|
182
|
+
"[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)] dark:[--btn-icon:var(--color-zinc-500)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
|
|
183
|
+
],
|
|
184
|
+
dark: [
|
|
185
|
+
"text-white [--btn-bg:var(--color-zinc-900)] [--btn-border:var(--color-zinc-950)]/90 [--btn-hover-overlay:var(--color-white)]/10",
|
|
186
|
+
"dark:[--btn-hover-overlay:var(--color-white)]/5 dark:[--btn-bg:var(--color-zinc-800)]",
|
|
187
|
+
"[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)]"
|
|
188
|
+
],
|
|
189
|
+
white: [
|
|
190
|
+
"text-zinc-950 [--btn-bg:white] [--btn-border:var(--color-zinc-950)]/10 [--btn-hover-overlay:var(--color-zinc-950)]/2.5 data-active:[--btn-border:var(--color-zinc-950)]/15 data-hover:[--btn-border:var(--color-zinc-950)]/15",
|
|
191
|
+
"dark:[--btn-hover-overlay:var(--color-zinc-950)]/5",
|
|
192
|
+
"[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-500)] data-hover:[--btn-icon:var(--color-zinc-500)]"
|
|
193
|
+
],
|
|
194
|
+
zinc: [
|
|
195
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-zinc-600)] [--btn-border:var(--color-zinc-700)]/90",
|
|
196
|
+
"dark:[--btn-hover-overlay:var(--color-white)]/5",
|
|
197
|
+
"[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)]"
|
|
198
|
+
],
|
|
199
|
+
indigo: [
|
|
200
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-indigo-500)] [--btn-border:var(--color-indigo-600)]/90",
|
|
201
|
+
"[--btn-icon:var(--color-indigo-300)] data-active:[--btn-icon:var(--color-indigo-200)] data-hover:[--btn-icon:var(--color-indigo-200)]"
|
|
202
|
+
],
|
|
203
|
+
cyan: [
|
|
204
|
+
"text-cyan-950 [--btn-bg:var(--color-cyan-300)] [--btn-border:var(--color-cyan-400)]/80 [--btn-hover-overlay:var(--color-white)]/25",
|
|
205
|
+
"[--btn-icon:var(--color-cyan-500)]"
|
|
206
|
+
],
|
|
207
|
+
red: [
|
|
208
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-red-600)] [--btn-border:var(--color-red-700)]/90",
|
|
209
|
+
"[--btn-icon:var(--color-red-300)] data-active:[--btn-icon:var(--color-red-200)] data-hover:[--btn-icon:var(--color-red-200)]"
|
|
210
|
+
],
|
|
211
|
+
orange: [
|
|
212
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-orange-500)] [--btn-border:var(--color-orange-600)]/90",
|
|
213
|
+
"[--btn-icon:var(--color-orange-300)] data-active:[--btn-icon:var(--color-orange-200)] data-hover:[--btn-icon:var(--color-orange-200)]"
|
|
214
|
+
],
|
|
215
|
+
amber: [
|
|
216
|
+
"text-amber-950 [--btn-hover-overlay:var(--color-white)]/25 [--btn-bg:var(--color-amber-400)] [--btn-border:var(--color-amber-500)]/80",
|
|
217
|
+
"[--btn-icon:var(--color-amber-600)]"
|
|
218
|
+
],
|
|
219
|
+
yellow: [
|
|
220
|
+
"text-yellow-950 [--btn-hover-overlay:var(--color-white)]/25 [--btn-bg:var(--color-yellow-300)] [--btn-border:var(--color-yellow-400)]/80",
|
|
221
|
+
"[--btn-icon:var(--color-yellow-600)] data-active:[--btn-icon:var(--color-yellow-700)] data-hover:[--btn-icon:var(--color-yellow-700)]"
|
|
222
|
+
],
|
|
223
|
+
lime: [
|
|
224
|
+
"text-lime-950 [--btn-hover-overlay:var(--color-white)]/25 [--btn-bg:var(--color-lime-300)] [--btn-border:var(--color-lime-400)]/80",
|
|
225
|
+
"[--btn-icon:var(--color-lime-600)] data-active:[--btn-icon:var(--color-lime-700)] data-hover:[--btn-icon:var(--color-lime-700)]"
|
|
226
|
+
],
|
|
227
|
+
green: [
|
|
228
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-green-600)] [--btn-border:var(--color-green-700)]/90",
|
|
229
|
+
"[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
|
|
230
|
+
],
|
|
231
|
+
emerald: [
|
|
232
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-emerald-600)] [--btn-border:var(--color-emerald-700)]/90",
|
|
233
|
+
"[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
|
|
234
|
+
],
|
|
235
|
+
teal: [
|
|
236
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-teal-600)] [--btn-border:var(--color-teal-700)]/90",
|
|
237
|
+
"[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
|
|
238
|
+
],
|
|
239
|
+
sky: [
|
|
240
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-sky-500)] [--btn-border:var(--color-sky-600)]/80",
|
|
241
|
+
"[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
|
|
242
|
+
],
|
|
243
|
+
blue: [
|
|
244
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-blue-600)] [--btn-border:var(--color-blue-700)]/90",
|
|
245
|
+
"[--btn-icon:var(--color-blue-400)] data-active:[--btn-icon:var(--color-blue-300)] data-hover:[--btn-icon:var(--color-blue-300)]"
|
|
246
|
+
],
|
|
247
|
+
violet: [
|
|
248
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-violet-500)] [--btn-border:var(--color-violet-600)]/90",
|
|
249
|
+
"[--btn-icon:var(--color-violet-300)] data-active:[--btn-icon:var(--color-violet-200)] data-hover:[--btn-icon:var(--color-violet-200)]"
|
|
250
|
+
],
|
|
251
|
+
purple: [
|
|
252
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-purple-500)] [--btn-border:var(--color-purple-600)]/90",
|
|
253
|
+
"[--btn-icon:var(--color-purple-300)] data-active:[--btn-icon:var(--color-purple-200)] data-hover:[--btn-icon:var(--color-purple-200)]"
|
|
254
|
+
],
|
|
255
|
+
fuchsia: [
|
|
256
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-fuchsia-500)] [--btn-border:var(--color-fuchsia-600)]/90",
|
|
257
|
+
"[--btn-icon:var(--color-fuchsia-300)] data-active:[--btn-icon:var(--color-fuchsia-200)] data-hover:[--btn-icon:var(--color-fuchsia-200)]"
|
|
258
|
+
],
|
|
259
|
+
pink: [
|
|
260
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-pink-500)] [--btn-border:var(--color-pink-600)]/90",
|
|
261
|
+
"[--btn-icon:var(--color-pink-300)] data-active:[--btn-icon:var(--color-pink-200)] data-hover:[--btn-icon:var(--color-pink-200)]"
|
|
262
|
+
],
|
|
263
|
+
rose: [
|
|
264
|
+
"text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-rose-500)] [--btn-border:var(--color-rose-600)]/90",
|
|
265
|
+
"[--btn-icon:var(--color-rose-300)] data-active:[--btn-icon:var(--color-rose-200)] data-hover:[--btn-icon:var(--color-rose-200)]"
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
const Button = forwardRef(function Button2({ color, outline, plain, className, children, ...props }, ref) {
|
|
270
|
+
const disabled = "disabled" in props ? props.disabled : false;
|
|
271
|
+
const interactiveProps = useDataInteractive({ disabled: disabled ?? false });
|
|
272
|
+
const classes = clsx(
|
|
273
|
+
className,
|
|
274
|
+
styles.base,
|
|
275
|
+
outline ? styles.outline : plain ? styles.plain : clsx(styles.solid, styles.colors[color ?? "dark/zinc"])
|
|
276
|
+
);
|
|
277
|
+
return typeof props.href === "string" ? /* @__PURE__ */ jsx(Link, { ...props, className: classes, ref, children: /* @__PURE__ */ jsx(TouchTarget, { children }) }) : /* @__PURE__ */ jsx(
|
|
278
|
+
"button",
|
|
279
|
+
{
|
|
280
|
+
type: "button",
|
|
281
|
+
...props,
|
|
282
|
+
...interactiveProps,
|
|
283
|
+
className: clsx(classes, "cursor-default"),
|
|
284
|
+
ref,
|
|
285
|
+
children: /* @__PURE__ */ jsx(TouchTarget, { children })
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
function TouchTarget({ children }) {
|
|
290
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
291
|
+
/* @__PURE__ */ jsx(
|
|
292
|
+
"span",
|
|
293
|
+
{
|
|
294
|
+
className: "absolute top-1/2 left-1/2 size-[max(100%,2.75rem)] -translate-x-1/2 -translate-y-1/2 pointer-fine:hidden",
|
|
295
|
+
"aria-hidden": "true"
|
|
296
|
+
}
|
|
297
|
+
),
|
|
298
|
+
children
|
|
299
|
+
] });
|
|
300
|
+
}
|
|
301
|
+
function Avatar({
|
|
302
|
+
src = null,
|
|
303
|
+
square = false,
|
|
304
|
+
initials,
|
|
305
|
+
alt = "",
|
|
306
|
+
className,
|
|
307
|
+
...props
|
|
308
|
+
}) {
|
|
309
|
+
const title = alt && alt.trim().length > 0 ? alt.trim() : "Avatar";
|
|
310
|
+
return /* @__PURE__ */ jsxs(
|
|
311
|
+
"span",
|
|
312
|
+
{
|
|
313
|
+
"data-slot": "avatar",
|
|
314
|
+
...props,
|
|
315
|
+
className: clsx(
|
|
316
|
+
className,
|
|
317
|
+
// Basic layout
|
|
318
|
+
"inline-grid shrink-0 align-middle [--avatar-radius:20%] *:col-start-1 *:row-start-1",
|
|
319
|
+
"outline -outline-offset-1 outline-black/10 dark:outline-white/10",
|
|
320
|
+
// Border radius
|
|
321
|
+
square ? "rounded-(--avatar-radius) *:rounded-(--avatar-radius)" : "rounded-full *:rounded-full"
|
|
322
|
+
),
|
|
323
|
+
children: [
|
|
324
|
+
initials && /* @__PURE__ */ jsxs(
|
|
325
|
+
"svg",
|
|
326
|
+
{
|
|
327
|
+
className: "size-full fill-current p-[5%] text-[48px] font-medium uppercase select-none",
|
|
328
|
+
viewBox: "0 0 100 100",
|
|
329
|
+
"aria-hidden": alt && alt.trim().length > 0 ? void 0 : "true",
|
|
330
|
+
children: [
|
|
331
|
+
/* @__PURE__ */ jsx("title", { children: title }),
|
|
332
|
+
/* @__PURE__ */ jsx(
|
|
333
|
+
"text",
|
|
334
|
+
{
|
|
335
|
+
x: "50%",
|
|
336
|
+
y: "50%",
|
|
337
|
+
alignmentBaseline: "middle",
|
|
338
|
+
dominantBaseline: "middle",
|
|
339
|
+
textAnchor: "middle",
|
|
340
|
+
dy: ".125em",
|
|
341
|
+
children: initials
|
|
342
|
+
}
|
|
343
|
+
)
|
|
344
|
+
]
|
|
345
|
+
}
|
|
346
|
+
),
|
|
347
|
+
src && /* @__PURE__ */ jsx("img", { className: "size-full", src, alt })
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
forwardRef(function AvatarButton2({
|
|
353
|
+
src,
|
|
354
|
+
square = false,
|
|
355
|
+
initials,
|
|
356
|
+
alt,
|
|
357
|
+
className,
|
|
358
|
+
...props
|
|
359
|
+
}, ref) {
|
|
360
|
+
const disabled = "disabled" in props ? props.disabled : false;
|
|
361
|
+
const interactiveProps = useDataInteractive({ disabled: disabled ?? false });
|
|
362
|
+
const classes = clsx(
|
|
363
|
+
className,
|
|
364
|
+
square ? "rounded-[20%]" : "rounded-full",
|
|
365
|
+
"relative inline-grid focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500"
|
|
366
|
+
);
|
|
367
|
+
return typeof props.href === "string" ? /* @__PURE__ */ jsx(Link, { ...props, className: classes, ref, children: /* @__PURE__ */ jsx(TouchTarget, { children: /* @__PURE__ */ jsx(Avatar, { src, square, initials, alt }) }) }) : /* @__PURE__ */ jsx("button", { type: "button", ...props, ...interactiveProps, className: classes, ref, children: /* @__PURE__ */ jsx(TouchTarget, { children: /* @__PURE__ */ jsx(Avatar, { src, square, initials, alt }) }) });
|
|
368
|
+
});
|
|
369
|
+
function AvatarGroup({
|
|
370
|
+
items,
|
|
371
|
+
max = 5,
|
|
372
|
+
size = "md",
|
|
373
|
+
className
|
|
374
|
+
}) {
|
|
375
|
+
const sizeClasses = { xs: "size-6", sm: "size-8", md: "size-10", lg: "size-12" };
|
|
376
|
+
const overlapClass = { xs: "-ml-1.5", sm: "-ml-2", md: "-ml-3", lg: "-ml-4" };
|
|
377
|
+
const visible = items.slice(0, max);
|
|
378
|
+
const overflow = items.length - max;
|
|
379
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("flex items-center", className), children: [
|
|
380
|
+
visible.map((item, i) => {
|
|
381
|
+
return /* @__PURE__ */ jsx(
|
|
382
|
+
"div",
|
|
383
|
+
{
|
|
384
|
+
className: clsx(
|
|
385
|
+
"ring-2 ring-white dark:ring-zinc-900",
|
|
386
|
+
sizeClasses[size],
|
|
387
|
+
i > 0 && overlapClass[size],
|
|
388
|
+
"rounded-full"
|
|
389
|
+
),
|
|
390
|
+
children: /* @__PURE__ */ jsx(
|
|
391
|
+
Avatar,
|
|
392
|
+
{
|
|
393
|
+
src: item.src,
|
|
394
|
+
initials: item.initials,
|
|
395
|
+
alt: item.alt ?? "",
|
|
396
|
+
className: "size-full"
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
},
|
|
400
|
+
i
|
|
401
|
+
);
|
|
402
|
+
}),
|
|
403
|
+
overflow > 0 && /* @__PURE__ */ jsxs(
|
|
404
|
+
"div",
|
|
405
|
+
{
|
|
406
|
+
className: clsx(
|
|
407
|
+
overlapClass[size],
|
|
408
|
+
sizeClasses[size],
|
|
409
|
+
"flex items-center justify-center rounded-full bg-zinc-200 text-xs font-medium text-zinc-600 ring-2 ring-white dark:bg-zinc-700 dark:text-zinc-300 dark:ring-zinc-900"
|
|
410
|
+
),
|
|
411
|
+
role: "img",
|
|
412
|
+
"aria-label": `${overflow} more`,
|
|
413
|
+
children: [
|
|
414
|
+
"+",
|
|
415
|
+
overflow
|
|
416
|
+
]
|
|
417
|
+
}
|
|
418
|
+
)
|
|
419
|
+
] });
|
|
420
|
+
}
|
|
421
|
+
function Breadcrumb({
|
|
422
|
+
items,
|
|
423
|
+
separator,
|
|
424
|
+
className
|
|
425
|
+
}) {
|
|
426
|
+
const sep = separator ?? /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", viewBox: "0 0 16 16", fill: "none", className: "size-3.5 text-zinc-400", children: /* @__PURE__ */ jsx(
|
|
427
|
+
"path",
|
|
428
|
+
{
|
|
429
|
+
d: "M6 4l4 4-4 4",
|
|
430
|
+
stroke: "currentColor",
|
|
431
|
+
strokeWidth: "1.5",
|
|
432
|
+
strokeLinecap: "round",
|
|
433
|
+
strokeLinejoin: "round"
|
|
434
|
+
}
|
|
435
|
+
) });
|
|
436
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx("ol", { className: clsx("flex flex-wrap items-center gap-1.5 text-sm", className), children: items.map((item, index) => {
|
|
437
|
+
const isLast = index === items.length - 1;
|
|
438
|
+
return (
|
|
439
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: breadcrumb items are positionally ordered with no stable ID
|
|
440
|
+
/* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5", children: [
|
|
441
|
+
isLast || !item.href ? /* @__PURE__ */ jsx(
|
|
442
|
+
"span",
|
|
443
|
+
{
|
|
444
|
+
"aria-current": isLast ? "page" : void 0,
|
|
445
|
+
className: clsx(
|
|
446
|
+
isLast ? "font-medium text-zinc-950 dark:text-white" : "text-zinc-500 dark:text-zinc-400"
|
|
447
|
+
),
|
|
448
|
+
children: item.label
|
|
449
|
+
}
|
|
450
|
+
) : /* @__PURE__ */ jsx(
|
|
451
|
+
"a",
|
|
452
|
+
{
|
|
453
|
+
href: item.href,
|
|
454
|
+
className: "text-zinc-500 transition-colors hover:text-zinc-950 dark:text-zinc-400 dark:hover:text-white",
|
|
455
|
+
children: item.label
|
|
456
|
+
}
|
|
457
|
+
),
|
|
458
|
+
!isLast && sep
|
|
459
|
+
] }, index)
|
|
460
|
+
);
|
|
461
|
+
}) }) });
|
|
462
|
+
}
|
|
463
|
+
const CheckboxContext = React__default.createContext(null);
|
|
464
|
+
const Checkbox$1 = React__default.forwardRef(
|
|
465
|
+
({ checked, defaultChecked, disabled, onCheckedChange, className, ...props }, ref) => {
|
|
466
|
+
const [internalChecked, setInternalChecked] = React__default.useState(
|
|
467
|
+
defaultChecked ?? false
|
|
468
|
+
);
|
|
469
|
+
const handleChange = (e) => {
|
|
470
|
+
if (disabled) return;
|
|
471
|
+
const newChecked = e.target.checked;
|
|
472
|
+
setInternalChecked(newChecked);
|
|
473
|
+
onCheckedChange?.(newChecked);
|
|
474
|
+
};
|
|
475
|
+
React__default.useEffect(() => {
|
|
476
|
+
if (checked !== void 0) {
|
|
477
|
+
setInternalChecked(checked);
|
|
478
|
+
}
|
|
479
|
+
}, [checked]);
|
|
480
|
+
return /* @__PURE__ */ jsx(CheckboxContext.Provider, { value: { state: internalChecked, disabled, onCheckedChange }, children: /* @__PURE__ */ jsx(
|
|
481
|
+
"input",
|
|
482
|
+
{
|
|
483
|
+
type: "checkbox",
|
|
484
|
+
disabled,
|
|
485
|
+
checked: checked !== void 0 ? checked : internalChecked === "indeterminate" ? false : internalChecked,
|
|
486
|
+
ref: (el) => {
|
|
487
|
+
if (el) {
|
|
488
|
+
el.indeterminate = internalChecked === "indeterminate";
|
|
489
|
+
}
|
|
490
|
+
if (ref) {
|
|
491
|
+
if (typeof ref === "function") {
|
|
492
|
+
ref(el);
|
|
493
|
+
} else {
|
|
494
|
+
ref.current = el;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
onChange: handleChange,
|
|
499
|
+
className: cn(
|
|
500
|
+
"peer h-4 w-4 shrink-0 rounded border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
501
|
+
className
|
|
502
|
+
),
|
|
503
|
+
"data-state": internalChecked === "indeterminate" ? "indeterminate" : internalChecked ? "checked" : "unchecked",
|
|
504
|
+
...props
|
|
505
|
+
}
|
|
506
|
+
) });
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
Checkbox$1.displayName = "Checkbox";
|
|
510
|
+
const CheckboxIndicator = React__default.forwardRef(
|
|
511
|
+
({ className, ...props }, ref) => {
|
|
512
|
+
const context = React__default.useContext(CheckboxContext);
|
|
513
|
+
if (!context) {
|
|
514
|
+
throw new Error("CheckboxIndicator must be used within a Checkbox");
|
|
515
|
+
}
|
|
516
|
+
return /* @__PURE__ */ jsxs(
|
|
517
|
+
"span",
|
|
518
|
+
{
|
|
519
|
+
"data-state": context.state === "indeterminate" ? "indeterminate" : context.state ? "checked" : "unchecked",
|
|
520
|
+
ref,
|
|
521
|
+
className: cn("flex items-center justify-center text-current", className),
|
|
522
|
+
...props,
|
|
523
|
+
children: [
|
|
524
|
+
context.state === true && "✔",
|
|
525
|
+
context.state === "indeterminate" && "−"
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
CheckboxIndicator.displayName = "CheckboxIndicator";
|
|
532
|
+
const variantStyles = {
|
|
533
|
+
info: {
|
|
534
|
+
wrapper: "bg-blue-50 ring-blue-200 dark:bg-blue-950/30 dark:ring-blue-800",
|
|
535
|
+
icon: "text-blue-600 dark:text-blue-400",
|
|
536
|
+
iconChar: "i"
|
|
537
|
+
},
|
|
538
|
+
warning: {
|
|
539
|
+
wrapper: "bg-amber-50 ring-amber-200 dark:bg-amber-950/30 dark:ring-amber-800",
|
|
540
|
+
icon: "text-amber-600 dark:text-amber-400",
|
|
541
|
+
iconChar: "!"
|
|
542
|
+
},
|
|
543
|
+
error: {
|
|
544
|
+
wrapper: "bg-red-50 ring-red-200 dark:bg-red-950/30 dark:ring-red-800",
|
|
545
|
+
icon: "text-red-600 dark:text-red-400",
|
|
546
|
+
iconChar: "✕"
|
|
547
|
+
},
|
|
548
|
+
success: {
|
|
549
|
+
wrapper: "bg-green-50 ring-green-200 dark:bg-green-950/30 dark:ring-green-800",
|
|
550
|
+
icon: "text-green-600 dark:text-green-400",
|
|
551
|
+
iconChar: "✓"
|
|
552
|
+
},
|
|
553
|
+
tip: {
|
|
554
|
+
wrapper: "bg-violet-50 ring-violet-200 dark:bg-violet-950/30 dark:ring-violet-800",
|
|
555
|
+
icon: "text-violet-600 dark:text-violet-400",
|
|
556
|
+
iconChar: "★"
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
function Callout({
|
|
560
|
+
variant = "info",
|
|
561
|
+
title,
|
|
562
|
+
icon,
|
|
563
|
+
className,
|
|
564
|
+
children
|
|
565
|
+
}) {
|
|
566
|
+
const styles2 = variantStyles[variant];
|
|
567
|
+
return /* @__PURE__ */ jsx("div", { role: "note", className: clsx("rounded-xl p-4 ring-1", styles2.wrapper, className), children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
568
|
+
/* @__PURE__ */ jsx("span", { className: clsx("mt-0.5 shrink-0 text-sm font-bold", styles2.icon), "aria-hidden": "true", children: icon ?? styles2.iconChar }),
|
|
569
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
570
|
+
title && /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: title }),
|
|
571
|
+
/* @__PURE__ */ jsx("div", { className: clsx("text-sm text-zinc-700 dark:text-zinc-300", title && "mt-1"), children })
|
|
572
|
+
] })
|
|
573
|
+
] }) });
|
|
574
|
+
}
|
|
575
|
+
const FieldContext = createContext(null);
|
|
576
|
+
function useFieldContext() {
|
|
577
|
+
return useContext(FieldContext);
|
|
578
|
+
}
|
|
579
|
+
function FieldProvider({ children, disabled = false }) {
|
|
580
|
+
const id = useId();
|
|
581
|
+
const value = useMemo(
|
|
582
|
+
() => ({
|
|
583
|
+
controlId: `${id}-control`,
|
|
584
|
+
labelId: `${id}-label`,
|
|
585
|
+
descriptionId: `${id}-description`,
|
|
586
|
+
errorId: `${id}-error`,
|
|
587
|
+
disabled
|
|
588
|
+
}),
|
|
589
|
+
[id, disabled]
|
|
590
|
+
);
|
|
591
|
+
return /* @__PURE__ */ jsx(FieldContext, { value, children });
|
|
592
|
+
}
|
|
593
|
+
function useFieldControlProps() {
|
|
594
|
+
const ctx = useFieldContext();
|
|
595
|
+
if (!ctx) return {};
|
|
596
|
+
return {
|
|
597
|
+
id: ctx.controlId,
|
|
598
|
+
"aria-labelledby": ctx.labelId,
|
|
599
|
+
"aria-describedby": ctx.descriptionId,
|
|
600
|
+
"data-disabled": ctx.disabled ? "" : void 0
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function useFieldLabelProps() {
|
|
604
|
+
const ctx = useFieldContext();
|
|
605
|
+
if (!ctx) return {};
|
|
606
|
+
return {
|
|
607
|
+
id: ctx.labelId,
|
|
608
|
+
htmlFor: ctx.controlId,
|
|
609
|
+
"data-disabled": ctx.disabled ? "" : void 0
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
function useFieldDescriptionProps() {
|
|
613
|
+
const ctx = useFieldContext();
|
|
614
|
+
if (!ctx) return {};
|
|
615
|
+
return {
|
|
616
|
+
id: ctx.descriptionId,
|
|
617
|
+
"data-disabled": ctx.disabled ? "" : void 0
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function useFieldErrorProps() {
|
|
621
|
+
const ctx = useFieldContext();
|
|
622
|
+
if (!ctx) return {};
|
|
623
|
+
return {
|
|
624
|
+
id: ctx.errorId,
|
|
625
|
+
"data-disabled": ctx.disabled ? "" : void 0
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
function useControllableState({
|
|
629
|
+
value: controlledValue,
|
|
630
|
+
defaultValue,
|
|
631
|
+
onChange
|
|
632
|
+
}) {
|
|
633
|
+
const isControlled = controlledValue !== void 0;
|
|
634
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
635
|
+
const value = isControlled ? controlledValue : internalValue;
|
|
636
|
+
const onChangeRef = useRef(onChange);
|
|
637
|
+
onChangeRef.current = onChange;
|
|
638
|
+
const setValue = useCallback(
|
|
639
|
+
(next) => {
|
|
640
|
+
const resolvedValue = typeof next === "function" ? next(value) : next;
|
|
641
|
+
if (!isControlled) {
|
|
642
|
+
setInternalValue(resolvedValue);
|
|
643
|
+
}
|
|
644
|
+
onChangeRef.current?.(resolvedValue);
|
|
645
|
+
},
|
|
646
|
+
[isControlled, value]
|
|
647
|
+
);
|
|
648
|
+
return [value, setValue];
|
|
649
|
+
}
|
|
650
|
+
function useToggle({
|
|
651
|
+
checked: controlledChecked,
|
|
652
|
+
defaultChecked = false,
|
|
653
|
+
onChange,
|
|
654
|
+
disabled = false
|
|
655
|
+
} = {}) {
|
|
656
|
+
const [checked, setChecked] = useControllableState({
|
|
657
|
+
value: controlledChecked,
|
|
658
|
+
defaultValue: defaultChecked,
|
|
659
|
+
onChange
|
|
660
|
+
});
|
|
661
|
+
const toggle = useCallback(() => {
|
|
662
|
+
if (!disabled) {
|
|
663
|
+
setChecked((prev) => !prev);
|
|
664
|
+
}
|
|
665
|
+
}, [disabled, setChecked]);
|
|
666
|
+
const onClick = useCallback(() => {
|
|
667
|
+
toggle();
|
|
668
|
+
}, [toggle]);
|
|
669
|
+
const onKeyDown = useCallback(
|
|
670
|
+
(e) => {
|
|
671
|
+
if (e.key === " ") {
|
|
672
|
+
e.preventDefault();
|
|
673
|
+
toggle();
|
|
674
|
+
}
|
|
675
|
+
},
|
|
676
|
+
[toggle]
|
|
677
|
+
);
|
|
678
|
+
return {
|
|
679
|
+
checked,
|
|
680
|
+
toggle,
|
|
681
|
+
toggleProps: {
|
|
682
|
+
"aria-checked": checked,
|
|
683
|
+
"data-checked": checked ? "" : void 0,
|
|
684
|
+
tabIndex: 0,
|
|
685
|
+
onClick,
|
|
686
|
+
onKeyDown
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
function CheckboxGroup({ className, ...props }) {
|
|
691
|
+
return /* @__PURE__ */ jsx(
|
|
692
|
+
"div",
|
|
693
|
+
{
|
|
694
|
+
"data-slot": "control",
|
|
695
|
+
...props,
|
|
696
|
+
className: clsx(
|
|
697
|
+
className,
|
|
698
|
+
// Basic groups
|
|
699
|
+
"space-y-3",
|
|
700
|
+
// With descriptions
|
|
701
|
+
"has-data-[slot=description]:space-y-6 has-data-[slot=description]:**:data-[slot=label]:font-medium"
|
|
702
|
+
)
|
|
703
|
+
}
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
function CheckboxField({
|
|
707
|
+
className,
|
|
708
|
+
disabled,
|
|
709
|
+
...props
|
|
710
|
+
}) {
|
|
711
|
+
return /* @__PURE__ */ jsx(FieldProvider, { disabled, children: /* @__PURE__ */ jsx(
|
|
712
|
+
"div",
|
|
713
|
+
{
|
|
714
|
+
"data-slot": "field",
|
|
715
|
+
"data-disabled": disabled ? "" : void 0,
|
|
716
|
+
...props,
|
|
717
|
+
className: clsx(
|
|
718
|
+
className,
|
|
719
|
+
// Base layout
|
|
720
|
+
"grid grid-cols-[1.125rem_1fr] gap-x-4 gap-y-1 sm:grid-cols-[1rem_1fr]",
|
|
721
|
+
// Control layout
|
|
722
|
+
"*:data-[slot=control]:col-start-1 *:data-[slot=control]:row-start-1 *:data-[slot=control]:mt-0.75 sm:*:data-[slot=control]:mt-1",
|
|
723
|
+
// Label layout
|
|
724
|
+
"*:data-[slot=label]:col-start-2 *:data-[slot=label]:row-start-1",
|
|
725
|
+
// Description layout
|
|
726
|
+
"*:data-[slot=description]:col-start-2 *:data-[slot=description]:row-start-2",
|
|
727
|
+
// With description
|
|
728
|
+
"has-data-[slot=description]:**:data-[slot=label]:font-medium"
|
|
729
|
+
)
|
|
730
|
+
}
|
|
731
|
+
) });
|
|
732
|
+
}
|
|
733
|
+
const base = [
|
|
734
|
+
// Basic layout
|
|
735
|
+
"relative isolate flex size-4.5 items-center justify-center rounded-[0.3125rem] sm:size-4",
|
|
736
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
737
|
+
"before:absolute before:inset-0 before:-z-10 before:rounded-[calc(0.3125rem-1px)] before:bg-white before:shadow-sm",
|
|
738
|
+
// Background color when checked
|
|
739
|
+
"group-data-checked:before:bg-(--checkbox-checked-bg)",
|
|
740
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
741
|
+
"dark:before:hidden",
|
|
742
|
+
// Background color applied to control in dark mode
|
|
743
|
+
"dark:bg-white/5 dark:group-data-checked:bg-(--checkbox-checked-bg)",
|
|
744
|
+
// Border
|
|
745
|
+
"border border-zinc-950/15 group-data-checked:border-transparent group-data-hover:group-data-checked:border-transparent group-data-hover:border-zinc-950/30 group-data-checked:bg-(--checkbox-checked-border)",
|
|
746
|
+
"dark:border-white/15 dark:group-data-checked:border-white/5 dark:group-data-hover:group-data-checked:border-white/5 dark:group-data-hover:border-white/30",
|
|
747
|
+
// Inner highlight shadow
|
|
748
|
+
"after:absolute after:inset-0 after:rounded-[calc(0.3125rem-1px)] after:shadow-[inset_0_1px_--theme(--color-white/15%)]",
|
|
749
|
+
"dark:after:-inset-px dark:after:hidden dark:after:rounded-[0.3125rem] dark:group-data-checked:after:block",
|
|
750
|
+
// Focus ring
|
|
751
|
+
"group-data-focus:outline-2 group-data-focus:outline-offset-2 group-data-focus:outline-blue-500",
|
|
752
|
+
// Disabled state
|
|
753
|
+
"group-data-disabled:opacity-50",
|
|
754
|
+
"group-data-disabled:border-zinc-950/25 group-data-disabled:bg-zinc-950/5 group-data-disabled:[--checkbox-check:var(--color-zinc-950)]/50 group-data-disabled:before:bg-transparent",
|
|
755
|
+
"dark:group-data-disabled:border-white/20 dark:group-data-disabled:bg-white/2.5 dark:group-data-disabled:[--checkbox-check:var(--color-white)]/50 dark:group-data-checked:group-data-disabled:after:hidden",
|
|
756
|
+
// Forced colors mode
|
|
757
|
+
"forced-colors:[--checkbox-check:HighlightText] forced-colors:[--checkbox-checked-bg:Highlight] forced-colors:group-data-disabled:[--checkbox-check:Highlight]",
|
|
758
|
+
"dark:forced-colors:[--checkbox-check:HighlightText] dark:forced-colors:[--checkbox-checked-bg:Highlight] dark:forced-colors:group-data-disabled:[--checkbox-check:Highlight]"
|
|
759
|
+
];
|
|
760
|
+
const colors = {
|
|
761
|
+
"dark/zinc": [
|
|
762
|
+
"[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-900)] [--checkbox-checked-border:var(--color-zinc-950)]/90",
|
|
763
|
+
"dark:[--checkbox-checked-bg:var(--color-zinc-600)]"
|
|
764
|
+
],
|
|
765
|
+
"dark/white": [
|
|
766
|
+
"[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-900)] [--checkbox-checked-border:var(--color-zinc-950)]/90",
|
|
767
|
+
"dark:[--checkbox-check:var(--color-zinc-900)] dark:[--checkbox-checked-bg:var(--color-white)] dark:[--checkbox-checked-border:var(--color-zinc-950)]/15"
|
|
768
|
+
],
|
|
769
|
+
white: "[--checkbox-check:var(--color-zinc-900)] [--checkbox-checked-bg:var(--color-white)] [--checkbox-checked-border:var(--color-zinc-950)]/15",
|
|
770
|
+
dark: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-900)] [--checkbox-checked-border:var(--color-zinc-950)]/90",
|
|
771
|
+
zinc: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-600)] [--checkbox-checked-border:var(--color-zinc-700)]/90",
|
|
772
|
+
red: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-red-600)] [--checkbox-checked-border:var(--color-red-700)]/90",
|
|
773
|
+
orange: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-orange-500)] [--checkbox-checked-border:var(--color-orange-600)]/90",
|
|
774
|
+
amber: "[--checkbox-check:var(--color-amber-950)] [--checkbox-checked-bg:var(--color-amber-400)] [--checkbox-checked-border:var(--color-amber-500)]/80",
|
|
775
|
+
yellow: "[--checkbox-check:var(--color-yellow-950)] [--checkbox-checked-bg:var(--color-yellow-300)] [--checkbox-checked-border:var(--color-yellow-400)]/80",
|
|
776
|
+
lime: "[--checkbox-check:var(--color-lime-950)] [--checkbox-checked-bg:var(--color-lime-300)] [--checkbox-checked-border:var(--color-lime-400)]/80",
|
|
777
|
+
green: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-green-600)] [--checkbox-checked-border:var(--color-green-700)]/90",
|
|
778
|
+
emerald: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-emerald-600)] [--checkbox-checked-border:var(--color-emerald-700)]/90",
|
|
779
|
+
teal: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-teal-600)] [--checkbox-checked-border:var(--color-teal-700)]/90",
|
|
780
|
+
cyan: "[--checkbox-check:var(--color-cyan-950)] [--checkbox-checked-bg:var(--color-cyan-300)] [--checkbox-checked-border:var(--color-cyan-400)]/80",
|
|
781
|
+
sky: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-sky-500)] [--checkbox-checked-border:var(--color-sky-600)]/80",
|
|
782
|
+
blue: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-blue-600)] [--checkbox-checked-border:var(--color-blue-700)]/90",
|
|
783
|
+
indigo: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-indigo-500)] [--checkbox-checked-border:var(--color-indigo-600)]/90",
|
|
784
|
+
violet: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-violet-500)] [--checkbox-checked-border:var(--color-violet-600)]/90",
|
|
785
|
+
purple: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-purple-500)] [--checkbox-checked-border:var(--color-purple-600)]/90",
|
|
786
|
+
fuchsia: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-fuchsia-500)] [--checkbox-checked-border:var(--color-fuchsia-600)]/90",
|
|
787
|
+
pink: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-pink-500)] [--checkbox-checked-border:var(--color-pink-600)]/90",
|
|
788
|
+
rose: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-rose-500)] [--checkbox-checked-border:var(--color-rose-600)]/90"
|
|
789
|
+
};
|
|
790
|
+
function Checkbox({
|
|
791
|
+
color = "dark/zinc",
|
|
792
|
+
className,
|
|
793
|
+
checked: controlledChecked,
|
|
794
|
+
defaultChecked,
|
|
795
|
+
onChange,
|
|
796
|
+
disabled,
|
|
797
|
+
indeterminate,
|
|
798
|
+
name,
|
|
799
|
+
value,
|
|
800
|
+
...props
|
|
801
|
+
}) {
|
|
802
|
+
const { checked, toggleProps } = useToggle({
|
|
803
|
+
checked: controlledChecked,
|
|
804
|
+
defaultChecked,
|
|
805
|
+
onChange,
|
|
806
|
+
disabled
|
|
807
|
+
});
|
|
808
|
+
const interactiveProps = useDataInteractive({ disabled });
|
|
809
|
+
const handleKeyDown = useCallback(
|
|
810
|
+
(e) => {
|
|
811
|
+
if (e.key === " ") {
|
|
812
|
+
e.preventDefault();
|
|
813
|
+
toggleProps.onKeyDown(e);
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
[toggleProps]
|
|
817
|
+
);
|
|
818
|
+
return /* @__PURE__ */ jsxs(
|
|
819
|
+
"span",
|
|
820
|
+
{
|
|
821
|
+
"data-slot": "control",
|
|
822
|
+
role: "checkbox",
|
|
823
|
+
"aria-checked": indeterminate ? "mixed" : checked,
|
|
824
|
+
"data-checked": checked ? "" : void 0,
|
|
825
|
+
"data-indeterminate": indeterminate ? "" : void 0,
|
|
826
|
+
"data-disabled": disabled ? "" : void 0,
|
|
827
|
+
tabIndex: disabled ? void 0 : 0,
|
|
828
|
+
onClick: disabled ? void 0 : toggleProps.onClick,
|
|
829
|
+
onKeyDown: disabled ? void 0 : handleKeyDown,
|
|
830
|
+
...interactiveProps,
|
|
831
|
+
...props,
|
|
832
|
+
className: clsx(className, "group inline-flex focus:outline-hidden"),
|
|
833
|
+
children: [
|
|
834
|
+
name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: checked ? value ?? "on" : "" }),
|
|
835
|
+
/* @__PURE__ */ jsx("span", { className: clsx([base, colors[color]]), children: /* @__PURE__ */ jsxs(
|
|
836
|
+
"svg",
|
|
837
|
+
{
|
|
838
|
+
className: "size-4 stroke-(--checkbox-check) opacity-0 group-data-checked:opacity-100 sm:h-3.5 sm:w-3.5",
|
|
839
|
+
viewBox: "0 0 14 14",
|
|
840
|
+
fill: "none",
|
|
841
|
+
children: [
|
|
842
|
+
/* @__PURE__ */ jsx("title", { children: "Checkmark" }),
|
|
843
|
+
/* @__PURE__ */ jsx(
|
|
844
|
+
"path",
|
|
845
|
+
{
|
|
846
|
+
className: "opacity-100 group-data-indeterminate:opacity-0",
|
|
847
|
+
d: "M3 8L6 11L11 3.5",
|
|
848
|
+
strokeWidth: 2,
|
|
849
|
+
strokeLinecap: "round",
|
|
850
|
+
strokeLinejoin: "round"
|
|
851
|
+
}
|
|
852
|
+
),
|
|
853
|
+
/* @__PURE__ */ jsx(
|
|
854
|
+
"path",
|
|
855
|
+
{
|
|
856
|
+
className: "opacity-0 group-data-indeterminate:opacity-100",
|
|
857
|
+
d: "M3 7H11",
|
|
858
|
+
strokeWidth: 2,
|
|
859
|
+
strokeLinecap: "round",
|
|
860
|
+
strokeLinejoin: "round"
|
|
861
|
+
}
|
|
862
|
+
)
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
) })
|
|
866
|
+
]
|
|
867
|
+
}
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
function CodeBlock({
|
|
871
|
+
code,
|
|
872
|
+
language,
|
|
873
|
+
filename,
|
|
874
|
+
showCopy = true,
|
|
875
|
+
className
|
|
876
|
+
}) {
|
|
877
|
+
const [copied, setCopied] = useState(false);
|
|
878
|
+
const handleCopy = useCallback(async () => {
|
|
879
|
+
await navigator.clipboard.writeText(code);
|
|
880
|
+
setCopied(true);
|
|
881
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
882
|
+
}, [code]);
|
|
883
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("overflow-hidden rounded-xl bg-zinc-950 ring-1 ring-zinc-800", className), children: [
|
|
884
|
+
(filename || language || showCopy) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-zinc-800 px-4 py-2.5", children: [
|
|
885
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
886
|
+
filename && /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-400", children: filename }),
|
|
887
|
+
language && !filename && /* @__PURE__ */ jsx("span", { className: "rounded bg-zinc-800 px-1.5 py-0.5 text-xs text-zinc-400", children: language })
|
|
888
|
+
] }),
|
|
889
|
+
showCopy && /* @__PURE__ */ jsx(
|
|
890
|
+
"button",
|
|
891
|
+
{
|
|
892
|
+
type: "button",
|
|
893
|
+
onClick: handleCopy,
|
|
894
|
+
"aria-label": copied ? "Copied" : "Copy code",
|
|
895
|
+
className: "rounded px-2 py-1 text-xs text-zinc-400 transition-colors hover:bg-zinc-800 hover:text-zinc-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",
|
|
896
|
+
children: copied ? "Copied!" : "Copy"
|
|
897
|
+
}
|
|
898
|
+
)
|
|
899
|
+
] }),
|
|
900
|
+
/* @__PURE__ */ jsx("pre", { className: "overflow-x-auto p-4 text-sm leading-relaxed text-zinc-300", children: /* @__PURE__ */ jsx("code", { children: code }) })
|
|
901
|
+
] });
|
|
902
|
+
}
|
|
903
|
+
function useEscapeKey(onEscape, enabled = true) {
|
|
904
|
+
const callbackRef = useRef(onEscape);
|
|
905
|
+
callbackRef.current = onEscape;
|
|
906
|
+
useEffect(() => {
|
|
907
|
+
if (!enabled) return;
|
|
908
|
+
function handleKeyDown(e) {
|
|
909
|
+
if (e.key === "Escape") {
|
|
910
|
+
e.stopPropagation();
|
|
911
|
+
callbackRef.current();
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
915
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
916
|
+
}, [enabled]);
|
|
917
|
+
}
|
|
918
|
+
const FOCUSABLE_SELECTOR = [
|
|
919
|
+
"a[href]",
|
|
920
|
+
"button:not([disabled])",
|
|
921
|
+
'input:not([disabled]):not([type="hidden"])',
|
|
922
|
+
"textarea:not([disabled])",
|
|
923
|
+
"select:not([disabled])",
|
|
924
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
925
|
+
].join(", ");
|
|
926
|
+
function getFocusableElements(container) {
|
|
927
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
928
|
+
}
|
|
929
|
+
function useFocusTrap(containerRef, enabled = true) {
|
|
930
|
+
useEffect(() => {
|
|
931
|
+
if (!enabled) return;
|
|
932
|
+
const container = containerRef.current;
|
|
933
|
+
if (!container) return;
|
|
934
|
+
const previouslyFocused = document.activeElement;
|
|
935
|
+
const focusableElements = getFocusableElements(container);
|
|
936
|
+
if (focusableElements.length > 0) {
|
|
937
|
+
focusableElements[0]?.focus();
|
|
938
|
+
} else {
|
|
939
|
+
container.setAttribute("tabindex", "-1");
|
|
940
|
+
container.focus();
|
|
941
|
+
}
|
|
942
|
+
function handleKeyDown(e) {
|
|
943
|
+
if (e.key !== "Tab" || !container) return;
|
|
944
|
+
const focusable = getFocusableElements(container);
|
|
945
|
+
if (focusable.length === 0) {
|
|
946
|
+
e.preventDefault();
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
const first = focusable[0];
|
|
950
|
+
const last = focusable[focusable.length - 1];
|
|
951
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
952
|
+
e.preventDefault();
|
|
953
|
+
last?.focus();
|
|
954
|
+
} else if (!e.shiftKey && document.activeElement === last) {
|
|
955
|
+
e.preventDefault();
|
|
956
|
+
first?.focus();
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
960
|
+
return () => {
|
|
961
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
962
|
+
previouslyFocused?.focus();
|
|
963
|
+
};
|
|
964
|
+
}, [containerRef, enabled]);
|
|
965
|
+
}
|
|
966
|
+
function useScrollLock(enabled = true) {
|
|
967
|
+
useEffect(() => {
|
|
968
|
+
if (!enabled) return;
|
|
969
|
+
const originalOverflow = document.body.style.overflow;
|
|
970
|
+
const originalPaddingRight = document.body.style.paddingRight;
|
|
971
|
+
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
972
|
+
document.body.style.overflow = "hidden";
|
|
973
|
+
if (scrollbarWidth > 0) {
|
|
974
|
+
document.body.style.paddingRight = `${scrollbarWidth}px`;
|
|
975
|
+
}
|
|
976
|
+
return () => {
|
|
977
|
+
document.body.style.overflow = originalOverflow;
|
|
978
|
+
document.body.style.paddingRight = originalPaddingRight;
|
|
979
|
+
};
|
|
980
|
+
}, [enabled]);
|
|
981
|
+
}
|
|
982
|
+
function useTransition(show) {
|
|
983
|
+
const nodeRef = useRef(null);
|
|
984
|
+
const [, setTick] = useState(0);
|
|
985
|
+
const rerender = useCallback(() => setTick((t) => t + 1), []);
|
|
986
|
+
const phase = useRef(
|
|
987
|
+
show ? "visible" : "hidden"
|
|
988
|
+
);
|
|
989
|
+
const prevShow = useRef(show);
|
|
990
|
+
const cleanupRef = useRef(null);
|
|
991
|
+
useEffect(() => {
|
|
992
|
+
cleanupRef.current?.();
|
|
993
|
+
cleanupRef.current = null;
|
|
994
|
+
if (show && !prevShow.current) {
|
|
995
|
+
phase.current = "enter-from";
|
|
996
|
+
rerender();
|
|
997
|
+
const frame1 = requestAnimationFrame(() => {
|
|
998
|
+
const frame2 = requestAnimationFrame(() => {
|
|
999
|
+
if (phase.current !== "enter-from") return;
|
|
1000
|
+
phase.current = "enter-to";
|
|
1001
|
+
rerender();
|
|
1002
|
+
const node = nodeRef.current;
|
|
1003
|
+
if (!node) {
|
|
1004
|
+
phase.current = "visible";
|
|
1005
|
+
rerender();
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
let cleaned = false;
|
|
1009
|
+
const done = () => {
|
|
1010
|
+
if (cleaned) return;
|
|
1011
|
+
cleaned = true;
|
|
1012
|
+
phase.current = "visible";
|
|
1013
|
+
rerender();
|
|
1014
|
+
};
|
|
1015
|
+
node.addEventListener("transitionend", done, { once: true });
|
|
1016
|
+
const fallback = setTimeout(done, 500);
|
|
1017
|
+
cleanupRef.current = () => {
|
|
1018
|
+
cleaned = true;
|
|
1019
|
+
node.removeEventListener("transitionend", done);
|
|
1020
|
+
clearTimeout(fallback);
|
|
1021
|
+
};
|
|
1022
|
+
});
|
|
1023
|
+
cleanupRef.current = () => cancelAnimationFrame(frame2);
|
|
1024
|
+
});
|
|
1025
|
+
cleanupRef.current = () => cancelAnimationFrame(frame1);
|
|
1026
|
+
} else if (!show && prevShow.current) {
|
|
1027
|
+
phase.current = "leave";
|
|
1028
|
+
rerender();
|
|
1029
|
+
const node = nodeRef.current;
|
|
1030
|
+
if (!node) {
|
|
1031
|
+
phase.current = "hidden";
|
|
1032
|
+
rerender();
|
|
1033
|
+
prevShow.current = show;
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
let cleaned = false;
|
|
1037
|
+
const done = () => {
|
|
1038
|
+
if (cleaned) return;
|
|
1039
|
+
cleaned = true;
|
|
1040
|
+
phase.current = "hidden";
|
|
1041
|
+
rerender();
|
|
1042
|
+
};
|
|
1043
|
+
node.addEventListener("transitionend", done, { once: true });
|
|
1044
|
+
const fallback = setTimeout(done, 500);
|
|
1045
|
+
cleanupRef.current = () => {
|
|
1046
|
+
cleaned = true;
|
|
1047
|
+
node.removeEventListener("transitionend", done);
|
|
1048
|
+
clearTimeout(fallback);
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
prevShow.current = show;
|
|
1052
|
+
}, [show, rerender]);
|
|
1053
|
+
useEffect(() => {
|
|
1054
|
+
return () => {
|
|
1055
|
+
cleanupRef.current?.();
|
|
1056
|
+
};
|
|
1057
|
+
}, []);
|
|
1058
|
+
const p = phase.current;
|
|
1059
|
+
return {
|
|
1060
|
+
mounted: p !== "hidden",
|
|
1061
|
+
nodeRef,
|
|
1062
|
+
transitionProps: {
|
|
1063
|
+
"data-closed": p === "enter-from" || p === "leave" || p === "hidden" ? "" : void 0,
|
|
1064
|
+
"data-enter": p === "enter-from" || p === "enter-to" ? "" : void 0,
|
|
1065
|
+
"data-leave": p === "leave" ? "" : void 0,
|
|
1066
|
+
"data-transition": p === "enter-from" || p === "enter-to" || p === "leave" ? "" : void 0
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
const sideClasses$1 = {
|
|
1071
|
+
left: "inset-y-0 left-0 h-full w-full max-w-sm data-closed:-translate-x-full",
|
|
1072
|
+
right: "inset-y-0 right-0 h-full w-full max-w-sm data-closed:translate-x-full",
|
|
1073
|
+
top: "inset-x-0 top-0 w-full max-h-[50vh] data-closed:-translate-y-full",
|
|
1074
|
+
bottom: "inset-x-0 bottom-0 w-full max-h-[50vh] data-closed:translate-y-full"
|
|
1075
|
+
};
|
|
1076
|
+
function Drawer({
|
|
1077
|
+
open,
|
|
1078
|
+
onClose,
|
|
1079
|
+
side = "right",
|
|
1080
|
+
className,
|
|
1081
|
+
children
|
|
1082
|
+
}) {
|
|
1083
|
+
const panelRef = useRef(null);
|
|
1084
|
+
const titleId = useId();
|
|
1085
|
+
const backdrop = useTransition(open);
|
|
1086
|
+
const panel = useTransition(open);
|
|
1087
|
+
useScrollLock(open);
|
|
1088
|
+
useFocusTrap(panelRef, open);
|
|
1089
|
+
useEscapeKey(onClose, open);
|
|
1090
|
+
const handleBackdropClick = useCallback(
|
|
1091
|
+
(e) => {
|
|
1092
|
+
if (e.target === e.currentTarget) onClose();
|
|
1093
|
+
},
|
|
1094
|
+
[onClose]
|
|
1095
|
+
);
|
|
1096
|
+
if (!(backdrop.mounted || panel.mounted)) return null;
|
|
1097
|
+
return createPortal(
|
|
1098
|
+
/* @__PURE__ */ jsxs("div", { role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [
|
|
1099
|
+
backdrop.mounted && /* @__PURE__ */ jsx(
|
|
1100
|
+
"div",
|
|
1101
|
+
{
|
|
1102
|
+
ref: backdrop.nodeRef,
|
|
1103
|
+
...backdrop.transitionProps,
|
|
1104
|
+
onClick: handleBackdropClick,
|
|
1105
|
+
className: "fixed inset-0 z-40 bg-zinc-950/25 transition duration-200 data-closed:opacity-0 data-enter:ease-out data-leave:ease-in dark:bg-zinc-950/50"
|
|
1106
|
+
}
|
|
1107
|
+
),
|
|
1108
|
+
panel.mounted && /* @__PURE__ */ jsx(
|
|
1109
|
+
"div",
|
|
1110
|
+
{
|
|
1111
|
+
ref: (node) => {
|
|
1112
|
+
panelRef.current = node;
|
|
1113
|
+
panel.nodeRef.current = node;
|
|
1114
|
+
},
|
|
1115
|
+
...panel.transitionProps,
|
|
1116
|
+
className: clsx(
|
|
1117
|
+
"fixed z-50 overflow-y-auto bg-white shadow-xl ring-1 ring-zinc-950/10 transition duration-300 ease-in-out dark:bg-zinc-900 dark:ring-white/10",
|
|
1118
|
+
sideClasses$1[side],
|
|
1119
|
+
className
|
|
1120
|
+
),
|
|
1121
|
+
children
|
|
1122
|
+
}
|
|
1123
|
+
)
|
|
1124
|
+
] }),
|
|
1125
|
+
document.body
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
function DrawerHeader({
|
|
1129
|
+
onClose,
|
|
1130
|
+
className,
|
|
1131
|
+
children
|
|
1132
|
+
}) {
|
|
1133
|
+
return /* @__PURE__ */ jsxs(
|
|
1134
|
+
"div",
|
|
1135
|
+
{
|
|
1136
|
+
className: clsx(
|
|
1137
|
+
"flex items-center justify-between border-b border-zinc-200 px-6 py-4 dark:border-zinc-700",
|
|
1138
|
+
className
|
|
1139
|
+
),
|
|
1140
|
+
children: [
|
|
1141
|
+
/* @__PURE__ */ jsx("div", { className: "text-base font-semibold text-zinc-950 dark:text-white", children }),
|
|
1142
|
+
onClose && /* @__PURE__ */ jsx(
|
|
1143
|
+
"button",
|
|
1144
|
+
{
|
|
1145
|
+
type: "button",
|
|
1146
|
+
"aria-label": "Close drawer",
|
|
1147
|
+
onClick: onClose,
|
|
1148
|
+
className: "rounded-md p-1 text-zinc-400 hover:text-zinc-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:hover:text-zinc-200",
|
|
1149
|
+
children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", className: "size-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
|
|
1150
|
+
"path",
|
|
1151
|
+
{
|
|
1152
|
+
d: "M4 4l8 8M12 4l-8 8",
|
|
1153
|
+
stroke: "currentColor",
|
|
1154
|
+
strokeWidth: "1.5",
|
|
1155
|
+
strokeLinecap: "round"
|
|
1156
|
+
}
|
|
1157
|
+
) })
|
|
1158
|
+
}
|
|
1159
|
+
)
|
|
1160
|
+
]
|
|
1161
|
+
}
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
function DrawerBody({ className, ...props }) {
|
|
1165
|
+
return /* @__PURE__ */ jsx("div", { ...props, className: clsx("px-6 py-4", className) });
|
|
1166
|
+
}
|
|
1167
|
+
function DrawerFooter({ className, ...props }) {
|
|
1168
|
+
return /* @__PURE__ */ jsx(
|
|
1169
|
+
"div",
|
|
1170
|
+
{
|
|
1171
|
+
...props,
|
|
1172
|
+
className: clsx(
|
|
1173
|
+
"flex items-center justify-end gap-3 border-t border-zinc-200 px-6 py-4 dark:border-zinc-700",
|
|
1174
|
+
className
|
|
1175
|
+
)
|
|
1176
|
+
}
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
function EmptyState({
|
|
1180
|
+
icon,
|
|
1181
|
+
title,
|
|
1182
|
+
description,
|
|
1183
|
+
action,
|
|
1184
|
+
className
|
|
1185
|
+
}) {
|
|
1186
|
+
return /* @__PURE__ */ jsxs(
|
|
1187
|
+
"div",
|
|
1188
|
+
{
|
|
1189
|
+
className: clsx(
|
|
1190
|
+
"flex flex-col items-center justify-center rounded-xl border border-dashed border-zinc-300 px-6 py-16 text-center dark:border-zinc-700",
|
|
1191
|
+
className
|
|
1192
|
+
),
|
|
1193
|
+
children: [
|
|
1194
|
+
icon && /* @__PURE__ */ jsx("div", { className: "mb-4 flex size-12 items-center justify-center rounded-full bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400", children: icon }),
|
|
1195
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: title }),
|
|
1196
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-sm text-sm text-zinc-500 dark:text-zinc-400", children: description }),
|
|
1197
|
+
action && /* @__PURE__ */ jsx("div", { className: "mt-6", children: action })
|
|
1198
|
+
]
|
|
1199
|
+
}
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
function InputGroup({ children }) {
|
|
1203
|
+
return /* @__PURE__ */ jsx(
|
|
1204
|
+
"span",
|
|
1205
|
+
{
|
|
1206
|
+
"data-slot": "control",
|
|
1207
|
+
className: clsx(
|
|
1208
|
+
"relative isolate block",
|
|
1209
|
+
"has-[[data-slot=icon]:first-child]:[&_input]:pl-10 has-[[data-slot=icon]:last-child]:[&_input]:pr-10 sm:has-[[data-slot=icon]:first-child]:[&_input]:pl-8 sm:has-[[data-slot=icon]:last-child]:[&_input]:pr-8",
|
|
1210
|
+
"*:data-[slot=icon]:pointer-events-none *:data-[slot=icon]:absolute *:data-[slot=icon]:top-3 *:data-[slot=icon]:z-10 *:data-[slot=icon]:size-5 sm:*:data-[slot=icon]:top-2.5 sm:*:data-[slot=icon]:size-4",
|
|
1211
|
+
"[&>[data-slot=icon]:first-child]:left-3 sm:[&>[data-slot=icon]:first-child]:left-2.5 [&>[data-slot=icon]:last-child]:right-3 sm:[&>[data-slot=icon]:last-child]:right-2.5",
|
|
1212
|
+
"*:data-[slot=icon]:text-zinc-500 dark:*:data-[slot=icon]:text-zinc-400"
|
|
1213
|
+
),
|
|
1214
|
+
children
|
|
1215
|
+
}
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
const dateTypes = ["date", "datetime-local", "month", "time", "week"];
|
|
1219
|
+
const Input = forwardRef(function Input2({ className, disabled, invalid, ...props }, ref) {
|
|
1220
|
+
const interactiveProps = useDataInteractive({ disabled });
|
|
1221
|
+
const fieldProps = useFieldControlProps();
|
|
1222
|
+
return /* @__PURE__ */ jsx(
|
|
1223
|
+
"span",
|
|
1224
|
+
{
|
|
1225
|
+
"data-slot": "control",
|
|
1226
|
+
className: clsx([
|
|
1227
|
+
className,
|
|
1228
|
+
// Basic layout
|
|
1229
|
+
"relative block w-full",
|
|
1230
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
1231
|
+
"before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm",
|
|
1232
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
1233
|
+
"dark:before:hidden",
|
|
1234
|
+
// Focus ring
|
|
1235
|
+
"after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500",
|
|
1236
|
+
// Disabled state
|
|
1237
|
+
"has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none"
|
|
1238
|
+
]),
|
|
1239
|
+
children: /* @__PURE__ */ jsx(
|
|
1240
|
+
"input",
|
|
1241
|
+
{
|
|
1242
|
+
ref,
|
|
1243
|
+
disabled,
|
|
1244
|
+
...props,
|
|
1245
|
+
...interactiveProps,
|
|
1246
|
+
...fieldProps,
|
|
1247
|
+
"data-invalid": invalid ? "" : void 0,
|
|
1248
|
+
"data-disabled": disabled ? "" : void 0,
|
|
1249
|
+
className: clsx([
|
|
1250
|
+
// Date classes
|
|
1251
|
+
props.type && dateTypes.includes(props.type) && [
|
|
1252
|
+
"[&::-webkit-datetime-edit-fields-wrapper]:p-0",
|
|
1253
|
+
"[&::-webkit-date-and-time-value]:min-h-[1.5em]",
|
|
1254
|
+
"[&::-webkit-datetime-edit]:inline-flex",
|
|
1255
|
+
"[&::-webkit-datetime-edit]:p-0",
|
|
1256
|
+
"[&::-webkit-datetime-edit-year-field]:p-0",
|
|
1257
|
+
"[&::-webkit-datetime-edit-month-field]:p-0",
|
|
1258
|
+
"[&::-webkit-datetime-edit-day-field]:p-0",
|
|
1259
|
+
"[&::-webkit-datetime-edit-hour-field]:p-0",
|
|
1260
|
+
"[&::-webkit-datetime-edit-minute-field]:p-0",
|
|
1261
|
+
"[&::-webkit-datetime-edit-second-field]:p-0",
|
|
1262
|
+
"[&::-webkit-datetime-edit-millisecond-field]:p-0",
|
|
1263
|
+
"[&::-webkit-datetime-edit-meridiem-field]:p-0"
|
|
1264
|
+
],
|
|
1265
|
+
// Basic layout
|
|
1266
|
+
"relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)]",
|
|
1267
|
+
// Typography
|
|
1268
|
+
"text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white",
|
|
1269
|
+
// Border
|
|
1270
|
+
"border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20",
|
|
1271
|
+
// Background color
|
|
1272
|
+
"bg-transparent dark:bg-white/5",
|
|
1273
|
+
// Hide default focus styles
|
|
1274
|
+
"focus:outline-hidden",
|
|
1275
|
+
// Invalid state
|
|
1276
|
+
"data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-600 dark:data-invalid:data-hover:border-red-600",
|
|
1277
|
+
// Disabled state
|
|
1278
|
+
"data-disabled:border-zinc-950/20 dark:data-disabled:border-white/15 dark:data-disabled:bg-white/2.5 dark:data-hover:data-disabled:border-white/15",
|
|
1279
|
+
// System icons
|
|
1280
|
+
"dark:scheme-dark"
|
|
1281
|
+
])
|
|
1282
|
+
}
|
|
1283
|
+
)
|
|
1284
|
+
}
|
|
1285
|
+
);
|
|
1286
|
+
});
|
|
1287
|
+
function Kbd({ className, children, ...props }) {
|
|
1288
|
+
return /* @__PURE__ */ jsx(
|
|
1289
|
+
"kbd",
|
|
1290
|
+
{
|
|
1291
|
+
...props,
|
|
1292
|
+
className: clsx(
|
|
1293
|
+
"inline-flex items-center rounded border border-zinc-300 bg-zinc-100 px-1.5 py-0.5 font-mono text-xs font-medium text-zinc-700 dark:border-zinc-600 dark:bg-zinc-800 dark:text-zinc-300",
|
|
1294
|
+
className
|
|
1295
|
+
),
|
|
1296
|
+
children
|
|
1297
|
+
}
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
function KbdShortcut({
|
|
1301
|
+
keys,
|
|
1302
|
+
separator = "+",
|
|
1303
|
+
className
|
|
1304
|
+
}) {
|
|
1305
|
+
return /* @__PURE__ */ jsx("span", { className: clsx("inline-flex items-center gap-1", className), children: keys.map((key, i) => (
|
|
1306
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: keyboard shortcut keys are positionally ordered with no stable ID
|
|
1307
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
1308
|
+
/* @__PURE__ */ jsx(Kbd, { children: key }),
|
|
1309
|
+
i < keys.length - 1 && /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-400", children: separator })
|
|
1310
|
+
] }, i)
|
|
1311
|
+
)) });
|
|
1312
|
+
}
|
|
1313
|
+
const trackClasses = {
|
|
1314
|
+
blue: "bg-blue-600 dark:bg-blue-500",
|
|
1315
|
+
green: "bg-green-600 dark:bg-green-500",
|
|
1316
|
+
red: "bg-red-600 dark:bg-red-500",
|
|
1317
|
+
amber: "bg-amber-500 dark:bg-amber-400",
|
|
1318
|
+
violet: "bg-violet-600 dark:bg-violet-500",
|
|
1319
|
+
zinc: "bg-zinc-600 dark:bg-zinc-400"
|
|
1320
|
+
};
|
|
1321
|
+
function Progress({
|
|
1322
|
+
value,
|
|
1323
|
+
max = 100,
|
|
1324
|
+
color = "blue",
|
|
1325
|
+
size = "md",
|
|
1326
|
+
label,
|
|
1327
|
+
showValue = false,
|
|
1328
|
+
className
|
|
1329
|
+
}) {
|
|
1330
|
+
const percentage = Math.min(100, Math.max(0, value / max * 100));
|
|
1331
|
+
const heightClass = { xs: "h-1", sm: "h-1.5", md: "h-2.5", lg: "h-4" }[size];
|
|
1332
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("w-full", className), children: [
|
|
1333
|
+
(label || showValue) && /* @__PURE__ */ jsxs("div", { className: "mb-1.5 flex items-center justify-between", children: [
|
|
1334
|
+
label && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: label }),
|
|
1335
|
+
showValue && /* @__PURE__ */ jsxs("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: [
|
|
1336
|
+
Math.round(percentage),
|
|
1337
|
+
"%"
|
|
1338
|
+
] })
|
|
1339
|
+
] }),
|
|
1340
|
+
/* @__PURE__ */ jsx(
|
|
1341
|
+
"div",
|
|
1342
|
+
{
|
|
1343
|
+
role: "progressbar",
|
|
1344
|
+
"aria-valuenow": value,
|
|
1345
|
+
"aria-valuemin": 0,
|
|
1346
|
+
"aria-valuemax": max,
|
|
1347
|
+
"aria-label": label,
|
|
1348
|
+
className: clsx(
|
|
1349
|
+
"w-full overflow-hidden rounded-full bg-zinc-200 dark:bg-zinc-700",
|
|
1350
|
+
heightClass
|
|
1351
|
+
),
|
|
1352
|
+
children: /* @__PURE__ */ jsx(
|
|
1353
|
+
"div",
|
|
1354
|
+
{
|
|
1355
|
+
className: clsx(
|
|
1356
|
+
"h-full rounded-full transition-all duration-300 ease-in-out",
|
|
1357
|
+
trackClasses[color]
|
|
1358
|
+
),
|
|
1359
|
+
style: { width: `${percentage}%` }
|
|
1360
|
+
}
|
|
1361
|
+
)
|
|
1362
|
+
}
|
|
1363
|
+
)
|
|
1364
|
+
] });
|
|
1365
|
+
}
|
|
1366
|
+
function Rating({
|
|
1367
|
+
value: controlledValue,
|
|
1368
|
+
defaultValue = 0,
|
|
1369
|
+
max = 5,
|
|
1370
|
+
onChange,
|
|
1371
|
+
readOnly = false,
|
|
1372
|
+
size = "md",
|
|
1373
|
+
label,
|
|
1374
|
+
className
|
|
1375
|
+
}) {
|
|
1376
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
1377
|
+
const [hovered, setHovered] = useState(0);
|
|
1378
|
+
const id = useId();
|
|
1379
|
+
const value = controlledValue ?? internalValue;
|
|
1380
|
+
const sizeClass = { sm: "size-4", md: "size-6", lg: "size-8" }[size];
|
|
1381
|
+
const handleClick = useCallback(
|
|
1382
|
+
(star) => {
|
|
1383
|
+
if (readOnly) return;
|
|
1384
|
+
setInternalValue(star);
|
|
1385
|
+
onChange?.(star);
|
|
1386
|
+
},
|
|
1387
|
+
[readOnly, onChange]
|
|
1388
|
+
);
|
|
1389
|
+
const display = hovered > 0 ? hovered : value;
|
|
1390
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
1391
|
+
label && /* @__PURE__ */ jsx("span", { id, className: "sr-only", children: label }),
|
|
1392
|
+
/* @__PURE__ */ jsx(
|
|
1393
|
+
"div",
|
|
1394
|
+
{
|
|
1395
|
+
role: readOnly ? "img" : "radiogroup",
|
|
1396
|
+
"aria-label": label ?? `Rating: ${value} out of ${max}`,
|
|
1397
|
+
"aria-labelledby": label ? id : void 0,
|
|
1398
|
+
className: "flex items-center gap-0.5",
|
|
1399
|
+
children: Array.from({ length: max }).map((_, i) => {
|
|
1400
|
+
const star = i + 1;
|
|
1401
|
+
const filled = star <= display;
|
|
1402
|
+
return (
|
|
1403
|
+
// biome-ignore lint/a11y/useAriaPropsSupportedByRole: aria-checked and aria-label are valid on role="radio" per WAI-ARIA spec
|
|
1404
|
+
/* @__PURE__ */ jsx(
|
|
1405
|
+
"button",
|
|
1406
|
+
{
|
|
1407
|
+
type: "button",
|
|
1408
|
+
role: readOnly ? void 0 : "radio",
|
|
1409
|
+
"aria-checked": readOnly ? void 0 : value === star,
|
|
1410
|
+
"aria-label": readOnly ? void 0 : `${star} star${star !== 1 ? "s" : ""}`,
|
|
1411
|
+
disabled: readOnly,
|
|
1412
|
+
onClick: () => handleClick(star),
|
|
1413
|
+
onMouseEnter: () => !readOnly && setHovered(star),
|
|
1414
|
+
onMouseLeave: () => !readOnly && setHovered(0),
|
|
1415
|
+
className: clsx(
|
|
1416
|
+
sizeClass,
|
|
1417
|
+
"transition-colors",
|
|
1418
|
+
readOnly ? "cursor-default" : "cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500"
|
|
1419
|
+
),
|
|
1420
|
+
children: /* @__PURE__ */ jsx(
|
|
1421
|
+
"svg",
|
|
1422
|
+
{
|
|
1423
|
+
viewBox: "0 0 20 20",
|
|
1424
|
+
"aria-hidden": "true",
|
|
1425
|
+
className: clsx(
|
|
1426
|
+
"size-full",
|
|
1427
|
+
filled ? "fill-amber-400 text-amber-400" : "fill-zinc-200 text-zinc-200 dark:fill-zinc-700 dark:text-zinc-700"
|
|
1428
|
+
),
|
|
1429
|
+
children: /* @__PURE__ */ jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
|
|
1430
|
+
}
|
|
1431
|
+
)
|
|
1432
|
+
},
|
|
1433
|
+
star
|
|
1434
|
+
)
|
|
1435
|
+
);
|
|
1436
|
+
})
|
|
1437
|
+
}
|
|
1438
|
+
)
|
|
1439
|
+
] });
|
|
1440
|
+
}
|
|
1441
|
+
const Check = ({ className }) => {
|
|
1442
|
+
return /* @__PURE__ */ jsxs(
|
|
1443
|
+
"svg",
|
|
1444
|
+
{
|
|
1445
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1446
|
+
fill: "none",
|
|
1447
|
+
viewBox: "0 0 24 24",
|
|
1448
|
+
strokeWidth: 1.5,
|
|
1449
|
+
stroke: "currentColor",
|
|
1450
|
+
className: cn("size-6", className),
|
|
1451
|
+
children: [
|
|
1452
|
+
/* @__PURE__ */ jsx("title", { children: "Selected" }),
|
|
1453
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 12l4 4L18 8" })
|
|
1454
|
+
]
|
|
1455
|
+
}
|
|
1456
|
+
);
|
|
1457
|
+
};
|
|
1458
|
+
const ChevronUp = ({ className }) => {
|
|
1459
|
+
return /* @__PURE__ */ jsxs(
|
|
1460
|
+
"svg",
|
|
1461
|
+
{
|
|
1462
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1463
|
+
fill: "none",
|
|
1464
|
+
viewBox: "0 0 24 24",
|
|
1465
|
+
strokeWidth: 1.5,
|
|
1466
|
+
stroke: "currentColor",
|
|
1467
|
+
className: cn("size-6", className),
|
|
1468
|
+
children: [
|
|
1469
|
+
/* @__PURE__ */ jsx("title", { children: "Scroll up" }),
|
|
1470
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 15.75l-7.5-7.5-7.5 7.5" })
|
|
1471
|
+
]
|
|
1472
|
+
}
|
|
1473
|
+
);
|
|
1474
|
+
};
|
|
1475
|
+
const ChevronDown = ({ className }) => {
|
|
1476
|
+
return /* @__PURE__ */ jsxs(
|
|
1477
|
+
"svg",
|
|
1478
|
+
{
|
|
1479
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1480
|
+
fill: "none",
|
|
1481
|
+
viewBox: "0 0 24 24",
|
|
1482
|
+
strokeWidth: 1.5,
|
|
1483
|
+
stroke: "currentColor",
|
|
1484
|
+
className: cn("size-6", className),
|
|
1485
|
+
children: [
|
|
1486
|
+
/* @__PURE__ */ jsx("title", { children: "Scroll down" }),
|
|
1487
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 8.25l7.5 7.5 7.5-7.5" })
|
|
1488
|
+
]
|
|
1489
|
+
}
|
|
1490
|
+
);
|
|
1491
|
+
};
|
|
1492
|
+
const Select$1 = React__default.forwardRef(
|
|
1493
|
+
({ children, className, ...props }, ref) => /* @__PURE__ */ jsx(Box, { ref, className: cn(className), ...props, children })
|
|
1494
|
+
);
|
|
1495
|
+
Select$1.displayName = "Select";
|
|
1496
|
+
const SelectGroup = React__default.forwardRef(
|
|
1497
|
+
({ children, className, ...props }, ref) => /* @__PURE__ */ jsx(Box, { ref, className: cn(className), ...props, children })
|
|
1498
|
+
);
|
|
1499
|
+
SelectGroup.displayName = "SelectGroup";
|
|
1500
|
+
const SelectValue = React__default.forwardRef(
|
|
1501
|
+
({ placeholder, children, value, ...props }, ref) => /* @__PURE__ */ jsx("span", { ref, ...props, children: children || placeholder || value })
|
|
1502
|
+
);
|
|
1503
|
+
SelectValue.displayName = "SelectValue";
|
|
1504
|
+
const SelectTrigger = React__default.forwardRef(
|
|
1505
|
+
({ children, className, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
1506
|
+
Box,
|
|
1507
|
+
{
|
|
1508
|
+
className: cn(
|
|
1509
|
+
"flex h-10 w-full items-center justify-between rounded border border-input bg-background px-3 py-2 text-inherit ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
|
1510
|
+
className
|
|
1511
|
+
),
|
|
1512
|
+
ref,
|
|
1513
|
+
...props,
|
|
1514
|
+
children: [
|
|
1515
|
+
children,
|
|
1516
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "size-4 opacity-50" })
|
|
1517
|
+
]
|
|
1518
|
+
}
|
|
1519
|
+
)
|
|
1520
|
+
);
|
|
1521
|
+
SelectTrigger.displayName = "SelectTrigger";
|
|
1522
|
+
const SelectScrollUpButton = React__default.forwardRef(
|
|
1523
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
1524
|
+
"button",
|
|
1525
|
+
{
|
|
1526
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
1527
|
+
ref,
|
|
1528
|
+
...props,
|
|
1529
|
+
children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-4" })
|
|
1530
|
+
}
|
|
1531
|
+
)
|
|
1532
|
+
);
|
|
1533
|
+
SelectScrollUpButton.displayName = "SelectScrollUpButton";
|
|
1534
|
+
const SelectScrollDownButton = React__default.forwardRef(
|
|
1535
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
1536
|
+
"button",
|
|
1537
|
+
{
|
|
1538
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
1539
|
+
ref,
|
|
1540
|
+
...props,
|
|
1541
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
|
|
1542
|
+
}
|
|
1543
|
+
)
|
|
1544
|
+
);
|
|
1545
|
+
SelectScrollDownButton.displayName = "SelectScrollDownButton";
|
|
1546
|
+
const SelectContent = React__default.forwardRef(
|
|
1547
|
+
({ children, className, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
1548
|
+
Box,
|
|
1549
|
+
{
|
|
1550
|
+
className: cn(
|
|
1551
|
+
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded border bg-card text-popover-foreground shadow-md",
|
|
1552
|
+
className
|
|
1553
|
+
),
|
|
1554
|
+
ref,
|
|
1555
|
+
...props,
|
|
1556
|
+
children: [
|
|
1557
|
+
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
1558
|
+
/* @__PURE__ */ jsx("div", { className: "p-1", children }),
|
|
1559
|
+
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
1560
|
+
]
|
|
1561
|
+
}
|
|
1562
|
+
)
|
|
1563
|
+
);
|
|
1564
|
+
SelectContent.displayName = "SelectContent";
|
|
1565
|
+
const SelectLabel = React__default.forwardRef(
|
|
1566
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className), ref, ...props })
|
|
1567
|
+
);
|
|
1568
|
+
SelectLabel.displayName = "SelectLabel";
|
|
1569
|
+
const SelectItem = React__default.forwardRef(
|
|
1570
|
+
({ children, className, value, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
1571
|
+
Box,
|
|
1572
|
+
{
|
|
1573
|
+
className: cn(
|
|
1574
|
+
"relative flex w-full cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
1575
|
+
className
|
|
1576
|
+
),
|
|
1577
|
+
"data-value": value,
|
|
1578
|
+
ref,
|
|
1579
|
+
...props,
|
|
1580
|
+
children: [
|
|
1581
|
+
/* @__PURE__ */ jsx("span", { className: "absolute left-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(Check, { className: "size-4" }) }),
|
|
1582
|
+
/* @__PURE__ */ jsx("span", { children })
|
|
1583
|
+
]
|
|
1584
|
+
}
|
|
1585
|
+
)
|
|
1586
|
+
);
|
|
1587
|
+
SelectItem.displayName = "SelectItem";
|
|
1588
|
+
const SelectSeparator = React__default.forwardRef(
|
|
1589
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(Box, { className: cn("-mx-1 my-1 h-px bg-muted", className), ref, ...props })
|
|
1590
|
+
);
|
|
1591
|
+
SelectSeparator.displayName = "SelectSeparator";
|
|
1592
|
+
const Select = forwardRef(function Select2({ className, multiple, disabled, invalid, ...props }, ref) {
|
|
1593
|
+
const interactiveProps = useDataInteractive({ disabled });
|
|
1594
|
+
const fieldProps = useFieldControlProps();
|
|
1595
|
+
return /* @__PURE__ */ jsxs(
|
|
1596
|
+
"span",
|
|
1597
|
+
{
|
|
1598
|
+
"data-slot": "control",
|
|
1599
|
+
className: clsx([
|
|
1600
|
+
className,
|
|
1601
|
+
// Basic layout
|
|
1602
|
+
"group relative block w-full",
|
|
1603
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
1604
|
+
"before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm",
|
|
1605
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
1606
|
+
"dark:before:hidden",
|
|
1607
|
+
// Focus ring
|
|
1608
|
+
"after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset has-data-focus:after:ring-2 has-data-focus:after:ring-blue-500",
|
|
1609
|
+
// Disabled state
|
|
1610
|
+
"has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none"
|
|
1611
|
+
]),
|
|
1612
|
+
children: [
|
|
1613
|
+
/* @__PURE__ */ jsx(
|
|
1614
|
+
"select",
|
|
1615
|
+
{
|
|
1616
|
+
ref,
|
|
1617
|
+
multiple,
|
|
1618
|
+
disabled,
|
|
1619
|
+
...props,
|
|
1620
|
+
...interactiveProps,
|
|
1621
|
+
...fieldProps,
|
|
1622
|
+
"data-invalid": invalid ? "" : void 0,
|
|
1623
|
+
"data-disabled": disabled ? "" : void 0,
|
|
1624
|
+
className: clsx([
|
|
1625
|
+
// Basic layout
|
|
1626
|
+
"relative block w-full appearance-none rounded-lg py-[calc(--spacing(2.5)-1px)] sm:py-[calc(--spacing(1.5)-1px)]",
|
|
1627
|
+
// Horizontal padding
|
|
1628
|
+
multiple ? "px-[calc(--spacing(3.5)-1px)] sm:px-[calc(--spacing(3)-1px)]" : "pr-[calc(--spacing(10)-1px)] pl-[calc(--spacing(3.5)-1px)] sm:pr-[calc(--spacing(9)-1px)] sm:pl-[calc(--spacing(3)-1px)]",
|
|
1629
|
+
// Options (multi-select)
|
|
1630
|
+
"[&_optgroup]:font-semibold",
|
|
1631
|
+
// Typography
|
|
1632
|
+
"text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white dark:*:text-white",
|
|
1633
|
+
// Border
|
|
1634
|
+
"border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20",
|
|
1635
|
+
// Background color
|
|
1636
|
+
"bg-transparent dark:bg-white/5 dark:*:bg-zinc-800",
|
|
1637
|
+
// Hide default focus styles
|
|
1638
|
+
"focus:outline-hidden",
|
|
1639
|
+
// Invalid state
|
|
1640
|
+
"data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-600 dark:data-invalid:data-hover:border-red-600",
|
|
1641
|
+
// Disabled state
|
|
1642
|
+
"data-disabled:border-zinc-950/20 data-disabled:opacity-100 dark:data-disabled:border-white/15 dark:data-disabled:bg-white/2.5 dark:data-hover:data-disabled:border-white/15"
|
|
1643
|
+
])
|
|
1644
|
+
}
|
|
1645
|
+
),
|
|
1646
|
+
!multiple && /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2", children: /* @__PURE__ */ jsxs(
|
|
1647
|
+
"svg",
|
|
1648
|
+
{
|
|
1649
|
+
className: "size-5 stroke-zinc-500 group-has-data-disabled:stroke-zinc-600 sm:size-4 dark:stroke-zinc-400 forced-colors:stroke-[CanvasText]",
|
|
1650
|
+
viewBox: "0 0 16 16",
|
|
1651
|
+
"aria-hidden": "true",
|
|
1652
|
+
fill: "none",
|
|
1653
|
+
children: [
|
|
1654
|
+
/* @__PURE__ */ jsx(
|
|
1655
|
+
"path",
|
|
1656
|
+
{
|
|
1657
|
+
d: "M5.75 10.75L8 13L10.25 10.75",
|
|
1658
|
+
strokeWidth: 1.5,
|
|
1659
|
+
strokeLinecap: "round",
|
|
1660
|
+
strokeLinejoin: "round"
|
|
1661
|
+
}
|
|
1662
|
+
),
|
|
1663
|
+
/* @__PURE__ */ jsx(
|
|
1664
|
+
"path",
|
|
1665
|
+
{
|
|
1666
|
+
d: "M10.25 5.25L8 3L5.75 5.25",
|
|
1667
|
+
strokeWidth: 1.5,
|
|
1668
|
+
strokeLinecap: "round",
|
|
1669
|
+
strokeLinejoin: "round"
|
|
1670
|
+
}
|
|
1671
|
+
)
|
|
1672
|
+
]
|
|
1673
|
+
}
|
|
1674
|
+
) })
|
|
1675
|
+
]
|
|
1676
|
+
}
|
|
1677
|
+
);
|
|
1678
|
+
});
|
|
1679
|
+
function Skeleton({ className, ...props }) {
|
|
1680
|
+
return /* @__PURE__ */ jsx(
|
|
1681
|
+
"div",
|
|
1682
|
+
{
|
|
1683
|
+
"aria-hidden": "true",
|
|
1684
|
+
...props,
|
|
1685
|
+
className: clsx("animate-pulse rounded-md bg-zinc-200 dark:bg-zinc-700", className)
|
|
1686
|
+
}
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
function SkeletonText({ lines = 3, className }) {
|
|
1690
|
+
return /* @__PURE__ */ jsx("div", { className: clsx("space-y-2", className), children: Array.from({ length: lines }).map((_, i) => {
|
|
1691
|
+
return /* @__PURE__ */ jsx(
|
|
1692
|
+
Skeleton,
|
|
1693
|
+
{
|
|
1694
|
+
className: clsx("h-4", i === lines - 1 && lines > 1 ? "w-4/5" : "w-full")
|
|
1695
|
+
},
|
|
1696
|
+
i
|
|
1697
|
+
);
|
|
1698
|
+
}) });
|
|
1699
|
+
}
|
|
1700
|
+
function SkeletonCard({ className }) {
|
|
1701
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("rounded-xl border border-zinc-200 p-4 dark:border-zinc-700", className), children: [
|
|
1702
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1703
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "size-10 rounded-full" }),
|
|
1704
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
1705
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/3" }),
|
|
1706
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-1/2" })
|
|
1707
|
+
] })
|
|
1708
|
+
] }),
|
|
1709
|
+
/* @__PURE__ */ jsx(SkeletonText, { lines: 3, className: "mt-4" })
|
|
1710
|
+
] });
|
|
1711
|
+
}
|
|
1712
|
+
function Slider({
|
|
1713
|
+
value: controlledValue,
|
|
1714
|
+
defaultValue = 0,
|
|
1715
|
+
min = 0,
|
|
1716
|
+
max = 100,
|
|
1717
|
+
step = 1,
|
|
1718
|
+
onChange,
|
|
1719
|
+
disabled = false,
|
|
1720
|
+
label,
|
|
1721
|
+
showValue = false,
|
|
1722
|
+
className
|
|
1723
|
+
}) {
|
|
1724
|
+
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
1725
|
+
const value = controlledValue ?? internalValue;
|
|
1726
|
+
const id = useId();
|
|
1727
|
+
const handleChange = useCallback(
|
|
1728
|
+
(e) => {
|
|
1729
|
+
const next = Number(e.target.value);
|
|
1730
|
+
setInternalValue(next);
|
|
1731
|
+
onChange?.(next);
|
|
1732
|
+
},
|
|
1733
|
+
[onChange]
|
|
1734
|
+
);
|
|
1735
|
+
const percentage = (value - min) / (max - min) * 100;
|
|
1736
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("w-full", className), children: [
|
|
1737
|
+
(label || showValue) && /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
|
|
1738
|
+
label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: label }),
|
|
1739
|
+
showValue && /* @__PURE__ */ jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: value })
|
|
1740
|
+
] }),
|
|
1741
|
+
/* @__PURE__ */ jsx(
|
|
1742
|
+
"input",
|
|
1743
|
+
{
|
|
1744
|
+
id,
|
|
1745
|
+
type: "range",
|
|
1746
|
+
min,
|
|
1747
|
+
max,
|
|
1748
|
+
step,
|
|
1749
|
+
value,
|
|
1750
|
+
disabled,
|
|
1751
|
+
onChange: handleChange,
|
|
1752
|
+
style: { "--slider-pct": `${percentage}%` },
|
|
1753
|
+
className: clsx(
|
|
1754
|
+
"h-2 w-full cursor-pointer appearance-none rounded-full outline-none",
|
|
1755
|
+
"bg-zinc-200 dark:bg-zinc-700",
|
|
1756
|
+
"[&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:appearance-none",
|
|
1757
|
+
"[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:shadow-sm",
|
|
1758
|
+
"[&::-webkit-slider-thumb]:ring-2 [&::-webkit-slider-thumb]:ring-white [&::-webkit-slider-thumb]:dark:ring-zinc-900",
|
|
1759
|
+
"[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:appearance-none",
|
|
1760
|
+
"[&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-none [&::-moz-range-thumb]:bg-blue-600",
|
|
1761
|
+
"focus-visible:[&::-webkit-slider-thumb]:outline-2 focus-visible:[&::-webkit-slider-thumb]:outline-offset-2 focus-visible:[&::-webkit-slider-thumb]:outline-blue-500",
|
|
1762
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
1763
|
+
)
|
|
1764
|
+
}
|
|
1765
|
+
)
|
|
1766
|
+
] });
|
|
1767
|
+
}
|
|
1768
|
+
function Stat({
|
|
1769
|
+
label,
|
|
1770
|
+
value,
|
|
1771
|
+
change,
|
|
1772
|
+
trend,
|
|
1773
|
+
description,
|
|
1774
|
+
icon,
|
|
1775
|
+
className
|
|
1776
|
+
}) {
|
|
1777
|
+
const trendColor = {
|
|
1778
|
+
up: "text-green-600 dark:text-green-400",
|
|
1779
|
+
down: "text-red-600 dark:text-red-400",
|
|
1780
|
+
neutral: "text-zinc-500 dark:text-zinc-400"
|
|
1781
|
+
};
|
|
1782
|
+
const trendArrow = { up: "↑", down: "↓", neutral: "→" };
|
|
1783
|
+
return /* @__PURE__ */ jsxs(
|
|
1784
|
+
"div",
|
|
1785
|
+
{
|
|
1786
|
+
className: clsx(
|
|
1787
|
+
"rounded-xl bg-white p-6 ring-1 ring-zinc-950/5 dark:bg-zinc-900 dark:ring-white/10",
|
|
1788
|
+
className
|
|
1789
|
+
),
|
|
1790
|
+
children: [
|
|
1791
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
1792
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-zinc-500 dark:text-zinc-400", children: label }),
|
|
1793
|
+
icon && /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-zinc-100 p-2 dark:bg-zinc-800", children: icon })
|
|
1794
|
+
] }),
|
|
1795
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-3xl font-semibold tracking-tight text-zinc-950 dark:text-white", children: value }),
|
|
1796
|
+
(change || description) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
1797
|
+
change && trend && /* @__PURE__ */ jsxs("span", { className: clsx("text-sm font-medium", trendColor[trend]), children: [
|
|
1798
|
+
trendArrow[trend],
|
|
1799
|
+
" ",
|
|
1800
|
+
change
|
|
1801
|
+
] }),
|
|
1802
|
+
description && /* @__PURE__ */ jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: description })
|
|
1803
|
+
] })
|
|
1804
|
+
]
|
|
1805
|
+
}
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
function StatGroup({
|
|
1809
|
+
className,
|
|
1810
|
+
children
|
|
1811
|
+
}) {
|
|
1812
|
+
return /* @__PURE__ */ jsx("div", { className: clsx("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4", className), children });
|
|
1813
|
+
}
|
|
1814
|
+
function Stepper({
|
|
1815
|
+
steps,
|
|
1816
|
+
orientation = "horizontal",
|
|
1817
|
+
className
|
|
1818
|
+
}) {
|
|
1819
|
+
return orientation === "vertical" ? /* @__PURE__ */ jsx(StepperVertical, { steps, className }) : /* @__PURE__ */ jsx(StepperHorizontal, { steps, className });
|
|
1820
|
+
}
|
|
1821
|
+
function StepIcon({ status }) {
|
|
1822
|
+
if (status === "complete") {
|
|
1823
|
+
return /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full bg-blue-600", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", className: "size-4 text-white", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
|
|
1824
|
+
"path",
|
|
1825
|
+
{
|
|
1826
|
+
d: "M3 8l3.5 3.5L13 4",
|
|
1827
|
+
stroke: "currentColor",
|
|
1828
|
+
strokeWidth: "2",
|
|
1829
|
+
strokeLinecap: "round",
|
|
1830
|
+
strokeLinejoin: "round"
|
|
1831
|
+
}
|
|
1832
|
+
) }) });
|
|
1833
|
+
}
|
|
1834
|
+
if (status === "current") {
|
|
1835
|
+
return /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full border-2 border-blue-600 bg-white dark:bg-zinc-900", children: /* @__PURE__ */ jsx("span", { className: "size-2.5 rounded-full bg-blue-600" }) });
|
|
1836
|
+
}
|
|
1837
|
+
return /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full border-2 border-zinc-300 bg-white dark:border-zinc-600 dark:bg-zinc-900", children: /* @__PURE__ */ jsx("span", { className: "size-2.5 rounded-full bg-transparent" }) });
|
|
1838
|
+
}
|
|
1839
|
+
function StepperHorizontal({ steps, className }) {
|
|
1840
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": "Progress", children: /* @__PURE__ */ jsx("ol", { className: clsx("flex items-center", className), children: steps.map((step, index) => {
|
|
1841
|
+
const isLast = index === steps.length - 1;
|
|
1842
|
+
return (
|
|
1843
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stepper steps are positionally ordered with no stable ID
|
|
1844
|
+
/* @__PURE__ */ jsxs("li", { className: clsx("flex items-center", !isLast && "flex-1"), children: [
|
|
1845
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1.5", children: [
|
|
1846
|
+
/* @__PURE__ */ jsx(StepIcon, { status: step.status }),
|
|
1847
|
+
/* @__PURE__ */ jsx(
|
|
1848
|
+
"span",
|
|
1849
|
+
{
|
|
1850
|
+
className: clsx(
|
|
1851
|
+
"text-xs font-medium",
|
|
1852
|
+
step.status === "current" ? "text-blue-600" : step.status === "complete" ? "text-zinc-950 dark:text-white" : "text-zinc-400 dark:text-zinc-500"
|
|
1853
|
+
),
|
|
1854
|
+
children: step.label
|
|
1855
|
+
}
|
|
1856
|
+
)
|
|
1857
|
+
] }),
|
|
1858
|
+
!isLast && /* @__PURE__ */ jsx(
|
|
1859
|
+
"div",
|
|
1860
|
+
{
|
|
1861
|
+
"aria-hidden": "true",
|
|
1862
|
+
className: clsx(
|
|
1863
|
+
"mx-3 h-px flex-1",
|
|
1864
|
+
step.status === "complete" ? "bg-blue-600" : "bg-zinc-200 dark:bg-zinc-700"
|
|
1865
|
+
)
|
|
1866
|
+
}
|
|
1867
|
+
)
|
|
1868
|
+
] }, index)
|
|
1869
|
+
);
|
|
1870
|
+
}) }) });
|
|
1871
|
+
}
|
|
1872
|
+
function StepperVertical({ steps, className }) {
|
|
1873
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": "Progress", children: /* @__PURE__ */ jsx("ol", { className: clsx("space-y-0", className), children: steps.map((step, index) => {
|
|
1874
|
+
const isLast = index === steps.length - 1;
|
|
1875
|
+
return (
|
|
1876
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stepper steps are positionally ordered with no stable ID
|
|
1877
|
+
/* @__PURE__ */ jsxs("li", { className: "relative flex gap-4", children: [
|
|
1878
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
1879
|
+
/* @__PURE__ */ jsx(StepIcon, { status: step.status }),
|
|
1880
|
+
!isLast && /* @__PURE__ */ jsx(
|
|
1881
|
+
"div",
|
|
1882
|
+
{
|
|
1883
|
+
"aria-hidden": "true",
|
|
1884
|
+
className: clsx(
|
|
1885
|
+
"w-px flex-1",
|
|
1886
|
+
step.status === "complete" ? "bg-blue-600" : "bg-zinc-200 dark:bg-zinc-700"
|
|
1887
|
+
)
|
|
1888
|
+
}
|
|
1889
|
+
)
|
|
1890
|
+
] }),
|
|
1891
|
+
/* @__PURE__ */ jsxs("div", { className: clsx("pb-6 pt-1", isLast && "pb-0"), children: [
|
|
1892
|
+
/* @__PURE__ */ jsx(
|
|
1893
|
+
"p",
|
|
1894
|
+
{
|
|
1895
|
+
className: clsx(
|
|
1896
|
+
"text-sm font-medium",
|
|
1897
|
+
step.status === "current" ? "text-blue-600" : step.status === "complete" ? "text-zinc-950 dark:text-white" : "text-zinc-400 dark:text-zinc-500"
|
|
1898
|
+
),
|
|
1899
|
+
children: step.label
|
|
1900
|
+
}
|
|
1901
|
+
),
|
|
1902
|
+
step.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-sm text-zinc-500 dark:text-zinc-400", children: step.description })
|
|
1903
|
+
] })
|
|
1904
|
+
] }, index)
|
|
1905
|
+
);
|
|
1906
|
+
}) }) });
|
|
1907
|
+
}
|
|
1908
|
+
const TabsContext = createContext(null);
|
|
1909
|
+
function useTabsContext() {
|
|
1910
|
+
const ctx = useContext(TabsContext);
|
|
1911
|
+
if (!ctx) throw new Error("Tabs subcomponents must be used inside <Tabs>");
|
|
1912
|
+
return ctx;
|
|
1913
|
+
}
|
|
1914
|
+
function Tabs({
|
|
1915
|
+
defaultTab,
|
|
1916
|
+
value,
|
|
1917
|
+
onChange,
|
|
1918
|
+
className,
|
|
1919
|
+
children
|
|
1920
|
+
}) {
|
|
1921
|
+
const baseId = useId();
|
|
1922
|
+
const [internalTab, setInternalTab] = useState(defaultTab ?? "");
|
|
1923
|
+
const activeTab = value ?? internalTab;
|
|
1924
|
+
const setActiveTab = useCallback(
|
|
1925
|
+
(id) => {
|
|
1926
|
+
setInternalTab(id);
|
|
1927
|
+
onChange?.(id);
|
|
1928
|
+
},
|
|
1929
|
+
[onChange]
|
|
1930
|
+
);
|
|
1931
|
+
return /* @__PURE__ */ jsx(TabsContext, { value: { activeTab, setActiveTab, baseId }, children: /* @__PURE__ */ jsx("div", { className, children }) });
|
|
1932
|
+
}
|
|
1933
|
+
function TabList({
|
|
1934
|
+
className,
|
|
1935
|
+
children
|
|
1936
|
+
}) {
|
|
1937
|
+
return /* @__PURE__ */ jsx(
|
|
1938
|
+
"div",
|
|
1939
|
+
{
|
|
1940
|
+
role: "tablist",
|
|
1941
|
+
className: clsx("flex border-b border-zinc-200 dark:border-zinc-700", className),
|
|
1942
|
+
children
|
|
1943
|
+
}
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
function Tab({
|
|
1947
|
+
id,
|
|
1948
|
+
className,
|
|
1949
|
+
children
|
|
1950
|
+
}) {
|
|
1951
|
+
const { activeTab, setActiveTab, baseId } = useTabsContext();
|
|
1952
|
+
const isActive = activeTab === id;
|
|
1953
|
+
return /* @__PURE__ */ jsx(
|
|
1954
|
+
"button",
|
|
1955
|
+
{
|
|
1956
|
+
type: "button",
|
|
1957
|
+
role: "tab",
|
|
1958
|
+
id: `${baseId}-tab-${id}`,
|
|
1959
|
+
"aria-controls": `${baseId}-panel-${id}`,
|
|
1960
|
+
"aria-selected": isActive,
|
|
1961
|
+
tabIndex: isActive ? 0 : -1,
|
|
1962
|
+
onClick: () => setActiveTab(id),
|
|
1963
|
+
className: clsx(
|
|
1964
|
+
className,
|
|
1965
|
+
"relative -mb-px border-b-2 px-4 py-2.5 text-sm font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",
|
|
1966
|
+
isActive ? "border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400" : "border-transparent text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"
|
|
1967
|
+
),
|
|
1968
|
+
children
|
|
1969
|
+
}
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
function TabPanel({
|
|
1973
|
+
id,
|
|
1974
|
+
className,
|
|
1975
|
+
children
|
|
1976
|
+
}) {
|
|
1977
|
+
const { activeTab, baseId } = useTabsContext();
|
|
1978
|
+
if (activeTab !== id) return null;
|
|
1979
|
+
return /* @__PURE__ */ jsx(
|
|
1980
|
+
"div",
|
|
1981
|
+
{
|
|
1982
|
+
role: "tabpanel",
|
|
1983
|
+
id: `${baseId}-panel-${id}`,
|
|
1984
|
+
"aria-labelledby": `${baseId}-tab-${id}`,
|
|
1985
|
+
tabIndex: 0,
|
|
1986
|
+
className: clsx("focus-visible:outline-none", className),
|
|
1987
|
+
children
|
|
1988
|
+
}
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1991
|
+
const Textarea = forwardRef(function Textarea2({ className, resizable = true, disabled, invalid, ...props }, ref) {
|
|
1992
|
+
const interactiveProps = useDataInteractive({ disabled });
|
|
1993
|
+
const fieldProps = useFieldControlProps();
|
|
1994
|
+
return /* @__PURE__ */ jsx(
|
|
1995
|
+
"span",
|
|
1996
|
+
{
|
|
1997
|
+
"data-slot": "control",
|
|
1998
|
+
className: clsx([
|
|
1999
|
+
className,
|
|
2000
|
+
// Basic layout
|
|
2001
|
+
"relative block w-full",
|
|
2002
|
+
// Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
|
|
2003
|
+
"before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm",
|
|
2004
|
+
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
|
2005
|
+
"dark:before:hidden",
|
|
2006
|
+
// Focus ring
|
|
2007
|
+
"after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500",
|
|
2008
|
+
// Disabled state
|
|
2009
|
+
"has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none"
|
|
2010
|
+
]),
|
|
2011
|
+
children: /* @__PURE__ */ jsx(
|
|
2012
|
+
"textarea",
|
|
2013
|
+
{
|
|
2014
|
+
ref,
|
|
2015
|
+
disabled,
|
|
2016
|
+
...props,
|
|
2017
|
+
...interactiveProps,
|
|
2018
|
+
...fieldProps,
|
|
2019
|
+
"data-invalid": invalid ? "" : void 0,
|
|
2020
|
+
"data-disabled": disabled ? "" : void 0,
|
|
2021
|
+
className: clsx([
|
|
2022
|
+
// Basic layout
|
|
2023
|
+
"relative block h-full w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)]",
|
|
2024
|
+
// Typography
|
|
2025
|
+
"text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white",
|
|
2026
|
+
// Border
|
|
2027
|
+
"border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20",
|
|
2028
|
+
// Background color
|
|
2029
|
+
"bg-transparent dark:bg-white/5",
|
|
2030
|
+
// Hide default focus styles
|
|
2031
|
+
"focus:outline-hidden",
|
|
2032
|
+
// Invalid state
|
|
2033
|
+
"data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-600 dark:data-invalid:data-hover:border-red-600",
|
|
2034
|
+
// Disabled state
|
|
2035
|
+
"disabled:border-zinc-950/20 dark:disabled:border-white/15 dark:disabled:bg-white/2.5 dark:data-hover:disabled:border-white/15",
|
|
2036
|
+
// Resizable
|
|
2037
|
+
resizable ? "resize-y" : "resize-none"
|
|
2038
|
+
])
|
|
2039
|
+
}
|
|
2040
|
+
)
|
|
2041
|
+
}
|
|
2042
|
+
);
|
|
2043
|
+
});
|
|
2044
|
+
function Timeline({
|
|
2045
|
+
className,
|
|
2046
|
+
children
|
|
2047
|
+
}) {
|
|
2048
|
+
return /* @__PURE__ */ jsx("ol", { className: clsx("relative", className), children });
|
|
2049
|
+
}
|
|
2050
|
+
function TimelineItem({
|
|
2051
|
+
icon,
|
|
2052
|
+
date,
|
|
2053
|
+
title,
|
|
2054
|
+
description,
|
|
2055
|
+
isLast = false,
|
|
2056
|
+
className
|
|
2057
|
+
}) {
|
|
2058
|
+
return /* @__PURE__ */ jsxs("li", { className: clsx("relative flex gap-4", !isLast && "pb-8", className), children: [
|
|
2059
|
+
!isLast && /* @__PURE__ */ jsx(
|
|
2060
|
+
"div",
|
|
2061
|
+
{
|
|
2062
|
+
"aria-hidden": "true",
|
|
2063
|
+
className: "absolute left-4 top-8 -bottom-0 w-px bg-zinc-200 dark:bg-zinc-700"
|
|
2064
|
+
}
|
|
2065
|
+
),
|
|
2066
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-10 flex size-8 shrink-0 items-center justify-center rounded-full bg-white ring-1 ring-zinc-200 dark:bg-zinc-900 dark:ring-zinc-700", children: icon ?? /* @__PURE__ */ jsx("div", { className: "size-2 rounded-full bg-zinc-400 dark:bg-zinc-500" }) }),
|
|
2067
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 pt-0.5", children: [
|
|
2068
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-x-4", children: [
|
|
2069
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: title }),
|
|
2070
|
+
date && /* @__PURE__ */ jsx("time", { className: "shrink-0 text-xs text-zinc-400 dark:text-zinc-500", children: date })
|
|
2071
|
+
] }),
|
|
2072
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-zinc-600 dark:text-zinc-400", children: description })
|
|
2073
|
+
] })
|
|
2074
|
+
] });
|
|
2075
|
+
}
|
|
2076
|
+
function toastReducer(state, action) {
|
|
2077
|
+
switch (action.type) {
|
|
2078
|
+
case "ADD":
|
|
2079
|
+
return [...state, action.toast];
|
|
2080
|
+
case "REMOVE":
|
|
2081
|
+
return state.filter((t) => t.id !== action.id);
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
const ToastContext = createContext(null);
|
|
2085
|
+
function ToastProvider({ children }) {
|
|
2086
|
+
const [toasts, dispatch] = useReducer(toastReducer, []);
|
|
2087
|
+
const addToast = useCallback((toast) => {
|
|
2088
|
+
const id = Math.random().toString(36).slice(2);
|
|
2089
|
+
const duration = toast.duration ?? 5e3;
|
|
2090
|
+
dispatch({ type: "ADD", toast: { ...toast, id } });
|
|
2091
|
+
if (duration > 0) {
|
|
2092
|
+
setTimeout(() => dispatch({ type: "REMOVE", id }), duration);
|
|
2093
|
+
}
|
|
2094
|
+
return id;
|
|
2095
|
+
}, []);
|
|
2096
|
+
const removeToast = useCallback((id) => {
|
|
2097
|
+
dispatch({ type: "REMOVE", id });
|
|
2098
|
+
}, []);
|
|
2099
|
+
return /* @__PURE__ */ jsxs(ToastContext, { value: { toasts, addToast, removeToast }, children: [
|
|
2100
|
+
children,
|
|
2101
|
+
typeof document !== "undefined" && createPortal(/* @__PURE__ */ jsx(ToastList, { toasts, onRemove: removeToast }), document.body)
|
|
2102
|
+
] });
|
|
2103
|
+
}
|
|
2104
|
+
function useToast() {
|
|
2105
|
+
const ctx = useContext(ToastContext);
|
|
2106
|
+
if (!ctx) throw new Error("useToast must be used within a ToastProvider");
|
|
2107
|
+
return ctx;
|
|
2108
|
+
}
|
|
2109
|
+
const variantClasses = {
|
|
2110
|
+
default: "bg-white dark:bg-zinc-800 ring-zinc-950/10 dark:ring-white/10",
|
|
2111
|
+
success: "bg-white dark:bg-zinc-800 ring-green-500/30",
|
|
2112
|
+
error: "bg-white dark:bg-zinc-800 ring-red-500/30",
|
|
2113
|
+
warning: "bg-white dark:bg-zinc-800 ring-amber-500/30",
|
|
2114
|
+
info: "bg-white dark:bg-zinc-800 ring-blue-500/30"
|
|
2115
|
+
};
|
|
2116
|
+
const variantIconClasses = {
|
|
2117
|
+
default: "hidden",
|
|
2118
|
+
success: "text-green-500",
|
|
2119
|
+
error: "text-red-500",
|
|
2120
|
+
warning: "text-amber-500",
|
|
2121
|
+
info: "text-blue-500"
|
|
2122
|
+
};
|
|
2123
|
+
const variantIcons = {
|
|
2124
|
+
default: "",
|
|
2125
|
+
success: "✓",
|
|
2126
|
+
error: "✕",
|
|
2127
|
+
warning: "!",
|
|
2128
|
+
info: "i"
|
|
2129
|
+
};
|
|
2130
|
+
function ToastList({ toasts, onRemove }) {
|
|
2131
|
+
if (toasts.length === 0) return null;
|
|
2132
|
+
return /* @__PURE__ */ jsx(
|
|
2133
|
+
"div",
|
|
2134
|
+
{
|
|
2135
|
+
"aria-live": "assertive",
|
|
2136
|
+
className: "pointer-events-none fixed inset-0 z-50 flex flex-col items-end justify-end gap-2 p-4 sm:p-6",
|
|
2137
|
+
children: toasts.map((toast) => /* @__PURE__ */ jsx(ToastItem, { toast, onRemove }, toast.id))
|
|
2138
|
+
}
|
|
2139
|
+
);
|
|
2140
|
+
}
|
|
2141
|
+
function ToastItem({ toast, onRemove }) {
|
|
2142
|
+
const variant = toast.variant ?? "default";
|
|
2143
|
+
return /* @__PURE__ */ jsxs(
|
|
2144
|
+
"div",
|
|
2145
|
+
{
|
|
2146
|
+
role: "alert",
|
|
2147
|
+
className: clsx(
|
|
2148
|
+
"pointer-events-auto flex w-full max-w-sm items-start gap-3 rounded-xl p-4 shadow-lg ring-1",
|
|
2149
|
+
variantClasses[variant]
|
|
2150
|
+
),
|
|
2151
|
+
children: [
|
|
2152
|
+
variant !== "default" && /* @__PURE__ */ jsx("span", { className: clsx("mt-0.5 text-sm font-bold", variantIconClasses[variant]), children: variantIcons[variant] }),
|
|
2153
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
2154
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: toast.title }),
|
|
2155
|
+
toast.description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-zinc-500 dark:text-zinc-400", children: toast.description })
|
|
2156
|
+
] }),
|
|
2157
|
+
/* @__PURE__ */ jsx(
|
|
2158
|
+
"button",
|
|
2159
|
+
{
|
|
2160
|
+
type: "button",
|
|
2161
|
+
"aria-label": "Dismiss",
|
|
2162
|
+
onClick: () => onRemove(toast.id),
|
|
2163
|
+
className: "shrink-0 rounded-md text-zinc-400 hover:text-zinc-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:text-zinc-500 dark:hover:text-zinc-300",
|
|
2164
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "✕" })
|
|
2165
|
+
}
|
|
2166
|
+
)
|
|
2167
|
+
]
|
|
2168
|
+
}
|
|
2169
|
+
);
|
|
2170
|
+
}
|
|
2171
|
+
const sideClasses = {
|
|
2172
|
+
top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
|
|
2173
|
+
bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
|
|
2174
|
+
left: "right-full top-1/2 -translate-y-1/2 mr-2",
|
|
2175
|
+
right: "left-full top-1/2 -translate-y-1/2 ml-2"
|
|
2176
|
+
};
|
|
2177
|
+
function Tooltip({
|
|
2178
|
+
content,
|
|
2179
|
+
side = "top",
|
|
2180
|
+
className,
|
|
2181
|
+
children
|
|
2182
|
+
}) {
|
|
2183
|
+
const [visible, setVisible] = useState(false);
|
|
2184
|
+
const id = useId();
|
|
2185
|
+
const timeoutRef = useRef(null);
|
|
2186
|
+
const show = useCallback(() => {
|
|
2187
|
+
timeoutRef.current = setTimeout(() => setVisible(true), 200);
|
|
2188
|
+
}, []);
|
|
2189
|
+
const hide = useCallback(() => {
|
|
2190
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
2191
|
+
setVisible(false);
|
|
2192
|
+
}, []);
|
|
2193
|
+
return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", onMouseEnter: show, onMouseLeave: hide, children: [
|
|
2194
|
+
children,
|
|
2195
|
+
visible && /* @__PURE__ */ jsx(
|
|
2196
|
+
"span",
|
|
2197
|
+
{
|
|
2198
|
+
role: "tooltip",
|
|
2199
|
+
id,
|
|
2200
|
+
className: clsx(
|
|
2201
|
+
className,
|
|
2202
|
+
sideClasses[side],
|
|
2203
|
+
"pointer-events-none absolute z-50 w-max max-w-xs rounded-lg bg-zinc-950 px-2.5 py-1.5 text-xs text-white shadow-lg dark:bg-zinc-700"
|
|
2204
|
+
),
|
|
2205
|
+
children: content
|
|
2206
|
+
}
|
|
2207
|
+
)
|
|
2208
|
+
] });
|
|
2209
|
+
}
|
|
2210
|
+
export {
|
|
2211
|
+
useScrollLock as $,
|
|
2212
|
+
Accordion as A,
|
|
2213
|
+
Breadcrumb as B,
|
|
2214
|
+
Callout as C,
|
|
2215
|
+
Drawer as D,
|
|
2216
|
+
EmptyState as E,
|
|
2217
|
+
SkeletonText as F,
|
|
2218
|
+
Slider as G,
|
|
2219
|
+
Stat as H,
|
|
2220
|
+
Input as I,
|
|
2221
|
+
StatGroup as J,
|
|
2222
|
+
Kbd as K,
|
|
2223
|
+
Stepper as L,
|
|
2224
|
+
TabList as M,
|
|
2225
|
+
TabPanel as N,
|
|
2226
|
+
Tabs as O,
|
|
2227
|
+
Progress as P,
|
|
2228
|
+
Textarea as Q,
|
|
2229
|
+
Rating as R,
|
|
2230
|
+
Select as S,
|
|
2231
|
+
Tab as T,
|
|
2232
|
+
Timeline as U,
|
|
2233
|
+
TimelineItem as V,
|
|
2234
|
+
ToastProvider as W,
|
|
2235
|
+
Tooltip as X,
|
|
2236
|
+
TouchTarget as Y,
|
|
2237
|
+
useToast as Z,
|
|
2238
|
+
useTransition as _,
|
|
2239
|
+
AccordionItem as a,
|
|
2240
|
+
useFocusTrap as a0,
|
|
2241
|
+
useEscapeKey as a1,
|
|
2242
|
+
useDataInteractive as a2,
|
|
2243
|
+
Link as a3,
|
|
2244
|
+
useControllableState as a4,
|
|
2245
|
+
useFieldDescriptionProps as a5,
|
|
2246
|
+
useFieldErrorProps as a6,
|
|
2247
|
+
FieldProvider as a7,
|
|
2248
|
+
useFieldLabelProps as a8,
|
|
2249
|
+
useToggle as a9,
|
|
2250
|
+
Avatar as aa,
|
|
2251
|
+
AvatarGroup as b,
|
|
2252
|
+
Button as c,
|
|
2253
|
+
Checkbox as d,
|
|
2254
|
+
Checkbox$1 as e,
|
|
2255
|
+
CheckboxField as f,
|
|
2256
|
+
CheckboxGroup as g,
|
|
2257
|
+
CheckboxIndicator as h,
|
|
2258
|
+
CodeBlock as i,
|
|
2259
|
+
DrawerBody as j,
|
|
2260
|
+
DrawerFooter as k,
|
|
2261
|
+
DrawerHeader as l,
|
|
2262
|
+
InputGroup as m,
|
|
2263
|
+
KbdShortcut as n,
|
|
2264
|
+
Select$1 as o,
|
|
2265
|
+
SelectContent as p,
|
|
2266
|
+
SelectGroup as q,
|
|
2267
|
+
SelectItem as r,
|
|
2268
|
+
SelectLabel as s,
|
|
2269
|
+
SelectScrollDownButton as t,
|
|
2270
|
+
SelectScrollUpButton as u,
|
|
2271
|
+
SelectSeparator as v,
|
|
2272
|
+
SelectTrigger as w,
|
|
2273
|
+
SelectValue as x,
|
|
2274
|
+
Skeleton as y,
|
|
2275
|
+
SkeletonCard as z
|
|
2276
|
+
};
|
|
2277
|
+
//# sourceMappingURL=tooltip-oH4lAnkn.js.map
|