@puzzle-ui/ui 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +70 -70
  2. package/dist/components/actions/button/button.css +5 -2
  3. package/dist/components/actions/button-group/button-group.css +16 -17
  4. package/dist/components/data-display/badge/badge.css +15 -2
  5. package/dist/components/data-display/badge/index.cjs +13 -2
  6. package/dist/components/data-display/badge/index.cjs.map +1 -1
  7. package/dist/components/data-display/badge/index.d.cts +7 -2
  8. package/dist/components/data-display/badge/index.d.ts +7 -2
  9. package/dist/components/data-display/badge/index.js +13 -2
  10. package/dist/components/data-display/badge/index.js.map +1 -1
  11. package/dist/components/data-display/empty-state/empty-state.css +128 -0
  12. package/dist/components/data-display/empty-state/empty-state.utils.cjs +6 -0
  13. package/dist/components/data-display/empty-state/empty-state.utils.cjs.map +1 -0
  14. package/dist/components/data-display/empty-state/empty-state.utils.js +6 -0
  15. package/dist/components/data-display/empty-state/empty-state.utils.js.map +1 -0
  16. package/dist/components/data-display/empty-state/index.cjs +49 -0
  17. package/dist/components/data-display/empty-state/index.cjs.map +1 -0
  18. package/dist/components/data-display/empty-state/index.d.cts +19 -0
  19. package/dist/components/data-display/empty-state/index.d.ts +19 -0
  20. package/dist/components/data-display/empty-state/index.js +44 -0
  21. package/dist/components/data-display/empty-state/index.js.map +1 -0
  22. package/dist/components/data-display/rating/index.cjs +84 -0
  23. package/dist/components/data-display/rating/index.cjs.map +1 -0
  24. package/dist/components/data-display/rating/index.d.cts +3 -0
  25. package/dist/components/data-display/rating/index.d.ts +3 -0
  26. package/dist/components/data-display/rating/index.js +84 -0
  27. package/dist/components/data-display/rating/index.js.map +1 -0
  28. package/dist/components/data-display/rating/rating.css +72 -0
  29. package/dist/components/data-display/rating/rating.types.d.cts +15 -0
  30. package/dist/components/data-display/rating/rating.types.d.ts +15 -0
  31. package/dist/components/data-display/rating/rating.utils.cjs +27 -0
  32. package/dist/components/data-display/rating/rating.utils.cjs.map +1 -0
  33. package/dist/components/data-display/rating/rating.utils.js +25 -0
  34. package/dist/components/data-display/rating/rating.utils.js.map +1 -0
  35. package/dist/components/editors/text-editor/editor.cjs.map +1 -1
  36. package/dist/components/editors/text-editor/editor.js.map +1 -1
  37. package/dist/components/editors/text-editor/text-document.cjs.map +1 -1
  38. package/dist/components/editors/text-editor/text-document.js.map +1 -1
  39. package/dist/components/editors/text-editor/text-parser.cjs.map +1 -1
  40. package/dist/components/editors/text-editor/text-parser.js.map +1 -1
  41. package/dist/components/editors/text-editor/text-renderer.cjs.map +1 -1
  42. package/dist/components/editors/text-editor/text-renderer.js.map +1 -1
  43. package/dist/components/forms/autocomplete/index.cjs.map +1 -1
  44. package/dist/components/forms/autocomplete/index.js.map +1 -1
  45. package/dist/components/forms/checkbox/checkbox.css +2 -10
  46. package/dist/components/forms/color-picker/color-picker.css +351 -0
  47. package/dist/components/forms/color-picker/color-picker.types.d.cts +25 -0
  48. package/dist/components/forms/color-picker/color-picker.types.d.ts +25 -0
  49. package/dist/components/forms/color-picker/color-picker.utils.cjs +116 -0
  50. package/dist/components/forms/color-picker/color-picker.utils.cjs.map +1 -0
  51. package/dist/components/forms/color-picker/color-picker.utils.js +109 -0
  52. package/dist/components/forms/color-picker/color-picker.utils.js.map +1 -0
  53. package/dist/components/forms/color-picker/index.cjs +340 -0
  54. package/dist/components/forms/color-picker/index.cjs.map +1 -0
  55. package/dist/components/forms/color-picker/index.d.cts +3 -0
  56. package/dist/components/forms/color-picker/index.d.ts +3 -0
  57. package/dist/components/forms/color-picker/index.js +340 -0
  58. package/dist/components/forms/color-picker/index.js.map +1 -0
  59. package/dist/components/forms/file-upload/file-upload.utils.cjs.map +1 -1
  60. package/dist/components/forms/file-upload/file-upload.utils.js.map +1 -1
  61. package/dist/components/forms/input/number-input.js +5 -5
  62. package/dist/components/forms/input/number-input.js.map +1 -1
  63. package/dist/components/forms/input-group/index.d.cts +3 -0
  64. package/dist/components/forms/input-group/index.d.ts +3 -0
  65. package/dist/components/forms/input-group/input-group.cjs +18 -0
  66. package/dist/components/forms/input-group/input-group.cjs.map +1 -0
  67. package/dist/components/forms/input-group/input-group.css +62 -0
  68. package/dist/components/forms/input-group/input-group.d.cts +7 -0
  69. package/dist/components/forms/input-group/input-group.d.ts +7 -0
  70. package/dist/components/forms/input-group/input-group.js +18 -0
  71. package/dist/components/forms/input-group/input-group.js.map +1 -0
  72. package/dist/components/forms/input-group/input-group.types.d.cts +7 -0
  73. package/dist/components/forms/input-group/input-group.types.d.ts +7 -0
  74. package/dist/components/forms/input-group/input-group.utils.cjs +5 -0
  75. package/dist/components/forms/input-group/input-group.utils.cjs.map +1 -0
  76. package/dist/components/forms/input-group/input-group.utils.js +5 -0
  77. package/dist/components/forms/input-group/input-group.utils.js.map +1 -0
  78. package/dist/components/forms/radio-group/index.d.cts +2 -1
  79. package/dist/components/forms/radio-group/index.d.ts +2 -1
  80. package/dist/components/forms/select/index.cjs.map +1 -1
  81. package/dist/components/forms/select/index.js.map +1 -1
  82. package/dist/components/forms/slider/index.cjs +1 -1
  83. package/dist/components/forms/slider/index.cjs.map +1 -1
  84. package/dist/components/forms/slider/index.js +1 -1
  85. package/dist/components/forms/slider/index.js.map +1 -1
  86. package/dist/components/forms/stepper/index.d.cts +4 -2
  87. package/dist/components/forms/stepper/index.d.ts +4 -2
  88. package/dist/components/forms/time-picker/index.cjs +108 -0
  89. package/dist/components/forms/time-picker/index.cjs.map +1 -0
  90. package/dist/components/forms/time-picker/index.d.cts +3 -0
  91. package/dist/components/forms/time-picker/index.d.ts +3 -0
  92. package/dist/components/forms/time-picker/index.js +108 -0
  93. package/dist/components/forms/time-picker/index.js.map +1 -0
  94. package/dist/components/forms/time-picker/time-picker.css +166 -0
  95. package/dist/components/forms/time-picker/time-picker.types.d.cts +34 -0
  96. package/dist/components/forms/time-picker/time-picker.types.d.ts +34 -0
  97. package/dist/components/forms/time-picker/time-picker.utils.cjs +25 -0
  98. package/dist/components/forms/time-picker/time-picker.utils.cjs.map +1 -0
  99. package/dist/components/forms/time-picker/time-picker.utils.js +24 -0
  100. package/dist/components/forms/time-picker/time-picker.utils.js.map +1 -0
  101. package/dist/components/forms/token-input/index.cjs +189 -0
  102. package/dist/components/forms/token-input/index.cjs.map +1 -0
  103. package/dist/components/forms/token-input/index.d.cts +3 -0
  104. package/dist/components/forms/token-input/index.d.ts +3 -0
  105. package/dist/components/forms/token-input/index.js +189 -0
  106. package/dist/components/forms/token-input/index.js.map +1 -0
  107. package/dist/components/forms/token-input/token-input.css +145 -0
  108. package/dist/components/forms/token-input/token-input.types.d.cts +48 -0
  109. package/dist/components/forms/token-input/token-input.types.d.ts +48 -0
  110. package/dist/components/forms/token-input/token-input.utils.cjs +30 -0
  111. package/dist/components/forms/token-input/token-input.utils.cjs.map +1 -0
  112. package/dist/components/forms/token-input/token-input.utils.js +24 -0
  113. package/dist/components/forms/token-input/token-input.utils.js.map +1 -0
  114. package/dist/components/layout/aspect-ratio/aspect-ratio.css +14 -0
  115. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs +11 -0
  116. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs.map +1 -0
  117. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js +11 -0
  118. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js.map +1 -0
  119. package/dist/components/layout/aspect-ratio/index.cjs +16 -0
  120. package/dist/components/layout/aspect-ratio/index.cjs.map +1 -0
  121. package/dist/components/layout/aspect-ratio/index.d.cts +11 -0
  122. package/dist/components/layout/aspect-ratio/index.d.ts +11 -0
  123. package/dist/components/layout/aspect-ratio/index.js +16 -0
  124. package/dist/components/layout/aspect-ratio/index.js.map +1 -0
  125. package/dist/components/layout/container/container.css +1 -0
  126. package/dist/components/layout/page-layout/page-layout.css +1 -0
  127. package/dist/components/layout/resizable-panels/index.cjs +1 -1
  128. package/dist/components/layout/resizable-panels/index.cjs.map +1 -1
  129. package/dist/components/layout/resizable-panels/index.js +1 -1
  130. package/dist/components/layout/resizable-panels/index.js.map +1 -1
  131. package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs.map +1 -1
  132. package/dist/components/layout/resizable-panels/resizable-panels.utils.js.map +1 -1
  133. package/dist/components/layout/scroll-area/index.cjs +27 -0
  134. package/dist/components/layout/scroll-area/index.cjs.map +1 -0
  135. package/dist/components/layout/scroll-area/index.d.cts +15 -0
  136. package/dist/components/layout/scroll-area/index.d.ts +15 -0
  137. package/dist/components/layout/scroll-area/index.js +27 -0
  138. package/dist/components/layout/scroll-area/index.js.map +1 -0
  139. package/dist/components/layout/scroll-area/scroll-area.css +25 -0
  140. package/dist/components/layout/scroll-area/scroll-area.utils.cjs +8 -0
  141. package/dist/components/layout/scroll-area/scroll-area.utils.cjs.map +1 -0
  142. package/dist/components/layout/scroll-area/scroll-area.utils.d.cts +2 -0
  143. package/dist/components/layout/scroll-area/scroll-area.utils.d.ts +2 -0
  144. package/dist/components/layout/scroll-area/scroll-area.utils.js +8 -0
  145. package/dist/components/layout/scroll-area/scroll-area.utils.js.map +1 -0
  146. package/dist/components/layout/section/index.cjs +10 -4
  147. package/dist/components/layout/section/index.cjs.map +1 -1
  148. package/dist/components/layout/section/index.d.cts +1 -1
  149. package/dist/components/layout/section/index.d.ts +1 -1
  150. package/dist/components/layout/section/index.js +11 -5
  151. package/dist/components/layout/section/index.js.map +1 -1
  152. package/dist/components/layout/section/section.css +9 -3
  153. package/dist/components/layout/section/types.d.cts +5 -5
  154. package/dist/components/layout/section/types.d.ts +5 -5
  155. package/dist/components/layout/separator/index.cjs +18 -0
  156. package/dist/components/layout/separator/index.cjs.map +1 -0
  157. package/dist/components/layout/separator/index.d.cts +17 -0
  158. package/dist/components/layout/separator/index.d.ts +17 -0
  159. package/dist/components/layout/separator/index.js +18 -0
  160. package/dist/components/layout/separator/index.js.map +1 -0
  161. package/dist/components/layout/separator/separator.css +15 -0
  162. package/dist/components/layout/separator/separator.utils.cjs +11 -0
  163. package/dist/components/layout/separator/separator.utils.cjs.map +1 -0
  164. package/dist/components/layout/separator/separator.utils.d.cts +2 -0
  165. package/dist/components/layout/separator/separator.utils.d.ts +2 -0
  166. package/dist/components/layout/separator/separator.utils.js +11 -0
  167. package/dist/components/layout/separator/separator.utils.js.map +1 -0
  168. package/dist/components/layout/stack/index.cjs +18 -2
  169. package/dist/components/layout/stack/index.cjs.map +1 -1
  170. package/dist/components/layout/stack/index.d.cts +8 -6
  171. package/dist/components/layout/stack/index.d.ts +8 -6
  172. package/dist/components/layout/stack/index.js +18 -2
  173. package/dist/components/layout/stack/index.js.map +1 -1
  174. package/dist/components/layout/stack/stack.css +118 -138
  175. package/dist/components/navigation/accordion/index.cjs.map +1 -1
  176. package/dist/components/navigation/accordion/index.js.map +1 -1
  177. package/dist/components/navigation/carousel/index.cjs +5 -2
  178. package/dist/components/navigation/carousel/index.cjs.map +1 -1
  179. package/dist/components/navigation/carousel/index.js +5 -2
  180. package/dist/components/navigation/carousel/index.js.map +1 -1
  181. package/dist/components/navigation/pagination/index.cjs +146 -0
  182. package/dist/components/navigation/pagination/index.cjs.map +1 -0
  183. package/dist/components/navigation/pagination/index.d.cts +3 -0
  184. package/dist/components/navigation/pagination/index.d.ts +3 -0
  185. package/dist/components/navigation/pagination/index.js +146 -0
  186. package/dist/components/navigation/pagination/index.js.map +1 -0
  187. package/dist/components/navigation/pagination/pagination.css +134 -0
  188. package/dist/components/navigation/pagination/pagination.types.d.cts +38 -0
  189. package/dist/components/navigation/pagination/pagination.types.d.ts +38 -0
  190. package/dist/components/navigation/pagination/pagination.utils.cjs +54 -0
  191. package/dist/components/navigation/pagination/pagination.utils.cjs.map +1 -0
  192. package/dist/components/navigation/pagination/pagination.utils.js +53 -0
  193. package/dist/components/navigation/pagination/pagination.utils.js.map +1 -0
  194. package/dist/components/navigation/tabs/index.d.cts +3 -2
  195. package/dist/components/navigation/tabs/index.d.ts +3 -2
  196. package/dist/components/navigation/tree-view/index.cjs.map +1 -1
  197. package/dist/components/navigation/tree-view/index.js.map +1 -1
  198. package/dist/components/overlays/context-menu/context-menu.css +151 -0
  199. package/dist/components/overlays/context-menu/context-menu.types.d.cts +69 -0
  200. package/dist/components/overlays/context-menu/context-menu.types.d.ts +69 -0
  201. package/dist/components/overlays/context-menu/context-menu.utils.cjs +46 -0
  202. package/dist/components/overlays/context-menu/context-menu.utils.cjs.map +1 -0
  203. package/dist/components/overlays/context-menu/context-menu.utils.js +40 -0
  204. package/dist/components/overlays/context-menu/context-menu.utils.js.map +1 -0
  205. package/dist/components/overlays/context-menu/index.cjs +830 -0
  206. package/dist/components/overlays/context-menu/index.cjs.map +1 -0
  207. package/dist/components/overlays/context-menu/index.d.cts +42 -0
  208. package/dist/components/overlays/context-menu/index.d.ts +42 -0
  209. package/dist/components/overlays/context-menu/index.js +818 -0
  210. package/dist/components/overlays/context-menu/index.js.map +1 -0
  211. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs.map +1 -1
  212. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js.map +1 -1
  213. package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.cjs.map +1 -1
  214. package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.js.map +1 -1
  215. package/dist/components/typography/heading.cjs +6 -2
  216. package/dist/components/typography/heading.cjs.map +1 -1
  217. package/dist/components/typography/heading.d.cts +3 -2
  218. package/dist/components/typography/heading.d.ts +3 -2
  219. package/dist/components/typography/heading.js +6 -2
  220. package/dist/components/typography/heading.js.map +1 -1
  221. package/dist/components/typography/text.cjs +6 -2
  222. package/dist/components/typography/text.cjs.map +1 -1
  223. package/dist/components/typography/text.d.cts +3 -2
  224. package/dist/components/typography/text.d.ts +3 -2
  225. package/dist/components/typography/text.js +6 -2
  226. package/dist/components/typography/text.js.map +1 -1
  227. package/dist/components/utilities/preview/index.cjs +89 -21
  228. package/dist/components/utilities/preview/index.cjs.map +1 -1
  229. package/dist/components/utilities/preview/index.d.cts +6 -2
  230. package/dist/components/utilities/preview/index.d.ts +6 -2
  231. package/dist/components/utilities/preview/index.js +89 -21
  232. package/dist/components/utilities/preview/index.js.map +1 -1
  233. package/dist/components/utilities/preview/preview.css +26 -11
  234. package/dist/components/utilities/transition/index.d.cts +1 -1
  235. package/dist/components/utilities/transition/index.d.ts +1 -1
  236. package/dist/index.cjs +136 -97
  237. package/dist/index.d.cts +23 -2
  238. package/dist/index.d.ts +23 -2
  239. package/dist/index.js +12 -1
  240. package/package.json +7 -6
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["useId","useState","cn"],"sources":["../../../../src/components/forms/slider/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useId,\n useState,\n type ChangeEvent,\n type ComponentPropsWithRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport \"./slider.css\";\n\ntype SliderSize = \"sm\" | \"md\" | \"lg\";\n\ntype SliderMark = {\n /** Numeric position of the mark. */\n value: number;\n\n /** Optional visible label below the mark. */\n label?: ReactNode;\n};\n\ntype SliderProps = Omit<\n ComponentPropsWithRef<\"input\">,\n | \"type\"\n | \"value\"\n | \"defaultValue\"\n | \"onChange\"\n | \"min\"\n | \"max\"\n | \"step\"\n | \"size\"\n | \"className\"\n> & {\n /** Controlled numeric value. */\n value?: number;\n\n /** Initial value for uncontrolled usage. Defaults to the range midpoint. */\n defaultValue?: number;\n\n /** Called whenever the selected value changes. */\n onChange?: (value: number) => void;\n\n /** Minimum selectable value. Defaults to 0. */\n min?: number;\n\n /** Maximum selectable value. Defaults to 100. */\n max?: number;\n\n /** Allowed increment. Use \"any\" to disable step rounding. */\n step?: number | \"any\";\n\n /** Visual size of the slider. */\n size?: SliderSize;\n\n /** Optional marks displayed below the track. */\n marks?: readonly SliderMark[];\n\n /** Displays the current value above the slider. */\n showValue?: boolean;\n\n /**\n * Formats the visible value and supplies aria-valuetext.\n * An explicitly supplied aria-valuetext takes precedence.\n */\n formatValue?: (value: number) => string;\n\n /** Class applied to the outer slider element. */\n className?: string;\n};\n\nconst getPrecision = (value: number) => {\n const [coefficient, exponent = \"0\"] = String(value).toLowerCase().split(\"e\");\n\n const decimals = coefficient.split(\".\")[1]?.length ?? 0;\n\n return Math.min(12, Math.max(0, decimals - Number(exponent)));\n};\n\nconst normalizeSliderValue = (\n value: number,\n min: number,\n max: number,\n step: number | \"any\",\n) => {\n if (max <= min) {\n return min;\n }\n\n const boundedValue = Math.min(max, Math.max(min, value));\n\n if (step === \"any\") {\n return boundedValue;\n }\n\n const precision = Math.max(getPrecision(min), getPrecision(step));\n const factor = 10 ** precision;\n\n const steppedValue = min + Math.round((boundedValue - min) / step) * step;\n\n return Math.min(\n max,\n Math.max(min, Math.round(steppedValue * factor) / factor),\n );\n};\n\nconst Slider = ({\n value,\n defaultValue,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n size = \"md\",\n marks,\n showValue = false,\n formatValue,\n className,\n id,\n ref,\n disabled = false,\n style,\n \"aria-invalid\": ariaInvalid,\n \"aria-valuetext\": ariaValueText,\n ...inputProps\n}: SliderProps) => {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n\n const resolvedMin = Number.isFinite(min) ? min : 0;\n\n const requestedMax = Number.isFinite(max) ? max : 100;\n const resolvedMax = Math.max(resolvedMin, requestedMax);\n\n const resolvedStep =\n step === \"any\" ? \"any\" : Number.isFinite(step) && step > 0 ? step : 1;\n\n const isControlled = value !== undefined;\n\n const [internalValue, setInternalValue] = useState(() =>\n normalizeSliderValue(\n defaultValue ?? (resolvedMin + resolvedMax) / 2,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n ),\n );\n\n const currentValue = normalizeSliderValue(\n isControlled ? value : internalValue,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n const progress =\n resolvedMax > resolvedMin\n ? ((currentValue - resolvedMin) / (resolvedMax - resolvedMin)) * 100\n : 0;\n\n const formattedValue = formatValue?.(currentValue);\n\n const isInvalid = ariaInvalid === true || ariaInvalid === \"true\";\n\n const resolvedMarks = (marks ?? [])\n .filter(\n (mark) =>\n Number.isFinite(mark.value) &&\n mark.value >= resolvedMin &&\n mark.value <= resolvedMax,\n )\n .slice()\n .sort((a, b) => a.value - b.value);\n\n const hasMarkLabels = resolvedMarks.some((mark) => mark.label != null);\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = normalizeSliderValue(\n event.currentTarget.valueAsNumber,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n if (!isControlled) {\n setInternalValue(nextValue);\n }\n\n onChange?.(nextValue);\n };\n\n return (\n <div\n className={cn(\"puzzle-slider\", className)}\n data-size={size}\n data-disabled={disabled || undefined}\n data-invalid={isInvalid || undefined}\n >\n {showValue && (\n <output htmlFor={inputId} className=\"puzzle-slider__value\">\n {formattedValue ?? currentValue}\n </output>\n )}\n\n <input\n {...inputProps}\n ref={ref}\n id={inputId}\n className=\"puzzle-slider__input\"\n type=\"range\"\n min={resolvedMin}\n max={resolvedMax}\n step={resolvedStep}\n value={currentValue}\n disabled={disabled}\n aria-invalid={ariaInvalid}\n aria-valuetext={ariaValueText ?? formattedValue}\n style={\n {\n ...style,\n \"--puzzle-slider-progress\": `${progress}%`,\n } as CSSProperties\n }\n onChange={handleChange}\n />\n\n {resolvedMarks.length > 0 && (\n <div\n className=\"puzzle-slider__marks\"\n data-has-labels={hasMarkLabels || undefined}\n >\n {resolvedMarks.map((mark, index) => {\n const position =\n resolvedMax > resolvedMin\n ? ((mark.value - resolvedMin) / (resolvedMax - resolvedMin)) *\n 100\n : 0;\n\n return (\n <span\n key={`${mark.value}-${index}`}\n className=\"puzzle-slider__mark\"\n data-edge={\n index === 0\n ? \"start\"\n : index === resolvedMarks.length - 1\n ? \"end\"\n : undefined\n }\n style={{\n insetInlineStart: `${position}%`,\n }}\n >\n <span className=\"puzzle-slider__mark-tick\" aria-hidden=\"true\" />\n\n {mark.label != null && (\n <span className=\"puzzle-slider__mark-label\">\n {mark.label}\n </span>\n )}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport { Slider, type SliderProps, type SliderMark, type SliderSize };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["useId","useState","cn"],"sources":["../../../../src/components/forms/slider/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useId,\n useState,\n type ChangeEvent,\n type ComponentPropsWithRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport \"./slider.css\";\n\ntype SliderSize = \"sm\" | \"md\" | \"lg\";\n\ntype SliderMark = {\n /** Numeric position of the mark. */\n value: number;\n\n /** Optional visible label below the mark. */\n label?: ReactNode;\n};\n\ntype SliderProps = Omit<\n ComponentPropsWithRef<\"input\">,\n | \"type\"\n | \"value\"\n | \"defaultValue\"\n | \"onChange\"\n | \"min\"\n | \"max\"\n | \"step\"\n | \"size\"\n | \"className\"\n> & {\n /** Controlled numeric value. */\n value?: number;\n\n /** Initial value for uncontrolled usage. Defaults to the range midpoint. */\n defaultValue?: number;\n\n /** Called whenever the selected value changes. */\n onChange?: (value: number) => void;\n\n /** Minimum selectable value. Defaults to 0. */\n min?: number;\n\n /** Maximum selectable value. Defaults to 100. */\n max?: number;\n\n /** Allowed increment. Use \"any\" to disable step rounding. */\n step?: number | \"any\";\n\n /** Visual size of the slider. */\n size?: SliderSize;\n\n /** Optional marks displayed below the track. */\n marks?: readonly SliderMark[];\n\n /** Displays the current value above the slider. */\n showValue?: boolean;\n\n /**\n * Formats the visible value and supplies aria-valuetext.\n * An explicitly supplied aria-valuetext takes precedence.\n */\n formatValue?: (value: number) => string;\n\n /** Class applied to the outer slider element. */\n className?: string;\n};\n\nconst getPrecision = (value: number) => {\n const [coefficient = \"\", exponent = \"0\"] = String(value).toLowerCase().split(\"e\");\n\n const decimals = coefficient.split(\".\")[1]?.length ?? 0;\n\n return Math.min(12, Math.max(0, decimals - Number(exponent)));\n};\n\nconst normalizeSliderValue = (\n value: number,\n min: number,\n max: number,\n step: number | \"any\",\n) => {\n if (max <= min) {\n return min;\n }\n\n const boundedValue = Math.min(max, Math.max(min, value));\n\n if (step === \"any\") {\n return boundedValue;\n }\n\n const precision = Math.max(getPrecision(min), getPrecision(step));\n const factor = 10 ** precision;\n\n const steppedValue = min + Math.round((boundedValue - min) / step) * step;\n\n return Math.min(\n max,\n Math.max(min, Math.round(steppedValue * factor) / factor),\n );\n};\n\nconst Slider = ({\n value,\n defaultValue,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n size = \"md\",\n marks,\n showValue = false,\n formatValue,\n className,\n id,\n ref,\n disabled = false,\n style,\n \"aria-invalid\": ariaInvalid,\n \"aria-valuetext\": ariaValueText,\n ...inputProps\n}: SliderProps) => {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n\n const resolvedMin = Number.isFinite(min) ? min : 0;\n\n const requestedMax = Number.isFinite(max) ? max : 100;\n const resolvedMax = Math.max(resolvedMin, requestedMax);\n\n const resolvedStep =\n step === \"any\" ? \"any\" : Number.isFinite(step) && step > 0 ? step : 1;\n\n const isControlled = value !== undefined;\n\n const [internalValue, setInternalValue] = useState(() =>\n normalizeSliderValue(\n defaultValue ?? (resolvedMin + resolvedMax) / 2,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n ),\n );\n\n const currentValue = normalizeSliderValue(\n isControlled ? value : internalValue,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n const progress =\n resolvedMax > resolvedMin\n ? ((currentValue - resolvedMin) / (resolvedMax - resolvedMin)) * 100\n : 0;\n\n const formattedValue = formatValue?.(currentValue);\n\n const isInvalid = ariaInvalid === true || ariaInvalid === \"true\";\n\n const resolvedMarks = (marks ?? [])\n .filter(\n (mark) =>\n Number.isFinite(mark.value) &&\n mark.value >= resolvedMin &&\n mark.value <= resolvedMax,\n )\n .slice()\n .sort((a, b) => a.value - b.value);\n\n const hasMarkLabels = resolvedMarks.some((mark) => mark.label != null);\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = normalizeSliderValue(\n event.currentTarget.valueAsNumber,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n if (!isControlled) {\n setInternalValue(nextValue);\n }\n\n onChange?.(nextValue);\n };\n\n return (\n <div\n className={cn(\"puzzle-slider\", className)}\n data-size={size}\n data-disabled={disabled || undefined}\n data-invalid={isInvalid || undefined}\n >\n {showValue && (\n <output htmlFor={inputId} className=\"puzzle-slider__value\">\n {formattedValue ?? currentValue}\n </output>\n )}\n\n <input\n {...inputProps}\n ref={ref}\n id={inputId}\n className=\"puzzle-slider__input\"\n type=\"range\"\n min={resolvedMin}\n max={resolvedMax}\n step={resolvedStep}\n value={currentValue}\n disabled={disabled}\n aria-invalid={ariaInvalid}\n aria-valuetext={ariaValueText ?? formattedValue}\n style={\n {\n ...style,\n \"--puzzle-slider-progress\": `${progress}%`,\n } as CSSProperties\n }\n onChange={handleChange}\n />\n\n {resolvedMarks.length > 0 && (\n <div\n className=\"puzzle-slider__marks\"\n data-has-labels={hasMarkLabels || undefined}\n >\n {resolvedMarks.map((mark, index) => {\n const position =\n resolvedMax > resolvedMin\n ? ((mark.value - resolvedMin) / (resolvedMax - resolvedMin)) *\n 100\n : 0;\n\n return (\n <span\n key={`${mark.value}-${index}`}\n className=\"puzzle-slider__mark\"\n data-edge={\n index === 0\n ? \"start\"\n : index === resolvedMarks.length - 1\n ? \"end\"\n : undefined\n }\n style={{\n insetInlineStart: `${position}%`,\n }}\n >\n <span className=\"puzzle-slider__mark-tick\" aria-hidden=\"true\" />\n\n {mark.label != null && (\n <span className=\"puzzle-slider__mark-label\">\n {mark.label}\n </span>\n )}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport { Slider, type SliderProps, type SliderMark, type SliderSize };\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { useId, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  // src/components/forms/slider/index.tsx
7
7
  const getPrecision = (value) => {
8
- const [coefficient, exponent = "0"] = String(value).toLowerCase().split("e");
8
+ const [coefficient = "", exponent = "0"] = String(value).toLowerCase().split("e");
9
9
  const decimals = coefficient.split(".")[1]?.length ?? 0;
10
10
  return Math.min(12, Math.max(0, decimals - Number(exponent)));
11
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/forms/slider/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useId,\n useState,\n type ChangeEvent,\n type ComponentPropsWithRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport \"./slider.css\";\n\ntype SliderSize = \"sm\" | \"md\" | \"lg\";\n\ntype SliderMark = {\n /** Numeric position of the mark. */\n value: number;\n\n /** Optional visible label below the mark. */\n label?: ReactNode;\n};\n\ntype SliderProps = Omit<\n ComponentPropsWithRef<\"input\">,\n | \"type\"\n | \"value\"\n | \"defaultValue\"\n | \"onChange\"\n | \"min\"\n | \"max\"\n | \"step\"\n | \"size\"\n | \"className\"\n> & {\n /** Controlled numeric value. */\n value?: number;\n\n /** Initial value for uncontrolled usage. Defaults to the range midpoint. */\n defaultValue?: number;\n\n /** Called whenever the selected value changes. */\n onChange?: (value: number) => void;\n\n /** Minimum selectable value. Defaults to 0. */\n min?: number;\n\n /** Maximum selectable value. Defaults to 100. */\n max?: number;\n\n /** Allowed increment. Use \"any\" to disable step rounding. */\n step?: number | \"any\";\n\n /** Visual size of the slider. */\n size?: SliderSize;\n\n /** Optional marks displayed below the track. */\n marks?: readonly SliderMark[];\n\n /** Displays the current value above the slider. */\n showValue?: boolean;\n\n /**\n * Formats the visible value and supplies aria-valuetext.\n * An explicitly supplied aria-valuetext takes precedence.\n */\n formatValue?: (value: number) => string;\n\n /** Class applied to the outer slider element. */\n className?: string;\n};\n\nconst getPrecision = (value: number) => {\n const [coefficient, exponent = \"0\"] = String(value).toLowerCase().split(\"e\");\n\n const decimals = coefficient.split(\".\")[1]?.length ?? 0;\n\n return Math.min(12, Math.max(0, decimals - Number(exponent)));\n};\n\nconst normalizeSliderValue = (\n value: number,\n min: number,\n max: number,\n step: number | \"any\",\n) => {\n if (max <= min) {\n return min;\n }\n\n const boundedValue = Math.min(max, Math.max(min, value));\n\n if (step === \"any\") {\n return boundedValue;\n }\n\n const precision = Math.max(getPrecision(min), getPrecision(step));\n const factor = 10 ** precision;\n\n const steppedValue = min + Math.round((boundedValue - min) / step) * step;\n\n return Math.min(\n max,\n Math.max(min, Math.round(steppedValue * factor) / factor),\n );\n};\n\nconst Slider = ({\n value,\n defaultValue,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n size = \"md\",\n marks,\n showValue = false,\n formatValue,\n className,\n id,\n ref,\n disabled = false,\n style,\n \"aria-invalid\": ariaInvalid,\n \"aria-valuetext\": ariaValueText,\n ...inputProps\n}: SliderProps) => {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n\n const resolvedMin = Number.isFinite(min) ? min : 0;\n\n const requestedMax = Number.isFinite(max) ? max : 100;\n const resolvedMax = Math.max(resolvedMin, requestedMax);\n\n const resolvedStep =\n step === \"any\" ? \"any\" : Number.isFinite(step) && step > 0 ? step : 1;\n\n const isControlled = value !== undefined;\n\n const [internalValue, setInternalValue] = useState(() =>\n normalizeSliderValue(\n defaultValue ?? (resolvedMin + resolvedMax) / 2,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n ),\n );\n\n const currentValue = normalizeSliderValue(\n isControlled ? value : internalValue,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n const progress =\n resolvedMax > resolvedMin\n ? ((currentValue - resolvedMin) / (resolvedMax - resolvedMin)) * 100\n : 0;\n\n const formattedValue = formatValue?.(currentValue);\n\n const isInvalid = ariaInvalid === true || ariaInvalid === \"true\";\n\n const resolvedMarks = (marks ?? [])\n .filter(\n (mark) =>\n Number.isFinite(mark.value) &&\n mark.value >= resolvedMin &&\n mark.value <= resolvedMax,\n )\n .slice()\n .sort((a, b) => a.value - b.value);\n\n const hasMarkLabels = resolvedMarks.some((mark) => mark.label != null);\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = normalizeSliderValue(\n event.currentTarget.valueAsNumber,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n if (!isControlled) {\n setInternalValue(nextValue);\n }\n\n onChange?.(nextValue);\n };\n\n return (\n <div\n className={cn(\"puzzle-slider\", className)}\n data-size={size}\n data-disabled={disabled || undefined}\n data-invalid={isInvalid || undefined}\n >\n {showValue && (\n <output htmlFor={inputId} className=\"puzzle-slider__value\">\n {formattedValue ?? currentValue}\n </output>\n )}\n\n <input\n {...inputProps}\n ref={ref}\n id={inputId}\n className=\"puzzle-slider__input\"\n type=\"range\"\n min={resolvedMin}\n max={resolvedMax}\n step={resolvedStep}\n value={currentValue}\n disabled={disabled}\n aria-invalid={ariaInvalid}\n aria-valuetext={ariaValueText ?? formattedValue}\n style={\n {\n ...style,\n \"--puzzle-slider-progress\": `${progress}%`,\n } as CSSProperties\n }\n onChange={handleChange}\n />\n\n {resolvedMarks.length > 0 && (\n <div\n className=\"puzzle-slider__marks\"\n data-has-labels={hasMarkLabels || undefined}\n >\n {resolvedMarks.map((mark, index) => {\n const position =\n resolvedMax > resolvedMin\n ? ((mark.value - resolvedMin) / (resolvedMax - resolvedMin)) *\n 100\n : 0;\n\n return (\n <span\n key={`${mark.value}-${index}`}\n className=\"puzzle-slider__mark\"\n data-edge={\n index === 0\n ? \"start\"\n : index === resolvedMarks.length - 1\n ? \"end\"\n : undefined\n }\n style={{\n insetInlineStart: `${position}%`,\n }}\n >\n <span className=\"puzzle-slider__mark-tick\" aria-hidden=\"true\" />\n\n {mark.label != null && (\n <span className=\"puzzle-slider__mark-label\">\n {mark.label}\n </span>\n )}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport { Slider, type SliderProps, type SliderMark, type SliderSize };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/forms/slider/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useId,\n useState,\n type ChangeEvent,\n type ComponentPropsWithRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport \"./slider.css\";\n\ntype SliderSize = \"sm\" | \"md\" | \"lg\";\n\ntype SliderMark = {\n /** Numeric position of the mark. */\n value: number;\n\n /** Optional visible label below the mark. */\n label?: ReactNode;\n};\n\ntype SliderProps = Omit<\n ComponentPropsWithRef<\"input\">,\n | \"type\"\n | \"value\"\n | \"defaultValue\"\n | \"onChange\"\n | \"min\"\n | \"max\"\n | \"step\"\n | \"size\"\n | \"className\"\n> & {\n /** Controlled numeric value. */\n value?: number;\n\n /** Initial value for uncontrolled usage. Defaults to the range midpoint. */\n defaultValue?: number;\n\n /** Called whenever the selected value changes. */\n onChange?: (value: number) => void;\n\n /** Minimum selectable value. Defaults to 0. */\n min?: number;\n\n /** Maximum selectable value. Defaults to 100. */\n max?: number;\n\n /** Allowed increment. Use \"any\" to disable step rounding. */\n step?: number | \"any\";\n\n /** Visual size of the slider. */\n size?: SliderSize;\n\n /** Optional marks displayed below the track. */\n marks?: readonly SliderMark[];\n\n /** Displays the current value above the slider. */\n showValue?: boolean;\n\n /**\n * Formats the visible value and supplies aria-valuetext.\n * An explicitly supplied aria-valuetext takes precedence.\n */\n formatValue?: (value: number) => string;\n\n /** Class applied to the outer slider element. */\n className?: string;\n};\n\nconst getPrecision = (value: number) => {\n const [coefficient = \"\", exponent = \"0\"] = String(value).toLowerCase().split(\"e\");\n\n const decimals = coefficient.split(\".\")[1]?.length ?? 0;\n\n return Math.min(12, Math.max(0, decimals - Number(exponent)));\n};\n\nconst normalizeSliderValue = (\n value: number,\n min: number,\n max: number,\n step: number | \"any\",\n) => {\n if (max <= min) {\n return min;\n }\n\n const boundedValue = Math.min(max, Math.max(min, value));\n\n if (step === \"any\") {\n return boundedValue;\n }\n\n const precision = Math.max(getPrecision(min), getPrecision(step));\n const factor = 10 ** precision;\n\n const steppedValue = min + Math.round((boundedValue - min) / step) * step;\n\n return Math.min(\n max,\n Math.max(min, Math.round(steppedValue * factor) / factor),\n );\n};\n\nconst Slider = ({\n value,\n defaultValue,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n size = \"md\",\n marks,\n showValue = false,\n formatValue,\n className,\n id,\n ref,\n disabled = false,\n style,\n \"aria-invalid\": ariaInvalid,\n \"aria-valuetext\": ariaValueText,\n ...inputProps\n}: SliderProps) => {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n\n const resolvedMin = Number.isFinite(min) ? min : 0;\n\n const requestedMax = Number.isFinite(max) ? max : 100;\n const resolvedMax = Math.max(resolvedMin, requestedMax);\n\n const resolvedStep =\n step === \"any\" ? \"any\" : Number.isFinite(step) && step > 0 ? step : 1;\n\n const isControlled = value !== undefined;\n\n const [internalValue, setInternalValue] = useState(() =>\n normalizeSliderValue(\n defaultValue ?? (resolvedMin + resolvedMax) / 2,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n ),\n );\n\n const currentValue = normalizeSliderValue(\n isControlled ? value : internalValue,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n const progress =\n resolvedMax > resolvedMin\n ? ((currentValue - resolvedMin) / (resolvedMax - resolvedMin)) * 100\n : 0;\n\n const formattedValue = formatValue?.(currentValue);\n\n const isInvalid = ariaInvalid === true || ariaInvalid === \"true\";\n\n const resolvedMarks = (marks ?? [])\n .filter(\n (mark) =>\n Number.isFinite(mark.value) &&\n mark.value >= resolvedMin &&\n mark.value <= resolvedMax,\n )\n .slice()\n .sort((a, b) => a.value - b.value);\n\n const hasMarkLabels = resolvedMarks.some((mark) => mark.label != null);\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = normalizeSliderValue(\n event.currentTarget.valueAsNumber,\n resolvedMin,\n resolvedMax,\n resolvedStep,\n );\n\n if (!isControlled) {\n setInternalValue(nextValue);\n }\n\n onChange?.(nextValue);\n };\n\n return (\n <div\n className={cn(\"puzzle-slider\", className)}\n data-size={size}\n data-disabled={disabled || undefined}\n data-invalid={isInvalid || undefined}\n >\n {showValue && (\n <output htmlFor={inputId} className=\"puzzle-slider__value\">\n {formattedValue ?? currentValue}\n </output>\n )}\n\n <input\n {...inputProps}\n ref={ref}\n id={inputId}\n className=\"puzzle-slider__input\"\n type=\"range\"\n min={resolvedMin}\n max={resolvedMax}\n step={resolvedStep}\n value={currentValue}\n disabled={disabled}\n aria-invalid={ariaInvalid}\n aria-valuetext={ariaValueText ?? formattedValue}\n style={\n {\n ...style,\n \"--puzzle-slider-progress\": `${progress}%`,\n } as CSSProperties\n }\n onChange={handleChange}\n />\n\n {resolvedMarks.length > 0 && (\n <div\n className=\"puzzle-slider__marks\"\n data-has-labels={hasMarkLabels || undefined}\n >\n {resolvedMarks.map((mark, index) => {\n const position =\n resolvedMax > resolvedMin\n ? ((mark.value - resolvedMin) / (resolvedMax - resolvedMin)) *\n 100\n : 0;\n\n return (\n <span\n key={`${mark.value}-${index}`}\n className=\"puzzle-slider__mark\"\n data-edge={\n index === 0\n ? \"start\"\n : index === resolvedMarks.length - 1\n ? \"end\"\n : undefined\n }\n style={{\n insetInlineStart: `${position}%`,\n }}\n >\n <span className=\"puzzle-slider__mark-tick\" aria-hidden=\"true\" />\n\n {mark.label != null && (\n <span className=\"puzzle-slider__mark-label\">\n {mark.label}\n </span>\n )}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport { Slider, type SliderProps, type SliderMark, type SliderSize };\n"],"mappings":"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"}
@@ -42,7 +42,9 @@ type StepperProps = Omit<ComponentPropsWithoutRef<"ol">, "children"> & {
42
42
  linear?: boolean;
43
43
  children: ReactNode;
44
44
  };
