xertica-ui 2.5.2 → 2.5.3

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.
@@ -0,0 +1,2964 @@
1
+ 'use strict';
2
+
3
+ const jsxRuntime = require('react/jsx-runtime');
4
+ const ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
5
+ const button = require('./button-0BlA47It.cjs');
6
+ const React = require('react');
7
+ const RechartsPrimitive = require('recharts');
8
+ const classVarianceAuthority = require('class-variance-authority');
9
+ const lucideReact = require('lucide-react');
10
+ const skeleton = require('./skeleton-DjiHerJn.cjs');
11
+ const select = require('./select-CH6v_KcQ.cjs');
12
+ const DialogPrimitive = require('@radix-ui/react-dialog');
13
+ const dropdownMenu = require('./dropdown-menu-BMcykFDf.cjs');
14
+ const input = require('./input-ByYuOv8A.cjs');
15
+
16
+ function _interopNamespaceDefault(e) {
17
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
18
+ if (e) {
19
+ for (const k in e) {
20
+ if (k !== 'default') {
21
+ const d = Object.getOwnPropertyDescriptor(e, k);
22
+ Object.defineProperty(n, k, d.get ? d : {
23
+ enumerable: true,
24
+ get: () => e[k]
25
+ });
26
+ }
27
+ }
28
+ }
29
+ n.default = e;
30
+ return Object.freeze(n);
31
+ }
32
+
33
+ const ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(ScrollAreaPrimitive);
34
+ const React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
35
+ const RechartsPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(RechartsPrimitive);
36
+ const DialogPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(DialogPrimitive);
37
+
38
+ function ScrollArea({
39
+ className,
40
+ children,
41
+ ...props
42
+ }) {
43
+ return /* @__PURE__ */ jsxRuntime.jsxs(
44
+ ScrollAreaPrimitive__namespace.Root,
45
+ {
46
+ "data-slot": "scroll-area",
47
+ className: button.cn("relative", className),
48
+ ...props,
49
+ children: [
50
+ /* @__PURE__ */ jsxRuntime.jsx(
51
+ ScrollAreaPrimitive__namespace.Viewport,
52
+ {
53
+ "data-slot": "scroll-area-viewport",
54
+ tabIndex: 0,
55
+ role: "region",
56
+ "aria-label": "Região rolável",
57
+ className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
58
+ children
59
+ }
60
+ ),
61
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
62
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollAreaPrimitive__namespace.Corner, {})
63
+ ]
64
+ }
65
+ );
66
+ }
67
+ function ScrollBar({
68
+ className,
69
+ orientation = "vertical",
70
+ ...props
71
+ }) {
72
+ return /* @__PURE__ */ jsxRuntime.jsx(
73
+ ScrollAreaPrimitive__namespace.ScrollAreaScrollbar,
74
+ {
75
+ "data-slot": "scroll-area-scrollbar",
76
+ orientation,
77
+ className: button.cn(
78
+ "flex touch-none p-px transition-colors select-none",
79
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
80
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
81
+ className
82
+ ),
83
+ ...props,
84
+ children: /* @__PURE__ */ jsxRuntime.jsx(
85
+ ScrollAreaPrimitive__namespace.ScrollAreaThumb,
86
+ {
87
+ "data-slot": "scroll-area-thumb",
88
+ className: "bg-border relative flex-1 rounded-full"
89
+ }
90
+ )
91
+ }
92
+ );
93
+ }
94
+
95
+ const alertVariants = classVarianceAuthority.cva(
96
+ "relative w-full rounded-[var(--radius)] border-l-4 px-4 py-3 grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-5 [&>svg]:translate-y-0.5 [&>svg]:text-current",
97
+ {
98
+ variants: {
99
+ variant: {
100
+ default: "bg-muted/50 border-l-border text-foreground [&>svg]:text-muted-foreground",
101
+ success: "bg-[color:var(--success)]/10 dark:bg-[color:var(--success)]/20 border-l-[color:var(--success)] text-foreground [&>svg]:text-[color:var(--success)]",
102
+ info: "bg-[color:var(--info)]/10 dark:bg-[color:var(--info)]/20 border-l-[color:var(--info)] text-foreground [&>svg]:text-[color:var(--info)]",
103
+ warning: "bg-[color:var(--warning)]/10 dark:bg-[color:var(--warning)]/20 border-l-[color:var(--warning)] text-foreground [&>svg]:text-[color:var(--warning)]",
104
+ destructive: "bg-[color:var(--destructive)]/10 dark:bg-[color:var(--destructive)]/20 border-l-[color:var(--destructive)] text-foreground [&>svg]:text-[color:var(--destructive)]"
105
+ }
106
+ },
107
+ defaultVariants: {
108
+ variant: "default"
109
+ }
110
+ }
111
+ );
112
+ const alertIcons = {
113
+ default: lucideReact.Info,
114
+ success: lucideReact.CheckCircle,
115
+ info: lucideReact.Info,
116
+ warning: lucideReact.AlertTriangle,
117
+ destructive: lucideReact.XCircle
118
+ };
119
+ function Alert({ className, variant, icon, children, ...props }) {
120
+ const alertVariant = variant && variant in alertIcons ? variant : "default";
121
+ const DefaultIcon = alertIcons[alertVariant];
122
+ return /* @__PURE__ */ jsxRuntime.jsxs(
123
+ "div",
124
+ {
125
+ "data-slot": "alert",
126
+ role: "alert",
127
+ className: button.cn(alertVariants({ variant }), className),
128
+ ...props,
129
+ children: [
130
+ icon !== void 0 ? icon : /* @__PURE__ */ jsxRuntime.jsx(DefaultIcon, { className: "flex-shrink-0" }),
131
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children })
132
+ ]
133
+ }
134
+ );
135
+ }
136
+ function AlertTitle({ className, ...props }) {
137
+ return /* @__PURE__ */ jsxRuntime.jsx(
138
+ "div",
139
+ {
140
+ "data-slot": "alert-title",
141
+ className: button.cn("font-medium mb-1 leading-tight", className),
142
+ ...props
143
+ }
144
+ );
145
+ }
146
+ function AlertDescription({ className, ...props }) {
147
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "alert-description", className: button.cn("leading-relaxed", className), ...props });
148
+ }
149
+
150
+ const Empty = React__namespace.forwardRef(
151
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
152
+ "div",
153
+ {
154
+ ref,
155
+ className: button.cn(
156
+ "flex min-h-[400px] flex-col items-center justify-center rounded-[var(--radius-card)] border border-dashed border-border p-8 text-center animate-in fade-in-50",
157
+ className
158
+ ),
159
+ ...props
160
+ }
161
+ )
162
+ );
163
+ Empty.displayName = "Empty";
164
+ const EmptyIcon = React__namespace.forwardRef(
165
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
166
+ "div",
167
+ {
168
+ ref,
169
+ className: button.cn(
170
+ "mx-auto flex h-20 w-20 items-center justify-center rounded-full bg-muted",
171
+ className
172
+ ),
173
+ ...props
174
+ }
175
+ )
176
+ );
177
+ EmptyIcon.displayName = "EmptyIcon";
178
+ const EmptyImage = React__namespace.forwardRef(
179
+ ({ className, alt, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
180
+ "img",
181
+ {
182
+ ref,
183
+ alt,
184
+ className: button.cn("mx-auto mb-4 h-48 w-48 object-contain opacity-50", className),
185
+ ...props
186
+ }
187
+ )
188
+ );
189
+ EmptyImage.displayName = "EmptyImage";
190
+ const EmptyTitle = React__namespace.forwardRef(
191
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: button.cn("mt-4 font-semibold text-foreground", className), ...props })
192
+ );
193
+ EmptyTitle.displayName = "EmptyTitle";
194
+ const EmptyDescription = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
195
+ "p",
196
+ {
197
+ ref,
198
+ className: button.cn("mt-2 text-sm text-muted-foreground max-w-sm mx-auto", className),
199
+ ...props
200
+ }
201
+ ));
202
+ EmptyDescription.displayName = "EmptyDescription";
203
+ const EmptyAction = React__namespace.forwardRef(
204
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
205
+ "div",
206
+ {
207
+ ref,
208
+ className: button.cn("mt-6 flex flex-col gap-2 sm:flex-row sm:gap-4", className),
209
+ ...props
210
+ }
211
+ )
212
+ );
213
+ EmptyAction.displayName = "EmptyAction";
214
+
215
+ const THEMES = { light: "", dark: ".dark" };
216
+ const defaultPeriods = [
217
+ { value: "7d", label: "7 days" },
218
+ { value: "30d", label: "30 days" },
219
+ { value: "90d", label: "90 days" }
220
+ ];
221
+ const defaultChartColors = [
222
+ "var(--chart-1)",
223
+ "var(--chart-2)",
224
+ "var(--chart-3)",
225
+ "var(--chart-4)",
226
+ "var(--chart-5)",
227
+ "var(--chart-6)",
228
+ "var(--chart-7)",
229
+ "var(--chart-8)"
230
+ ];
231
+ const chartBarSizes = {
232
+ sm: 8,
233
+ md: 14,
234
+ lg: 22,
235
+ xl: 32
236
+ };
237
+ const ChartContext = React__namespace.createContext(null);
238
+ function useChart() {
239
+ const context = React__namespace.useContext(ChartContext);
240
+ if (!context) {
241
+ throw new Error("useChart must be used within a <ChartContainer />");
242
+ }
243
+ return context;
244
+ }
245
+ function ChartContainer({
246
+ id,
247
+ className,
248
+ children,
249
+ config,
250
+ ...props
251
+ }) {
252
+ const uniqueId = React__namespace.useId();
253
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
254
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxRuntime.jsxs(
255
+ "div",
256
+ {
257
+ "data-slot": "chart",
258
+ "data-chart": chartId,
259
+ className: button.cn(
260
+ "[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border relative h-[300px] min-h-[200px] w-full min-w-0 overflow-hidden text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
261
+ className
262
+ ),
263
+ ...props,
264
+ children: [
265
+ /* @__PURE__ */ jsxRuntime.jsx(ChartStyle, { id: chartId, config }),
266
+ /* @__PURE__ */ jsxRuntime.jsx(RechartsPrimitive__namespace.ResponsiveContainer, { width: "100%", height: "100%", children })
267
+ ]
268
+ }
269
+ ) });
270
+ }
271
+ const ChartStyle = ({ id, config }) => {
272
+ const colorConfig = Object.entries(config).filter(([, config2]) => config2.theme || config2.color);
273
+ if (!colorConfig.length) {
274
+ return null;
275
+ }
276
+ return /* @__PURE__ */ jsxRuntime.jsx(
277
+ "style",
278
+ {
279
+ dangerouslySetInnerHTML: {
280
+ __html: Object.entries(THEMES).map(
281
+ ([theme, prefix]) => `
282
+ ${prefix} [data-chart=${id}] {
283
+ ${colorConfig.map(([key, itemConfig]) => {
284
+ const color = itemConfig.theme?.[theme] || itemConfig.color;
285
+ return color ? ` --color-${key}: ${color};` : null;
286
+ }).join("\n")}
287
+ }
288
+ `
289
+ ).join("\n")
290
+ }
291
+ }
292
+ );
293
+ };
294
+ const ChartTooltip = RechartsPrimitive__namespace.Tooltip;
295
+ function ChartTooltipContent({
296
+ active,
297
+ payload,
298
+ className,
299
+ indicator = "dot",
300
+ hideLabel = false,
301
+ hideIndicator = false,
302
+ label,
303
+ labelFormatter,
304
+ labelClassName,
305
+ formatter,
306
+ color,
307
+ nameKey,
308
+ labelKey
309
+ }) {
310
+ const { config } = useChart();
311
+ const tooltipLabel = React__namespace.useMemo(() => {
312
+ if (hideLabel || !payload?.length) {
313
+ return null;
314
+ }
315
+ const [item] = payload;
316
+ const key = `${labelKey || item?.dataKey || item?.name || "value"}`;
317
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
318
+ const value = !labelKey && typeof label === "string" ? config[label]?.label || label : itemConfig?.label;
319
+ if (labelFormatter) {
320
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: button.cn("font-medium", labelClassName), children: labelFormatter(value, payload) });
321
+ }
322
+ if (!value) {
323
+ return null;
324
+ }
325
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: button.cn("font-medium", labelClassName), children: value });
326
+ }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);
327
+ if (!active || !payload?.length) {
328
+ return null;
329
+ }
330
+ const nestLabel = payload.length === 1 && indicator !== "dot";
331
+ return /* @__PURE__ */ jsxRuntime.jsxs(
332
+ "div",
333
+ {
334
+ className: button.cn(
335
+ "border-border/50 bg-background/95 backdrop-blur-sm grid min-w-[8rem] items-start gap-1.5 rounded-xl border px-3 py-2 text-xs shadow-xl",
336
+ className
337
+ ),
338
+ children: [
339
+ !nestLabel ? tooltipLabel : null,
340
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-1.5", children: payload.map((item, index) => {
341
+ const key = `${nameKey || item.name || item.dataKey || "value"}`;
342
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
343
+ const indicatorColor = color || item.payload?.fill || item.color;
344
+ return /* @__PURE__ */ jsxRuntime.jsx(
345
+ "div",
346
+ {
347
+ className: button.cn(
348
+ "[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
349
+ indicator === "dot" && "items-center"
350
+ ),
351
+ children: formatter && item?.value !== void 0 && item.name ? formatter(item.value, item.name, item, index, item.payload) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
352
+ itemConfig?.icon ? /* @__PURE__ */ jsxRuntime.jsx(itemConfig.icon, {}) : !hideIndicator && /* @__PURE__ */ jsxRuntime.jsx(
353
+ "div",
354
+ {
355
+ className: button.cn(
356
+ "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
357
+ {
358
+ "h-2.5 w-2.5": indicator === "dot",
359
+ "w-1": indicator === "line",
360
+ "w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
361
+ "my-0.5": nestLabel && indicator === "dashed"
362
+ }
363
+ ),
364
+ style: {
365
+ "--color-bg": indicatorColor,
366
+ "--color-border": indicatorColor
367
+ }
368
+ }
369
+ ),
370
+ /* @__PURE__ */ jsxRuntime.jsxs(
371
+ "div",
372
+ {
373
+ className: button.cn(
374
+ "flex flex-1 justify-between leading-none",
375
+ nestLabel ? "items-end" : "items-center"
376
+ ),
377
+ children: [
378
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-1.5", children: [
379
+ nestLabel ? tooltipLabel : null,
380
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: itemConfig?.label || item.name })
381
+ ] }),
382
+ item.value && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground font-mono font-semibold tabular-nums", children: item.value.toLocaleString() })
383
+ ]
384
+ }
385
+ )
386
+ ] })
387
+ },
388
+ `${item.dataKey ?? index}`
389
+ );
390
+ }) })
391
+ ]
392
+ }
393
+ );
394
+ }
395
+ const ChartLegend = RechartsPrimitive__namespace.Legend;
396
+ function ChartLegendContent({
397
+ className,
398
+ hideIcon = false,
399
+ payload,
400
+ verticalAlign = "bottom",
401
+ nameKey
402
+ }) {
403
+ const { config } = useChart();
404
+ if (!payload?.length) {
405
+ return null;
406
+ }
407
+ return /* @__PURE__ */ jsxRuntime.jsx(
408
+ "div",
409
+ {
410
+ className: button.cn(
411
+ "flex items-center justify-center gap-4",
412
+ verticalAlign === "top" ? "pb-3" : "pt-3",
413
+ className
414
+ ),
415
+ children: payload.map((item) => {
416
+ const key = `${nameKey ? item.value : item.dataKey || item.value || "value"}`;
417
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
418
+ return /* @__PURE__ */ jsxRuntime.jsxs(
419
+ "div",
420
+ {
421
+ className: button.cn(
422
+ "[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3"
423
+ ),
424
+ children: [
425
+ itemConfig?.icon && !hideIcon ? /* @__PURE__ */ jsxRuntime.jsx(itemConfig.icon, {}) : /* @__PURE__ */ jsxRuntime.jsx(
426
+ "div",
427
+ {
428
+ className: "h-2 w-2 shrink-0 rounded-full bg-(--color-bg)",
429
+ style: {
430
+ "--color-bg": item.color || `var(--color-${key})`
431
+ }
432
+ }
433
+ ),
434
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs", children: itemConfig?.label || item.value })
435
+ ]
436
+ },
437
+ item.value
438
+ );
439
+ })
440
+ }
441
+ );
442
+ }
443
+ function getPayloadConfigFromPayload(config, payload, key) {
444
+ if (typeof payload !== "object" || payload === null) {
445
+ return void 0;
446
+ }
447
+ const payloadPayload = "payload" in payload && typeof payload.payload === "object" && payload.payload !== null ? payload.payload : void 0;
448
+ let configLabelKey = key;
449
+ if (key in payload && typeof payload[key] === "string") {
450
+ configLabelKey = payload[key];
451
+ } else if (payloadPayload && key in payloadPayload && typeof payloadPayload[key] === "string") {
452
+ configLabelKey = payloadPayload[key];
453
+ }
454
+ return configLabelKey in config ? config[configLabelKey] : config[key];
455
+ }
456
+ function getChartSeries(config, series) {
457
+ if (series?.length) {
458
+ return series;
459
+ }
460
+ return Object.entries(config).map(([key, item]) => ({
461
+ key,
462
+ label: item.label
463
+ }));
464
+ }
465
+ function getSeriesColor(key, index, colors) {
466
+ if (Array.isArray(colors)) {
467
+ return colors[index] || defaultChartColors[index % defaultChartColors.length];
468
+ }
469
+ return colors?.[key] || defaultChartColors[index % defaultChartColors.length];
470
+ }
471
+ function getChartConfigWithColors(config, keys, colors) {
472
+ return keys.reduce((nextConfig, key, index) => {
473
+ const item = config[key];
474
+ if (item?.theme && !colors) {
475
+ nextConfig[key] = item;
476
+ return nextConfig;
477
+ }
478
+ nextConfig[key] = {
479
+ label: item?.label || key,
480
+ icon: item?.icon,
481
+ color: colors ? getSeriesColor(key, index, colors) : item?.color || getSeriesColor(key, index)
482
+ };
483
+ return nextConfig;
484
+ }, {});
485
+ }
486
+ function buildChartConfig(keys, colors) {
487
+ return keys.reduce((cfg, key, index) => {
488
+ cfg[key] = {
489
+ label: key,
490
+ color: getSeriesColor(key, index, colors)
491
+ };
492
+ return cfg;
493
+ }, {});
494
+ }
495
+ function formatTick(value) {
496
+ if (typeof value !== "number") {
497
+ return value;
498
+ }
499
+ return Intl.NumberFormat("en", {
500
+ notation: "compact",
501
+ maximumFractionDigits: 1
502
+ }).format(value);
503
+ }
504
+ function defaultFilterData(data, period) {
505
+ const match = period.match(/^(\d+)/);
506
+ if (!match) {
507
+ return data;
508
+ }
509
+ const limit = Number(match[1]);
510
+ return data.slice(Math.max(data.length - limit, 0));
511
+ }
512
+ function getErrorDescription(error) {
513
+ if (typeof error === "string") {
514
+ return error;
515
+ }
516
+ if (error instanceof Error) {
517
+ return error.message;
518
+ }
519
+ return void 0;
520
+ }
521
+ function getBarSize(barSize = "md") {
522
+ return typeof barSize === "number" ? barSize : chartBarSizes[barSize];
523
+ }
524
+ function hasChartData(data, series) {
525
+ if (!data.length || !series.length) {
526
+ return false;
527
+ }
528
+ return data.some(
529
+ (item) => series.some((serie) => {
530
+ const value = item[serie.key];
531
+ return value !== null && value !== void 0 && value !== "";
532
+ })
533
+ );
534
+ }
535
+ function hasPieData(data, nameKey, valueKey) {
536
+ return data.some((item) => {
537
+ const name = item[nameKey];
538
+ const value = item[valueKey];
539
+ return name !== null && name !== void 0 && name !== "" && value !== null && value !== void 0 && value !== "";
540
+ });
541
+ }
542
+ function ChartState({
543
+ type,
544
+ className,
545
+ error,
546
+ onRetry,
547
+ retryLabel = "Try again",
548
+ emptyTitle = "No data available",
549
+ emptyDescription = "There is no data available for this chart yet.",
550
+ errorTitle = "Connection error",
551
+ errorDescription,
552
+ loadingLabel = "Loading chart data"
553
+ }) {
554
+ if (type === "loading") {
555
+ return /* @__PURE__ */ jsxRuntime.jsxs(
556
+ "div",
557
+ {
558
+ className: button.cn(
559
+ "flex min-h-[240px] flex-col justify-end gap-3 rounded-[var(--radius-card)] border border-border p-6",
560
+ className
561
+ ),
562
+ "aria-label": typeof loadingLabel === "string" ? loadingLabel : void 0,
563
+ children: [
564
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-8 w-2/5" }),
565
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-14 w-3/5" }),
566
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-24 w-4/5" }),
567
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-36 w-full" })
568
+ ]
569
+ }
570
+ );
571
+ }
572
+ if (type === "error") {
573
+ return /* @__PURE__ */ jsxRuntime.jsx(
574
+ "div",
575
+ {
576
+ className: button.cn(
577
+ "flex min-h-[240px] items-center justify-center rounded-[var(--radius-card)] border border-border p-6",
578
+ className
579
+ ),
580
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Alert, { variant: "destructive", className: "max-w-xl", children: [
581
+ /* @__PURE__ */ jsxRuntime.jsx(AlertTitle, { children: errorTitle }),
582
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDescription, { children: errorDescription || getErrorDescription(error) || "Unable to load chart data. Check your connection and try again." }),
583
+ onRetry ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsxs(button.Button, { size: "sm", variant: "outline", onClick: onRetry, children: [
584
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "size-4" }),
585
+ retryLabel
586
+ ] }) }) : null
587
+ ] })
588
+ }
589
+ );
590
+ }
591
+ return /* @__PURE__ */ jsxRuntime.jsxs(Empty, { className: button.cn("min-h-[240px]", className), children: [
592
+ /* @__PURE__ */ jsxRuntime.jsx(EmptyIcon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BarChart3, { className: "size-10 text-muted-foreground" }) }),
593
+ /* @__PURE__ */ jsxRuntime.jsx(EmptyTitle, { children: emptyTitle }),
594
+ /* @__PURE__ */ jsxRuntime.jsx(EmptyDescription, { children: emptyDescription }),
595
+ onRetry ? /* @__PURE__ */ jsxRuntime.jsx(EmptyAction, { children: /* @__PURE__ */ jsxRuntime.jsxs(button.Button, { size: "sm", variant: "outline", onClick: onRetry, children: [
596
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WifiOff, { className: "size-4" }),
597
+ retryLabel
598
+ ] }) }) : null
599
+ ] });
600
+ }
601
+ function getChartState(state, hasData, className) {
602
+ if (state.isLoading) {
603
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartState, { ...state, type: "loading", className });
604
+ }
605
+ if (state.error) {
606
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartState, { ...state, type: "error", className });
607
+ }
608
+ if (!hasData) {
609
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartState, { ...state, type: "empty", className });
610
+ }
611
+ return null;
612
+ }
613
+ function ChartCard({
614
+ title,
615
+ description,
616
+ action,
617
+ footer,
618
+ children,
619
+ className,
620
+ contentClassName,
621
+ ...props
622
+ }) {
623
+ return /* @__PURE__ */ jsxRuntime.jsxs(skeleton.Card, { className: button.cn("w-full min-w-0 overflow-hidden", className), ...props, children: [
624
+ /* @__PURE__ */ jsxRuntime.jsxs(skeleton.CardHeader, { children: [
625
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.CardTitle, { children: title }),
626
+ description ? /* @__PURE__ */ jsxRuntime.jsx(skeleton.CardDescription, { children: description }) : null,
627
+ action ? /* @__PURE__ */ jsxRuntime.jsx(skeleton.CardAction, { children: action }) : null
628
+ ] }),
629
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.CardContent, { className: contentClassName, children }),
630
+ footer ? /* @__PURE__ */ jsxRuntime.jsx(skeleton.CardFooter, { children: footer }) : null
631
+ ] });
632
+ }
633
+ function AreaGradientDefs({
634
+ seriesKeys,
635
+ opacity = 0.3
636
+ }) {
637
+ return /* @__PURE__ */ jsxRuntime.jsx("defs", { children: seriesKeys.map((key) => /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: `gradient-${key}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
638
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "5%", stopColor: `var(--color-${key})`, stopOpacity: opacity }),
639
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "95%", stopColor: `var(--color-${key})`, stopOpacity: 0 })
640
+ ] }, key)) });
641
+ }
642
+ function DashboardBarChart({
643
+ data,
644
+ config,
645
+ indexKey = "name",
646
+ series,
647
+ colors,
648
+ barSize = "md",
649
+ stacked = false,
650
+ showGrid = true,
651
+ showLegend = true,
652
+ valueFormatter = formatTick,
653
+ isLoading,
654
+ error,
655
+ onRetry,
656
+ retryLabel,
657
+ emptyTitle,
658
+ emptyDescription,
659
+ errorTitle,
660
+ errorDescription,
661
+ loadingLabel,
662
+ stateClassName,
663
+ className,
664
+ ...props
665
+ }) {
666
+ const chartSeries = getChartSeries(config, series);
667
+ const chartConfig = getChartConfigWithColors(
668
+ config,
669
+ chartSeries.map((item) => item.key),
670
+ colors
671
+ );
672
+ const chartState = getChartState(
673
+ {
674
+ isLoading,
675
+ error,
676
+ onRetry,
677
+ retryLabel,
678
+ emptyTitle,
679
+ emptyDescription,
680
+ errorTitle,
681
+ errorDescription,
682
+ loadingLabel
683
+ },
684
+ hasChartData(data, chartSeries),
685
+ button.cn("h-[320px] w-full", stateClassName)
686
+ );
687
+ const barElements = React__namespace.useMemo(() => {
688
+ const topOfStack = /* @__PURE__ */ new Set();
689
+ if (stacked) {
690
+ const lastByStack = /* @__PURE__ */ new Map();
691
+ chartSeries.forEach((s) => lastByStack.set(s.stackId || "total", s.key));
692
+ lastByStack.forEach((key) => topOfStack.add(key));
693
+ }
694
+ return chartSeries.map((item) => {
695
+ const isTop = !stacked || topOfStack.has(item.key);
696
+ return /* @__PURE__ */ jsxRuntime.jsx(
697
+ RechartsPrimitive__namespace.Bar,
698
+ {
699
+ dataKey: item.key,
700
+ fill: `var(--color-${item.key})`,
701
+ radius: isTop ? [4, 4, 0, 0] : [0, 0, 0, 0],
702
+ barSize: getBarSize(barSize),
703
+ stackId: stacked ? item.stackId || "total" : item.stackId,
704
+ isAnimationActive: true,
705
+ animationDuration: 600,
706
+ animationEasing: "ease-out"
707
+ },
708
+ item.key
709
+ );
710
+ });
711
+ }, [stacked, chartSeries]);
712
+ if (chartState) {
713
+ return chartState;
714
+ }
715
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: button.cn("h-[320px] w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(RechartsPrimitive__namespace.BarChart, { data, accessibilityLayer: true, barGap: 4, children: [
716
+ showGrid ? /* @__PURE__ */ jsxRuntime.jsx(
717
+ RechartsPrimitive__namespace.CartesianGrid,
718
+ {
719
+ vertical: false,
720
+ strokeDasharray: "3 3",
721
+ stroke: "var(--border)",
722
+ strokeOpacity: 0.5
723
+ }
724
+ ) : null,
725
+ /* @__PURE__ */ jsxRuntime.jsx(
726
+ RechartsPrimitive__namespace.XAxis,
727
+ {
728
+ dataKey: indexKey,
729
+ tickLine: false,
730
+ axisLine: false,
731
+ tickMargin: 8
732
+ }
733
+ ),
734
+ /* @__PURE__ */ jsxRuntime.jsx(
735
+ RechartsPrimitive__namespace.YAxis,
736
+ {
737
+ tickLine: false,
738
+ axisLine: false,
739
+ tickMargin: 8,
740
+ tickFormatter: valueFormatter
741
+ }
742
+ ),
743
+ /* @__PURE__ */ jsxRuntime.jsx(
744
+ ChartTooltip,
745
+ {
746
+ cursor: { fill: "var(--muted)", opacity: 0.4, radius: 4 },
747
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, {})
748
+ }
749
+ ),
750
+ showLegend ? /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {}) }) : null,
751
+ barElements
752
+ ] }) });
753
+ }
754
+ function DashboardLineChart({
755
+ data,
756
+ config,
757
+ indexKey = "name",
758
+ series,
759
+ colors,
760
+ showDots = false,
761
+ showGrid = true,
762
+ showLegend = true,
763
+ curveType = "monotone",
764
+ strokeWidth = 2,
765
+ valueFormatter = formatTick,
766
+ isLoading,
767
+ error,
768
+ onRetry,
769
+ retryLabel,
770
+ emptyTitle,
771
+ emptyDescription,
772
+ errorTitle,
773
+ errorDescription,
774
+ loadingLabel,
775
+ stateClassName,
776
+ className,
777
+ ...props
778
+ }) {
779
+ const chartSeries = getChartSeries(config, series);
780
+ const chartConfig = getChartConfigWithColors(
781
+ config,
782
+ chartSeries.map((item) => item.key),
783
+ colors
784
+ );
785
+ const chartState = getChartState(
786
+ {
787
+ isLoading,
788
+ error,
789
+ onRetry,
790
+ retryLabel,
791
+ emptyTitle,
792
+ emptyDescription,
793
+ errorTitle,
794
+ errorDescription,
795
+ loadingLabel
796
+ },
797
+ hasChartData(data, chartSeries),
798
+ button.cn("h-[320px] w-full", stateClassName)
799
+ );
800
+ if (chartState) {
801
+ return chartState;
802
+ }
803
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: button.cn("h-[320px] w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(RechartsPrimitive__namespace.LineChart, { data, accessibilityLayer: true, children: [
804
+ showGrid ? /* @__PURE__ */ jsxRuntime.jsx(
805
+ RechartsPrimitive__namespace.CartesianGrid,
806
+ {
807
+ vertical: false,
808
+ strokeDasharray: "3 3",
809
+ stroke: "var(--border)",
810
+ strokeOpacity: 0.5
811
+ }
812
+ ) : null,
813
+ /* @__PURE__ */ jsxRuntime.jsx(
814
+ RechartsPrimitive__namespace.XAxis,
815
+ {
816
+ dataKey: indexKey,
817
+ tickLine: false,
818
+ axisLine: false,
819
+ tickMargin: 8
820
+ }
821
+ ),
822
+ /* @__PURE__ */ jsxRuntime.jsx(
823
+ RechartsPrimitive__namespace.YAxis,
824
+ {
825
+ tickLine: false,
826
+ axisLine: false,
827
+ tickMargin: 8,
828
+ tickFormatter: valueFormatter
829
+ }
830
+ ),
831
+ /* @__PURE__ */ jsxRuntime.jsx(ChartTooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, { indicator: "line" }) }),
832
+ showLegend ? /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {}) }) : null,
833
+ chartSeries.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
834
+ RechartsPrimitive__namespace.Line,
835
+ {
836
+ type: curveType,
837
+ dataKey: item.key,
838
+ stroke: `var(--color-${item.key})`,
839
+ strokeWidth,
840
+ dot: showDots ? { r: 3, fill: `var(--color-${item.key})`, strokeWidth: 0 } : false,
841
+ activeDot: { r: 5, strokeWidth: 0 },
842
+ yAxisId: item.yAxisId,
843
+ isAnimationActive: true,
844
+ animationDuration: 600,
845
+ animationEasing: "ease-out"
846
+ },
847
+ item.key
848
+ ))
849
+ ] }) });
850
+ }
851
+ function HorizontalBarChart({
852
+ data,
853
+ config,
854
+ indexKey = "name",
855
+ series,
856
+ colors,
857
+ barSize = "md",
858
+ stacked = false,
859
+ categoryWidth = 96,
860
+ showGrid = true,
861
+ showLegend = true,
862
+ valueFormatter = formatTick,
863
+ isLoading,
864
+ error,
865
+ onRetry,
866
+ retryLabel,
867
+ emptyTitle,
868
+ emptyDescription,
869
+ errorTitle,
870
+ errorDescription,
871
+ loadingLabel,
872
+ stateClassName,
873
+ className,
874
+ ...props
875
+ }) {
876
+ const chartSeries = getChartSeries(config, series);
877
+ const chartConfig = getChartConfigWithColors(
878
+ config,
879
+ chartSeries.map((item) => item.key),
880
+ colors
881
+ );
882
+ const chartState = getChartState(
883
+ {
884
+ isLoading,
885
+ error,
886
+ onRetry,
887
+ retryLabel,
888
+ emptyTitle,
889
+ emptyDescription,
890
+ errorTitle,
891
+ errorDescription,
892
+ loadingLabel
893
+ },
894
+ hasChartData(data, chartSeries),
895
+ button.cn("h-[320px] w-full", stateClassName)
896
+ );
897
+ if (chartState) {
898
+ return chartState;
899
+ }
900
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: button.cn("h-[320px] w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(
901
+ RechartsPrimitive__namespace.BarChart,
902
+ {
903
+ data,
904
+ layout: "vertical",
905
+ accessibilityLayer: true,
906
+ margin: { left: 8, right: 16 },
907
+ children: [
908
+ showGrid ? /* @__PURE__ */ jsxRuntime.jsx(
909
+ RechartsPrimitive__namespace.CartesianGrid,
910
+ {
911
+ horizontal: false,
912
+ strokeDasharray: "3 3",
913
+ stroke: "var(--border)",
914
+ strokeOpacity: 0.5
915
+ }
916
+ ) : null,
917
+ /* @__PURE__ */ jsxRuntime.jsx(
918
+ RechartsPrimitive__namespace.XAxis,
919
+ {
920
+ type: "number",
921
+ tickLine: false,
922
+ axisLine: false,
923
+ tickMargin: 8,
924
+ tickFormatter: valueFormatter
925
+ }
926
+ ),
927
+ /* @__PURE__ */ jsxRuntime.jsx(
928
+ RechartsPrimitive__namespace.YAxis,
929
+ {
930
+ dataKey: indexKey,
931
+ type: "category",
932
+ tickLine: false,
933
+ axisLine: false,
934
+ tickMargin: 8,
935
+ width: categoryWidth
936
+ }
937
+ ),
938
+ /* @__PURE__ */ jsxRuntime.jsx(ChartTooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, {}) }),
939
+ showLegend ? /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {}) }) : null,
940
+ chartSeries.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
941
+ RechartsPrimitive__namespace.Bar,
942
+ {
943
+ dataKey: item.key,
944
+ fill: `var(--color-${item.key})`,
945
+ radius: [0, 4, 4, 0],
946
+ barSize: getBarSize(barSize),
947
+ stackId: stacked ? item.stackId || "total" : item.stackId,
948
+ isAnimationActive: true,
949
+ animationDuration: 600,
950
+ animationEasing: "ease-out"
951
+ },
952
+ item.key
953
+ ))
954
+ ]
955
+ }
956
+ ) });
957
+ }
958
+ function InteractiveTimeSeriesChart({
959
+ data,
960
+ config,
961
+ indexKey = "date",
962
+ series,
963
+ colors,
964
+ periods = defaultPeriods,
965
+ defaultPeriod = periods[1]?.value || periods[0]?.value || "30d",
966
+ defaultSeries,
967
+ filterData = defaultFilterData,
968
+ showGrid = true,
969
+ showLegend = false,
970
+ showDots = false,
971
+ gradientFill = true,
972
+ curveType = "monotone",
973
+ strokeWidth = 2,
974
+ valueFormatter = formatTick,
975
+ isLoading,
976
+ error,
977
+ onRetry,
978
+ retryLabel,
979
+ emptyTitle,
980
+ emptyDescription,
981
+ errorTitle,
982
+ errorDescription,
983
+ loadingLabel,
984
+ stateClassName,
985
+ className,
986
+ ...props
987
+ }) {
988
+ const chartSeries = getChartSeries(config, series);
989
+ const chartConfig = getChartConfigWithColors(
990
+ config,
991
+ chartSeries.map((item) => item.key),
992
+ colors
993
+ );
994
+ const [period, setPeriod] = React__namespace.useState(defaultPeriod);
995
+ const [activeSeries, setActiveSeries] = React__namespace.useState(
996
+ defaultSeries || chartSeries[0]?.key || ""
997
+ );
998
+ const filteredData = React__namespace.useMemo(() => filterData(data, period), [data, filterData, period]);
999
+ const visibleSeries = chartSeries.length > 1 ? chartSeries.filter((item) => item.key === activeSeries) : chartSeries;
1000
+ const chartState = getChartState(
1001
+ {
1002
+ isLoading,
1003
+ error,
1004
+ onRetry,
1005
+ retryLabel,
1006
+ emptyTitle,
1007
+ emptyDescription,
1008
+ errorTitle,
1009
+ errorDescription,
1010
+ loadingLabel
1011
+ },
1012
+ hasChartData(filteredData, visibleSeries),
1013
+ button.cn("h-[320px] w-full", stateClassName)
1014
+ );
1015
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full space-y-4", children: [
1016
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
1017
+ chartSeries.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
1018
+ "div",
1019
+ {
1020
+ className: "inline-flex h-10 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
1021
+ role: "group",
1022
+ "aria-label": "Selecionar metrica do grafico",
1023
+ children: chartSeries.map((item) => {
1024
+ const label = item.label || config[item.key]?.label || item.key;
1025
+ return /* @__PURE__ */ jsxRuntime.jsx(
1026
+ button.Button,
1027
+ {
1028
+ type: "button",
1029
+ variant: "ghost",
1030
+ size: "sm",
1031
+ "aria-pressed": activeSeries === item.key,
1032
+ onClick: () => setActiveSeries(item.key),
1033
+ className: button.cn(
1034
+ "h-8 px-3 text-sm font-medium transition-all",
1035
+ activeSeries === item.key ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
1036
+ ),
1037
+ children: label
1038
+ },
1039
+ item.key
1040
+ );
1041
+ })
1042
+ }
1043
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
1044
+ /* @__PURE__ */ jsxRuntime.jsxs(select.Select, { value: period, onValueChange: setPeriod, children: [
1045
+ /* @__PURE__ */ jsxRuntime.jsx(
1046
+ select.SelectTrigger,
1047
+ {
1048
+ className: "w-full sm:w-[160px]",
1049
+ size: "sm",
1050
+ "aria-label": "Selecionar periodo do grafico",
1051
+ children: /* @__PURE__ */ jsxRuntime.jsx(select.SelectValue, { placeholder: "Period" })
1052
+ }
1053
+ ),
1054
+ /* @__PURE__ */ jsxRuntime.jsx(select.SelectContent, { children: periods.map((item) => /* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: item.value, children: item.label }, item.value)) })
1055
+ ] })
1056
+ ] }),
1057
+ chartState || /* @__PURE__ */ jsxRuntime.jsx(
1058
+ ChartContainer,
1059
+ {
1060
+ config: chartConfig,
1061
+ className: button.cn("h-[320px] w-full", className),
1062
+ ...props,
1063
+ children: /* @__PURE__ */ jsxRuntime.jsxs(RechartsPrimitive__namespace.AreaChart, { data: filteredData, accessibilityLayer: true, children: [
1064
+ gradientFill && /* @__PURE__ */ jsxRuntime.jsx(AreaGradientDefs, { seriesKeys: visibleSeries.map((s) => s.key), opacity: 0.4 }),
1065
+ showGrid ? /* @__PURE__ */ jsxRuntime.jsx(
1066
+ RechartsPrimitive__namespace.CartesianGrid,
1067
+ {
1068
+ vertical: false,
1069
+ strokeDasharray: "3 3",
1070
+ stroke: "var(--border)",
1071
+ strokeOpacity: 0.5
1072
+ }
1073
+ ) : null,
1074
+ /* @__PURE__ */ jsxRuntime.jsx(
1075
+ RechartsPrimitive__namespace.XAxis,
1076
+ {
1077
+ dataKey: indexKey,
1078
+ tickLine: false,
1079
+ axisLine: false,
1080
+ tickMargin: 8
1081
+ }
1082
+ ),
1083
+ /* @__PURE__ */ jsxRuntime.jsx(
1084
+ RechartsPrimitive__namespace.YAxis,
1085
+ {
1086
+ tickLine: false,
1087
+ axisLine: false,
1088
+ tickMargin: 8,
1089
+ tickFormatter: valueFormatter
1090
+ }
1091
+ ),
1092
+ /* @__PURE__ */ jsxRuntime.jsx(ChartTooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, { indicator: "line" }) }),
1093
+ showLegend ? /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {}) }) : null,
1094
+ visibleSeries.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1095
+ RechartsPrimitive__namespace.Area,
1096
+ {
1097
+ type: curveType,
1098
+ dataKey: item.key,
1099
+ stroke: `var(--color-${item.key})`,
1100
+ fill: gradientFill ? `url(#gradient-${item.key})` : `var(--color-${item.key})`,
1101
+ fillOpacity: gradientFill ? 1 : 0.16,
1102
+ strokeWidth,
1103
+ dot: showDots ? { r: 3, fill: `var(--color-${item.key})`, strokeWidth: 0 } : false,
1104
+ activeDot: { r: 5, strokeWidth: 0 },
1105
+ isAnimationActive: true,
1106
+ animationDuration: 600,
1107
+ animationEasing: "ease-out"
1108
+ },
1109
+ item.key
1110
+ ))
1111
+ ] })
1112
+ }
1113
+ )
1114
+ ] });
1115
+ }
1116
+ function ComboMetricChart({
1117
+ data,
1118
+ config,
1119
+ indexKey = "name",
1120
+ series,
1121
+ colors,
1122
+ barSize = "md",
1123
+ showGrid = true,
1124
+ showLegend = true,
1125
+ gradientFill = false,
1126
+ curveType = "monotone",
1127
+ valueFormatter = formatTick,
1128
+ isLoading,
1129
+ error,
1130
+ onRetry,
1131
+ retryLabel,
1132
+ emptyTitle,
1133
+ emptyDescription,
1134
+ errorTitle,
1135
+ errorDescription,
1136
+ loadingLabel,
1137
+ stateClassName,
1138
+ className,
1139
+ ...props
1140
+ }) {
1141
+ const chartSeries = getChartSeries(config, series);
1142
+ const chartConfig = getChartConfigWithColors(
1143
+ config,
1144
+ chartSeries.map((item) => item.key),
1145
+ colors
1146
+ );
1147
+ const chartState = getChartState(
1148
+ {
1149
+ isLoading,
1150
+ error,
1151
+ onRetry,
1152
+ retryLabel,
1153
+ emptyTitle,
1154
+ emptyDescription,
1155
+ errorTitle,
1156
+ errorDescription,
1157
+ loadingLabel
1158
+ },
1159
+ hasChartData(data, chartSeries),
1160
+ button.cn("h-[340px] w-full", stateClassName)
1161
+ );
1162
+ if (chartState) {
1163
+ return chartState;
1164
+ }
1165
+ const areaSeries = gradientFill ? chartSeries.filter((s) => s.type === "area").map((s) => s.key) : [];
1166
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: button.cn("h-[340px] w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(RechartsPrimitive__namespace.ComposedChart, { data, accessibilityLayer: true, children: [
1167
+ gradientFill && areaSeries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(AreaGradientDefs, { seriesKeys: areaSeries, opacity: 0.35 }),
1168
+ showGrid ? /* @__PURE__ */ jsxRuntime.jsx(
1169
+ RechartsPrimitive__namespace.CartesianGrid,
1170
+ {
1171
+ vertical: false,
1172
+ strokeDasharray: "3 3",
1173
+ stroke: "var(--border)",
1174
+ strokeOpacity: 0.5
1175
+ }
1176
+ ) : null,
1177
+ /* @__PURE__ */ jsxRuntime.jsx(
1178
+ RechartsPrimitive__namespace.XAxis,
1179
+ {
1180
+ dataKey: indexKey,
1181
+ tickLine: false,
1182
+ axisLine: false,
1183
+ tickMargin: 8
1184
+ }
1185
+ ),
1186
+ /* @__PURE__ */ jsxRuntime.jsx(
1187
+ RechartsPrimitive__namespace.YAxis,
1188
+ {
1189
+ tickLine: false,
1190
+ axisLine: false,
1191
+ tickMargin: 8,
1192
+ tickFormatter: valueFormatter
1193
+ }
1194
+ ),
1195
+ /* @__PURE__ */ jsxRuntime.jsx(ChartTooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, {}) }),
1196
+ showLegend ? /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {}) }) : null,
1197
+ chartSeries.map(
1198
+ (item) => item.type === "line" ? /* @__PURE__ */ jsxRuntime.jsx(
1199
+ RechartsPrimitive__namespace.Line,
1200
+ {
1201
+ type: curveType,
1202
+ dataKey: item.key,
1203
+ stroke: `var(--color-${item.key})`,
1204
+ strokeWidth: 2,
1205
+ dot: false,
1206
+ activeDot: { r: 5, strokeWidth: 0 },
1207
+ yAxisId: item.yAxisId,
1208
+ isAnimationActive: true,
1209
+ animationDuration: 600,
1210
+ animationEasing: "ease-out"
1211
+ },
1212
+ item.key
1213
+ ) : item.type === "area" ? /* @__PURE__ */ jsxRuntime.jsx(
1214
+ RechartsPrimitive__namespace.Area,
1215
+ {
1216
+ type: curveType,
1217
+ dataKey: item.key,
1218
+ stroke: `var(--color-${item.key})`,
1219
+ fill: gradientFill ? `url(#gradient-${item.key})` : `var(--color-${item.key})`,
1220
+ fillOpacity: gradientFill ? 1 : 0.12,
1221
+ strokeWidth: 2,
1222
+ dot: false,
1223
+ activeDot: { r: 5, strokeWidth: 0 },
1224
+ yAxisId: item.yAxisId,
1225
+ isAnimationActive: true,
1226
+ animationDuration: 600,
1227
+ animationEasing: "ease-out"
1228
+ },
1229
+ item.key
1230
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1231
+ RechartsPrimitive__namespace.Bar,
1232
+ {
1233
+ dataKey: item.key,
1234
+ fill: `var(--color-${item.key})`,
1235
+ radius: [4, 4, 0, 0],
1236
+ barSize: getBarSize(barSize),
1237
+ yAxisId: item.yAxisId,
1238
+ isAnimationActive: true,
1239
+ animationDuration: 600,
1240
+ animationEasing: "ease-out"
1241
+ },
1242
+ item.key
1243
+ )
1244
+ )
1245
+ ] }) });
1246
+ }
1247
+ function DonutBreakdownChart({
1248
+ data,
1249
+ config,
1250
+ nameKey = "name",
1251
+ valueKey = "value",
1252
+ colors,
1253
+ centerLabel,
1254
+ centerValue,
1255
+ showLegend = true,
1256
+ innerRadius = "58%",
1257
+ outerRadius = "82%",
1258
+ isLoading,
1259
+ error,
1260
+ onRetry,
1261
+ retryLabel,
1262
+ emptyTitle,
1263
+ emptyDescription,
1264
+ errorTitle,
1265
+ errorDescription,
1266
+ loadingLabel,
1267
+ stateClassName,
1268
+ className,
1269
+ ...props
1270
+ }) {
1271
+ const [activeIndex, setActiveIndex] = React__namespace.useState(0);
1272
+ const chartKeys = data.map((entry, index) => String(entry[nameKey] || `segment-${index}`));
1273
+ const chartConfig = getChartConfigWithColors(config, chartKeys, colors);
1274
+ const chartState = getChartState(
1275
+ {
1276
+ isLoading,
1277
+ error,
1278
+ onRetry,
1279
+ retryLabel,
1280
+ emptyTitle,
1281
+ emptyDescription,
1282
+ errorTitle,
1283
+ errorDescription,
1284
+ loadingLabel
1285
+ },
1286
+ hasPieData(data, nameKey, valueKey),
1287
+ button.cn("h-[320px] w-full", stateClassName)
1288
+ );
1289
+ if (chartState) {
1290
+ return chartState;
1291
+ }
1292
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: button.cn("h-[320px] w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(RechartsPrimitive__namespace.PieChart, { accessibilityLayer: true, children: [
1293
+ /* @__PURE__ */ jsxRuntime.jsx(
1294
+ ChartTooltip,
1295
+ {
1296
+ cursor: false,
1297
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, { hideLabel: true, nameKey })
1298
+ }
1299
+ ),
1300
+ showLegend ? /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, { nameKey }), verticalAlign: "bottom" }) : null,
1301
+ /* @__PURE__ */ jsxRuntime.jsxs(
1302
+ RechartsPrimitive__namespace.Pie,
1303
+ {
1304
+ data,
1305
+ dataKey: valueKey,
1306
+ nameKey,
1307
+ innerRadius,
1308
+ outerRadius,
1309
+ paddingAngle: 3,
1310
+ onMouseEnter: (_, index) => setActiveIndex(index),
1311
+ isAnimationActive: true,
1312
+ animationDuration: 600,
1313
+ animationEasing: "ease-out",
1314
+ children: [
1315
+ data.map((entry, index) => {
1316
+ const key = String(entry[nameKey] || `segment-${index}`);
1317
+ return /* @__PURE__ */ jsxRuntime.jsx(
1318
+ RechartsPrimitive__namespace.Cell,
1319
+ {
1320
+ fill: `var(--color-${key})`,
1321
+ opacity: index === activeIndex ? 1 : 0.7,
1322
+ stroke: "transparent"
1323
+ },
1324
+ key
1325
+ );
1326
+ }),
1327
+ centerValue || centerLabel ? /* @__PURE__ */ jsxRuntime.jsx(
1328
+ RechartsPrimitive__namespace.Label,
1329
+ {
1330
+ position: "center",
1331
+ content: ({ viewBox }) => {
1332
+ if (!viewBox || !("cx" in viewBox) || !("cy" in viewBox)) {
1333
+ return null;
1334
+ }
1335
+ return /* @__PURE__ */ jsxRuntime.jsxs("text", { x: viewBox.cx, y: viewBox.cy, textAnchor: "middle", dominantBaseline: "middle", children: [
1336
+ centerValue ? /* @__PURE__ */ jsxRuntime.jsx(
1337
+ "tspan",
1338
+ {
1339
+ x: viewBox.cx,
1340
+ y: viewBox.cy,
1341
+ className: "fill-foreground text-2xl font-semibold",
1342
+ children: centerValue
1343
+ }
1344
+ ) : null,
1345
+ centerLabel ? /* @__PURE__ */ jsxRuntime.jsx(
1346
+ "tspan",
1347
+ {
1348
+ x: viewBox.cx,
1349
+ y: Number(viewBox.cy) + 22,
1350
+ className: "fill-muted-foreground text-xs",
1351
+ children: centerLabel
1352
+ }
1353
+ ) : null
1354
+ ] });
1355
+ }
1356
+ }
1357
+ ) : null
1358
+ ]
1359
+ }
1360
+ )
1361
+ ] }) });
1362
+ }
1363
+ function SparklineChart({
1364
+ data,
1365
+ dataKey,
1366
+ color = "var(--chart-1)",
1367
+ filled = true,
1368
+ showEndDot = true,
1369
+ curveType = "monotone",
1370
+ strokeWidth = 2,
1371
+ className
1372
+ }) {
1373
+ const sparkId = React__namespace.useId().replace(/:/g, "");
1374
+ const lastPoint = data[data.length - 1];
1375
+ const lastValue = lastPoint ? lastPoint[dataKey] : void 0;
1376
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: button.cn("relative h-12 w-full min-w-0", className), children: [
1377
+ /* @__PURE__ */ jsxRuntime.jsx(RechartsPrimitive__namespace.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1378
+ RechartsPrimitive__namespace.AreaChart,
1379
+ {
1380
+ data,
1381
+ margin: { top: 4, right: showEndDot ? 8 : 0, bottom: 0, left: 0 },
1382
+ children: [
1383
+ filled && /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: `spark-gradient-${sparkId}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
1384
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "5%", stopColor: color, stopOpacity: 0.3 }),
1385
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "95%", stopColor: color, stopOpacity: 0 })
1386
+ ] }) }),
1387
+ /* @__PURE__ */ jsxRuntime.jsx(
1388
+ RechartsPrimitive__namespace.Area,
1389
+ {
1390
+ type: curveType,
1391
+ dataKey,
1392
+ stroke: color,
1393
+ strokeWidth,
1394
+ fill: filled ? `url(#spark-gradient-${sparkId})` : "none",
1395
+ fillOpacity: 1,
1396
+ dot: false,
1397
+ activeDot: false,
1398
+ isAnimationActive: true,
1399
+ animationDuration: 600,
1400
+ animationEasing: "ease-out"
1401
+ }
1402
+ )
1403
+ ]
1404
+ }
1405
+ ) }),
1406
+ showEndDot && lastValue !== void 0 && lastValue !== null && /* @__PURE__ */ jsxRuntime.jsx(
1407
+ "div",
1408
+ {
1409
+ className: "pointer-events-none absolute right-0 top-1/2 h-2.5 w-2.5 -translate-y-1/2 rounded-full ring-2 ring-background",
1410
+ style: { backgroundColor: color }
1411
+ }
1412
+ )
1413
+ ] });
1414
+ }
1415
+ function RadarMetricChart({
1416
+ data,
1417
+ labelKey,
1418
+ series,
1419
+ colors,
1420
+ filled = true,
1421
+ fillOpacity = 0.25,
1422
+ showDots = false,
1423
+ showGrid = true,
1424
+ showLegend,
1425
+ valueFormatter,
1426
+ isLoading,
1427
+ error,
1428
+ onRetry,
1429
+ retryLabel,
1430
+ emptyTitle,
1431
+ emptyDescription,
1432
+ errorTitle,
1433
+ errorDescription,
1434
+ loadingLabel,
1435
+ stateClassName,
1436
+ className
1437
+ }) {
1438
+ const chartConfig = React__namespace.useMemo(
1439
+ () => buildChartConfig(
1440
+ series.map((s) => s.key),
1441
+ colors
1442
+ ),
1443
+ [series, colors]
1444
+ );
1445
+ const hasData = data.length > 0 && series.length > 0;
1446
+ const chartState = getChartState(
1447
+ {
1448
+ isLoading,
1449
+ error,
1450
+ emptyTitle,
1451
+ emptyDescription,
1452
+ errorTitle,
1453
+ errorDescription,
1454
+ loadingLabel,
1455
+ stateClassName,
1456
+ onRetry,
1457
+ retryLabel
1458
+ },
1459
+ hasData
1460
+ );
1461
+ const displayLegend = showLegend ?? series.length > 1;
1462
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: button.cn("h-[300px] w-full", className), children: chartState ?? /* @__PURE__ */ jsxRuntime.jsxs(RechartsPrimitive__namespace.RadarChart, { data, accessibilityLayer: true, children: [
1463
+ showGrid && /* @__PURE__ */ jsxRuntime.jsx(RechartsPrimitive__namespace.PolarGrid, { stroke: "var(--border)", strokeOpacity: 0.6 }),
1464
+ /* @__PURE__ */ jsxRuntime.jsx(
1465
+ RechartsPrimitive__namespace.PolarAngleAxis,
1466
+ {
1467
+ dataKey: labelKey,
1468
+ tick: { fill: "var(--muted-foreground)", fontSize: 12 }
1469
+ }
1470
+ ),
1471
+ /* @__PURE__ */ jsxRuntime.jsx(
1472
+ RechartsPrimitive__namespace.PolarRadiusAxis,
1473
+ {
1474
+ tick: false,
1475
+ axisLine: false,
1476
+ tickFormatter: valueFormatter
1477
+ }
1478
+ ),
1479
+ /* @__PURE__ */ jsxRuntime.jsx(
1480
+ ChartTooltip,
1481
+ {
1482
+ content: /* @__PURE__ */ jsxRuntime.jsx(
1483
+ ChartTooltipContent,
1484
+ {
1485
+ formatter: valueFormatter ? (v) => valueFormatter(v) : void 0
1486
+ }
1487
+ )
1488
+ }
1489
+ ),
1490
+ displayLegend && /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {}) }),
1491
+ series.map((s) => /* @__PURE__ */ jsxRuntime.jsx(
1492
+ RechartsPrimitive__namespace.Radar,
1493
+ {
1494
+ name: s.label ?? s.key,
1495
+ dataKey: s.key,
1496
+ stroke: `var(--color-${s.key})`,
1497
+ fill: filled ? `var(--color-${s.key})` : "none",
1498
+ fillOpacity: filled ? fillOpacity : 0,
1499
+ dot: showDots ? { r: 3, fill: `var(--color-${s.key})` } : false,
1500
+ isAnimationActive: true,
1501
+ animationDuration: 600,
1502
+ animationEasing: "ease-out"
1503
+ },
1504
+ s.key
1505
+ ))
1506
+ ] }) });
1507
+ }
1508
+ function PieMetricChart({
1509
+ data,
1510
+ nameKey,
1511
+ valueKey,
1512
+ colors,
1513
+ outerRadius = "80%",
1514
+ innerRadius = 0,
1515
+ showLabels = false,
1516
+ showLegend = true,
1517
+ explodeIndex,
1518
+ explodeOffset = 12,
1519
+ valueFormatter,
1520
+ isLoading,
1521
+ error,
1522
+ onRetry,
1523
+ retryLabel,
1524
+ emptyTitle,
1525
+ emptyDescription,
1526
+ errorTitle,
1527
+ errorDescription,
1528
+ loadingLabel,
1529
+ stateClassName,
1530
+ className
1531
+ }) {
1532
+ const names = React__namespace.useMemo(() => data.map((d) => String(d[nameKey] ?? "")), [data, nameKey]);
1533
+ const chartConfig = React__namespace.useMemo(() => buildChartConfig(names, colors), [names, colors]);
1534
+ const hasData = hasPieData(data, nameKey, valueKey);
1535
+ const chartState = getChartState(
1536
+ {
1537
+ isLoading,
1538
+ error,
1539
+ emptyTitle,
1540
+ emptyDescription,
1541
+ errorTitle,
1542
+ errorDescription,
1543
+ loadingLabel,
1544
+ stateClassName,
1545
+ onRetry,
1546
+ retryLabel
1547
+ },
1548
+ hasData
1549
+ );
1550
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: button.cn("h-[300px] w-full", className), children: chartState ?? /* @__PURE__ */ jsxRuntime.jsxs(RechartsPrimitive__namespace.PieChart, { accessibilityLayer: true, children: [
1551
+ /* @__PURE__ */ jsxRuntime.jsx(
1552
+ ChartTooltip,
1553
+ {
1554
+ content: /* @__PURE__ */ jsxRuntime.jsx(
1555
+ ChartTooltipContent,
1556
+ {
1557
+ nameKey,
1558
+ formatter: valueFormatter ? (v) => valueFormatter(v) : void 0
1559
+ }
1560
+ )
1561
+ }
1562
+ ),
1563
+ showLegend && /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, { nameKey }) }),
1564
+ /* @__PURE__ */ jsxRuntime.jsx(
1565
+ RechartsPrimitive__namespace.Pie,
1566
+ {
1567
+ data,
1568
+ dataKey: valueKey,
1569
+ nameKey,
1570
+ outerRadius,
1571
+ innerRadius,
1572
+ paddingAngle: 2,
1573
+ label: showLabels ? ({ cx, cy, midAngle, innerRadius: ir, outerRadius: or, percent }) => {
1574
+ if (midAngle == null || percent == null) return null;
1575
+ const RADIAN = Math.PI / 180;
1576
+ const radius = Number(ir) + (Number(or) - Number(ir)) * 1.35;
1577
+ const x = Number(cx) + radius * Math.cos(-midAngle * RADIAN);
1578
+ const y = Number(cy) + radius * Math.sin(-midAngle * RADIAN);
1579
+ return percent > 0.04 ? /* @__PURE__ */ jsxRuntime.jsx(
1580
+ "text",
1581
+ {
1582
+ x,
1583
+ y,
1584
+ fill: "var(--foreground)",
1585
+ textAnchor: x > Number(cx) ? "start" : "end",
1586
+ dominantBaseline: "central",
1587
+ fontSize: 12,
1588
+ fontWeight: 500,
1589
+ children: `${(percent * 100).toFixed(0)}%`
1590
+ }
1591
+ ) : null;
1592
+ } : false,
1593
+ labelLine: false,
1594
+ isAnimationActive: true,
1595
+ animationDuration: 600,
1596
+ animationEasing: "ease-out",
1597
+ children: data.map((entry, index) => {
1598
+ const name = String(entry[nameKey] ?? "");
1599
+ const isExploded = index === explodeIndex;
1600
+ return /* @__PURE__ */ jsxRuntime.jsx(
1601
+ RechartsPrimitive__namespace.Cell,
1602
+ {
1603
+ fill: chartConfig[name]?.color ?? `var(--chart-${index % 8 + 1})`,
1604
+ stroke: "var(--background)",
1605
+ strokeWidth: 2,
1606
+ style: isExploded ? {
1607
+ filter: `drop-shadow(0 4px 8px color-mix(in srgb, ${chartConfig[name]?.color ?? "var(--chart-1)"} 40%, transparent))`
1608
+ } : void 0
1609
+ },
1610
+ `cell-${index}`
1611
+ );
1612
+ })
1613
+ }
1614
+ )
1615
+ ] }) });
1616
+ }
1617
+ function RadialBarMetricChart({
1618
+ data,
1619
+ dataKey = "value",
1620
+ nameKey = "name",
1621
+ colors,
1622
+ innerRadius = "30%",
1623
+ outerRadius = "100%",
1624
+ startAngle = 90,
1625
+ endAngle = -270,
1626
+ showBackground = true,
1627
+ showLegend = true,
1628
+ valueFormatter,
1629
+ isLoading,
1630
+ error,
1631
+ onRetry,
1632
+ retryLabel,
1633
+ emptyTitle,
1634
+ emptyDescription,
1635
+ errorTitle,
1636
+ errorDescription,
1637
+ loadingLabel,
1638
+ stateClassName,
1639
+ className
1640
+ }) {
1641
+ const names = React__namespace.useMemo(() => data.map((d) => String(d[nameKey] ?? "")), [data, nameKey]);
1642
+ const chartConfig = React__namespace.useMemo(() => buildChartConfig(names, colors), [names, colors]);
1643
+ const hasData = data.length > 0;
1644
+ const chartState = getChartState(
1645
+ {
1646
+ isLoading,
1647
+ error,
1648
+ emptyTitle,
1649
+ emptyDescription,
1650
+ errorTitle,
1651
+ errorDescription,
1652
+ loadingLabel,
1653
+ stateClassName,
1654
+ onRetry,
1655
+ retryLabel
1656
+ },
1657
+ hasData
1658
+ );
1659
+ const coloredData = React__namespace.useMemo(
1660
+ () => data.map((item, index) => {
1661
+ const name = String(item[nameKey] ?? "");
1662
+ return {
1663
+ ...item,
1664
+ fill: chartConfig[name]?.color ?? `var(--chart-${index % 8 + 1})`
1665
+ };
1666
+ }),
1667
+ [data, nameKey, chartConfig]
1668
+ );
1669
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: button.cn("flex w-full flex-col gap-3", className), children: [
1670
+ /* @__PURE__ */ jsxRuntime.jsx(ChartContainer, { config: chartConfig, className: "h-[260px] w-full", children: chartState ?? /* @__PURE__ */ jsxRuntime.jsxs(
1671
+ RechartsPrimitive__namespace.RadialBarChart,
1672
+ {
1673
+ data: coloredData,
1674
+ innerRadius,
1675
+ outerRadius,
1676
+ startAngle,
1677
+ endAngle,
1678
+ accessibilityLayer: true,
1679
+ children: [
1680
+ /* @__PURE__ */ jsxRuntime.jsx(
1681
+ ChartTooltip,
1682
+ {
1683
+ cursor: false,
1684
+ content: /* @__PURE__ */ jsxRuntime.jsx(
1685
+ ChartTooltipContent,
1686
+ {
1687
+ nameKey,
1688
+ formatter: valueFormatter ? (v) => valueFormatter(v) : void 0
1689
+ }
1690
+ )
1691
+ }
1692
+ ),
1693
+ /* @__PURE__ */ jsxRuntime.jsx(
1694
+ RechartsPrimitive__namespace.RadialBar,
1695
+ {
1696
+ dataKey,
1697
+ background: showBackground ? { fill: "var(--muted)" } : false,
1698
+ cornerRadius: 6,
1699
+ isAnimationActive: true,
1700
+ animationDuration: 700,
1701
+ animationEasing: "ease-out"
1702
+ }
1703
+ )
1704
+ ]
1705
+ }
1706
+ ) }),
1707
+ showLegend && !chartState && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap justify-center gap-x-4 gap-y-1.5 px-2", children: coloredData.map((item, index) => {
1708
+ const d = item;
1709
+ const name = String(d[nameKey] ?? "");
1710
+ const fillColor = d.fill ?? `var(--chart-${index % 8 + 1})`;
1711
+ const val = d[dataKey];
1712
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
1713
+ /* @__PURE__ */ jsxRuntime.jsx(
1714
+ "span",
1715
+ {
1716
+ className: "inline-block h-2.5 w-2.5 shrink-0 rounded-full",
1717
+ style: { backgroundColor: fillColor }
1718
+ }
1719
+ ),
1720
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
1721
+ name,
1722
+ val !== void 0 && val !== null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 font-medium text-foreground", children: valueFormatter ? valueFormatter(val) : String(val) })
1723
+ ] })
1724
+ ] }, name);
1725
+ }) })
1726
+ ] });
1727
+ }
1728
+ function GaugeChart({
1729
+ value,
1730
+ min = 0,
1731
+ max = 100,
1732
+ thresholds,
1733
+ label,
1734
+ valueFormatter,
1735
+ showNeedle = true,
1736
+ className
1737
+ }) {
1738
+ const percent = Math.min(1, Math.max(0, (value - min) / (max - min)));
1739
+ const percentInt = Math.round(percent * 100);
1740
+ const activeColor = React__namespace.useMemo(() => {
1741
+ if (!thresholds || thresholds.length === 0) return "var(--chart-1)";
1742
+ for (const t of thresholds) {
1743
+ if (percentInt <= t.value) return t.color;
1744
+ }
1745
+ return thresholds[thresholds.length - 1].color;
1746
+ }, [thresholds, percentInt]);
1747
+ const displayText = valueFormatter ? valueFormatter(value, percentInt) : `${percentInt}%`;
1748
+ const cx = 100;
1749
+ const cy = 100;
1750
+ const R = 80;
1751
+ const r = 54;
1752
+ const polar = (angleDeg, radius) => {
1753
+ const rad = angleDeg * Math.PI / 180;
1754
+ return {
1755
+ x: cx + radius * Math.cos(rad),
1756
+ y: cy - radius * Math.sin(rad)
1757
+ };
1758
+ };
1759
+ const trackStart = polar(180, R);
1760
+ const trackEnd = polar(0, R);
1761
+ const trackStartI = polar(180, r);
1762
+ const trackEndI = polar(0, r);
1763
+ const trackPath = [
1764
+ `M ${trackStart.x} ${trackStart.y}`,
1765
+ `A ${R} ${R} 0 0 1 ${trackEnd.x} ${trackEnd.y}`,
1766
+ `L ${trackEndI.x} ${trackEndI.y}`,
1767
+ `A ${r} ${r} 0 0 0 ${trackStartI.x} ${trackStartI.y}`,
1768
+ "Z"
1769
+ ].join(" ");
1770
+ const valueAngle = 180 - percent * 180;
1771
+ const valueEnd = polar(valueAngle, R);
1772
+ const valueEndI = polar(valueAngle, r);
1773
+ const valuePath = percent <= 0 ? "" : percent >= 1 ? trackPath : [
1774
+ `M ${trackStart.x} ${trackStart.y}`,
1775
+ `A ${R} ${R} 0 0 1 ${valueEnd.x} ${valueEnd.y}`,
1776
+ `L ${valueEndI.x} ${valueEndI.y}`,
1777
+ `A ${r} ${r} 0 0 0 ${trackStartI.x} ${trackStartI.y}`,
1778
+ "Z"
1779
+ ].join(" ");
1780
+ const needleAngle = 180 - percent * 180;
1781
+ const needleTip = polar(needleAngle, r - 6);
1782
+ const needleBase1 = polar(needleAngle + 90, 5);
1783
+ const needleBase2 = polar(needleAngle - 90, 5);
1784
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: button.cn("flex flex-col items-center gap-2", className), children: [
1785
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full max-w-[260px]", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 200 130", className: "w-full", "aria-label": `Gauge: ${displayText}`, children: [
1786
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: trackPath, fill: "var(--muted)" }),
1787
+ valuePath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: valuePath, fill: activeColor }),
1788
+ showNeedle && /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
1789
+ /* @__PURE__ */ jsxRuntime.jsx(
1790
+ "polygon",
1791
+ {
1792
+ points: `${needleTip.x},${needleTip.y} ${needleBase1.x},${needleBase1.y} ${needleBase2.x},${needleBase2.y}`,
1793
+ fill: "var(--foreground)",
1794
+ opacity: 0.85
1795
+ }
1796
+ ),
1797
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx, cy, r: 5, fill: "var(--foreground)" })
1798
+ ] }),
1799
+ /* @__PURE__ */ jsxRuntime.jsx(
1800
+ "text",
1801
+ {
1802
+ x: cx,
1803
+ y: cy + 18,
1804
+ textAnchor: "middle",
1805
+ dominantBaseline: "middle",
1806
+ fontSize: 22,
1807
+ fontWeight: 700,
1808
+ fill: "currentColor",
1809
+ className: "fill-foreground",
1810
+ children: displayText
1811
+ }
1812
+ ),
1813
+ label && /* @__PURE__ */ jsxRuntime.jsx(
1814
+ "text",
1815
+ {
1816
+ x: cx,
1817
+ y: cy + 36,
1818
+ textAnchor: "middle",
1819
+ dominantBaseline: "middle",
1820
+ fontSize: 10,
1821
+ fill: "currentColor",
1822
+ className: "fill-muted-foreground",
1823
+ children: label
1824
+ }
1825
+ )
1826
+ ] }) }),
1827
+ thresholds && thresholds.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap justify-center gap-x-3 gap-y-1", children: thresholds.map((t, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
1828
+ /* @__PURE__ */ jsxRuntime.jsx(
1829
+ "span",
1830
+ {
1831
+ className: "inline-block h-2 w-2 shrink-0 rounded-full",
1832
+ style: { backgroundColor: t.color }
1833
+ }
1834
+ ),
1835
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: t.label })
1836
+ ] }, i)) })
1837
+ ] });
1838
+ }
1839
+
1840
+ function Table({ className, ...props }) {
1841
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "table-container", className: "relative w-full overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
1842
+ "table",
1843
+ {
1844
+ "data-slot": "table",
1845
+ className: button.cn("w-full caption-bottom text-sm", className),
1846
+ ...props
1847
+ }
1848
+ ) });
1849
+ }
1850
+ function TableHeader({ className, ...props }) {
1851
+ return /* @__PURE__ */ jsxRuntime.jsx("thead", { "data-slot": "table-header", className: button.cn("[&_tr]:border-b", className), ...props });
1852
+ }
1853
+ function TableBody({ className, ...props }) {
1854
+ return /* @__PURE__ */ jsxRuntime.jsx(
1855
+ "tbody",
1856
+ {
1857
+ "data-slot": "table-body",
1858
+ className: button.cn("[&_tr:last-child]:border-0", className),
1859
+ ...props
1860
+ }
1861
+ );
1862
+ }
1863
+ function TableFooter({ className, ...props }) {
1864
+ return /* @__PURE__ */ jsxRuntime.jsx(
1865
+ "tfoot",
1866
+ {
1867
+ "data-slot": "table-footer",
1868
+ className: button.cn("bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", className),
1869
+ ...props
1870
+ }
1871
+ );
1872
+ }
1873
+ function TableRow({ className, ...props }) {
1874
+ return /* @__PURE__ */ jsxRuntime.jsx(
1875
+ "tr",
1876
+ {
1877
+ "data-slot": "table-row",
1878
+ className: button.cn(
1879
+ "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
1880
+ className
1881
+ ),
1882
+ ...props
1883
+ }
1884
+ );
1885
+ }
1886
+ function TableHead({ className, ...props }) {
1887
+ return /* @__PURE__ */ jsxRuntime.jsx(
1888
+ "th",
1889
+ {
1890
+ "data-slot": "table-head",
1891
+ className: button.cn(
1892
+ "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
1893
+ className
1894
+ ),
1895
+ ...props
1896
+ }
1897
+ );
1898
+ }
1899
+ function TableCell({ className, ...props }) {
1900
+ return /* @__PURE__ */ jsxRuntime.jsx(
1901
+ "td",
1902
+ {
1903
+ "data-slot": "table-cell",
1904
+ className: button.cn(
1905
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
1906
+ className
1907
+ ),
1908
+ ...props
1909
+ }
1910
+ );
1911
+ }
1912
+ function TableCaption({ className, ...props }) {
1913
+ return /* @__PURE__ */ jsxRuntime.jsx(
1914
+ "caption",
1915
+ {
1916
+ "data-slot": "table-caption",
1917
+ className: button.cn("text-muted-foreground mt-4 text-sm", className),
1918
+ ...props
1919
+ }
1920
+ );
1921
+ }
1922
+
1923
+ const Textarea = React__namespace.forwardRef(
1924
+ ({ className, size = "md", ...props }, ref) => {
1925
+ const sizeClasses = {
1926
+ sm: "px-2 py-1 text-sm",
1927
+ md: "px-3 py-2 text-base",
1928
+ lg: "px-4 py-3 text-base"
1929
+ };
1930
+ return /* @__PURE__ */ jsxRuntime.jsx(
1931
+ "textarea",
1932
+ {
1933
+ "data-slot": "textarea",
1934
+ className: button.cn(
1935
+ "flex min-h-16 w-full bg-background rounded-[var(--radius)] border border-border transition-colors outline-none resize-none text-foreground",
1936
+ "placeholder:text-muted-foreground",
1937
+ "focus:ring-2 focus:ring-primary focus:border-transparent",
1938
+ "disabled:cursor-not-allowed disabled:opacity-50",
1939
+ sizeClasses[size],
1940
+ className
1941
+ ),
1942
+ ref,
1943
+ ...props
1944
+ }
1945
+ );
1946
+ }
1947
+ );
1948
+ Textarea.displayName = "Textarea";
1949
+
1950
+ function Dialog({ ...props }) {
1951
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
1952
+ }
1953
+ function DialogTrigger({ ...props }) {
1954
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Trigger, { "data-slot": "dialog-trigger", ...props });
1955
+ }
1956
+ function DialogPortal({ ...props }) {
1957
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
1958
+ }
1959
+ function DialogClose({ ...props }) {
1960
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "data-slot": "dialog-close", ...props });
1961
+ }
1962
+ const DialogOverlay = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1963
+ DialogPrimitive__namespace.Overlay,
1964
+ {
1965
+ ref,
1966
+ "data-slot": "dialog-overlay",
1967
+ className: button.cn(
1968
+ "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/40 backdrop-blur-sm",
1969
+ className
1970
+ ),
1971
+ ...props
1972
+ }
1973
+ ));
1974
+ DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
1975
+ const dialogVariants = classVarianceAuthority.cva(
1976
+ "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 flex flex-col w-full translate-x-[-50%] translate-y-[-50%] border shadow-elevation-sm duration-200 rounded-[var(--radius-card)] overflow-hidden max-h-[calc(100dvh-2rem)]",
1977
+ {
1978
+ variants: {
1979
+ size: {
1980
+ sm: "max-w-sm",
1981
+ md: "max-w-md",
1982
+ lg: "max-w-lg",
1983
+ xl: "max-w-xl",
1984
+ "2xl": "max-w-2xl",
1985
+ "3xl": "max-w-3xl",
1986
+ "4xl": "max-w-4xl",
1987
+ "5xl": "max-w-5xl",
1988
+ full: "max-w-[calc(100vw-2rem)] h-[calc(100dvh-2rem)]"
1989
+ }
1990
+ },
1991
+ defaultVariants: {
1992
+ size: "lg"
1993
+ }
1994
+ }
1995
+ );
1996
+ const DialogContent = React__namespace.forwardRef(({ className, children, size, showClose = true, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
1997
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1998
+ /* @__PURE__ */ jsxRuntime.jsxs(
1999
+ DialogPrimitive__namespace.Content,
2000
+ {
2001
+ ref,
2002
+ "data-slot": "dialog-content",
2003
+ className: button.cn(dialogVariants({ size }), className),
2004
+ ...props,
2005
+ children: [
2006
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4 p-6 overflow-y-auto flex-1 min-h-0", children }),
2007
+ showClose && /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "absolute top-4 right-4 z-10 rounded-full p-2 opacity-70 transition-all hover:opacity-100 hover:bg-accent focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:outline-none disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", children: [
2008
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
2009
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
2010
+ ] })
2011
+ ]
2012
+ }
2013
+ )
2014
+ ] }));
2015
+ DialogContent.displayName = DialogPrimitive__namespace.Content.displayName;
2016
+ function DialogHeader({ className, ...props }) {
2017
+ return /* @__PURE__ */ jsxRuntime.jsx(
2018
+ "div",
2019
+ {
2020
+ "data-slot": "dialog-header",
2021
+ className: button.cn("flex flex-col gap-2 text-left shrink-0", className),
2022
+ ...props
2023
+ }
2024
+ );
2025
+ }
2026
+ function DialogBody({ className, ...props }) {
2027
+ return /* @__PURE__ */ jsxRuntime.jsx(
2028
+ "div",
2029
+ {
2030
+ "data-slot": "dialog-body",
2031
+ className: button.cn("flex-1 overflow-y-auto min-h-0 -mx-6 px-6", className),
2032
+ ...props
2033
+ }
2034
+ );
2035
+ }
2036
+ function DialogFooter({ className, ...props }) {
2037
+ return /* @__PURE__ */ jsxRuntime.jsx(
2038
+ "div",
2039
+ {
2040
+ "data-slot": "dialog-footer",
2041
+ className: button.cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end shrink-0", className),
2042
+ ...props
2043
+ }
2044
+ );
2045
+ }
2046
+ function DialogTitle({ className, ...props }) {
2047
+ return /* @__PURE__ */ jsxRuntime.jsx(
2048
+ DialogPrimitive__namespace.Title,
2049
+ {
2050
+ "data-slot": "dialog-title",
2051
+ className: button.cn(
2052
+ "text-foreground font-semibold leading-tight text-[length:var(--text-h4)]",
2053
+ className
2054
+ ),
2055
+ ...props
2056
+ }
2057
+ );
2058
+ }
2059
+ function DialogDescription({
2060
+ className,
2061
+ ...props
2062
+ }) {
2063
+ return /* @__PURE__ */ jsxRuntime.jsx(
2064
+ DialogPrimitive__namespace.Description,
2065
+ {
2066
+ "data-slot": "dialog-description",
2067
+ className: button.cn("text-muted-foreground", className),
2068
+ ...props
2069
+ }
2070
+ );
2071
+ }
2072
+
2073
+ function useRichTextEditor({
2074
+ value,
2075
+ onChange
2076
+ }) {
2077
+ const editorRef = React.useRef(null);
2078
+ const searchInputRef = React.useRef(null);
2079
+ const linkInputRef = React.useRef(null);
2080
+ const savedSelection = React.useRef(null);
2081
+ const [wordCount, setWordCount] = React.useState(0);
2082
+ const [characterCount, setCharacterCount] = React.useState(0);
2083
+ const [activeFormats, setActiveFormats] = React.useState({
2084
+ bold: false,
2085
+ italic: false,
2086
+ underline: false,
2087
+ justifyLeft: false,
2088
+ justifyCenter: false,
2089
+ justifyRight: false,
2090
+ insertUnorderedList: false,
2091
+ insertOrderedList: false,
2092
+ link: false,
2093
+ h1: false,
2094
+ h2: false,
2095
+ h3: false,
2096
+ p: true
2097
+ });
2098
+ const [isSearchOpen, setIsSearchOpen] = React.useState(false);
2099
+ const [searchQuery, setSearchQuery] = React.useState("");
2100
+ const [linkUrl, setLinkUrl] = React.useState("https://");
2101
+ const [isLinkOpen, setIsLinkOpen] = React.useState(false);
2102
+ const [hasSavedSelection, setHasSavedSelection] = React.useState(false);
2103
+ const findParentTag = React.useCallback((node, tagName) => {
2104
+ let current = node;
2105
+ while (current && current !== editorRef.current) {
2106
+ if (current.nodeName === tagName) return current;
2107
+ current = current.parentNode;
2108
+ }
2109
+ return null;
2110
+ }, []);
2111
+ const updateActiveFormats = React.useCallback(() => {
2112
+ let formatBlock = "";
2113
+ try {
2114
+ formatBlock = document.queryCommandValue("formatBlock");
2115
+ } catch (_e) {
2116
+ }
2117
+ const selection = window.getSelection();
2118
+ const anchorNode = selection?.anchorNode;
2119
+ const focusNode = selection?.focusNode;
2120
+ setActiveFormats({
2121
+ bold: document.queryCommandState("bold"),
2122
+ italic: document.queryCommandState("italic"),
2123
+ underline: document.queryCommandState("underline"),
2124
+ justifyLeft: document.queryCommandState("justifyLeft"),
2125
+ justifyCenter: document.queryCommandState("justifyCenter"),
2126
+ justifyRight: document.queryCommandState("justifyRight"),
2127
+ insertUnorderedList: document.queryCommandState("insertUnorderedList"),
2128
+ insertOrderedList: document.queryCommandState("insertOrderedList"),
2129
+ link: !!(findParentTag(anchorNode || null, "A") || findParentTag(focusNode || null, "A")),
2130
+ h1: formatBlock === "h1" || formatBlock === "H1",
2131
+ h2: formatBlock === "h2" || formatBlock === "H2",
2132
+ h3: formatBlock === "h3" || formatBlock === "H3",
2133
+ p: formatBlock === "p" || formatBlock === "P" || formatBlock === "div" || formatBlock === "DIV" || formatBlock === ""
2134
+ });
2135
+ }, [findParentTag]);
2136
+ const updateActiveFormatsRef = React.useRef(updateActiveFormats);
2137
+ React.useEffect(() => {
2138
+ updateActiveFormatsRef.current = updateActiveFormats;
2139
+ }, [updateActiveFormats]);
2140
+ React.useEffect(() => {
2141
+ if (editorRef.current && editorRef.current.innerHTML !== value) {
2142
+ editorRef.current.innerHTML = value;
2143
+ }
2144
+ const handleSelectionChange = () => {
2145
+ if (document.activeElement === editorRef.current) {
2146
+ updateActiveFormatsRef.current();
2147
+ }
2148
+ };
2149
+ document.addEventListener("selectionchange", handleSelectionChange);
2150
+ return () => document.removeEventListener("selectionchange", handleSelectionChange);
2151
+ }, []);
2152
+ React.useEffect(() => {
2153
+ const text = editorRef.current?.innerText || "";
2154
+ setWordCount(text.trim() ? text.trim().split(/\s+/).length : 0);
2155
+ setCharacterCount(text.trim() ? text.length : 0);
2156
+ }, [value]);
2157
+ const handleInput = React.useCallback(() => {
2158
+ if (editorRef.current) {
2159
+ onChange?.(editorRef.current.innerHTML);
2160
+ updateActiveFormats();
2161
+ const text = editorRef.current.innerText || "";
2162
+ setWordCount(text.trim() ? text.trim().split(/\s+/).length : 0);
2163
+ setCharacterCount(text.trim() ? text.length : 0);
2164
+ }
2165
+ }, [onChange, updateActiveFormats]);
2166
+ const execCommand = React.useCallback(
2167
+ (command, val = "") => {
2168
+ document.execCommand(command, false, val);
2169
+ updateActiveFormats();
2170
+ editorRef.current?.focus();
2171
+ if (editorRef.current) {
2172
+ onChange?.(editorRef.current.innerHTML);
2173
+ }
2174
+ },
2175
+ [onChange, updateActiveFormats]
2176
+ );
2177
+ const performSearch = React.useCallback((text, backward = false) => {
2178
+ if (!text || !editorRef.current) return;
2179
+ const editor = editorRef.current;
2180
+ const selection = window.getSelection();
2181
+ if (!selection) return;
2182
+ const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT);
2183
+ const segments = [];
2184
+ let offset = 0;
2185
+ let node;
2186
+ while (node = walker.nextNode()) {
2187
+ segments.push({ node, start: offset });
2188
+ offset += node.length;
2189
+ }
2190
+ const fullText = segments.reduce((acc, s) => acc + (s.node.textContent ?? ""), "");
2191
+ let searchFrom = 0;
2192
+ if (selection.rangeCount > 0) {
2193
+ const range2 = selection.getRangeAt(0);
2194
+ if (editor.contains(range2.startContainer)) {
2195
+ const seg = segments.find((s) => s.node === range2.startContainer);
2196
+ if (seg) {
2197
+ searchFrom = backward ? seg.start + range2.startOffset - 1 : seg.start + range2.endOffset;
2198
+ }
2199
+ }
2200
+ }
2201
+ const lowerFull = fullText.toLowerCase();
2202
+ const lowerQuery = text.toLowerCase();
2203
+ let matchStart = -1;
2204
+ if (backward) {
2205
+ matchStart = lowerFull.lastIndexOf(lowerQuery, Math.max(0, searchFrom));
2206
+ if (matchStart === -1) matchStart = lowerFull.lastIndexOf(lowerQuery);
2207
+ } else {
2208
+ matchStart = lowerFull.indexOf(lowerQuery, searchFrom);
2209
+ if (matchStart === -1) matchStart = lowerFull.indexOf(lowerQuery);
2210
+ }
2211
+ if (matchStart === -1) return;
2212
+ const matchEnd = matchStart + text.length;
2213
+ const range = document.createRange();
2214
+ let startSet = false;
2215
+ let endSet = false;
2216
+ for (let i = 0; i < segments.length && !endSet; i++) {
2217
+ const seg = segments[i];
2218
+ const segEnd = seg.start + seg.node.length;
2219
+ if (!startSet && matchStart < segEnd && matchStart >= seg.start) {
2220
+ range.setStart(seg.node, matchStart - seg.start);
2221
+ startSet = true;
2222
+ }
2223
+ if (startSet && matchEnd <= segEnd) {
2224
+ range.setEnd(seg.node, matchEnd - seg.start);
2225
+ endSet = true;
2226
+ }
2227
+ }
2228
+ if (startSet && endSet) {
2229
+ selection.removeAllRanges();
2230
+ selection.addRange(range);
2231
+ range.startContainer.parentElement?.scrollIntoView?.({ block: "nearest" });
2232
+ }
2233
+ }, []);
2234
+ const handleCreateLink = React.useCallback(() => {
2235
+ if (savedSelection.current) {
2236
+ const selection2 = window.getSelection();
2237
+ selection2?.removeAllRanges();
2238
+ selection2?.addRange(savedSelection.current);
2239
+ }
2240
+ const selection = window.getSelection();
2241
+ const anchorNode = selection?.anchorNode;
2242
+ const existingLink = findParentTag(anchorNode || null, "A");
2243
+ if (existingLink) {
2244
+ if (linkUrl) {
2245
+ existingLink.setAttribute("href", linkUrl);
2246
+ existingLink.setAttribute("target", "_blank");
2247
+ existingLink.setAttribute("rel", "noopener noreferrer");
2248
+ existingLink.style.color = "hsl(var(--primary))";
2249
+ existingLink.style.textDecoration = "underline";
2250
+ existingLink.style.cursor = "pointer";
2251
+ }
2252
+ handleInput();
2253
+ setIsLinkOpen(false);
2254
+ savedSelection.current = null;
2255
+ return;
2256
+ }
2257
+ if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
2258
+ return;
2259
+ }
2260
+ if (linkUrl) {
2261
+ document.execCommand("createLink", false, linkUrl);
2262
+ setTimeout(() => {
2263
+ const anchor = findParentTag(window.getSelection()?.anchorNode || null, "A");
2264
+ if (anchor) {
2265
+ anchor.setAttribute("target", "_blank");
2266
+ anchor.setAttribute("rel", "noopener noreferrer");
2267
+ anchor.style.color = "hsl(var(--primary))";
2268
+ anchor.style.textDecoration = "underline";
2269
+ anchor.style.cursor = "pointer";
2270
+ }
2271
+ handleInput();
2272
+ }, 10);
2273
+ setIsLinkOpen(false);
2274
+ savedSelection.current = null;
2275
+ }
2276
+ }, [linkUrl, findParentTag, handleInput]);
2277
+ const handleUnlink = React.useCallback(() => {
2278
+ const selection = window.getSelection();
2279
+ const anchorNode = selection?.anchorNode;
2280
+ const existingLink = findParentTag(anchorNode || null, "A");
2281
+ if (existingLink) {
2282
+ const parent = existingLink.parentNode;
2283
+ while (existingLink.firstChild) {
2284
+ parent?.insertBefore(existingLink.firstChild, existingLink);
2285
+ }
2286
+ parent?.removeChild(existingLink);
2287
+ handleInput();
2288
+ } else {
2289
+ document.execCommand("unlink", false, "");
2290
+ }
2291
+ }, [findParentTag, handleInput]);
2292
+ const onLinkPopoverOpenChange = React.useCallback(
2293
+ (open) => {
2294
+ if (open) {
2295
+ const selection = window.getSelection();
2296
+ const anchorNode = selection?.anchorNode;
2297
+ const focusNode = selection?.focusNode;
2298
+ const existingLink = findParentTag(anchorNode || null, "A") || findParentTag(focusNode || null, "A");
2299
+ if (existingLink) {
2300
+ setLinkUrl(existingLink.getAttribute("href") || "https://");
2301
+ } else {
2302
+ setLinkUrl("https://");
2303
+ }
2304
+ if (selection && selection.rangeCount > 0 && (!selection.isCollapsed || existingLink)) {
2305
+ savedSelection.current = selection.getRangeAt(0).cloneRange();
2306
+ setHasSavedSelection(true);
2307
+ } else {
2308
+ savedSelection.current = null;
2309
+ setHasSavedSelection(false);
2310
+ }
2311
+ setTimeout(() => linkInputRef.current?.focus(), 100);
2312
+ } else {
2313
+ setHasSavedSelection(false);
2314
+ }
2315
+ setIsLinkOpen(open);
2316
+ },
2317
+ [findParentTag]
2318
+ );
2319
+ return {
2320
+ // Refs
2321
+ editorRef,
2322
+ searchInputRef,
2323
+ linkInputRef,
2324
+ // State
2325
+ activeFormats,
2326
+ isSearchOpen,
2327
+ setIsSearchOpen,
2328
+ searchQuery,
2329
+ setSearchQuery,
2330
+ linkUrl,
2331
+ setLinkUrl,
2332
+ isLinkOpen,
2333
+ hasSavedSelection,
2334
+ // Computed
2335
+ wordCount,
2336
+ characterCount,
2337
+ // Handlers
2338
+ updateActiveFormats,
2339
+ execCommand,
2340
+ handleInput,
2341
+ performSearch,
2342
+ handleCreateLink,
2343
+ handleUnlink,
2344
+ onLinkPopoverOpenChange
2345
+ };
2346
+ }
2347
+
2348
+ function RichTextEditor({
2349
+ value,
2350
+ onChange,
2351
+ placeholder,
2352
+ className,
2353
+ actionButton,
2354
+ allowSearch = true,
2355
+ allowLinks = true,
2356
+ allowUndoRedo = true,
2357
+ allowHeadings = true,
2358
+ allowFormatting = true,
2359
+ allowAlignment = true,
2360
+ allowLists = true,
2361
+ showWordCount = true,
2362
+ showCharacterCount = true,
2363
+ disabled = false,
2364
+ readOnly = false,
2365
+ onFocus,
2366
+ onBlur,
2367
+ minHeight,
2368
+ maxHeight
2369
+ }) {
2370
+ const isEditable = !disabled && !readOnly;
2371
+ const showToolbar = isEditable;
2372
+ const {
2373
+ editorRef,
2374
+ searchInputRef,
2375
+ linkInputRef,
2376
+ activeFormats,
2377
+ isSearchOpen,
2378
+ setIsSearchOpen,
2379
+ searchQuery,
2380
+ setSearchQuery,
2381
+ linkUrl,
2382
+ setLinkUrl,
2383
+ isLinkOpen,
2384
+ hasSavedSelection,
2385
+ wordCount,
2386
+ characterCount,
2387
+ updateActiveFormats,
2388
+ execCommand,
2389
+ handleInput,
2390
+ performSearch,
2391
+ handleCreateLink,
2392
+ handleUnlink,
2393
+ onLinkPopoverOpenChange
2394
+ } = useRichTextEditor({ value, onChange });
2395
+ const getCurrentBlockLabel = () => {
2396
+ if (activeFormats.h1)
2397
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2398
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading1, { className: "w-4 h-4 mr-1 shrink-0" }),
2399
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: "Título 1" })
2400
+ ] });
2401
+ if (activeFormats.h2)
2402
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2403
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading2, { className: "w-4 h-4 mr-1 shrink-0" }),
2404
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: "Título 2" })
2405
+ ] });
2406
+ if (activeFormats.h3)
2407
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2408
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading3, { className: "w-4 h-4 mr-1 shrink-0" }),
2409
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: "Título 3" })
2410
+ ] });
2411
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2412
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Type, { className: "w-4 h-4 mr-1 shrink-0" }),
2413
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: "Parágrafo" })
2414
+ ] });
2415
+ };
2416
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2417
+ "div",
2418
+ {
2419
+ className: button.cn(
2420
+ "flex flex-col h-full w-full bg-background sm:border border-border sm:shadow-sm sm:rounded-lg overflow-hidden",
2421
+ disabled && "opacity-50 pointer-events-none",
2422
+ className
2423
+ ),
2424
+ children: [
2425
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
2426
+ [contenteditable]:empty:before {
2427
+ content: attr(data-placeholder);
2428
+ color: hsl(var(--muted-foreground));
2429
+ pointer-events: none;
2430
+ display: block;
2431
+ }
2432
+ .prose-editor ul {
2433
+ list-style-type: disc !important;
2434
+ padding-left: 1.5rem !important;
2435
+ margin-top: 0.5rem !important;
2436
+ margin-bottom: 0.5rem !important;
2437
+ }
2438
+ .prose-editor ol {
2439
+ list-style-type: decimal !important;
2440
+ padding-left: 1.5rem !important;
2441
+ margin-top: 0.5rem !important;
2442
+ margin-bottom: 0.5rem !important;
2443
+ }
2444
+ .prose-editor b, .prose-editor strong {
2445
+ font-weight: 600 !important;
2446
+ }
2447
+ .prose-editor i, .prose-editor em {
2448
+ font-style: italic !important;
2449
+ }
2450
+ .prose-editor u {
2451
+ text-decoration: underline !important;
2452
+ }
2453
+ .prose-editor h1 {
2454
+ font-size: 2.25rem !important;
2455
+ font-weight: 700 !important;
2456
+ margin-bottom: 1.25rem !important;
2457
+ line-height: 1.2 !important;
2458
+ margin-top: 2rem !important;
2459
+ color: hsl(var(--foreground));
2460
+ }
2461
+ .prose-editor h2 {
2462
+ font-size: 1.75rem !important;
2463
+ font-weight: 600 !important;
2464
+ margin-bottom: 1rem !important;
2465
+ margin-top: 1.5rem !important;
2466
+ color: hsl(var(--foreground));
2467
+ }
2468
+ .prose-editor h3 {
2469
+ font-size: 1.35rem !important;
2470
+ font-weight: 600 !important;
2471
+ margin-bottom: 0.75rem !important;
2472
+ margin-top: 1.25rem !important;
2473
+ color: hsl(var(--foreground));
2474
+ }
2475
+ .prose-editor p {
2476
+ margin-bottom: 1rem !important;
2477
+ line-height: 1.6 !important;
2478
+ }
2479
+ .prose-editor a {
2480
+ color: var(--info) !important;
2481
+ text-decoration: underline !important;
2482
+ cursor: pointer !important;
2483
+ }
2484
+ .prose-editor h1:first-child, .prose-editor h2:first-child, .prose-editor h3:first-child, .prose-editor p:first-child {
2485
+ margin-top: 0 !important;
2486
+ }
2487
+ .prose-editor {
2488
+ outline: none !important;
2489
+ }
2490
+ ` }),
2491
+ showToolbar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 border-b border-border bg-muted/30 flex items-center gap-1 flex-wrap shrink-0", children: [
2492
+ allowUndoRedo && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2493
+ /* @__PURE__ */ jsxRuntime.jsx(
2494
+ button.Button,
2495
+ {
2496
+ variant: "ghost",
2497
+ size: "icon",
2498
+ className: "h-8 w-8 text-muted-foreground",
2499
+ onClick: () => execCommand("undo"),
2500
+ title: "Desfazer",
2501
+ "aria-label": "Desfazer",
2502
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo, { className: "w-4 h-4" })
2503
+ }
2504
+ ),
2505
+ /* @__PURE__ */ jsxRuntime.jsx(
2506
+ button.Button,
2507
+ {
2508
+ variant: "ghost",
2509
+ size: "icon",
2510
+ className: "h-8 w-8 text-muted-foreground",
2511
+ onClick: () => execCommand("redo"),
2512
+ title: "Refazer",
2513
+ "aria-label": "Refazer",
2514
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Redo, { className: "w-4 h-4" })
2515
+ }
2516
+ ),
2517
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-6 bg-border mx-1 hidden sm:block" })
2518
+ ] }),
2519
+ allowHeadings && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2520
+ /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu, { modal: false, children: [
2521
+ /* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
2522
+ button.Button,
2523
+ {
2524
+ variant: "ghost",
2525
+ size: "sm",
2526
+ className: "h-8 gap-0 text-muted-foreground w-[120px] justify-start px-2",
2527
+ children: [
2528
+ getCurrentBlockLabel(),
2529
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3 h-3 ml-auto opacity-50 shrink-0" })
2530
+ ]
2531
+ }
2532
+ ) }),
2533
+ /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenuContent, { align: "start", className: "w-[160px]", style: { zIndex: 9999 }, children: [
2534
+ /* @__PURE__ */ jsxRuntime.jsxs(
2535
+ dropdownMenu.DropdownMenuItem,
2536
+ {
2537
+ onPointerDown: (e) => e.preventDefault(),
2538
+ onClick: () => execCommand("formatBlock", "P"),
2539
+ className: "gap-2",
2540
+ children: [
2541
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Type, { className: "w-4 h-4 text-muted-foreground" }),
2542
+ " Parágrafo"
2543
+ ]
2544
+ }
2545
+ ),
2546
+ /* @__PURE__ */ jsxRuntime.jsxs(
2547
+ dropdownMenu.DropdownMenuItem,
2548
+ {
2549
+ onPointerDown: (e) => e.preventDefault(),
2550
+ onClick: () => execCommand("formatBlock", "H1"),
2551
+ className: "gap-2",
2552
+ children: [
2553
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading1, { className: "w-4 h-4 text-muted-foreground" }),
2554
+ " Título 1"
2555
+ ]
2556
+ }
2557
+ ),
2558
+ /* @__PURE__ */ jsxRuntime.jsxs(
2559
+ dropdownMenu.DropdownMenuItem,
2560
+ {
2561
+ onPointerDown: (e) => e.preventDefault(),
2562
+ onClick: () => execCommand("formatBlock", "H2"),
2563
+ className: "gap-2",
2564
+ children: [
2565
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading2, { className: "w-4 h-4 text-muted-foreground" }),
2566
+ " Título 2"
2567
+ ]
2568
+ }
2569
+ ),
2570
+ /* @__PURE__ */ jsxRuntime.jsxs(
2571
+ dropdownMenu.DropdownMenuItem,
2572
+ {
2573
+ onPointerDown: (e) => e.preventDefault(),
2574
+ onClick: () => execCommand("formatBlock", "H3"),
2575
+ className: "gap-2",
2576
+ children: [
2577
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading3, { className: "w-4 h-4 text-muted-foreground" }),
2578
+ " Título 3"
2579
+ ]
2580
+ }
2581
+ )
2582
+ ] })
2583
+ ] }),
2584
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-6 bg-border mx-1 hidden sm:block" })
2585
+ ] }),
2586
+ allowFormatting && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2587
+ /* @__PURE__ */ jsxRuntime.jsx(
2588
+ button.Button,
2589
+ {
2590
+ variant: "ghost",
2591
+ size: "icon",
2592
+ className: button.cn(
2593
+ "h-8 w-8 text-muted-foreground",
2594
+ activeFormats.bold && "bg-muted text-foreground"
2595
+ ),
2596
+ onClick: () => execCommand("bold"),
2597
+ title: "Negrito",
2598
+ "aria-label": "Negrito",
2599
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bold, { className: "w-4 h-4" })
2600
+ }
2601
+ ),
2602
+ /* @__PURE__ */ jsxRuntime.jsx(
2603
+ button.Button,
2604
+ {
2605
+ variant: "ghost",
2606
+ size: "icon",
2607
+ className: button.cn(
2608
+ "h-8 w-8 text-muted-foreground",
2609
+ activeFormats.italic && "bg-muted text-foreground"
2610
+ ),
2611
+ onClick: () => execCommand("italic"),
2612
+ title: "Itálico",
2613
+ "aria-label": "Itálico",
2614
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Italic, { className: "w-4 h-4" })
2615
+ }
2616
+ ),
2617
+ /* @__PURE__ */ jsxRuntime.jsx(
2618
+ button.Button,
2619
+ {
2620
+ variant: "ghost",
2621
+ size: "icon",
2622
+ className: button.cn(
2623
+ "h-8 w-8 text-muted-foreground",
2624
+ activeFormats.underline && "bg-muted text-foreground"
2625
+ ),
2626
+ onClick: () => execCommand("underline"),
2627
+ title: "Sublinhado",
2628
+ "aria-label": "Sublinhado",
2629
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Underline, { className: "w-4 h-4" })
2630
+ }
2631
+ ),
2632
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-6 bg-border mx-1 hidden sm:block" })
2633
+ ] }),
2634
+ allowAlignment && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2635
+ /* @__PURE__ */ jsxRuntime.jsx(
2636
+ button.Button,
2637
+ {
2638
+ variant: "ghost",
2639
+ size: "icon",
2640
+ className: button.cn(
2641
+ "h-8 w-8 text-muted-foreground",
2642
+ activeFormats.justifyLeft && "bg-muted text-foreground"
2643
+ ),
2644
+ onClick: () => execCommand("justifyLeft"),
2645
+ title: "Alinhar à esquerda",
2646
+ "aria-label": "Alinhar à esquerda",
2647
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "w-4 h-4" })
2648
+ }
2649
+ ),
2650
+ /* @__PURE__ */ jsxRuntime.jsx(
2651
+ button.Button,
2652
+ {
2653
+ variant: "ghost",
2654
+ size: "icon",
2655
+ className: button.cn(
2656
+ "h-8 w-8 text-muted-foreground",
2657
+ activeFormats.justifyCenter && "bg-muted text-foreground"
2658
+ ),
2659
+ onClick: () => execCommand("justifyCenter"),
2660
+ title: "Centralizar",
2661
+ "aria-label": "Centralizar",
2662
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenter, { className: "w-4 h-4" })
2663
+ }
2664
+ ),
2665
+ /* @__PURE__ */ jsxRuntime.jsx(
2666
+ button.Button,
2667
+ {
2668
+ variant: "ghost",
2669
+ size: "icon",
2670
+ className: button.cn(
2671
+ "h-8 w-8 text-muted-foreground",
2672
+ activeFormats.justifyRight && "bg-muted text-foreground"
2673
+ ),
2674
+ onClick: () => execCommand("justifyRight"),
2675
+ title: "Alinhar à direita",
2676
+ "aria-label": "Alinhar à direita",
2677
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignRight, { className: "w-4 h-4" })
2678
+ }
2679
+ ),
2680
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-6 bg-border mx-1 hidden sm:block" })
2681
+ ] }),
2682
+ allowLists && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2683
+ /* @__PURE__ */ jsxRuntime.jsx(
2684
+ button.Button,
2685
+ {
2686
+ variant: "ghost",
2687
+ size: "icon",
2688
+ className: button.cn(
2689
+ "h-8 w-8 text-muted-foreground",
2690
+ activeFormats.insertUnorderedList && "bg-muted text-foreground"
2691
+ ),
2692
+ onClick: () => execCommand("insertUnorderedList"),
2693
+ title: "Lista com marcadores",
2694
+ "aria-label": "Lista com marcadores",
2695
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.List, { className: "w-4 h-4" })
2696
+ }
2697
+ ),
2698
+ /* @__PURE__ */ jsxRuntime.jsx(
2699
+ button.Button,
2700
+ {
2701
+ variant: "ghost",
2702
+ size: "icon",
2703
+ className: button.cn(
2704
+ "h-8 w-8 text-muted-foreground",
2705
+ activeFormats.insertOrderedList && "bg-muted text-foreground"
2706
+ ),
2707
+ onClick: () => execCommand("insertOrderedList"),
2708
+ title: "Lista numerada",
2709
+ "aria-label": "Lista numerada",
2710
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListOrdered, { className: "w-4 h-4" })
2711
+ }
2712
+ ),
2713
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-6 bg-border mx-1 hidden sm:block" })
2714
+ ] }),
2715
+ allowLinks && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2716
+ /* @__PURE__ */ jsxRuntime.jsxs(input.Popover, { open: isLinkOpen, onOpenChange: onLinkPopoverOpenChange, modal: false, children: [
2717
+ /* @__PURE__ */ jsxRuntime.jsx(input.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
2718
+ button.Button,
2719
+ {
2720
+ variant: "ghost",
2721
+ size: "icon",
2722
+ className: button.cn(
2723
+ "h-8 w-8 text-muted-foreground",
2724
+ (activeFormats.link || isLinkOpen) && "bg-muted text-foreground"
2725
+ ),
2726
+ title: "Inserir link",
2727
+ "aria-label": "Inserir link",
2728
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link, { className: "w-4 h-4" })
2729
+ }
2730
+ ) }),
2731
+ /* @__PURE__ */ jsxRuntime.jsx(input.PopoverContent, { className: "w-80 p-3", align: "start", style: { zIndex: 9999 }, children: !activeFormats.link && !hasSavedSelection ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground py-1", children: "Selecione um texto para criar um link." }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
2732
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium", children: activeFormats.link ? "Editar Link" : "Inserir Link" }),
2733
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
2734
+ /* @__PURE__ */ jsxRuntime.jsx(
2735
+ input.Input,
2736
+ {
2737
+ ref: linkInputRef,
2738
+ placeholder: "https://...",
2739
+ value: linkUrl,
2740
+ onChange: (e) => setLinkUrl(e.target.value),
2741
+ onKeyDown: (e) => {
2742
+ if (e.key === "Enter") {
2743
+ e.preventDefault();
2744
+ e.stopPropagation();
2745
+ handleCreateLink();
2746
+ }
2747
+ },
2748
+ className: "h-8 text-xs"
2749
+ }
2750
+ ),
2751
+ /* @__PURE__ */ jsxRuntime.jsx(button.Button, { size: "sm", className: "h-8", onClick: handleCreateLink, children: "Aplicar" })
2752
+ ] })
2753
+ ] }) })
2754
+ ] }),
2755
+ /* @__PURE__ */ jsxRuntime.jsx(
2756
+ button.Button,
2757
+ {
2758
+ variant: "ghost",
2759
+ size: "icon",
2760
+ className: "h-8 w-8 text-muted-foreground",
2761
+ onClick: handleUnlink,
2762
+ title: "Remover link",
2763
+ "aria-label": "Remover link",
2764
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
2765
+ }
2766
+ ),
2767
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-6 bg-border mx-1 hidden sm:block" })
2768
+ ] }),
2769
+ (allowFormatting || allowHeadings || allowAlignment || allowLists || allowLinks) && /* @__PURE__ */ jsxRuntime.jsx(
2770
+ button.Button,
2771
+ {
2772
+ variant: "ghost",
2773
+ size: "icon",
2774
+ className: "h-8 w-8 text-muted-foreground",
2775
+ onClick: () => execCommand("removeFormat"),
2776
+ title: "Limpar formatação",
2777
+ "aria-label": "Limpar formatação",
2778
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Type, { className: "w-4 h-4" })
2779
+ }
2780
+ ),
2781
+ allowSearch && /* @__PURE__ */ jsxRuntime.jsx(
2782
+ button.Button,
2783
+ {
2784
+ variant: "ghost",
2785
+ size: "icon",
2786
+ className: button.cn(
2787
+ "h-8 w-8 text-muted-foreground",
2788
+ isSearchOpen && "bg-muted text-foreground"
2789
+ ),
2790
+ onClick: () => {
2791
+ setIsSearchOpen(!isSearchOpen);
2792
+ if (!isSearchOpen) setTimeout(() => searchInputRef.current?.focus(), 100);
2793
+ },
2794
+ title: "Buscar",
2795
+ "aria-label": "Buscar",
2796
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "w-4 h-4" })
2797
+ }
2798
+ ),
2799
+ actionButton && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2800
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
2801
+ actionButton
2802
+ ] })
2803
+ ] }),
2804
+ isSearchOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-1.5 border-b border-border bg-muted/20 flex items-center gap-2", children: [
2805
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 max-w-sm", children: [
2806
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground" }),
2807
+ /* @__PURE__ */ jsxRuntime.jsx(
2808
+ input.Input,
2809
+ {
2810
+ ref: searchInputRef,
2811
+ placeholder: "Buscar no texto...",
2812
+ value: searchQuery,
2813
+ onChange: (e) => setSearchQuery(e.target.value),
2814
+ onKeyDown: (e) => {
2815
+ if (e.key === "Enter") {
2816
+ e.preventDefault();
2817
+ performSearch(searchQuery, e.shiftKey);
2818
+ }
2819
+ if (e.key === "Escape") {
2820
+ setIsSearchOpen(false);
2821
+ }
2822
+ },
2823
+ className: "h-8 pl-8 text-xs bg-background"
2824
+ }
2825
+ )
2826
+ ] }),
2827
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2828
+ /* @__PURE__ */ jsxRuntime.jsx(
2829
+ button.Button,
2830
+ {
2831
+ variant: "ghost",
2832
+ size: "icon",
2833
+ className: "h-7 w-7",
2834
+ onMouseDown: (e) => e.preventDefault(),
2835
+ onClick: () => performSearch(searchQuery, true),
2836
+ title: "Anterior",
2837
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "w-4 h-4" })
2838
+ }
2839
+ ),
2840
+ /* @__PURE__ */ jsxRuntime.jsx(
2841
+ button.Button,
2842
+ {
2843
+ variant: "ghost",
2844
+ size: "icon",
2845
+ className: "h-7 w-7",
2846
+ onMouseDown: (e) => e.preventDefault(),
2847
+ onClick: () => performSearch(searchQuery, false),
2848
+ title: "Próximo",
2849
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-4 h-4" })
2850
+ }
2851
+ ),
2852
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-border mx-1" }),
2853
+ /* @__PURE__ */ jsxRuntime.jsx(
2854
+ button.Button,
2855
+ {
2856
+ variant: "ghost",
2857
+ size: "icon",
2858
+ className: "h-7 w-7 text-muted-foreground hover:text-foreground",
2859
+ onClick: () => setIsSearchOpen(false),
2860
+ title: "Fechar busca",
2861
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
2862
+ }
2863
+ )
2864
+ ] }),
2865
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block text-[10px] text-muted-foreground ml-auto uppercase tracking-wider font-medium", children: "Pressione Enter para buscar" })
2866
+ ] }),
2867
+ /* @__PURE__ */ jsxRuntime.jsx(
2868
+ "div",
2869
+ {
2870
+ className: "flex-1 overflow-y-auto p-4 sm:p-8 bg-background scrollbar-thin",
2871
+ style: { minHeight, maxHeight },
2872
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2873
+ "div",
2874
+ {
2875
+ ref: editorRef,
2876
+ contentEditable: isEditable,
2877
+ role: "textbox",
2878
+ "aria-multiline": "true",
2879
+ "aria-label": placeholder || "Editor de texto",
2880
+ "aria-readonly": readOnly,
2881
+ "aria-disabled": disabled,
2882
+ onInput: handleInput,
2883
+ onSelect: isEditable ? updateActiveFormats : void 0,
2884
+ onFocus: () => {
2885
+ updateActiveFormats();
2886
+ onFocus?.();
2887
+ },
2888
+ onBlur,
2889
+ className: "prose-editor min-h-full max-w-none focus:outline-none",
2890
+ "data-placeholder": placeholder
2891
+ }
2892
+ )
2893
+ }
2894
+ ),
2895
+ (showWordCount || showCharacterCount) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 border-t border-border bg-muted/20 flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[10px] sm:text-xs text-muted-foreground font-medium uppercase tracking-wider flex items-center gap-2", children: [
2896
+ showWordCount && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2897
+ wordCount,
2898
+ " ",
2899
+ wordCount === 1 ? "palavra" : "palavras"
2900
+ ] }),
2901
+ showWordCount && showCharacterCount && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "•" }),
2902
+ showCharacterCount && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2903
+ characterCount,
2904
+ " ",
2905
+ characterCount === 1 ? "caractere" : "caracteres"
2906
+ ] })
2907
+ ] }) })
2908
+ ]
2909
+ }
2910
+ );
2911
+ }
2912
+
2913
+ exports.Alert = Alert;
2914
+ exports.AlertDescription = AlertDescription;
2915
+ exports.AlertTitle = AlertTitle;
2916
+ exports.ChartCard = ChartCard;
2917
+ exports.ChartContainer = ChartContainer;
2918
+ exports.ChartLegend = ChartLegend;
2919
+ exports.ChartLegendContent = ChartLegendContent;
2920
+ exports.ChartStyle = ChartStyle;
2921
+ exports.ChartTooltip = ChartTooltip;
2922
+ exports.ChartTooltipContent = ChartTooltipContent;
2923
+ exports.ComboMetricChart = ComboMetricChart;
2924
+ exports.DashboardBarChart = DashboardBarChart;
2925
+ exports.DashboardLineChart = DashboardLineChart;
2926
+ exports.Dialog = Dialog;
2927
+ exports.DialogBody = DialogBody;
2928
+ exports.DialogClose = DialogClose;
2929
+ exports.DialogContent = DialogContent;
2930
+ exports.DialogDescription = DialogDescription;
2931
+ exports.DialogFooter = DialogFooter;
2932
+ exports.DialogHeader = DialogHeader;
2933
+ exports.DialogOverlay = DialogOverlay;
2934
+ exports.DialogPortal = DialogPortal;
2935
+ exports.DialogTitle = DialogTitle;
2936
+ exports.DialogTrigger = DialogTrigger;
2937
+ exports.DonutBreakdownChart = DonutBreakdownChart;
2938
+ exports.Empty = Empty;
2939
+ exports.EmptyAction = EmptyAction;
2940
+ exports.EmptyDescription = EmptyDescription;
2941
+ exports.EmptyIcon = EmptyIcon;
2942
+ exports.EmptyImage = EmptyImage;
2943
+ exports.EmptyTitle = EmptyTitle;
2944
+ exports.GaugeChart = GaugeChart;
2945
+ exports.HorizontalBarChart = HorizontalBarChart;
2946
+ exports.InteractiveTimeSeriesChart = InteractiveTimeSeriesChart;
2947
+ exports.PieMetricChart = PieMetricChart;
2948
+ exports.RadarMetricChart = RadarMetricChart;
2949
+ exports.RadialBarMetricChart = RadialBarMetricChart;
2950
+ exports.RichTextEditor = RichTextEditor;
2951
+ exports.ScrollArea = ScrollArea;
2952
+ exports.ScrollBar = ScrollBar;
2953
+ exports.SparklineChart = SparklineChart;
2954
+ exports.Table = Table;
2955
+ exports.TableBody = TableBody;
2956
+ exports.TableCaption = TableCaption;
2957
+ exports.TableCell = TableCell;
2958
+ exports.TableFooter = TableFooter;
2959
+ exports.TableHead = TableHead;
2960
+ exports.TableHeader = TableHeader;
2961
+ exports.TableRow = TableRow;
2962
+ exports.Textarea = Textarea;
2963
+ exports.useChart = useChart;
2964
+ exports.useRichTextEditor = useRichTextEditor;