@puzzle-ui/ui 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -70
- package/dist/components/data-display/empty-state/empty-state.css +128 -0
- package/dist/components/data-display/empty-state/empty-state.utils.cjs +6 -0
- package/dist/components/data-display/empty-state/empty-state.utils.cjs.map +1 -0
- package/dist/components/data-display/empty-state/empty-state.utils.js +6 -0
- package/dist/components/data-display/empty-state/empty-state.utils.js.map +1 -0
- package/dist/components/data-display/empty-state/index.cjs +49 -0
- package/dist/components/data-display/empty-state/index.cjs.map +1 -0
- package/dist/components/data-display/empty-state/index.d.cts +19 -0
- package/dist/components/data-display/empty-state/index.d.ts +19 -0
- package/dist/components/data-display/empty-state/index.js +44 -0
- package/dist/components/data-display/empty-state/index.js.map +1 -0
- package/dist/components/editors/text-editor/editor.cjs.map +1 -1
- package/dist/components/editors/text-editor/editor.js.map +1 -1
- package/dist/components/editors/text-editor/text-document.cjs.map +1 -1
- package/dist/components/editors/text-editor/text-document.js.map +1 -1
- package/dist/components/editors/text-editor/text-parser.cjs.map +1 -1
- package/dist/components/editors/text-editor/text-parser.js.map +1 -1
- package/dist/components/editors/text-editor/text-renderer.cjs.map +1 -1
- package/dist/components/editors/text-editor/text-renderer.js.map +1 -1
- package/dist/components/forms/autocomplete/index.cjs.map +1 -1
- package/dist/components/forms/autocomplete/index.js.map +1 -1
- package/dist/components/forms/color-picker/color-picker.css +351 -0
- package/dist/components/forms/color-picker/color-picker.types.d.cts +25 -0
- package/dist/components/forms/color-picker/color-picker.types.d.ts +25 -0
- package/dist/components/forms/color-picker/color-picker.utils.cjs +116 -0
- package/dist/components/forms/color-picker/color-picker.utils.cjs.map +1 -0
- package/dist/components/forms/color-picker/color-picker.utils.js +109 -0
- package/dist/components/forms/color-picker/color-picker.utils.js.map +1 -0
- package/dist/components/forms/color-picker/index.cjs +340 -0
- package/dist/components/forms/color-picker/index.cjs.map +1 -0
- package/dist/components/forms/color-picker/index.d.cts +3 -0
- package/dist/components/forms/color-picker/index.d.ts +3 -0
- package/dist/components/forms/color-picker/index.js +340 -0
- package/dist/components/forms/color-picker/index.js.map +1 -0
- package/dist/components/forms/file-upload/file-upload.utils.cjs.map +1 -1
- package/dist/components/forms/file-upload/file-upload.utils.js.map +1 -1
- package/dist/components/forms/input/number-input.js +5 -5
- package/dist/components/forms/input/number-input.js.map +1 -1
- package/dist/components/forms/input-group/index.d.cts +3 -0
- package/dist/components/forms/input-group/index.d.ts +3 -0
- package/dist/components/forms/input-group/input-group.cjs +18 -0
- package/dist/components/forms/input-group/input-group.cjs.map +1 -0
- package/dist/components/forms/input-group/input-group.css +62 -0
- package/dist/components/forms/input-group/input-group.d.cts +5 -0
- package/dist/components/forms/input-group/input-group.d.ts +5 -0
- package/dist/components/forms/input-group/input-group.js +18 -0
- package/dist/components/forms/input-group/input-group.js.map +1 -0
- package/dist/components/forms/input-group/input-group.types.d.cts +7 -0
- package/dist/components/forms/input-group/input-group.types.d.ts +7 -0
- package/dist/components/forms/input-group/input-group.utils.cjs +5 -0
- package/dist/components/forms/input-group/input-group.utils.cjs.map +1 -0
- package/dist/components/forms/input-group/input-group.utils.js +5 -0
- package/dist/components/forms/input-group/input-group.utils.js.map +1 -0
- package/dist/components/forms/select/index.cjs.map +1 -1
- package/dist/components/forms/select/index.js.map +1 -1
- package/dist/components/forms/slider/index.cjs +1 -1
- package/dist/components/forms/slider/index.cjs.map +1 -1
- package/dist/components/forms/slider/index.js +1 -1
- package/dist/components/forms/slider/index.js.map +1 -1
- package/dist/components/layout/resizable-panels/index.cjs +1 -1
- package/dist/components/layout/resizable-panels/index.cjs.map +1 -1
- package/dist/components/layout/resizable-panels/index.js +1 -1
- package/dist/components/layout/resizable-panels/index.js.map +1 -1
- package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs.map +1 -1
- package/dist/components/layout/resizable-panels/resizable-panels.utils.js.map +1 -1
- package/dist/components/navigation/accordion/index.cjs.map +1 -1
- package/dist/components/navigation/accordion/index.js.map +1 -1
- package/dist/components/navigation/carousel/index.cjs +1 -1
- package/dist/components/navigation/carousel/index.cjs.map +1 -1
- package/dist/components/navigation/carousel/index.js +1 -1
- package/dist/components/navigation/carousel/index.js.map +1 -1
- package/dist/components/navigation/pagination/index.cjs +146 -0
- package/dist/components/navigation/pagination/index.cjs.map +1 -0
- package/dist/components/navigation/pagination/index.d.cts +3 -0
- package/dist/components/navigation/pagination/index.d.ts +3 -0
- package/dist/components/navigation/pagination/index.js +146 -0
- package/dist/components/navigation/pagination/index.js.map +1 -0
- package/dist/components/navigation/pagination/pagination.css +134 -0
- package/dist/components/navigation/pagination/pagination.types.d.cts +38 -0
- package/dist/components/navigation/pagination/pagination.types.d.ts +38 -0
- package/dist/components/navigation/pagination/pagination.utils.cjs +54 -0
- package/dist/components/navigation/pagination/pagination.utils.cjs.map +1 -0
- package/dist/components/navigation/pagination/pagination.utils.js +53 -0
- package/dist/components/navigation/pagination/pagination.utils.js.map +1 -0
- package/dist/components/navigation/tree-view/index.cjs.map +1 -1
- package/dist/components/navigation/tree-view/index.js.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.cjs.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.js.map +1 -1
- package/dist/components/utilities/preview/index.cjs +1 -1
- package/dist/components/utilities/preview/index.cjs.map +1 -1
- package/dist/components/utilities/preview/index.js +1 -1
- package/dist/components/utilities/preview/index.js.map +1 -1
- package/dist/index.cjs +110 -97
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +5 -1
- package/package.json +6 -5
|
@@ -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":";;;;;;AA0EA,MAAM,gBAAgB,UAAkB;CACtC,MAAM,CAAC,
|
|
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":";;;;;;AA0EA,MAAM,gBAAgB,UAAkB;CACtC,MAAM,CAAC,cAAc,IAAI,WAAW,OAAO,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG;CAEhF,MAAM,WAAW,YAAY,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,UAAU;CAEtD,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,WAAW,OAAO,QAAQ,CAAC,CAAC;AAC9D;AAEA,MAAM,wBACJ,OACA,KACA,KACA,SACG;CACH,IAAI,OAAO,KACT,OAAO;CAGT,MAAM,eAAe,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;CAEvD,IAAI,SAAS,OACX,OAAO;CAIT,MAAM,SAAS,MADG,KAAK,IAAI,aAAa,GAAG,GAAG,aAAa,IAAI,CAClC;CAE7B,MAAM,eAAe,MAAM,KAAK,OAAO,eAAe,OAAO,IAAI,IAAI;CAErE,OAAO,KAAK,IACV,KACA,KAAK,IAAI,KAAK,KAAK,MAAM,eAAe,MAAM,IAAI,MAAM,CAC1D;AACF;AAEA,MAAM,UAAU,EACd,OACA,cACA,UACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,OAAO,MACP,OACA,YAAY,OACZ,aACA,WACA,IACA,KACA,WAAW,OACX,OACA,gBAAgB,aAChB,kBAAkB,eAClB,GAAG,iBACc;CACjB,MAAM,eAAA,GAAcA,MAAAA,MAAAA,CAAM;CAC1B,MAAM,UAAU,MAAM;CAEtB,MAAM,cAAc,OAAO,SAAS,GAAG,IAAI,MAAM;CAGjD,MAAM,cAAc,KAAK,IAAI,aADR,OAAO,SAAS,GAAG,IAAI,MAAM,GACI;CAEtD,MAAM,eACJ,SAAS,QAAQ,QAAQ,OAAO,SAAS,IAAI,KAAK,OAAO,IAAI,OAAO;CAEtE,MAAM,eAAe,UAAU,KAAA;CAE/B,MAAM,CAAC,eAAe,qBAAA,GAAoBC,MAAAA,SAAAA,OACxC,qBACE,iBAAiB,cAAc,eAAe,GAC9C,aACA,aACA,YACF,CACF;CAEA,MAAM,eAAe,qBACnB,eAAe,QAAQ,eACvB,aACA,aACA,YACF;CAEA,MAAM,WACJ,cAAc,eACR,eAAe,gBAAgB,cAAc,eAAgB,MAC/D;CAEN,MAAM,iBAAiB,cAAc,YAAY;CAEjD,MAAM,YAAY,gBAAgB,QAAQ,gBAAgB;CAE1D,MAAM,iBAAiB,SAAS,CAAC,EAAA,CAC9B,QACE,SACC,OAAO,SAAS,KAAK,KAAK,KAC1B,KAAK,SAAS,eACd,KAAK,SAAS,WAClB,CAAC,CACA,MAAM,CAAC,CACP,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;CAEnC,MAAM,gBAAgB,cAAc,MAAM,SAAS,KAAK,SAAS,IAAI;CAErE,MAAM,gBAAgB,UAAyC;EAC7D,MAAM,YAAY,qBAChB,MAAM,cAAc,eACpB,aACA,aACA,YACF;EAEA,IAAI,CAAC,cACH,iBAAiB,SAAS;EAG5B,WAAW,SAAS;CACtB;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EACE,YAAA,GAAWC,gBAAAA,GAAAA,CAAG,iBAAiB,SAAS;EACxC,aAAW;EACX,iBAAe,YAAY,KAAA;EAC3B,gBAAc,aAAa,KAAA;EAJ7B,UAAA;GAMG,aACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,SAAS;IAAS,WAAU;IACjC,UAAA,kBAAkB;GACb,CAAA;GAGV,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;IACE,GAAI;IACC;IACL,IAAI;IACJ,WAAU;IACV,MAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,OAAO;IACG;IACV,gBAAc;IACd,kBAAgB,iBAAiB;IACjC,OACE;KACE,GAAG;KACH,4BAA4B,GAAG,SAAS;IAC1C;IAEF,UAAU;GACX,CAAA;GAEA,cAAc,SAAS,KACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IACE,WAAU;IACV,mBAAiB,iBAAiB,KAAA;IAEjC,UAAA,cAAc,KAAK,MAAM,UAAU;KAClC,MAAM,WACJ,cAAc,eACR,KAAK,QAAQ,gBAAgB,cAAc,eAC7C,MACA;KAEN,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAEE,WAAU;MACV,aACE,UAAU,IACN,UACA,UAAU,cAAc,SAAS,IAC/B,QACA,KAAA;MAER,OAAO,EACL,kBAAkB,GAAG,SAAS,GAChC;MAZF,UAAA,CAcE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAU;OAA2B,eAAY;MAAQ,CAAA,GAE9D,KAAK,SAAS,QACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAU;OACb,UAAA,KAAK;MACF,CAAA,CAEJ;KApBC,GAAA,GAAG,KAAK,MAAM,GAAG,OAoBlB;IAEV,CAAC;GACE,CAAA;EAEJ;;AAET"}
|
|
@@ -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":";;;;;;AA0EA,MAAM,gBAAgB,UAAkB;CACtC,MAAM,CAAC,
|
|
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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"}
|
|
@@ -115,7 +115,7 @@ const ResizablePanelsRoot = ({ children, orientation = "horizontal", sizes, defa
|
|
|
115
115
|
const pointerDragRef = (0, react.useRef)(null);
|
|
116
116
|
const updateSizes = (nextSizes) => {
|
|
117
117
|
const normalized = require_resizable_panels_utils.normalizePanelSizes(nextSizes, panelConstraints);
|
|
118
|
-
if (!normalized.some((size, index) => Math.abs(size - currentSizes[index]) > 1e-6)) return;
|
|
118
|
+
if (!normalized.some((size, index) => Math.abs(size - (currentSizes[index] ?? 0)) > 1e-6)) return;
|
|
119
119
|
if (sizes === void 0) setUncontrolledSizes(normalized);
|
|
120
120
|
onSizesChange?.(normalized);
|
|
121
121
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["isValidElement","cn","useId","Children","useState","normalizePanelSizes","useRef","resizePanelPair","getPanelPairBounds","cloneElement"],"sources":["../../../../src/components/layout/resizable-panels/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport {\n Children,\n cloneElement,\n isValidElement,\n useId,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\nimport {\n getPanelPairBounds,\n normalizePanelSizes,\n resizePanelPair,\n type PanelSizeConstraint,\n} from \"./resizable-panels.utils\";\n\nimport \"./resizable-panels.css\";\n\ntype ResizablePanelsOrientation = \"horizontal\" | \"vertical\";\n\ntype ResizablePanelsProps = Omit<ComponentPropsWithRef<\"div\">, \"children\"> & {\n /** Layout direction. Defaults to horizontal. */\n orientation?: ResizablePanelsOrientation;\n\n /** Controlled panel sizes, expressed as percentages. */\n sizes?: readonly number[];\n\n /** Initial panel sizes for uncontrolled usage. */\n defaultSizes?: readonly number[];\n\n /** Called whenever the panel layout changes. */\n onSizesChange?: (sizes: number[]) => void;\n\n /** Disables all resizing interactions. */\n disabled?: boolean;\n\n /** Percentage change per keyboard interaction. Defaults to 1. */\n keyboardStep?: number;\n\n /** Panels and handles that make up the group. */\n children: ReactNode;\n};\n\ntype ResizablePanelProps = ComponentPropsWithRef<\"div\"> & {\n /** Minimum panel size in percentages. Defaults to 0. */\n minSize?: number;\n\n /** Maximum panel size in percentages. Defaults to 100. */\n maxSize?: number;\n};\n\ntype ResizableHandleProps = ComponentPropsWithRef<\"div\"> & {\n /** Renders a visible grip inside the resize handle. */\n withGrip?: boolean;\n\n /** Disables resizing through this handle. */\n disabled?: boolean;\n};\n\ntype ResizePointerHandler = (\n event: ReactPointerEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype ResizeKeyboardHandler = (\n event: ReactKeyboardEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype InternalResizablePanelProps = {\n panelIndex?: number;\n panelSize?: number;\n panelId?: string;\n};\n\ntype InternalResizableHandleProps = {\n handleIndex?: number;\n orientation?: ResizablePanelsOrientation;\n value?: number;\n minValue?: number;\n maxValue?: number;\n panelIds?: [string, string];\n inheritedDisabled?: boolean;\n\n onResizeStart?: ResizePointerHandler;\n onResizeMove?: ResizePointerHandler;\n onResizeEnd?: ResizePointerHandler;\n onResizeKeyDown?: ResizeKeyboardHandler;\n};\n\ntype PointerDragState = {\n handleIndex: number;\n pointerId: number;\n startCoordinate: number;\n availableSize: number;\n direction: number;\n sizes: number[];\n};\n\nconst isResizablePanelElement = (\n child: ReactNode,\n): child is ReactElement<ResizablePanelProps> =>\n isValidElement(child) && child.type === ResizablePanel;\n\nconst isResizableHandleElement = (\n child: ReactNode,\n): child is ReactElement<ResizableHandleProps> =>\n isValidElement(child) && child.type === ResizableHandle;\n\nconst parsePixels = (value: string | undefined) =>\n Number.parseFloat(value ?? \"\") || 0;\n\nconst getAvailableSize = (\n group: HTMLDivElement,\n orientation: ResizablePanelsOrientation,\n) => {\n const computedStyle =\n group.ownerDocument.defaultView?.getComputedStyle(group);\n\n const isHorizontal = orientation === \"horizontal\";\n\n const totalSize = isHorizontal ? group.clientWidth : group.clientHeight;\n\n const paddingSize = computedStyle\n ? isHorizontal\n ? parsePixels(computedStyle.paddingLeft) +\n parsePixels(computedStyle.paddingRight)\n : parsePixels(computedStyle.paddingTop) +\n parsePixels(computedStyle.paddingBottom)\n : 0;\n\n const handleSize = Array.from(group.children).reduce((total, child) => {\n const element = child as HTMLElement;\n\n if (!element.hasAttribute(\"data-puzzle-resizable-handle\")) {\n return total;\n }\n\n const rect = element.getBoundingClientRect();\n\n return total + (isHorizontal ? rect.width : rect.height);\n }, 0);\n\n return Math.max(0, totalSize - paddingSize - handleSize);\n};\n\nconst getResizeDirection = (\n element: HTMLElement,\n orientation: ResizablePanelsOrientation,\n) => {\n if (orientation !== \"horizontal\") {\n return 1;\n }\n\n const direction =\n element.ownerDocument.defaultView?.getComputedStyle(element).direction;\n\n return direction === \"rtl\" ? -1 : 1;\n};\n\nconst getPointerCoordinate = (\n event: ReactPointerEvent<HTMLDivElement>,\n orientation: ResizablePanelsOrientation,\n) => (orientation === \"horizontal\" ? event.clientX : event.clientY);\n\nconst ResizablePanel = ({\n id,\n minSize = 0,\n maxSize = 100,\n panelIndex = 0,\n panelSize = 1,\n panelId,\n className,\n style,\n ...props\n}: ResizablePanelProps & InternalResizablePanelProps) => (\n <div\n {...props}\n id={panelId ?? id}\n className={cn(\"puzzle-resizable-panels__panel\", className)}\n style={{\n ...style,\n flex: `${panelSize} 1 0%`,\n }}\n data-panel-index={panelIndex}\n data-panel-size={panelSize}\n data-panel-min-size={minSize}\n data-panel-max-size={maxSize}\n />\n);\n\nconst ResizableHandle = ({\n withGrip = false,\n disabled = false,\n handleIndex = -1,\n orientation = \"horizontal\",\n value,\n minValue,\n maxValue,\n panelIds,\n inheritedDisabled = false,\n onResizeStart,\n onResizeMove,\n onResizeEnd,\n onResizeKeyDown,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n onLostPointerCapture,\n onKeyDown,\n className,\n children,\n tabIndex,\n \"aria-label\": ariaLabel,\n ...props\n}: ResizableHandleProps & InternalResizableHandleProps) => {\n const isDisabled = disabled || inheritedDisabled;\n\n const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeStart?.(event, handleIndex);\n }\n };\n\n const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerMove?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeMove?.(event, handleIndex);\n }\n };\n\n const handlePointerUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerUp?.(event);\n };\n\n const handlePointerCancel = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerCancel?.(event);\n };\n\n const handleLostPointerCapture = (\n event: ReactPointerEvent<HTMLDivElement>,\n ) => {\n onResizeEnd?.(event, handleIndex);\n onLostPointerCapture?.(event);\n };\n\n const handleKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeKeyDown?.(event, handleIndex);\n }\n };\n\n return (\n <div\n {...props}\n className={cn(\"puzzle-resizable-panels__handle\", className)}\n role=\"separator\"\n tabIndex={isDisabled ? -1 : (tabIndex ?? 0)}\n aria-label={ariaLabel ?? \"Resize panels\"}\n aria-orientation={\n orientation === \"horizontal\" ? \"vertical\" : \"horizontal\"\n }\n aria-controls={panelIds?.join(\" \")}\n aria-valuenow={value}\n aria-valuemin={minValue}\n aria-valuemax={maxValue}\n aria-valuetext={\n value === undefined ? undefined : `${Math.round(value * 100) / 100}%`\n }\n aria-disabled={isDisabled || undefined}\n data-puzzle-resizable-handle=\"\"\n data-orientation={orientation}\n data-disabled={isDisabled ? \"true\" : undefined}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerCancel}\n onLostPointerCapture={handleLostPointerCapture}\n onKeyDown={handleKeyDown}\n >\n {withGrip ? (\n <span\n className=\"puzzle-resizable-panels__handle-grip\"\n aria-hidden=\"true\"\n />\n ) : (\n children\n )}\n </div>\n );\n};\n\nconst ResizablePanelsRoot = ({\n children,\n orientation = \"horizontal\",\n sizes,\n defaultSizes,\n onSizesChange,\n disabled = false,\n keyboardStep = 1,\n id,\n role,\n className,\n style,\n ref: forwardedRef,\n ...rootProps\n}: ResizablePanelsProps) => {\n const generatedId = useId();\n\n const groupId = id ?? `puzzle-resizable-panels-${generatedId}`;\n\n if (!Number.isFinite(keyboardStep) || keyboardStep <= 0) {\n throw new RangeError(\"keyboardStep must be a positive finite number.\");\n }\n\n const childrenArray = Children.toArray(children);\n\n const validChildren =\n childrenArray.length >= 3 &&\n childrenArray.length % 2 === 1 &&\n childrenArray.every((child, index) =>\n index % 2 === 0\n ? isResizablePanelElement(child)\n : isResizableHandleElement(child),\n );\n\n if (!validChildren) {\n throw new Error(\n \"ResizablePanels requires alternating Panel and Handle children, starting and ending with a Panel. At least two panels are required.\",\n );\n }\n\n const panelElements = childrenArray.filter(isResizablePanelElement);\n\n const panelCount = panelElements.length;\n\n const panelConstraints: PanelSizeConstraint[] = panelElements.map(\n (panel) => ({\n minSize: panel.props.minSize,\n maxSize: panel.props.maxSize,\n }),\n );\n\n const panelIds = panelElements.map(\n (panel, index) => panel.props.id ?? `${groupId}-panel-${index}`,\n );\n\n if (new Set(panelIds).size !== panelIds.length) {\n throw new Error(\"ResizablePanels requires unique panel IDs.\");\n }\n\n const [uncontrolledSizes, setUncontrolledSizes] = useState<number[]>(() =>\n normalizePanelSizes(\n sizes === undefined ? defaultSizes : undefined,\n panelConstraints,\n ),\n );\n\n const layoutInput =\n sizes ??\n (uncontrolledSizes.length === panelCount ? uncontrolledSizes : undefined);\n\n const currentSizes = normalizePanelSizes(layoutInput, panelConstraints);\n\n const [isResizing, setIsResizing] = useState(false);\n\n const groupRef = useRef<HTMLDivElement | null>(null);\n\n const pointerDragRef = useRef<PointerDragState | null>(null);\n\n const updateSizes = (nextSizes: readonly number[]) => {\n const normalized = normalizePanelSizes(nextSizes, panelConstraints);\n\n const hasChanged = normalized.some(\n (size, index) => Math.abs(size - currentSizes[index]) > 0.000001,\n );\n\n if (!hasChanged) {\n return;\n }\n\n if (sizes === undefined) {\n setUncontrolledSizes(normalized);\n }\n\n onSizesChange?.(normalized);\n };\n\n const handlePointerDown: ResizePointerHandler = (event, handleIndex) => {\n const group = groupRef.current;\n\n if (!group || disabled) {\n return;\n }\n\n if (\n event.button !== 0 &&\n event.pointerType !== \"touch\" &&\n event.pointerType !== \"pen\"\n ) {\n return;\n }\n\n const availableSize = getAvailableSize(group, orientation);\n\n if (availableSize <= 0) {\n return;\n }\n\n pointerDragRef.current = {\n handleIndex,\n pointerId: event.pointerId,\n startCoordinate: getPointerCoordinate(event, orientation),\n availableSize,\n direction: getResizeDirection(group, orientation),\n sizes: [...currentSizes],\n };\n\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Synthetic pointer events and detached elements may not\n // support pointer capture.\n }\n\n event.preventDefault();\n setIsResizing(true);\n };\n\n const handlePointerMove: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n const currentCoordinate = getPointerCoordinate(event, orientation);\n\n const delta =\n ((currentCoordinate - drag.startCoordinate) / drag.availableSize) *\n 100 *\n drag.direction;\n\n const nextSizes = resizePanelPair(\n drag.sizes,\n panelConstraints,\n handleIndex,\n delta,\n );\n\n event.preventDefault();\n updateSizes(nextSizes);\n };\n\n const handlePointerEnd: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n pointerDragRef.current = null;\n setIsResizing(false);\n };\n\n const handleKeyDown: ResizeKeyboardHandler = (event, handleIndex) => {\n if (disabled) {\n return;\n }\n\n const currentSize = currentSizes[handleIndex];\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n const group = groupRef.current;\n\n const direction = group ? getResizeDirection(group, orientation) : 1;\n\n const step = keyboardStep * (event.shiftKey ? 10 : 1);\n\n let nextSize: number | undefined;\n\n if (event.key === \"Home\") {\n nextSize = bounds.minSize;\n } else if (event.key === \"End\") {\n nextSize = bounds.maxSize;\n } else if (orientation === \"horizontal\") {\n if (event.key === \"ArrowRight\") {\n nextSize = currentSize + step * direction;\n } else if (event.key === \"ArrowLeft\") {\n nextSize = currentSize - step * direction;\n }\n } else {\n if (event.key === \"ArrowDown\") {\n nextSize = currentSize + step;\n } else if (event.key === \"ArrowUp\") {\n nextSize = currentSize - step;\n }\n }\n\n if (nextSize === undefined) {\n return;\n }\n\n event.preventDefault();\n\n updateSizes(\n resizePanelPair(\n currentSizes,\n panelConstraints,\n handleIndex,\n nextSize - currentSize,\n ),\n );\n };\n\n let panelIndex = 0;\n\n const enhancedChildren = childrenArray.map((child) => {\n if (isResizablePanelElement(child)) {\n const index = panelIndex++;\n\n return cloneElement(\n child as ReactElement<\n ResizablePanelProps & InternalResizablePanelProps\n >,\n {\n panelIndex: index,\n panelSize: currentSizes[index],\n panelId: panelIds[index],\n },\n );\n }\n\n const handleIndex = panelIndex - 1;\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n return cloneElement(\n child as ReactElement<\n ResizableHandleProps & InternalResizableHandleProps\n >,\n {\n handleIndex,\n orientation,\n value: currentSizes[handleIndex],\n minValue: bounds.minSize,\n maxValue: bounds.maxSize,\n panelIds: [panelIds[handleIndex], panelIds[handleIndex + 1]],\n inheritedDisabled: disabled,\n onResizeStart: handlePointerDown,\n onResizeMove: handlePointerMove,\n onResizeEnd: handlePointerEnd,\n onResizeKeyDown: handleKeyDown,\n },\n );\n });\n\n return (\n <div\n {...rootProps}\n ref={(node) => {\n groupRef.current = node;\n\n if (typeof forwardedRef === \"function\") {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n id={groupId}\n role={role ?? \"group\"}\n className={cn(\"puzzle-resizable-panels\", className)}\n style={style}\n data-orientation={orientation}\n data-disabled={disabled ? \"true\" : undefined}\n data-resizing={isResizing ? \"true\" : undefined}\n >\n {enhancedChildren}\n </div>\n );\n};\n\ntype ResizablePanelsComponent = typeof ResizablePanelsRoot & {\n Panel: typeof ResizablePanel;\n Handle: typeof ResizableHandle;\n};\n\nconst ResizablePanels = Object.assign(ResizablePanelsRoot, {\n Panel: ResizablePanel,\n Handle: ResizableHandle,\n}) as ResizablePanelsComponent;\n\nexport {\n ResizablePanels,\n ResizablePanel,\n ResizableHandle,\n type ResizablePanelsProps,\n type ResizablePanelProps,\n type ResizableHandleProps,\n type ResizablePanelsOrientation,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["isValidElement","cn","useId","Children","useState","normalizePanelSizes","useRef","resizePanelPair","getPanelPairBounds","cloneElement"],"sources":["../../../../src/components/layout/resizable-panels/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport {\n Children,\n cloneElement,\n isValidElement,\n useId,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\nimport {\n getPanelPairBounds,\n normalizePanelSizes,\n resizePanelPair,\n type PanelSizeConstraint,\n} from \"./resizable-panels.utils\";\n\nimport \"./resizable-panels.css\";\n\ntype ResizablePanelsOrientation = \"horizontal\" | \"vertical\";\n\ntype ResizablePanelsProps = Omit<ComponentPropsWithRef<\"div\">, \"children\"> & {\n /** Layout direction. Defaults to horizontal. */\n orientation?: ResizablePanelsOrientation;\n\n /** Controlled panel sizes, expressed as percentages. */\n sizes?: readonly number[];\n\n /** Initial panel sizes for uncontrolled usage. */\n defaultSizes?: readonly number[];\n\n /** Called whenever the panel layout changes. */\n onSizesChange?: (sizes: number[]) => void;\n\n /** Disables all resizing interactions. */\n disabled?: boolean;\n\n /** Percentage change per keyboard interaction. Defaults to 1. */\n keyboardStep?: number;\n\n /** Panels and handles that make up the group. */\n children: ReactNode;\n};\n\ntype ResizablePanelProps = ComponentPropsWithRef<\"div\"> & {\n /** Minimum panel size in percentages. Defaults to 0. */\n minSize?: number;\n\n /** Maximum panel size in percentages. Defaults to 100. */\n maxSize?: number;\n};\n\ntype ResizableHandleProps = ComponentPropsWithRef<\"div\"> & {\n /** Renders a visible grip inside the resize handle. */\n withGrip?: boolean;\n\n /** Disables resizing through this handle. */\n disabled?: boolean;\n};\n\ntype ResizePointerHandler = (\n event: ReactPointerEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype ResizeKeyboardHandler = (\n event: ReactKeyboardEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype InternalResizablePanelProps = {\n panelIndex?: number;\n panelSize?: number;\n panelId?: string;\n};\n\ntype InternalResizableHandleProps = {\n handleIndex?: number;\n orientation?: ResizablePanelsOrientation;\n value?: number;\n minValue?: number;\n maxValue?: number;\n panelIds?: [string, string];\n inheritedDisabled?: boolean;\n\n onResizeStart?: ResizePointerHandler;\n onResizeMove?: ResizePointerHandler;\n onResizeEnd?: ResizePointerHandler;\n onResizeKeyDown?: ResizeKeyboardHandler;\n};\n\ntype PointerDragState = {\n handleIndex: number;\n pointerId: number;\n startCoordinate: number;\n availableSize: number;\n direction: number;\n sizes: number[];\n};\n\nconst isResizablePanelElement = (\n child: ReactNode,\n): child is ReactElement<ResizablePanelProps> =>\n isValidElement(child) && child.type === ResizablePanel;\n\nconst isResizableHandleElement = (\n child: ReactNode,\n): child is ReactElement<ResizableHandleProps> =>\n isValidElement(child) && child.type === ResizableHandle;\n\nconst parsePixels = (value: string | undefined) =>\n Number.parseFloat(value ?? \"\") || 0;\n\nconst getAvailableSize = (\n group: HTMLDivElement,\n orientation: ResizablePanelsOrientation,\n) => {\n const computedStyle =\n group.ownerDocument.defaultView?.getComputedStyle(group);\n\n const isHorizontal = orientation === \"horizontal\";\n\n const totalSize = isHorizontal ? group.clientWidth : group.clientHeight;\n\n const paddingSize = computedStyle\n ? isHorizontal\n ? parsePixels(computedStyle.paddingLeft) +\n parsePixels(computedStyle.paddingRight)\n : parsePixels(computedStyle.paddingTop) +\n parsePixels(computedStyle.paddingBottom)\n : 0;\n\n const handleSize = Array.from(group.children).reduce((total, child) => {\n const element = child as HTMLElement;\n\n if (!element.hasAttribute(\"data-puzzle-resizable-handle\")) {\n return total;\n }\n\n const rect = element.getBoundingClientRect();\n\n return total + (isHorizontal ? rect.width : rect.height);\n }, 0);\n\n return Math.max(0, totalSize - paddingSize - handleSize);\n};\n\nconst getResizeDirection = (\n element: HTMLElement,\n orientation: ResizablePanelsOrientation,\n) => {\n if (orientation !== \"horizontal\") {\n return 1;\n }\n\n const direction =\n element.ownerDocument.defaultView?.getComputedStyle(element).direction;\n\n return direction === \"rtl\" ? -1 : 1;\n};\n\nconst getPointerCoordinate = (\n event: ReactPointerEvent<HTMLDivElement>,\n orientation: ResizablePanelsOrientation,\n) => (orientation === \"horizontal\" ? event.clientX : event.clientY);\n\nconst ResizablePanel = ({\n id,\n minSize = 0,\n maxSize = 100,\n panelIndex = 0,\n panelSize = 1,\n panelId,\n className,\n style,\n ...props\n}: ResizablePanelProps & InternalResizablePanelProps) => (\n <div\n {...props}\n id={panelId ?? id}\n className={cn(\"puzzle-resizable-panels__panel\", className)}\n style={{\n ...style,\n flex: `${panelSize} 1 0%`,\n }}\n data-panel-index={panelIndex}\n data-panel-size={panelSize}\n data-panel-min-size={minSize}\n data-panel-max-size={maxSize}\n />\n);\n\nconst ResizableHandle = ({\n withGrip = false,\n disabled = false,\n handleIndex = -1,\n orientation = \"horizontal\",\n value,\n minValue,\n maxValue,\n panelIds,\n inheritedDisabled = false,\n onResizeStart,\n onResizeMove,\n onResizeEnd,\n onResizeKeyDown,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n onLostPointerCapture,\n onKeyDown,\n className,\n children,\n tabIndex,\n \"aria-label\": ariaLabel,\n ...props\n}: ResizableHandleProps & InternalResizableHandleProps) => {\n const isDisabled = disabled || inheritedDisabled;\n\n const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeStart?.(event, handleIndex);\n }\n };\n\n const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerMove?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeMove?.(event, handleIndex);\n }\n };\n\n const handlePointerUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerUp?.(event);\n };\n\n const handlePointerCancel = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerCancel?.(event);\n };\n\n const handleLostPointerCapture = (\n event: ReactPointerEvent<HTMLDivElement>,\n ) => {\n onResizeEnd?.(event, handleIndex);\n onLostPointerCapture?.(event);\n };\n\n const handleKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeKeyDown?.(event, handleIndex);\n }\n };\n\n return (\n <div\n {...props}\n className={cn(\"puzzle-resizable-panels__handle\", className)}\n role=\"separator\"\n tabIndex={isDisabled ? -1 : (tabIndex ?? 0)}\n aria-label={ariaLabel ?? \"Resize panels\"}\n aria-orientation={\n orientation === \"horizontal\" ? \"vertical\" : \"horizontal\"\n }\n aria-controls={panelIds?.join(\" \")}\n aria-valuenow={value}\n aria-valuemin={minValue}\n aria-valuemax={maxValue}\n aria-valuetext={\n value === undefined ? undefined : `${Math.round(value * 100) / 100}%`\n }\n aria-disabled={isDisabled || undefined}\n data-puzzle-resizable-handle=\"\"\n data-orientation={orientation}\n data-disabled={isDisabled ? \"true\" : undefined}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerCancel}\n onLostPointerCapture={handleLostPointerCapture}\n onKeyDown={handleKeyDown}\n >\n {withGrip ? (\n <span\n className=\"puzzle-resizable-panels__handle-grip\"\n aria-hidden=\"true\"\n />\n ) : (\n children\n )}\n </div>\n );\n};\n\nconst ResizablePanelsRoot = ({\n children,\n orientation = \"horizontal\",\n sizes,\n defaultSizes,\n onSizesChange,\n disabled = false,\n keyboardStep = 1,\n id,\n role,\n className,\n style,\n ref: forwardedRef,\n ...rootProps\n}: ResizablePanelsProps) => {\n const generatedId = useId();\n\n const groupId = id ?? `puzzle-resizable-panels-${generatedId}`;\n\n if (!Number.isFinite(keyboardStep) || keyboardStep <= 0) {\n throw new RangeError(\"keyboardStep must be a positive finite number.\");\n }\n\n const childrenArray = Children.toArray(children);\n\n const validChildren =\n childrenArray.length >= 3 &&\n childrenArray.length % 2 === 1 &&\n childrenArray.every((child, index) =>\n index % 2 === 0\n ? isResizablePanelElement(child)\n : isResizableHandleElement(child),\n );\n\n if (!validChildren) {\n throw new Error(\n \"ResizablePanels requires alternating Panel and Handle children, starting and ending with a Panel. At least two panels are required.\",\n );\n }\n\n const panelElements = childrenArray.filter(isResizablePanelElement);\n\n const panelCount = panelElements.length;\n\n const panelConstraints: PanelSizeConstraint[] = panelElements.map(\n (panel) => ({\n minSize: panel.props.minSize,\n maxSize: panel.props.maxSize,\n }),\n );\n\n const panelIds = panelElements.map(\n (panel, index) => panel.props.id ?? `${groupId}-panel-${index}`,\n );\n\n if (new Set(panelIds).size !== panelIds.length) {\n throw new Error(\"ResizablePanels requires unique panel IDs.\");\n }\n\n const [uncontrolledSizes, setUncontrolledSizes] = useState<number[]>(() =>\n normalizePanelSizes(\n sizes === undefined ? defaultSizes : undefined,\n panelConstraints,\n ),\n );\n\n const layoutInput =\n sizes ??\n (uncontrolledSizes.length === panelCount ? uncontrolledSizes : undefined);\n\n const currentSizes = normalizePanelSizes(layoutInput, panelConstraints);\n\n const [isResizing, setIsResizing] = useState(false);\n\n const groupRef = useRef<HTMLDivElement | null>(null);\n\n const pointerDragRef = useRef<PointerDragState | null>(null);\n\n const updateSizes = (nextSizes: readonly number[]) => {\n const normalized = normalizePanelSizes(nextSizes, panelConstraints);\n\n const hasChanged = normalized.some(\n (size, index) => Math.abs(size - (currentSizes[index] ?? 0)) > 0.000001,\n );\n\n if (!hasChanged) {\n return;\n }\n\n if (sizes === undefined) {\n setUncontrolledSizes(normalized);\n }\n\n onSizesChange?.(normalized);\n };\n\n const handlePointerDown: ResizePointerHandler = (event, handleIndex) => {\n const group = groupRef.current;\n\n if (!group || disabled) {\n return;\n }\n\n if (\n event.button !== 0 &&\n event.pointerType !== \"touch\" &&\n event.pointerType !== \"pen\"\n ) {\n return;\n }\n\n const availableSize = getAvailableSize(group, orientation);\n\n if (availableSize <= 0) {\n return;\n }\n\n pointerDragRef.current = {\n handleIndex,\n pointerId: event.pointerId,\n startCoordinate: getPointerCoordinate(event, orientation),\n availableSize,\n direction: getResizeDirection(group, orientation),\n sizes: [...currentSizes],\n };\n\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Synthetic pointer events and detached elements may not\n // support pointer capture.\n }\n\n event.preventDefault();\n setIsResizing(true);\n };\n\n const handlePointerMove: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n const currentCoordinate = getPointerCoordinate(event, orientation);\n\n const delta =\n ((currentCoordinate - drag.startCoordinate) / drag.availableSize) *\n 100 *\n drag.direction;\n\n const nextSizes = resizePanelPair(\n drag.sizes,\n panelConstraints,\n handleIndex,\n delta,\n );\n\n event.preventDefault();\n updateSizes(nextSizes);\n };\n\n const handlePointerEnd: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n pointerDragRef.current = null;\n setIsResizing(false);\n };\n\n const handleKeyDown: ResizeKeyboardHandler = (event, handleIndex) => {\n if (disabled) {\n return;\n }\n\n const currentSize = currentSizes[handleIndex]!;\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n const group = groupRef.current;\n\n const direction = group ? getResizeDirection(group, orientation) : 1;\n\n const step = keyboardStep * (event.shiftKey ? 10 : 1);\n\n let nextSize: number | undefined;\n\n if (event.key === \"Home\") {\n nextSize = bounds.minSize;\n } else if (event.key === \"End\") {\n nextSize = bounds.maxSize;\n } else if (orientation === \"horizontal\") {\n if (event.key === \"ArrowRight\") {\n nextSize = currentSize + step * direction;\n } else if (event.key === \"ArrowLeft\") {\n nextSize = currentSize - step * direction;\n }\n } else {\n if (event.key === \"ArrowDown\") {\n nextSize = currentSize + step;\n } else if (event.key === \"ArrowUp\") {\n nextSize = currentSize - step;\n }\n }\n\n if (nextSize === undefined) {\n return;\n }\n\n event.preventDefault();\n\n updateSizes(\n resizePanelPair(\n currentSizes,\n panelConstraints,\n handleIndex,\n nextSize - currentSize,\n ),\n );\n };\n\n let panelIndex = 0;\n\n const enhancedChildren = childrenArray.map((child) => {\n if (isResizablePanelElement(child)) {\n const index = panelIndex++;\n\n return cloneElement(\n child as ReactElement<\n ResizablePanelProps & InternalResizablePanelProps\n >,\n {\n panelIndex: index,\n panelSize: currentSizes[index],\n panelId: panelIds[index],\n },\n );\n }\n\n const handleIndex = panelIndex - 1;\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n return cloneElement(\n child as ReactElement<\n ResizableHandleProps & InternalResizableHandleProps\n >,\n {\n handleIndex,\n orientation,\n value: currentSizes[handleIndex],\n minValue: bounds.minSize,\n maxValue: bounds.maxSize,\n panelIds: [panelIds[handleIndex]!, panelIds[handleIndex + 1]!],\n inheritedDisabled: disabled,\n onResizeStart: handlePointerDown,\n onResizeMove: handlePointerMove,\n onResizeEnd: handlePointerEnd,\n onResizeKeyDown: handleKeyDown,\n },\n );\n });\n\n return (\n <div\n {...rootProps}\n ref={(node) => {\n groupRef.current = node;\n\n if (typeof forwardedRef === \"function\") {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n id={groupId}\n role={role ?? \"group\"}\n className={cn(\"puzzle-resizable-panels\", className)}\n style={style}\n data-orientation={orientation}\n data-disabled={disabled ? \"true\" : undefined}\n data-resizing={isResizing ? \"true\" : undefined}\n >\n {enhancedChildren}\n </div>\n );\n};\n\ntype ResizablePanelsComponent = typeof ResizablePanelsRoot & {\n Panel: typeof ResizablePanel;\n Handle: typeof ResizableHandle;\n};\n\nconst ResizablePanels = Object.assign(ResizablePanelsRoot, {\n Panel: ResizablePanel,\n Handle: ResizableHandle,\n}) as ResizablePanelsComponent;\n\nexport {\n ResizablePanels,\n ResizablePanel,\n ResizableHandle,\n type ResizablePanelsProps,\n type ResizablePanelProps,\n type ResizableHandleProps,\n type ResizablePanelsOrientation,\n};\n"],"mappings":"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"}
|
|
@@ -115,7 +115,7 @@ const ResizablePanelsRoot = ({ children, orientation = "horizontal", sizes, defa
|
|
|
115
115
|
const pointerDragRef = useRef(null);
|
|
116
116
|
const updateSizes = (nextSizes) => {
|
|
117
117
|
const normalized = normalizePanelSizes(nextSizes, panelConstraints);
|
|
118
|
-
if (!normalized.some((size, index) => Math.abs(size - currentSizes[index]) > 1e-6)) return;
|
|
118
|
+
if (!normalized.some((size, index) => Math.abs(size - (currentSizes[index] ?? 0)) > 1e-6)) return;
|
|
119
119
|
if (sizes === void 0) setUncontrolledSizes(normalized);
|
|
120
120
|
onSizesChange?.(normalized);
|
|
121
121
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/layout/resizable-panels/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport {\n Children,\n cloneElement,\n isValidElement,\n useId,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\nimport {\n getPanelPairBounds,\n normalizePanelSizes,\n resizePanelPair,\n type PanelSizeConstraint,\n} from \"./resizable-panels.utils\";\n\nimport \"./resizable-panels.css\";\n\ntype ResizablePanelsOrientation = \"horizontal\" | \"vertical\";\n\ntype ResizablePanelsProps = Omit<ComponentPropsWithRef<\"div\">, \"children\"> & {\n /** Layout direction. Defaults to horizontal. */\n orientation?: ResizablePanelsOrientation;\n\n /** Controlled panel sizes, expressed as percentages. */\n sizes?: readonly number[];\n\n /** Initial panel sizes for uncontrolled usage. */\n defaultSizes?: readonly number[];\n\n /** Called whenever the panel layout changes. */\n onSizesChange?: (sizes: number[]) => void;\n\n /** Disables all resizing interactions. */\n disabled?: boolean;\n\n /** Percentage change per keyboard interaction. Defaults to 1. */\n keyboardStep?: number;\n\n /** Panels and handles that make up the group. */\n children: ReactNode;\n};\n\ntype ResizablePanelProps = ComponentPropsWithRef<\"div\"> & {\n /** Minimum panel size in percentages. Defaults to 0. */\n minSize?: number;\n\n /** Maximum panel size in percentages. Defaults to 100. */\n maxSize?: number;\n};\n\ntype ResizableHandleProps = ComponentPropsWithRef<\"div\"> & {\n /** Renders a visible grip inside the resize handle. */\n withGrip?: boolean;\n\n /** Disables resizing through this handle. */\n disabled?: boolean;\n};\n\ntype ResizePointerHandler = (\n event: ReactPointerEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype ResizeKeyboardHandler = (\n event: ReactKeyboardEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype InternalResizablePanelProps = {\n panelIndex?: number;\n panelSize?: number;\n panelId?: string;\n};\n\ntype InternalResizableHandleProps = {\n handleIndex?: number;\n orientation?: ResizablePanelsOrientation;\n value?: number;\n minValue?: number;\n maxValue?: number;\n panelIds?: [string, string];\n inheritedDisabled?: boolean;\n\n onResizeStart?: ResizePointerHandler;\n onResizeMove?: ResizePointerHandler;\n onResizeEnd?: ResizePointerHandler;\n onResizeKeyDown?: ResizeKeyboardHandler;\n};\n\ntype PointerDragState = {\n handleIndex: number;\n pointerId: number;\n startCoordinate: number;\n availableSize: number;\n direction: number;\n sizes: number[];\n};\n\nconst isResizablePanelElement = (\n child: ReactNode,\n): child is ReactElement<ResizablePanelProps> =>\n isValidElement(child) && child.type === ResizablePanel;\n\nconst isResizableHandleElement = (\n child: ReactNode,\n): child is ReactElement<ResizableHandleProps> =>\n isValidElement(child) && child.type === ResizableHandle;\n\nconst parsePixels = (value: string | undefined) =>\n Number.parseFloat(value ?? \"\") || 0;\n\nconst getAvailableSize = (\n group: HTMLDivElement,\n orientation: ResizablePanelsOrientation,\n) => {\n const computedStyle =\n group.ownerDocument.defaultView?.getComputedStyle(group);\n\n const isHorizontal = orientation === \"horizontal\";\n\n const totalSize = isHorizontal ? group.clientWidth : group.clientHeight;\n\n const paddingSize = computedStyle\n ? isHorizontal\n ? parsePixels(computedStyle.paddingLeft) +\n parsePixels(computedStyle.paddingRight)\n : parsePixels(computedStyle.paddingTop) +\n parsePixels(computedStyle.paddingBottom)\n : 0;\n\n const handleSize = Array.from(group.children).reduce((total, child) => {\n const element = child as HTMLElement;\n\n if (!element.hasAttribute(\"data-puzzle-resizable-handle\")) {\n return total;\n }\n\n const rect = element.getBoundingClientRect();\n\n return total + (isHorizontal ? rect.width : rect.height);\n }, 0);\n\n return Math.max(0, totalSize - paddingSize - handleSize);\n};\n\nconst getResizeDirection = (\n element: HTMLElement,\n orientation: ResizablePanelsOrientation,\n) => {\n if (orientation !== \"horizontal\") {\n return 1;\n }\n\n const direction =\n element.ownerDocument.defaultView?.getComputedStyle(element).direction;\n\n return direction === \"rtl\" ? -1 : 1;\n};\n\nconst getPointerCoordinate = (\n event: ReactPointerEvent<HTMLDivElement>,\n orientation: ResizablePanelsOrientation,\n) => (orientation === \"horizontal\" ? event.clientX : event.clientY);\n\nconst ResizablePanel = ({\n id,\n minSize = 0,\n maxSize = 100,\n panelIndex = 0,\n panelSize = 1,\n panelId,\n className,\n style,\n ...props\n}: ResizablePanelProps & InternalResizablePanelProps) => (\n <div\n {...props}\n id={panelId ?? id}\n className={cn(\"puzzle-resizable-panels__panel\", className)}\n style={{\n ...style,\n flex: `${panelSize} 1 0%`,\n }}\n data-panel-index={panelIndex}\n data-panel-size={panelSize}\n data-panel-min-size={minSize}\n data-panel-max-size={maxSize}\n />\n);\n\nconst ResizableHandle = ({\n withGrip = false,\n disabled = false,\n handleIndex = -1,\n orientation = \"horizontal\",\n value,\n minValue,\n maxValue,\n panelIds,\n inheritedDisabled = false,\n onResizeStart,\n onResizeMove,\n onResizeEnd,\n onResizeKeyDown,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n onLostPointerCapture,\n onKeyDown,\n className,\n children,\n tabIndex,\n \"aria-label\": ariaLabel,\n ...props\n}: ResizableHandleProps & InternalResizableHandleProps) => {\n const isDisabled = disabled || inheritedDisabled;\n\n const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeStart?.(event, handleIndex);\n }\n };\n\n const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerMove?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeMove?.(event, handleIndex);\n }\n };\n\n const handlePointerUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerUp?.(event);\n };\n\n const handlePointerCancel = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerCancel?.(event);\n };\n\n const handleLostPointerCapture = (\n event: ReactPointerEvent<HTMLDivElement>,\n ) => {\n onResizeEnd?.(event, handleIndex);\n onLostPointerCapture?.(event);\n };\n\n const handleKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeKeyDown?.(event, handleIndex);\n }\n };\n\n return (\n <div\n {...props}\n className={cn(\"puzzle-resizable-panels__handle\", className)}\n role=\"separator\"\n tabIndex={isDisabled ? -1 : (tabIndex ?? 0)}\n aria-label={ariaLabel ?? \"Resize panels\"}\n aria-orientation={\n orientation === \"horizontal\" ? \"vertical\" : \"horizontal\"\n }\n aria-controls={panelIds?.join(\" \")}\n aria-valuenow={value}\n aria-valuemin={minValue}\n aria-valuemax={maxValue}\n aria-valuetext={\n value === undefined ? undefined : `${Math.round(value * 100) / 100}%`\n }\n aria-disabled={isDisabled || undefined}\n data-puzzle-resizable-handle=\"\"\n data-orientation={orientation}\n data-disabled={isDisabled ? \"true\" : undefined}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerCancel}\n onLostPointerCapture={handleLostPointerCapture}\n onKeyDown={handleKeyDown}\n >\n {withGrip ? (\n <span\n className=\"puzzle-resizable-panels__handle-grip\"\n aria-hidden=\"true\"\n />\n ) : (\n children\n )}\n </div>\n );\n};\n\nconst ResizablePanelsRoot = ({\n children,\n orientation = \"horizontal\",\n sizes,\n defaultSizes,\n onSizesChange,\n disabled = false,\n keyboardStep = 1,\n id,\n role,\n className,\n style,\n ref: forwardedRef,\n ...rootProps\n}: ResizablePanelsProps) => {\n const generatedId = useId();\n\n const groupId = id ?? `puzzle-resizable-panels-${generatedId}`;\n\n if (!Number.isFinite(keyboardStep) || keyboardStep <= 0) {\n throw new RangeError(\"keyboardStep must be a positive finite number.\");\n }\n\n const childrenArray = Children.toArray(children);\n\n const validChildren =\n childrenArray.length >= 3 &&\n childrenArray.length % 2 === 1 &&\n childrenArray.every((child, index) =>\n index % 2 === 0\n ? isResizablePanelElement(child)\n : isResizableHandleElement(child),\n );\n\n if (!validChildren) {\n throw new Error(\n \"ResizablePanels requires alternating Panel and Handle children, starting and ending with a Panel. At least two panels are required.\",\n );\n }\n\n const panelElements = childrenArray.filter(isResizablePanelElement);\n\n const panelCount = panelElements.length;\n\n const panelConstraints: PanelSizeConstraint[] = panelElements.map(\n (panel) => ({\n minSize: panel.props.minSize,\n maxSize: panel.props.maxSize,\n }),\n );\n\n const panelIds = panelElements.map(\n (panel, index) => panel.props.id ?? `${groupId}-panel-${index}`,\n );\n\n if (new Set(panelIds).size !== panelIds.length) {\n throw new Error(\"ResizablePanels requires unique panel IDs.\");\n }\n\n const [uncontrolledSizes, setUncontrolledSizes] = useState<number[]>(() =>\n normalizePanelSizes(\n sizes === undefined ? defaultSizes : undefined,\n panelConstraints,\n ),\n );\n\n const layoutInput =\n sizes ??\n (uncontrolledSizes.length === panelCount ? uncontrolledSizes : undefined);\n\n const currentSizes = normalizePanelSizes(layoutInput, panelConstraints);\n\n const [isResizing, setIsResizing] = useState(false);\n\n const groupRef = useRef<HTMLDivElement | null>(null);\n\n const pointerDragRef = useRef<PointerDragState | null>(null);\n\n const updateSizes = (nextSizes: readonly number[]) => {\n const normalized = normalizePanelSizes(nextSizes, panelConstraints);\n\n const hasChanged = normalized.some(\n (size, index) => Math.abs(size - currentSizes[index]) > 0.000001,\n );\n\n if (!hasChanged) {\n return;\n }\n\n if (sizes === undefined) {\n setUncontrolledSizes(normalized);\n }\n\n onSizesChange?.(normalized);\n };\n\n const handlePointerDown: ResizePointerHandler = (event, handleIndex) => {\n const group = groupRef.current;\n\n if (!group || disabled) {\n return;\n }\n\n if (\n event.button !== 0 &&\n event.pointerType !== \"touch\" &&\n event.pointerType !== \"pen\"\n ) {\n return;\n }\n\n const availableSize = getAvailableSize(group, orientation);\n\n if (availableSize <= 0) {\n return;\n }\n\n pointerDragRef.current = {\n handleIndex,\n pointerId: event.pointerId,\n startCoordinate: getPointerCoordinate(event, orientation),\n availableSize,\n direction: getResizeDirection(group, orientation),\n sizes: [...currentSizes],\n };\n\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Synthetic pointer events and detached elements may not\n // support pointer capture.\n }\n\n event.preventDefault();\n setIsResizing(true);\n };\n\n const handlePointerMove: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n const currentCoordinate = getPointerCoordinate(event, orientation);\n\n const delta =\n ((currentCoordinate - drag.startCoordinate) / drag.availableSize) *\n 100 *\n drag.direction;\n\n const nextSizes = resizePanelPair(\n drag.sizes,\n panelConstraints,\n handleIndex,\n delta,\n );\n\n event.preventDefault();\n updateSizes(nextSizes);\n };\n\n const handlePointerEnd: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n pointerDragRef.current = null;\n setIsResizing(false);\n };\n\n const handleKeyDown: ResizeKeyboardHandler = (event, handleIndex) => {\n if (disabled) {\n return;\n }\n\n const currentSize = currentSizes[handleIndex];\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n const group = groupRef.current;\n\n const direction = group ? getResizeDirection(group, orientation) : 1;\n\n const step = keyboardStep * (event.shiftKey ? 10 : 1);\n\n let nextSize: number | undefined;\n\n if (event.key === \"Home\") {\n nextSize = bounds.minSize;\n } else if (event.key === \"End\") {\n nextSize = bounds.maxSize;\n } else if (orientation === \"horizontal\") {\n if (event.key === \"ArrowRight\") {\n nextSize = currentSize + step * direction;\n } else if (event.key === \"ArrowLeft\") {\n nextSize = currentSize - step * direction;\n }\n } else {\n if (event.key === \"ArrowDown\") {\n nextSize = currentSize + step;\n } else if (event.key === \"ArrowUp\") {\n nextSize = currentSize - step;\n }\n }\n\n if (nextSize === undefined) {\n return;\n }\n\n event.preventDefault();\n\n updateSizes(\n resizePanelPair(\n currentSizes,\n panelConstraints,\n handleIndex,\n nextSize - currentSize,\n ),\n );\n };\n\n let panelIndex = 0;\n\n const enhancedChildren = childrenArray.map((child) => {\n if (isResizablePanelElement(child)) {\n const index = panelIndex++;\n\n return cloneElement(\n child as ReactElement<\n ResizablePanelProps & InternalResizablePanelProps\n >,\n {\n panelIndex: index,\n panelSize: currentSizes[index],\n panelId: panelIds[index],\n },\n );\n }\n\n const handleIndex = panelIndex - 1;\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n return cloneElement(\n child as ReactElement<\n ResizableHandleProps & InternalResizableHandleProps\n >,\n {\n handleIndex,\n orientation,\n value: currentSizes[handleIndex],\n minValue: bounds.minSize,\n maxValue: bounds.maxSize,\n panelIds: [panelIds[handleIndex], panelIds[handleIndex + 1]],\n inheritedDisabled: disabled,\n onResizeStart: handlePointerDown,\n onResizeMove: handlePointerMove,\n onResizeEnd: handlePointerEnd,\n onResizeKeyDown: handleKeyDown,\n },\n );\n });\n\n return (\n <div\n {...rootProps}\n ref={(node) => {\n groupRef.current = node;\n\n if (typeof forwardedRef === \"function\") {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n id={groupId}\n role={role ?? \"group\"}\n className={cn(\"puzzle-resizable-panels\", className)}\n style={style}\n data-orientation={orientation}\n data-disabled={disabled ? \"true\" : undefined}\n data-resizing={isResizing ? \"true\" : undefined}\n >\n {enhancedChildren}\n </div>\n );\n};\n\ntype ResizablePanelsComponent = typeof ResizablePanelsRoot & {\n Panel: typeof ResizablePanel;\n Handle: typeof ResizableHandle;\n};\n\nconst ResizablePanels = Object.assign(ResizablePanelsRoot, {\n Panel: ResizablePanel,\n Handle: ResizableHandle,\n}) as ResizablePanelsComponent;\n\nexport {\n ResizablePanels,\n ResizablePanel,\n ResizableHandle,\n type ResizablePanelsProps,\n type ResizablePanelProps,\n type ResizableHandleProps,\n type ResizablePanelsOrientation,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/layout/resizable-panels/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport {\n Children,\n cloneElement,\n isValidElement,\n useId,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\nimport {\n getPanelPairBounds,\n normalizePanelSizes,\n resizePanelPair,\n type PanelSizeConstraint,\n} from \"./resizable-panels.utils\";\n\nimport \"./resizable-panels.css\";\n\ntype ResizablePanelsOrientation = \"horizontal\" | \"vertical\";\n\ntype ResizablePanelsProps = Omit<ComponentPropsWithRef<\"div\">, \"children\"> & {\n /** Layout direction. Defaults to horizontal. */\n orientation?: ResizablePanelsOrientation;\n\n /** Controlled panel sizes, expressed as percentages. */\n sizes?: readonly number[];\n\n /** Initial panel sizes for uncontrolled usage. */\n defaultSizes?: readonly number[];\n\n /** Called whenever the panel layout changes. */\n onSizesChange?: (sizes: number[]) => void;\n\n /** Disables all resizing interactions. */\n disabled?: boolean;\n\n /** Percentage change per keyboard interaction. Defaults to 1. */\n keyboardStep?: number;\n\n /** Panels and handles that make up the group. */\n children: ReactNode;\n};\n\ntype ResizablePanelProps = ComponentPropsWithRef<\"div\"> & {\n /** Minimum panel size in percentages. Defaults to 0. */\n minSize?: number;\n\n /** Maximum panel size in percentages. Defaults to 100. */\n maxSize?: number;\n};\n\ntype ResizableHandleProps = ComponentPropsWithRef<\"div\"> & {\n /** Renders a visible grip inside the resize handle. */\n withGrip?: boolean;\n\n /** Disables resizing through this handle. */\n disabled?: boolean;\n};\n\ntype ResizePointerHandler = (\n event: ReactPointerEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype ResizeKeyboardHandler = (\n event: ReactKeyboardEvent<HTMLDivElement>,\n handleIndex: number,\n) => void;\n\ntype InternalResizablePanelProps = {\n panelIndex?: number;\n panelSize?: number;\n panelId?: string;\n};\n\ntype InternalResizableHandleProps = {\n handleIndex?: number;\n orientation?: ResizablePanelsOrientation;\n value?: number;\n minValue?: number;\n maxValue?: number;\n panelIds?: [string, string];\n inheritedDisabled?: boolean;\n\n onResizeStart?: ResizePointerHandler;\n onResizeMove?: ResizePointerHandler;\n onResizeEnd?: ResizePointerHandler;\n onResizeKeyDown?: ResizeKeyboardHandler;\n};\n\ntype PointerDragState = {\n handleIndex: number;\n pointerId: number;\n startCoordinate: number;\n availableSize: number;\n direction: number;\n sizes: number[];\n};\n\nconst isResizablePanelElement = (\n child: ReactNode,\n): child is ReactElement<ResizablePanelProps> =>\n isValidElement(child) && child.type === ResizablePanel;\n\nconst isResizableHandleElement = (\n child: ReactNode,\n): child is ReactElement<ResizableHandleProps> =>\n isValidElement(child) && child.type === ResizableHandle;\n\nconst parsePixels = (value: string | undefined) =>\n Number.parseFloat(value ?? \"\") || 0;\n\nconst getAvailableSize = (\n group: HTMLDivElement,\n orientation: ResizablePanelsOrientation,\n) => {\n const computedStyle =\n group.ownerDocument.defaultView?.getComputedStyle(group);\n\n const isHorizontal = orientation === \"horizontal\";\n\n const totalSize = isHorizontal ? group.clientWidth : group.clientHeight;\n\n const paddingSize = computedStyle\n ? isHorizontal\n ? parsePixels(computedStyle.paddingLeft) +\n parsePixels(computedStyle.paddingRight)\n : parsePixels(computedStyle.paddingTop) +\n parsePixels(computedStyle.paddingBottom)\n : 0;\n\n const handleSize = Array.from(group.children).reduce((total, child) => {\n const element = child as HTMLElement;\n\n if (!element.hasAttribute(\"data-puzzle-resizable-handle\")) {\n return total;\n }\n\n const rect = element.getBoundingClientRect();\n\n return total + (isHorizontal ? rect.width : rect.height);\n }, 0);\n\n return Math.max(0, totalSize - paddingSize - handleSize);\n};\n\nconst getResizeDirection = (\n element: HTMLElement,\n orientation: ResizablePanelsOrientation,\n) => {\n if (orientation !== \"horizontal\") {\n return 1;\n }\n\n const direction =\n element.ownerDocument.defaultView?.getComputedStyle(element).direction;\n\n return direction === \"rtl\" ? -1 : 1;\n};\n\nconst getPointerCoordinate = (\n event: ReactPointerEvent<HTMLDivElement>,\n orientation: ResizablePanelsOrientation,\n) => (orientation === \"horizontal\" ? event.clientX : event.clientY);\n\nconst ResizablePanel = ({\n id,\n minSize = 0,\n maxSize = 100,\n panelIndex = 0,\n panelSize = 1,\n panelId,\n className,\n style,\n ...props\n}: ResizablePanelProps & InternalResizablePanelProps) => (\n <div\n {...props}\n id={panelId ?? id}\n className={cn(\"puzzle-resizable-panels__panel\", className)}\n style={{\n ...style,\n flex: `${panelSize} 1 0%`,\n }}\n data-panel-index={panelIndex}\n data-panel-size={panelSize}\n data-panel-min-size={minSize}\n data-panel-max-size={maxSize}\n />\n);\n\nconst ResizableHandle = ({\n withGrip = false,\n disabled = false,\n handleIndex = -1,\n orientation = \"horizontal\",\n value,\n minValue,\n maxValue,\n panelIds,\n inheritedDisabled = false,\n onResizeStart,\n onResizeMove,\n onResizeEnd,\n onResizeKeyDown,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n onLostPointerCapture,\n onKeyDown,\n className,\n children,\n tabIndex,\n \"aria-label\": ariaLabel,\n ...props\n}: ResizableHandleProps & InternalResizableHandleProps) => {\n const isDisabled = disabled || inheritedDisabled;\n\n const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeStart?.(event, handleIndex);\n }\n };\n\n const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerMove?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeMove?.(event, handleIndex);\n }\n };\n\n const handlePointerUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerUp?.(event);\n };\n\n const handlePointerCancel = (event: ReactPointerEvent<HTMLDivElement>) => {\n onResizeEnd?.(event, handleIndex);\n onPointerCancel?.(event);\n };\n\n const handleLostPointerCapture = (\n event: ReactPointerEvent<HTMLDivElement>,\n ) => {\n onResizeEnd?.(event, handleIndex);\n onLostPointerCapture?.(event);\n };\n\n const handleKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (!event.defaultPrevented && !isDisabled) {\n onResizeKeyDown?.(event, handleIndex);\n }\n };\n\n return (\n <div\n {...props}\n className={cn(\"puzzle-resizable-panels__handle\", className)}\n role=\"separator\"\n tabIndex={isDisabled ? -1 : (tabIndex ?? 0)}\n aria-label={ariaLabel ?? \"Resize panels\"}\n aria-orientation={\n orientation === \"horizontal\" ? \"vertical\" : \"horizontal\"\n }\n aria-controls={panelIds?.join(\" \")}\n aria-valuenow={value}\n aria-valuemin={minValue}\n aria-valuemax={maxValue}\n aria-valuetext={\n value === undefined ? undefined : `${Math.round(value * 100) / 100}%`\n }\n aria-disabled={isDisabled || undefined}\n data-puzzle-resizable-handle=\"\"\n data-orientation={orientation}\n data-disabled={isDisabled ? \"true\" : undefined}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerCancel}\n onLostPointerCapture={handleLostPointerCapture}\n onKeyDown={handleKeyDown}\n >\n {withGrip ? (\n <span\n className=\"puzzle-resizable-panels__handle-grip\"\n aria-hidden=\"true\"\n />\n ) : (\n children\n )}\n </div>\n );\n};\n\nconst ResizablePanelsRoot = ({\n children,\n orientation = \"horizontal\",\n sizes,\n defaultSizes,\n onSizesChange,\n disabled = false,\n keyboardStep = 1,\n id,\n role,\n className,\n style,\n ref: forwardedRef,\n ...rootProps\n}: ResizablePanelsProps) => {\n const generatedId = useId();\n\n const groupId = id ?? `puzzle-resizable-panels-${generatedId}`;\n\n if (!Number.isFinite(keyboardStep) || keyboardStep <= 0) {\n throw new RangeError(\"keyboardStep must be a positive finite number.\");\n }\n\n const childrenArray = Children.toArray(children);\n\n const validChildren =\n childrenArray.length >= 3 &&\n childrenArray.length % 2 === 1 &&\n childrenArray.every((child, index) =>\n index % 2 === 0\n ? isResizablePanelElement(child)\n : isResizableHandleElement(child),\n );\n\n if (!validChildren) {\n throw new Error(\n \"ResizablePanels requires alternating Panel and Handle children, starting and ending with a Panel. At least two panels are required.\",\n );\n }\n\n const panelElements = childrenArray.filter(isResizablePanelElement);\n\n const panelCount = panelElements.length;\n\n const panelConstraints: PanelSizeConstraint[] = panelElements.map(\n (panel) => ({\n minSize: panel.props.minSize,\n maxSize: panel.props.maxSize,\n }),\n );\n\n const panelIds = panelElements.map(\n (panel, index) => panel.props.id ?? `${groupId}-panel-${index}`,\n );\n\n if (new Set(panelIds).size !== panelIds.length) {\n throw new Error(\"ResizablePanels requires unique panel IDs.\");\n }\n\n const [uncontrolledSizes, setUncontrolledSizes] = useState<number[]>(() =>\n normalizePanelSizes(\n sizes === undefined ? defaultSizes : undefined,\n panelConstraints,\n ),\n );\n\n const layoutInput =\n sizes ??\n (uncontrolledSizes.length === panelCount ? uncontrolledSizes : undefined);\n\n const currentSizes = normalizePanelSizes(layoutInput, panelConstraints);\n\n const [isResizing, setIsResizing] = useState(false);\n\n const groupRef = useRef<HTMLDivElement | null>(null);\n\n const pointerDragRef = useRef<PointerDragState | null>(null);\n\n const updateSizes = (nextSizes: readonly number[]) => {\n const normalized = normalizePanelSizes(nextSizes, panelConstraints);\n\n const hasChanged = normalized.some(\n (size, index) => Math.abs(size - (currentSizes[index] ?? 0)) > 0.000001,\n );\n\n if (!hasChanged) {\n return;\n }\n\n if (sizes === undefined) {\n setUncontrolledSizes(normalized);\n }\n\n onSizesChange?.(normalized);\n };\n\n const handlePointerDown: ResizePointerHandler = (event, handleIndex) => {\n const group = groupRef.current;\n\n if (!group || disabled) {\n return;\n }\n\n if (\n event.button !== 0 &&\n event.pointerType !== \"touch\" &&\n event.pointerType !== \"pen\"\n ) {\n return;\n }\n\n const availableSize = getAvailableSize(group, orientation);\n\n if (availableSize <= 0) {\n return;\n }\n\n pointerDragRef.current = {\n handleIndex,\n pointerId: event.pointerId,\n startCoordinate: getPointerCoordinate(event, orientation),\n availableSize,\n direction: getResizeDirection(group, orientation),\n sizes: [...currentSizes],\n };\n\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // Synthetic pointer events and detached elements may not\n // support pointer capture.\n }\n\n event.preventDefault();\n setIsResizing(true);\n };\n\n const handlePointerMove: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n const currentCoordinate = getPointerCoordinate(event, orientation);\n\n const delta =\n ((currentCoordinate - drag.startCoordinate) / drag.availableSize) *\n 100 *\n drag.direction;\n\n const nextSizes = resizePanelPair(\n drag.sizes,\n panelConstraints,\n handleIndex,\n delta,\n );\n\n event.preventDefault();\n updateSizes(nextSizes);\n };\n\n const handlePointerEnd: ResizePointerHandler = (event, handleIndex) => {\n const drag = pointerDragRef.current;\n\n if (\n !drag ||\n drag.pointerId !== event.pointerId ||\n drag.handleIndex !== handleIndex\n ) {\n return;\n }\n\n pointerDragRef.current = null;\n setIsResizing(false);\n };\n\n const handleKeyDown: ResizeKeyboardHandler = (event, handleIndex) => {\n if (disabled) {\n return;\n }\n\n const currentSize = currentSizes[handleIndex]!;\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n const group = groupRef.current;\n\n const direction = group ? getResizeDirection(group, orientation) : 1;\n\n const step = keyboardStep * (event.shiftKey ? 10 : 1);\n\n let nextSize: number | undefined;\n\n if (event.key === \"Home\") {\n nextSize = bounds.minSize;\n } else if (event.key === \"End\") {\n nextSize = bounds.maxSize;\n } else if (orientation === \"horizontal\") {\n if (event.key === \"ArrowRight\") {\n nextSize = currentSize + step * direction;\n } else if (event.key === \"ArrowLeft\") {\n nextSize = currentSize - step * direction;\n }\n } else {\n if (event.key === \"ArrowDown\") {\n nextSize = currentSize + step;\n } else if (event.key === \"ArrowUp\") {\n nextSize = currentSize - step;\n }\n }\n\n if (nextSize === undefined) {\n return;\n }\n\n event.preventDefault();\n\n updateSizes(\n resizePanelPair(\n currentSizes,\n panelConstraints,\n handleIndex,\n nextSize - currentSize,\n ),\n );\n };\n\n let panelIndex = 0;\n\n const enhancedChildren = childrenArray.map((child) => {\n if (isResizablePanelElement(child)) {\n const index = panelIndex++;\n\n return cloneElement(\n child as ReactElement<\n ResizablePanelProps & InternalResizablePanelProps\n >,\n {\n panelIndex: index,\n panelSize: currentSizes[index],\n panelId: panelIds[index],\n },\n );\n }\n\n const handleIndex = panelIndex - 1;\n\n const bounds = getPanelPairBounds(\n currentSizes,\n panelConstraints,\n handleIndex,\n );\n\n return cloneElement(\n child as ReactElement<\n ResizableHandleProps & InternalResizableHandleProps\n >,\n {\n handleIndex,\n orientation,\n value: currentSizes[handleIndex],\n minValue: bounds.minSize,\n maxValue: bounds.maxSize,\n panelIds: [panelIds[handleIndex]!, panelIds[handleIndex + 1]!],\n inheritedDisabled: disabled,\n onResizeStart: handlePointerDown,\n onResizeMove: handlePointerMove,\n onResizeEnd: handlePointerEnd,\n onResizeKeyDown: handleKeyDown,\n },\n );\n });\n\n return (\n <div\n {...rootProps}\n ref={(node) => {\n groupRef.current = node;\n\n if (typeof forwardedRef === \"function\") {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n id={groupId}\n role={role ?? \"group\"}\n className={cn(\"puzzle-resizable-panels\", className)}\n style={style}\n data-orientation={orientation}\n data-disabled={disabled ? \"true\" : undefined}\n data-resizing={isResizing ? \"true\" : undefined}\n >\n {enhancedChildren}\n </div>\n );\n};\n\ntype ResizablePanelsComponent = typeof ResizablePanelsRoot & {\n Panel: typeof ResizablePanel;\n Handle: typeof ResizableHandle;\n};\n\nconst ResizablePanels = Object.assign(ResizablePanelsRoot, {\n Panel: ResizablePanel,\n Handle: ResizableHandle,\n}) as ResizablePanelsComponent;\n\nexport {\n ResizablePanels,\n ResizablePanel,\n ResizableHandle,\n type ResizablePanelsProps,\n type ResizablePanelProps,\n type ResizableHandleProps,\n type ResizablePanelsOrientation,\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resizable-panels.utils.cjs","names":[],"sources":["../../../../src/components/layout/resizable-panels/resizable-panels.utils.ts"],"sourcesContent":["export type PanelSizeConstraint = {\n minSize?: number;\n maxSize?: number;\n};\n\ntype NormalizedPanelSizeConstraint = {\n minSize: number;\n maxSize: number;\n};\n\ntype PanelPairBounds = {\n minSize: number;\n maxSize: number;\n};\n\nconst normalizePanelConstraints = (\n constraints: readonly PanelSizeConstraint[],\n): NormalizedPanelSizeConstraint[] => {\n if (constraints.length < 2) {\n throw new RangeError(\"ResizablePanels requires at least two panels.\");\n }\n\n const normalized = constraints.map((constraint, index) => {\n const minSize = constraint.minSize ?? 0;\n const maxSize = constraint.maxSize ?? 100;\n\n if (\n !Number.isFinite(minSize) ||\n !Number.isFinite(maxSize) ||\n minSize < 0 ||\n maxSize > 100 ||\n minSize > maxSize\n ) {\n throw new RangeError(`Invalid size constraints for panel ${index}.`);\n }\n\n return { minSize, maxSize };\n });\n\n const minimumTotal = normalized.reduce(\n (total, constraint) => total + constraint.minSize,\n 0,\n );\n\n const maximumTotal = normalized.reduce(\n (total, constraint) => total + constraint.maxSize,\n 0,\n );\n\n if (minimumTotal > 100 || maximumTotal < 100) {\n throw new RangeError(\n \"Panel size constraints cannot produce a layout totaling 100%.\",\n );\n }\n\n return normalized;\n};\n\n/**\n * Normalizes panel sizes to 100% while respecting every panel constraint.\n *\n * When a panel reaches its minimum or maximum, the remaining space is\n * distributed proportionally between the other panels.\n */\nconst normalizePanelSizes = (\n sizes: readonly number[] | undefined,\n constraints: readonly PanelSizeConstraint[],\n): number[] => {\n const normalizedConstraints = normalizePanelConstraints(constraints);\n\n if (sizes && sizes.length !== constraints.length) {\n throw new RangeError(\n \"The number of panel sizes must match the number of panels.\",\n );\n }\n\n const weights = normalizedConstraints.map((_, index) => {\n const size = sizes?.[index] ?? 1;\n\n return Number.isFinite(size) ? Math.max(0, size) : 0;\n });\n\n const result = new Array<number>(constraints.length).fill(0);\n\n const unresolved = normalizedConstraints.map((_, index) => index);\n\n let remainingSize = 100;\n\n while (unresolved.length > 0) {\n const activeWeightTotal = unresolved.reduce(\n (total, index) => total + weights[index]
|
|
1
|
+
{"version":3,"file":"resizable-panels.utils.cjs","names":[],"sources":["../../../../src/components/layout/resizable-panels/resizable-panels.utils.ts"],"sourcesContent":["export type PanelSizeConstraint = {\n minSize?: number;\n maxSize?: number;\n};\n\ntype NormalizedPanelSizeConstraint = {\n minSize: number;\n maxSize: number;\n};\n\ntype PanelPairBounds = {\n minSize: number;\n maxSize: number;\n};\n\nconst normalizePanelConstraints = (\n constraints: readonly PanelSizeConstraint[],\n): NormalizedPanelSizeConstraint[] => {\n if (constraints.length < 2) {\n throw new RangeError(\"ResizablePanels requires at least two panels.\");\n }\n\n const normalized = constraints.map((constraint, index) => {\n const minSize = constraint.minSize ?? 0;\n const maxSize = constraint.maxSize ?? 100;\n\n if (\n !Number.isFinite(minSize) ||\n !Number.isFinite(maxSize) ||\n minSize < 0 ||\n maxSize > 100 ||\n minSize > maxSize\n ) {\n throw new RangeError(`Invalid size constraints for panel ${index}.`);\n }\n\n return { minSize, maxSize };\n });\n\n const minimumTotal = normalized.reduce(\n (total, constraint) => total + constraint.minSize,\n 0,\n );\n\n const maximumTotal = normalized.reduce(\n (total, constraint) => total + constraint.maxSize,\n 0,\n );\n\n if (minimumTotal > 100 || maximumTotal < 100) {\n throw new RangeError(\n \"Panel size constraints cannot produce a layout totaling 100%.\",\n );\n }\n\n return normalized;\n};\n\n/**\n * Normalizes panel sizes to 100% while respecting every panel constraint.\n *\n * When a panel reaches its minimum or maximum, the remaining space is\n * distributed proportionally between the other panels.\n */\nconst normalizePanelSizes = (\n sizes: readonly number[] | undefined,\n constraints: readonly PanelSizeConstraint[],\n): number[] => {\n const normalizedConstraints = normalizePanelConstraints(constraints);\n\n if (sizes && sizes.length !== constraints.length) {\n throw new RangeError(\n \"The number of panel sizes must match the number of panels.\",\n );\n }\n\n const weights = normalizedConstraints.map((_, index) => {\n const size = sizes?.[index] ?? 1;\n\n return Number.isFinite(size) ? Math.max(0, size) : 0;\n });\n\n const result = new Array<number>(constraints.length).fill(0);\n\n const unresolved = normalizedConstraints.map((_, index) => index);\n\n let remainingSize = 100;\n\n while (unresolved.length > 0) {\n const activeWeightTotal = unresolved.reduce(\n (total, index) => total + weights[index]!,\n 0,\n );\n\n const useEqualDistribution = activeWeightTotal === 0;\n\n const candidates = unresolved.map((index) => ({\n index,\n size:\n (remainingSize * (useEqualDistribution ? 1 : weights[index]!)) /\n (useEqualDistribution ? unresolved.length : activeWeightTotal),\n }));\n\n const violations = candidates.filter(({ index, size }) => {\n const constraint = normalizedConstraints[index]!;\n\n return size < constraint.minSize || size > constraint.maxSize;\n });\n\n if (violations.length === 0) {\n for (const candidate of candidates) {\n result[candidate.index] = candidate.size;\n }\n\n break;\n }\n\n const clampedViolations = violations.map(({ index, size }) => {\n const constraint = normalizedConstraints[index]!;\n\n return {\n index,\n size,\n fixedSize: Math.min(\n constraint.maxSize,\n Math.max(constraint.minSize, size),\n ),\n };\n });\n\n // Only clamp in the direction of the net correction; clamping both\n // directions at once can overshoot or undershoot 100%.\n const totalCorrection = clampedViolations.reduce(\n (total, { size, fixedSize }) => total + fixedSize - size,\n 0,\n );\n\n const fixedIndexes = new Set<number>();\n\n for (const { index, size, fixedSize } of clampedViolations) {\n if (\n (totalCorrection > 0 && fixedSize < size) ||\n (totalCorrection < 0 && fixedSize > size)\n ) {\n continue;\n }\n\n result[index] = fixedSize;\n remainingSize -= fixedSize;\n fixedIndexes.add(index);\n }\n\n for (let index = unresolved.length - 1; index >= 0; index--) {\n if (fixedIndexes.has(unresolved[index]!)) {\n unresolved.splice(index, 1);\n }\n }\n }\n\n return result;\n};\n\n/**\n * Returns the allowed size range of the first panel in a pair.\n *\n * Both panels retain their combined size during resizing.\n */\nconst getPanelPairBounds = (\n sizes: readonly number[],\n constraints: readonly PanelSizeConstraint[],\n panelIndex: number,\n): PanelPairBounds => {\n const normalizedConstraints = normalizePanelConstraints(constraints);\n\n const normalizedSizes = normalizePanelSizes(sizes, normalizedConstraints);\n\n if (\n !Number.isInteger(panelIndex) ||\n panelIndex < 0 ||\n panelIndex >= normalizedSizes.length - 1\n ) {\n throw new RangeError(\"Invalid panel resize index.\");\n }\n\n // The guard above ensures both panels of the pair exist.\n const first = normalizedConstraints[panelIndex]!;\n const second = normalizedConstraints[panelIndex + 1]!;\n\n const combinedSize =\n normalizedSizes[panelIndex]! + normalizedSizes[panelIndex + 1]!;\n\n return {\n minSize: Math.max(first.minSize, combinedSize - second.maxSize),\n maxSize: Math.min(first.maxSize, combinedSize - second.minSize),\n };\n};\n\n/**\n * Resizes two adjacent panels while keeping their combined size unchanged.\n *\n * A positive delta increases the first panel.\n * A negative delta decreases the first panel.\n */\nconst resizePanelPair = (\n sizes: readonly number[],\n constraints: readonly PanelSizeConstraint[],\n panelIndex: number,\n delta: number,\n): number[] => {\n if (!Number.isFinite(delta)) {\n throw new RangeError(\"Resize delta must be a finite number.\");\n }\n\n const normalizedSizes = normalizePanelSizes(sizes, constraints);\n\n const bounds = getPanelPairBounds(normalizedSizes, constraints, panelIndex);\n\n // getPanelPairBounds has validated panelIndex.\n const combinedSize =\n normalizedSizes[panelIndex]! + normalizedSizes[panelIndex + 1]!;\n\n const nextFirstSize = Math.min(\n bounds.maxSize,\n Math.max(bounds.minSize, normalizedSizes[panelIndex]! + delta),\n );\n\n const nextSizes = [...normalizedSizes];\n\n nextSizes[panelIndex] = nextFirstSize;\n nextSizes[panelIndex + 1] = combinedSize - nextFirstSize;\n\n return nextSizes;\n};\n\nexport { normalizePanelSizes, getPanelPairBounds, resizePanelPair };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resizable-panels.utils.js","names":[],"sources":["../../../../src/components/layout/resizable-panels/resizable-panels.utils.ts"],"sourcesContent":["export type PanelSizeConstraint = {\n minSize?: number;\n maxSize?: number;\n};\n\ntype NormalizedPanelSizeConstraint = {\n minSize: number;\n maxSize: number;\n};\n\ntype PanelPairBounds = {\n minSize: number;\n maxSize: number;\n};\n\nconst normalizePanelConstraints = (\n constraints: readonly PanelSizeConstraint[],\n): NormalizedPanelSizeConstraint[] => {\n if (constraints.length < 2) {\n throw new RangeError(\"ResizablePanels requires at least two panels.\");\n }\n\n const normalized = constraints.map((constraint, index) => {\n const minSize = constraint.minSize ?? 0;\n const maxSize = constraint.maxSize ?? 100;\n\n if (\n !Number.isFinite(minSize) ||\n !Number.isFinite(maxSize) ||\n minSize < 0 ||\n maxSize > 100 ||\n minSize > maxSize\n ) {\n throw new RangeError(`Invalid size constraints for panel ${index}.`);\n }\n\n return { minSize, maxSize };\n });\n\n const minimumTotal = normalized.reduce(\n (total, constraint) => total + constraint.minSize,\n 0,\n );\n\n const maximumTotal = normalized.reduce(\n (total, constraint) => total + constraint.maxSize,\n 0,\n );\n\n if (minimumTotal > 100 || maximumTotal < 100) {\n throw new RangeError(\n \"Panel size constraints cannot produce a layout totaling 100%.\",\n );\n }\n\n return normalized;\n};\n\n/**\n * Normalizes panel sizes to 100% while respecting every panel constraint.\n *\n * When a panel reaches its minimum or maximum, the remaining space is\n * distributed proportionally between the other panels.\n */\nconst normalizePanelSizes = (\n sizes: readonly number[] | undefined,\n constraints: readonly PanelSizeConstraint[],\n): number[] => {\n const normalizedConstraints = normalizePanelConstraints(constraints);\n\n if (sizes && sizes.length !== constraints.length) {\n throw new RangeError(\n \"The number of panel sizes must match the number of panels.\",\n );\n }\n\n const weights = normalizedConstraints.map((_, index) => {\n const size = sizes?.[index] ?? 1;\n\n return Number.isFinite(size) ? Math.max(0, size) : 0;\n });\n\n const result = new Array<number>(constraints.length).fill(0);\n\n const unresolved = normalizedConstraints.map((_, index) => index);\n\n let remainingSize = 100;\n\n while (unresolved.length > 0) {\n const activeWeightTotal = unresolved.reduce(\n (total, index) => total + weights[index]
|
|
1
|
+
{"version":3,"file":"resizable-panels.utils.js","names":[],"sources":["../../../../src/components/layout/resizable-panels/resizable-panels.utils.ts"],"sourcesContent":["export type PanelSizeConstraint = {\n minSize?: number;\n maxSize?: number;\n};\n\ntype NormalizedPanelSizeConstraint = {\n minSize: number;\n maxSize: number;\n};\n\ntype PanelPairBounds = {\n minSize: number;\n maxSize: number;\n};\n\nconst normalizePanelConstraints = (\n constraints: readonly PanelSizeConstraint[],\n): NormalizedPanelSizeConstraint[] => {\n if (constraints.length < 2) {\n throw new RangeError(\"ResizablePanels requires at least two panels.\");\n }\n\n const normalized = constraints.map((constraint, index) => {\n const minSize = constraint.minSize ?? 0;\n const maxSize = constraint.maxSize ?? 100;\n\n if (\n !Number.isFinite(minSize) ||\n !Number.isFinite(maxSize) ||\n minSize < 0 ||\n maxSize > 100 ||\n minSize > maxSize\n ) {\n throw new RangeError(`Invalid size constraints for panel ${index}.`);\n }\n\n return { minSize, maxSize };\n });\n\n const minimumTotal = normalized.reduce(\n (total, constraint) => total + constraint.minSize,\n 0,\n );\n\n const maximumTotal = normalized.reduce(\n (total, constraint) => total + constraint.maxSize,\n 0,\n );\n\n if (minimumTotal > 100 || maximumTotal < 100) {\n throw new RangeError(\n \"Panel size constraints cannot produce a layout totaling 100%.\",\n );\n }\n\n return normalized;\n};\n\n/**\n * Normalizes panel sizes to 100% while respecting every panel constraint.\n *\n * When a panel reaches its minimum or maximum, the remaining space is\n * distributed proportionally between the other panels.\n */\nconst normalizePanelSizes = (\n sizes: readonly number[] | undefined,\n constraints: readonly PanelSizeConstraint[],\n): number[] => {\n const normalizedConstraints = normalizePanelConstraints(constraints);\n\n if (sizes && sizes.length !== constraints.length) {\n throw new RangeError(\n \"The number of panel sizes must match the number of panels.\",\n );\n }\n\n const weights = normalizedConstraints.map((_, index) => {\n const size = sizes?.[index] ?? 1;\n\n return Number.isFinite(size) ? Math.max(0, size) : 0;\n });\n\n const result = new Array<number>(constraints.length).fill(0);\n\n const unresolved = normalizedConstraints.map((_, index) => index);\n\n let remainingSize = 100;\n\n while (unresolved.length > 0) {\n const activeWeightTotal = unresolved.reduce(\n (total, index) => total + weights[index]!,\n 0,\n );\n\n const useEqualDistribution = activeWeightTotal === 0;\n\n const candidates = unresolved.map((index) => ({\n index,\n size:\n (remainingSize * (useEqualDistribution ? 1 : weights[index]!)) /\n (useEqualDistribution ? unresolved.length : activeWeightTotal),\n }));\n\n const violations = candidates.filter(({ index, size }) => {\n const constraint = normalizedConstraints[index]!;\n\n return size < constraint.minSize || size > constraint.maxSize;\n });\n\n if (violations.length === 0) {\n for (const candidate of candidates) {\n result[candidate.index] = candidate.size;\n }\n\n break;\n }\n\n const clampedViolations = violations.map(({ index, size }) => {\n const constraint = normalizedConstraints[index]!;\n\n return {\n index,\n size,\n fixedSize: Math.min(\n constraint.maxSize,\n Math.max(constraint.minSize, size),\n ),\n };\n });\n\n // Only clamp in the direction of the net correction; clamping both\n // directions at once can overshoot or undershoot 100%.\n const totalCorrection = clampedViolations.reduce(\n (total, { size, fixedSize }) => total + fixedSize - size,\n 0,\n );\n\n const fixedIndexes = new Set<number>();\n\n for (const { index, size, fixedSize } of clampedViolations) {\n if (\n (totalCorrection > 0 && fixedSize < size) ||\n (totalCorrection < 0 && fixedSize > size)\n ) {\n continue;\n }\n\n result[index] = fixedSize;\n remainingSize -= fixedSize;\n fixedIndexes.add(index);\n }\n\n for (let index = unresolved.length - 1; index >= 0; index--) {\n if (fixedIndexes.has(unresolved[index]!)) {\n unresolved.splice(index, 1);\n }\n }\n }\n\n return result;\n};\n\n/**\n * Returns the allowed size range of the first panel in a pair.\n *\n * Both panels retain their combined size during resizing.\n */\nconst getPanelPairBounds = (\n sizes: readonly number[],\n constraints: readonly PanelSizeConstraint[],\n panelIndex: number,\n): PanelPairBounds => {\n const normalizedConstraints = normalizePanelConstraints(constraints);\n\n const normalizedSizes = normalizePanelSizes(sizes, normalizedConstraints);\n\n if (\n !Number.isInteger(panelIndex) ||\n panelIndex < 0 ||\n panelIndex >= normalizedSizes.length - 1\n ) {\n throw new RangeError(\"Invalid panel resize index.\");\n }\n\n // The guard above ensures both panels of the pair exist.\n const first = normalizedConstraints[panelIndex]!;\n const second = normalizedConstraints[panelIndex + 1]!;\n\n const combinedSize =\n normalizedSizes[panelIndex]! + normalizedSizes[panelIndex + 1]!;\n\n return {\n minSize: Math.max(first.minSize, combinedSize - second.maxSize),\n maxSize: Math.min(first.maxSize, combinedSize - second.minSize),\n };\n};\n\n/**\n * Resizes two adjacent panels while keeping their combined size unchanged.\n *\n * A positive delta increases the first panel.\n * A negative delta decreases the first panel.\n */\nconst resizePanelPair = (\n sizes: readonly number[],\n constraints: readonly PanelSizeConstraint[],\n panelIndex: number,\n delta: number,\n): number[] => {\n if (!Number.isFinite(delta)) {\n throw new RangeError(\"Resize delta must be a finite number.\");\n }\n\n const normalizedSizes = normalizePanelSizes(sizes, constraints);\n\n const bounds = getPanelPairBounds(normalizedSizes, constraints, panelIndex);\n\n // getPanelPairBounds has validated panelIndex.\n const combinedSize =\n normalizedSizes[panelIndex]! + normalizedSizes[panelIndex + 1]!;\n\n const nextFirstSize = Math.min(\n bounds.maxSize,\n Math.max(bounds.minSize, normalizedSizes[panelIndex]! + delta),\n );\n\n const nextSizes = [...normalizedSizes];\n\n nextSizes[panelIndex] = nextFirstSize;\n nextSizes[panelIndex + 1] = combinedSize - nextFirstSize;\n\n return nextSizes;\n};\n\nexport { normalizePanelSizes, getPanelPairBounds, resizePanelPair };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["useId","useRef","useState","cn","Fragment","Transition"],"sources":["../../../../src/components/navigation/accordion/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Fragment,\n useId,\n useState,\n useRef,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport { Transition } from \"../../utilities/transition\";\nimport \"./accordion.css\";\n\ntype AccordionType = \"single\" | \"multiple\";\ntype AccordionItemId = string | number;\ntype AccordionValue =\n | AccordionItemId\n | readonly AccordionItemId[]\n | null;\n\ntype AccordionItemData = {\n /** Stable key for the item when the list is reordered. */\n id?: string | number;\n\n /** Visible title of the accordion item. */\n title: ReactNode;\n\n /** Content shown when the item is expanded. */\n content: ReactNode;\n\n /** Prevents the item from being toggled by the user. */\n disabled?: boolean;\n};\n\ntype AccordionProps = Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"children\" | \"onChange\"\n> & {\n /** Items displayed by the accordion. */\n items: AccordionItemData[];\n\n /** Initial expanded indexes for uncontrolled usage. Defaults to []. */\n initialOpenItemIndexes?: number[];\n\n /** Expanded indexes for controlled usage. */\n openItemIndexes?: number[];\n\n /** Called with the next expanded indexes after user interaction. */\n onChange?: (openItemIndexes: number[]) => void;\n\n /** Expanded item ID(s). Requires an ID on every item. */\n value?: AccordionValue;\n\n /** Initially expanded item ID(s). Requires an ID on every item. */\n defaultValue?: AccordionValue;\n\n /** Called with the next expanded item ID(s). */\n onValueChange?: (value: AccordionItemId | AccordionItemId[] | null) => void;\n\n /** Whether multiple items can be expanded simultaneously. */\n type?: AccordionType;\n\n /** Allow the currently expanded item to collapse in single mode. */\n collapsible?: boolean;\n\n /** Semantic heading level used for each item. Defaults to 3. */\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n\n /** Adds region landmarks to the panels. Defaults to true for <= 6 items. */\n region?: boolean;\n\n /** Class applied to each trigger button. */\n triggerClassName?: string;\n\n /** Class applied to each animated panel. */\n panelClassName?: string;\n\n /** Class applied to the panel content wrapper. */\n contentClassName?: string;\n\n /** Unmount panel content after its closing animation completes. Defaults to false. */\n unMountOnClose?: boolean;\n};\n\nconst normalizeOpenItemIndexes = (\n indexes: number[] | undefined,\n itemCount: number,\n type: AccordionType,\n): number[] => {\n const validIndexes = Array.from(\n new Set(\n (indexes ?? []).filter(\n (index) => Number.isInteger(index) && index >= 0 && index < itemCount,\n ),\n ),\n );\n\n if (type === \"single\") {\n return validIndexes.slice(0, 1);\n }\n\n return validIndexes.sort((a, b) => a - b);\n};\n\nconst normalizeOpenItemIds = (\n value: AccordionValue | undefined,\n type: AccordionType,\n): AccordionItemId[] => {\n const ids =\n value == null ? [] : Array.isArray(value) ? [...value] : [value];\n const uniqueIds = Array.from(new Set(ids));\n\n return type === \"single\" ? uniqueIds.slice(0, 1) : uniqueIds;\n};\n\nconst Accordion = ({\n items,\n initialOpenItemIndexes,\n openItemIndexes,\n onChange,\n value,\n defaultValue,\n onValueChange,\n type = \"multiple\",\n collapsible = true,\n headingLevel = 3,\n region,\n className,\n triggerClassName,\n panelClassName,\n contentClassName,\n unMountOnClose = false,\n ...rootProps\n}: AccordionProps) => {\n const generatedId = useId();\n const isValueMode = value !== undefined || defaultValue !== undefined;\n const isValueControlled = value !== undefined;\n const triggerRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const contentRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n if (isValueMode) {\n const itemIds = new Set<string>();\n\n for (const item of items) {\n if (item.id === undefined) {\n throw new Error(\n \"Accordion value and defaultValue require an id on every item.\",\n );\n }\n\n const key = `${typeof item.id}:${item.id}`;\n\n if (itemIds.has(key)) {\n throw new Error(\"Accordion item IDs must be unique.\");\n }\n\n itemIds.add(key);\n }\n }\n\n const [uncontrolledOpenItemIndexes, setUncontrolledOpenItemIndexes] =\n useState<number[]>(() =>\n normalizeOpenItemIndexes(initialOpenItemIndexes, items.length, type),\n );\n\n const [uncontrolledOpenItemIds, setUncontrolledOpenItemIds] = useState<\n AccordionItemId[]\n >(() => normalizeOpenItemIds(defaultValue, type));\n\n const requestedOpenItemIds = normalizeOpenItemIds(\n isValueControlled ? value : uncontrolledOpenItemIds,\n type,\n );\n const currentOpenItemIndexes = isValueMode\n ? items.flatMap((item, index) =>\n requestedOpenItemIds.includes(item.id as AccordionItemId) ? [index] : [],\n )\n : normalizeOpenItemIndexes(\n openItemIndexes ?? uncontrolledOpenItemIndexes,\n items.length,\n type,\n );\n\n const HeadingTag = `h${headingLevel}` as\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\";\n\n // Avoid excessive landmark regions in long accordions.\n const useRegions = region ?? items.length <= 6;\n\n const handleToggle = (index: number, disabled = false) => {\n if (disabled) {\n return;\n }\n\n const isOpen = currentOpenItemIndexes.includes(index);\n\n if (type === \"single\" && isOpen && !collapsible) {\n return;\n }\n\n const nextOpenItemIndexes = normalizeOpenItemIndexes(\n type === \"single\"\n ? isOpen\n ? []\n : [index]\n : isOpen\n ? currentOpenItemIndexes.filter((openIndex) => openIndex !== index)\n : [...currentOpenItemIndexes, index],\n items.length,\n type,\n );\n\n if (isValueMode) {\n const nextIds = nextOpenItemIndexes.map(\n (openIndex) => items[openIndex].id as AccordionItemId,\n );\n\n if (!isValueControlled) {\n setUncontrolledOpenItemIds(nextIds);\n }\n\n onValueChange?.(\n type === \"single\" ? (nextIds[0] ?? null) : nextIds,\n );\n } else if (openItemIndexes === undefined) {\n setUncontrolledOpenItemIndexes(nextOpenItemIndexes);\n }\n\n onChange?.(nextOpenItemIndexes);\n };\n\n return (\n <div className={cn(\"puzzle-accordion\", className)} {...rootProps}>\n {items.map((item, index) => {\n const isOpen = currentOpenItemIndexes.includes(index);\n const cannotCollapse = type === \"single\" && isOpen && !collapsible;\n\n const triggerId = `${generatedId}-trigger-${index}`;\n const panelId = `${generatedId}-panel-${index}`;\n\n return (\n <Fragment\n key={\n item.id === undefined\n ? index\n : `${typeof item.id}:${item.id}`\n }\n >\n <HeadingTag className=\"puzzle-accordion__heading\">\n <button\n ref={(node) => {\n triggerRefs.current[index] = node;\n }}\n id={triggerId}\n type=\"button\"\n className={cn(\"puzzle-accordion__trigger\", triggerClassName)}\n aria-expanded={isOpen}\n aria-controls={panelId}\n aria-disabled={cannotCollapse || undefined}\n data-state={isOpen ? \"open\" : \"closed\"}\n disabled={item.disabled}\n onClick={() => handleToggle(index, item.disabled)}\n >\n {item.title}\n </button>\n </HeadingTag>\n\n <Transition\n visible={isOpen}\n template=\"accordion\"\n duration={300}\n unmountOnExit={unMountOnClose}\n className={panelClassName}\n id={panelId}\n role={useRegions ? \"region\" : undefined}\n aria-labelledby={useRegions ? triggerId : undefined}\n aria-hidden={!isOpen}\n inert={!isOpen}\n data-state={isOpen ? \"open\" : \"closed\"}\n >\n <div\n ref={(node) => {\n contentRefs.current[index] = node;\n }}\n className=\"puzzle-accordion__panel\"\n >\n <div className=\"puzzle-accordion__panel-inner\">\n <div\n className={cn(\n \"puzzle-accordion__content\",\n contentClassName,\n )}\n >\n {item.content}\n </div>\n </div>\n </div>\n </Transition>\n </Fragment>\n );\n })}\n </div>\n );\n};\n\nexport {\n Accordion,\n type AccordionProps,\n type AccordionItemData,\n type AccordionType,\n type AccordionItemId,\n type AccordionValue,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["useId","useRef","useState","cn","Fragment","Transition"],"sources":["../../../../src/components/navigation/accordion/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Fragment,\n useId,\n useState,\n useRef,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport { Transition } from \"../../utilities/transition\";\nimport \"./accordion.css\";\n\ntype AccordionType = \"single\" | \"multiple\";\ntype AccordionItemId = string | number;\ntype AccordionValue =\n | AccordionItemId\n | readonly AccordionItemId[]\n | null;\n\ntype AccordionItemData = {\n /** Stable key for the item when the list is reordered. */\n id?: string | number;\n\n /** Visible title of the accordion item. */\n title: ReactNode;\n\n /** Content shown when the item is expanded. */\n content: ReactNode;\n\n /** Prevents the item from being toggled by the user. */\n disabled?: boolean;\n};\n\ntype AccordionProps = Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"children\" | \"onChange\"\n> & {\n /** Items displayed by the accordion. */\n items: AccordionItemData[];\n\n /** Initial expanded indexes for uncontrolled usage. Defaults to []. */\n initialOpenItemIndexes?: number[];\n\n /** Expanded indexes for controlled usage. */\n openItemIndexes?: number[];\n\n /** Called with the next expanded indexes after user interaction. */\n onChange?: (openItemIndexes: number[]) => void;\n\n /** Expanded item ID(s). Requires an ID on every item. */\n value?: AccordionValue;\n\n /** Initially expanded item ID(s). Requires an ID on every item. */\n defaultValue?: AccordionValue;\n\n /** Called with the next expanded item ID(s). */\n onValueChange?: (value: AccordionItemId | AccordionItemId[] | null) => void;\n\n /** Whether multiple items can be expanded simultaneously. */\n type?: AccordionType;\n\n /** Allow the currently expanded item to collapse in single mode. */\n collapsible?: boolean;\n\n /** Semantic heading level used for each item. Defaults to 3. */\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n\n /** Adds region landmarks to the panels. Defaults to true for <= 6 items. */\n region?: boolean;\n\n /** Class applied to each trigger button. */\n triggerClassName?: string;\n\n /** Class applied to each animated panel. */\n panelClassName?: string;\n\n /** Class applied to the panel content wrapper. */\n contentClassName?: string;\n\n /** Unmount panel content after its closing animation completes. Defaults to false. */\n unMountOnClose?: boolean;\n};\n\nconst normalizeOpenItemIndexes = (\n indexes: number[] | undefined,\n itemCount: number,\n type: AccordionType,\n): number[] => {\n const validIndexes = Array.from(\n new Set(\n (indexes ?? []).filter(\n (index) => Number.isInteger(index) && index >= 0 && index < itemCount,\n ),\n ),\n );\n\n if (type === \"single\") {\n return validIndexes.slice(0, 1);\n }\n\n return validIndexes.sort((a, b) => a - b);\n};\n\nconst normalizeOpenItemIds = (\n value: AccordionValue | undefined,\n type: AccordionType,\n): AccordionItemId[] => {\n const ids =\n value == null ? [] : Array.isArray(value) ? [...value] : [value];\n const uniqueIds = Array.from(new Set(ids));\n\n return type === \"single\" ? uniqueIds.slice(0, 1) : uniqueIds;\n};\n\nconst Accordion = ({\n items,\n initialOpenItemIndexes,\n openItemIndexes,\n onChange,\n value,\n defaultValue,\n onValueChange,\n type = \"multiple\",\n collapsible = true,\n headingLevel = 3,\n region,\n className,\n triggerClassName,\n panelClassName,\n contentClassName,\n unMountOnClose = false,\n ...rootProps\n}: AccordionProps) => {\n const generatedId = useId();\n const isValueMode = value !== undefined || defaultValue !== undefined;\n const isValueControlled = value !== undefined;\n const triggerRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const contentRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n if (isValueMode) {\n const itemIds = new Set<string>();\n\n for (const item of items) {\n if (item.id === undefined) {\n throw new Error(\n \"Accordion value and defaultValue require an id on every item.\",\n );\n }\n\n const key = `${typeof item.id}:${item.id}`;\n\n if (itemIds.has(key)) {\n throw new Error(\"Accordion item IDs must be unique.\");\n }\n\n itemIds.add(key);\n }\n }\n\n const [uncontrolledOpenItemIndexes, setUncontrolledOpenItemIndexes] =\n useState<number[]>(() =>\n normalizeOpenItemIndexes(initialOpenItemIndexes, items.length, type),\n );\n\n const [uncontrolledOpenItemIds, setUncontrolledOpenItemIds] = useState<\n AccordionItemId[]\n >(() => normalizeOpenItemIds(defaultValue, type));\n\n const requestedOpenItemIds = normalizeOpenItemIds(\n isValueControlled ? value : uncontrolledOpenItemIds,\n type,\n );\n const currentOpenItemIndexes = isValueMode\n ? items.flatMap((item, index) =>\n requestedOpenItemIds.includes(item.id as AccordionItemId) ? [index] : [],\n )\n : normalizeOpenItemIndexes(\n openItemIndexes ?? uncontrolledOpenItemIndexes,\n items.length,\n type,\n );\n\n const HeadingTag = `h${headingLevel}` as\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\";\n\n // Avoid excessive landmark regions in long accordions.\n const useRegions = region ?? items.length <= 6;\n\n const handleToggle = (index: number, disabled = false) => {\n if (disabled) {\n return;\n }\n\n const isOpen = currentOpenItemIndexes.includes(index);\n\n if (type === \"single\" && isOpen && !collapsible) {\n return;\n }\n\n const nextOpenItemIndexes = normalizeOpenItemIndexes(\n type === \"single\"\n ? isOpen\n ? []\n : [index]\n : isOpen\n ? currentOpenItemIndexes.filter((openIndex) => openIndex !== index)\n : [...currentOpenItemIndexes, index],\n items.length,\n type,\n );\n\n if (isValueMode) {\n const nextIds = nextOpenItemIndexes.map(\n (openIndex) => items[openIndex]!.id as AccordionItemId,\n );\n\n if (!isValueControlled) {\n setUncontrolledOpenItemIds(nextIds);\n }\n\n onValueChange?.(\n type === \"single\" ? (nextIds[0] ?? null) : nextIds,\n );\n } else if (openItemIndexes === undefined) {\n setUncontrolledOpenItemIndexes(nextOpenItemIndexes);\n }\n\n onChange?.(nextOpenItemIndexes);\n };\n\n return (\n <div className={cn(\"puzzle-accordion\", className)} {...rootProps}>\n {items.map((item, index) => {\n const isOpen = currentOpenItemIndexes.includes(index);\n const cannotCollapse = type === \"single\" && isOpen && !collapsible;\n\n const triggerId = `${generatedId}-trigger-${index}`;\n const panelId = `${generatedId}-panel-${index}`;\n\n return (\n <Fragment\n key={\n item.id === undefined\n ? index\n : `${typeof item.id}:${item.id}`\n }\n >\n <HeadingTag className=\"puzzle-accordion__heading\">\n <button\n ref={(node) => {\n triggerRefs.current[index] = node;\n }}\n id={triggerId}\n type=\"button\"\n className={cn(\"puzzle-accordion__trigger\", triggerClassName)}\n aria-expanded={isOpen}\n aria-controls={panelId}\n aria-disabled={cannotCollapse || undefined}\n data-state={isOpen ? \"open\" : \"closed\"}\n disabled={item.disabled}\n onClick={() => handleToggle(index, item.disabled)}\n >\n {item.title}\n </button>\n </HeadingTag>\n\n <Transition\n visible={isOpen}\n template=\"accordion\"\n duration={300}\n unmountOnExit={unMountOnClose}\n className={panelClassName}\n id={panelId}\n role={useRegions ? \"region\" : undefined}\n aria-labelledby={useRegions ? triggerId : undefined}\n aria-hidden={!isOpen}\n inert={!isOpen}\n data-state={isOpen ? \"open\" : \"closed\"}\n >\n <div\n ref={(node) => {\n contentRefs.current[index] = node;\n }}\n className=\"puzzle-accordion__panel\"\n >\n <div className=\"puzzle-accordion__panel-inner\">\n <div\n className={cn(\n \"puzzle-accordion__content\",\n contentClassName,\n )}\n >\n {item.content}\n </div>\n </div>\n </div>\n </Transition>\n </Fragment>\n );\n })}\n </div>\n );\n};\n\nexport {\n Accordion,\n type AccordionProps,\n type AccordionItemData,\n type AccordionType,\n type AccordionItemId,\n type AccordionValue,\n};\n"],"mappings":";;;;;;;AAqFA,MAAM,4BACJ,SACA,WACA,SACa;CACb,MAAM,eAAe,MAAM,KACzB,IAAI,KACD,WAAW,CAAC,EAAA,CAAG,QACb,UAAU,OAAO,UAAU,KAAK,KAAK,SAAS,KAAK,QAAQ,SAC9D,CACF,CACF;CAEA,IAAI,SAAS,UACX,OAAO,aAAa,MAAM,GAAG,CAAC;CAGhC,OAAO,aAAa,MAAM,GAAG,MAAM,IAAI,CAAC;AAC1C;AAEA,MAAM,wBACJ,OACA,SACsB;CACtB,MAAM,MACJ,SAAS,OAAO,CAAC,IAAI,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK;CACjE,MAAM,YAAY,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC;CAEzC,OAAO,SAAS,WAAW,UAAU,MAAM,GAAG,CAAC,IAAI;AACrD;AAEA,MAAM,aAAa,EACjB,OACA,wBACA,iBACA,UACA,OACA,cACA,eACA,OAAO,YACP,cAAc,MACd,eAAe,GACf,QACA,WACA,kBACA,gBACA,kBACA,iBAAiB,OACjB,GAAG,gBACiB;CACpB,MAAM,eAAA,GAAcA,MAAAA,MAAAA,CAAM;CAC1B,MAAM,cAAc,UAAU,KAAA,KAAa,iBAAiB,KAAA;CAC5D,MAAM,oBAAoB,UAAU,KAAA;CACpC,MAAM,eAAA,GAAcC,MAAAA,OAAAA,CAAqC,CAAC,CAAC;CAC3D,MAAM,eAAA,GAAcA,MAAAA,OAAAA,CAAkC,CAAC,CAAC;CAExD,IAAI,aAAa;EACf,MAAM,0BAAU,IAAI,IAAY;EAEhC,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,KAAK,OAAO,KAAA,GACd,MAAM,IAAI,MACR,+DACF;GAGF,MAAM,MAAM,GAAG,OAAO,KAAK,GAAG,GAAG,KAAK;GAEtC,IAAI,QAAQ,IAAI,GAAG,GACjB,MAAM,IAAI,MAAM,oCAAoC;GAGtD,QAAQ,IAAI,GAAG;EACjB;CACF;CAEA,MAAM,CAAC,6BAA6B,mCAAA,GAClCC,MAAAA,SAAAA,OACE,yBAAyB,wBAAwB,MAAM,QAAQ,IAAI,CACrE;CAEF,MAAM,CAAC,yBAAyB,+BAAA,GAA8BA,MAAAA,SAAAA,OAEtD,qBAAqB,cAAc,IAAI,CAAC;CAEhD,MAAM,uBAAuB,qBAC3B,oBAAoB,QAAQ,yBAC5B,IACF;CACA,MAAM,yBAAyB,cAC3B,MAAM,SAAS,MAAM,UACnB,qBAAqB,SAAS,KAAK,EAAqB,IAAI,CAAC,KAAK,IAAI,CAAC,CACzE,IACA,yBACE,mBAAmB,6BACnB,MAAM,QACN,IACF;CAEJ,MAAM,aAAa,IAAI;CASvB,MAAM,aAAa,UAAU,MAAM,UAAU;CAE7C,MAAM,gBAAgB,OAAe,WAAW,UAAU;EACxD,IAAI,UACF;EAGF,MAAM,SAAS,uBAAuB,SAAS,KAAK;EAEpD,IAAI,SAAS,YAAY,UAAU,CAAC,aAClC;EAGF,MAAM,sBAAsB,yBAC1B,SAAS,WACL,SACE,CAAC,IACD,CAAC,KAAK,IACR,SACE,uBAAuB,QAAQ,cAAc,cAAc,KAAK,IAChE,CAAC,GAAG,wBAAwB,KAAK,GACvC,MAAM,QACN,IACF;EAEA,IAAI,aAAa;GACf,MAAM,UAAU,oBAAoB,KACjC,cAAc,MAAM,UAAU,CAAE,EACnC;GAEA,IAAI,CAAC,mBACH,2BAA2B,OAAO;GAGpC,gBACE,SAAS,WAAY,QAAQ,MAAM,OAAQ,OAC7C;EACF,OAAO,IAAI,oBAAoB,KAAA,GAC7B,+BAA+B,mBAAmB;EAGpD,WAAW,mBAAmB;CAChC;CAEA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,YAAA,GAAWC,gBAAAA,GAAAA,CAAG,oBAAoB,SAAS;EAAG,GAAI;EACpD,UAAA,MAAM,KAAK,MAAM,UAAU;GAC1B,MAAM,SAAS,uBAAuB,SAAS,KAAK;GACpD,MAAM,iBAAiB,SAAS,YAAY,UAAU,CAAC;GAEvD,MAAM,YAAY,GAAG,YAAY,WAAW;GAC5C,MAAM,UAAU,GAAG,YAAY,SAAS;GAExC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAACC,MAAAA,UAAD,EAAA,UAAA,CAOE,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;IAAY,WAAU;IACpB,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KACE,MAAM,SAAS;MACb,YAAY,QAAQ,SAAS;KAC/B;KACA,IAAI;KACJ,MAAK;KACL,YAAA,GAAWD,gBAAAA,GAAAA,CAAG,6BAA6B,gBAAgB;KAC3D,iBAAe;KACf,iBAAe;KACf,iBAAe,kBAAkB,KAAA;KACjC,cAAY,SAAS,SAAS;KAC9B,UAAU,KAAK;KACf,eAAe,aAAa,OAAO,KAAK,QAAQ;KAE/C,UAAA,KAAK;IACA,CAAA;GACE,CAAA,GAEZ,iBAAA,GAAA,kBAAA,IAAA,CAACE,cAAAA,YAAD;IACE,SAAS;IACT,UAAS;IACT,UAAU;IACV,eAAe;IACf,WAAW;IACX,IAAI;IACJ,MAAM,aAAa,WAAW,KAAA;IAC9B,mBAAiB,aAAa,YAAY,KAAA;IAC1C,eAAa,CAAC;IACd,OAAO,CAAC;IACR,cAAY,SAAS,SAAS;IAE9B,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KACE,MAAM,SAAS;MACb,YAAY,QAAQ,SAAS;KAC/B;KACA,WAAU;KAEV,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAU;MACb,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OACE,YAAA,GAAWF,gBAAAA,GAAAA,CACT,6BACA,gBACF;OAEC,UAAA,KAAK;MACH,CAAA;KACF,CAAA;IACF,CAAA;GACK,CAAA,CACJ,EAAA,GAvDN,KAAK,OAAO,KAAA,IACR,QACA,GAAG,OAAO,KAAK,GAAG,GAAG,KAAK,IAqDxB;EAEd,CAAC;CACE,CAAA;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/navigation/accordion/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Fragment,\n useId,\n useState,\n useRef,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport { Transition } from \"../../utilities/transition\";\nimport \"./accordion.css\";\n\ntype AccordionType = \"single\" | \"multiple\";\ntype AccordionItemId = string | number;\ntype AccordionValue =\n | AccordionItemId\n | readonly AccordionItemId[]\n | null;\n\ntype AccordionItemData = {\n /** Stable key for the item when the list is reordered. */\n id?: string | number;\n\n /** Visible title of the accordion item. */\n title: ReactNode;\n\n /** Content shown when the item is expanded. */\n content: ReactNode;\n\n /** Prevents the item from being toggled by the user. */\n disabled?: boolean;\n};\n\ntype AccordionProps = Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"children\" | \"onChange\"\n> & {\n /** Items displayed by the accordion. */\n items: AccordionItemData[];\n\n /** Initial expanded indexes for uncontrolled usage. Defaults to []. */\n initialOpenItemIndexes?: number[];\n\n /** Expanded indexes for controlled usage. */\n openItemIndexes?: number[];\n\n /** Called with the next expanded indexes after user interaction. */\n onChange?: (openItemIndexes: number[]) => void;\n\n /** Expanded item ID(s). Requires an ID on every item. */\n value?: AccordionValue;\n\n /** Initially expanded item ID(s). Requires an ID on every item. */\n defaultValue?: AccordionValue;\n\n /** Called with the next expanded item ID(s). */\n onValueChange?: (value: AccordionItemId | AccordionItemId[] | null) => void;\n\n /** Whether multiple items can be expanded simultaneously. */\n type?: AccordionType;\n\n /** Allow the currently expanded item to collapse in single mode. */\n collapsible?: boolean;\n\n /** Semantic heading level used for each item. Defaults to 3. */\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n\n /** Adds region landmarks to the panels. Defaults to true for <= 6 items. */\n region?: boolean;\n\n /** Class applied to each trigger button. */\n triggerClassName?: string;\n\n /** Class applied to each animated panel. */\n panelClassName?: string;\n\n /** Class applied to the panel content wrapper. */\n contentClassName?: string;\n\n /** Unmount panel content after its closing animation completes. Defaults to false. */\n unMountOnClose?: boolean;\n};\n\nconst normalizeOpenItemIndexes = (\n indexes: number[] | undefined,\n itemCount: number,\n type: AccordionType,\n): number[] => {\n const validIndexes = Array.from(\n new Set(\n (indexes ?? []).filter(\n (index) => Number.isInteger(index) && index >= 0 && index < itemCount,\n ),\n ),\n );\n\n if (type === \"single\") {\n return validIndexes.slice(0, 1);\n }\n\n return validIndexes.sort((a, b) => a - b);\n};\n\nconst normalizeOpenItemIds = (\n value: AccordionValue | undefined,\n type: AccordionType,\n): AccordionItemId[] => {\n const ids =\n value == null ? [] : Array.isArray(value) ? [...value] : [value];\n const uniqueIds = Array.from(new Set(ids));\n\n return type === \"single\" ? uniqueIds.slice(0, 1) : uniqueIds;\n};\n\nconst Accordion = ({\n items,\n initialOpenItemIndexes,\n openItemIndexes,\n onChange,\n value,\n defaultValue,\n onValueChange,\n type = \"multiple\",\n collapsible = true,\n headingLevel = 3,\n region,\n className,\n triggerClassName,\n panelClassName,\n contentClassName,\n unMountOnClose = false,\n ...rootProps\n}: AccordionProps) => {\n const generatedId = useId();\n const isValueMode = value !== undefined || defaultValue !== undefined;\n const isValueControlled = value !== undefined;\n const triggerRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const contentRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n if (isValueMode) {\n const itemIds = new Set<string>();\n\n for (const item of items) {\n if (item.id === undefined) {\n throw new Error(\n \"Accordion value and defaultValue require an id on every item.\",\n );\n }\n\n const key = `${typeof item.id}:${item.id}`;\n\n if (itemIds.has(key)) {\n throw new Error(\"Accordion item IDs must be unique.\");\n }\n\n itemIds.add(key);\n }\n }\n\n const [uncontrolledOpenItemIndexes, setUncontrolledOpenItemIndexes] =\n useState<number[]>(() =>\n normalizeOpenItemIndexes(initialOpenItemIndexes, items.length, type),\n );\n\n const [uncontrolledOpenItemIds, setUncontrolledOpenItemIds] = useState<\n AccordionItemId[]\n >(() => normalizeOpenItemIds(defaultValue, type));\n\n const requestedOpenItemIds = normalizeOpenItemIds(\n isValueControlled ? value : uncontrolledOpenItemIds,\n type,\n );\n const currentOpenItemIndexes = isValueMode\n ? items.flatMap((item, index) =>\n requestedOpenItemIds.includes(item.id as AccordionItemId) ? [index] : [],\n )\n : normalizeOpenItemIndexes(\n openItemIndexes ?? uncontrolledOpenItemIndexes,\n items.length,\n type,\n );\n\n const HeadingTag = `h${headingLevel}` as\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\";\n\n // Avoid excessive landmark regions in long accordions.\n const useRegions = region ?? items.length <= 6;\n\n const handleToggle = (index: number, disabled = false) => {\n if (disabled) {\n return;\n }\n\n const isOpen = currentOpenItemIndexes.includes(index);\n\n if (type === \"single\" && isOpen && !collapsible) {\n return;\n }\n\n const nextOpenItemIndexes = normalizeOpenItemIndexes(\n type === \"single\"\n ? isOpen\n ? []\n : [index]\n : isOpen\n ? currentOpenItemIndexes.filter((openIndex) => openIndex !== index)\n : [...currentOpenItemIndexes, index],\n items.length,\n type,\n );\n\n if (isValueMode) {\n const nextIds = nextOpenItemIndexes.map(\n (openIndex) => items[openIndex].id as AccordionItemId,\n );\n\n if (!isValueControlled) {\n setUncontrolledOpenItemIds(nextIds);\n }\n\n onValueChange?.(\n type === \"single\" ? (nextIds[0] ?? null) : nextIds,\n );\n } else if (openItemIndexes === undefined) {\n setUncontrolledOpenItemIndexes(nextOpenItemIndexes);\n }\n\n onChange?.(nextOpenItemIndexes);\n };\n\n return (\n <div className={cn(\"puzzle-accordion\", className)} {...rootProps}>\n {items.map((item, index) => {\n const isOpen = currentOpenItemIndexes.includes(index);\n const cannotCollapse = type === \"single\" && isOpen && !collapsible;\n\n const triggerId = `${generatedId}-trigger-${index}`;\n const panelId = `${generatedId}-panel-${index}`;\n\n return (\n <Fragment\n key={\n item.id === undefined\n ? index\n : `${typeof item.id}:${item.id}`\n }\n >\n <HeadingTag className=\"puzzle-accordion__heading\">\n <button\n ref={(node) => {\n triggerRefs.current[index] = node;\n }}\n id={triggerId}\n type=\"button\"\n className={cn(\"puzzle-accordion__trigger\", triggerClassName)}\n aria-expanded={isOpen}\n aria-controls={panelId}\n aria-disabled={cannotCollapse || undefined}\n data-state={isOpen ? \"open\" : \"closed\"}\n disabled={item.disabled}\n onClick={() => handleToggle(index, item.disabled)}\n >\n {item.title}\n </button>\n </HeadingTag>\n\n <Transition\n visible={isOpen}\n template=\"accordion\"\n duration={300}\n unmountOnExit={unMountOnClose}\n className={panelClassName}\n id={panelId}\n role={useRegions ? \"region\" : undefined}\n aria-labelledby={useRegions ? triggerId : undefined}\n aria-hidden={!isOpen}\n inert={!isOpen}\n data-state={isOpen ? \"open\" : \"closed\"}\n >\n <div\n ref={(node) => {\n contentRefs.current[index] = node;\n }}\n className=\"puzzle-accordion__panel\"\n >\n <div className=\"puzzle-accordion__panel-inner\">\n <div\n className={cn(\n \"puzzle-accordion__content\",\n contentClassName,\n )}\n >\n {item.content}\n </div>\n </div>\n </div>\n </Transition>\n </Fragment>\n );\n })}\n </div>\n );\n};\n\nexport {\n Accordion,\n type AccordionProps,\n type AccordionItemData,\n type AccordionType,\n type AccordionItemId,\n type AccordionValue,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/navigation/accordion/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Fragment,\n useId,\n useState,\n useRef,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport { Transition } from \"../../utilities/transition\";\nimport \"./accordion.css\";\n\ntype AccordionType = \"single\" | \"multiple\";\ntype AccordionItemId = string | number;\ntype AccordionValue =\n | AccordionItemId\n | readonly AccordionItemId[]\n | null;\n\ntype AccordionItemData = {\n /** Stable key for the item when the list is reordered. */\n id?: string | number;\n\n /** Visible title of the accordion item. */\n title: ReactNode;\n\n /** Content shown when the item is expanded. */\n content: ReactNode;\n\n /** Prevents the item from being toggled by the user. */\n disabled?: boolean;\n};\n\ntype AccordionProps = Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"children\" | \"onChange\"\n> & {\n /** Items displayed by the accordion. */\n items: AccordionItemData[];\n\n /** Initial expanded indexes for uncontrolled usage. Defaults to []. */\n initialOpenItemIndexes?: number[];\n\n /** Expanded indexes for controlled usage. */\n openItemIndexes?: number[];\n\n /** Called with the next expanded indexes after user interaction. */\n onChange?: (openItemIndexes: number[]) => void;\n\n /** Expanded item ID(s). Requires an ID on every item. */\n value?: AccordionValue;\n\n /** Initially expanded item ID(s). Requires an ID on every item. */\n defaultValue?: AccordionValue;\n\n /** Called with the next expanded item ID(s). */\n onValueChange?: (value: AccordionItemId | AccordionItemId[] | null) => void;\n\n /** Whether multiple items can be expanded simultaneously. */\n type?: AccordionType;\n\n /** Allow the currently expanded item to collapse in single mode. */\n collapsible?: boolean;\n\n /** Semantic heading level used for each item. Defaults to 3. */\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;\n\n /** Adds region landmarks to the panels. Defaults to true for <= 6 items. */\n region?: boolean;\n\n /** Class applied to each trigger button. */\n triggerClassName?: string;\n\n /** Class applied to each animated panel. */\n panelClassName?: string;\n\n /** Class applied to the panel content wrapper. */\n contentClassName?: string;\n\n /** Unmount panel content after its closing animation completes. Defaults to false. */\n unMountOnClose?: boolean;\n};\n\nconst normalizeOpenItemIndexes = (\n indexes: number[] | undefined,\n itemCount: number,\n type: AccordionType,\n): number[] => {\n const validIndexes = Array.from(\n new Set(\n (indexes ?? []).filter(\n (index) => Number.isInteger(index) && index >= 0 && index < itemCount,\n ),\n ),\n );\n\n if (type === \"single\") {\n return validIndexes.slice(0, 1);\n }\n\n return validIndexes.sort((a, b) => a - b);\n};\n\nconst normalizeOpenItemIds = (\n value: AccordionValue | undefined,\n type: AccordionType,\n): AccordionItemId[] => {\n const ids =\n value == null ? [] : Array.isArray(value) ? [...value] : [value];\n const uniqueIds = Array.from(new Set(ids));\n\n return type === \"single\" ? uniqueIds.slice(0, 1) : uniqueIds;\n};\n\nconst Accordion = ({\n items,\n initialOpenItemIndexes,\n openItemIndexes,\n onChange,\n value,\n defaultValue,\n onValueChange,\n type = \"multiple\",\n collapsible = true,\n headingLevel = 3,\n region,\n className,\n triggerClassName,\n panelClassName,\n contentClassName,\n unMountOnClose = false,\n ...rootProps\n}: AccordionProps) => {\n const generatedId = useId();\n const isValueMode = value !== undefined || defaultValue !== undefined;\n const isValueControlled = value !== undefined;\n const triggerRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const contentRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n if (isValueMode) {\n const itemIds = new Set<string>();\n\n for (const item of items) {\n if (item.id === undefined) {\n throw new Error(\n \"Accordion value and defaultValue require an id on every item.\",\n );\n }\n\n const key = `${typeof item.id}:${item.id}`;\n\n if (itemIds.has(key)) {\n throw new Error(\"Accordion item IDs must be unique.\");\n }\n\n itemIds.add(key);\n }\n }\n\n const [uncontrolledOpenItemIndexes, setUncontrolledOpenItemIndexes] =\n useState<number[]>(() =>\n normalizeOpenItemIndexes(initialOpenItemIndexes, items.length, type),\n );\n\n const [uncontrolledOpenItemIds, setUncontrolledOpenItemIds] = useState<\n AccordionItemId[]\n >(() => normalizeOpenItemIds(defaultValue, type));\n\n const requestedOpenItemIds = normalizeOpenItemIds(\n isValueControlled ? value : uncontrolledOpenItemIds,\n type,\n );\n const currentOpenItemIndexes = isValueMode\n ? items.flatMap((item, index) =>\n requestedOpenItemIds.includes(item.id as AccordionItemId) ? [index] : [],\n )\n : normalizeOpenItemIndexes(\n openItemIndexes ?? uncontrolledOpenItemIndexes,\n items.length,\n type,\n );\n\n const HeadingTag = `h${headingLevel}` as\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\";\n\n // Avoid excessive landmark regions in long accordions.\n const useRegions = region ?? items.length <= 6;\n\n const handleToggle = (index: number, disabled = false) => {\n if (disabled) {\n return;\n }\n\n const isOpen = currentOpenItemIndexes.includes(index);\n\n if (type === \"single\" && isOpen && !collapsible) {\n return;\n }\n\n const nextOpenItemIndexes = normalizeOpenItemIndexes(\n type === \"single\"\n ? isOpen\n ? []\n : [index]\n : isOpen\n ? currentOpenItemIndexes.filter((openIndex) => openIndex !== index)\n : [...currentOpenItemIndexes, index],\n items.length,\n type,\n );\n\n if (isValueMode) {\n const nextIds = nextOpenItemIndexes.map(\n (openIndex) => items[openIndex]!.id as AccordionItemId,\n );\n\n if (!isValueControlled) {\n setUncontrolledOpenItemIds(nextIds);\n }\n\n onValueChange?.(\n type === \"single\" ? (nextIds[0] ?? null) : nextIds,\n );\n } else if (openItemIndexes === undefined) {\n setUncontrolledOpenItemIndexes(nextOpenItemIndexes);\n }\n\n onChange?.(nextOpenItemIndexes);\n };\n\n return (\n <div className={cn(\"puzzle-accordion\", className)} {...rootProps}>\n {items.map((item, index) => {\n const isOpen = currentOpenItemIndexes.includes(index);\n const cannotCollapse = type === \"single\" && isOpen && !collapsible;\n\n const triggerId = `${generatedId}-trigger-${index}`;\n const panelId = `${generatedId}-panel-${index}`;\n\n return (\n <Fragment\n key={\n item.id === undefined\n ? index\n : `${typeof item.id}:${item.id}`\n }\n >\n <HeadingTag className=\"puzzle-accordion__heading\">\n <button\n ref={(node) => {\n triggerRefs.current[index] = node;\n }}\n id={triggerId}\n type=\"button\"\n className={cn(\"puzzle-accordion__trigger\", triggerClassName)}\n aria-expanded={isOpen}\n aria-controls={panelId}\n aria-disabled={cannotCollapse || undefined}\n data-state={isOpen ? \"open\" : \"closed\"}\n disabled={item.disabled}\n onClick={() => handleToggle(index, item.disabled)}\n >\n {item.title}\n </button>\n </HeadingTag>\n\n <Transition\n visible={isOpen}\n template=\"accordion\"\n duration={300}\n unmountOnExit={unMountOnClose}\n className={panelClassName}\n id={panelId}\n role={useRegions ? \"region\" : undefined}\n aria-labelledby={useRegions ? triggerId : undefined}\n aria-hidden={!isOpen}\n inert={!isOpen}\n data-state={isOpen ? \"open\" : \"closed\"}\n >\n <div\n ref={(node) => {\n contentRefs.current[index] = node;\n }}\n className=\"puzzle-accordion__panel\"\n >\n <div className=\"puzzle-accordion__panel-inner\">\n <div\n className={cn(\n \"puzzle-accordion__content\",\n contentClassName,\n )}\n >\n {item.content}\n </div>\n </div>\n </div>\n </Transition>\n </Fragment>\n );\n })}\n </div>\n );\n};\n\nexport {\n Accordion,\n type AccordionProps,\n type AccordionItemData,\n type AccordionType,\n type AccordionItemId,\n type AccordionValue,\n};\n"],"mappings":"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"}
|