erp-pro-ui 0.1.2 → 0.1.4
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/animations.css +40 -0
- package/dist/calendar.cjs +1 -1
- package/dist/calendar.mjs +1 -1
- package/dist/card.cjs +1 -1
- package/dist/card.mjs +1 -1
- package/dist/carousel.cjs +1 -1
- package/dist/carousel.mjs +1 -1
- package/dist/catalog.cjs +6 -0
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.ts +11 -1
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.mjs +6 -0
- package/dist/catalog.mjs.map +1 -1
- package/dist/charts.cjs +2 -1
- package/dist/charts.mjs +2 -2
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.mjs +1 -1
- package/dist/chip.cjs +1 -1
- package/dist/chip.mjs +1 -1
- package/dist/chroma-grid.cjs +1 -1
- package/dist/chroma-grid.mjs +1 -1
- package/dist/chunks/{calendar-xrGmvukr.cjs → calendar-Cpp_Rc7T.cjs} +58 -17
- package/dist/chunks/calendar-Cpp_Rc7T.cjs.map +1 -0
- package/dist/chunks/{calendar-BarcG6x_.mjs → calendar-DrCgT_pj.mjs} +58 -17
- package/dist/chunks/calendar-DrCgT_pj.mjs.map +1 -0
- package/dist/chunks/{card-gt-HZh0h.cjs → card-C5_tFK6Q.cjs} +1 -1
- package/dist/chunks/{card-gt-HZh0h.cjs.map → card-C5_tFK6Q.cjs.map} +1 -1
- package/dist/chunks/{card-CcIF6z2H.mjs → card-Dh8wNv8N.mjs} +1 -1
- package/dist/chunks/{card-CcIF6z2H.mjs.map → card-Dh8wNv8N.mjs.map} +1 -1
- package/dist/chunks/{carousel-DJdqBVRK.mjs → carousel-BYwqI4cA.mjs} +1 -1
- package/dist/chunks/{carousel-DJdqBVRK.mjs.map → carousel-BYwqI4cA.mjs.map} +1 -1
- package/dist/chunks/{carousel-Cq5uwqQt.cjs → carousel-C1338X8h.cjs} +1 -1
- package/dist/chunks/{carousel-Cq5uwqQt.cjs.map → carousel-C1338X8h.cjs.map} +1 -1
- package/dist/chunks/{charts-DugYWvEf.mjs → charts-BYvM4TMG.mjs} +371 -117
- package/dist/chunks/charts-BYvM4TMG.mjs.map +1 -0
- package/dist/chunks/{charts-BpElnsoR.cjs → charts-DbxyHtlX.cjs} +375 -115
- package/dist/chunks/charts-DbxyHtlX.cjs.map +1 -0
- package/dist/chunks/{checkbox-yHuSw-hV.cjs → checkbox-CxOcjoGP.cjs} +1 -1
- package/dist/chunks/{checkbox-yHuSw-hV.cjs.map → checkbox-CxOcjoGP.cjs.map} +1 -1
- package/dist/chunks/{checkbox-DvwlGwWe.mjs → checkbox-Pr49U9F1.mjs} +1 -1
- package/dist/chunks/{checkbox-DvwlGwWe.mjs.map → checkbox-Pr49U9F1.mjs.map} +1 -1
- package/dist/chunks/{chip-DcBji__g.cjs → chip-B4ol1yPk.cjs} +1 -1
- package/dist/chunks/{chip-DcBji__g.cjs.map → chip-B4ol1yPk.cjs.map} +1 -1
- package/dist/chunks/{chip-BGSUmnlO.mjs → chip-DdnBLdpl.mjs} +1 -1
- package/dist/chunks/{chip-BGSUmnlO.mjs.map → chip-DdnBLdpl.mjs.map} +1 -1
- package/dist/chunks/{chroma-grid-Cdeql_2C.mjs → chroma-grid-BAo6V5A7.mjs} +1 -1
- package/dist/chunks/{chroma-grid-Cdeql_2C.mjs.map → chroma-grid-BAo6V5A7.mjs.map} +1 -1
- package/dist/chunks/{chroma-grid-9E9j1s9I.cjs → chroma-grid-CIk0dsNS.cjs} +1 -1
- package/dist/chunks/{chroma-grid-9E9j1s9I.cjs.map → chroma-grid-CIk0dsNS.cjs.map} +1 -1
- package/dist/chunks/{color-palette-BLvDnCOD.cjs → color-palette-2TuEMkAn.cjs} +1 -1
- package/dist/chunks/{color-palette-BLvDnCOD.cjs.map → color-palette-2TuEMkAn.cjs.map} +1 -1
- package/dist/chunks/{color-palette-CXlCDiZz.mjs → color-palette-euKQMWlV.mjs} +1 -1
- package/dist/chunks/{color-palette-CXlCDiZz.mjs.map → color-palette-euKQMWlV.mjs.map} +1 -1
- package/dist/chunks/{combobox-BXu3s0dt.cjs → combobox-CwGubKTt.cjs} +2 -2
- package/dist/chunks/combobox-CwGubKTt.cjs.map +1 -0
- package/dist/chunks/{combobox-CjK-qG4k.mjs → combobox-DrFmkI0F.mjs} +2 -2
- package/dist/chunks/combobox-DrFmkI0F.mjs.map +1 -0
- package/dist/chunks/{data-table-DyEQn9Yj.mjs → data-table-Bo80m7qV.mjs} +8 -8
- package/dist/chunks/{data-table-DyEQn9Yj.mjs.map → data-table-Bo80m7qV.mjs.map} +1 -1
- package/dist/chunks/{data-table-9HELVsYR.cjs → data-table-W1sK5tkL.cjs} +8 -8
- package/dist/chunks/{data-table-9HELVsYR.cjs.map → data-table-W1sK5tkL.cjs.map} +1 -1
- package/dist/chunks/{date-picker-D8gaaMlJ.mjs → date-picker-CNPORxhv.mjs} +87 -17
- package/dist/chunks/date-picker-CNPORxhv.mjs.map +1 -0
- package/dist/chunks/{date-picker-W9om1j7A.cjs → date-picker-CZo68Fkl.cjs} +87 -17
- package/dist/chunks/date-picker-CZo68Fkl.cjs.map +1 -0
- package/dist/chunks/input-BWM6G7jq.cjs +117 -0
- package/dist/chunks/input-BWM6G7jq.cjs.map +1 -0
- package/dist/chunks/input-Bt_r_B_c.mjs +105 -0
- package/dist/chunks/input-Bt_r_B_c.mjs.map +1 -0
- package/dist/chunks/{multi-select-combobox-ELSH_Xr4.mjs → multi-select-combobox-D46M-AN9.mjs} +2 -2
- package/dist/chunks/multi-select-combobox-D46M-AN9.mjs.map +1 -0
- package/dist/chunks/{multi-select-combobox-UW0X15W7.cjs → multi-select-combobox-dS6bJE_e.cjs} +2 -2
- package/dist/chunks/multi-select-combobox-dS6bJE_e.cjs.map +1 -0
- package/dist/chunks/{otp-input-B6zzOEqw.cjs → otp-input-DSW9Ca_D.cjs} +2 -2
- package/dist/chunks/otp-input-DSW9Ca_D.cjs.map +1 -0
- package/dist/chunks/{otp-input-Bg4nQG6x.mjs → otp-input-DeAi4nJ_.mjs} +2 -2
- package/dist/chunks/otp-input-DeAi4nJ_.mjs.map +1 -0
- package/dist/chunks/{progress-bar-C9FZDrju.mjs → progress-bar-B9sy7WBT.mjs} +1 -1
- package/dist/chunks/{progress-bar-C9FZDrju.mjs.map → progress-bar-B9sy7WBT.mjs.map} +1 -1
- package/dist/chunks/{progress-bar-C1OvQ-NI.cjs → progress-bar-BdvQtpm3.cjs} +1 -1
- package/dist/chunks/{progress-bar-C1OvQ-NI.cjs.map → progress-bar-BdvQtpm3.cjs.map} +1 -1
- package/dist/chunks/select-B8UQ6Uq5.mjs +170 -0
- package/dist/chunks/select-B8UQ6Uq5.mjs.map +1 -0
- package/dist/chunks/select-CCUSMvfS.cjs +176 -0
- package/dist/chunks/select-CCUSMvfS.cjs.map +1 -0
- package/dist/chunks/skeleton-BNea1Rcp.cjs +422 -0
- package/dist/chunks/skeleton-BNea1Rcp.cjs.map +1 -0
- package/dist/chunks/skeleton-CtLumdRw.mjs +368 -0
- package/dist/chunks/skeleton-CtLumdRw.mjs.map +1 -0
- package/dist/chunks/stepper-D6qQbZdg.cjs +642 -0
- package/dist/chunks/stepper-D6qQbZdg.cjs.map +1 -0
- package/dist/chunks/stepper-DUknuW2E.mjs +618 -0
- package/dist/chunks/stepper-DUknuW2E.mjs.map +1 -0
- package/dist/chunks/{textarea-CU5C-Zw9.mjs → textarea-Blky_fLK.mjs} +2 -2
- package/dist/chunks/{textarea-CU5C-Zw9.mjs.map → textarea-Blky_fLK.mjs.map} +1 -1
- package/dist/chunks/{textarea-CAUsyu4-.cjs → textarea-ok_NlE2p.cjs} +2 -2
- package/dist/chunks/textarea-ok_NlE2p.cjs.map +1 -0
- package/dist/color-palette.cjs +1 -1
- package/dist/color-palette.mjs +1 -1
- package/dist/colors.css +3 -0
- package/dist/combobox.cjs +1 -1
- package/dist/combobox.mjs +1 -1
- package/dist/components/data-display/charts/AreaChart.d.ts.map +1 -1
- package/dist/components/data-display/charts/BarChart.d.ts +1 -0
- package/dist/components/data-display/charts/BarChart.d.ts.map +1 -1
- package/dist/components/data-display/charts/NeonLineChart.d.ts.map +1 -1
- package/dist/components/data-display/charts/PieChart.d.ts +18 -2
- package/dist/components/data-display/charts/PieChart.d.ts.map +1 -1
- package/dist/components/data-display/charts/PositiveNegativeBarChart.d.ts +21 -0
- package/dist/components/data-display/charts/PositiveNegativeBarChart.d.ts.map +1 -0
- package/dist/components/data-display/charts/StackedBarChart.d.ts.map +1 -1
- package/dist/components/data-display/charts/ThinBreakdownBar.d.ts +3 -0
- package/dist/components/data-display/charts/ThinBreakdownBar.d.ts.map +1 -1
- package/dist/components/data-display/charts/chartStyles.d.ts +24 -0
- package/dist/components/data-display/charts/chartStyles.d.ts.map +1 -0
- package/dist/components/data-display/charts/index.d.ts +2 -0
- package/dist/components/data-display/charts/index.d.ts.map +1 -1
- package/dist/components/data-display/skeleton/Skeleton.d.ts +32 -5
- package/dist/components/data-display/skeleton/Skeleton.d.ts.map +1 -1
- package/dist/components/data-display/skeleton/index.d.ts +2 -2
- package/dist/components/data-display/skeleton/index.d.ts.map +1 -1
- package/dist/components/forms/calendar/Calendar.d.ts.map +1 -1
- package/dist/components/forms/date-picker/DatePicker.d.ts.map +1 -1
- package/dist/components/forms/input/Input.d.ts.map +1 -1
- package/dist/components/forms/input/types.d.ts +5 -0
- package/dist/components/forms/input/types.d.ts.map +1 -1
- package/dist/components/forms/select/Select.d.ts.map +1 -1
- package/dist/components/forms/select/types.d.ts +7 -1
- package/dist/components/forms/select/types.d.ts.map +1 -1
- package/dist/components/navigation/stepper/Stepper1.d.ts +4 -0
- package/dist/components/navigation/stepper/Stepper1.d.ts.map +1 -0
- package/dist/components/navigation/stepper/Stepper2.d.ts +5 -0
- package/dist/components/navigation/stepper/Stepper2.d.ts.map +1 -0
- package/dist/components/navigation/stepper/index.d.ts +4 -1
- package/dist/components/navigation/stepper/index.d.ts.map +1 -1
- package/dist/components/navigation/stepper/types.d.ts +85 -0
- package/dist/components/navigation/stepper/types.d.ts.map +1 -1
- package/dist/data-table.cjs +1 -1
- package/dist/data-table.mjs +1 -1
- package/dist/date-picker.cjs +1 -1
- package/dist/date-picker.mjs +1 -1
- package/dist/docs.cjs +12 -2
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.d.ts.map +1 -1
- package/dist/docs.mjs +12 -2
- package/dist/docs.mjs.map +1 -1
- package/dist/foundation.css +7 -0
- package/dist/index.cjs +32 -19
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +20 -20
- package/dist/input.cjs +1 -1
- package/dist/input.mjs +1 -1
- package/dist/multi-select-combobox.cjs +1 -1
- package/dist/multi-select-combobox.mjs +1 -1
- package/dist/otp-input.cjs +1 -1
- package/dist/otp-input.mjs +1 -1
- package/dist/progress-bar.cjs +1 -1
- package/dist/progress-bar.mjs +1 -1
- package/dist/select.cjs +1 -1
- package/dist/select.mjs +1 -1
- package/dist/skeleton.cjs +9 -1
- package/dist/skeleton.mjs +2 -2
- package/dist/stepper.cjs +5 -1
- package/dist/stepper.mjs +2 -2
- package/dist/textarea.cjs +1 -1
- package/dist/textarea.mjs +1 -1
- package/dist/tokens.css +11 -2
- package/package.json +9 -9
- package/dist/chunks/calendar-BarcG6x_.mjs.map +0 -1
- package/dist/chunks/calendar-xrGmvukr.cjs.map +0 -1
- package/dist/chunks/charts-BpElnsoR.cjs.map +0 -1
- package/dist/chunks/charts-DugYWvEf.mjs.map +0 -1
- package/dist/chunks/combobox-BXu3s0dt.cjs.map +0 -1
- package/dist/chunks/combobox-CjK-qG4k.mjs.map +0 -1
- package/dist/chunks/date-picker-D8gaaMlJ.mjs.map +0 -1
- package/dist/chunks/date-picker-W9om1j7A.cjs.map +0 -1
- package/dist/chunks/input-D9qZNqXV.cjs +0 -99
- package/dist/chunks/input-D9qZNqXV.cjs.map +0 -1
- package/dist/chunks/input-wNqevfQ4.mjs +0 -87
- package/dist/chunks/input-wNqevfQ4.mjs.map +0 -1
- package/dist/chunks/multi-select-combobox-ELSH_Xr4.mjs.map +0 -1
- package/dist/chunks/multi-select-combobox-UW0X15W7.cjs.map +0 -1
- package/dist/chunks/otp-input-B6zzOEqw.cjs.map +0 -1
- package/dist/chunks/otp-input-Bg4nQG6x.mjs.map +0 -1
- package/dist/chunks/select-D71tk6-I.mjs +0 -152
- package/dist/chunks/select-D71tk6-I.mjs.map +0 -1
- package/dist/chunks/select-WC_kPqUP.cjs +0 -158
- package/dist/chunks/select-WC_kPqUP.cjs.map +0 -1
- package/dist/chunks/skeleton-BhYWOp0Q.mjs +0 -215
- package/dist/chunks/skeleton-BhYWOp0Q.mjs.map +0 -1
- package/dist/chunks/skeleton-DTXpHYYB.cjs +0 -221
- package/dist/chunks/skeleton-DTXpHYYB.cjs.map +0 -1
- package/dist/chunks/stepper-D4yQsQB0.mjs +0 -261
- package/dist/chunks/stepper-D4yQsQB0.mjs.map +0 -1
- package/dist/chunks/stepper-fY-Sx72k.cjs +0 -267
- package/dist/chunks/stepper-fY-Sx72k.cjs.map +0 -1
- package/dist/chunks/textarea-CAUsyu4-.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"charts-DugYWvEf.mjs","names":[],"sources":["../../src/components/data-display/charts/chartPalette.ts","../../src/components/data-display/charts/NeonLineChart.tsx","../../src/components/data-display/charts/StackedBarChart.tsx","../../src/components/data-display/charts/ThinBreakdownBar.tsx","../../src/components/data-display/charts/AreaChart.tsx","../../src/components/data-display/charts/BarChart.tsx","../../src/components/data-display/charts/PieChart.tsx"],"sourcesContent":["const chartColorSlots = [\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n] as const;\n\nexport type ChartColorSlot = (typeof chartColorSlots)[number];\nexport type ChartColorToken = `chart-${ChartColorSlot}`;\n\nexport const chartColorTokens = chartColorSlots.map(\n (slot) => `chart-${slot}` as ChartColorToken,\n);\n\nconst chartPalette = chartColorSlots.map((slot) => `var(--ds-chart-${slot})`);\n\ntype RgbColor = {\n r: number;\n g: number;\n b: number;\n};\n\nconst resolvedColorCache = new Map<string, RgbColor | null>();\n\nconst chartTokenPattern = /^chart-(\\d+)$/i;\nconst chartVariablePattern = /^--((?:ds|color)-chart-(\\d+))$/i;\n\nconst getChartSlotValue = (slot: ChartColorSlot | ChartColorToken): number =>\n typeof slot === \"number\" ? slot : Number(slot.replace(\"chart-\", \"\"));\n\nexport const getChartColorVar = (\n slot: ChartColorSlot | ChartColorToken,\n namespace: \"ds\" | \"color\" = \"ds\",\n): string => `var(--${namespace}-chart-${getChartSlotValue(slot)})`;\n\nexport const normalizeChartColorValue = (\n value?: string,\n): string | undefined => {\n const normalizedValue = value?.trim();\n\n if (!normalizedValue) {\n return undefined;\n }\n\n const tokenMatch = normalizedValue.match(chartTokenPattern);\n if (tokenMatch) {\n return `var(--ds-chart-${tokenMatch[1]})`;\n }\n\n const variableMatch = normalizedValue.match(chartVariablePattern);\n if (variableMatch) {\n return `var(--${variableMatch[1]})`;\n }\n\n return normalizedValue;\n};\n\nconst getThemeSignature = (): string => {\n if (typeof document === \"undefined\") return \"\";\n\n const root = document.documentElement;\n return [\n root.getAttribute(\"data-brand\") ?? \"\",\n root.getAttribute(\"data-mode\") ?? \"\",\n root.getAttribute(\"data-theme\") ?? \"\",\n ].join(\"|\");\n};\n\nconst resolveColor = (value: string): RgbColor | null => {\n if (typeof document === \"undefined\") return null;\n\n const cacheKey = `${getThemeSignature()}::${value}`;\n const cached = resolvedColorCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const probe = document.createElement(\"span\");\n probe.style.color = value;\n probe.style.position = \"fixed\";\n probe.style.opacity = \"0\";\n probe.style.pointerEvents = \"none\";\n document.body.appendChild(probe);\n\n const computedColor = getComputedStyle(probe).color;\n document.body.removeChild(probe);\n\n const match = computedColor.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/i);\n\n const resolved = match\n ? {\n r: Number(match[1]),\n g: Number(match[2]),\n b: Number(match[3]),\n }\n : null;\n\n resolvedColorCache.set(cacheKey, resolved);\n return resolved;\n};\n\nconst getColorDistance = (left: RgbColor, right: RgbColor): number => {\n const deltaR = left.r - right.r;\n const deltaG = left.g - right.g;\n const deltaB = left.b - right.b;\n\n return Math.sqrt(deltaR ** 2 + deltaG ** 2 + deltaB ** 2);\n};\n\nconst isTooSimilar = (\n candidate: string,\n usedColors: readonly string[],\n minDistance = 84,\n): boolean => {\n if (usedColors.includes(candidate)) {\n return true;\n }\n\n const candidateRgb = resolveColor(candidate);\n if (!candidateRgb) {\n return false;\n }\n\n return usedColors.some((usedColor) => {\n const usedRgb = resolveColor(usedColor);\n return usedRgb\n ? getColorDistance(candidateRgb, usedRgb) < minDistance\n : false;\n });\n};\n\nexport const getChartPalette = (count = chartPalette.length): string[] =>\n Array.from(\n { length: count },\n (_, index) => chartPalette[index % chartPalette.length],\n );\n\nexport const normalizeChartColors = (\n requestedColors: readonly (string | undefined)[],\n): string[] => {\n const usedColors: string[] = [];\n let paletteIndex = 0;\n\n const getNextDistinctPaletteColor = (): string => {\n for (let attempt = 0; attempt < chartPalette.length; attempt++) {\n const candidate =\n chartPalette[(paletteIndex + attempt) % chartPalette.length];\n\n if (!isTooSimilar(candidate, usedColors)) {\n paletteIndex = (paletteIndex + attempt + 1) % chartPalette.length;\n return candidate;\n }\n }\n\n const fallback = chartPalette[paletteIndex % chartPalette.length];\n paletteIndex = (paletteIndex + 1) % chartPalette.length;\n return fallback;\n };\n\n return requestedColors.map((requestedColor) => {\n const normalizedRequestedColor = normalizeChartColorValue(requestedColor);\n const resolvedColor =\n normalizedRequestedColor &&\n !isTooSimilar(normalizedRequestedColor, usedColors)\n ? normalizedRequestedColor\n : getNextDistinctPaletteColor();\n\n usedColors.push(resolvedColor);\n return resolvedColor;\n });\n};\n","\"use client\";\n\nimport React from \"react\";\nimport {\n LineChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n} from \"recharts\";\n\nimport {\n getChartColorVar,\n normalizeChartColorValue,\n normalizeChartColors,\n} from \"./chartPalette\";\n\ninterface DataPoint {\n name: string;\n value: number;\n}\n\ninterface NeonLineChartProps {\n data: DataPoint[];\n height?: number | string;\n lineColorStop1?: string;\n lineColorStop2?: string;\n className?: string;\n glowColor?: string;\n}\n\nexport const NeonLineChart: React.FC<NeonLineChartProps> = ({\n data,\n height = 300,\n lineColorStop1 = getChartColorVar(2),\n lineColorStop2 = getChartColorVar(1),\n glowColor = getChartColorVar(1),\n className = \"\",\n}) => {\n const [normalizedStop1, normalizedStop2] = React.useMemo(\n () => normalizeChartColors([lineColorStop1, lineColorStop2]),\n [lineColorStop1, lineColorStop2],\n );\n const normalizedGlowColor = React.useMemo(\n () => normalizeChartColorValue(glowColor) ?? getChartColorVar(1),\n [glowColor],\n );\n\n return (\n <div className={`w-full relative ${className}`} style={{ height }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart\n data={data}\n margin={{ top: 20, right: 30, left: 10, bottom: 20 }}\n >\n <defs>\n {/* Linear Gradient for the Line */}\n <linearGradient id=\"neonGradient\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">\n <stop offset=\"0%\" stopColor={normalizedStop1} />\n <stop offset=\"100%\" stopColor={normalizedStop2} />\n </linearGradient>\n\n {/* Glowing Drop Shadow Filter */}\n <filter id=\"neonGlow\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\">\n <feDropShadow\n dx=\"0\"\n dy=\"6\"\n stdDeviation=\"8\"\n floodColor={normalizedGlowColor}\n floodOpacity=\"0.8\"\n />\n <feDropShadow\n dx=\"0\"\n dy=\"0\"\n stdDeviation=\"15\"\n floodColor={normalizedStop1}\n floodOpacity=\"0.3\"\n />\n </filter>\n </defs>\n\n {/* Minimal Grid */}\n <CartesianGrid\n strokeDasharray=\"3 3\"\n vertical={false}\n stroke=\"var(--ds-color-border)\"\n opacity={0.5}\n />\n\n <XAxis\n dataKey=\"name\"\n axisLine={false}\n tickLine={false}\n tick={{ fill: \"var(--ds-color-fg-muted)\", fontSize: 12 }}\n dy={10}\n />\n\n <YAxis\n axisLine={false}\n tickLine={false}\n tick={{ fill: \"var(--ds-color-fg-muted)\", fontSize: 12 }}\n dx={-10}\n />\n\n <Tooltip\n contentStyle={{\n backgroundColor:\n \"color-mix(in srgb, var(--ds-color-surface) 92%, transparent)\",\n border: \"1px solid var(--ds-color-border)\",\n borderRadius: \"8px\",\n backdropFilter: \"blur(8px)\",\n color: \"var(--ds-color-fg)\",\n }}\n itemStyle={{ color: \"var(--ds-color-fg)\" }}\n />\n\n {/* The Neon Line */}\n <Line\n type=\"monotone\"\n dataKey=\"value\"\n stroke=\"url(#neonGradient)\"\n strokeWidth={3}\n dot={false}\n activeDot={{\n r: 6,\n fill: \"var(--ds-color-surface)\",\n stroke: normalizedStop2,\n strokeWidth: 2,\n }}\n filter=\"url(#neonGlow)\"\n />\n </LineChart>\n </ResponsiveContainer>\n </div>\n );\n};\n","\"use client\";\n\nimport React from \"react\";\nimport {\n BarChart as RechartsBarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n Legend,\n ResponsiveContainer,\n} from \"recharts\";\n\nimport { normalizeChartColors } from \"./chartPalette\";\n\nexport interface StackedBarData {\n name: string;\n [key: string]: string | number;\n}\n\ninterface StackedBarChartProps {\n data: StackedBarData[];\n categories: { key: string; color: string; label: string }[];\n height?: number | string;\n yAxisDomain?: [number, number];\n className?: string;\n}\n\nexport const StackedBarChart: React.FC<StackedBarChartProps> = ({\n data,\n categories,\n height = 300,\n yAxisDomain,\n className = \"\",\n}) => {\n const normalizedCategories = React.useMemo(() => {\n const normalizedColors = normalizeChartColors(\n categories.map((category) => category.color),\n );\n\n return categories.map((category, index) => ({\n ...category,\n color: normalizedColors[index] ?? category.color,\n }));\n }, [categories]);\n\n return (\n <div className={`w-full ${className}`} style={{ height }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n margin={{ top: 20, right: 30, left: 20, bottom: 5 }}\n >\n <CartesianGrid\n strokeDasharray=\"3 3\"\n vertical={false}\n stroke=\"var(--ds-color-border)\"\n opacity={0.4}\n />\n <XAxis\n dataKey=\"name\"\n axisLine={false}\n tickLine={false}\n tick={{ fill: \"var(--ds-color-fg-muted)\", fontSize: 12 }}\n dy={10}\n />\n <YAxis\n axisLine={false}\n tickLine={false}\n tick={{ fill: \"var(--ds-color-fg-muted)\", fontSize: 12 }}\n dx={-10}\n domain={yAxisDomain}\n />\n <Tooltip\n cursor={{\n fill: \"color-mix(in srgb, var(--ds-color-accent) 10%, transparent)\",\n }}\n contentStyle={{\n backgroundColor:\n \"color-mix(in srgb, var(--ds-color-surface) 92%, transparent)\",\n border: \"1px solid var(--ds-color-border)\",\n borderRadius: \"8px\",\n backdropFilter: \"blur(8px)\",\n color: \"var(--ds-color-fg)\",\n }}\n />\n <Legend\n iconType=\"circle\"\n wrapperStyle={{\n paddingTop: \"20px\",\n fontSize: \"12px\",\n color: \"var(--color-neutral-300)\",\n }}\n />\n\n {normalizedCategories.map((cat, index) => {\n // Apply rounded radius only to the top bar in the stack\n const isTop = index === normalizedCategories.length - 1;\n const radius: [number, number, number, number] = isTop\n ? [6, 6, 0, 0]\n : [0, 0, 0, 0];\n\n return (\n <Bar\n key={cat.key}\n dataKey={cat.key}\n name={cat.label}\n stackId=\"a\"\n fill={cat.color}\n radius={radius}\n barSize={32}\n />\n );\n })}\n </RechartsBarChart>\n </ResponsiveContainer>\n </div>\n );\n};\n","\"use client\";\n\nimport React from \"react\";\n\nimport { normalizeChartColors } from \"./chartPalette\";\n\nexport interface BreakdownSegment {\n id?: string;\n label: string;\n value: number; // The absolute value or percentage\n color: string;\n}\n\ninterface ThinBreakdownBarProps {\n data: BreakdownSegment[];\n className?: string;\n showLabels?: boolean;\n}\n\nexport const ThinBreakdownBar: React.FC<ThinBreakdownBarProps> = ({\n data: segments,\n className = \"\",\n showLabels = true,\n}) => {\n const [activeSegmentKey, setActiveSegmentKey] = React.useState<string | null>(\n null,\n );\n\n const normalizedSegments = React.useMemo(() => {\n const normalizedColors = normalizeChartColors(\n segments.map((segment) => segment.color),\n );\n\n const totalValue = segments.reduce((sum, item) => sum + item.value, 0);\n\n return segments.map((segment, index) => ({\n ...segment,\n key: segment.id || `segment-${index}`,\n color: normalizedColors[index] ?? segment.color,\n widthPercent:\n totalValue > 0 ? Math.max((segment.value / totalValue) * 100, 0) : 0,\n }));\n }, [segments]);\n\n const segmentsWithMetrics = React.useMemo(() => {\n let runningPercent = 0;\n\n return normalizedSegments.map((segment) => {\n const nextSegment = {\n ...segment,\n centerPercent: runningPercent + segment.widthPercent / 2,\n };\n\n runningPercent += segment.widthPercent;\n return nextSegment;\n });\n }, [normalizedSegments]);\n\n const activeSegment = React.useMemo(\n () =>\n segmentsWithMetrics.find((segment) => segment.key === activeSegmentKey) ??\n null,\n [activeSegmentKey, segmentsWithMetrics],\n );\n\n return (\n <div className={`w-full flex flex-col gap-3 ${className}`}>\n <div className=\"relative\">\n {activeSegment && (\n <div\n className=\"pointer-events-none absolute -top-10 z-10 -translate-x-1/2 rounded-full border border-border/70 bg-background/95 px-2.5 py-1 text-[11px] font-medium text-foreground shadow-lg backdrop-blur-md\"\n style={{ left: `${activeSegment.centerPercent}%` }}\n >\n <span>{activeSegment.label}</span>\n <span className=\"mx-1 text-muted-foreground\">•</span>\n <span style={{ color: activeSegment.color }}>\n {activeSegment.value}\n </span>\n </div>\n )}\n\n <div className=\"rounded-full bg-background-tertiary/80 p-0.5\">\n <div\n className=\"flex w-full gap-1\"\n onMouseLeave={() => setActiveSegmentKey(null)}\n >\n {segmentsWithMetrics.map((segment) => {\n const isActive = activeSegmentKey === segment.key;\n\n return (\n <div\n key={segment.key}\n className=\"relative flex h-2.5 min-w-0 items-center\"\n style={{ width: `${segment.widthPercent}%` }}\n onMouseEnter={() => setActiveSegmentKey(segment.key)}\n >\n <div\n className=\"h-full w-full rounded-full transition-[transform,filter,box-shadow,opacity] duration-200 ease-out\"\n style={{\n backgroundColor: segment.color,\n opacity: activeSegmentKey && !isActive ? 0.72 : 1,\n transform: isActive ? \"scaleY(1.3)\" : \"scaleY(1)\",\n filter: isActive\n ? \"saturate(1.1) brightness(1.05)\"\n : \"none\",\n boxShadow: isActive\n ? `inset 0 1px 1px rgba(255,255,255,0.28), 0 0 0 1px color-mix(in srgb, ${segment.color} 35%, transparent), 0 0 14px color-mix(in srgb, ${segment.color} 45%, transparent)`\n : `inset 0 1px 1px rgba(255,255,255,0.2), 0 0 8px color-mix(in srgb, ${segment.color} 30%, transparent)`,\n }}\n title={`${segment.label}: ${segment.value}`}\n />\n </div>\n );\n })}\n </div>\n </div>\n </div>\n\n {showLabels && (\n <div className=\"flex w-full items-start gap-1 px-0.5\">\n {segmentsWithMetrics.map((segment) => {\n const isActive = activeSegmentKey === segment.key;\n\n return (\n <div\n key={`label-${segment.key}`}\n className=\"flex min-w-0 justify-center\"\n style={{ width: `${segment.widthPercent}%` }}\n >\n <span\n className=\"whitespace-nowrap px-1 text-center text-[11px] font-medium tracking-wide text-muted-foreground transition-colors duration-200\"\n style={isActive ? { color: segment.color } : undefined}\n >\n {segment.label}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n","\"use client\";\n\nimport React from \"react\";\nimport {\n AreaChart as RechartsAreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n} from \"recharts\";\n\nimport { normalizeChartColors } from \"./chartPalette\";\n\nexport interface AreaChartData {\n name: string;\n [key: string]: string | number;\n}\n\ninterface AreaChartProps {\n data: AreaChartData[];\n categories: { key: string; color: string }[];\n height?: number | string;\n className?: string;\n showGrid?: boolean;\n}\n\nexport const AreaChart: React.FC<AreaChartProps> = ({\n data,\n categories,\n height = 300,\n className = \"\",\n showGrid = true,\n}) => {\n const normalizedCategories = React.useMemo(() => {\n const normalizedColors = normalizeChartColors(\n categories.map((category) => category.color),\n );\n\n return categories.map((category, index) => ({\n ...category,\n color: normalizedColors[index] ?? category.color,\n }));\n }, [categories]);\n\n return (\n <div className={`w-full ${className}`} style={{ height }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsAreaChart\n data={data}\n margin={{ top: 10, right: 30, left: 0, bottom: 0 }}\n >\n <defs>\n {normalizedCategories.map((cat) => (\n <linearGradient\n key={`gradient-${cat.key}`}\n id={`color-${cat.key}`}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n >\n <stop offset=\"5%\" stopColor={cat.color} stopOpacity={0.3} />\n <stop offset=\"95%\" stopColor={cat.color} stopOpacity={0} />\n </linearGradient>\n ))}\n </defs>\n\n {showGrid && (\n <CartesianGrid\n strokeDasharray=\"3 3\"\n vertical={false}\n stroke=\"var(--ds-color-border)\"\n opacity={0.5}\n />\n )}\n\n <XAxis\n dataKey=\"name\"\n axisLine={false}\n tickLine={false}\n tick={{ fill: \"var(--ds-color-fg-muted)\", fontSize: 12 }}\n dy={10}\n />\n\n <YAxis\n axisLine={false}\n tickLine={false}\n tick={{ fill: \"var(--ds-color-fg-muted)\", fontSize: 12 }}\n dx={-10}\n />\n\n <Tooltip\n contentStyle={{\n backgroundColor:\n \"color-mix(in srgb, var(--ds-color-surface) 92%, transparent)\",\n border: \"1px solid var(--ds-color-border)\",\n borderRadius: \"8px\",\n backdropFilter: \"blur(8px)\",\n color: \"var(--ds-color-fg)\",\n }}\n itemStyle={{ color: \"var(--ds-color-fg)\" }}\n />\n\n {normalizedCategories.map((cat) => (\n <Area\n key={cat.key}\n type=\"monotone\"\n dataKey={cat.key}\n stroke={cat.color}\n strokeWidth={2}\n fillOpacity={1}\n fill={`url(#color-${cat.key})`}\n />\n ))}\n </RechartsAreaChart>\n </ResponsiveContainer>\n </div>\n );\n};\n","\"use client\";\n\nimport React from \"react\";\nimport {\n BarChart as RechartsBarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n} from \"recharts\";\n\nimport { normalizeChartColors } from \"./chartPalette\";\n\nexport interface BarChartData {\n name: string;\n [key: string]: string | number;\n}\n\ninterface BarChartProps {\n data: BarChartData[];\n categories: { key: string; color: string }[];\n height?: number | string;\n className?: string;\n layout?: \"horizontal\" | \"vertical\";\n}\n\nexport const BarChart: React.FC<BarChartProps> = ({\n data,\n categories,\n height = 300,\n className = \"\",\n layout = \"horizontal\",\n}) => {\n const normalizedCategories = React.useMemo(() => {\n const normalizedColors = normalizeChartColors(\n categories.map((category) => category.color),\n );\n\n return categories.map((category, index) => ({\n ...category,\n color: normalizedColors[index] ?? category.color,\n }));\n }, [categories]);\n\n return (\n <div className={`w-full ${className}`} style={{ height }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n layout={layout}\n margin={{ top: 20, right: 30, left: 20, bottom: 5 }}\n >\n <CartesianGrid\n strokeDasharray=\"3 3\"\n horizontal={layout === \"horizontal\"}\n vertical={layout === \"vertical\"}\n stroke=\"var(--ds-color-border)\"\n opacity={0.4}\n />\n\n {layout === \"horizontal\" ? (\n <>\n <XAxis\n dataKey=\"name\"\n axisLine={false}\n tickLine={false}\n tick={{\n fill: \"var(--ds-color-fg-muted)\",\n fontSize: 12,\n }}\n dy={10}\n />\n <YAxis\n axisLine={false}\n tickLine={false}\n tick={{\n fill: \"var(--ds-color-fg-muted)\",\n fontSize: 12,\n }}\n dx={-10}\n />\n </>\n ) : (\n <>\n <XAxis\n type=\"number\"\n axisLine={false}\n tickLine={false}\n tick={{\n fill: \"var(--ds-color-fg-muted)\",\n fontSize: 12,\n }}\n dy={10}\n />\n <YAxis\n dataKey=\"name\"\n type=\"category\"\n axisLine={false}\n tickLine={false}\n tick={{\n fill: \"var(--ds-color-fg-muted)\",\n fontSize: 12,\n }}\n dx={-10}\n />\n </>\n )}\n\n <Tooltip\n cursor={{\n fill: \"color-mix(in srgb, var(--ds-color-accent) 10%, transparent)\",\n }}\n contentStyle={{\n backgroundColor:\n \"color-mix(in srgb, var(--ds-color-surface) 92%, transparent)\",\n border: \"1px solid var(--ds-color-border)\",\n borderRadius: \"8px\",\n backdropFilter: \"blur(8px)\",\n color: \"var(--ds-color-fg)\",\n }}\n />\n\n {normalizedCategories.map((cat) => (\n <Bar\n key={cat.key}\n dataKey={cat.key}\n fill={cat.color}\n radius={layout === \"horizontal\" ? [4, 4, 0, 0] : [0, 4, 4, 0]}\n />\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n </div>\n );\n};\n","\"use client\";\n\nimport React from \"react\";\nimport {\n PieChart as RechartsPieChart,\n Pie,\n Cell,\n Tooltip,\n Legend,\n ResponsiveContainer,\n} from \"recharts\";\n\nimport { normalizeChartColors } from \"./chartPalette\";\n\nexport interface PieChartData {\n name: string;\n value: number;\n}\n\ninterface PieChartProps {\n data: PieChartData[];\n colors: string[];\n height?: number | string;\n className?: string;\n variant?: \"pie\" | \"donut\";\n}\n\nexport const PieChart: React.FC<PieChartProps> = ({\n data,\n colors,\n height = 300,\n className = \"\",\n variant = \"donut\",\n}) => {\n const innerRadius = variant === \"donut\" ? \"60%\" : 0;\n const normalizedColors = React.useMemo(\n () => normalizeChartColors(colors),\n [colors],\n );\n\n return (\n <div className={`w-full ${className}`} style={{ height }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsPieChart>\n <Pie\n data={data}\n cx=\"50%\"\n cy=\"50%\"\n innerRadius={innerRadius}\n outerRadius=\"80%\"\n paddingAngle={variant === \"donut\" ? 2 : 0}\n dataKey=\"value\"\n stroke=\"none\"\n >\n {data.map((entry, index) => (\n <Cell\n key={`cell-${index}`}\n fill={normalizedColors[index % normalizedColors.length]}\n />\n ))}\n </Pie>\n\n <Tooltip\n contentStyle={{\n backgroundColor:\n \"color-mix(in srgb, var(--ds-color-surface) 92%, transparent)\",\n border: \"1px solid var(--ds-color-border)\",\n borderRadius: \"8px\",\n backdropFilter: \"blur(8px)\",\n color: \"var(--ds-color-fg)\",\n }}\n itemStyle={{ color: \"var(--ds-color-fg)\" }}\n />\n\n <Legend\n iconType=\"circle\"\n wrapperStyle={{\n fontSize: \"12px\",\n color: \"var(--color-neutral-300)\",\n }}\n />\n </RechartsPieChart>\n </ResponsiveContainer>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"combobox-BXu3s0dt.cjs","names":[],"sources":["../../src/components/forms/combobox/Combobox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { CheckIcon, ChevronDownIcon } from \"../../icons\";\nimport { mergeClassNames } from \"../../../utils\";\n\nexport interface ComboboxOption {\n label: string;\n value: string;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n className?: string;\n bgClassName?: string;\n createOptionLabel?: string;\n onCreateOption?: () => void;\n}\n\nconst Combobox: React.FC<ComboboxProps> = ({\n options,\n value,\n onChange,\n placeholder = \"Select...\",\n className,\n bgClassName = \"bg-background-secondary\",\n createOptionLabel,\n onCreateOption,\n}) => {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [visible, setVisible] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n\n // Filter options by search\n const filteredOptions = options.filter((opt) =>\n opt.label.toLowerCase().includes(search.toLowerCase()),\n );\n\n // Close dropdown on outside click\n useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n setSearch(\"\");\n }\n };\n if (open) {\n document.addEventListener(\"mousedown\", handleClick);\n }\n return () => document.removeEventListener(\"mousedown\", handleClick);\n }, [open]);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n return (\n <div\n ref={ref}\n className={mergeClassNames(\"relative w-full\", className)}\n tabIndex={0}\n >\n <motion.div\n style={{\n backgroundImage: useMotionTemplate`\n radial-gradient(\n ${visible ? `${radius}px` : \"0px\"} circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={handleMouseMove}\n onMouseEnter={() => setVisible(true)}\n onMouseLeave={() => setVisible(false)}\n className=\"group/combobox rounded-lg border-border p-[2px] transition duration-300 hover:border-accent\"\n >\n <div\n className={mergeClassNames(\n \"shadow-input flex h-10 w-full cursor-pointer items-center justify-between rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/combobox:shadow-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none\",\n bgClassName,\n )}\n onClick={() => {\n setOpen((current) => {\n if (current) {\n setSearch(\"\");\n }\n\n return !current;\n });\n }}\n >\n {value ? (\n <span className=\"flex-1 truncate text-foreground\">\n {options.find((opt) => opt.value === value)?.label}\n </span>\n ) : (\n <span className=\"flex-1 text-muted-foreground\">{placeholder}</span>\n )}\n <span\n className={mergeClassNames(\n \"ml-2 text-muted-foreground transition-transform duration-300\",\n open ? \"rotate-180\" : \"rotate-0\",\n )}\n >\n <ChevronDownIcon\n width={24}\n height={24}\n color=\"currentColor\"\n className=\"h-5 w-5\"\n />\n </span>\n </div>\n </motion.div>\n {open && (\n <div className=\"absolute right-0 left-0 z-20 mt-1 flex max-h-60 flex-col rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition\">\n {/* Sticky search input */}\n <div className=\"sticky top-0 z-10 rounded-t-lg border-b border-border-muted bg-elevated/95 backdrop-blur-sm\">\n <input\n autoFocus\n className=\"w-full bg-transparent px-3 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent\"\n placeholder=\"Type to search...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onClick={(e) => e.stopPropagation()}\n />\n </div>\n {/* Scrollable options */}\n <div className=\"max-h-80 flex-1 overflow-auto\">\n {filteredOptions.length === 0 && !createOptionLabel && (\n <div className=\"px-3 py-2 text-muted-foreground\">No options</div>\n )}\n {filteredOptions.map((opt) => (\n <div\n key={opt.value}\n className={mergeClassNames(\n \"mx-1 my-1 flex cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-sm text-foreground transition\",\n opt.value === value\n ? \"bg-accent-subtle text-accent font-semibold\"\n : \"\",\n \"hover:bg-accent hover:text-on-accent\",\n )}\n onClick={() => {\n onChange(opt.value);\n setSearch(\"\");\n setOpen(false);\n }}\n >\n <span className=\"flex w-5 items-center justify-center\">\n {opt.value === value && (\n <CheckIcon className=\"text-accent\" width={18} height={18} />\n )}\n </span>\n <span className=\"min-w-0 flex-1 truncate\">{opt.label}</span>\n </div>\n ))}\n </div>\n {/* Sticky create option */}\n {createOptionLabel && onCreateOption && (\n <div className=\"sticky bottom-0 z-10 rounded-b-lg border-t border-border-muted bg-elevated/95 backdrop-blur-sm\">\n <div\n className=\"mx-1 my-1 flex cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-sm font-semibold text-foreground transition hover:bg-accent hover:text-on-accent\"\n onClick={() => {\n onCreateOption();\n setSearch(\"\");\n setOpen(false);\n }}\n >\n <span className=\"flex w-5 items-center justify-center\">\n {/* Optionally add an icon here */}\n </span>\n <span className=\"min-w-0 flex-1 truncate\">\n {createOptionLabel}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n\nexport default Combobox;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"combobox-CjK-qG4k.mjs","names":[],"sources":["../../src/components/forms/combobox/Combobox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { CheckIcon, ChevronDownIcon } from \"../../icons\";\nimport { mergeClassNames } from \"../../../utils\";\n\nexport interface ComboboxOption {\n label: string;\n value: string;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n className?: string;\n bgClassName?: string;\n createOptionLabel?: string;\n onCreateOption?: () => void;\n}\n\nconst Combobox: React.FC<ComboboxProps> = ({\n options,\n value,\n onChange,\n placeholder = \"Select...\",\n className,\n bgClassName = \"bg-background-secondary\",\n createOptionLabel,\n onCreateOption,\n}) => {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [visible, setVisible] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n\n // Filter options by search\n const filteredOptions = options.filter((opt) =>\n opt.label.toLowerCase().includes(search.toLowerCase()),\n );\n\n // Close dropdown on outside click\n useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n setSearch(\"\");\n }\n };\n if (open) {\n document.addEventListener(\"mousedown\", handleClick);\n }\n return () => document.removeEventListener(\"mousedown\", handleClick);\n }, [open]);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n return (\n <div\n ref={ref}\n className={mergeClassNames(\"relative w-full\", className)}\n tabIndex={0}\n >\n <motion.div\n style={{\n backgroundImage: useMotionTemplate`\n radial-gradient(\n ${visible ? `${radius}px` : \"0px\"} circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={handleMouseMove}\n onMouseEnter={() => setVisible(true)}\n onMouseLeave={() => setVisible(false)}\n className=\"group/combobox rounded-lg border-border p-[2px] transition duration-300 hover:border-accent\"\n >\n <div\n className={mergeClassNames(\n \"shadow-input flex h-10 w-full cursor-pointer items-center justify-between rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/combobox:shadow-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none\",\n bgClassName,\n )}\n onClick={() => {\n setOpen((current) => {\n if (current) {\n setSearch(\"\");\n }\n\n return !current;\n });\n }}\n >\n {value ? (\n <span className=\"flex-1 truncate text-foreground\">\n {options.find((opt) => opt.value === value)?.label}\n </span>\n ) : (\n <span className=\"flex-1 text-muted-foreground\">{placeholder}</span>\n )}\n <span\n className={mergeClassNames(\n \"ml-2 text-muted-foreground transition-transform duration-300\",\n open ? \"rotate-180\" : \"rotate-0\",\n )}\n >\n <ChevronDownIcon\n width={24}\n height={24}\n color=\"currentColor\"\n className=\"h-5 w-5\"\n />\n </span>\n </div>\n </motion.div>\n {open && (\n <div className=\"absolute right-0 left-0 z-20 mt-1 flex max-h-60 flex-col rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition\">\n {/* Sticky search input */}\n <div className=\"sticky top-0 z-10 rounded-t-lg border-b border-border-muted bg-elevated/95 backdrop-blur-sm\">\n <input\n autoFocus\n className=\"w-full bg-transparent px-3 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent\"\n placeholder=\"Type to search...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onClick={(e) => e.stopPropagation()}\n />\n </div>\n {/* Scrollable options */}\n <div className=\"max-h-80 flex-1 overflow-auto\">\n {filteredOptions.length === 0 && !createOptionLabel && (\n <div className=\"px-3 py-2 text-muted-foreground\">No options</div>\n )}\n {filteredOptions.map((opt) => (\n <div\n key={opt.value}\n className={mergeClassNames(\n \"mx-1 my-1 flex cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-sm text-foreground transition\",\n opt.value === value\n ? \"bg-accent-subtle text-accent font-semibold\"\n : \"\",\n \"hover:bg-accent hover:text-on-accent\",\n )}\n onClick={() => {\n onChange(opt.value);\n setSearch(\"\");\n setOpen(false);\n }}\n >\n <span className=\"flex w-5 items-center justify-center\">\n {opt.value === value && (\n <CheckIcon className=\"text-accent\" width={18} height={18} />\n )}\n </span>\n <span className=\"min-w-0 flex-1 truncate\">{opt.label}</span>\n </div>\n ))}\n </div>\n {/* Sticky create option */}\n {createOptionLabel && onCreateOption && (\n <div className=\"sticky bottom-0 z-10 rounded-b-lg border-t border-border-muted bg-elevated/95 backdrop-blur-sm\">\n <div\n className=\"mx-1 my-1 flex cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-sm font-semibold text-foreground transition hover:bg-accent hover:text-on-accent\"\n onClick={() => {\n onCreateOption();\n setSearch(\"\");\n setOpen(false);\n }}\n >\n <span className=\"flex w-5 items-center justify-center\">\n {/* Optionally add an icon here */}\n </span>\n <span className=\"min-w-0 flex-1 truncate\">\n {createOptionLabel}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n\nexport default Combobox;\n"],"mappings":";;;;;;AAsBA,IAAM,YAAqC,EACzC,SACA,OACA,UACA,cAAc,aACd,WACA,cAAc,2BACd,mBACA,qBACI;CACJ,MAAM,CAAC,MAAM,WAAW,SAAS,MAAM;CACvC,MAAM,CAAC,QAAQ,aAAa,SAAS,GAAG;CACxC,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,MAAM,OAAuB,KAAK;CACxC,MAAM,SAAS,eAAe,EAAE;CAChC,MAAM,SAAS,eAAe,EAAE;CAChC,MAAM,SAAS;CAGf,MAAM,kBAAkB,QAAQ,QAAQ,QACtC,IAAI,MAAM,aAAa,CAAC,SAAS,OAAO,aAAa,CAAC,CACvD;AAGD,iBAAgB;EACd,MAAM,eAAe,MAAkB;AACrC,OAAI,IAAI,WAAW,CAAC,IAAI,QAAQ,SAAS,EAAE,OAAe,EAAE;AAC1D,YAAQ,MAAM;AACd,cAAU,GAAG;;;AAGjB,MAAI,KACF,UAAS,iBAAiB,aAAa,YAAY;AAErD,eAAa,SAAS,oBAAoB,aAAa,YAAY;IAClE,CAAC,KAAK,CAAC;CAEV,MAAM,mBAAmB,UAA4C;EACnE,MAAM,EAAE,MAAM,QAAQ,MAAM,cAAc,uBAAuB;AACjE,SAAO,IAAI,MAAM,UAAU,KAAK;AAChC,SAAO,IAAI,MAAM,UAAU,IAAI;;AAGjC,QACE,qBAAC,OAAD;EACO;EACL,WAAW,gBAAgB,mBAAmB,UAAU;EACxD,UAAU;YAHZ,CAKE,oBAAC,OAAO,KAAR;GACE,OAAO,EACL,iBAAiB,iBAAiB;;gBAE5B,UAAU,GAAG,OAAO,MAAM,MAAM,aAAa,OAAO,KAAK,OAAO;;;;aAKvE;GACD,aAAa;GACb,oBAAoB,WAAW,KAAK;GACpC,oBAAoB,WAAW,MAAM;GACrC,WAAU;aAEV,qBAAC,OAAD;IACE,WAAW,gBACT,6RACA,YACD;IACD,eAAe;AACb,cAAS,YAAY;AACnB,UAAI,QACF,WAAU,GAAG;AAGf,aAAO,CAAC;OACR;;cAZN,CAeG,QACC,oBAAC,QAAD;KAAM,WAAU;eACb,QAAQ,MAAM,QAAQ,IAAI,UAAU,MAAM,EAAE;KACxC,CAAA,GAEP,oBAAC,QAAD;KAAM,WAAU;eAAgC;KAAmB,CAAA,EAErE,oBAAC,QAAD;KACE,WAAW,gBACT,gEACA,OAAO,eAAe,WACvB;eAED,oBAAC,iBAAD;MACE,OAAO;MACP,QAAQ;MACR,OAAM;MACN,WAAU;MACV,CAAA;KACG,CAAA,CACH;;GACK,CAAA,EACZ,QACC,qBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,SAAD;MACE,WAAA;MACA,WAAU;MACV,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,UAAU,EAAE,OAAO,MAAM;MAC1C,UAAU,MAAM,EAAE,iBAAiB;MACnC,CAAA;KACE,CAAA;IAEN,qBAAC,OAAD;KAAK,WAAU;eAAf,CACG,gBAAgB,WAAW,KAAK,CAAC,qBAChC,oBAAC,OAAD;MAAK,WAAU;gBAAkC;MAAgB,CAAA,EAElE,gBAAgB,KAAK,QACpB,qBAAC,OAAD;MAEE,WAAW,gBACT,4GACA,IAAI,UAAU,QACV,+CACA,IACJ,uCACD;MACD,eAAe;AACb,gBAAS,IAAI,MAAM;AACnB,iBAAU,GAAG;AACb,eAAQ,MAAM;;gBAZlB,CAeE,oBAAC,QAAD;OAAM,WAAU;iBACb,IAAI,UAAU,SACb,oBAAC,WAAD;QAAW,WAAU;QAAc,OAAO;QAAI,QAAQ;QAAM,CAAA;OAEzD,CAAA,EACP,oBAAC,QAAD;OAAM,WAAU;iBAA2B,IAAI;OAAa,CAAA,CACxD;QApBC,IAAI,MAoBL,CACN,CACE;;IAEL,qBAAqB,kBACpB,oBAAC,OAAD;KAAK,WAAU;eACb,qBAAC,OAAD;MACE,WAAU;MACV,eAAe;AACb,uBAAgB;AAChB,iBAAU,GAAG;AACb,eAAQ,MAAM;;gBALlB,CAQE,oBAAC,QAAD,EAAM,WAAU,wCAET,CAAA,EACP,oBAAC,QAAD;OAAM,WAAU;iBACb;OACI,CAAA,CACH;;KACF,CAAA;IAEJ;KAEJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"date-picker-D8gaaMlJ.mjs","names":[],"sources":["../../src/components/forms/date-picker/DatePicker.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { Calendar } from \"../calendar\";\n\nimport type { DatePickerProps, DatePickerValue, DateRangeValue } from \"./types\";\n\nconst formatDate = (date: Date | null) =>\n date?.toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n }) ?? \"\";\n\nconst isRangeValue = (value: DatePickerValue): value is DateRangeValue =>\n typeof value === \"object\" &&\n value !== null &&\n \"start\" in value &&\n \"end\" in value;\n\nconst emptyRange: DateRangeValue = { start: null, end: null };\n\nexport const DatePicker = ({\n mode = \"single\",\n value,\n onChange,\n label,\n placeholder = \"Pick a date\",\n helperText,\n disabled = false,\n className = \"\",\n presets,\n}: DatePickerProps) => {\n const [open, setOpen] = useState(false);\n const [visible, setVisible] = useState(false);\n const isControlled = value !== undefined;\n const [internalValue, setInternalValue] = useState<DatePickerValue>(\n value ?? (mode === \"range\" ? emptyRange : null),\n );\n\n const currentValue = isControlled ? value : internalValue;\n const singleValue = mode === \"range\" ? null : (currentValue as Date | null);\n const rangeValue =\n mode === \"range\" && isRangeValue(currentValue)\n ? currentValue\n : mode === \"range\"\n ? { ...emptyRange }\n : emptyRange;\n\n const displayValue = useMemo(() => {\n if (mode === \"range\") {\n if (rangeValue.start && rangeValue.end) {\n return `${formatDate(rangeValue.start)} — ${formatDate(rangeValue.end)}`;\n }\n if (rangeValue.start) {\n return `${formatDate(rangeValue.start)} — …`;\n }\n return \"\";\n }\n return formatDate(singleValue);\n }, [mode, rangeValue.end, rangeValue.start, singleValue]);\n\n const updateValue = (next: DatePickerValue) => {\n if (!isControlled) {\n setInternalValue(next);\n }\n onChange?.(next);\n };\n\n const containerRef = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n setOpen(false);\n }\n };\n\n if (open) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, [open]);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const handlePresetClick = (getValue: () => DatePickerValue) => {\n const next = getValue();\n updateValue(next);\n setOpen(false);\n };\n\n return (\n <div ref={containerRef} className={`w-full space-y-2 ${className}`.trim()}>\n {label && <p className=\"text-sm font-medium text-heading\">{label}</p>}\n <div className=\"relative\">\n <motion.div\n style={{\n backgroundImage: disabled\n ? \"none\"\n : useMotionTemplate`\n radial-gradient(\n ${\n visible ? `${radius}px` : \"0px\"\n } circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={!disabled ? handleMouseMove : undefined}\n onMouseEnter={!disabled ? () => setVisible(true) : undefined}\n onMouseLeave={!disabled ? () => setVisible(false) : undefined}\n className={\n disabled\n ? \"group/date-picker rounded-lg border-none bg-muted p-[2px]\"\n : \"group/date-picker rounded-lg border-border p-[2px]\"\n }\n >\n <button\n type=\"button\"\n className={`shadow-input flex w-full items-center justify-between rounded-md border border-input bg-background-secondary px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out ${\n disabled\n ? \"cursor-not-allowed opacity-50\"\n : \"group-hover/date-picker:shadow-none\"\n }`}\n onClick={() => !disabled && setOpen((prev) => !prev)}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n disabled={disabled}\n >\n <span\n className={\n displayValue ? \"text-foreground\" : \"text-muted-foreground\"\n }\n >\n {displayValue || placeholder}\n </span>\n <span aria-hidden=\"true\">📅</span>\n </button>\n </motion.div>\n {open && !disabled && (\n <div className=\"absolute left-0 top-12 z-40 dropdown-panel\">\n <Calendar\n value={mode === \"single\" ? (singleValue ?? null) : undefined}\n selectionMode={mode}\n range={mode === \"range\" ? rangeValue : undefined}\n onSelect={\n mode === \"single\"\n ? (date) => {\n updateValue(date);\n setOpen(false);\n }\n : undefined\n }\n onRangeSelect={\n mode === \"range\"\n ? (nextRange) => {\n updateValue(nextRange);\n if (nextRange.start && nextRange.end) {\n setOpen(false);\n }\n }\n : undefined\n }\n />\n {presets?.length ? (\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {presets.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className=\"rounded-full border border-input px-3 py-1 text-xs text-muted-foreground transition-colors hover:border-accent hover:bg-accent-subtle hover:text-accent\"\n onClick={() => handlePresetClick(preset.value)}\n >\n {preset.label}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n )}\n </div>\n {helperText && (\n <p className=\"text-xs text-muted-foreground\">{helperText}</p>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"date-picker-W9om1j7A.cjs","names":[],"sources":["../../src/components/forms/date-picker/DatePicker.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { Calendar } from \"../calendar\";\n\nimport type { DatePickerProps, DatePickerValue, DateRangeValue } from \"./types\";\n\nconst formatDate = (date: Date | null) =>\n date?.toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n }) ?? \"\";\n\nconst isRangeValue = (value: DatePickerValue): value is DateRangeValue =>\n typeof value === \"object\" &&\n value !== null &&\n \"start\" in value &&\n \"end\" in value;\n\nconst emptyRange: DateRangeValue = { start: null, end: null };\n\nexport const DatePicker = ({\n mode = \"single\",\n value,\n onChange,\n label,\n placeholder = \"Pick a date\",\n helperText,\n disabled = false,\n className = \"\",\n presets,\n}: DatePickerProps) => {\n const [open, setOpen] = useState(false);\n const [visible, setVisible] = useState(false);\n const isControlled = value !== undefined;\n const [internalValue, setInternalValue] = useState<DatePickerValue>(\n value ?? (mode === \"range\" ? emptyRange : null),\n );\n\n const currentValue = isControlled ? value : internalValue;\n const singleValue = mode === \"range\" ? null : (currentValue as Date | null);\n const rangeValue =\n mode === \"range\" && isRangeValue(currentValue)\n ? currentValue\n : mode === \"range\"\n ? { ...emptyRange }\n : emptyRange;\n\n const displayValue = useMemo(() => {\n if (mode === \"range\") {\n if (rangeValue.start && rangeValue.end) {\n return `${formatDate(rangeValue.start)} — ${formatDate(rangeValue.end)}`;\n }\n if (rangeValue.start) {\n return `${formatDate(rangeValue.start)} — …`;\n }\n return \"\";\n }\n return formatDate(singleValue);\n }, [mode, rangeValue.end, rangeValue.start, singleValue]);\n\n const updateValue = (next: DatePickerValue) => {\n if (!isControlled) {\n setInternalValue(next);\n }\n onChange?.(next);\n };\n\n const containerRef = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n setOpen(false);\n }\n };\n\n if (open) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, [open]);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const handlePresetClick = (getValue: () => DatePickerValue) => {\n const next = getValue();\n updateValue(next);\n setOpen(false);\n };\n\n return (\n <div ref={containerRef} className={`w-full space-y-2 ${className}`.trim()}>\n {label && <p className=\"text-sm font-medium text-heading\">{label}</p>}\n <div className=\"relative\">\n <motion.div\n style={{\n backgroundImage: disabled\n ? \"none\"\n : useMotionTemplate`\n radial-gradient(\n ${\n visible ? `${radius}px` : \"0px\"\n } circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={!disabled ? handleMouseMove : undefined}\n onMouseEnter={!disabled ? () => setVisible(true) : undefined}\n onMouseLeave={!disabled ? () => setVisible(false) : undefined}\n className={\n disabled\n ? \"group/date-picker rounded-lg border-none bg-muted p-[2px]\"\n : \"group/date-picker rounded-lg border-border p-[2px]\"\n }\n >\n <button\n type=\"button\"\n className={`shadow-input flex w-full items-center justify-between rounded-md border border-input bg-background-secondary px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out ${\n disabled\n ? \"cursor-not-allowed opacity-50\"\n : \"group-hover/date-picker:shadow-none\"\n }`}\n onClick={() => !disabled && setOpen((prev) => !prev)}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n disabled={disabled}\n >\n <span\n className={\n displayValue ? \"text-foreground\" : \"text-muted-foreground\"\n }\n >\n {displayValue || placeholder}\n </span>\n <span aria-hidden=\"true\">📅</span>\n </button>\n </motion.div>\n {open && !disabled && (\n <div className=\"absolute left-0 top-12 z-40 dropdown-panel\">\n <Calendar\n value={mode === \"single\" ? (singleValue ?? null) : undefined}\n selectionMode={mode}\n range={mode === \"range\" ? rangeValue : undefined}\n onSelect={\n mode === \"single\"\n ? (date) => {\n updateValue(date);\n setOpen(false);\n }\n : undefined\n }\n onRangeSelect={\n mode === \"range\"\n ? (nextRange) => {\n updateValue(nextRange);\n if (nextRange.start && nextRange.end) {\n setOpen(false);\n }\n }\n : undefined\n }\n />\n {presets?.length ? (\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {presets.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className=\"rounded-full border border-input px-3 py-1 text-xs text-muted-foreground transition-colors hover:border-accent hover:bg-accent-subtle hover:text-accent\"\n onClick={() => handlePresetClick(preset.value)}\n >\n {preset.label}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n )}\n </div>\n {helperText && (\n <p className=\"text-xs text-muted-foreground\">{helperText}</p>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
require("./chunk-B_GkZjkl.cjs");
|
|
2
|
-
const require_utils = require("./utils-B4SmmY4J.cjs");
|
|
3
|
-
let react = require("react");
|
|
4
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
-
let framer_motion = require("framer-motion");
|
|
6
|
-
//#region src/components/forms/input/types.ts
|
|
7
|
-
var InputState = /* @__PURE__ */ function(InputState) {
|
|
8
|
-
InputState["DEFAULT"] = "default";
|
|
9
|
-
InputState["DISABLED"] = "disabled";
|
|
10
|
-
InputState["ERROR"] = "error";
|
|
11
|
-
InputState["SUCCESS"] = "success";
|
|
12
|
-
return InputState;
|
|
13
|
-
}({});
|
|
14
|
-
//#endregion
|
|
15
|
-
//#region src/components/forms/input/Input.tsx
|
|
16
|
-
var Input = (0, react.forwardRef)(({ className = "", label, error, helperText, id, extra, placeholder, state = InputState.DEFAULT, disabled, message, icon, iconClassName, bgClassName = "bg-background-secondary", ...props }, ref) => {
|
|
17
|
-
const radius = 100;
|
|
18
|
-
const [visible, setVisible] = (0, react.useState)(false);
|
|
19
|
-
const mouseX = (0, framer_motion.useMotionValue)(0);
|
|
20
|
-
const mouseY = (0, framer_motion.useMotionValue)(0);
|
|
21
|
-
const handleMouseMove = (event) => {
|
|
22
|
-
const { left, top } = event.currentTarget.getBoundingClientRect();
|
|
23
|
-
mouseX.set(event.clientX - left);
|
|
24
|
-
mouseY.set(event.clientY - top);
|
|
25
|
-
};
|
|
26
|
-
const wrapperStateStyles = {
|
|
27
|
-
[InputState.DISABLED]: "bg-muted border-none",
|
|
28
|
-
[InputState.ERROR]: "border-destructive ",
|
|
29
|
-
[InputState.SUCCESS]: "border-success-border ",
|
|
30
|
-
[InputState.DEFAULT]: "border-border "
|
|
31
|
-
};
|
|
32
|
-
const inputStateStyles = {
|
|
33
|
-
[InputState.DISABLED]: "placeholder:!text-muted-foreground",
|
|
34
|
-
[InputState.ERROR]: "text-destructive placeholder:text-destructive",
|
|
35
|
-
[InputState.SUCCESS]: "text-success placeholder:text-success",
|
|
36
|
-
[InputState.DEFAULT]: "text-foreground"
|
|
37
|
-
};
|
|
38
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
39
|
-
className: "w-full",
|
|
40
|
-
children: [
|
|
41
|
-
label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
42
|
-
className: "text-sm font-medium text-foreground leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block",
|
|
43
|
-
children: label
|
|
44
|
-
}),
|
|
45
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(framer_motion.motion.div, {
|
|
46
|
-
style: { backgroundImage: disabled ? "none" : framer_motion.useMotionTemplate`
|
|
47
|
-
radial-gradient(
|
|
48
|
-
${visible ? `${radius}px` : "0px"} circle at ${mouseX}px ${mouseY}px,
|
|
49
|
-
var(--ds-color-accent),
|
|
50
|
-
transparent 90%
|
|
51
|
-
)
|
|
52
|
-
` },
|
|
53
|
-
onMouseMove: !disabled ? handleMouseMove : void 0,
|
|
54
|
-
onMouseEnter: !disabled ? () => setVisible(true) : void 0,
|
|
55
|
-
onMouseLeave: !disabled ? () => setVisible(false) : void 0,
|
|
56
|
-
className: require_utils.mergeClassNames("group/input rounded-lg p-[2px] transition duration-300 hover:border-accent", wrapperStateStyles[state], extra),
|
|
57
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58
|
-
className: "relative flex items-center ",
|
|
59
|
-
children: [icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
60
|
-
className: require_utils.mergeClassNames("pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3", iconClassName),
|
|
61
|
-
children: icon
|
|
62
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
63
|
-
ref,
|
|
64
|
-
id,
|
|
65
|
-
placeholder,
|
|
66
|
-
disabled,
|
|
67
|
-
className: require_utils.mergeClassNames("shadow-input flex h-10 w-full rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/input:shadow-none file:border-0 file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", bgClassName, inputStateStyles[state], className),
|
|
68
|
-
...props,
|
|
69
|
-
autoComplete: "off"
|
|
70
|
-
})]
|
|
71
|
-
})
|
|
72
|
-
}),
|
|
73
|
-
(error || message) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
74
|
-
className: require_utils.mergeClassNames("text-sm font-medium mt-1", error ? "text-destructive" : "text-muted-foreground"),
|
|
75
|
-
children: error || message
|
|
76
|
-
}),
|
|
77
|
-
helperText && !error && !message && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
78
|
-
className: "text-sm text-neutral-500 dark:text-neutral-400 mt-1",
|
|
79
|
-
children: helperText
|
|
80
|
-
})
|
|
81
|
-
]
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
Input.displayName = "Input";
|
|
85
|
-
//#endregion
|
|
86
|
-
Object.defineProperty(exports, "Input", {
|
|
87
|
-
enumerable: true,
|
|
88
|
-
get: function() {
|
|
89
|
-
return Input;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
Object.defineProperty(exports, "InputState", {
|
|
93
|
-
enumerable: true,
|
|
94
|
-
get: function() {
|
|
95
|
-
return InputState;
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
//# sourceMappingURL=input-D9qZNqXV.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"input-D9qZNqXV.cjs","names":[],"sources":["../../src/components/forms/input/types.ts","../../src/components/forms/input/Input.tsx"],"sourcesContent":["import type { InputHTMLAttributes, ReactNode } from \"react\";\n\nexport enum InputState {\n DEFAULT = \"default\",\n DISABLED = \"disabled\",\n ERROR = \"error\",\n SUCCESS = \"success\",\n}\n\nexport interface InputProps extends InputHTMLAttributes<HTMLInputElement> {\n label?: string;\n error?: string;\n helperText?: string;\n id?: string;\n extra?: string;\n state?: InputState;\n message?: string;\n icon?: ReactNode;\n iconClassName?: string;\n /** Custom background classes for light/dark mode (e.g. \"ui:bg-white ui:dark:bg-zinc-900\") */\n bgClassName?: string;\n}\n","import { forwardRef, useState } from \"react\";\nimport { type InputProps, InputState } from \"./types\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\nimport { mergeClassNames } from \"../../../utils\";\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n (\n {\n className = \"\",\n label,\n error,\n helperText,\n id,\n extra,\n placeholder,\n state = InputState.DEFAULT,\n disabled,\n message,\n icon,\n iconClassName,\n // bgClassName = \"bg-zinc-950/40\",\n bgClassName = \"bg-background-secondary\",\n // bgClassName = \"bg-white/40 dark:bg-zinc-950/40 backdrop-blur-xl\",\n ...props\n },\n ref,\n ) => {\n const radius = 100; // Radius for the hover effect\n const [visible, setVisible] = useState(false);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const wrapperStateStyles: Record<InputState, string> = {\n [InputState.DISABLED]: \"bg-muted border-none\",\n [InputState.ERROR]: \"border-destructive \",\n [InputState.SUCCESS]: \"border-success-border \",\n [InputState.DEFAULT]: \"border-border \",\n };\n\n const inputStateStyles: Record<InputState, string> = {\n [InputState.DISABLED]: \"placeholder:!text-muted-foreground\",\n [InputState.ERROR]: \"text-destructive placeholder:text-destructive\",\n [InputState.SUCCESS]: \"text-success placeholder:text-success\",\n [InputState.DEFAULT]: \"text-foreground\",\n };\n\n return (\n <div className=\"w-full\">\n {label && (\n <label className=\"text-sm font-medium text-foreground leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block\">\n {label}\n </label>\n )}\n\n <motion.div\n style={{\n backgroundImage: disabled\n ? \"none\"\n : useMotionTemplate`\n radial-gradient(\n ${\n visible ? `${radius}px` : \"0px\"\n } circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={!disabled ? handleMouseMove : undefined}\n onMouseEnter={!disabled ? () => setVisible(true) : undefined}\n onMouseLeave={!disabled ? () => setVisible(false) : undefined}\n className={mergeClassNames(\n \"group/input rounded-lg p-[2px] transition duration-300 hover:border-accent\",\n wrapperStateStyles[state],\n extra,\n )}\n >\n <div className=\"relative flex items-center \">\n {icon && (\n <div\n className={mergeClassNames(\n \"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3\",\n iconClassName,\n )}\n >\n {icon}\n </div>\n )}\n <input\n ref={ref}\n id={id}\n placeholder={placeholder}\n disabled={disabled}\n className={mergeClassNames(\n \"shadow-input flex h-10 w-full rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/input:shadow-none file:border-0 file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50\",\n bgClassName,\n inputStateStyles[state],\n className,\n )}\n {...props}\n autoComplete=\"off\"\n />\n </div>\n </motion.div>\n\n {(error || message) && (\n <p\n className={mergeClassNames(\n \"text-sm font-medium mt-1\",\n error ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {error || message}\n </p>\n )}\n {helperText && !error && !message && (\n <p className=\"text-sm text-neutral-500 dark:text-neutral-400 mt-1\">\n {helperText}\n </p>\n )}\n </div>\n );\n },\n);\n\nInput.displayName = \"Input\";\n"],"mappings":";;;;;;AAEA,IAAY,aAAL,yBAAA,YAAA;AACL,YAAA,aAAA;AACA,YAAA,cAAA;AACA,YAAA,WAAA;AACA,YAAA,aAAA;;KACD;;;ACFD,IAAa,SAAA,GAAA,MAAA,aAET,EACE,YAAY,IACZ,OACA,OACA,YACA,IACA,OACA,aACA,QAAQ,WAAW,SACnB,UACA,SACA,MACA,eAEA,cAAc,2BAEd,GAAG,SAEL,QACG;CACH,MAAM,SAAS;CACf,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,UAAuB,MAAM;CAC7C,MAAM,UAAA,GAAA,cAAA,gBAAwB,EAAE;CAChC,MAAM,UAAA,GAAA,cAAA,gBAAwB,EAAE;CAEhC,MAAM,mBAAmB,UAA4C;EACnE,MAAM,EAAE,MAAM,QAAQ,MAAM,cAAc,uBAAuB;AACjE,SAAO,IAAI,MAAM,UAAU,KAAK;AAChC,SAAO,IAAI,MAAM,UAAU,IAAI;;CAGjC,MAAM,qBAAiD;GACpD,WAAW,WAAW;GACtB,WAAW,QAAQ;GACnB,WAAW,UAAU;GACrB,WAAW,UAAU;EACvB;CAED,MAAM,mBAA+C;GAClD,WAAW,WAAW;GACtB,WAAW,QAAQ;GACnB,WAAW,UAAU;GACrB,WAAW,UAAU;EACvB;AAED,QACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,iBAAA,GAAA,kBAAA,KAAC,SAAD;IAAO,WAAU;cACd;IACK,CAAA;GAGV,iBAAA,GAAA,kBAAA,KAAC,cAAA,OAAO,KAAR;IACE,OAAO,EACL,iBAAiB,WACb,SACA,cAAA,iBAAiB;;sBAGX,UAAU,GAAG,OAAO,MAAM,MAC3B,aAAa,OAAO,KAAK,OAAO;;;;mBAK1C;IACD,aAAa,CAAC,WAAW,kBAAkB,KAAA;IAC3C,cAAc,CAAC,iBAAiB,WAAW,KAAK,GAAG,KAAA;IACnD,cAAc,CAAC,iBAAiB,WAAW,MAAM,GAAG,KAAA;IACpD,WAAW,cAAA,gBACT,8EACA,mBAAmB,QACnB,MACD;cAED,iBAAA,GAAA,kBAAA,MAAC,OAAD;KAAK,WAAU;eAAf,CACG,QACC,iBAAA,GAAA,kBAAA,KAAC,OAAD;MACE,WAAW,cAAA,gBACT,yEACA,cACD;gBAEA;MACG,CAAA,EAER,iBAAA,GAAA,kBAAA,KAAC,SAAD;MACO;MACD;MACS;MACH;MACV,WAAW,cAAA,gBACT,6WACA,aACA,iBAAiB,QACjB,UACD;MACD,GAAI;MACJ,cAAa;MACb,CAAA,CACE;;IACK,CAAA;IAEX,SAAS,YACT,iBAAA,GAAA,kBAAA,KAAC,KAAD;IACE,WAAW,cAAA,gBACT,4BACA,QAAQ,qBAAqB,wBAC9B;cAEA,SAAS;IACR,CAAA;GAEL,cAAc,CAAC,SAAS,CAAC,WACxB,iBAAA,GAAA,kBAAA,KAAC,KAAD;IAAG,WAAU;cACV;IACC,CAAA;GAEF;;EAGX;AAED,MAAM,cAAc"}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { n as mergeClassNames } from "./utils-ati1KkDb.mjs";
|
|
2
|
-
import { forwardRef, useState } from "react";
|
|
3
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
import { motion, useMotionTemplate, useMotionValue } from "framer-motion";
|
|
5
|
-
//#region src/components/forms/input/types.ts
|
|
6
|
-
var InputState = /* @__PURE__ */ function(InputState) {
|
|
7
|
-
InputState["DEFAULT"] = "default";
|
|
8
|
-
InputState["DISABLED"] = "disabled";
|
|
9
|
-
InputState["ERROR"] = "error";
|
|
10
|
-
InputState["SUCCESS"] = "success";
|
|
11
|
-
return InputState;
|
|
12
|
-
}({});
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region src/components/forms/input/Input.tsx
|
|
15
|
-
var Input = forwardRef(({ className = "", label, error, helperText, id, extra, placeholder, state = InputState.DEFAULT, disabled, message, icon, iconClassName, bgClassName = "bg-background-secondary", ...props }, ref) => {
|
|
16
|
-
const radius = 100;
|
|
17
|
-
const [visible, setVisible] = useState(false);
|
|
18
|
-
const mouseX = useMotionValue(0);
|
|
19
|
-
const mouseY = useMotionValue(0);
|
|
20
|
-
const handleMouseMove = (event) => {
|
|
21
|
-
const { left, top } = event.currentTarget.getBoundingClientRect();
|
|
22
|
-
mouseX.set(event.clientX - left);
|
|
23
|
-
mouseY.set(event.clientY - top);
|
|
24
|
-
};
|
|
25
|
-
const wrapperStateStyles = {
|
|
26
|
-
[InputState.DISABLED]: "bg-muted border-none",
|
|
27
|
-
[InputState.ERROR]: "border-destructive ",
|
|
28
|
-
[InputState.SUCCESS]: "border-success-border ",
|
|
29
|
-
[InputState.DEFAULT]: "border-border "
|
|
30
|
-
};
|
|
31
|
-
const inputStateStyles = {
|
|
32
|
-
[InputState.DISABLED]: "placeholder:!text-muted-foreground",
|
|
33
|
-
[InputState.ERROR]: "text-destructive placeholder:text-destructive",
|
|
34
|
-
[InputState.SUCCESS]: "text-success placeholder:text-success",
|
|
35
|
-
[InputState.DEFAULT]: "text-foreground"
|
|
36
|
-
};
|
|
37
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
38
|
-
className: "w-full",
|
|
39
|
-
children: [
|
|
40
|
-
label && /* @__PURE__ */ jsx("label", {
|
|
41
|
-
className: "text-sm font-medium text-foreground leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block",
|
|
42
|
-
children: label
|
|
43
|
-
}),
|
|
44
|
-
/* @__PURE__ */ jsx(motion.div, {
|
|
45
|
-
style: { backgroundImage: disabled ? "none" : useMotionTemplate`
|
|
46
|
-
radial-gradient(
|
|
47
|
-
${visible ? `${radius}px` : "0px"} circle at ${mouseX}px ${mouseY}px,
|
|
48
|
-
var(--ds-color-accent),
|
|
49
|
-
transparent 90%
|
|
50
|
-
)
|
|
51
|
-
` },
|
|
52
|
-
onMouseMove: !disabled ? handleMouseMove : void 0,
|
|
53
|
-
onMouseEnter: !disabled ? () => setVisible(true) : void 0,
|
|
54
|
-
onMouseLeave: !disabled ? () => setVisible(false) : void 0,
|
|
55
|
-
className: mergeClassNames("group/input rounded-lg p-[2px] transition duration-300 hover:border-accent", wrapperStateStyles[state], extra),
|
|
56
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
57
|
-
className: "relative flex items-center ",
|
|
58
|
-
children: [icon && /* @__PURE__ */ jsx("div", {
|
|
59
|
-
className: mergeClassNames("pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3", iconClassName),
|
|
60
|
-
children: icon
|
|
61
|
-
}), /* @__PURE__ */ jsx("input", {
|
|
62
|
-
ref,
|
|
63
|
-
id,
|
|
64
|
-
placeholder,
|
|
65
|
-
disabled,
|
|
66
|
-
className: mergeClassNames("shadow-input flex h-10 w-full rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/input:shadow-none file:border-0 file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", bgClassName, inputStateStyles[state], className),
|
|
67
|
-
...props,
|
|
68
|
-
autoComplete: "off"
|
|
69
|
-
})]
|
|
70
|
-
})
|
|
71
|
-
}),
|
|
72
|
-
(error || message) && /* @__PURE__ */ jsx("p", {
|
|
73
|
-
className: mergeClassNames("text-sm font-medium mt-1", error ? "text-destructive" : "text-muted-foreground"),
|
|
74
|
-
children: error || message
|
|
75
|
-
}),
|
|
76
|
-
helperText && !error && !message && /* @__PURE__ */ jsx("p", {
|
|
77
|
-
className: "text-sm text-neutral-500 dark:text-neutral-400 mt-1",
|
|
78
|
-
children: helperText
|
|
79
|
-
})
|
|
80
|
-
]
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
Input.displayName = "Input";
|
|
84
|
-
//#endregion
|
|
85
|
-
export { InputState as n, Input as t };
|
|
86
|
-
|
|
87
|
-
//# sourceMappingURL=input-wNqevfQ4.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"input-wNqevfQ4.mjs","names":[],"sources":["../../src/components/forms/input/types.ts","../../src/components/forms/input/Input.tsx"],"sourcesContent":["import type { InputHTMLAttributes, ReactNode } from \"react\";\n\nexport enum InputState {\n DEFAULT = \"default\",\n DISABLED = \"disabled\",\n ERROR = \"error\",\n SUCCESS = \"success\",\n}\n\nexport interface InputProps extends InputHTMLAttributes<HTMLInputElement> {\n label?: string;\n error?: string;\n helperText?: string;\n id?: string;\n extra?: string;\n state?: InputState;\n message?: string;\n icon?: ReactNode;\n iconClassName?: string;\n /** Custom background classes for light/dark mode (e.g. \"ui:bg-white ui:dark:bg-zinc-900\") */\n bgClassName?: string;\n}\n","import { forwardRef, useState } from \"react\";\nimport { type InputProps, InputState } from \"./types\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\nimport { mergeClassNames } from \"../../../utils\";\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n (\n {\n className = \"\",\n label,\n error,\n helperText,\n id,\n extra,\n placeholder,\n state = InputState.DEFAULT,\n disabled,\n message,\n icon,\n iconClassName,\n // bgClassName = \"bg-zinc-950/40\",\n bgClassName = \"bg-background-secondary\",\n // bgClassName = \"bg-white/40 dark:bg-zinc-950/40 backdrop-blur-xl\",\n ...props\n },\n ref,\n ) => {\n const radius = 100; // Radius for the hover effect\n const [visible, setVisible] = useState(false);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const wrapperStateStyles: Record<InputState, string> = {\n [InputState.DISABLED]: \"bg-muted border-none\",\n [InputState.ERROR]: \"border-destructive \",\n [InputState.SUCCESS]: \"border-success-border \",\n [InputState.DEFAULT]: \"border-border \",\n };\n\n const inputStateStyles: Record<InputState, string> = {\n [InputState.DISABLED]: \"placeholder:!text-muted-foreground\",\n [InputState.ERROR]: \"text-destructive placeholder:text-destructive\",\n [InputState.SUCCESS]: \"text-success placeholder:text-success\",\n [InputState.DEFAULT]: \"text-foreground\",\n };\n\n return (\n <div className=\"w-full\">\n {label && (\n <label className=\"text-sm font-medium text-foreground leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block\">\n {label}\n </label>\n )}\n\n <motion.div\n style={{\n backgroundImage: disabled\n ? \"none\"\n : useMotionTemplate`\n radial-gradient(\n ${\n visible ? `${radius}px` : \"0px\"\n } circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={!disabled ? handleMouseMove : undefined}\n onMouseEnter={!disabled ? () => setVisible(true) : undefined}\n onMouseLeave={!disabled ? () => setVisible(false) : undefined}\n className={mergeClassNames(\n \"group/input rounded-lg p-[2px] transition duration-300 hover:border-accent\",\n wrapperStateStyles[state],\n extra,\n )}\n >\n <div className=\"relative flex items-center \">\n {icon && (\n <div\n className={mergeClassNames(\n \"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3\",\n iconClassName,\n )}\n >\n {icon}\n </div>\n )}\n <input\n ref={ref}\n id={id}\n placeholder={placeholder}\n disabled={disabled}\n className={mergeClassNames(\n \"shadow-input flex h-10 w-full rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/input:shadow-none file:border-0 file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50\",\n bgClassName,\n inputStateStyles[state],\n className,\n )}\n {...props}\n autoComplete=\"off\"\n />\n </div>\n </motion.div>\n\n {(error || message) && (\n <p\n className={mergeClassNames(\n \"text-sm font-medium mt-1\",\n error ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {error || message}\n </p>\n )}\n {helperText && !error && !message && (\n <p className=\"text-sm text-neutral-500 dark:text-neutral-400 mt-1\">\n {helperText}\n </p>\n )}\n </div>\n );\n },\n);\n\nInput.displayName = \"Input\";\n"],"mappings":";;;;;AAEA,IAAY,aAAL,yBAAA,YAAA;AACL,YAAA,aAAA;AACA,YAAA,cAAA;AACA,YAAA,WAAA;AACA,YAAA,aAAA;;KACD;;;ACFD,IAAa,QAAQ,YAEjB,EACE,YAAY,IACZ,OACA,OACA,YACA,IACA,OACA,aACA,QAAQ,WAAW,SACnB,UACA,SACA,MACA,eAEA,cAAc,2BAEd,GAAG,SAEL,QACG;CACH,MAAM,SAAS;CACf,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,SAAS,eAAe,EAAE;CAChC,MAAM,SAAS,eAAe,EAAE;CAEhC,MAAM,mBAAmB,UAA4C;EACnE,MAAM,EAAE,MAAM,QAAQ,MAAM,cAAc,uBAAuB;AACjE,SAAO,IAAI,MAAM,UAAU,KAAK;AAChC,SAAO,IAAI,MAAM,UAAU,IAAI;;CAGjC,MAAM,qBAAiD;GACpD,WAAW,WAAW;GACtB,WAAW,QAAQ;GACnB,WAAW,UAAU;GACrB,WAAW,UAAU;EACvB;CAED,MAAM,mBAA+C;GAClD,WAAW,WAAW;GACtB,WAAW,QAAQ;GACnB,WAAW,UAAU;GACrB,WAAW,UAAU;EACvB;AAED,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SACC,oBAAC,SAAD;IAAO,WAAU;cACd;IACK,CAAA;GAGV,oBAAC,OAAO,KAAR;IACE,OAAO,EACL,iBAAiB,WACb,SACA,iBAAiB;;sBAGX,UAAU,GAAG,OAAO,MAAM,MAC3B,aAAa,OAAO,KAAK,OAAO;;;;mBAK1C;IACD,aAAa,CAAC,WAAW,kBAAkB,KAAA;IAC3C,cAAc,CAAC,iBAAiB,WAAW,KAAK,GAAG,KAAA;IACnD,cAAc,CAAC,iBAAiB,WAAW,MAAM,GAAG,KAAA;IACpD,WAAW,gBACT,8EACA,mBAAmB,QACnB,MACD;cAED,qBAAC,OAAD;KAAK,WAAU;eAAf,CACG,QACC,oBAAC,OAAD;MACE,WAAW,gBACT,yEACA,cACD;gBAEA;MACG,CAAA,EAER,oBAAC,SAAD;MACO;MACD;MACS;MACH;MACV,WAAW,gBACT,6WACA,aACA,iBAAiB,QACjB,UACD;MACD,GAAI;MACJ,cAAa;MACb,CAAA,CACE;;IACK,CAAA;IAEX,SAAS,YACT,oBAAC,KAAD;IACE,WAAW,gBACT,4BACA,QAAQ,qBAAqB,wBAC9B;cAEA,SAAS;IACR,CAAA;GAEL,cAAc,CAAC,SAAS,CAAC,WACxB,oBAAC,KAAD;IAAG,WAAU;cACV;IACC,CAAA;GAEF;;EAGX;AAED,MAAM,cAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"multi-select-combobox-ELSH_Xr4.mjs","names":[],"sources":["../../src/components/forms/multi-select-combobox/MultiSelectCombobox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { CheckIcon, ChevronDownIcon, CloseIcon } from \"../../icons\";\nimport { mergeClassNames } from \"../../../utils\";\n\nexport interface MultiSelectOption {\n label: string;\n value: string;\n}\n\nexport interface MultiSelectComboboxProps {\n options: MultiSelectOption[];\n value: string[];\n onChange: (values: string[]) => void;\n placeholder?: string;\n className?: string;\n bgClassName?: string;\n}\n\nconst MultiSelectCombobox: React.FC<MultiSelectComboboxProps> = ({\n options,\n value = [],\n onChange,\n placeholder = \"Select...\",\n className,\n bgClassName = \"bg-background-secondary\",\n}) => {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [visible, setVisible] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n\n // Filter options by search\n const filteredOptions = options.filter((opt) =>\n opt.label.toLowerCase().includes(search.toLowerCase()),\n );\n\n // Close dropdown on outside click\n useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n setSearch(\"\");\n }\n };\n if (open) {\n document.addEventListener(\"mousedown\", handleClick);\n }\n return () => document.removeEventListener(\"mousedown\", handleClick);\n }, [open]);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const handleOptionClick = (optionValue: string) => {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue));\n } else {\n onChange([...value, optionValue]);\n }\n };\n\n const handleRemoveTag = (optionValue: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onChange(value.filter((v) => v !== optionValue));\n };\n\n const selectedLabels = value\n .map((v) => options.find((opt) => opt.value === v)?.label)\n .filter(Boolean);\n\n return (\n <div\n ref={ref}\n className={mergeClassNames(\"relative w-full\", className)}\n tabIndex={0}\n >\n <motion.div\n style={{\n backgroundImage: useMotionTemplate`\n radial-gradient(\n ${visible ? `${radius}px` : \"0px\"} circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={handleMouseMove}\n onMouseEnter={() => setVisible(true)}\n onMouseLeave={() => setVisible(false)}\n className=\"group/multi-combobox rounded-lg border-border p-[2px] transition duration-300 hover:border-accent\"\n >\n <div\n className={mergeClassNames(\n \"shadow-input flex min-h-10 w-full cursor-pointer items-center justify-between rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/multi-combobox:shadow-none\",\n bgClassName,\n )}\n onClick={() => {\n setOpen((o) => {\n if (o) setSearch(\"\");\n return !o;\n });\n }}\n >\n <div className=\"flex flex-1 flex-wrap gap-1\">\n {selectedLabels.length > 0 ? (\n selectedLabels.map((label, index) => (\n <span\n key={value[index]}\n className=\"inline-flex items-center gap-1 rounded-md bg-accent-subtle px-2 py-0.5 text-xs font-medium text-accent\"\n >\n {label}\n <button\n type=\"button\"\n onClick={(e) => handleRemoveTag(value[index], e)}\n className=\"ml-0.5 rounded-full p-0.5 transition-colors hover:bg-accent/10\"\n >\n <CloseIcon className=\"w-3 h-3\" aria-hidden=\"true\" />\n </button>\n </span>\n ))\n ) : (\n <span className=\"text-muted-foreground\">{placeholder}</span>\n )}\n </div>\n <span\n className={mergeClassNames(\n \"ml-2 shrink-0 text-muted-foreground transition-transform duration-300\",\n open ? \"rotate-180\" : \"rotate-0\",\n )}\n >\n <ChevronDownIcon\n width={24}\n height={24}\n color=\"currentColor\"\n className=\"h-5 w-5\"\n />\n </span>\n </div>\n </motion.div>\n {open && (\n <div className=\"absolute right-0 left-0 z-20 mt-1 flex max-h-60 flex-col rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition\">\n {/* Sticky search input */}\n <div className=\"sticky top-0 z-10 rounded-t-lg border-b border-border-muted bg-elevated/95 backdrop-blur-sm\">\n <input\n autoFocus\n className=\"w-full bg-transparent px-3 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent\"\n placeholder=\"Type to search...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onClick={(e) => e.stopPropagation()}\n />\n </div>\n {/* Scrollable options */}\n <div className=\"max-h-80 flex-1 overflow-auto\">\n {filteredOptions.length === 0 && (\n <div className=\"p-3 text-center text-muted-foreground text-sm\">\n No options found\n </div>\n )}\n {filteredOptions.map((option) => {\n const isSelected = value.includes(option.value);\n return (\n <div\n key={option.value}\n className={mergeClassNames(\n \"flex cursor-pointer items-center gap-2 px-3 py-2 text-sm transition\",\n isSelected\n ? \"bg-accent-subtle text-accent\"\n : \"text-foreground hover:bg-accent hover:text-on-accent\",\n )}\n onClick={() => handleOptionClick(option.value)}\n >\n <span\n className={mergeClassNames(\n \"flex h-4 w-4 items-center justify-center rounded border transition\",\n isSelected\n ? \"border-accent bg-accent text-on-accent\"\n : \"border-border\",\n )}\n >\n {isSelected && <CheckIcon width={12} height={12} />}\n </span>\n <span className=\"flex-1\">{option.label}</span>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default MultiSelectCombobox;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"multi-select-combobox-UW0X15W7.cjs","names":[],"sources":["../../src/components/forms/multi-select-combobox/MultiSelectCombobox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { CheckIcon, ChevronDownIcon, CloseIcon } from \"../../icons\";\nimport { mergeClassNames } from \"../../../utils\";\n\nexport interface MultiSelectOption {\n label: string;\n value: string;\n}\n\nexport interface MultiSelectComboboxProps {\n options: MultiSelectOption[];\n value: string[];\n onChange: (values: string[]) => void;\n placeholder?: string;\n className?: string;\n bgClassName?: string;\n}\n\nconst MultiSelectCombobox: React.FC<MultiSelectComboboxProps> = ({\n options,\n value = [],\n onChange,\n placeholder = \"Select...\",\n className,\n bgClassName = \"bg-background-secondary\",\n}) => {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [visible, setVisible] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n\n // Filter options by search\n const filteredOptions = options.filter((opt) =>\n opt.label.toLowerCase().includes(search.toLowerCase()),\n );\n\n // Close dropdown on outside click\n useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n setSearch(\"\");\n }\n };\n if (open) {\n document.addEventListener(\"mousedown\", handleClick);\n }\n return () => document.removeEventListener(\"mousedown\", handleClick);\n }, [open]);\n\n const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const handleOptionClick = (optionValue: string) => {\n if (value.includes(optionValue)) {\n onChange(value.filter((v) => v !== optionValue));\n } else {\n onChange([...value, optionValue]);\n }\n };\n\n const handleRemoveTag = (optionValue: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onChange(value.filter((v) => v !== optionValue));\n };\n\n const selectedLabels = value\n .map((v) => options.find((opt) => opt.value === v)?.label)\n .filter(Boolean);\n\n return (\n <div\n ref={ref}\n className={mergeClassNames(\"relative w-full\", className)}\n tabIndex={0}\n >\n <motion.div\n style={{\n backgroundImage: useMotionTemplate`\n radial-gradient(\n ${visible ? `${radius}px` : \"0px\"} circle at ${mouseX}px ${mouseY}px,\n var(--ds-color-accent),\n transparent 90%\n )\n `,\n }}\n onMouseMove={handleMouseMove}\n onMouseEnter={() => setVisible(true)}\n onMouseLeave={() => setVisible(false)}\n className=\"group/multi-combobox rounded-lg border-border p-[2px] transition duration-300 hover:border-accent\"\n >\n <div\n className={mergeClassNames(\n \"shadow-input flex min-h-10 w-full cursor-pointer items-center justify-between rounded-md border border-input px-3 py-2 text-sm text-foreground transition duration-400 ease-in-out group-hover/multi-combobox:shadow-none\",\n bgClassName,\n )}\n onClick={() => {\n setOpen((o) => {\n if (o) setSearch(\"\");\n return !o;\n });\n }}\n >\n <div className=\"flex flex-1 flex-wrap gap-1\">\n {selectedLabels.length > 0 ? (\n selectedLabels.map((label, index) => (\n <span\n key={value[index]}\n className=\"inline-flex items-center gap-1 rounded-md bg-accent-subtle px-2 py-0.5 text-xs font-medium text-accent\"\n >\n {label}\n <button\n type=\"button\"\n onClick={(e) => handleRemoveTag(value[index], e)}\n className=\"ml-0.5 rounded-full p-0.5 transition-colors hover:bg-accent/10\"\n >\n <CloseIcon className=\"w-3 h-3\" aria-hidden=\"true\" />\n </button>\n </span>\n ))\n ) : (\n <span className=\"text-muted-foreground\">{placeholder}</span>\n )}\n </div>\n <span\n className={mergeClassNames(\n \"ml-2 shrink-0 text-muted-foreground transition-transform duration-300\",\n open ? \"rotate-180\" : \"rotate-0\",\n )}\n >\n <ChevronDownIcon\n width={24}\n height={24}\n color=\"currentColor\"\n className=\"h-5 w-5\"\n />\n </span>\n </div>\n </motion.div>\n {open && (\n <div className=\"absolute right-0 left-0 z-20 mt-1 flex max-h-60 flex-col rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition\">\n {/* Sticky search input */}\n <div className=\"sticky top-0 z-10 rounded-t-lg border-b border-border-muted bg-elevated/95 backdrop-blur-sm\">\n <input\n autoFocus\n className=\"w-full bg-transparent px-3 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-accent\"\n placeholder=\"Type to search...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onClick={(e) => e.stopPropagation()}\n />\n </div>\n {/* Scrollable options */}\n <div className=\"max-h-80 flex-1 overflow-auto\">\n {filteredOptions.length === 0 && (\n <div className=\"p-3 text-center text-muted-foreground text-sm\">\n No options found\n </div>\n )}\n {filteredOptions.map((option) => {\n const isSelected = value.includes(option.value);\n return (\n <div\n key={option.value}\n className={mergeClassNames(\n \"flex cursor-pointer items-center gap-2 px-3 py-2 text-sm transition\",\n isSelected\n ? \"bg-accent-subtle text-accent\"\n : \"text-foreground hover:bg-accent hover:text-on-accent\",\n )}\n onClick={() => handleOptionClick(option.value)}\n >\n <span\n className={mergeClassNames(\n \"flex h-4 w-4 items-center justify-center rounded border transition\",\n isSelected\n ? \"border-accent bg-accent text-on-accent\"\n : \"border-border\",\n )}\n >\n {isSelected && <CheckIcon width={12} height={12} />}\n </span>\n <span className=\"flex-1\">{option.label}</span>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default MultiSelectCombobox;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"otp-input-B6zzOEqw.cjs","names":[],"sources":["../../src/components/forms/otp-input/OTPInput.tsx"],"sourcesContent":["import {\n forwardRef,\n useState,\n useRef,\n useCallback,\n useEffect,\n type KeyboardEvent,\n type ClipboardEvent,\n type ChangeEvent,\n} from \"react\";\n\nexport type OTPInputSize = \"sm\" | \"md\" | \"lg\";\nexport type OTPInputVariant = \"outlined\" | \"filled\" | \"underlined\";\n\nexport interface OTPInputProps {\n /** Number of OTP digits */\n length?: number;\n /** Callback when OTP value changes */\n onChange?: (value: string) => void;\n /** Callback when all digits are filled */\n onComplete?: (value: string) => void;\n /** The current value (controlled) */\n value?: string;\n /** Default value (uncontrolled) */\n defaultValue?: string;\n /** Size of the input boxes */\n size?: OTPInputSize;\n /** Visual variant */\n variant?: OTPInputVariant;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Whether there's an error */\n error?: boolean;\n /** Error message to display */\n errorMessage?: string;\n /** Placeholder character */\n placeholder?: string;\n /** Whether to mask the input (like password) */\n mask?: boolean;\n /** Whether to auto-focus the first input */\n autoFocus?: boolean;\n /** Input type - number only or alphanumeric */\n type?: \"number\" | \"text\";\n /** Custom className for the container */\n className?: string;\n /** Custom className for each input box */\n inputClassName?: string;\n /** Separator to show between groups of digits */\n separator?: React.ReactNode;\n /** Position(s) to show separator (e.g., [3] means after 3rd digit) */\n separatorPositions?: number[];\n /** Accessible label */\n \"aria-label\"?: string;\n}\n\nconst sizeStyles: Record<OTPInputSize, string> = {\n sm: \"w-9 h-10 text-base\",\n md: \"w-12 h-14 text-xl\",\n lg: \"w-14 h-16 text-2xl\",\n};\n\nconst variantStyles: Record<\n OTPInputVariant,\n { base: string; focus: string; error: string }\n> = {\n outlined: {\n base: \"border border-input bg-background-secondary rounded-lg shadow-input text-foreground\",\n focus: \"focus:border-accent focus:ring-2 focus:ring-accent\",\n error: \"border-destructive\",\n },\n filled: {\n base: \"border border-transparent bg-accent-subtle rounded-lg text-foreground\",\n focus:\n \"focus:border-accent focus:bg-background-secondary focus:ring-2 focus:ring-accent\",\n error: \"bg-danger-subtle border-danger-border\",\n },\n underlined: {\n base: \"border-b-2 border-border-strong bg-transparent rounded-none text-foreground\",\n focus: \"focus:border-accent\",\n error: \"border-destructive\",\n },\n};\n\nconst OTPInput = forwardRef<HTMLDivElement, OTPInputProps>(\n (\n {\n length = 6,\n onChange,\n onComplete,\n value: controlledValue,\n defaultValue = \"\",\n size = \"md\",\n variant = \"outlined\",\n disabled = false,\n error = false,\n errorMessage,\n placeholder = \"\",\n mask = false,\n autoFocus = false,\n type = \"number\",\n className = \"\",\n inputClassName = \"\",\n separator = <span className=\"text-neutral-400 text-2xl mx-2\">—</span>,\n separatorPositions = [],\n \"aria-label\": ariaLabel = \"One-time password\",\n },\n ref,\n ) => {\n const [values, setValues] = useState<string[]>(() => {\n const initial = controlledValue ?? defaultValue;\n return initial\n .split(\"\")\n .slice(0, length)\n .concat(Array(length).fill(\"\"))\n .slice(0, length);\n });\n\n const inputRefs = useRef<(HTMLInputElement | null)[]>([]);\n\n // Sync with controlled value\n useEffect(() => {\n if (controlledValue !== undefined) {\n const newValues = controlledValue\n .split(\"\")\n .slice(0, length)\n .concat(Array(length).fill(\"\"))\n .slice(0, length);\n setValues(newValues);\n }\n }, [controlledValue, length]);\n\n // Auto-focus first input\n useEffect(() => {\n if (autoFocus && inputRefs.current[0]) {\n inputRefs.current[0].focus();\n }\n }, [autoFocus]);\n\n const focusInput = useCallback(\n (index: number) => {\n if (index >= 0 && index < length && inputRefs.current[index]) {\n inputRefs.current[index]?.focus();\n inputRefs.current[index]?.select();\n }\n },\n [length],\n );\n\n const handleChange = useCallback(\n (index: number, e: ChangeEvent<HTMLInputElement>) => {\n const inputValue = e.target.value;\n const char = inputValue.slice(-1);\n\n // Validate input based on type\n if (type === \"number\" && char && !/^\\d$/.test(char)) {\n return;\n }\n\n const newValues = [...values];\n newValues[index] = char;\n setValues(newValues);\n\n const otpValue = newValues.join(\"\");\n onChange?.(otpValue);\n\n // Move to next input if value entered\n if (char && index < length - 1) {\n focusInput(index + 1);\n }\n\n // Check if complete\n if (newValues.every((v) => v !== \"\") && newValues.length === length) {\n onComplete?.(otpValue);\n }\n },\n [values, onChange, onComplete, length, type, focusInput],\n );\n\n const handleKeyDown = useCallback(\n (index: number, e: KeyboardEvent<HTMLInputElement>) => {\n switch (e.key) {\n case \"Backspace\":\n e.preventDefault();\n const newValues = [...values];\n if (values[index]) {\n // Clear current value\n newValues[index] = \"\";\n setValues(newValues);\n onChange?.(newValues.join(\"\"));\n } else if (index > 0) {\n // Move to previous and clear\n newValues[index - 1] = \"\";\n setValues(newValues);\n onChange?.(newValues.join(\"\"));\n focusInput(index - 1);\n }\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n focusInput(index - 1);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n focusInput(index + 1);\n break;\n case \"Delete\":\n e.preventDefault();\n const deleteValues = [...values];\n deleteValues[index] = \"\";\n setValues(deleteValues);\n onChange?.(deleteValues.join(\"\"));\n break;\n }\n },\n [values, onChange, focusInput],\n );\n\n const handlePaste = useCallback(\n (e: ClipboardEvent<HTMLInputElement>) => {\n e.preventDefault();\n const pastedData = e.clipboardData.getData(\"text\").slice(0, length);\n\n // Validate pasted content\n if (type === \"number\" && !/^\\d*$/.test(pastedData)) {\n return;\n }\n\n const newValues = pastedData\n .split(\"\")\n .slice(0, length)\n .concat(Array(length).fill(\"\"))\n .slice(0, length);\n\n setValues(newValues);\n const otpValue = newValues.join(\"\");\n onChange?.(otpValue);\n\n // Focus last filled input or last input\n const lastFilledIndex = newValues.findLastIndex((v) => v !== \"\");\n focusInput(Math.min(lastFilledIndex + 1, length - 1));\n\n // Check if complete\n if (newValues.every((v) => v !== \"\") && pastedData.length >= length) {\n onComplete?.(otpValue);\n }\n },\n [length, type, onChange, onComplete, focusInput],\n );\n\n const handleFocus = useCallback((e: React.FocusEvent<HTMLInputElement>) => {\n e.target.select();\n }, []);\n\n const renderInputs = () => {\n const inputs: React.ReactNode[] = [];\n\n for (let i = 0; i < length; i++) {\n // Add separator if needed\n if (separatorPositions.includes(i) && i > 0) {\n inputs.push(\n <div key={`separator-${i}`} className=\"flex items-center\">\n {separator}\n </div>,\n );\n }\n\n inputs.push(\n <input\n key={i}\n ref={(el) => {\n inputRefs.current[i] = el;\n // React 19: Return cleanup function\n return () => {\n inputRefs.current[i] = null;\n };\n }}\n type={mask ? \"password\" : \"text\"}\n inputMode={type === \"number\" ? \"numeric\" : \"text\"}\n pattern={type === \"number\" ? \"\\\\d*\" : undefined}\n maxLength={1}\n value={values[i] || \"\"}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => handleChange(i, e)}\n onKeyDown={(e) => handleKeyDown(i, e)}\n onPaste={handlePaste}\n onFocus={handleFocus}\n aria-label={`${ariaLabel} digit ${i + 1}`}\n className={`\n text-center font-semibold outline-none transition-all\n placeholder:text-muted-foreground\n ${sizeStyles[size]}\n ${variantStyles[variant].base}\n ${!error ? variantStyles[variant].focus : \"\"}\n ${error ? variantStyles[variant].error : \"\"}\n ${disabled ? \"opacity-50 cursor-not-allowed bg-muted\" : \"\"}\n ${inputClassName}\n `}\n />,\n );\n }\n\n return inputs;\n };\n\n return (\n <div ref={ref} className={`flex flex-col gap-2 ${className}`}>\n <div\n className=\"flex items-center gap-2\"\n role=\"group\"\n aria-label={ariaLabel}\n >\n {renderInputs()}\n </div>\n {error && errorMessage && (\n <span className=\"text-sm text-destructive\">{errorMessage}</span>\n )}\n </div>\n );\n },\n);\n\nOTPInput.displayName = \"OTPInput\";\n\nexport default OTPInput;\nexport { OTPInput };\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"otp-input-Bg4nQG6x.mjs","names":[],"sources":["../../src/components/forms/otp-input/OTPInput.tsx"],"sourcesContent":["import {\n forwardRef,\n useState,\n useRef,\n useCallback,\n useEffect,\n type KeyboardEvent,\n type ClipboardEvent,\n type ChangeEvent,\n} from \"react\";\n\nexport type OTPInputSize = \"sm\" | \"md\" | \"lg\";\nexport type OTPInputVariant = \"outlined\" | \"filled\" | \"underlined\";\n\nexport interface OTPInputProps {\n /** Number of OTP digits */\n length?: number;\n /** Callback when OTP value changes */\n onChange?: (value: string) => void;\n /** Callback when all digits are filled */\n onComplete?: (value: string) => void;\n /** The current value (controlled) */\n value?: string;\n /** Default value (uncontrolled) */\n defaultValue?: string;\n /** Size of the input boxes */\n size?: OTPInputSize;\n /** Visual variant */\n variant?: OTPInputVariant;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Whether there's an error */\n error?: boolean;\n /** Error message to display */\n errorMessage?: string;\n /** Placeholder character */\n placeholder?: string;\n /** Whether to mask the input (like password) */\n mask?: boolean;\n /** Whether to auto-focus the first input */\n autoFocus?: boolean;\n /** Input type - number only or alphanumeric */\n type?: \"number\" | \"text\";\n /** Custom className for the container */\n className?: string;\n /** Custom className for each input box */\n inputClassName?: string;\n /** Separator to show between groups of digits */\n separator?: React.ReactNode;\n /** Position(s) to show separator (e.g., [3] means after 3rd digit) */\n separatorPositions?: number[];\n /** Accessible label */\n \"aria-label\"?: string;\n}\n\nconst sizeStyles: Record<OTPInputSize, string> = {\n sm: \"w-9 h-10 text-base\",\n md: \"w-12 h-14 text-xl\",\n lg: \"w-14 h-16 text-2xl\",\n};\n\nconst variantStyles: Record<\n OTPInputVariant,\n { base: string; focus: string; error: string }\n> = {\n outlined: {\n base: \"border border-input bg-background-secondary rounded-lg shadow-input text-foreground\",\n focus: \"focus:border-accent focus:ring-2 focus:ring-accent\",\n error: \"border-destructive\",\n },\n filled: {\n base: \"border border-transparent bg-accent-subtle rounded-lg text-foreground\",\n focus:\n \"focus:border-accent focus:bg-background-secondary focus:ring-2 focus:ring-accent\",\n error: \"bg-danger-subtle border-danger-border\",\n },\n underlined: {\n base: \"border-b-2 border-border-strong bg-transparent rounded-none text-foreground\",\n focus: \"focus:border-accent\",\n error: \"border-destructive\",\n },\n};\n\nconst OTPInput = forwardRef<HTMLDivElement, OTPInputProps>(\n (\n {\n length = 6,\n onChange,\n onComplete,\n value: controlledValue,\n defaultValue = \"\",\n size = \"md\",\n variant = \"outlined\",\n disabled = false,\n error = false,\n errorMessage,\n placeholder = \"\",\n mask = false,\n autoFocus = false,\n type = \"number\",\n className = \"\",\n inputClassName = \"\",\n separator = <span className=\"text-neutral-400 text-2xl mx-2\">—</span>,\n separatorPositions = [],\n \"aria-label\": ariaLabel = \"One-time password\",\n },\n ref,\n ) => {\n const [values, setValues] = useState<string[]>(() => {\n const initial = controlledValue ?? defaultValue;\n return initial\n .split(\"\")\n .slice(0, length)\n .concat(Array(length).fill(\"\"))\n .slice(0, length);\n });\n\n const inputRefs = useRef<(HTMLInputElement | null)[]>([]);\n\n // Sync with controlled value\n useEffect(() => {\n if (controlledValue !== undefined) {\n const newValues = controlledValue\n .split(\"\")\n .slice(0, length)\n .concat(Array(length).fill(\"\"))\n .slice(0, length);\n setValues(newValues);\n }\n }, [controlledValue, length]);\n\n // Auto-focus first input\n useEffect(() => {\n if (autoFocus && inputRefs.current[0]) {\n inputRefs.current[0].focus();\n }\n }, [autoFocus]);\n\n const focusInput = useCallback(\n (index: number) => {\n if (index >= 0 && index < length && inputRefs.current[index]) {\n inputRefs.current[index]?.focus();\n inputRefs.current[index]?.select();\n }\n },\n [length],\n );\n\n const handleChange = useCallback(\n (index: number, e: ChangeEvent<HTMLInputElement>) => {\n const inputValue = e.target.value;\n const char = inputValue.slice(-1);\n\n // Validate input based on type\n if (type === \"number\" && char && !/^\\d$/.test(char)) {\n return;\n }\n\n const newValues = [...values];\n newValues[index] = char;\n setValues(newValues);\n\n const otpValue = newValues.join(\"\");\n onChange?.(otpValue);\n\n // Move to next input if value entered\n if (char && index < length - 1) {\n focusInput(index + 1);\n }\n\n // Check if complete\n if (newValues.every((v) => v !== \"\") && newValues.length === length) {\n onComplete?.(otpValue);\n }\n },\n [values, onChange, onComplete, length, type, focusInput],\n );\n\n const handleKeyDown = useCallback(\n (index: number, e: KeyboardEvent<HTMLInputElement>) => {\n switch (e.key) {\n case \"Backspace\":\n e.preventDefault();\n const newValues = [...values];\n if (values[index]) {\n // Clear current value\n newValues[index] = \"\";\n setValues(newValues);\n onChange?.(newValues.join(\"\"));\n } else if (index > 0) {\n // Move to previous and clear\n newValues[index - 1] = \"\";\n setValues(newValues);\n onChange?.(newValues.join(\"\"));\n focusInput(index - 1);\n }\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n focusInput(index - 1);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n focusInput(index + 1);\n break;\n case \"Delete\":\n e.preventDefault();\n const deleteValues = [...values];\n deleteValues[index] = \"\";\n setValues(deleteValues);\n onChange?.(deleteValues.join(\"\"));\n break;\n }\n },\n [values, onChange, focusInput],\n );\n\n const handlePaste = useCallback(\n (e: ClipboardEvent<HTMLInputElement>) => {\n e.preventDefault();\n const pastedData = e.clipboardData.getData(\"text\").slice(0, length);\n\n // Validate pasted content\n if (type === \"number\" && !/^\\d*$/.test(pastedData)) {\n return;\n }\n\n const newValues = pastedData\n .split(\"\")\n .slice(0, length)\n .concat(Array(length).fill(\"\"))\n .slice(0, length);\n\n setValues(newValues);\n const otpValue = newValues.join(\"\");\n onChange?.(otpValue);\n\n // Focus last filled input or last input\n const lastFilledIndex = newValues.findLastIndex((v) => v !== \"\");\n focusInput(Math.min(lastFilledIndex + 1, length - 1));\n\n // Check if complete\n if (newValues.every((v) => v !== \"\") && pastedData.length >= length) {\n onComplete?.(otpValue);\n }\n },\n [length, type, onChange, onComplete, focusInput],\n );\n\n const handleFocus = useCallback((e: React.FocusEvent<HTMLInputElement>) => {\n e.target.select();\n }, []);\n\n const renderInputs = () => {\n const inputs: React.ReactNode[] = [];\n\n for (let i = 0; i < length; i++) {\n // Add separator if needed\n if (separatorPositions.includes(i) && i > 0) {\n inputs.push(\n <div key={`separator-${i}`} className=\"flex items-center\">\n {separator}\n </div>,\n );\n }\n\n inputs.push(\n <input\n key={i}\n ref={(el) => {\n inputRefs.current[i] = el;\n // React 19: Return cleanup function\n return () => {\n inputRefs.current[i] = null;\n };\n }}\n type={mask ? \"password\" : \"text\"}\n inputMode={type === \"number\" ? \"numeric\" : \"text\"}\n pattern={type === \"number\" ? \"\\\\d*\" : undefined}\n maxLength={1}\n value={values[i] || \"\"}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => handleChange(i, e)}\n onKeyDown={(e) => handleKeyDown(i, e)}\n onPaste={handlePaste}\n onFocus={handleFocus}\n aria-label={`${ariaLabel} digit ${i + 1}`}\n className={`\n text-center font-semibold outline-none transition-all\n placeholder:text-muted-foreground\n ${sizeStyles[size]}\n ${variantStyles[variant].base}\n ${!error ? variantStyles[variant].focus : \"\"}\n ${error ? variantStyles[variant].error : \"\"}\n ${disabled ? \"opacity-50 cursor-not-allowed bg-muted\" : \"\"}\n ${inputClassName}\n `}\n />,\n );\n }\n\n return inputs;\n };\n\n return (\n <div ref={ref} className={`flex flex-col gap-2 ${className}`}>\n <div\n className=\"flex items-center gap-2\"\n role=\"group\"\n aria-label={ariaLabel}\n >\n {renderInputs()}\n </div>\n {error && errorMessage && (\n <span className=\"text-sm text-destructive\">{errorMessage}</span>\n )}\n </div>\n );\n },\n);\n\nOTPInput.displayName = \"OTPInput\";\n\nexport default OTPInput;\nexport { OTPInput };\n"],"mappings":"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"}
|