erp-pro-ui 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/dist/calendar.cjs +1 -1
  2. package/dist/calendar.mjs +1 -1
  3. package/dist/card.cjs +1 -1
  4. package/dist/card.mjs +1 -1
  5. package/dist/carousel.cjs +1 -1
  6. package/dist/carousel.mjs +1 -1
  7. package/dist/catalog.cjs +6 -0
  8. package/dist/catalog.cjs.map +1 -1
  9. package/dist/catalog.d.ts +11 -1
  10. package/dist/catalog.d.ts.map +1 -1
  11. package/dist/catalog.mjs +6 -0
  12. package/dist/catalog.mjs.map +1 -1
  13. package/dist/charts.cjs +2 -1
  14. package/dist/charts.mjs +2 -2
  15. package/dist/checkbox.cjs +1 -1
  16. package/dist/checkbox.mjs +1 -1
  17. package/dist/chip.cjs +1 -1
  18. package/dist/chip.mjs +1 -1
  19. package/dist/chroma-grid.cjs +1 -1
  20. package/dist/chroma-grid.mjs +1 -1
  21. package/dist/chunks/{calendar-xrGmvukr.cjs → calendar-Cpp_Rc7T.cjs} +58 -17
  22. package/dist/chunks/calendar-Cpp_Rc7T.cjs.map +1 -0
  23. package/dist/chunks/{calendar-BarcG6x_.mjs → calendar-DrCgT_pj.mjs} +58 -17
  24. package/dist/chunks/calendar-DrCgT_pj.mjs.map +1 -0
  25. package/dist/chunks/{card-gt-HZh0h.cjs → card-C5_tFK6Q.cjs} +1 -1
  26. package/dist/chunks/{card-gt-HZh0h.cjs.map → card-C5_tFK6Q.cjs.map} +1 -1
  27. package/dist/chunks/{card-CcIF6z2H.mjs → card-Dh8wNv8N.mjs} +1 -1
  28. package/dist/chunks/{card-CcIF6z2H.mjs.map → card-Dh8wNv8N.mjs.map} +1 -1
  29. package/dist/chunks/{carousel-DJdqBVRK.mjs → carousel-BYwqI4cA.mjs} +1 -1
  30. package/dist/chunks/{carousel-DJdqBVRK.mjs.map → carousel-BYwqI4cA.mjs.map} +1 -1
  31. package/dist/chunks/{carousel-Cq5uwqQt.cjs → carousel-C1338X8h.cjs} +1 -1
  32. package/dist/chunks/{carousel-Cq5uwqQt.cjs.map → carousel-C1338X8h.cjs.map} +1 -1
  33. package/dist/chunks/{charts-DugYWvEf.mjs → charts-BYvM4TMG.mjs} +371 -117
  34. package/dist/chunks/charts-BYvM4TMG.mjs.map +1 -0
  35. package/dist/chunks/{charts-BpElnsoR.cjs → charts-DbxyHtlX.cjs} +375 -115
  36. package/dist/chunks/charts-DbxyHtlX.cjs.map +1 -0
  37. package/dist/chunks/{checkbox-yHuSw-hV.cjs → checkbox-CxOcjoGP.cjs} +1 -1
  38. package/dist/chunks/{checkbox-yHuSw-hV.cjs.map → checkbox-CxOcjoGP.cjs.map} +1 -1
  39. package/dist/chunks/{checkbox-DvwlGwWe.mjs → checkbox-Pr49U9F1.mjs} +1 -1
  40. package/dist/chunks/{checkbox-DvwlGwWe.mjs.map → checkbox-Pr49U9F1.mjs.map} +1 -1
  41. package/dist/chunks/{chip-DcBji__g.cjs → chip-B4ol1yPk.cjs} +1 -1
  42. package/dist/chunks/{chip-DcBji__g.cjs.map → chip-B4ol1yPk.cjs.map} +1 -1
  43. package/dist/chunks/{chip-BGSUmnlO.mjs → chip-DdnBLdpl.mjs} +1 -1
  44. package/dist/chunks/{chip-BGSUmnlO.mjs.map → chip-DdnBLdpl.mjs.map} +1 -1
  45. package/dist/chunks/{chroma-grid-Cdeql_2C.mjs → chroma-grid-BAo6V5A7.mjs} +1 -1
  46. package/dist/chunks/{chroma-grid-Cdeql_2C.mjs.map → chroma-grid-BAo6V5A7.mjs.map} +1 -1
  47. package/dist/chunks/{chroma-grid-9E9j1s9I.cjs → chroma-grid-CIk0dsNS.cjs} +1 -1
  48. package/dist/chunks/{chroma-grid-9E9j1s9I.cjs.map → chroma-grid-CIk0dsNS.cjs.map} +1 -1
  49. package/dist/chunks/{color-palette-BLvDnCOD.cjs → color-palette-2TuEMkAn.cjs} +1 -1
  50. package/dist/chunks/{color-palette-BLvDnCOD.cjs.map → color-palette-2TuEMkAn.cjs.map} +1 -1
  51. package/dist/chunks/{color-palette-CXlCDiZz.mjs → color-palette-euKQMWlV.mjs} +1 -1
  52. package/dist/chunks/{color-palette-CXlCDiZz.mjs.map → color-palette-euKQMWlV.mjs.map} +1 -1
  53. package/dist/chunks/{combobox-BXu3s0dt.cjs → combobox-CwGubKTt.cjs} +2 -2
  54. package/dist/chunks/combobox-CwGubKTt.cjs.map +1 -0
  55. package/dist/chunks/{combobox-CjK-qG4k.mjs → combobox-DrFmkI0F.mjs} +2 -2
  56. package/dist/chunks/combobox-DrFmkI0F.mjs.map +1 -0
  57. package/dist/chunks/{data-table-DyEQn9Yj.mjs → data-table-Bo80m7qV.mjs} +8 -8
  58. package/dist/chunks/{data-table-DyEQn9Yj.mjs.map → data-table-Bo80m7qV.mjs.map} +1 -1
  59. package/dist/chunks/{data-table-9HELVsYR.cjs → data-table-W1sK5tkL.cjs} +8 -8
  60. package/dist/chunks/{data-table-9HELVsYR.cjs.map → data-table-W1sK5tkL.cjs.map} +1 -1
  61. package/dist/chunks/{date-picker-D8gaaMlJ.mjs → date-picker-CNPORxhv.mjs} +87 -17
  62. package/dist/chunks/date-picker-CNPORxhv.mjs.map +1 -0
  63. package/dist/chunks/{date-picker-W9om1j7A.cjs → date-picker-CZo68Fkl.cjs} +87 -17
  64. package/dist/chunks/date-picker-CZo68Fkl.cjs.map +1 -0
  65. package/dist/chunks/input-BWM6G7jq.cjs +117 -0
  66. package/dist/chunks/input-BWM6G7jq.cjs.map +1 -0
  67. package/dist/chunks/input-Bt_r_B_c.mjs +105 -0
  68. package/dist/chunks/input-Bt_r_B_c.mjs.map +1 -0
  69. package/dist/chunks/{multi-select-combobox-ELSH_Xr4.mjs → multi-select-combobox-D46M-AN9.mjs} +2 -2
  70. package/dist/chunks/multi-select-combobox-D46M-AN9.mjs.map +1 -0
  71. package/dist/chunks/{multi-select-combobox-UW0X15W7.cjs → multi-select-combobox-dS6bJE_e.cjs} +2 -2
  72. package/dist/chunks/multi-select-combobox-dS6bJE_e.cjs.map +1 -0
  73. package/dist/chunks/{otp-input-B6zzOEqw.cjs → otp-input-DSW9Ca_D.cjs} +2 -2
  74. package/dist/chunks/otp-input-DSW9Ca_D.cjs.map +1 -0
  75. package/dist/chunks/{otp-input-Bg4nQG6x.mjs → otp-input-DeAi4nJ_.mjs} +2 -2
  76. package/dist/chunks/otp-input-DeAi4nJ_.mjs.map +1 -0
  77. package/dist/chunks/{progress-bar-C9FZDrju.mjs → progress-bar-B9sy7WBT.mjs} +1 -1
  78. package/dist/chunks/{progress-bar-C9FZDrju.mjs.map → progress-bar-B9sy7WBT.mjs.map} +1 -1
  79. package/dist/chunks/{progress-bar-C1OvQ-NI.cjs → progress-bar-BdvQtpm3.cjs} +1 -1
  80. package/dist/chunks/{progress-bar-C1OvQ-NI.cjs.map → progress-bar-BdvQtpm3.cjs.map} +1 -1
  81. package/dist/chunks/select-B8UQ6Uq5.mjs +170 -0
  82. package/dist/chunks/select-B8UQ6Uq5.mjs.map +1 -0
  83. package/dist/chunks/select-CCUSMvfS.cjs +176 -0
  84. package/dist/chunks/select-CCUSMvfS.cjs.map +1 -0
  85. package/dist/chunks/stepper-D6qQbZdg.cjs +642 -0
  86. package/dist/chunks/stepper-D6qQbZdg.cjs.map +1 -0
  87. package/dist/chunks/stepper-DUknuW2E.mjs +618 -0
  88. package/dist/chunks/stepper-DUknuW2E.mjs.map +1 -0
  89. package/dist/chunks/{textarea-CU5C-Zw9.mjs → textarea-Blky_fLK.mjs} +2 -2
  90. package/dist/chunks/{textarea-CU5C-Zw9.mjs.map → textarea-Blky_fLK.mjs.map} +1 -1
  91. package/dist/chunks/{textarea-CAUsyu4-.cjs → textarea-ok_NlE2p.cjs} +2 -2
  92. package/dist/chunks/textarea-ok_NlE2p.cjs.map +1 -0
  93. package/dist/color-palette.cjs +1 -1
  94. package/dist/color-palette.mjs +1 -1
  95. package/dist/colors.css +3 -0
  96. package/dist/combobox.cjs +1 -1
  97. package/dist/combobox.mjs +1 -1
  98. package/dist/components/data-display/charts/AreaChart.d.ts.map +1 -1
  99. package/dist/components/data-display/charts/BarChart.d.ts +1 -0
  100. package/dist/components/data-display/charts/BarChart.d.ts.map +1 -1
  101. package/dist/components/data-display/charts/NeonLineChart.d.ts.map +1 -1
  102. package/dist/components/data-display/charts/PieChart.d.ts +18 -2
  103. package/dist/components/data-display/charts/PieChart.d.ts.map +1 -1
  104. package/dist/components/data-display/charts/PositiveNegativeBarChart.d.ts +21 -0
  105. package/dist/components/data-display/charts/PositiveNegativeBarChart.d.ts.map +1 -0
  106. package/dist/components/data-display/charts/StackedBarChart.d.ts.map +1 -1
  107. package/dist/components/data-display/charts/ThinBreakdownBar.d.ts +3 -0
  108. package/dist/components/data-display/charts/ThinBreakdownBar.d.ts.map +1 -1
  109. package/dist/components/data-display/charts/chartStyles.d.ts +24 -0
  110. package/dist/components/data-display/charts/chartStyles.d.ts.map +1 -0
  111. package/dist/components/data-display/charts/index.d.ts +2 -0
  112. package/dist/components/data-display/charts/index.d.ts.map +1 -1
  113. package/dist/components/forms/calendar/Calendar.d.ts.map +1 -1
  114. package/dist/components/forms/date-picker/DatePicker.d.ts.map +1 -1
  115. package/dist/components/forms/input/Input.d.ts.map +1 -1
  116. package/dist/components/forms/input/types.d.ts +5 -0
  117. package/dist/components/forms/input/types.d.ts.map +1 -1
  118. package/dist/components/forms/select/Select.d.ts.map +1 -1
  119. package/dist/components/forms/select/types.d.ts +7 -1
  120. package/dist/components/forms/select/types.d.ts.map +1 -1
  121. package/dist/components/navigation/stepper/Stepper1.d.ts +4 -0
  122. package/dist/components/navigation/stepper/Stepper1.d.ts.map +1 -0
  123. package/dist/components/navigation/stepper/Stepper2.d.ts +5 -0
  124. package/dist/components/navigation/stepper/Stepper2.d.ts.map +1 -0
  125. package/dist/components/navigation/stepper/index.d.ts +4 -1
  126. package/dist/components/navigation/stepper/index.d.ts.map +1 -1
  127. package/dist/components/navigation/stepper/types.d.ts +85 -0
  128. package/dist/components/navigation/stepper/types.d.ts.map +1 -1
  129. package/dist/data-table.cjs +1 -1
  130. package/dist/data-table.mjs +1 -1
  131. package/dist/date-picker.cjs +1 -1
  132. package/dist/date-picker.mjs +1 -1
  133. package/dist/docs.cjs +10 -0
  134. package/dist/docs.cjs.map +1 -1
  135. package/dist/docs.d.ts.map +1 -1
  136. package/dist/docs.mjs +10 -0
  137. package/dist/docs.mjs.map +1 -1
  138. package/dist/foundation.css +7 -0
  139. package/dist/index.cjs +23 -18
  140. package/dist/index.d.ts +5 -3
  141. package/dist/index.d.ts.map +1 -1
  142. package/dist/index.mjs +19 -19
  143. package/dist/input.cjs +1 -1
  144. package/dist/input.mjs +1 -1
  145. package/dist/multi-select-combobox.cjs +1 -1
  146. package/dist/multi-select-combobox.mjs +1 -1
  147. package/dist/otp-input.cjs +1 -1
  148. package/dist/otp-input.mjs +1 -1
  149. package/dist/progress-bar.cjs +1 -1
  150. package/dist/progress-bar.mjs +1 -1
  151. package/dist/select.cjs +1 -1
  152. package/dist/select.mjs +1 -1
  153. package/dist/stepper.cjs +5 -1
  154. package/dist/stepper.mjs +2 -2
  155. package/dist/textarea.cjs +1 -1
  156. package/dist/textarea.mjs +1 -1
  157. package/dist/tokens.css +11 -2
  158. package/package.json +4 -4
  159. package/dist/chunks/calendar-BarcG6x_.mjs.map +0 -1
  160. package/dist/chunks/calendar-xrGmvukr.cjs.map +0 -1
  161. package/dist/chunks/charts-BpElnsoR.cjs.map +0 -1
  162. package/dist/chunks/charts-DugYWvEf.mjs.map +0 -1
  163. package/dist/chunks/combobox-BXu3s0dt.cjs.map +0 -1
  164. package/dist/chunks/combobox-CjK-qG4k.mjs.map +0 -1
  165. package/dist/chunks/date-picker-D8gaaMlJ.mjs.map +0 -1
  166. package/dist/chunks/date-picker-W9om1j7A.cjs.map +0 -1
  167. package/dist/chunks/input-D9qZNqXV.cjs +0 -99
  168. package/dist/chunks/input-D9qZNqXV.cjs.map +0 -1
  169. package/dist/chunks/input-wNqevfQ4.mjs +0 -87
  170. package/dist/chunks/input-wNqevfQ4.mjs.map +0 -1
  171. package/dist/chunks/multi-select-combobox-ELSH_Xr4.mjs.map +0 -1
  172. package/dist/chunks/multi-select-combobox-UW0X15W7.cjs.map +0 -1
  173. package/dist/chunks/otp-input-B6zzOEqw.cjs.map +0 -1
  174. package/dist/chunks/otp-input-Bg4nQG6x.mjs.map +0 -1
  175. package/dist/chunks/select-D71tk6-I.mjs +0 -152
  176. package/dist/chunks/select-D71tk6-I.mjs.map +0 -1
  177. package/dist/chunks/select-WC_kPqUP.cjs +0 -158
  178. package/dist/chunks/select-WC_kPqUP.cjs.map +0 -1
  179. package/dist/chunks/stepper-D4yQsQB0.mjs +0 -261
  180. package/dist/chunks/stepper-D4yQsQB0.mjs.map +0 -1
  181. package/dist/chunks/stepper-fY-Sx72k.cjs +0 -267
  182. package/dist/chunks/stepper-fY-Sx72k.cjs.map +0 -1
  183. package/dist/chunks/textarea-CAUsyu4-.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otp-input-DSW9Ca_D.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 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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"}