45
- declare const Stepper: (({ activeStep, activeStepId, defaultActiveStep, defaultActiveStepId, onStepChange, onStepIdChange, orientation, clickable, linear, children, className, ...rootProps }: StepperProps) => import("react").JSX.Element) & {
46
- Step: (_props: StepperStepProps) => null;
45
+ declare const StepperStep: (_props: StepperStepProps) => null;
46
+ declare const StepperRoot: ({ activeStep, activeStepId, defaultActiveStep, defaultActiveStepId, onStepChange, onStepIdChange, orientation, clickable, linear, children, className, ...rootProps }: StepperProps) => import("react").JSX.Element;
47
+ declare const Stepper: typeof StepperRoot & {
48
+ Step: typeof StepperStep;
47
49
  };
48
50
  export { Stepper, type StepperOrientation, type StepperProps, type StepperStepProps };
@@ -42,7 +42,9 @@ type StepperProps = Omit<ComponentPropsWithoutRef<"ol">, "children"> & {
42
42
  linear?: boolean;
43
43
  children: ReactNode;
44
44
  };
45
- declare const Stepper: (({ activeStep, activeStepId, defaultActiveStep, defaultActiveStepId, onStepChange, onStepIdChange, orientation, clickable, linear, children, className, ...rootProps }: StepperProps) => import("react").JSX.Element) & {
46
- Step: (_props: StepperStepProps) => null;
45
+ declare const StepperStep: (_props: StepperStepProps) => null;
46
+ declare const StepperRoot: ({ activeStep, activeStepId, defaultActiveStep, defaultActiveStepId, onStepChange, onStepIdChange, orientation, clickable, linear, children, className, ...rootProps }: StepperProps) => import("react").JSX.Element;
47
+ declare const Stepper: typeof StepperRoot & {
48
+ Step: typeof StepperStep;
47
49
  };
48
50
  export { Stepper, type StepperOrientation, type StepperProps, type StepperStepProps };
@@ -0,0 +1,108 @@
1
+ "use client";
2
+ const require_time_picker_utils = require("./time-picker.utils.cjs");
3
+ ;/* empty css */
4
+ let _puzzle_ui_core = require("@puzzle-ui/core");
5
+ let react = require("react");
6
+ let react_jsx_runtime = require("react/jsx-runtime");
7
+ // src/components/forms/time-picker/index.tsx
8
+ const TimePicker = ({ value, defaultValue, onChange, label, description, error, disabled = false, readOnly = false, required = false, name, form, minTime, maxTime, minuteStep = 1, showSeconds = false, secondStep = 1, size = "md", fullWidth = false, rootClassName, className, id, style, onBlur, onFocus, onInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...inputProps }) => {
9
+ const baseId = (0, react.useId)();
10
+ const inputId = id ?? `${baseId}-input`;
11
+ const labelId = `${baseId}-label`;
12
+ const descriptionId = `${baseId}-description`;
13
+ const errorId = `${baseId}-error`;
14
+ const isControlled = value !== void 0;
15
+ const selectedValue = require_time_picker_utils.normalizeTime(isControlled ? value : defaultValue, showSeconds);
16
+ const responsiveSize = (0, _puzzle_ui_core.resolveResponsiveValue)(size, "md");
17
+ const responsiveFullWidth = (0, _puzzle_ui_core.resolveResponsiveValue)(fullWidth, false);
18
+ const hasError = error !== void 0 && error !== null && error !== false;
19
+ const isInvalid = hasError || ariaInvalid !== void 0 && ariaInvalid !== false && ariaInvalid !== "false";
20
+ const resolvedAriaInvalid = isInvalid ? true : ariaInvalid;
21
+ const errorContent = error === true ? "Invalid time" : error;
22
+ const resolvedLabelledBy = ariaLabelledBy ?? (label != null ? labelId : void 0);
23
+ const resolvedDescribedBy = [
24
+ ariaDescribedBy,
25
+ description != null ? descriptionId : void 0,
26
+ hasError ? errorId : void 0
27
+ ].filter(Boolean).join(" ") || void 0;
28
+ const isConfigurationInvalid = (0, react.useMemo)(() => {
29
+ const min = require_time_picker_utils.parseTime(minTime);
30
+ const max = require_time_picker_utils.parseTime(maxTime);
31
+ return minTime != null && min === null || maxTime != null && max === null || min !== null && max !== null && min > max || !Number.isInteger(minuteStep) || minuteStep < 1 || minuteStep > 60 || !Number.isInteger(secondStep) || secondStep < 1 || secondStep > 60;
32
+ }, [
33
+ minTime,
34
+ maxTime,
35
+ minuteStep,
36
+ secondStep
37
+ ]);
38
+ const step = showSeconds ? secondStep : minuteStep * 60;
39
+ const handleChange = (event) => {
40
+ const nextValue = require_time_picker_utils.normalizeTime(event.currentTarget.value, showSeconds);
41
+ onChange?.(nextValue);
42
+ };
43
+ const inputValue = selectedValue ?? "";
44
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
45
+ className: (0, _puzzle_ui_core.cn)("puzzle-time-picker", rootClassName),
46
+ "data-disabled": disabled ? "true" : void 0,
47
+ "data-readonly": readOnly ? "true" : void 0,
48
+ "data-invalid": isInvalid ? "true" : void 0,
49
+ "data-size-mobile": responsiveSize.mobile,
50
+ "data-size-tablet": responsiveSize.tablet,
51
+ "data-size-desktop": responsiveSize.desktop,
52
+ "data-full-width-mobile": String(responsiveFullWidth.mobile),
53
+ "data-full-width-tablet": String(responsiveFullWidth.tablet),
54
+ "data-full-width-desktop": String(responsiveFullWidth.desktop),
55
+ children: [
56
+ label != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
57
+ id: labelId,
58
+ className: "puzzle-time-picker__label",
59
+ htmlFor: inputId,
60
+ children: [label, required && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
61
+ className: "puzzle-time-picker__required",
62
+ "aria-hidden": "true",
63
+ children: "*"
64
+ })]
65
+ }),
66
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
67
+ ...inputProps,
68
+ id: inputId,
69
+ type: "time",
70
+ name,
71
+ form,
72
+ value: isControlled ? inputValue : void 0,
73
+ defaultValue: !isControlled ? inputValue : void 0,
74
+ disabled: disabled || isConfigurationInvalid,
75
+ readOnly,
76
+ required,
77
+ min: minTime,
78
+ max: maxTime,
79
+ step,
80
+ style,
81
+ className: (0, _puzzle_ui_core.cn)("puzzle-time-picker__input", className),
82
+ onChange: handleChange,
83
+ onBlur,
84
+ onFocus,
85
+ onInvalid,
86
+ "aria-label": ariaLabel,
87
+ "aria-labelledby": resolvedLabelledBy,
88
+ "aria-describedby": resolvedDescribedBy,
89
+ "aria-invalid": resolvedAriaInvalid,
90
+ "aria-required": required || void 0
91
+ }),
92
+ description != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
93
+ id: descriptionId,
94
+ className: "puzzle-time-picker__description",
95
+ children: description
96
+ }),
97
+ hasError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
98
+ id: errorId,
99
+ className: "puzzle-time-picker__error",
100
+ role: "alert",
101
+ children: errorContent
102
+ })
103
+ ]
104
+ });
105
+ };
106
+ exports.TimePicker = TimePicker;
107
+
108
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["useId","normalizeTime","resolveResponsiveValue","useMemo","parseTime","cn"],"sources":["../../../../src/components/forms/time-picker/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { useId, useMemo, type ChangeEvent } from \"react\";\n\nimport { cn, resolveResponsiveValue } from \"@puzzle-ui/core\";\n\nimport { normalizeTime, parseTime } from \"./time-picker.utils\";\n\nimport type { TimePickerProps } from \"./time-picker.types\";\n\nimport \"./time-picker.css\";\n\nconst TimePicker = ({\n value,\n defaultValue,\n onChange,\n label,\n description,\n error,\n disabled = false,\n readOnly = false,\n required = false,\n name,\n form,\n minTime,\n maxTime,\n minuteStep = 1,\n showSeconds = false,\n secondStep = 1,\n size = \"md\",\n fullWidth = false,\n rootClassName,\n className,\n id,\n style,\n onBlur,\n onFocus,\n onInvalid,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n ...inputProps\n}: TimePickerProps) => {\n const baseId = useId();\n\n const inputId = id ?? `${baseId}-input`;\n const labelId = `${baseId}-label`;\n const descriptionId = `${baseId}-description`;\n const errorId = `${baseId}-error`;\n\n const isControlled = value !== undefined;\n\n const selectedValue = normalizeTime(\n isControlled ? value : defaultValue,\n showSeconds,\n );\n\n const responsiveSize = resolveResponsiveValue(size, \"md\");\n const responsiveFullWidth = resolveResponsiveValue(fullWidth, false);\n\n const hasError = error !== undefined && error !== null && error !== false;\n\n const isAriaInvalid =\n ariaInvalid !== undefined &&\n ariaInvalid !== false &&\n ariaInvalid !== \"false\";\n\n const isInvalid = hasError || isAriaInvalid;\n\n const resolvedAriaInvalid = isInvalid ? true : ariaInvalid;\n\n const errorContent = error === true ? \"Invalid time\" : error;\n\n const resolvedLabelledBy =\n ariaLabelledBy ?? (label != null ? labelId : undefined);\n\n const resolvedDescribedBy =\n [\n ariaDescribedBy,\n description != null ? descriptionId : undefined,\n hasError ? errorId : undefined,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n const isConfigurationInvalid = useMemo(() => {\n const min = parseTime(minTime);\n const max = parseTime(maxTime);\n\n return (\n (minTime != null && min === null) ||\n (maxTime != null && max === null) ||\n (min !== null && max !== null && min > max) ||\n !Number.isInteger(minuteStep) ||\n minuteStep < 1 ||\n minuteStep > 60 ||\n !Number.isInteger(secondStep) ||\n secondStep < 1 ||\n secondStep > 60\n );\n }, [minTime, maxTime, minuteStep, secondStep]);\n\n const step = showSeconds ? secondStep : minuteStep * 60;\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = normalizeTime(event.currentTarget.value, showSeconds);\n\n onChange?.(nextValue);\n };\n\n const inputValue = selectedValue ?? \"\";\n\n return (\n <div\n className={cn(\"puzzle-time-picker\", rootClassName)}\n data-disabled={disabled ? \"true\" : undefined}\n data-readonly={readOnly ? \"true\" : undefined}\n data-invalid={isInvalid ? \"true\" : undefined}\n data-size-mobile={responsiveSize.mobile}\n data-size-tablet={responsiveSize.tablet}\n data-size-desktop={responsiveSize.desktop}\n data-full-width-mobile={String(responsiveFullWidth.mobile)}\n data-full-width-tablet={String(responsiveFullWidth.tablet)}\n data-full-width-desktop={String(responsiveFullWidth.desktop)}\n >\n {label != null && (\n <label\n id={labelId}\n className=\"puzzle-time-picker__label\"\n htmlFor={inputId}\n >\n {label}\n {required && (\n <span className=\"puzzle-time-picker__required\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <input\n {...inputProps}\n id={inputId}\n type=\"time\"\n name={name}\n form={form}\n value={isControlled ? inputValue : undefined}\n defaultValue={!isControlled ? inputValue : undefined}\n disabled={disabled || isConfigurationInvalid}\n readOnly={readOnly}\n required={required}\n min={minTime}\n max={maxTime}\n step={step}\n style={style}\n className={cn(\"puzzle-time-picker__input\", className)}\n onChange={handleChange}\n onBlur={onBlur}\n onFocus={onFocus}\n onInvalid={onInvalid}\n aria-label={ariaLabel}\n aria-labelledby={resolvedLabelledBy}\n aria-describedby={resolvedDescribedBy}\n aria-invalid={resolvedAriaInvalid}\n aria-required={required || undefined}\n />\n\n {description != null && (\n <div id={descriptionId} className=\"puzzle-time-picker__description\">\n {description}\n </div>\n )}\n\n {hasError && (\n <div id={errorId} className=\"puzzle-time-picker__error\" role=\"alert\">\n {errorContent}\n </div>\n )}\n </div>\n );\n};\n\nexport { TimePicker };\nexport type { TimePickerProps, TimePickerSize } from \"./time-picker.types\";\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { TimePickerProps, TimePickerSize } from "./time-picker.types.cjs";
2
+ declare const TimePicker: ({ value, defaultValue, onChange, label, description, error, disabled, readOnly, required, name, form, minTime, maxTime, minuteStep, showSeconds, secondStep, size, fullWidth, rootClassName, className, id, style, onBlur, onFocus, onInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...inputProps }: TimePickerProps) => import("react").JSX.Element;
3
+ export { TimePicker, type TimePickerProps, type TimePickerSize };
@@ -0,0 +1,3 @@
1
+ import { TimePickerProps, TimePickerSize } from "./time-picker.types.js";
2
+ declare const TimePicker: ({ value, defaultValue, onChange, label, description, error, disabled, readOnly, required, name, form, minTime, maxTime, minuteStep, showSeconds, secondStep, size, fullWidth, rootClassName, className, id, style, onBlur, onFocus, onInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...inputProps }: TimePickerProps) => import("react").JSX.Element;
3
+ export { TimePicker, type TimePickerProps, type TimePickerSize };
@@ -0,0 +1,108 @@
1
+ "use client";
2
+ import { normalizeTime, parseTime } from "./time-picker.utils.js";
3
+ import "./time-picker.css";
4
+ import { cn, resolveResponsiveValue } from "@puzzle-ui/core";
5
+ import { useId, useMemo } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ // src/components/forms/time-picker/index.tsx
8
+ const TimePicker = ({ value, defaultValue, onChange, label, description, error, disabled = false, readOnly = false, required = false, name, form, minTime, maxTime, minuteStep = 1, showSeconds = false, secondStep = 1, size = "md", fullWidth = false, rootClassName, className, id, style, onBlur, onFocus, onInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...inputProps }) => {
9
+ const baseId = useId();
10
+ const inputId = id ?? `${baseId}-input`;
11
+ const labelId = `${baseId}-label`;
12
+ const descriptionId = `${baseId}-description`;
13
+ const errorId = `${baseId}-error`;
14
+ const isControlled = value !== void 0;
15
+ const selectedValue = normalizeTime(isControlled ? value : defaultValue, showSeconds);
16
+ const responsiveSize = resolveResponsiveValue(size, "md");
17
+ const responsiveFullWidth = resolveResponsiveValue(fullWidth, false);
18
+ const hasError = error !== void 0 && error !== null && error !== false;
19
+ const isInvalid = hasError || ariaInvalid !== void 0 && ariaInvalid !== false && ariaInvalid !== "false";
20
+ const resolvedAriaInvalid = isInvalid ? true : ariaInvalid;
21
+ const errorContent = error === true ? "Invalid time" : error;
22
+ const resolvedLabelledBy = ariaLabelledBy ?? (label != null ? labelId : void 0);
23
+ const resolvedDescribedBy = [
24
+ ariaDescribedBy,
25
+ description != null ? descriptionId : void 0,
26
+ hasError ? errorId : void 0
27
+ ].filter(Boolean).join(" ") || void 0;
28
+ const isConfigurationInvalid = useMemo(() => {
29
+ const min = parseTime(minTime);
30
+ const max = parseTime(maxTime);
31
+ return minTime != null && min === null || maxTime != null && max === null || min !== null && max !== null && min > max || !Number.isInteger(minuteStep) || minuteStep < 1 || minuteStep > 60 || !Number.isInteger(secondStep) || secondStep < 1 || secondStep > 60;
32
+ }, [
33
+ minTime,
34
+ maxTime,
35
+ minuteStep,
36
+ secondStep
37
+ ]);
38
+ const step = showSeconds ? secondStep : minuteStep * 60;
39
+ const handleChange = (event) => {
40
+ const nextValue = normalizeTime(event.currentTarget.value, showSeconds);
41
+ onChange?.(nextValue);
42
+ };
43
+ const inputValue = selectedValue ?? "";
44
+ return /* @__PURE__ */ jsxs("div", {
45
+ className: cn("puzzle-time-picker", rootClassName),
46
+ "data-disabled": disabled ? "true" : void 0,
47
+ "data-readonly": readOnly ? "true" : void 0,
48
+ "data-invalid": isInvalid ? "true" : void 0,
49
+ "data-size-mobile": responsiveSize.mobile,
50
+ "data-size-tablet": responsiveSize.tablet,
51
+ "data-size-desktop": responsiveSize.desktop,
52
+ "data-full-width-mobile": String(responsiveFullWidth.mobile),
53
+ "data-full-width-tablet": String(responsiveFullWidth.tablet),
54
+ "data-full-width-desktop": String(responsiveFullWidth.desktop),
55
+ children: [
56
+ label != null && /* @__PURE__ */ jsxs("label", {
57
+ id: labelId,
58
+ className: "puzzle-time-picker__label",
59
+ htmlFor: inputId,
60
+ children: [label, required && /* @__PURE__ */ jsx("span", {
61
+ className: "puzzle-time-picker__required",
62
+ "aria-hidden": "true",
63
+ children: "*"
64
+ })]
65
+ }),
66
+ /* @__PURE__ */ jsx("input", {
67
+ ...inputProps,
68
+ id: inputId,
69
+ type: "time",
70
+ name,
71
+ form,
72
+ value: isControlled ? inputValue : void 0,
73
+ defaultValue: !isControlled ? inputValue : void 0,
74
+ disabled: disabled || isConfigurationInvalid,
75
+ readOnly,
76
+ required,
77
+ min: minTime,
78
+ max: maxTime,
79
+ step,
80
+ style,
81
+ className: cn("puzzle-time-picker__input", className),
82
+ onChange: handleChange,
83
+ onBlur,
84
+ onFocus,
85
+ onInvalid,
86
+ "aria-label": ariaLabel,
87
+ "aria-labelledby": resolvedLabelledBy,
88
+ "aria-describedby": resolvedDescribedBy,
89
+ "aria-invalid": resolvedAriaInvalid,
90
+ "aria-required": required || void 0
91
+ }),
92
+ description != null && /* @__PURE__ */ jsx("div", {
93
+ id: descriptionId,
94
+ className: "puzzle-time-picker__description",
95
+ children: description
96
+ }),
97
+ hasError && /* @__PURE__ */ jsx("div", {
98
+ id: errorId,
99
+ className: "puzzle-time-picker__error",
100
+ role: "alert",
101
+ children: errorContent
102
+ })
103
+ ]
104
+ });
105
+ };
106
+ export { TimePicker };
107
+
108
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/forms/time-picker/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { useId, useMemo, type ChangeEvent } from \"react\";\n\nimport { cn, resolveResponsiveValue } from \"@puzzle-ui/core\";\n\nimport { normalizeTime, parseTime } from \"./time-picker.utils\";\n\nimport type { TimePickerProps } from \"./time-picker.types\";\n\nimport \"./time-picker.css\";\n\nconst TimePicker = ({\n value,\n defaultValue,\n onChange,\n label,\n description,\n error,\n disabled = false,\n readOnly = false,\n required = false,\n name,\n form,\n minTime,\n maxTime,\n minuteStep = 1,\n showSeconds = false,\n secondStep = 1,\n size = \"md\",\n fullWidth = false,\n rootClassName,\n className,\n id,\n style,\n onBlur,\n onFocus,\n onInvalid,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n ...inputProps\n}: TimePickerProps) => {\n const baseId = useId();\n\n const inputId = id ?? `${baseId}-input`;\n const labelId = `${baseId}-label`;\n const descriptionId = `${baseId}-description`;\n const errorId = `${baseId}-error`;\n\n const isControlled = value !== undefined;\n\n const selectedValue = normalizeTime(\n isControlled ? value : defaultValue,\n showSeconds,\n );\n\n const responsiveSize = resolveResponsiveValue(size, \"md\");\n const responsiveFullWidth = resolveResponsiveValue(fullWidth, false);\n\n const hasError = error !== undefined && error !== null && error !== false;\n\n const isAriaInvalid =\n ariaInvalid !== undefined &&\n ariaInvalid !== false &&\n ariaInvalid !== \"false\";\n\n const isInvalid = hasError || isAriaInvalid;\n\n const resolvedAriaInvalid = isInvalid ? true : ariaInvalid;\n\n const errorContent = error === true ? \"Invalid time\" : error;\n\n const resolvedLabelledBy =\n ariaLabelledBy ?? (label != null ? labelId : undefined);\n\n const resolvedDescribedBy =\n [\n ariaDescribedBy,\n description != null ? descriptionId : undefined,\n hasError ? errorId : undefined,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n const isConfigurationInvalid = useMemo(() => {\n const min = parseTime(minTime);\n const max = parseTime(maxTime);\n\n return (\n (minTime != null && min === null) ||\n (maxTime != null && max === null) ||\n (min !== null && max !== null && min > max) ||\n !Number.isInteger(minuteStep) ||\n minuteStep < 1 ||\n minuteStep > 60 ||\n !Number.isInteger(secondStep) ||\n secondStep < 1 ||\n secondStep > 60\n );\n }, [minTime, maxTime, minuteStep, secondStep]);\n\n const step = showSeconds ? secondStep : minuteStep * 60;\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = normalizeTime(event.currentTarget.value, showSeconds);\n\n onChange?.(nextValue);\n };\n\n const inputValue = selectedValue ?? \"\";\n\n return (\n <div\n className={cn(\"puzzle-time-picker\", rootClassName)}\n data-disabled={disabled ? \"true\" : undefined}\n data-readonly={readOnly ? \"true\" : undefined}\n data-invalid={isInvalid ? \"true\" : undefined}\n data-size-mobile={responsiveSize.mobile}\n data-size-tablet={responsiveSize.tablet}\n data-size-desktop={responsiveSize.desktop}\n data-full-width-mobile={String(responsiveFullWidth.mobile)}\n data-full-width-tablet={String(responsiveFullWidth.tablet)}\n data-full-width-desktop={String(responsiveFullWidth.desktop)}\n >\n {label != null && (\n <label\n id={labelId}\n className=\"puzzle-time-picker__label\"\n htmlFor={inputId}\n >\n {label}\n {required && (\n <span className=\"puzzle-time-picker__required\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <input\n {...inputProps}\n id={inputId}\n type=\"time\"\n name={name}\n form={form}\n value={isControlled ? inputValue : undefined}\n defaultValue={!isControlled ? inputValue : undefined}\n disabled={disabled || isConfigurationInvalid}\n readOnly={readOnly}\n required={required}\n min={minTime}\n max={maxTime}\n step={step}\n style={style}\n className={cn(\"puzzle-time-picker__input\", className)}\n onChange={handleChange}\n onBlur={onBlur}\n onFocus={onFocus}\n onInvalid={onInvalid}\n aria-label={ariaLabel}\n aria-labelledby={resolvedLabelledBy}\n aria-describedby={resolvedDescribedBy}\n aria-invalid={resolvedAriaInvalid}\n aria-required={required || undefined}\n />\n\n {description != null && (\n <div id={descriptionId} className=\"puzzle-time-picker__description\">\n {description}\n </div>\n )}\n\n {hasError && (\n <div id={errorId} className=\"puzzle-time-picker__error\" role=\"alert\">\n {errorContent}\n </div>\n )}\n </div>\n );\n};\n\nexport { TimePicker };\nexport type { TimePickerProps, TimePickerSize } from \"./time-picker.types\";\n"],"mappings":";;;;;;;AAYA,MAAM,cAAc,EAClB,OACA,cACA,UACA,OACA,aACA,OACA,WAAW,OACX,WAAW,OACX,WAAW,OACX,MACA,MACA,SACA,SACA,aAAa,GACb,cAAc,OACd,aAAa,GACb,OAAO,MACP,YAAY,OACZ,eACA,WACA,IACA,OACA,QACA,SACA,WACA,cAAc,WACd,mBAAmB,gBACnB,oBAAoB,iBACpB,gBAAgB,aAChB,GAAG,iBACkB;CACrB,MAAM,SAAS,MAAM;CAErB,MAAM,UAAU,MAAM,GAAG,OAAO;CAChC,MAAM,UAAU,GAAG,OAAO;CAC1B,MAAM,gBAAgB,GAAG,OAAO;CAChC,MAAM,UAAU,GAAG,OAAO;CAE1B,MAAM,eAAe,UAAU,KAAA;CAE/B,MAAM,gBAAgB,cACpB,eAAe,QAAQ,cACvB,WACF;CAEA,MAAM,iBAAiB,uBAAuB,MAAM,IAAI;CACxD,MAAM,sBAAsB,uBAAuB,WAAW,KAAK;CAEnE,MAAM,WAAW,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU;CAOpE,MAAM,YAAY,YAJhB,gBAAgB,KAAA,KAChB,gBAAgB,SAChB,gBAAgB;CAIlB,MAAM,sBAAsB,YAAY,OAAO;CAE/C,MAAM,eAAe,UAAU,OAAO,iBAAiB;CAEvD,MAAM,qBACJ,mBAAmB,SAAS,OAAO,UAAU,KAAA;CAE/C,MAAM,sBACJ;EACE;EACA,eAAe,OAAO,gBAAgB,KAAA;EACtC,WAAW,UAAU,KAAA;CACvB,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,KAAK,KAAA;CAElB,MAAM,yBAAyB,cAAc;EAC3C,MAAM,MAAM,UAAU,OAAO;EAC7B,MAAM,MAAM,UAAU,OAAO;EAE7B,OACG,WAAW,QAAQ,QAAQ,QAC3B,WAAW,QAAQ,QAAQ,QAC3B,QAAQ,QAAQ,QAAQ,QAAQ,MAAM,OACvC,CAAC,OAAO,UAAU,UAAU,KAC5B,aAAa,KACb,aAAa,MACb,CAAC,OAAO,UAAU,UAAU,KAC5B,aAAa,KACb,aAAa;CAEjB,GAAG;EAAC;EAAS;EAAS;EAAY;CAAU,CAAC;CAE7C,MAAM,OAAO,cAAc,aAAa,aAAa;CAErD,MAAM,gBAAgB,UAAyC;EAC7D,MAAM,YAAY,cAAc,MAAM,cAAc,OAAO,WAAW;EAEtE,WAAW,SAAS;CACtB;CAEA,MAAM,aAAa,iBAAiB;CAEpC,OACE,qBAAC,OAAD;EACE,WAAW,GAAG,sBAAsB,aAAa;EACjD,iBAAe,WAAW,SAAS,KAAA;EACnC,iBAAe,WAAW,SAAS,KAAA;EACnC,gBAAc,YAAY,SAAS,KAAA;EACnC,oBAAkB,eAAe;EACjC,oBAAkB,eAAe;EACjC,qBAAmB,eAAe;EAClC,0BAAwB,OAAO,oBAAoB,MAAM;EACzD,0BAAwB,OAAO,oBAAoB,MAAM;EACzD,2BAAyB,OAAO,oBAAoB,OAAO;EAV7D,UAAA;GAYG,SAAS,QACR,qBAAC,SAAD;IACE,IAAI;IACJ,WAAU;IACV,SAAS;IAHX,UAAA,CAKG,OACA,YACC,oBAAC,QAAD;KAAM,WAAU;KAA+B,eAAY;KAAO,UAAA;IAE5D,CAAA,CAEH;;GAGT,oBAAC,SAAD;IACE,GAAI;IACJ,IAAI;IACJ,MAAK;IACC;IACA;IACN,OAAO,eAAe,aAAa,KAAA;IACnC,cAAc,CAAC,eAAe,aAAa,KAAA;IAC3C,UAAU,YAAY;IACZ;IACA;IACV,KAAK;IACL,KAAK;IACC;IACC;IACP,WAAW,GAAG,6BAA6B,SAAS;IACpD,UAAU;IACF;IACC;IACE;IACX,cAAY;IACZ,mBAAiB;IACjB,oBAAkB;IAClB,gBAAc;IACd,iBAAe,YAAY,KAAA;GAC5B,CAAA;GAEA,eAAe,QACd,oBAAC,OAAD;IAAK,IAAI;IAAe,WAAU;IAC/B,UAAA;GACE,CAAA;GAGN,YACC,oBAAC,OAAD;IAAK,IAAI;IAAS,WAAU;IAA4B,MAAK;IAC1D,UAAA;GACE,CAAA;EAEJ;;AAET"}
@@ -0,0 +1,166 @@
1
+ .puzzle-time-picker {
2
+ --puzzle-time-picker-height: 2.5rem;
3
+ --puzzle-time-picker-padding: var(--puzzle-space-3, .75rem);
4
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-sm, .875rem);
5
+ gap: var(--puzzle-space-1, .25rem);
6
+ min-width: 0;
7
+ color: var(--puzzle-color-text);
8
+ flex-direction: column;
9
+ font-family: inherit;
10
+ display: inline-flex;
11
+ }
12
+
13
+ .puzzle-time-picker[data-size-mobile="sm"] {
14
+ --puzzle-time-picker-height: 2rem;
15
+ --puzzle-time-picker-padding: var(--puzzle-space-2, .5rem);
16
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-xs, .75rem);
17
+ }
18
+
19
+ .puzzle-time-picker[data-size-mobile="md"] {
20
+ --puzzle-time-picker-height: 2.5rem;
21
+ --puzzle-time-picker-padding: var(--puzzle-space-3, .75rem);
22
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-sm, .875rem);
23
+ }
24
+
25
+ .puzzle-time-picker[data-size-mobile="lg"] {
26
+ --puzzle-time-picker-height: 3rem;
27
+ --puzzle-time-picker-padding: var(--puzzle-space-4, 1rem);
28
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-base, 1rem);
29
+ }
30
+
31
+ @media (width >= 768px) {
32
+ .puzzle-time-picker[data-size-tablet="sm"] {
33
+ --puzzle-time-picker-height: 2rem;
34
+ --puzzle-time-picker-padding: var(--puzzle-space-2, .5rem);
35
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-xs, .75rem);
36
+ }
37
+
38
+ .puzzle-time-picker[data-size-tablet="md"] {
39
+ --puzzle-time-picker-height: 2.5rem;
40
+ --puzzle-time-picker-padding: var(--puzzle-space-3, .75rem);
41
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-sm, .875rem);
42
+ }
43
+
44
+ .puzzle-time-picker[data-size-tablet="lg"] {
45
+ --puzzle-time-picker-height: 3rem;
46
+ --puzzle-time-picker-padding: var(--puzzle-space-4, 1rem);
47
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-base, 1rem);
48
+ }
49
+
50
+ .puzzle-time-picker[data-full-width-tablet="true"] {
51
+ width: 100%;
52
+ }
53
+
54
+ .puzzle-time-picker[data-full-width-tablet="false"] {
55
+ width: auto;
56
+ }
57
+ }
58
+
59
+ @media (width >= 1024px) {
60
+ .puzzle-time-picker[data-size-desktop="sm"] {
61
+ --puzzle-time-picker-height: 2rem;
62
+ --puzzle-time-picker-padding: var(--puzzle-space-2, .5rem);
63
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-xs, .75rem);
64
+ }
65
+
66
+ .puzzle-time-picker[data-size-desktop="md"] {
67
+ --puzzle-time-picker-height: 2.5rem;
68
+ --puzzle-time-picker-padding: var(--puzzle-space-3, .75rem);
69
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-sm, .875rem);
70
+ }
71
+
72
+ .puzzle-time-picker[data-size-desktop="lg"] {
73
+ --puzzle-time-picker-height: 3rem;
74
+ --puzzle-time-picker-padding: var(--puzzle-space-4, 1rem);
75
+ --puzzle-time-picker-font-size: var(--puzzle-font-size-base, 1rem);
76
+ }
77
+
78
+ .puzzle-time-picker[data-full-width-desktop="true"] {
79
+ width: 100%;
80
+ }
81
+
82
+ .puzzle-time-picker[data-full-width-desktop="false"] {
83
+ width: auto;
84
+ }
85
+ }
86
+
87
+ .puzzle-time-picker[data-full-width-mobile="true"] {
88
+ width: 100%;
89
+ }
90
+
91
+ .puzzle-time-picker__label {
92
+ color: var(--puzzle-color-text);
93
+ font-size: var(--puzzle-font-size-sm, .875rem);
94
+ font-weight: var(--puzzle-font-weight-medium, 500);
95
+ line-height: var(--puzzle-font-line-height-body2, 1.4);
96
+ display: block;
97
+ }
98
+
99
+ .puzzle-time-picker__required {
100
+ color: var(--puzzle-color-danger);
101
+ margin-inline-start: .2em;
102
+ }
103
+
104
+ .puzzle-time-picker__input {
105
+ box-sizing: border-box;
106
+ width: 100%;
107
+ min-width: 0;
108
+ min-height: var(--puzzle-time-picker-height);
109
+ padding-inline: var(--puzzle-time-picker-padding);
110
+ border: 1px solid var(--puzzle-color-border);
111
+ border-radius: var(--puzzle-radius-md, .5rem);
112
+ color: var(--puzzle-color-text);
113
+ background: var(--puzzle-color-surface);
114
+ font-family: inherit;
115
+ font-size: var(--puzzle-time-picker-font-size);
116
+ line-height: var(--puzzle-font-line-height-body2, 1.4);
117
+ transition: background-color var(--puzzle-duration-fast, .15s) ease,
118
+ border-color var(--puzzle-duration-fast, .15s) ease,
119
+ box-shadow var(--puzzle-duration-fast, .15s) ease;
120
+ display: block;
121
+ }
122
+
123
+ .puzzle-time-picker__input:hover:not(:disabled) {
124
+ border-color: var(--puzzle-color-border-strong, var(--puzzle-color-border));
125
+ }
126
+
127
+ .puzzle-time-picker__input:focus-visible {
128
+ outline: 2px solid var(--puzzle-color-ring);
129
+ outline-offset: 2px;
130
+ border-color: var(--puzzle-color-primary);
131
+ }
132
+
133
+ .puzzle-time-picker[data-invalid="true"] .puzzle-time-picker__input {
134
+ border-color: var(--puzzle-color-danger);
135
+ }
136
+
137
+ .puzzle-time-picker[data-invalid="true"] .puzzle-time-picker__input:focus-visible {
138
+ outline-color: var(--puzzle-color-danger);
139
+ }
140
+
141
+ .puzzle-time-picker__input:disabled {
142
+ opacity: .55;
143
+ cursor: not-allowed;
144
+ }
145
+
146
+ .puzzle-time-picker__input:read-only {
147
+ cursor: default;
148
+ }
149
+
150
+ .puzzle-time-picker__description {
151
+ color: var(--puzzle-color-text-muted);
152
+ font-size: var(--puzzle-font-size-xs, .75rem);
153
+ line-height: var(--puzzle-font-line-height-body2, 1.4);
154
+ }
155
+
156
+ .puzzle-time-picker__error {
157
+ color: var(--puzzle-color-danger);
158
+ font-size: var(--puzzle-font-size-xs, .75rem);
159
+ line-height: var(--puzzle-font-line-height-body2, 1.4);
160
+ }
161
+
162
+ @media (prefers-reduced-motion: reduce) {
163
+ .puzzle-time-picker__input {
164
+ transition: none;
165
+ }
166
+ }
@@ -0,0 +1,34 @@
1
+ import { InputHTMLAttributes, ReactNode } from "react";
2
+ import { ResponsiveValue } from "@puzzle-ui/core";
3
+ type TimePickerSize = "sm" | "md" | "lg";
4
+ type TimePickerProps = Omit<InputHTMLAttributes<HTMLInputElement>, "children" | "type" | "value" | "defaultValue" | "onChange" | "size" | "min" | "max" | "step"> & {
5
+ /** Selected time in HH:mm or HH:mm:ss format. */
6
+ value?: string | null;
7
+ /** Initial selected time for uncontrolled usage. */
8
+ defaultValue?: string | null;
9
+ /** Called whenever the selected time changes. */
10
+ onChange?: (value: string | null) => void;
11
+ /** Visible field label. */
12
+ label?: ReactNode;
13
+ /** Supporting text displayed below the control. */
14
+ description?: ReactNode;
15
+ /** Validation error. Set to true to use the default message. */
16
+ error?: ReactNode | boolean;
17
+ /** Earliest selectable time, inclusive. */
18
+ minTime?: string;
19
+ /** Latest selectable time, inclusive. */
20
+ maxTime?: string;
21
+ /** Minute interval when seconds are hidden. */
22
+ minuteStep?: number;
23
+ /** Display seconds in the time input. */
24
+ showSeconds?: boolean;
25
+ /** Second interval when seconds are displayed. */
26
+ secondStep?: number;
27
+ /** Responsive input size. */
28
+ size?: ResponsiveValue<TimePickerSize>;
29
+ /** Responsive full-width layout. */
30
+ fullWidth?: ResponsiveValue<boolean>;
31
+ /** Additional class applied to the outer field. */
32
+ rootClassName?: string;
33
+ };
34
+ export type { TimePickerProps, TimePickerSize };
@@ -0,0 +1,34 @@
1
+ import { ResponsiveValue } from "@puzzle-ui/core";
2
+ import { InputHTMLAttributes, ReactNode } from "react";
3
+ type TimePickerSize = "sm" | "md" | "lg";
4
+ type TimePickerProps = Omit<InputHTMLAttributes<HTMLInputElement>, "children" | "type" | "value" | "defaultValue" | "onChange" | "size" | "min" | "max" | "step"> & {
5
+ /** Selected time in HH:mm or HH:mm:ss format. */
6
+ value?: string | null;
7
+ /** Initial selected time for uncontrolled usage. */
8
+ defaultValue?: string | null;
9
+ /** Called whenever the selected time changes. */
10
+ onChange?: (value: string | null) => void;
11
+ /** Visible field label. */
12
+ label?: ReactNode;
13
+ /** Supporting text displayed below the control. */
14
+ description?: ReactNode;
15
+ /** Validation error. Set to true to use the default message. */
16
+ error?: ReactNode | boolean;
17
+ /** Earliest selectable time, inclusive. */
18
+ minTime?: string;
19
+ /** Latest selectable time, inclusive. */
20
+ maxTime?: string;
21
+ /** Minute interval when seconds are hidden. */
22
+ minuteStep?: number;
23
+ /** Display seconds in the time input. */
24
+ showSeconds?: boolean;
25
+ /** Second interval when seconds are displayed. */
26
+ secondStep?: number;
27
+ /** Responsive input size. */
28
+ size?: ResponsiveValue<TimePickerSize>;
29
+ /** Responsive full-width layout. */
30
+ fullWidth?: ResponsiveValue<boolean>;
31
+ /** Additional class applied to the outer field. */
32
+ rootClassName?: string;
33
+ };
34
+ export type { TimePickerProps, TimePickerSize };