@pablo2410/shared-ui 0.12.1 → 0.13.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/dist/{HealthFooter-BN5LHTp6.d.ts → HealthFooter-9rZjMmqc.d.ts} +12 -0
- package/dist/{chunk-LTUYIBMA.js → chunk-HR77H6PE.js} +489 -789
- package/dist/chunk-HR77H6PE.js.map +1 -0
- package/dist/{chunk-ETIKYZIX.js → chunk-J7LWAIQK.js} +8 -2
- package/dist/chunk-J7LWAIQK.js.map +1 -0
- package/dist/{chunk-NQZDFCIU.js → chunk-L2N36IW6.js} +57 -45
- package/dist/chunk-L2N36IW6.js.map +1 -0
- package/dist/chunk-R4NOLCSI.js +308 -0
- package/dist/chunk-R4NOLCSI.js.map +1 -0
- package/dist/components/index.d.ts +28 -1
- package/dist/components/index.js +127 -0
- package/dist/components/index.js.map +1 -1
- package/dist/hierarchy/index.js +3 -2
- package/dist/layout/index.d.ts +2 -2
- package/dist/layout/index.js +4 -3
- package/dist/primitives/index.js +20 -18
- package/dist/reporting/index.js +11 -9
- package/dist/reporting/index.js.map +1 -1
- package/dist/shell/index.d.ts +2 -2
- package/dist/shell/index.js +4 -3
- package/dist/shell/index.js.map +1 -1
- package/dist/shell/oplytics-shell.css +1 -1
- package/package.json +1 -1
- package/dist/chunk-ETIKYZIX.js.map +0 -1
- package/dist/chunk-LTUYIBMA.js.map +0 -1
- package/dist/chunk-NQZDFCIU.js.map +0 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// src/primitives/cn.ts
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
function cn(...inputs) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// src/primitives/button.tsx
|
|
9
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
10
|
+
import { cva } from "class-variance-authority";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
var buttonVariants = cva(
|
|
13
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
14
|
+
{
|
|
15
|
+
variants: {
|
|
16
|
+
variant: {
|
|
17
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
18
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
19
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
20
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
21
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
22
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
26
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
27
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
28
|
+
icon: "size-9"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
variant: "default",
|
|
33
|
+
size: "default"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
function Button({
|
|
38
|
+
className,
|
|
39
|
+
variant,
|
|
40
|
+
size,
|
|
41
|
+
asChild = false,
|
|
42
|
+
...props
|
|
43
|
+
}) {
|
|
44
|
+
const Comp = asChild ? Slot : "button";
|
|
45
|
+
return /* @__PURE__ */ jsx(
|
|
46
|
+
Comp,
|
|
47
|
+
{
|
|
48
|
+
"data-slot": "button",
|
|
49
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
50
|
+
...props
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/primitives/dialog.tsx
|
|
56
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
57
|
+
import { XIcon } from "lucide-react";
|
|
58
|
+
import * as React from "react";
|
|
59
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
60
|
+
var DialogCompositionContext = React.createContext({
|
|
61
|
+
isComposing: () => false,
|
|
62
|
+
setComposing: () => {
|
|
63
|
+
},
|
|
64
|
+
justEndedComposing: () => false,
|
|
65
|
+
markCompositionEnd: () => {
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
var useDialogComposition = () => React.useContext(DialogCompositionContext);
|
|
69
|
+
function Dialog({
|
|
70
|
+
...props
|
|
71
|
+
}) {
|
|
72
|
+
const composingRef = React.useRef(false);
|
|
73
|
+
const justEndedRef = React.useRef(false);
|
|
74
|
+
const endTimerRef = React.useRef(null);
|
|
75
|
+
const contextValue = React.useMemo(
|
|
76
|
+
() => ({
|
|
77
|
+
isComposing: () => composingRef.current,
|
|
78
|
+
setComposing: (composing) => {
|
|
79
|
+
composingRef.current = composing;
|
|
80
|
+
},
|
|
81
|
+
justEndedComposing: () => justEndedRef.current,
|
|
82
|
+
markCompositionEnd: () => {
|
|
83
|
+
justEndedRef.current = true;
|
|
84
|
+
if (endTimerRef.current) {
|
|
85
|
+
clearTimeout(endTimerRef.current);
|
|
86
|
+
}
|
|
87
|
+
endTimerRef.current = setTimeout(() => {
|
|
88
|
+
justEndedRef.current = false;
|
|
89
|
+
}, 150);
|
|
90
|
+
}
|
|
91
|
+
}),
|
|
92
|
+
[]
|
|
93
|
+
);
|
|
94
|
+
return /* @__PURE__ */ jsx2(DialogCompositionContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx2(DialogPrimitive.Root, { "data-slot": "dialog", ...props }) });
|
|
95
|
+
}
|
|
96
|
+
function DialogTrigger({
|
|
97
|
+
...props
|
|
98
|
+
}) {
|
|
99
|
+
return /* @__PURE__ */ jsx2(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
|
|
100
|
+
}
|
|
101
|
+
function DialogPortal({
|
|
102
|
+
...props
|
|
103
|
+
}) {
|
|
104
|
+
return /* @__PURE__ */ jsx2(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
|
|
105
|
+
}
|
|
106
|
+
function DialogClose({
|
|
107
|
+
...props
|
|
108
|
+
}) {
|
|
109
|
+
return /* @__PURE__ */ jsx2(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
|
|
110
|
+
}
|
|
111
|
+
function DialogOverlay({
|
|
112
|
+
className,
|
|
113
|
+
...props
|
|
114
|
+
}) {
|
|
115
|
+
return /* @__PURE__ */ jsx2(
|
|
116
|
+
DialogPrimitive.Overlay,
|
|
117
|
+
{
|
|
118
|
+
"data-slot": "dialog-overlay",
|
|
119
|
+
className: cn(
|
|
120
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
121
|
+
className
|
|
122
|
+
),
|
|
123
|
+
...props
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
DialogOverlay.displayName = "DialogOverlay";
|
|
128
|
+
function DialogContent({
|
|
129
|
+
className,
|
|
130
|
+
children,
|
|
131
|
+
showCloseButton = true,
|
|
132
|
+
onEscapeKeyDown,
|
|
133
|
+
...props
|
|
134
|
+
}) {
|
|
135
|
+
const { isComposing } = useDialogComposition();
|
|
136
|
+
const handleEscapeKeyDown = React.useCallback(
|
|
137
|
+
(e) => {
|
|
138
|
+
const isCurrentlyComposing = e.isComposing || isComposing();
|
|
139
|
+
if (isCurrentlyComposing) {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
onEscapeKeyDown?.(e);
|
|
144
|
+
},
|
|
145
|
+
[isComposing, onEscapeKeyDown]
|
|
146
|
+
);
|
|
147
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
148
|
+
/* @__PURE__ */ jsx2(DialogOverlay, {}),
|
|
149
|
+
/* @__PURE__ */ jsxs(
|
|
150
|
+
DialogPrimitive.Content,
|
|
151
|
+
{
|
|
152
|
+
"data-slot": "dialog-content",
|
|
153
|
+
className: cn(
|
|
154
|
+
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
|
155
|
+
className
|
|
156
|
+
),
|
|
157
|
+
onEscapeKeyDown: handleEscapeKeyDown,
|
|
158
|
+
...props,
|
|
159
|
+
children: [
|
|
160
|
+
children,
|
|
161
|
+
showCloseButton && /* @__PURE__ */ jsxs(
|
|
162
|
+
DialogPrimitive.Close,
|
|
163
|
+
{
|
|
164
|
+
"data-slot": "dialog-close",
|
|
165
|
+
className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
166
|
+
children: [
|
|
167
|
+
/* @__PURE__ */ jsx2(XIcon, {}),
|
|
168
|
+
/* @__PURE__ */ jsx2("span", { className: "sr-only", children: "Close" })
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
] });
|
|
176
|
+
}
|
|
177
|
+
function DialogHeader({ className, ...props }) {
|
|
178
|
+
return /* @__PURE__ */ jsx2(
|
|
179
|
+
"div",
|
|
180
|
+
{
|
|
181
|
+
"data-slot": "dialog-header",
|
|
182
|
+
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
183
|
+
...props
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
function DialogFooter({ className, ...props }) {
|
|
188
|
+
return /* @__PURE__ */ jsx2(
|
|
189
|
+
"div",
|
|
190
|
+
{
|
|
191
|
+
"data-slot": "dialog-footer",
|
|
192
|
+
className: cn(
|
|
193
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
194
|
+
className
|
|
195
|
+
),
|
|
196
|
+
...props
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
function DialogTitle({
|
|
201
|
+
className,
|
|
202
|
+
...props
|
|
203
|
+
}) {
|
|
204
|
+
return /* @__PURE__ */ jsx2(
|
|
205
|
+
DialogPrimitive.Title,
|
|
206
|
+
{
|
|
207
|
+
"data-slot": "dialog-title",
|
|
208
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
209
|
+
...props
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function DialogDescription({
|
|
214
|
+
className,
|
|
215
|
+
...props
|
|
216
|
+
}) {
|
|
217
|
+
return /* @__PURE__ */ jsx2(
|
|
218
|
+
DialogPrimitive.Description,
|
|
219
|
+
{
|
|
220
|
+
"data-slot": "dialog-description",
|
|
221
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
222
|
+
...props
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/primitives/label.tsx
|
|
228
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
229
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
230
|
+
function Label({
|
|
231
|
+
className,
|
|
232
|
+
...props
|
|
233
|
+
}) {
|
|
234
|
+
return /* @__PURE__ */ jsx3(
|
|
235
|
+
LabelPrimitive.Root,
|
|
236
|
+
{
|
|
237
|
+
"data-slot": "label",
|
|
238
|
+
className: cn(
|
|
239
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
240
|
+
className
|
|
241
|
+
),
|
|
242
|
+
...props
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/primitives/radio-group.tsx
|
|
248
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
249
|
+
import { CircleIcon } from "lucide-react";
|
|
250
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
251
|
+
function RadioGroup({
|
|
252
|
+
className,
|
|
253
|
+
...props
|
|
254
|
+
}) {
|
|
255
|
+
return /* @__PURE__ */ jsx4(
|
|
256
|
+
RadioGroupPrimitive.Root,
|
|
257
|
+
{
|
|
258
|
+
"data-slot": "radio-group",
|
|
259
|
+
className: cn("grid gap-3", className),
|
|
260
|
+
...props
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
function RadioGroupItem({
|
|
265
|
+
className,
|
|
266
|
+
...props
|
|
267
|
+
}) {
|
|
268
|
+
return /* @__PURE__ */ jsx4(
|
|
269
|
+
RadioGroupPrimitive.Item,
|
|
270
|
+
{
|
|
271
|
+
"data-slot": "radio-group-item",
|
|
272
|
+
className: cn(
|
|
273
|
+
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
274
|
+
className
|
|
275
|
+
),
|
|
276
|
+
...props,
|
|
277
|
+
children: /* @__PURE__ */ jsx4(
|
|
278
|
+
RadioGroupPrimitive.Indicator,
|
|
279
|
+
{
|
|
280
|
+
"data-slot": "radio-group-indicator",
|
|
281
|
+
className: "relative flex items-center justify-center",
|
|
282
|
+
children: /* @__PURE__ */ jsx4(CircleIcon, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" })
|
|
283
|
+
}
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export {
|
|
290
|
+
cn,
|
|
291
|
+
buttonVariants,
|
|
292
|
+
Button,
|
|
293
|
+
useDialogComposition,
|
|
294
|
+
Dialog,
|
|
295
|
+
DialogTrigger,
|
|
296
|
+
DialogPortal,
|
|
297
|
+
DialogClose,
|
|
298
|
+
DialogOverlay,
|
|
299
|
+
DialogContent,
|
|
300
|
+
DialogHeader,
|
|
301
|
+
DialogFooter,
|
|
302
|
+
DialogTitle,
|
|
303
|
+
DialogDescription,
|
|
304
|
+
Label,
|
|
305
|
+
RadioGroup,
|
|
306
|
+
RadioGroupItem
|
|
307
|
+
};
|
|
308
|
+
//# sourceMappingURL=chunk-R4NOLCSI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/primitives/cn.ts","../src/primitives/button.tsx","../src/primitives/dialog.tsx","../src/primitives/label.tsx","../src/primitives/radio-group.tsx"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"./cn\";\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\nexport { Button, buttonVariants };\n","import { cn } from \"./cn\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { XIcon } from \"lucide-react\";\nimport * as React from \"react\";\n\n// Context to track composition state across dialog children\nconst DialogCompositionContext = React.createContext<{\n isComposing: () => boolean;\n setComposing: (composing: boolean) => void;\n justEndedComposing: () => boolean;\n markCompositionEnd: () => void;\n}>({\n isComposing: () => false,\n setComposing: () => {},\n justEndedComposing: () => false,\n markCompositionEnd: () => {},\n});\n\nexport const useDialogComposition = () =>\n React.useContext(DialogCompositionContext);\n\nfunction Dialog({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n const composingRef = React.useRef(false);\n const justEndedRef = React.useRef(false);\n const endTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const contextValue = React.useMemo(\n () => ({\n isComposing: () => composingRef.current,\n setComposing: (composing: boolean) => {\n composingRef.current = composing;\n },\n justEndedComposing: () => justEndedRef.current,\n markCompositionEnd: () => {\n justEndedRef.current = true;\n if (endTimerRef.current) {\n clearTimeout(endTimerRef.current);\n }\n endTimerRef.current = setTimeout(() => {\n justEndedRef.current = false;\n }, 150);\n },\n }),\n []\n );\n\n return (\n <DialogCompositionContext.Provider value={contextValue}>\n <DialogPrimitive.Root data-slot=\"dialog\" {...props} />\n </DialogCompositionContext.Provider>\n );\n}\n\nfunction DialogTrigger({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n );\n}\n\nDialogOverlay.displayName = \"DialogOverlay\";\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n onEscapeKeyDown,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n const { isComposing } = useDialogComposition();\n\n const handleEscapeKeyDown = React.useCallback(\n (e: KeyboardEvent) => {\n // Check both the native isComposing property and our context state\n // This handles Safari's timing issues with composition events\n const isCurrentlyComposing = (e as any).isComposing || isComposing();\n\n // If IME is composing, prevent dialog from closing\n if (isCurrentlyComposing) {\n e.preventDefault();\n return;\n }\n\n // Call user's onEscapeKeyDown if provided\n onEscapeKeyDown?.(e);\n },\n [isComposing, onEscapeKeyDown]\n );\n\n return (\n <DialogPortal data-slot=\"dialog-portal\">\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg\",\n className\n )}\n onEscapeKeyDown={handleEscapeKeyDown}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\"\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"text-lg leading-none font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger\n};\n\n","import * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cn } from \"./cn\";\n\nfunction Label({\n className,\n ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import * as React from \"react\";\nimport * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport { CircleIcon } from \"lucide-react\";\n\nimport { cn } from \"./cn\";\n\nfunction RadioGroup({\n className,\n ...props\n}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {\n return (\n <RadioGroupPrimitive.Root\n data-slot=\"radio-group\"\n className={cn(\"grid gap-3\", className)}\n {...props}\n />\n );\n}\n\nfunction RadioGroupItem({\n className,\n ...props\n}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return (\n <RadioGroupPrimitive.Item\n data-slot=\"radio-group-item\"\n className={cn(\n \"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"relative flex items-center justify-center\"\n >\n <CircleIcon className=\"fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n );\n}\n\nexport { RadioGroup, RadioGroupItem };\n"],"mappings":"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","names":["jsx","jsx","jsx"]}
|
|
@@ -149,4 +149,31 @@ interface ViewOnlyBadgeProps {
|
|
|
149
149
|
}
|
|
150
150
|
declare function ViewOnlyBadge({ label, size, className, }: ViewOnlyBadgeProps): react_jsx_runtime.JSX.Element;
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
type ExportFormat = "csv" | "xlsx";
|
|
153
|
+
interface ExportResult {
|
|
154
|
+
/** File contents to save. */
|
|
155
|
+
data: Blob | string;
|
|
156
|
+
/** Suggested filename, including extension. */
|
|
157
|
+
filename: string;
|
|
158
|
+
/** MIME type for the Blob/save picker. */
|
|
159
|
+
mimeType: string;
|
|
160
|
+
}
|
|
161
|
+
interface ExportDialogProps {
|
|
162
|
+
open: boolean;
|
|
163
|
+
onOpenChange: (open: boolean) => void;
|
|
164
|
+
/** Title shown in the dialog header, e.g. "Export Actions". */
|
|
165
|
+
title?: string;
|
|
166
|
+
/** Description shown under the title. */
|
|
167
|
+
description?: string;
|
|
168
|
+
/**
|
|
169
|
+
* Produce the file contents for the chosen format. Called only when the
|
|
170
|
+
* user confirms — do the actual CSV/XLSX serialization here. May be async
|
|
171
|
+
* (e.g. fetching a fuller dataset than what's on screen).
|
|
172
|
+
*/
|
|
173
|
+
onExport: (format: ExportFormat) => Promise<ExportResult> | ExportResult;
|
|
174
|
+
/** Restrict which formats are offered (default: both). */
|
|
175
|
+
formats?: ExportFormat[];
|
|
176
|
+
}
|
|
177
|
+
declare function ExportDialog({ open, onOpenChange, title, description, onExport, formats, }: ExportDialogProps): react_jsx_runtime.JSX.Element;
|
|
178
|
+
|
|
179
|
+
export { AIChatBox, type AIChatBoxProps, type ChatMessage, ErrorBoundary, type ErrorBoundaryProps, ExportDialog, type ExportDialogProps, type ExportFormat, type ExportResult, ManusDialog, type ManusDialogProps, MapView, type MapViewProps, NotFoundPage, type NotFoundPageProps, ViewOnlyBadge, type ViewOnlyBadgeProps };
|
package/dist/components/index.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cn
|
|
3
3
|
} from "../chunk-JT3XLKKD.js";
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogContent,
|
|
8
|
+
DialogDescription,
|
|
9
|
+
DialogFooter,
|
|
10
|
+
DialogHeader,
|
|
11
|
+
DialogTitle,
|
|
12
|
+
Label,
|
|
13
|
+
RadioGroup,
|
|
14
|
+
RadioGroupItem
|
|
15
|
+
} from "../chunk-R4NOLCSI.js";
|
|
4
16
|
|
|
5
17
|
// src/components/ErrorBoundary.tsx
|
|
6
18
|
import { Component } from "react";
|
|
@@ -564,9 +576,124 @@ function ViewOnlyBadge({
|
|
|
564
576
|
}
|
|
565
577
|
);
|
|
566
578
|
}
|
|
579
|
+
|
|
580
|
+
// src/components/ExportDialog.tsx
|
|
581
|
+
import { useState as useState2 } from "react";
|
|
582
|
+
import { Download, FileSpreadsheet, FileText, Loader2 as Loader22 } from "lucide-react";
|
|
583
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
584
|
+
var FORMAT_META = {
|
|
585
|
+
csv: {
|
|
586
|
+
label: "CSV",
|
|
587
|
+
hint: "Plain text, opens in Excel, Sheets, or Numbers",
|
|
588
|
+
icon: FileText
|
|
589
|
+
},
|
|
590
|
+
xlsx: {
|
|
591
|
+
label: "Spreadsheet (.xlsx)",
|
|
592
|
+
hint: "Native Excel format with column formatting preserved",
|
|
593
|
+
icon: FileSpreadsheet
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
function supportsSavePicker() {
|
|
597
|
+
return typeof window !== "undefined" && "showSaveFilePicker" in window;
|
|
598
|
+
}
|
|
599
|
+
async function saveWithPicker(result) {
|
|
600
|
+
const picker = window.showSaveFilePicker;
|
|
601
|
+
const ext = result.filename.split(".").pop() ?? "txt";
|
|
602
|
+
let handle;
|
|
603
|
+
try {
|
|
604
|
+
handle = await picker({
|
|
605
|
+
suggestedName: result.filename,
|
|
606
|
+
types: [
|
|
607
|
+
{
|
|
608
|
+
description: FORMAT_META[ext === "xlsx" ? "xlsx" : "csv"].label,
|
|
609
|
+
accept: { [result.mimeType]: [`.${ext}`] }
|
|
610
|
+
}
|
|
611
|
+
]
|
|
612
|
+
});
|
|
613
|
+
} catch (err) {
|
|
614
|
+
if (err instanceof DOMException && err.name === "AbortError") return "cancelled";
|
|
615
|
+
throw err;
|
|
616
|
+
}
|
|
617
|
+
const writable = await handle.createWritable();
|
|
618
|
+
await writable.write(result.data);
|
|
619
|
+
await writable.close();
|
|
620
|
+
return "saved";
|
|
621
|
+
}
|
|
622
|
+
function downloadFallback(result) {
|
|
623
|
+
const blob = typeof result.data === "string" ? new Blob([result.data], { type: result.mimeType }) : result.data;
|
|
624
|
+
const url = URL.createObjectURL(blob);
|
|
625
|
+
const a = document.createElement("a");
|
|
626
|
+
a.href = url;
|
|
627
|
+
a.download = result.filename;
|
|
628
|
+
a.click();
|
|
629
|
+
URL.revokeObjectURL(url);
|
|
630
|
+
}
|
|
631
|
+
function ExportDialog({
|
|
632
|
+
open,
|
|
633
|
+
onOpenChange,
|
|
634
|
+
title = "Export data",
|
|
635
|
+
description = "Choose a format to export.",
|
|
636
|
+
onExport,
|
|
637
|
+
formats = ["csv", "xlsx"]
|
|
638
|
+
}) {
|
|
639
|
+
const [format, setFormat] = useState2(formats[0] ?? "csv");
|
|
640
|
+
const [busy, setBusy] = useState2(false);
|
|
641
|
+
const handleExport = async () => {
|
|
642
|
+
setBusy(true);
|
|
643
|
+
try {
|
|
644
|
+
const result = await onExport(format);
|
|
645
|
+
if (supportsSavePicker()) {
|
|
646
|
+
const outcome = await saveWithPicker(result);
|
|
647
|
+
if (outcome === "cancelled") return;
|
|
648
|
+
} else {
|
|
649
|
+
downloadFallback(result);
|
|
650
|
+
}
|
|
651
|
+
onOpenChange(false);
|
|
652
|
+
} finally {
|
|
653
|
+
setBusy(false);
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
return /* @__PURE__ */ jsx7(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs6(DialogContent, { className: "sm:max-w-md", children: [
|
|
657
|
+
/* @__PURE__ */ jsxs6(DialogHeader, { children: [
|
|
658
|
+
/* @__PURE__ */ jsx7(DialogTitle, { children: title }),
|
|
659
|
+
/* @__PURE__ */ jsx7(DialogDescription, { children: description })
|
|
660
|
+
] }),
|
|
661
|
+
/* @__PURE__ */ jsx7(RadioGroup, { value: format, onValueChange: (v) => setFormat(v), className: "gap-3", children: formats.map((f) => {
|
|
662
|
+
const meta = FORMAT_META[f];
|
|
663
|
+
const Icon = meta.icon;
|
|
664
|
+
return /* @__PURE__ */ jsxs6(
|
|
665
|
+
Label,
|
|
666
|
+
{
|
|
667
|
+
htmlFor: `export-format-${f}`,
|
|
668
|
+
className: cn(
|
|
669
|
+
"flex items-center gap-3 rounded-lg border p-3 cursor-pointer transition-colors",
|
|
670
|
+
format === f ? "border-primary bg-primary/5" : "border-border hover:bg-accent/50"
|
|
671
|
+
),
|
|
672
|
+
children: [
|
|
673
|
+
/* @__PURE__ */ jsx7(RadioGroupItem, { value: f, id: `export-format-${f}` }),
|
|
674
|
+
/* @__PURE__ */ jsx7(Icon, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
|
|
675
|
+
/* @__PURE__ */ jsxs6("span", { className: "flex flex-col min-w-0", children: [
|
|
676
|
+
/* @__PURE__ */ jsx7("span", { className: "text-sm font-medium", children: meta.label }),
|
|
677
|
+
/* @__PURE__ */ jsx7("span", { className: "text-xs text-muted-foreground", children: meta.hint })
|
|
678
|
+
] })
|
|
679
|
+
]
|
|
680
|
+
},
|
|
681
|
+
f
|
|
682
|
+
);
|
|
683
|
+
}) }),
|
|
684
|
+
/* @__PURE__ */ jsxs6(DialogFooter, { children: [
|
|
685
|
+
/* @__PURE__ */ jsx7(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: "Cancel" }),
|
|
686
|
+
/* @__PURE__ */ jsxs6(Button, { onClick: handleExport, disabled: busy, children: [
|
|
687
|
+
busy ? /* @__PURE__ */ jsx7(Loader22, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx7(Download, { className: "h-4 w-4" }),
|
|
688
|
+
supportsSavePicker() ? "Choose location & export" : "Download"
|
|
689
|
+
] })
|
|
690
|
+
] })
|
|
691
|
+
] }) });
|
|
692
|
+
}
|
|
567
693
|
export {
|
|
568
694
|
AIChatBox,
|
|
569
695
|
ErrorBoundary,
|
|
696
|
+
ExportDialog,
|
|
570
697
|
ManusDialog,
|
|
571
698
|
MapView,
|
|
572
699
|
NotFoundPage,
|