@@ -8,7 +8,7 @@ var sizeStyles = {
8
8
  };
9
9
  var variantStyles = {
10
10
  outlined: {
11
- base: "border border-input bg-background-secondary rounded-lg shadow-input text-foreground",
11
+ base: "border border-input bg-background-secondary rounded-lg text-foreground",
12
12
  focus: "focus:border-accent focus:ring-2 focus:ring-accent",
13
13
  error: "border-destructive"
14
14
  },
@@ -177,4 +177,4 @@ OTPInput.displayName = "OTPInput";
177
177
  //#endregion
178
178
  export { OTPInput as t };
179
179
 
180
- //# sourceMappingURL=otp-input-Bg4nQG6x.mjs.map
180
+ //# sourceMappingURL=otp-input-DeAi4nJ_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otp-input-DeAi4nJ_.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 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":";;;AAuDA,IAAM,aAA2C;CAC/C,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,IAAM,gBAGF;CACF,UAAU;EACR,MAAM;EACN,OAAO;EACP,OAAO;EACR;CACD,QAAQ;EACN,MAAM;EACN,OACE;EACF,OAAO;EACR;CACD,YAAY;EACV,MAAM;EACN,OAAO;EACP,OAAO;EACR;CACF;AAED,IAAM,WAAW,YAEb,EACE,SAAS,GACT,UACA,YACA,OAAO,iBACP,eAAe,IACf,OAAO,MACP,UAAU,YACV,WAAW,OACX,QAAQ,OACR,cACA,cAAc,IACd,OAAO,OACP,YAAY,OACZ,OAAO,UACP,YAAY,IACZ,iBAAiB,IACjB,YAAY,oBAAC,QAAD;CAAM,WAAU;WAAiC;CAAQ,CAAA,EACrE,qBAAqB,EAAE,EACvB,cAAc,YAAY,uBAE5B,QACG;CACH,MAAM,CAAC,QAAQ,aAAa,eAAyB;AAEnD,UADgB,mBAAmB,cAEhC,MAAM,GAAG,CACT,MAAM,GAAG,OAAO,CAChB,OAAO,MAAM,OAAO,CAAC,KAAK,GAAG,CAAC,CAC9B,MAAM,GAAG,OAAO;GACnB;CAEF,MAAM,YAAY,OAAoC,EAAE,CAAC;AAGzD,iBAAgB;AACd,MAAI,oBAAoB,KAAA,EAMtB,WALkB,gBACf,MAAM,GAAG,CACT,MAAM,GAAG,OAAO,CAChB,OAAO,MAAM,OAAO,CAAC,KAAK,GAAG,CAAC,CAC9B,MAAM,GAAG,OAAO,CACC;IAErB,CAAC,iBAAiB,OAAO,CAAC;AAG7B,iBAAgB;AACd,MAAI,aAAa,UAAU,QAAQ,GACjC,WAAU,QAAQ,GAAG,OAAO;IAE7B,CAAC,UAAU,CAAC;CAEf,MAAM,aAAa,aAChB,UAAkB;AACjB,MAAI,SAAS,KAAK,QAAQ,UAAU,UAAU,QAAQ,QAAQ;AAC5D,aAAU,QAAQ,QAAQ,OAAO;AACjC,aAAU,QAAQ,QAAQ,QAAQ;;IAGtC,CAAC,OAAO,CACT;CAED,MAAM,eAAe,aAClB,OAAe,MAAqC;EAEnD,MAAM,OADa,EAAE,OAAO,MACJ,MAAM,GAAG;AAGjC,MAAI,SAAS,YAAY,QAAQ,CAAC,OAAO,KAAK,KAAK,CACjD;EAGF,MAAM,YAAY,CAAC,GAAG,OAAO;AAC7B,YAAU,SAAS;AACnB,YAAU,UAAU;EAEpB,MAAM,WAAW,UAAU,KAAK,GAAG;AACnC,aAAW,SAAS;AAGpB,MAAI,QAAQ,QAAQ,SAAS,EAC3B,YAAW,QAAQ,EAAE;AAIvB,MAAI,UAAU,OAAO,MAAM,MAAM,GAAG,IAAI,UAAU,WAAW,OAC3D,cAAa,SAAS;IAG1B;EAAC;EAAQ;EAAU;EAAY;EAAQ;EAAM;EAAW,CACzD;CAED,MAAM,gBAAgB,aACnB,OAAe,MAAuC;AACrD,UAAQ,EAAE,KAAV;GACE,KAAK;AACH,MAAE,gBAAgB;IAClB,MAAM,YAAY,CAAC,GAAG,OAAO;AAC7B,QAAI,OAAO,QAAQ;AAEjB,eAAU,SAAS;AACnB,eAAU,UAAU;AACpB,gBAAW,UAAU,KAAK,GAAG,CAAC;eACrB,QAAQ,GAAG;AAEpB,eAAU,QAAQ,KAAK;AACvB,eAAU,UAAU;AACpB,gBAAW,UAAU,KAAK,GAAG,CAAC;AAC9B,gBAAW,QAAQ,EAAE;;AAEvB;GACF,KAAK;AACH,MAAE,gBAAgB;AAClB,eAAW,QAAQ,EAAE;AACrB;GACF,KAAK;AACH,MAAE,gBAAgB;AAClB,eAAW,QAAQ,EAAE;AACrB;GACF,KAAK;AACH,MAAE,gBAAgB;IAClB,MAAM,eAAe,CAAC,GAAG,OAAO;AAChC,iBAAa,SAAS;AACtB,cAAU,aAAa;AACvB,eAAW,aAAa,KAAK,GAAG,CAAC;AACjC;;IAGN;EAAC;EAAQ;EAAU;EAAW,CAC/B;CAED,MAAM,cAAc,aACjB,MAAwC;AACvC,IAAE,gBAAgB;EAClB,MAAM,aAAa,EAAE,cAAc,QAAQ,OAAO,CAAC,MAAM,GAAG,OAAO;AAGnE,MAAI,SAAS,YAAY,CAAC,QAAQ,KAAK,WAAW,CAChD;EAGF,MAAM,YAAY,WACf,MAAM,GAAG,CACT,MAAM,GAAG,OAAO,CAChB,OAAO,MAAM,OAAO,CAAC,KAAK,GAAG,CAAC,CAC9B,MAAM,GAAG,OAAO;AAEnB,YAAU,UAAU;EACpB,MAAM,WAAW,UAAU,KAAK,GAAG;AACnC,aAAW,SAAS;EAGpB,MAAM,kBAAkB,UAAU,eAAe,MAAM,MAAM,GAAG;AAChE,aAAW,KAAK,IAAI,kBAAkB,GAAG,SAAS,EAAE,CAAC;AAGrD,MAAI,UAAU,OAAO,MAAM,MAAM,GAAG,IAAI,WAAW,UAAU,OAC3D,cAAa,SAAS;IAG1B;EAAC;EAAQ;EAAM;EAAU;EAAY;EAAW,CACjD;CAED,MAAM,cAAc,aAAa,MAA0C;AACzE,IAAE,OAAO,QAAQ;IAChB,EAAE,CAAC;CAEN,MAAM,qBAAqB;EACzB,MAAM,SAA4B,EAAE;AAEpC,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;AAE/B,OAAI,mBAAmB,SAAS,EAAE,IAAI,IAAI,EACxC,QAAO,KACL,oBAAC,OAAD;IAA4B,WAAU;cACnC;IACG,EAFI,aAAa,IAEjB,CACP;AAGH,UAAO,KACL,oBAAC,SAAD;IAEE,MAAM,OAAO;AACX,eAAU,QAAQ,KAAK;AAEvB,kBAAa;AACX,gBAAU,QAAQ,KAAK;;;IAG3B,MAAM,OAAO,aAAa;IAC1B,WAAW,SAAS,WAAW,YAAY;IAC3C,SAAS,SAAS,WAAW,SAAS,KAAA;IACtC,WAAW;IACX,OAAO,OAAO,MAAM;IACP;IACH;IACV,WAAW,MAAM,aAAa,GAAG,EAAE;IACnC,YAAY,MAAM,cAAc,GAAG,EAAE;IACrC,SAAS;IACT,SAAS;IACT,cAAY,GAAG,UAAU,SAAS,IAAI;IACtC,WAAW;;;gBAGP,WAAW,MAAM;gBACjB,cAAc,SAAS,KAAK;gBAC5B,CAAC,QAAQ,cAAc,SAAS,QAAQ,GAAG;gBAC3C,QAAQ,cAAc,SAAS,QAAQ,GAAG;gBAC1C,WAAW,2CAA2C,GAAG;gBACzD,eAAe;;IAEnB,EA9BK,EA8BL,CACH;;AAGH,SAAO;;AAGT,QACE,qBAAC,OAAD;EAAU;EAAK,WAAW,uBAAuB;YAAjD,CACE,oBAAC,OAAD;GACE,WAAU;GACV,MAAK;GACL,cAAY;aAEX,cAAc;GACX,CAAA,EACL,SAAS,gBACR,oBAAC,QAAD;GAAM,WAAU;aAA4B;GAAoB,CAAA,CAE9D;;EAGX;AAED,SAAS,cAAc"}
@@ -86,4 +86,4 @@ function ProgressBar({ value, max = 100, label, percentageLabel, showPercentage
86
86
  //#endregion
87
87
  export { ProgressBar as t };
88
88
 
89
- //# sourceMappingURL=progress-bar-C9FZDrju.mjs.map
89
+ //# sourceMappingURL=progress-bar-B9sy7WBT.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress-bar-C9FZDrju.mjs","names":[],"sources":["../../src/components/data-display/progress-bar/ProgressBar.tsx"],"sourcesContent":["import React from \"react\";\n\nexport type ProgressBarSize = \"sm\" | \"md\" | \"lg\";\nexport type ProgressBarTone =\n | \"default\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"info\";\n\nexport interface ProgressBarProps {\n value: number;\n max?: number;\n label?: React.ReactNode;\n percentageLabel?: React.ReactNode;\n showPercentage?: boolean;\n size?: ProgressBarSize;\n tone?: ProgressBarTone;\n className?: string;\n trackClassName?: string;\n fillClassName?: string;\n ariaLabel?: string;\n}\n\nconst sizeStyles: Record<\n ProgressBarSize,\n {\n track: string;\n label: string;\n percentage: string;\n }\n> = {\n sm: {\n track: \"h-1.5\",\n label: \"text-xs\",\n percentage: \"text-xs\",\n },\n md: {\n track: \"h-2.5\",\n label: \"text-sm\",\n percentage: \"text-sm\",\n },\n lg: {\n track: \"h-3.5\",\n label: \"text-base\",\n percentage: \"text-base\",\n },\n};\n\nconst toneStyles: Record<\n ProgressBarTone,\n {\n color: string;\n trackBackground: string;\n }\n> = {\n default: {\n color: \"var(--ds-chart-1)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(15, 23, 42, 0.08) 0%, rgba(30, 41, 59, 0.14) 100%)\",\n },\n success: {\n color: \"var(--ds-chart-3)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(20, 83, 45, 0.12) 0%, rgba(34, 197, 94, 0.18) 100%)\",\n },\n warning: {\n color: \"var(--ds-chart-4)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(120, 53, 15, 0.12) 0%, rgba(245, 158, 11, 0.18) 100%)\",\n },\n danger: {\n color: \"var(--ds-chart-5)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(127, 29, 29, 0.12) 0%, rgba(239, 68, 68, 0.18) 100%)\",\n },\n info: {\n color: \"var(--ds-chart-2)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(30, 64, 175, 0.12) 0%, rgba(59, 130, 246, 0.18) 100%)\",\n },\n};\n\nfunction clampValue(value: number, max: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n\n return Math.min(Math.max(value, 0), max);\n}\n\nexport default function ProgressBar({\n value,\n max = 100,\n label,\n percentageLabel,\n showPercentage = true,\n size = \"md\",\n tone = \"default\",\n className = \"\",\n trackClassName = \"\",\n fillClassName = \"\",\n ariaLabel = \"Progress\",\n}: ProgressBarProps) {\n const safeMax = Number.isFinite(max) && max > 0 ? max : 100;\n const clampedValue = clampValue(value, safeMax);\n const percentage = (clampedValue / safeMax) * 100;\n const roundedPercentage = Math.round(percentage);\n const toneStyle = toneStyles[tone];\n const resolvedPercentageLabel = percentageLabel ?? `${roundedPercentage}%`;\n\n return (\n <div className={`w-full space-y-3 ${className}`}>\n {(label || showPercentage) && (\n <div className=\"flex items-center justify-between gap-4\">\n <div\n className={`font-mono font-semibold tracking-[0.08em] text-foreground ${sizeStyles[size].label}`}\n >\n {label}\n </div>\n {showPercentage && (\n <div\n className={`font-mono font-medium tracking-[0.08em] text-muted-foreground ${sizeStyles[size].percentage}`}\n >\n {resolvedPercentageLabel}\n </div>\n )}\n </div>\n )}\n\n <div\n role=\"progressbar\"\n aria-label={ariaLabel}\n aria-valuemin={0}\n aria-valuemax={safeMax}\n aria-valuenow={Math.round(clampedValue)}\n aria-valuetext={`${roundedPercentage}%`}\n className={`relative overflow-hidden rounded-full border border-white/12 bg-background-tertiary/80 shadow-[inset_0_1px_1px_rgba(255,255,255,0.2)] dark:border-white/6 ${sizeStyles[size].track} ${trackClassName}`}\n style={{ background: toneStyle.trackBackground }}\n >\n <div\n className={`h-full rounded-full transition-[width,filter,box-shadow] duration-500 ease-out ${fillClassName}`}\n style={{\n width: `${percentage}%`,\n background: `linear-gradient(90deg, color-mix(in srgb, ${toneStyle.color} 68%, white 32%) 0%, ${toneStyle.color} 100%)`,\n boxShadow: `inset 0 1px 0 rgba(255,255,255,0.4), 0 0 14px color-mix(in srgb, ${toneStyle.color} 32%, transparent)`,\n filter: percentage > 0 ? \"saturate(1.05) brightness(1.02)\" : \"none\",\n }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAwBA,IAAM,aAOF;CACF,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACF;AAED,IAAM,aAMF;CACF,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,QAAQ;EACN,OAAO;EACP,iBACE;EACH;CACD,MAAM;EACJ,OAAO;EACP,iBACE;EACH;CACF;AAED,SAAS,WAAW,OAAe,KAAqB;AACtD,KAAI,CAAC,OAAO,SAAS,MAAM,CACzB,QAAO;AAGT,QAAO,KAAK,IAAI,KAAK,IAAI,OAAO,EAAE,EAAE,IAAI;;AAG1C,SAAwB,YAAY,EAClC,OACA,MAAM,KACN,OACA,iBACA,iBAAiB,MACjB,OAAO,MACP,OAAO,WACP,YAAY,IACZ,iBAAiB,IACjB,gBAAgB,IAChB,YAAY,cACO;CACnB,MAAM,UAAU,OAAO,SAAS,IAAI,IAAI,MAAM,IAAI,MAAM;CACxD,MAAM,eAAe,WAAW,OAAO,QAAQ;CAC/C,MAAM,aAAc,eAAe,UAAW;CAC9C,MAAM,oBAAoB,KAAK,MAAM,WAAW;CAChD,MAAM,YAAY,WAAW;CAC7B,MAAM,0BAA0B,mBAAmB,GAAG,kBAAkB;AAExE,QACE,qBAAC,OAAD;EAAK,WAAW,oBAAoB;YAApC,EACI,SAAS,mBACT,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IACE,WAAW,6DAA6D,WAAW,MAAM;cAExF;IACG,CAAA,EACL,kBACC,oBAAC,OAAD;IACE,WAAW,iEAAiE,WAAW,MAAM;cAE5F;IACG,CAAA,CAEJ;MAGR,oBAAC,OAAD;GACE,MAAK;GACL,cAAY;GACZ,iBAAe;GACf,iBAAe;GACf,iBAAe,KAAK,MAAM,aAAa;GACvC,kBAAgB,GAAG,kBAAkB;GACrC,WAAW,6JAA6J,WAAW,MAAM,MAAM,GAAG;GAClM,OAAO,EAAE,YAAY,UAAU,iBAAiB;aAEhD,oBAAC,OAAD;IACE,WAAW,kFAAkF;IAC7F,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,YAAY,6CAA6C,UAAU,MAAM,uBAAuB,UAAU,MAAM;KAChH,WAAW,oEAAoE,UAAU,MAAM;KAC/F,QAAQ,aAAa,IAAI,oCAAoC;KAC9D;IACD,CAAA;GACE,CAAA,CACF"}
1
+ {"version":3,"file":"progress-bar-B9sy7WBT.mjs","names":[],"sources":["../../src/components/data-display/progress-bar/ProgressBar.tsx"],"sourcesContent":["import React from \"react\";\n\nexport type ProgressBarSize = \"sm\" | \"md\" | \"lg\";\nexport type ProgressBarTone =\n | \"default\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"info\";\n\nexport interface ProgressBarProps {\n value: number;\n max?: number;\n label?: React.ReactNode;\n percentageLabel?: React.ReactNode;\n showPercentage?: boolean;\n size?: ProgressBarSize;\n tone?: ProgressBarTone;\n className?: string;\n trackClassName?: string;\n fillClassName?: string;\n ariaLabel?: string;\n}\n\nconst sizeStyles: Record<\n ProgressBarSize,\n {\n track: string;\n label: string;\n percentage: string;\n }\n> = {\n sm: {\n track: \"h-1.5\",\n label: \"text-xs\",\n percentage: \"text-xs\",\n },\n md: {\n track: \"h-2.5\",\n label: \"text-sm\",\n percentage: \"text-sm\",\n },\n lg: {\n track: \"h-3.5\",\n label: \"text-base\",\n percentage: \"text-base\",\n },\n};\n\nconst toneStyles: Record<\n ProgressBarTone,\n {\n color: string;\n trackBackground: string;\n }\n> = {\n default: {\n color: \"var(--ds-chart-1)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(15, 23, 42, 0.08) 0%, rgba(30, 41, 59, 0.14) 100%)\",\n },\n success: {\n color: \"var(--ds-chart-3)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(20, 83, 45, 0.12) 0%, rgba(34, 197, 94, 0.18) 100%)\",\n },\n warning: {\n color: \"var(--ds-chart-4)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(120, 53, 15, 0.12) 0%, rgba(245, 158, 11, 0.18) 100%)\",\n },\n danger: {\n color: \"var(--ds-chart-5)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(127, 29, 29, 0.12) 0%, rgba(239, 68, 68, 0.18) 100%)\",\n },\n info: {\n color: \"var(--ds-chart-2)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(30, 64, 175, 0.12) 0%, rgba(59, 130, 246, 0.18) 100%)\",\n },\n};\n\nfunction clampValue(value: number, max: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n\n return Math.min(Math.max(value, 0), max);\n}\n\nexport default function ProgressBar({\n value,\n max = 100,\n label,\n percentageLabel,\n showPercentage = true,\n size = \"md\",\n tone = \"default\",\n className = \"\",\n trackClassName = \"\",\n fillClassName = \"\",\n ariaLabel = \"Progress\",\n}: ProgressBarProps) {\n const safeMax = Number.isFinite(max) && max > 0 ? max : 100;\n const clampedValue = clampValue(value, safeMax);\n const percentage = (clampedValue / safeMax) * 100;\n const roundedPercentage = Math.round(percentage);\n const toneStyle = toneStyles[tone];\n const resolvedPercentageLabel = percentageLabel ?? `${roundedPercentage}%`;\n\n return (\n <div className={`w-full space-y-3 ${className}`}>\n {(label || showPercentage) && (\n <div className=\"flex items-center justify-between gap-4\">\n <div\n className={`font-mono font-semibold tracking-[0.08em] text-foreground ${sizeStyles[size].label}`}\n >\n {label}\n </div>\n {showPercentage && (\n <div\n className={`font-mono font-medium tracking-[0.08em] text-muted-foreground ${sizeStyles[size].percentage}`}\n >\n {resolvedPercentageLabel}\n </div>\n )}\n </div>\n )}\n\n <div\n role=\"progressbar\"\n aria-label={ariaLabel}\n aria-valuemin={0}\n aria-valuemax={safeMax}\n aria-valuenow={Math.round(clampedValue)}\n aria-valuetext={`${roundedPercentage}%`}\n className={`relative overflow-hidden rounded-full border border-white/12 bg-background-tertiary/80 shadow-[inset_0_1px_1px_rgba(255,255,255,0.2)] dark:border-white/6 ${sizeStyles[size].track} ${trackClassName}`}\n style={{ background: toneStyle.trackBackground }}\n >\n <div\n className={`h-full rounded-full transition-[width,filter,box-shadow] duration-500 ease-out ${fillClassName}`}\n style={{\n width: `${percentage}%`,\n background: `linear-gradient(90deg, color-mix(in srgb, ${toneStyle.color} 68%, white 32%) 0%, ${toneStyle.color} 100%)`,\n boxShadow: `inset 0 1px 0 rgba(255,255,255,0.4), 0 0 14px color-mix(in srgb, ${toneStyle.color} 32%, transparent)`,\n filter: percentage > 0 ? \"saturate(1.05) brightness(1.02)\" : \"none\",\n }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAwBA,IAAM,aAOF;CACF,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACF;AAED,IAAM,aAMF;CACF,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,QAAQ;EACN,OAAO;EACP,iBACE;EACH;CACD,MAAM;EACJ,OAAO;EACP,iBACE;EACH;CACF;AAED,SAAS,WAAW,OAAe,KAAqB;AACtD,KAAI,CAAC,OAAO,SAAS,MAAM,CACzB,QAAO;AAGT,QAAO,KAAK,IAAI,KAAK,IAAI,OAAO,EAAE,EAAE,IAAI;;AAG1C,SAAwB,YAAY,EAClC,OACA,MAAM,KACN,OACA,iBACA,iBAAiB,MACjB,OAAO,MACP,OAAO,WACP,YAAY,IACZ,iBAAiB,IACjB,gBAAgB,IAChB,YAAY,cACO;CACnB,MAAM,UAAU,OAAO,SAAS,IAAI,IAAI,MAAM,IAAI,MAAM;CACxD,MAAM,eAAe,WAAW,OAAO,QAAQ;CAC/C,MAAM,aAAc,eAAe,UAAW;CAC9C,MAAM,oBAAoB,KAAK,MAAM,WAAW;CAChD,MAAM,YAAY,WAAW;CAC7B,MAAM,0BAA0B,mBAAmB,GAAG,kBAAkB;AAExE,QACE,qBAAC,OAAD;EAAK,WAAW,oBAAoB;YAApC,EACI,SAAS,mBACT,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IACE,WAAW,6DAA6D,WAAW,MAAM;cAExF;IACG,CAAA,EACL,kBACC,oBAAC,OAAD;IACE,WAAW,iEAAiE,WAAW,MAAM;cAE5F;IACG,CAAA,CAEJ;MAGR,oBAAC,OAAD;GACE,MAAK;GACL,cAAY;GACZ,iBAAe;GACf,iBAAe;GACf,iBAAe,KAAK,MAAM,aAAa;GACvC,kBAAgB,GAAG,kBAAkB;GACrC,WAAW,6JAA6J,WAAW,MAAM,MAAM,GAAG;GAClM,OAAO,EAAE,YAAY,UAAU,iBAAiB;aAEhD,oBAAC,OAAD;IACE,WAAW,kFAAkF;IAC7F,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,YAAY,6CAA6C,UAAU,MAAM,uBAAuB,UAAU,MAAM;KAChH,WAAW,oEAAoE,UAAU,MAAM;KAC/F,QAAQ,aAAa,IAAI,oCAAoC;KAC9D;IACD,CAAA;GACE,CAAA,CACF"}
@@ -93,4 +93,4 @@ Object.defineProperty(exports, "ProgressBar", {
93
93
  }
94
94
  });
95
95
 
96
- //# sourceMappingURL=progress-bar-C1OvQ-NI.cjs.map
96
+ //# sourceMappingURL=progress-bar-BdvQtpm3.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress-bar-C1OvQ-NI.cjs","names":[],"sources":["../../src/components/data-display/progress-bar/ProgressBar.tsx"],"sourcesContent":["import React from \"react\";\n\nexport type ProgressBarSize = \"sm\" | \"md\" | \"lg\";\nexport type ProgressBarTone =\n | \"default\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"info\";\n\nexport interface ProgressBarProps {\n value: number;\n max?: number;\n label?: React.ReactNode;\n percentageLabel?: React.ReactNode;\n showPercentage?: boolean;\n size?: ProgressBarSize;\n tone?: ProgressBarTone;\n className?: string;\n trackClassName?: string;\n fillClassName?: string;\n ariaLabel?: string;\n}\n\nconst sizeStyles: Record<\n ProgressBarSize,\n {\n track: string;\n label: string;\n percentage: string;\n }\n> = {\n sm: {\n track: \"h-1.5\",\n label: \"text-xs\",\n percentage: \"text-xs\",\n },\n md: {\n track: \"h-2.5\",\n label: \"text-sm\",\n percentage: \"text-sm\",\n },\n lg: {\n track: \"h-3.5\",\n label: \"text-base\",\n percentage: \"text-base\",\n },\n};\n\nconst toneStyles: Record<\n ProgressBarTone,\n {\n color: string;\n trackBackground: string;\n }\n> = {\n default: {\n color: \"var(--ds-chart-1)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(15, 23, 42, 0.08) 0%, rgba(30, 41, 59, 0.14) 100%)\",\n },\n success: {\n color: \"var(--ds-chart-3)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(20, 83, 45, 0.12) 0%, rgba(34, 197, 94, 0.18) 100%)\",\n },\n warning: {\n color: \"var(--ds-chart-4)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(120, 53, 15, 0.12) 0%, rgba(245, 158, 11, 0.18) 100%)\",\n },\n danger: {\n color: \"var(--ds-chart-5)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(127, 29, 29, 0.12) 0%, rgba(239, 68, 68, 0.18) 100%)\",\n },\n info: {\n color: \"var(--ds-chart-2)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(30, 64, 175, 0.12) 0%, rgba(59, 130, 246, 0.18) 100%)\",\n },\n};\n\nfunction clampValue(value: number, max: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n\n return Math.min(Math.max(value, 0), max);\n}\n\nexport default function ProgressBar({\n value,\n max = 100,\n label,\n percentageLabel,\n showPercentage = true,\n size = \"md\",\n tone = \"default\",\n className = \"\",\n trackClassName = \"\",\n fillClassName = \"\",\n ariaLabel = \"Progress\",\n}: ProgressBarProps) {\n const safeMax = Number.isFinite(max) && max > 0 ? max : 100;\n const clampedValue = clampValue(value, safeMax);\n const percentage = (clampedValue / safeMax) * 100;\n const roundedPercentage = Math.round(percentage);\n const toneStyle = toneStyles[tone];\n const resolvedPercentageLabel = percentageLabel ?? `${roundedPercentage}%`;\n\n return (\n <div className={`w-full space-y-3 ${className}`}>\n {(label || showPercentage) && (\n <div className=\"flex items-center justify-between gap-4\">\n <div\n className={`font-mono font-semibold tracking-[0.08em] text-foreground ${sizeStyles[size].label}`}\n >\n {label}\n </div>\n {showPercentage && (\n <div\n className={`font-mono font-medium tracking-[0.08em] text-muted-foreground ${sizeStyles[size].percentage}`}\n >\n {resolvedPercentageLabel}\n </div>\n )}\n </div>\n )}\n\n <div\n role=\"progressbar\"\n aria-label={ariaLabel}\n aria-valuemin={0}\n aria-valuemax={safeMax}\n aria-valuenow={Math.round(clampedValue)}\n aria-valuetext={`${roundedPercentage}%`}\n className={`relative overflow-hidden rounded-full border border-white/12 bg-background-tertiary/80 shadow-[inset_0_1px_1px_rgba(255,255,255,0.2)] dark:border-white/6 ${sizeStyles[size].track} ${trackClassName}`}\n style={{ background: toneStyle.trackBackground }}\n >\n <div\n className={`h-full rounded-full transition-[width,filter,box-shadow] duration-500 ease-out ${fillClassName}`}\n style={{\n width: `${percentage}%`,\n background: `linear-gradient(90deg, color-mix(in srgb, ${toneStyle.color} 68%, white 32%) 0%, ${toneStyle.color} 100%)`,\n boxShadow: `inset 0 1px 0 rgba(255,255,255,0.4), 0 0 14px color-mix(in srgb, ${toneStyle.color} 32%, transparent)`,\n filter: percentage > 0 ? \"saturate(1.05) brightness(1.02)\" : \"none\",\n }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAwBA,IAAM,aAOF;CACF,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACF;AAED,IAAM,aAMF;CACF,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,QAAQ;EACN,OAAO;EACP,iBACE;EACH;CACD,MAAM;EACJ,OAAO;EACP,iBACE;EACH;CACF;AAED,SAAS,WAAW,OAAe,KAAqB;AACtD,KAAI,CAAC,OAAO,SAAS,MAAM,CACzB,QAAO;AAGT,QAAO,KAAK,IAAI,KAAK,IAAI,OAAO,EAAE,EAAE,IAAI;;AAG1C,SAAwB,YAAY,EAClC,OACA,MAAM,KACN,OACA,iBACA,iBAAiB,MACjB,OAAO,MACP,OAAO,WACP,YAAY,IACZ,iBAAiB,IACjB,gBAAgB,IAChB,YAAY,cACO;CACnB,MAAM,UAAU,OAAO,SAAS,IAAI,IAAI,MAAM,IAAI,MAAM;CACxD,MAAM,eAAe,WAAW,OAAO,QAAQ;CAC/C,MAAM,aAAc,eAAe,UAAW;CAC9C,MAAM,oBAAoB,KAAK,MAAM,WAAW;CAChD,MAAM,YAAY,WAAW;CAC7B,MAAM,0BAA0B,mBAAmB,GAAG,kBAAkB;AAExE,QACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EAAK,WAAW,oBAAoB;YAApC,EACI,SAAS,mBACT,iBAAA,GAAA,kBAAA,MAAC,OAAD;GAAK,WAAU;aAAf,CACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,WAAW,6DAA6D,WAAW,MAAM;cAExF;IACG,CAAA,EACL,kBACC,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,WAAW,iEAAiE,WAAW,MAAM;cAE5F;IACG,CAAA,CAEJ;MAGR,iBAAA,GAAA,kBAAA,KAAC,OAAD;GACE,MAAK;GACL,cAAY;GACZ,iBAAe;GACf,iBAAe;GACf,iBAAe,KAAK,MAAM,aAAa;GACvC,kBAAgB,GAAG,kBAAkB;GACrC,WAAW,6JAA6J,WAAW,MAAM,MAAM,GAAG;GAClM,OAAO,EAAE,YAAY,UAAU,iBAAiB;aAEhD,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,WAAW,kFAAkF;IAC7F,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,YAAY,6CAA6C,UAAU,MAAM,uBAAuB,UAAU,MAAM;KAChH,WAAW,oEAAoE,UAAU,MAAM;KAC/F,QAAQ,aAAa,IAAI,oCAAoC;KAC9D;IACD,CAAA;GACE,CAAA,CACF"}
1
+ {"version":3,"file":"progress-bar-BdvQtpm3.cjs","names":[],"sources":["../../src/components/data-display/progress-bar/ProgressBar.tsx"],"sourcesContent":["import React from \"react\";\n\nexport type ProgressBarSize = \"sm\" | \"md\" | \"lg\";\nexport type ProgressBarTone =\n | \"default\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"info\";\n\nexport interface ProgressBarProps {\n value: number;\n max?: number;\n label?: React.ReactNode;\n percentageLabel?: React.ReactNode;\n showPercentage?: boolean;\n size?: ProgressBarSize;\n tone?: ProgressBarTone;\n className?: string;\n trackClassName?: string;\n fillClassName?: string;\n ariaLabel?: string;\n}\n\nconst sizeStyles: Record<\n ProgressBarSize,\n {\n track: string;\n label: string;\n percentage: string;\n }\n> = {\n sm: {\n track: \"h-1.5\",\n label: \"text-xs\",\n percentage: \"text-xs\",\n },\n md: {\n track: \"h-2.5\",\n label: \"text-sm\",\n percentage: \"text-sm\",\n },\n lg: {\n track: \"h-3.5\",\n label: \"text-base\",\n percentage: \"text-base\",\n },\n};\n\nconst toneStyles: Record<\n ProgressBarTone,\n {\n color: string;\n trackBackground: string;\n }\n> = {\n default: {\n color: \"var(--ds-chart-1)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(15, 23, 42, 0.08) 0%, rgba(30, 41, 59, 0.14) 100%)\",\n },\n success: {\n color: \"var(--ds-chart-3)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(20, 83, 45, 0.12) 0%, rgba(34, 197, 94, 0.18) 100%)\",\n },\n warning: {\n color: \"var(--ds-chart-4)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(120, 53, 15, 0.12) 0%, rgba(245, 158, 11, 0.18) 100%)\",\n },\n danger: {\n color: \"var(--ds-chart-5)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(127, 29, 29, 0.12) 0%, rgba(239, 68, 68, 0.18) 100%)\",\n },\n info: {\n color: \"var(--ds-chart-2)\",\n trackBackground:\n \"linear-gradient(90deg, rgba(30, 64, 175, 0.12) 0%, rgba(59, 130, 246, 0.18) 100%)\",\n },\n};\n\nfunction clampValue(value: number, max: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n\n return Math.min(Math.max(value, 0), max);\n}\n\nexport default function ProgressBar({\n value,\n max = 100,\n label,\n percentageLabel,\n showPercentage = true,\n size = \"md\",\n tone = \"default\",\n className = \"\",\n trackClassName = \"\",\n fillClassName = \"\",\n ariaLabel = \"Progress\",\n}: ProgressBarProps) {\n const safeMax = Number.isFinite(max) && max > 0 ? max : 100;\n const clampedValue = clampValue(value, safeMax);\n const percentage = (clampedValue / safeMax) * 100;\n const roundedPercentage = Math.round(percentage);\n const toneStyle = toneStyles[tone];\n const resolvedPercentageLabel = percentageLabel ?? `${roundedPercentage}%`;\n\n return (\n <div className={`w-full space-y-3 ${className}`}>\n {(label || showPercentage) && (\n <div className=\"flex items-center justify-between gap-4\">\n <div\n className={`font-mono font-semibold tracking-[0.08em] text-foreground ${sizeStyles[size].label}`}\n >\n {label}\n </div>\n {showPercentage && (\n <div\n className={`font-mono font-medium tracking-[0.08em] text-muted-foreground ${sizeStyles[size].percentage}`}\n >\n {resolvedPercentageLabel}\n </div>\n )}\n </div>\n )}\n\n <div\n role=\"progressbar\"\n aria-label={ariaLabel}\n aria-valuemin={0}\n aria-valuemax={safeMax}\n aria-valuenow={Math.round(clampedValue)}\n aria-valuetext={`${roundedPercentage}%`}\n className={`relative overflow-hidden rounded-full border border-white/12 bg-background-tertiary/80 shadow-[inset_0_1px_1px_rgba(255,255,255,0.2)] dark:border-white/6 ${sizeStyles[size].track} ${trackClassName}`}\n style={{ background: toneStyle.trackBackground }}\n >\n <div\n className={`h-full rounded-full transition-[width,filter,box-shadow] duration-500 ease-out ${fillClassName}`}\n style={{\n width: `${percentage}%`,\n background: `linear-gradient(90deg, color-mix(in srgb, ${toneStyle.color} 68%, white 32%) 0%, ${toneStyle.color} 100%)`,\n boxShadow: `inset 0 1px 0 rgba(255,255,255,0.4), 0 0 14px color-mix(in srgb, ${toneStyle.color} 32%, transparent)`,\n filter: percentage > 0 ? \"saturate(1.05) brightness(1.02)\" : \"none\",\n }}\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAwBA,IAAM,aAOF;CACF,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACD,IAAI;EACF,OAAO;EACP,OAAO;EACP,YAAY;EACb;CACF;AAED,IAAM,aAMF;CACF,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,SAAS;EACP,OAAO;EACP,iBACE;EACH;CACD,QAAQ;EACN,OAAO;EACP,iBACE;EACH;CACD,MAAM;EACJ,OAAO;EACP,iBACE;EACH;CACF;AAED,SAAS,WAAW,OAAe,KAAqB;AACtD,KAAI,CAAC,OAAO,SAAS,MAAM,CACzB,QAAO;AAGT,QAAO,KAAK,IAAI,KAAK,IAAI,OAAO,EAAE,EAAE,IAAI;;AAG1C,SAAwB,YAAY,EAClC,OACA,MAAM,KACN,OACA,iBACA,iBAAiB,MACjB,OAAO,MACP,OAAO,WACP,YAAY,IACZ,iBAAiB,IACjB,gBAAgB,IAChB,YAAY,cACO;CACnB,MAAM,UAAU,OAAO,SAAS,IAAI,IAAI,MAAM,IAAI,MAAM;CACxD,MAAM,eAAe,WAAW,OAAO,QAAQ;CAC/C,MAAM,aAAc,eAAe,UAAW;CAC9C,MAAM,oBAAoB,KAAK,MAAM,WAAW;CAChD,MAAM,YAAY,WAAW;CAC7B,MAAM,0BAA0B,mBAAmB,GAAG,kBAAkB;AAExE,QACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EAAK,WAAW,oBAAoB;YAApC,EACI,SAAS,mBACT,iBAAA,GAAA,kBAAA,MAAC,OAAD;GAAK,WAAU;aAAf,CACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,WAAW,6DAA6D,WAAW,MAAM;cAExF;IACG,CAAA,EACL,kBACC,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,WAAW,iEAAiE,WAAW,MAAM;cAE5F;IACG,CAAA,CAEJ;MAGR,iBAAA,GAAA,kBAAA,KAAC,OAAD;GACE,MAAK;GACL,cAAY;GACZ,iBAAe;GACf,iBAAe;GACf,iBAAe,KAAK,MAAM,aAAa;GACvC,kBAAgB,GAAG,kBAAkB;GACrC,WAAW,6JAA6J,WAAW,MAAM,MAAM,GAAG;GAClM,OAAO,EAAE,YAAY,UAAU,iBAAiB;aAEhD,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,WAAW,kFAAkF;IAC7F,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,YAAY,6CAA6C,UAAU,MAAM,uBAAuB,UAAU,MAAM;KAChH,WAAW,oEAAoE,UAAU,MAAM;KAC/F,QAAQ,aAAa,IAAI,oCAAoC;KAC9D;IACD,CAAA;GACE,CAAA,CACF"}
@@ -0,0 +1,170 @@
1
+ import { n as mergeClassNames } from "./utils-ati1KkDb.mjs";
2
+ import { J as CheckIcon, N as ChevronDownIcon } from "./icons-DuumN7z-.mjs";
3
+ import { forwardRef, useEffect, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { motion, useMotionTemplate, useMotionValue } from "framer-motion";
6
+ //#region src/components/forms/select/Select.tsx
7
+ var Select = forwardRef(function SelectComponent({ className = "", containerClassName = "", triggerClassName = "", dropdownClassName = "", optionClassName = "", label, error, helperText, options, value, onChange, placeholder = "Select...", disabled, bgClassName = "bg-background-secondary", size = "default", selectionIndicator = "check", ...props }, ref) {
8
+ const [open, setOpen] = useState(false);
9
+ const [visible, setVisible] = useState(false);
10
+ const containerRef = useRef(null);
11
+ const hiddenSelectRef = useRef(null);
12
+ const selectedOptionRef = useRef(null);
13
+ const mouseX = useMotionValue(0);
14
+ const mouseY = useMotionValue(0);
15
+ const radius = 100;
16
+ const isCompact = size === "compact";
17
+ const selectedOption = options.find((option) => option.value === value);
18
+ useEffect(() => {
19
+ if (typeof ref === "function") {
20
+ ref(hiddenSelectRef.current);
21
+ return;
22
+ }
23
+ if (ref) ref.current = hiddenSelectRef.current;
24
+ }, [ref]);
25
+ useEffect(() => {
26
+ const handleClick = (event) => {
27
+ if (containerRef.current && !containerRef.current.contains(event.target)) setOpen(false);
28
+ };
29
+ if (open) document.addEventListener("mousedown", handleClick);
30
+ return () => {
31
+ document.removeEventListener("mousedown", handleClick);
32
+ };
33
+ }, [open]);
34
+ useEffect(() => {
35
+ if (!open || !selectedOptionRef.current) return;
36
+ const frameId = window.requestAnimationFrame(() => {
37
+ selectedOptionRef.current?.scrollIntoView({ block: "nearest" });
38
+ });
39
+ return () => {
40
+ window.cancelAnimationFrame(frameId);
41
+ };
42
+ }, [open, value]);
43
+ const handleMouseMove = (event) => {
44
+ const { left, top } = event.currentTarget.getBoundingClientRect();
45
+ mouseX.set(event.clientX - left);
46
+ mouseY.set(event.clientY - top);
47
+ };
48
+ const handleSelect = (optionValue) => {
49
+ if (onChange && hiddenSelectRef.current) onChange({
50
+ target: {
51
+ value: optionValue,
52
+ name: props.name
53
+ },
54
+ currentTarget: {
55
+ value: optionValue,
56
+ name: props.name
57
+ }
58
+ });
59
+ setOpen(false);
60
+ };
61
+ const handleKeyDown = (event) => {
62
+ if (disabled) return;
63
+ if (event.key === "Enter" || event.key === " ") {
64
+ event.preventDefault();
65
+ setOpen((current) => !current);
66
+ }
67
+ if (event.key === "Escape") setOpen(false);
68
+ };
69
+ return /* @__PURE__ */ jsxs("div", {
70
+ className: mergeClassNames("w-full", isCompact ? "min-w-0" : "min-w-48", containerClassName),
71
+ children: [
72
+ label ? /* @__PURE__ */ jsx("label", {
73
+ className: "mb-2 block text-sm leading-none font-medium text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
74
+ children: label
75
+ }) : null,
76
+ /* @__PURE__ */ jsxs("select", {
77
+ ref: hiddenSelectRef,
78
+ className: "sr-only",
79
+ value,
80
+ onChange,
81
+ disabled,
82
+ ...props,
83
+ children: [/* @__PURE__ */ jsx("option", {
84
+ value: "",
85
+ children: placeholder
86
+ }), options.map((option) => /* @__PURE__ */ jsx("option", {
87
+ value: option.value,
88
+ children: option.label
89
+ }, option.value))]
90
+ }),
91
+ /* @__PURE__ */ jsxs("div", {
92
+ ref: containerRef,
93
+ className: mergeClassNames("relative w-full", className),
94
+ children: [/* @__PURE__ */ jsx(motion.div, {
95
+ style: { backgroundImage: disabled ? "none" : useMotionTemplate`
96
+ radial-gradient(
97
+ ${visible ? `${radius}px` : "0px"} circle at ${mouseX}px ${mouseY}px,
98
+ var(--ds-color-accent),
99
+ transparent 90%
100
+ )
101
+ ` },
102
+ onMouseMove: !disabled ? handleMouseMove : void 0,
103
+ onMouseEnter: !disabled ? () => setVisible(true) : void 0,
104
+ onMouseLeave: !disabled ? () => setVisible(false) : void 0,
105
+ className: mergeClassNames("group/select rounded-lg p-[2px] transition duration-300 hover:border-accent", disabled ? "border-none bg-muted" : error ? "border-destructive" : "border-border"),
106
+ children: /* @__PURE__ */ jsxs("div", {
107
+ className: mergeClassNames("flex w-full cursor-pointer items-center justify-between rounded-md border border-input transition duration-400 ease-in-out", isCompact ? "h-9 px-2.5 py-2 text-sm" : "h-10 px-3 py-2 text-sm", bgClassName, disabled ? "cursor-not-allowed opacity-50" : "text-foreground", error ? "border-destructive text-destructive focus-visible:ring-destructive" : "", triggerClassName),
108
+ onClick: () => {
109
+ if (!disabled) setOpen((current) => !current);
110
+ },
111
+ onKeyDown: handleKeyDown,
112
+ role: "button",
113
+ tabIndex: disabled ? -1 : 0,
114
+ "aria-haspopup": "listbox",
115
+ "aria-expanded": open,
116
+ children: [selectedOption ? /* @__PURE__ */ jsx("span", {
117
+ className: "min-w-0 flex-1 truncate text-foreground",
118
+ children: selectedOption.label
119
+ }) : /* @__PURE__ */ jsx("span", {
120
+ className: "min-w-0 flex-1 truncate text-muted-foreground",
121
+ children: placeholder
122
+ }), /* @__PURE__ */ jsx("span", {
123
+ className: mergeClassNames("ml-2 shrink-0 text-muted-foreground transition-transform duration-300", open ? "rotate-180" : "rotate-0"),
124
+ children: /* @__PURE__ */ jsx(ChevronDownIcon, {
125
+ width: 24,
126
+ height: 24,
127
+ color: "currentColor",
128
+ className: isCompact ? "h-4 w-4" : "h-5 w-5"
129
+ })
130
+ })]
131
+ })
132
+ }), open && !disabled ? /* @__PURE__ */ jsxs("div", {
133
+ className: mergeClassNames("absolute right-0 left-0 z-20 mt-1 flex flex-col overflow-auto rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition", isCompact ? "max-h-56" : "max-h-60", dropdownClassName),
134
+ children: [options.length === 0 ? /* @__PURE__ */ jsx("div", {
135
+ className: "px-3 py-2 text-muted-foreground",
136
+ children: "No options"
137
+ }) : null, options.map((option) => /* @__PURE__ */ jsxs("div", {
138
+ ref: option.value === value ? selectedOptionRef : null,
139
+ className: mergeClassNames("mx-1 my-1 flex cursor-pointer items-center rounded-md text-foreground transition", isCompact ? "gap-1.5 px-2.5 py-2 text-sm" : "gap-2 px-3 py-2 text-sm", option.value === value ? "bg-accent-subtle font-semibold text-accent" : "", "hover:bg-accent hover:text-on-accent", optionClassName),
140
+ onClick: () => handleSelect(option.value),
141
+ children: [selectionIndicator === "check" ? /* @__PURE__ */ jsx("span", {
142
+ className: mergeClassNames("flex items-center justify-center", isCompact ? "w-4" : "w-5"),
143
+ children: option.value === value ? /* @__PURE__ */ jsx(CheckIcon, {
144
+ className: "text-accent",
145
+ width: isCompact ? 16 : 18,
146
+ height: isCompact ? 16 : 18
147
+ }) : null
148
+ }) : null, /* @__PURE__ */ jsx("span", {
149
+ className: "min-w-0 flex-1 truncate",
150
+ children: option.label
151
+ })]
152
+ }, option.value))]
153
+ }) : null]
154
+ }),
155
+ error ? /* @__PURE__ */ jsx("p", {
156
+ className: "mt-1 text-sm font-medium text-destructive",
157
+ children: error
158
+ }) : null,
159
+ helperText && !error ? /* @__PURE__ */ jsx("p", {
160
+ className: "mt-1 text-sm text-muted-foreground",
161
+ children: helperText
162
+ }) : null
163
+ ]
164
+ });
165
+ });
166
+ Select.displayName = "Select";
167
+ //#endregion
168
+ export { Select as t };
169
+
170
+ //# sourceMappingURL=select-B8UQ6Uq5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-B8UQ6Uq5.mjs","names":[],"sources":["../../src/components/forms/select/Select.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type ForwardedRef,\n type KeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { CheckIcon, ChevronDownIcon } from \"../../icons\";\nimport { mergeClassNames } from \"../../../utils\";\nimport type { SelectProps } from \"./types\";\n\nexport const Select = forwardRef(function SelectComponent(\n {\n className = \"\",\n containerClassName = \"\",\n triggerClassName = \"\",\n dropdownClassName = \"\",\n optionClassName = \"\",\n label,\n error,\n helperText,\n options,\n value,\n onChange,\n placeholder = \"Select...\",\n disabled,\n bgClassName = \"bg-background-secondary\",\n size = \"default\",\n selectionIndicator = \"check\",\n ...props\n }: SelectProps,\n ref: ForwardedRef<HTMLSelectElement>,\n) {\n const [open, setOpen] = useState(false);\n const [visible, setVisible] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const hiddenSelectRef = useRef<HTMLSelectElement>(null);\n const selectedOptionRef = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n const isCompact = size === \"compact\";\n const selectedOption = options.find((option) => option.value === value);\n\n useEffect(() => {\n if (typeof ref === \"function\") {\n ref(hiddenSelectRef.current);\n return;\n }\n\n if (ref) {\n ref.current = hiddenSelectRef.current;\n }\n }, [ref]);\n\n useEffect(() => {\n const handleClick = (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\", handleClick);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClick);\n };\n }, [open]);\n\n useEffect(() => {\n if (!open || !selectedOptionRef.current) {\n return;\n }\n\n const frameId = window.requestAnimationFrame(() => {\n selectedOptionRef.current?.scrollIntoView({ block: \"nearest\" });\n });\n\n return () => {\n window.cancelAnimationFrame(frameId);\n };\n }, [open, value]);\n\n const handleMouseMove = (event: ReactMouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const handleSelect = (optionValue: string) => {\n if (onChange && hiddenSelectRef.current) {\n const syntheticEvent = {\n target: { value: optionValue, name: props.name },\n currentTarget: { value: optionValue, name: props.name },\n } as ChangeEvent<HTMLSelectElement>;\n\n onChange(syntheticEvent);\n }\n\n setOpen(false);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (disabled) {\n return;\n }\n\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen((current) => !current);\n }\n\n if (event.key === \"Escape\") {\n setOpen(false);\n }\n };\n\n return (\n <div\n className={mergeClassNames(\n \"w-full\",\n isCompact ? \"min-w-0\" : \"min-w-48\",\n containerClassName,\n )}\n >\n {label ? (\n <label className=\"mb-2 block text-sm leading-none font-medium text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70\">\n {label}\n </label>\n ) : null}\n\n <select\n ref={hiddenSelectRef}\n className=\"sr-only\"\n value={value}\n onChange={onChange}\n disabled={disabled}\n {...props}\n >\n <option value=\"\">{placeholder}</option>\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n\n <div\n ref={containerRef}\n className={mergeClassNames(\"relative w-full\", className)}\n >\n <motion.div\n style={{\n backgroundImage: disabled\n ? \"none\"\n : 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={!disabled ? handleMouseMove : undefined}\n onMouseEnter={!disabled ? () => setVisible(true) : undefined}\n onMouseLeave={!disabled ? () => setVisible(false) : undefined}\n className={mergeClassNames(\n \"group/select rounded-lg p-[2px] transition duration-300 hover:border-accent\",\n disabled\n ? \"border-none bg-muted\"\n : error\n ? \"border-destructive\"\n : \"border-border\",\n )}\n >\n <div\n className={mergeClassNames(\n \"flex w-full cursor-pointer items-center justify-between rounded-md border border-input transition duration-400 ease-in-out\",\n isCompact ? \"h-9 px-2.5 py-2 text-sm\" : \"h-10 px-3 py-2 text-sm\",\n bgClassName,\n disabled ? \"cursor-not-allowed opacity-50\" : \"text-foreground\",\n error\n ? \"border-destructive text-destructive focus-visible:ring-destructive\"\n : \"\",\n triggerClassName,\n )}\n onClick={() => {\n if (!disabled) {\n setOpen((current) => !current);\n }\n }}\n onKeyDown={handleKeyDown}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n >\n {selectedOption ? (\n <span className=\"min-w-0 flex-1 truncate text-foreground\">\n {selectedOption.label}\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 truncate text-muted-foreground\">\n {placeholder}\n </span>\n )}\n\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={isCompact ? \"h-4 w-4\" : \"h-5 w-5\"}\n />\n </span>\n </div>\n </motion.div>\n\n {open && !disabled ? (\n <div\n className={mergeClassNames(\n \"absolute right-0 left-0 z-20 mt-1 flex flex-col overflow-auto rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition\",\n isCompact ? \"max-h-56\" : \"max-h-60\",\n dropdownClassName,\n )}\n >\n {options.length === 0 ? (\n <div className=\"px-3 py-2 text-muted-foreground\">No options</div>\n ) : null}\n\n {options.map((option) => (\n <div\n key={option.value}\n ref={option.value === value ? selectedOptionRef : null}\n className={mergeClassNames(\n \"mx-1 my-1 flex cursor-pointer items-center rounded-md text-foreground transition\",\n isCompact\n ? \"gap-1.5 px-2.5 py-2 text-sm\"\n : \"gap-2 px-3 py-2 text-sm\",\n option.value === value\n ? \"bg-accent-subtle font-semibold text-accent\"\n : \"\",\n \"hover:bg-accent hover:text-on-accent\",\n optionClassName,\n )}\n onClick={() => handleSelect(option.value)}\n >\n {selectionIndicator === \"check\" ? (\n <span\n className={mergeClassNames(\n \"flex items-center justify-center\",\n isCompact ? \"w-4\" : \"w-5\",\n )}\n >\n {option.value === value ? (\n <CheckIcon\n className=\"text-accent\"\n width={isCompact ? 16 : 18}\n height={isCompact ? 16 : 18}\n />\n ) : null}\n </span>\n ) : null}\n\n <span className=\"min-w-0 flex-1 truncate\">{option.label}</span>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n\n {error ? (\n <p className=\"mt-1 text-sm font-medium text-destructive\">{error}</p>\n ) : null}\n {helperText && !error ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">{helperText}</p>\n ) : null}\n </div>\n );\n});\n\nSelect.displayName = \"Select\";\n"],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ require("./chunk-B_GkZjkl.cjs");
2
+ const require_utils = require("./utils-B4SmmY4J.cjs");
3
+ const require_icons = require("./icons-BxIzP2jd.cjs");
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ let framer_motion = require("framer-motion");
7
+ //#region src/components/forms/select/Select.tsx
8
+ var Select = (0, react.forwardRef)(function SelectComponent({ className = "", containerClassName = "", triggerClassName = "", dropdownClassName = "", optionClassName = "", label, error, helperText, options, value, onChange, placeholder = "Select...", disabled, bgClassName = "bg-background-secondary", size = "default", selectionIndicator = "check", ...props }, ref) {
9
+ const [open, setOpen] = (0, react.useState)(false);
10
+ const [visible, setVisible] = (0, react.useState)(false);
11
+ const containerRef = (0, react.useRef)(null);
12
+ const hiddenSelectRef = (0, react.useRef)(null);
13
+ const selectedOptionRef = (0, react.useRef)(null);
14
+ const mouseX = (0, framer_motion.useMotionValue)(0);
15
+ const mouseY = (0, framer_motion.useMotionValue)(0);
16
+ const radius = 100;
17
+ const isCompact = size === "compact";
18
+ const selectedOption = options.find((option) => option.value === value);
19
+ (0, react.useEffect)(() => {
20
+ if (typeof ref === "function") {
21
+ ref(hiddenSelectRef.current);
22
+ return;
23
+ }
24
+ if (ref) ref.current = hiddenSelectRef.current;
25
+ }, [ref]);
26
+ (0, react.useEffect)(() => {
27
+ const handleClick = (event) => {
28
+ if (containerRef.current && !containerRef.current.contains(event.target)) setOpen(false);
29
+ };
30
+ if (open) document.addEventListener("mousedown", handleClick);
31
+ return () => {
32
+ document.removeEventListener("mousedown", handleClick);
33
+ };
34
+ }, [open]);
35
+ (0, react.useEffect)(() => {
36
+ if (!open || !selectedOptionRef.current) return;
37
+ const frameId = window.requestAnimationFrame(() => {
38
+ selectedOptionRef.current?.scrollIntoView({ block: "nearest" });
39
+ });
40
+ return () => {
41
+ window.cancelAnimationFrame(frameId);
42
+ };
43
+ }, [open, value]);
44
+ const handleMouseMove = (event) => {
45
+ const { left, top } = event.currentTarget.getBoundingClientRect();
46
+ mouseX.set(event.clientX - left);
47
+ mouseY.set(event.clientY - top);
48
+ };
49
+ const handleSelect = (optionValue) => {
50
+ if (onChange && hiddenSelectRef.current) onChange({
51
+ target: {
52
+ value: optionValue,
53
+ name: props.name
54
+ },
55
+ currentTarget: {
56
+ value: optionValue,
57
+ name: props.name
58
+ }
59
+ });
60
+ setOpen(false);
61
+ };
62
+ const handleKeyDown = (event) => {
63
+ if (disabled) return;
64
+ if (event.key === "Enter" || event.key === " ") {
65
+ event.preventDefault();
66
+ setOpen((current) => !current);
67
+ }
68
+ if (event.key === "Escape") setOpen(false);
69
+ };
70
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
71
+ className: require_utils.mergeClassNames("w-full", isCompact ? "min-w-0" : "min-w-48", containerClassName),
72
+ children: [
73
+ label ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
74
+ className: "mb-2 block text-sm leading-none font-medium text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
75
+ children: label
76
+ }) : null,
77
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
78
+ ref: hiddenSelectRef,
79
+ className: "sr-only",
80
+ value,
81
+ onChange,
82
+ disabled,
83
+ ...props,
84
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
85
+ value: "",
86
+ children: placeholder
87
+ }), options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
88
+ value: option.value,
89
+ children: option.label
90
+ }, option.value))]
91
+ }),
92
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
93
+ ref: containerRef,
94
+ className: require_utils.mergeClassNames("relative w-full", className),
95
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(framer_motion.motion.div, {
96
+ style: { backgroundImage: disabled ? "none" : framer_motion.useMotionTemplate`
97
+ radial-gradient(
98
+ ${visible ? `${radius}px` : "0px"} circle at ${mouseX}px ${mouseY}px,
99
+ var(--ds-color-accent),
100
+ transparent 90%
101
+ )
102
+ ` },
103
+ onMouseMove: !disabled ? handleMouseMove : void 0,
104
+ onMouseEnter: !disabled ? () => setVisible(true) : void 0,
105
+ onMouseLeave: !disabled ? () => setVisible(false) : void 0,
106
+ className: require_utils.mergeClassNames("group/select rounded-lg p-[2px] transition duration-300 hover:border-accent", disabled ? "border-none bg-muted" : error ? "border-destructive" : "border-border"),
107
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
108
+ className: require_utils.mergeClassNames("flex w-full cursor-pointer items-center justify-between rounded-md border border-input transition duration-400 ease-in-out", isCompact ? "h-9 px-2.5 py-2 text-sm" : "h-10 px-3 py-2 text-sm", bgClassName, disabled ? "cursor-not-allowed opacity-50" : "text-foreground", error ? "border-destructive text-destructive focus-visible:ring-destructive" : "", triggerClassName),
109
+ onClick: () => {
110
+ if (!disabled) setOpen((current) => !current);
111
+ },
112
+ onKeyDown: handleKeyDown,
113
+ role: "button",
114
+ tabIndex: disabled ? -1 : 0,
115
+ "aria-haspopup": "listbox",
116
+ "aria-expanded": open,
117
+ children: [selectedOption ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
118
+ className: "min-w-0 flex-1 truncate text-foreground",
119
+ children: selectedOption.label
120
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
121
+ className: "min-w-0 flex-1 truncate text-muted-foreground",
122
+ children: placeholder
123
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
124
+ className: require_utils.mergeClassNames("ml-2 shrink-0 text-muted-foreground transition-transform duration-300", open ? "rotate-180" : "rotate-0"),
125
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons.ChevronDownIcon, {
126
+ width: 24,
127
+ height: 24,
128
+ color: "currentColor",
129
+ className: isCompact ? "h-4 w-4" : "h-5 w-5"
130
+ })
131
+ })]
132
+ })
133
+ }), open && !disabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
134
+ className: require_utils.mergeClassNames("absolute right-0 left-0 z-20 mt-1 flex flex-col overflow-auto rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition", isCompact ? "max-h-56" : "max-h-60", dropdownClassName),
135
+ children: [options.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
136
+ className: "px-3 py-2 text-muted-foreground",
137
+ children: "No options"
138
+ }) : null, options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
139
+ ref: option.value === value ? selectedOptionRef : null,
140
+ className: require_utils.mergeClassNames("mx-1 my-1 flex cursor-pointer items-center rounded-md text-foreground transition", isCompact ? "gap-1.5 px-2.5 py-2 text-sm" : "gap-2 px-3 py-2 text-sm", option.value === value ? "bg-accent-subtle font-semibold text-accent" : "", "hover:bg-accent hover:text-on-accent", optionClassName),
141
+ onClick: () => handleSelect(option.value),
142
+ children: [selectionIndicator === "check" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
143
+ className: require_utils.mergeClassNames("flex items-center justify-center", isCompact ? "w-4" : "w-5"),
144
+ children: option.value === value ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons.CheckIcon, {
145
+ className: "text-accent",
146
+ width: isCompact ? 16 : 18,
147
+ height: isCompact ? 16 : 18
148
+ }) : null
149
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
150
+ className: "min-w-0 flex-1 truncate",
151
+ children: option.label
152
+ })]
153
+ }, option.value))]
154
+ }) : null]
155
+ }),
156
+ error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
157
+ className: "mt-1 text-sm font-medium text-destructive",
158
+ children: error
159
+ }) : null,
160
+ helperText && !error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
161
+ className: "mt-1 text-sm text-muted-foreground",
162
+ children: helperText
163
+ }) : null
164
+ ]
165
+ });
166
+ });
167
+ Select.displayName = "Select";
168
+ //#endregion
169
+ Object.defineProperty(exports, "Select", {
170
+ enumerable: true,
171
+ get: function() {
172
+ return Select;
173
+ }
174
+ });
175
+
176
+ //# sourceMappingURL=select-CCUSMvfS.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-CCUSMvfS.cjs","names":[],"sources":["../../src/components/forms/select/Select.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type ForwardedRef,\n type KeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { motion, useMotionTemplate, useMotionValue } from \"framer-motion\";\n\nimport { CheckIcon, ChevronDownIcon } from \"../../icons\";\nimport { mergeClassNames } from \"../../../utils\";\nimport type { SelectProps } from \"./types\";\n\nexport const Select = forwardRef(function SelectComponent(\n {\n className = \"\",\n containerClassName = \"\",\n triggerClassName = \"\",\n dropdownClassName = \"\",\n optionClassName = \"\",\n label,\n error,\n helperText,\n options,\n value,\n onChange,\n placeholder = \"Select...\",\n disabled,\n bgClassName = \"bg-background-secondary\",\n size = \"default\",\n selectionIndicator = \"check\",\n ...props\n }: SelectProps,\n ref: ForwardedRef<HTMLSelectElement>,\n) {\n const [open, setOpen] = useState(false);\n const [visible, setVisible] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const hiddenSelectRef = useRef<HTMLSelectElement>(null);\n const selectedOptionRef = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const radius = 100;\n const isCompact = size === \"compact\";\n const selectedOption = options.find((option) => option.value === value);\n\n useEffect(() => {\n if (typeof ref === \"function\") {\n ref(hiddenSelectRef.current);\n return;\n }\n\n if (ref) {\n ref.current = hiddenSelectRef.current;\n }\n }, [ref]);\n\n useEffect(() => {\n const handleClick = (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\", handleClick);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClick);\n };\n }, [open]);\n\n useEffect(() => {\n if (!open || !selectedOptionRef.current) {\n return;\n }\n\n const frameId = window.requestAnimationFrame(() => {\n selectedOptionRef.current?.scrollIntoView({ block: \"nearest\" });\n });\n\n return () => {\n window.cancelAnimationFrame(frameId);\n };\n }, [open, value]);\n\n const handleMouseMove = (event: ReactMouseEvent<HTMLDivElement>) => {\n const { left, top } = event.currentTarget.getBoundingClientRect();\n mouseX.set(event.clientX - left);\n mouseY.set(event.clientY - top);\n };\n\n const handleSelect = (optionValue: string) => {\n if (onChange && hiddenSelectRef.current) {\n const syntheticEvent = {\n target: { value: optionValue, name: props.name },\n currentTarget: { value: optionValue, name: props.name },\n } as ChangeEvent<HTMLSelectElement>;\n\n onChange(syntheticEvent);\n }\n\n setOpen(false);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (disabled) {\n return;\n }\n\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen((current) => !current);\n }\n\n if (event.key === \"Escape\") {\n setOpen(false);\n }\n };\n\n return (\n <div\n className={mergeClassNames(\n \"w-full\",\n isCompact ? \"min-w-0\" : \"min-w-48\",\n containerClassName,\n )}\n >\n {label ? (\n <label className=\"mb-2 block text-sm leading-none font-medium text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70\">\n {label}\n </label>\n ) : null}\n\n <select\n ref={hiddenSelectRef}\n className=\"sr-only\"\n value={value}\n onChange={onChange}\n disabled={disabled}\n {...props}\n >\n <option value=\"\">{placeholder}</option>\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n\n <div\n ref={containerRef}\n className={mergeClassNames(\"relative w-full\", className)}\n >\n <motion.div\n style={{\n backgroundImage: disabled\n ? \"none\"\n : 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={!disabled ? handleMouseMove : undefined}\n onMouseEnter={!disabled ? () => setVisible(true) : undefined}\n onMouseLeave={!disabled ? () => setVisible(false) : undefined}\n className={mergeClassNames(\n \"group/select rounded-lg p-[2px] transition duration-300 hover:border-accent\",\n disabled\n ? \"border-none bg-muted\"\n : error\n ? \"border-destructive\"\n : \"border-border\",\n )}\n >\n <div\n className={mergeClassNames(\n \"flex w-full cursor-pointer items-center justify-between rounded-md border border-input transition duration-400 ease-in-out\",\n isCompact ? \"h-9 px-2.5 py-2 text-sm\" : \"h-10 px-3 py-2 text-sm\",\n bgClassName,\n disabled ? \"cursor-not-allowed opacity-50\" : \"text-foreground\",\n error\n ? \"border-destructive text-destructive focus-visible:ring-destructive\"\n : \"\",\n triggerClassName,\n )}\n onClick={() => {\n if (!disabled) {\n setOpen((current) => !current);\n }\n }}\n onKeyDown={handleKeyDown}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n >\n {selectedOption ? (\n <span className=\"min-w-0 flex-1 truncate text-foreground\">\n {selectedOption.label}\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 truncate text-muted-foreground\">\n {placeholder}\n </span>\n )}\n\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={isCompact ? \"h-4 w-4\" : \"h-5 w-5\"}\n />\n </span>\n </div>\n </motion.div>\n\n {open && !disabled ? (\n <div\n className={mergeClassNames(\n \"absolute right-0 left-0 z-20 mt-1 flex flex-col overflow-auto rounded-lg border border-border bg-background-secondary shadow-3 backdrop-blur-xl transition\",\n isCompact ? \"max-h-56\" : \"max-h-60\",\n dropdownClassName,\n )}\n >\n {options.length === 0 ? (\n <div className=\"px-3 py-2 text-muted-foreground\">No options</div>\n ) : null}\n\n {options.map((option) => (\n <div\n key={option.value}\n ref={option.value === value ? selectedOptionRef : null}\n className={mergeClassNames(\n \"mx-1 my-1 flex cursor-pointer items-center rounded-md text-foreground transition\",\n isCompact\n ? \"gap-1.5 px-2.5 py-2 text-sm\"\n : \"gap-2 px-3 py-2 text-sm\",\n option.value === value\n ? \"bg-accent-subtle font-semibold text-accent\"\n : \"\",\n \"hover:bg-accent hover:text-on-accent\",\n optionClassName,\n )}\n onClick={() => handleSelect(option.value)}\n >\n {selectionIndicator === \"check\" ? (\n <span\n className={mergeClassNames(\n \"flex items-center justify-center\",\n isCompact ? \"w-4\" : \"w-5\",\n )}\n >\n {option.value === value ? (\n <CheckIcon\n className=\"text-accent\"\n width={isCompact ? 16 : 18}\n height={isCompact ? 16 : 18}\n />\n ) : null}\n </span>\n ) : null}\n\n <span className=\"min-w-0 flex-1 truncate\">{option.label}</span>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n\n {error ? (\n <p className=\"mt-1 text-sm font-medium text-destructive\">{error}</p>\n ) : null}\n {helperText && !error ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">{helperText}</p>\n ) : null}\n </div>\n );\n});\n\nSelect.displayName = \"Select\";\n"],"mappings":"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"}