@fayz-ai/ui 0.12.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ChartWidgetInner-GDE5PBTR.js → ChartWidgetInner-IOLIUYTB.js} +21 -8
- package/dist/ChartWidgetInner-IOLIUYTB.js.map +1 -0
- package/dist/analytics/AnalyticsCard.d.ts.map +1 -1
- package/dist/analytics/AnalyticsControls.d.ts +5 -1
- package/dist/analytics/AnalyticsControls.d.ts.map +1 -1
- package/dist/chunk-3OVZ5JJQ.js +540 -0
- package/dist/chunk-3OVZ5JJQ.js.map +1 -0
- package/dist/{chunk-22EVFMS3.js → chunk-4GK6IHOI.js} +17 -3
- package/dist/chunk-4GK6IHOI.js.map +1 -0
- package/dist/{chunk-7BMXN7MP.js → chunk-5KMAEQA3.js} +25 -24
- package/dist/chunk-5KMAEQA3.js.map +1 -0
- package/dist/chunk-AASANYXN.js +601 -0
- package/dist/chunk-AASANYXN.js.map +1 -0
- package/dist/chunk-FFJ2C5YH.js +92 -0
- package/dist/chunk-FFJ2C5YH.js.map +1 -0
- package/dist/chunk-J7F3Z52K.js +152 -0
- package/dist/chunk-J7F3Z52K.js.map +1 -0
- package/dist/{chunk-JGJNRNQW.js → chunk-KD2V3TAX.js} +290 -67
- package/dist/chunk-KD2V3TAX.js.map +1 -0
- package/dist/{chunk-ZDRHCKRK.js → chunk-NA3GE4H3.js} +746 -533
- package/dist/chunk-NA3GE4H3.js.map +1 -0
- package/dist/{chunk-7BHG3XGJ.js → chunk-SLWTKHNY.js} +296 -269
- package/dist/chunk-SLWTKHNY.js.map +1 -0
- package/dist/dashboard/ChartWidgetInner.d.ts.map +1 -1
- package/dist/dashboard/DashboardCanvas.d.ts.map +1 -1
- package/dist/dashboard/DashboardCustomizeMenu.d.ts.map +1 -1
- package/dist/dashboard/DashboardRange.d.ts +8 -2
- package/dist/dashboard/DashboardRange.d.ts.map +1 -1
- package/dist/dashboard/index.js +4 -4
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +86 -99
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.d.ts +8 -2
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/ModulePage.d.ts +24 -1
- package/dist/layout/ModulePage.d.ts.map +1 -1
- package/dist/layout/Sidebar.d.ts +27 -4
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Topbar.d.ts +10 -3
- package/dist/layout/Topbar.d.ts.map +1 -1
- package/dist/layout/index.d.ts +2 -1
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +4 -4
- package/dist/layout/rail-flyout.d.ts +10 -0
- package/dist/layout/rail-flyout.d.ts.map +1 -1
- package/dist/primitives/SearchCombobox.d.ts +9 -1
- package/dist/primitives/SearchCombobox.d.ts.map +1 -1
- package/dist/primitives/bulk-action-bar.d.ts +3 -1
- package/dist/primitives/bulk-action-bar.d.ts.map +1 -1
- package/dist/primitives/color-palette.d.ts +24 -0
- package/dist/primitives/color-palette.d.ts.map +1 -0
- package/dist/primitives/header-tabs.d.ts +47 -7
- package/dist/primitives/header-tabs.d.ts.map +1 -1
- package/dist/primitives/image-drop.d.ts +28 -0
- package/dist/primitives/image-drop.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +9 -3
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +6 -3
- package/dist/primitives/list-view.d.ts +9 -1
- package/dist/primitives/list-view.d.ts.map +1 -1
- package/dist/primitives/option-select.d.ts +46 -0
- package/dist/primitives/option-select.d.ts.map +1 -0
- package/dist/primitives/page-toolbar.d.ts +80 -0
- package/dist/primitives/page-toolbar.d.ts.map +1 -0
- package/dist/primitives/search-select.d.ts +3 -1
- package/dist/primitives/search-select.d.ts.map +1 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/step-progress.d.ts +20 -0
- package/dist/primitives/step-progress.d.ts.map +1 -0
- package/dist/primitives/tabs.d.ts.map +1 -1
- package/dist/primitives/use-row-selection.d.ts +50 -0
- package/dist/primitives/use-row-selection.d.ts.map +1 -0
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/page-header.store.d.ts +26 -2
- package/dist/stores/page-header.store.d.ts.map +1 -1
- package/dist/styles.css +74 -17
- package/dist/wizard/Wizard.d.ts +38 -0
- package/dist/wizard/Wizard.d.ts.map +1 -0
- package/dist/wizard/WizardField.d.ts +22 -0
- package/dist/wizard/WizardField.d.ts.map +1 -0
- package/dist/wizard/index.d.ts +6 -0
- package/dist/wizard/index.d.ts.map +1 -0
- package/dist/wizard/index.js +5 -0
- package/dist/wizard/index.js.map +1 -0
- package/dist/wizard/logic.d.ts +39 -0
- package/dist/wizard/logic.d.ts.map +1 -0
- package/dist/wizard/types.d.ts +95 -0
- package/dist/wizard/types.d.ts.map +1 -0
- package/dist/wizard/useWizard.d.ts +47 -0
- package/dist/wizard/useWizard.d.ts.map +1 -0
- package/package.json +14 -8
- package/dist/ChartWidgetInner-GDE5PBTR.js.map +0 -1
- package/dist/chunk-22EVFMS3.js.map +0 -1
- package/dist/chunk-7BHG3XGJ.js.map +0 -1
- package/dist/chunk-7BMXN7MP.js.map +0 -1
- package/dist/chunk-JGJNRNQW.js.map +0 -1
- package/dist/chunk-VAKWUUVC.js +0 -425
- package/dist/chunk-VAKWUUVC.js.map +0 -1
- package/dist/chunk-ZBQ772DU.js +0 -17
- package/dist/chunk-ZBQ772DU.js.map +0 -1
- package/dist/chunk-ZDRHCKRK.js.map +0 -1
|
@@ -3,19 +3,32 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
3
3
|
|
|
4
4
|
// src/dashboard/ChartWidgetInner.tsx
|
|
5
5
|
var PALETTE = [
|
|
6
|
-
"hsl(var(--info))",
|
|
7
|
-
"hsl(var(--magic))",
|
|
8
|
-
"hsl(var(--success))",
|
|
9
|
-
"hsl(var(--warning))",
|
|
10
|
-
"hsl(var(--destructive))"
|
|
6
|
+
"hsl(var(--chart-1,var(--info)))",
|
|
7
|
+
"hsl(var(--chart-2,var(--magic)))",
|
|
8
|
+
"hsl(var(--chart-3,var(--success)))",
|
|
9
|
+
"hsl(var(--chart-4,var(--warning)))",
|
|
10
|
+
"hsl(var(--chart-5,var(--destructive)))"
|
|
11
11
|
];
|
|
12
12
|
var AXIS = "hsl(var(--muted-foreground))";
|
|
13
13
|
var GRID = "hsl(var(--border))";
|
|
14
14
|
function ChartWidgetInner({ type, data, series, categoryKey, height }) {
|
|
15
15
|
const color = (i, explicit) => explicit ?? PALETTE[i % PALETTE.length];
|
|
16
|
+
const pieKey = series[0]?.dataKey ?? "value";
|
|
17
|
+
const pieData = type === "pie" ? data.filter((row) => Number(row[pieKey]) > 0) : data;
|
|
16
18
|
return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: type === "pie" ? /* @__PURE__ */ jsxs(PieChart, { children: [
|
|
17
19
|
/* @__PURE__ */ jsx(Tooltip, {}),
|
|
18
|
-
/* @__PURE__ */ jsx(
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
Pie,
|
|
22
|
+
{
|
|
23
|
+
data: pieData,
|
|
24
|
+
dataKey: pieKey,
|
|
25
|
+
nameKey: categoryKey,
|
|
26
|
+
innerRadius: 50,
|
|
27
|
+
outerRadius: 80,
|
|
28
|
+
paddingAngle: pieData.length > 1 ? 2 : 0,
|
|
29
|
+
children: pieData.map((_, i) => /* @__PURE__ */ jsx(Cell, { fill: color(i, series[0]?.color) }, i))
|
|
30
|
+
}
|
|
31
|
+
),
|
|
19
32
|
/* @__PURE__ */ jsx(Legend, {})
|
|
20
33
|
] }) : type === "bar" ? /* @__PURE__ */ jsxs(BarChart, { data, children: [
|
|
21
34
|
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: GRID, vertical: false }),
|
|
@@ -42,5 +55,5 @@ function ChartWidgetInner({ type, data, series, categoryKey, height }) {
|
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
export { ChartWidgetInner as default };
|
|
45
|
-
//# sourceMappingURL=ChartWidgetInner-
|
|
46
|
-
//# sourceMappingURL=ChartWidgetInner-
|
|
58
|
+
//# sourceMappingURL=ChartWidgetInner-IOLIUYTB.js.map
|
|
59
|
+
//# sourceMappingURL=ChartWidgetInner-IOLIUYTB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dashboard/ChartWidgetInner.tsx"],"names":[],"mappings":"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","file":"ChartWidgetInner-IOLIUYTB.js","sourcesContent":["import * as React from 'react'\nimport {\n ResponsiveContainer,\n LineChart, Line,\n BarChart, Bar,\n AreaChart, Area,\n PieChart, Pie, Cell,\n XAxis, YAxis, CartesianGrid, Tooltip, Legend,\n} from 'recharts'\nimport type { ChartSeries, ChartType } from './types'\n\n/**\n * Series palette, in order.\n *\n * The status colours are the FALLBACK, not the definition: an app with a design\n * system of its own states `--chart-1..5` and the charts adopt its viz ramp.\n * Rebinding `--info` instead was the only lever before, and it repaints link\n * buttons, info badges and notification icons along with the chart — series\n * colour and \"this is informational\" are not the same decision.\n */\nconst PALETTE = [\n 'hsl(var(--chart-1,var(--info)))',\n 'hsl(var(--chart-2,var(--magic)))',\n 'hsl(var(--chart-3,var(--success)))',\n 'hsl(var(--chart-4,var(--warning)))',\n 'hsl(var(--chart-5,var(--destructive)))',\n]\nconst AXIS = 'hsl(var(--muted-foreground))'\nconst GRID = 'hsl(var(--border))'\n\nexport interface ChartWidgetInnerProps {\n type: ChartType\n data: Array<Record<string, string | number>>\n series: ChartSeries[]\n categoryKey: string\n height: number\n}\n\n// recharts-backed chart body. Default export + own module so ChartWidget can\n// React.lazy it — recharts (~400 KB min) then lives in an async chunk instead\n// of every consumer's entry bundle.\nexport default function ChartWidgetInner({ type, data, series, categoryKey, height }: ChartWidgetInnerProps) {\n const color = (i: number, explicit?: string) => explicit ?? PALETTE[i % PALETTE.length]\n\n // A pie only draws what has size. Two things collapse it otherwise, and both\n // are ordinary states, not edge cases:\n //\n // a zero slice — \"revenue by course\" when one course has not sold yet — is\n // a legend entry with no arc, so it reads as a missing wedge rather than a\n // zero; drop it and let the legend say what is actually on the chart.\n //\n // one slice left holding 100% — the common shape for a young tenant — is a\n // 360° sector, and recharts subtracts `paddingAngle` from EVERY sector,\n // including that one. Start and end angles meet, and the whole chart renders\n // as a flat line. Padding between slices needs at least two slices.\n const pieKey = series[0]?.dataKey ?? 'value'\n const pieData = type === 'pie' ? data.filter((row) => Number(row[pieKey]) > 0) : data\n\n return (\n <ResponsiveContainer width=\"100%\" height={height}>\n {type === 'pie' ? (\n <PieChart>\n <Tooltip />\n <Pie\n data={pieData} dataKey={pieKey} nameKey={categoryKey}\n innerRadius={50} outerRadius={80}\n paddingAngle={pieData.length > 1 ? 2 : 0}\n >\n {pieData.map((_, i) => <Cell key={i} fill={color(i, series[0]?.color)} />)}\n </Pie>\n <Legend />\n </PieChart>\n ) : type === 'bar' ? (\n <BarChart data={data}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID} vertical={false} />\n <XAxis dataKey={categoryKey} stroke={AXIS} fontSize={12} tickLine={false} axisLine={false} />\n <YAxis stroke={AXIS} fontSize={12} tickLine={false} axisLine={false} width={36} />\n <Tooltip cursor={{ fill: GRID, opacity: 0.3 }} />\n {series.length > 1 && <Legend />}\n {series.map((s, i) => (\n <Bar key={s.dataKey} dataKey={s.dataKey} name={s.label ?? s.dataKey} fill={color(i, s.color)} radius={[4, 4, 0, 0]} />\n ))}\n </BarChart>\n ) : type === 'area' ? (\n <AreaChart data={data}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID} vertical={false} />\n <XAxis dataKey={categoryKey} stroke={AXIS} fontSize={12} tickLine={false} axisLine={false} />\n <YAxis stroke={AXIS} fontSize={12} tickLine={false} axisLine={false} width={36} />\n <Tooltip />\n {series.length > 1 && <Legend />}\n {series.map((s, i) => (\n <Area key={s.dataKey} dataKey={s.dataKey} name={s.label ?? s.dataKey} stroke={color(i, s.color)} fill={color(i, s.color)} fillOpacity={0.15} />\n ))}\n </AreaChart>\n ) : (\n <LineChart data={data}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID} vertical={false} />\n <XAxis dataKey={categoryKey} stroke={AXIS} fontSize={12} tickLine={false} axisLine={false} />\n <YAxis stroke={AXIS} fontSize={12} tickLine={false} axisLine={false} width={36} />\n <Tooltip />\n {series.length > 1 && <Legend />}\n {series.map((s, i) => (\n <Line key={s.dataKey} dataKey={s.dataKey} name={s.label ?? s.dataKey} stroke={color(i, s.color)} strokeWidth={2} dot={false} />\n ))}\n </LineChart>\n )}\n </ResponsiveContainer>\n )\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsCard.d.ts","sourceRoot":"","sources":["../../src/analytics/AnalyticsCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"AnalyticsCard.d.ts","sourceRoot":"","sources":["../../src/analytics/AnalyticsCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EACV,gBAAgB,EACjB,MAAM,eAAe,CAAA;AAyBtB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAuKD,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,kBAAkB,qBA4I9E"}
|
|
@@ -12,7 +12,11 @@ export interface AnalyticsControlsProps {
|
|
|
12
12
|
showCompare?: boolean;
|
|
13
13
|
/** Right-aligned extras (e.g. Export, New report). */
|
|
14
14
|
actions?: React.ReactNode;
|
|
15
|
+
/** Which cards/widgets show — same slot the dashboard fills. */
|
|
16
|
+
customize?: React.ReactNode;
|
|
17
|
+
/** Solta a barra do topo (impressão, dentro de um modal). */
|
|
18
|
+
sticky?: boolean;
|
|
15
19
|
className?: string;
|
|
16
20
|
}
|
|
17
|
-
export declare function AnalyticsControls({ filters, showCompare, actions, className }: AnalyticsControlsProps): React.JSX.Element;
|
|
21
|
+
export declare function AnalyticsControls({ filters, showCompare, actions, customize, sticky, className }: AnalyticsControlsProps): React.JSX.Element;
|
|
18
22
|
//# sourceMappingURL=AnalyticsControls.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsControls.d.ts","sourceRoot":"","sources":["../../src/analytics/AnalyticsControls.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,kBAAkB,EAAyB,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"AnalyticsControls.d.ts","sourceRoot":"","sources":["../../src/analytics/AnalyticsControls.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,kBAAkB,EAAyB,MAAM,eAAe,CAAA;AAuI9E,MAAM,WAAW,0BAA0B;IACzC,oEAAoE;IACpE,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAC9B;AAED,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,EAAE,0BAA0B,4BAwG5E;AAuED,MAAM,WAAW,sBAAsB;IACrC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC9B,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,sDAAsD;IACtD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,gEAAgE;IAChE,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC3B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,OAAY,EAAE,WAAkB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,sBAAsB,qBAyDpI"}
|
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import { cn, Button } from './chunk-OKZ6WQB3.js';
|
|
2
|
+
import * as React4 from 'react';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
5
|
+
import { CheckCircle2, AlertTriangle, XCircle, Info, Check, ImagePlus, Loader2, X } from 'lucide-react';
|
|
6
|
+
|
|
7
|
+
var TRACK = {
|
|
8
|
+
sm: "h-4 w-7",
|
|
9
|
+
md: "h-5 w-9"
|
|
10
|
+
};
|
|
11
|
+
var THUMB = {
|
|
12
|
+
sm: "h-3 w-3 data-[on=true]:translate-x-3",
|
|
13
|
+
md: "h-4 w-4 data-[on=true]:translate-x-4"
|
|
14
|
+
};
|
|
15
|
+
var Switch = React4.forwardRef(function Switch2({ checked, onCheckedChange, size = "sm", label, className, disabled, ...rest }, ref) {
|
|
16
|
+
const control = /* @__PURE__ */ jsx(
|
|
17
|
+
"button",
|
|
18
|
+
{
|
|
19
|
+
ref,
|
|
20
|
+
type: "button",
|
|
21
|
+
role: "switch",
|
|
22
|
+
"aria-checked": checked,
|
|
23
|
+
disabled,
|
|
24
|
+
onClick: (e) => {
|
|
25
|
+
e.stopPropagation();
|
|
26
|
+
rest.onClick?.(e);
|
|
27
|
+
if (!disabled) onCheckedChange(!checked);
|
|
28
|
+
},
|
|
29
|
+
className: cn(
|
|
30
|
+
"relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-colors",
|
|
31
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
32
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
33
|
+
TRACK[size],
|
|
34
|
+
checked ? "bg-primary" : "bg-muted-foreground/30",
|
|
35
|
+
className
|
|
36
|
+
),
|
|
37
|
+
...rest,
|
|
38
|
+
children: /* @__PURE__ */ jsx(
|
|
39
|
+
"span",
|
|
40
|
+
{
|
|
41
|
+
"data-on": checked,
|
|
42
|
+
className: cn(
|
|
43
|
+
"pointer-events-none ml-0.5 inline-block rounded-full bg-background shadow-sm transition-transform",
|
|
44
|
+
THUMB[size]
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
if (label == null) return control;
|
|
51
|
+
return /* @__PURE__ */ jsxs(
|
|
52
|
+
"label",
|
|
53
|
+
{
|
|
54
|
+
className: cn(
|
|
55
|
+
"inline-flex items-center gap-2 text-xs text-muted-foreground",
|
|
56
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
57
|
+
),
|
|
58
|
+
onClick: (e) => e.stopPropagation(),
|
|
59
|
+
children: [
|
|
60
|
+
control,
|
|
61
|
+
/* @__PURE__ */ jsx("span", { children: label })
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
var VARIANT_CONFIG = {
|
|
67
|
+
default: {
|
|
68
|
+
icon: Info,
|
|
69
|
+
iconBg: "bg-info/10",
|
|
70
|
+
iconColor: "text-info",
|
|
71
|
+
buttonVariant: "default"
|
|
72
|
+
},
|
|
73
|
+
destructive: {
|
|
74
|
+
icon: XCircle,
|
|
75
|
+
iconBg: "bg-destructive/10",
|
|
76
|
+
iconColor: "text-destructive",
|
|
77
|
+
buttonVariant: "destructive"
|
|
78
|
+
},
|
|
79
|
+
warning: {
|
|
80
|
+
icon: AlertTriangle,
|
|
81
|
+
iconBg: "bg-warning/10",
|
|
82
|
+
iconColor: "text-warning",
|
|
83
|
+
buttonVariant: "destructive"
|
|
84
|
+
},
|
|
85
|
+
success: {
|
|
86
|
+
icon: CheckCircle2,
|
|
87
|
+
iconBg: "bg-success/10",
|
|
88
|
+
iconColor: "text-success",
|
|
89
|
+
buttonVariant: "default"
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
function ConfirmDialog({
|
|
93
|
+
open,
|
|
94
|
+
onConfirm,
|
|
95
|
+
onCancel,
|
|
96
|
+
title,
|
|
97
|
+
description,
|
|
98
|
+
confirmLabel = "Confirm",
|
|
99
|
+
cancelLabel = "Cancel",
|
|
100
|
+
variant = "default",
|
|
101
|
+
loading = false
|
|
102
|
+
}) {
|
|
103
|
+
const config = VARIANT_CONFIG[variant];
|
|
104
|
+
const Icon = config.icon;
|
|
105
|
+
React4.useEffect(() => {
|
|
106
|
+
if (!open) return;
|
|
107
|
+
function handleKey(e) {
|
|
108
|
+
if (e.key === "Escape") onCancel();
|
|
109
|
+
}
|
|
110
|
+
document.addEventListener("keydown", handleKey);
|
|
111
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
112
|
+
}, [open, onCancel]);
|
|
113
|
+
if (!open) return null;
|
|
114
|
+
return createPortal(
|
|
115
|
+
/* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[60] flex items-center justify-center", children: [
|
|
116
|
+
/* @__PURE__ */ jsx(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
className: "absolute inset-0 bg-black/50 backdrop-blur-[2px] animate-fade-in",
|
|
120
|
+
onClick: onCancel
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
"div",
|
|
125
|
+
{
|
|
126
|
+
className: "relative z-10 w-full max-w-sm mx-4 rounded-modal border border-border bg-card shadow-lg animate-zoom-in",
|
|
127
|
+
role: "alertdialog",
|
|
128
|
+
"aria-modal": "true",
|
|
129
|
+
"aria-labelledby": "confirm-title",
|
|
130
|
+
"aria-describedby": description ? "confirm-desc" : void 0,
|
|
131
|
+
children: /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
|
|
132
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
133
|
+
/* @__PURE__ */ jsx("div", { className: cn("flex h-10 w-10 items-center justify-center rounded-full shrink-0", config.iconBg), children: /* @__PURE__ */ jsx(Icon, { className: cn("h-5 w-5", config.iconColor) }) }),
|
|
134
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 pt-0.5", children: [
|
|
135
|
+
/* @__PURE__ */ jsx("h3", { id: "confirm-title", className: "text-sm font-semibold text-foreground", children: title }),
|
|
136
|
+
description && /* @__PURE__ */ jsx("p", { id: "confirm-desc", className: "text-xs text-muted-foreground mt-1 leading-relaxed", children: description })
|
|
137
|
+
] })
|
|
138
|
+
] }),
|
|
139
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-5", children: [
|
|
140
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onCancel, disabled: loading, children: cancelLabel }),
|
|
141
|
+
/* @__PURE__ */ jsx(Button, { variant: config.buttonVariant, size: "sm", onClick: onConfirm, disabled: loading, children: loading ? "Processing..." : confirmLabel })
|
|
142
|
+
] })
|
|
143
|
+
] })
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
] }),
|
|
147
|
+
document.body
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function StepProgress({ total, current, onSelect, className, ...rest }) {
|
|
151
|
+
return /* @__PURE__ */ jsx(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
role: "progressbar",
|
|
155
|
+
"aria-label": rest["aria-label"],
|
|
156
|
+
"aria-valuemin": 1,
|
|
157
|
+
"aria-valuemax": total,
|
|
158
|
+
"aria-valuenow": Math.min(current + 1, total),
|
|
159
|
+
className: cn("flex w-full items-center gap-2", className),
|
|
160
|
+
children: Array.from({ length: total }, (_, i) => {
|
|
161
|
+
const done = i <= current;
|
|
162
|
+
const clickable = Boolean(onSelect) && i < current;
|
|
163
|
+
return /* @__PURE__ */ jsx(
|
|
164
|
+
"button",
|
|
165
|
+
{
|
|
166
|
+
type: "button",
|
|
167
|
+
tabIndex: clickable ? 0 : -1,
|
|
168
|
+
"aria-hidden": !clickable,
|
|
169
|
+
disabled: !clickable,
|
|
170
|
+
onClick: clickable ? () => onSelect?.(i) : void 0,
|
|
171
|
+
className: cn(
|
|
172
|
+
"h-[2px] flex-1 rounded-full transition-colors duration-300",
|
|
173
|
+
done ? "bg-foreground" : "bg-border",
|
|
174
|
+
clickable && "cursor-pointer hover:bg-foreground/70"
|
|
175
|
+
)
|
|
176
|
+
},
|
|
177
|
+
i
|
|
178
|
+
);
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
function nextValue(current, picked, multi) {
|
|
184
|
+
if (!multi) return picked;
|
|
185
|
+
const list = Array.isArray(current) ? current : current ? [current] : [];
|
|
186
|
+
return list.includes(picked) ? list.filter((v) => v !== picked) : [...list, picked];
|
|
187
|
+
}
|
|
188
|
+
function isSelected(current, option) {
|
|
189
|
+
return Array.isArray(current) ? current.includes(option) : current === option;
|
|
190
|
+
}
|
|
191
|
+
var MAX_SHORTCUTS = 9;
|
|
192
|
+
function useOptionShortcuts(options, enabled, pick) {
|
|
193
|
+
const pickRef = React4.useRef(pick);
|
|
194
|
+
pickRef.current = pick;
|
|
195
|
+
const values = options.slice(0, MAX_SHORTCUTS).map((o) => o.value).join("\0");
|
|
196
|
+
React4.useEffect(() => {
|
|
197
|
+
if (!enabled) return;
|
|
198
|
+
const list = values.split("\0").filter(Boolean);
|
|
199
|
+
if (list.length === 0) return;
|
|
200
|
+
function onKey(e) {
|
|
201
|
+
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
|
202
|
+
const el = e.target;
|
|
203
|
+
const tag = el?.tagName;
|
|
204
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || el?.isContentEditable) return;
|
|
205
|
+
const index = Number(e.key) - 1;
|
|
206
|
+
if (!Number.isInteger(index) || index < 0 || index >= list.length) return;
|
|
207
|
+
e.preventDefault();
|
|
208
|
+
pickRef.current(list[index]);
|
|
209
|
+
}
|
|
210
|
+
document.addEventListener("keydown", onKey);
|
|
211
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
212
|
+
}, [enabled, values]);
|
|
213
|
+
}
|
|
214
|
+
function KeyHint({ index, selected, corner }) {
|
|
215
|
+
return /* @__PURE__ */ jsx(
|
|
216
|
+
"kbd",
|
|
217
|
+
{
|
|
218
|
+
"aria-hidden": true,
|
|
219
|
+
className: cn(
|
|
220
|
+
"hidden h-5 min-w-[1.25rem] shrink-0 items-center justify-center rounded border px-1 font-mono text-[10px] font-semibold sm:inline-flex",
|
|
221
|
+
// Parked in the corner rather than in the reading line: the shortcut is
|
|
222
|
+
// an accelerator, not part of the answer, and inline it pushed every
|
|
223
|
+
// label right and split the logo from the name it belongs to.
|
|
224
|
+
corner && "absolute right-2 top-2",
|
|
225
|
+
selected ? "border-primary/40 bg-primary/10 text-primary" : "border-border bg-muted text-muted-foreground"
|
|
226
|
+
),
|
|
227
|
+
children: index + 1
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
var COLUMNS = {
|
|
232
|
+
1: "grid-cols-1",
|
|
233
|
+
2: "grid-cols-1 sm:grid-cols-2",
|
|
234
|
+
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
|
|
235
|
+
};
|
|
236
|
+
function OptionCards({
|
|
237
|
+
options,
|
|
238
|
+
value,
|
|
239
|
+
onChange,
|
|
240
|
+
multi = false,
|
|
241
|
+
disabled,
|
|
242
|
+
shortcuts = false,
|
|
243
|
+
columns = 2,
|
|
244
|
+
className,
|
|
245
|
+
...rest
|
|
246
|
+
}) {
|
|
247
|
+
useOptionShortcuts(options, shortcuts && !disabled, (picked) => onChange(nextValue(value, picked, multi)));
|
|
248
|
+
return /* @__PURE__ */ jsx(
|
|
249
|
+
"div",
|
|
250
|
+
{
|
|
251
|
+
role: multi ? "group" : "radiogroup",
|
|
252
|
+
"aria-label": rest["aria-label"],
|
|
253
|
+
className: cn("grid gap-2.5", COLUMNS[columns], className),
|
|
254
|
+
children: options.map((option, index) => {
|
|
255
|
+
const selected = isSelected(value, option.value);
|
|
256
|
+
const corner = shortcuts && index < MAX_SHORTCUTS;
|
|
257
|
+
return /* @__PURE__ */ jsxs(
|
|
258
|
+
"button",
|
|
259
|
+
{
|
|
260
|
+
type: "button",
|
|
261
|
+
role: multi ? "checkbox" : "radio",
|
|
262
|
+
"aria-checked": selected,
|
|
263
|
+
disabled,
|
|
264
|
+
onClick: () => onChange(nextValue(value, option.value, multi)),
|
|
265
|
+
className: cn(
|
|
266
|
+
"group relative flex items-start gap-3 rounded-lg border bg-card p-4 text-left transition-all",
|
|
267
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
268
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
269
|
+
selected ? "border-primary ring-2 ring-primary/15" : "border-border hover:-translate-y-px hover:border-foreground/25 hover:shadow-button"
|
|
270
|
+
),
|
|
271
|
+
children: [
|
|
272
|
+
corner && selected && /* @__PURE__ */ jsx(Check, { className: "absolute right-2 top-2 h-4 w-4 text-primary" }),
|
|
273
|
+
corner && !selected && /* @__PURE__ */ jsx(KeyHint, { index, selected: false, corner: true }),
|
|
274
|
+
option.icon && /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: option.icon }),
|
|
275
|
+
/* @__PURE__ */ jsxs("span", { className: cn("min-w-0 flex-1", corner && "pr-5"), children: [
|
|
276
|
+
/* @__PURE__ */ jsx("span", { className: "block text-sm font-semibold text-foreground", children: option.label }),
|
|
277
|
+
option.hint && /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-xs leading-relaxed text-muted-foreground", children: option.hint })
|
|
278
|
+
] }),
|
|
279
|
+
!corner && selected && /* @__PURE__ */ jsx(Check, { className: "mt-0.5 h-4 w-4 shrink-0 text-primary" })
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
option.value
|
|
283
|
+
);
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
function OptionChips({
|
|
289
|
+
options,
|
|
290
|
+
value,
|
|
291
|
+
onChange,
|
|
292
|
+
multi = false,
|
|
293
|
+
disabled,
|
|
294
|
+
shortcuts = false,
|
|
295
|
+
className,
|
|
296
|
+
...rest
|
|
297
|
+
}) {
|
|
298
|
+
useOptionShortcuts(options, shortcuts && !disabled, (picked) => onChange(nextValue(value, picked, multi)));
|
|
299
|
+
return /* @__PURE__ */ jsx(
|
|
300
|
+
"div",
|
|
301
|
+
{
|
|
302
|
+
role: multi ? "group" : "radiogroup",
|
|
303
|
+
"aria-label": rest["aria-label"],
|
|
304
|
+
className: cn("flex flex-wrap gap-2", className),
|
|
305
|
+
children: options.map((option, index) => {
|
|
306
|
+
const selected = isSelected(value, option.value);
|
|
307
|
+
return /* @__PURE__ */ jsxs(
|
|
308
|
+
"button",
|
|
309
|
+
{
|
|
310
|
+
type: "button",
|
|
311
|
+
role: multi ? "checkbox" : "radio",
|
|
312
|
+
"aria-checked": selected,
|
|
313
|
+
disabled,
|
|
314
|
+
onClick: () => onChange(nextValue(value, option.value, multi)),
|
|
315
|
+
className: cn(
|
|
316
|
+
"inline-flex items-center gap-1.5 rounded-full border px-4 py-2 text-sm font-medium transition-colors",
|
|
317
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
318
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
319
|
+
selected ? "border-primary bg-primary/5 text-foreground" : "border-border bg-card text-muted-foreground hover:border-foreground/25 hover:text-foreground"
|
|
320
|
+
),
|
|
321
|
+
children: [
|
|
322
|
+
option.icon,
|
|
323
|
+
shortcuts && index < MAX_SHORTCUTS && /* @__PURE__ */ jsx(KeyHint, { index, selected }),
|
|
324
|
+
option.label,
|
|
325
|
+
selected && /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5 text-primary" })
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
option.value
|
|
329
|
+
);
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
var DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
|
|
335
|
+
function ImageDrop({
|
|
336
|
+
value,
|
|
337
|
+
onUpload,
|
|
338
|
+
onChange,
|
|
339
|
+
label,
|
|
340
|
+
hint,
|
|
341
|
+
accept = "image/*",
|
|
342
|
+
maxBytes = DEFAULT_MAX_BYTES,
|
|
343
|
+
shape = "square",
|
|
344
|
+
disabled,
|
|
345
|
+
tooLargeLabel = "File is larger than {max} MB.",
|
|
346
|
+
removeLabel = "Remove image",
|
|
347
|
+
className
|
|
348
|
+
}) {
|
|
349
|
+
const inputRef = React4.useRef(null);
|
|
350
|
+
const [url, setUrl] = React4.useState(value);
|
|
351
|
+
const [busy, setBusy] = React4.useState(false);
|
|
352
|
+
const [dragging, setDragging] = React4.useState(false);
|
|
353
|
+
const [error, setError] = React4.useState(null);
|
|
354
|
+
React4.useEffect(() => {
|
|
355
|
+
setUrl(value);
|
|
356
|
+
}, [value]);
|
|
357
|
+
const editable = Boolean(onUpload) && !disabled;
|
|
358
|
+
const handleFile = React4.useCallback(
|
|
359
|
+
async (file) => {
|
|
360
|
+
if (!file || !onUpload) return;
|
|
361
|
+
if (file.size > maxBytes) {
|
|
362
|
+
setError(tooLargeLabel.replace("{max}", String(Math.round(maxBytes / 1024 / 1024))));
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
setBusy(true);
|
|
366
|
+
setError(null);
|
|
367
|
+
try {
|
|
368
|
+
const next = await onUpload(file);
|
|
369
|
+
setUrl(next);
|
|
370
|
+
onChange?.(next);
|
|
371
|
+
} catch (err) {
|
|
372
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
373
|
+
} finally {
|
|
374
|
+
setBusy(false);
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
[onUpload, onChange, maxBytes, tooLargeLabel]
|
|
378
|
+
);
|
|
379
|
+
const pick = () => {
|
|
380
|
+
if (editable && !busy) inputRef.current?.click();
|
|
381
|
+
};
|
|
382
|
+
const clear = (e) => {
|
|
383
|
+
e.stopPropagation();
|
|
384
|
+
setUrl(void 0);
|
|
385
|
+
setError(null);
|
|
386
|
+
onChange?.(void 0);
|
|
387
|
+
};
|
|
388
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-4", className), children: [
|
|
389
|
+
/* @__PURE__ */ jsxs(
|
|
390
|
+
"div",
|
|
391
|
+
{
|
|
392
|
+
onClick: pick,
|
|
393
|
+
onKeyDown: (e) => {
|
|
394
|
+
if (editable && (e.key === "Enter" || e.key === " ")) {
|
|
395
|
+
e.preventDefault();
|
|
396
|
+
pick();
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
onDragOver: (e) => {
|
|
400
|
+
if (editable) {
|
|
401
|
+
e.preventDefault();
|
|
402
|
+
setDragging(true);
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
onDragLeave: () => setDragging(false),
|
|
406
|
+
onDrop: (e) => {
|
|
407
|
+
if (!editable) return;
|
|
408
|
+
e.preventDefault();
|
|
409
|
+
setDragging(false);
|
|
410
|
+
void handleFile(e.dataTransfer.files?.[0]);
|
|
411
|
+
},
|
|
412
|
+
role: editable ? "button" : void 0,
|
|
413
|
+
tabIndex: editable ? 0 : void 0,
|
|
414
|
+
className: cn(
|
|
415
|
+
"relative flex h-20 w-20 shrink-0 items-center justify-center overflow-hidden border-2 text-muted-foreground transition-colors",
|
|
416
|
+
shape === "circle" ? "rounded-full" : "rounded-xl",
|
|
417
|
+
url ? "border-solid border-border" : "border-dashed border-border",
|
|
418
|
+
dragging && "border-primary text-primary",
|
|
419
|
+
editable && "cursor-pointer hover:border-primary/40 hover:text-primary/60",
|
|
420
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
421
|
+
),
|
|
422
|
+
children: [
|
|
423
|
+
url ? /* @__PURE__ */ jsx("img", { src: url, alt: "", className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx(ImagePlus, { className: "h-5 w-5" }),
|
|
424
|
+
busy && /* @__PURE__ */ jsx("span", { className: "absolute inset-0 flex items-center justify-center bg-background/70", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) }),
|
|
425
|
+
url && editable && !busy && /* @__PURE__ */ jsx(
|
|
426
|
+
"button",
|
|
427
|
+
{
|
|
428
|
+
type: "button",
|
|
429
|
+
onClick: clear,
|
|
430
|
+
"aria-label": removeLabel,
|
|
431
|
+
className: "absolute right-0 top-0 flex h-5 w-5 items-center justify-center rounded-bl-lg bg-background/90 text-muted-foreground hover:text-foreground",
|
|
432
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
|
|
433
|
+
}
|
|
434
|
+
),
|
|
435
|
+
editable && /* @__PURE__ */ jsx(
|
|
436
|
+
"input",
|
|
437
|
+
{
|
|
438
|
+
ref: inputRef,
|
|
439
|
+
type: "file",
|
|
440
|
+
accept,
|
|
441
|
+
className: "hidden",
|
|
442
|
+
onChange: (e) => {
|
|
443
|
+
const file = e.target.files?.[0];
|
|
444
|
+
e.target.value = "";
|
|
445
|
+
void handleFile(file);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
]
|
|
450
|
+
}
|
|
451
|
+
),
|
|
452
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
453
|
+
label && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: label }),
|
|
454
|
+
hint && !error && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs leading-relaxed text-muted-foreground", children: hint }),
|
|
455
|
+
error && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-destructive", children: error })
|
|
456
|
+
] })
|
|
457
|
+
] });
|
|
458
|
+
}
|
|
459
|
+
var DEFAULT_SLOTS = 4;
|
|
460
|
+
var FALLBACK_SWATCH = "#000000";
|
|
461
|
+
function ColorPalette({
|
|
462
|
+
value,
|
|
463
|
+
onChange,
|
|
464
|
+
slots = DEFAULT_SLOTS,
|
|
465
|
+
labels,
|
|
466
|
+
removeLabel = "Remover cor",
|
|
467
|
+
className
|
|
468
|
+
}) {
|
|
469
|
+
const colors = React4.useMemo(() => {
|
|
470
|
+
const next = Array.from({ length: slots }, (_, i) => value?.[i] ?? "");
|
|
471
|
+
return next;
|
|
472
|
+
}, [value, slots]);
|
|
473
|
+
const commit = (next) => {
|
|
474
|
+
const trimmed = [...next];
|
|
475
|
+
while (trimmed.length > 0 && !trimmed[trimmed.length - 1]) trimmed.pop();
|
|
476
|
+
onChange(trimmed);
|
|
477
|
+
};
|
|
478
|
+
const setSlot = (index, hex) => {
|
|
479
|
+
const next = [...colors];
|
|
480
|
+
next[index] = hex;
|
|
481
|
+
commit(next);
|
|
482
|
+
};
|
|
483
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex gap-2", className), children: colors.map((color, index) => /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1", children: [
|
|
484
|
+
/* @__PURE__ */ jsxs("label", { className: "group relative block cursor-pointer", children: [
|
|
485
|
+
/* @__PURE__ */ jsx(
|
|
486
|
+
"div",
|
|
487
|
+
{
|
|
488
|
+
className: cn(
|
|
489
|
+
"h-10 rounded-lg border transition-colors",
|
|
490
|
+
color ? "border-border" : "border-dashed border-border bg-muted/40"
|
|
491
|
+
),
|
|
492
|
+
style: color ? { backgroundColor: color } : void 0
|
|
493
|
+
}
|
|
494
|
+
),
|
|
495
|
+
/* @__PURE__ */ jsx(
|
|
496
|
+
"input",
|
|
497
|
+
{
|
|
498
|
+
type: "color",
|
|
499
|
+
value: color || FALLBACK_SWATCH,
|
|
500
|
+
"aria-label": labels?.[index] ?? `Cor ${index + 1}`,
|
|
501
|
+
onChange: (e) => setSlot(index, e.target.value),
|
|
502
|
+
className: "absolute inset-0 cursor-pointer opacity-0"
|
|
503
|
+
}
|
|
504
|
+
),
|
|
505
|
+
color && /* @__PURE__ */ jsx(
|
|
506
|
+
"button",
|
|
507
|
+
{
|
|
508
|
+
type: "button",
|
|
509
|
+
"aria-label": removeLabel,
|
|
510
|
+
onClick: (e) => {
|
|
511
|
+
e.preventDefault();
|
|
512
|
+
e.stopPropagation();
|
|
513
|
+
setSlot(index, "");
|
|
514
|
+
},
|
|
515
|
+
className: "absolute -right-1.5 -top-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-foreground/80 text-background opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100",
|
|
516
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-2.5 w-2.5" })
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
] }),
|
|
520
|
+
/* @__PURE__ */ jsx(
|
|
521
|
+
"input",
|
|
522
|
+
{
|
|
523
|
+
type: "text",
|
|
524
|
+
value: color.toUpperCase(),
|
|
525
|
+
placeholder: labels?.[index] ?? `${index + 1}`,
|
|
526
|
+
onChange: (e) => setSlot(index, normalizeHex(e.target.value)),
|
|
527
|
+
className: "w-full truncate bg-transparent text-center text-[10px] text-muted-foreground outline-none placeholder:text-muted-foreground/50"
|
|
528
|
+
}
|
|
529
|
+
)
|
|
530
|
+
] }, index)) });
|
|
531
|
+
}
|
|
532
|
+
function normalizeHex(raw) {
|
|
533
|
+
const cleaned = raw.replace(/[^0-9a-fA-F#]/g, "");
|
|
534
|
+
const withHash = cleaned.startsWith("#") ? cleaned : `#${cleaned}`;
|
|
535
|
+
return withHash.slice(0, 7);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export { ColorPalette, ConfirmDialog, ImageDrop, OptionCards, OptionChips, StepProgress, Switch, normalizeHex };
|
|
539
|
+
//# sourceMappingURL=chunk-3OVZ5JJQ.js.map
|
|
540
|
+
//# sourceMappingURL=chunk-3OVZ5JJQ.js.map
|