@flanksource/clicky-ui 0.3.32 → 0.3.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/comments/CommentCard.cjs +9 -8
  2. package/dist/comments/CommentCard.cjs.map +1 -1
  3. package/dist/comments/CommentCard.d.ts.map +1 -1
  4. package/dist/comments/CommentCard.js +2 -1
  5. package/dist/comments/CommentCard.js.map +1 -1
  6. package/dist/comments/CommentCardParts.cjs +2 -1
  7. package/dist/comments/CommentCardParts.cjs.map +1 -1
  8. package/dist/comments/CommentCardParts.d.ts.map +1 -1
  9. package/dist/comments/CommentCardParts.js +2 -1
  10. package/dist/comments/CommentCardParts.js.map +1 -1
  11. package/dist/comments/CommentSidePanel.cjs +3 -2
  12. package/dist/comments/CommentSidePanel.cjs.map +1 -1
  13. package/dist/comments/CommentSidePanel.d.ts.map +1 -1
  14. package/dist/comments/CommentSidePanel.js +2 -1
  15. package/dist/comments/CommentSidePanel.js.map +1 -1
  16. package/dist/comments/comment-utils.cjs +0 -27
  17. package/dist/comments/comment-utils.cjs.map +1 -1
  18. package/dist/comments/comment-utils.d.ts +1 -7
  19. package/dist/comments/comment-utils.d.ts.map +1 -1
  20. package/dist/comments/comment-utils.js +0 -27
  21. package/dist/comments/comment-utils.js.map +1 -1
  22. package/dist/comments.cjs +4 -3
  23. package/dist/comments.cjs.map +1 -1
  24. package/dist/comments.d.ts +1 -0
  25. package/dist/comments.d.ts.map +1 -1
  26. package/dist/comments.js +2 -1
  27. package/dist/comments.js.map +1 -1
  28. package/dist/components/EndpointSelector.cjs +6 -6
  29. package/dist/components/EndpointSelector.cjs.map +1 -1
  30. package/dist/components/EndpointSelector.d.ts.map +1 -1
  31. package/dist/components/EndpointSelector.js +6 -6
  32. package/dist/components/EndpointSelector.js.map +1 -1
  33. package/dist/components/ErrorWrapper.cjs +3 -2
  34. package/dist/components/ErrorWrapper.cjs.map +1 -1
  35. package/dist/components/ErrorWrapper.js +3 -2
  36. package/dist/components/ErrorWrapper.js.map +1 -1
  37. package/dist/components/RangeSlider.cjs +122 -45
  38. package/dist/components/RangeSlider.cjs.map +1 -1
  39. package/dist/components/RangeSlider.d.ts +3 -1
  40. package/dist/components/RangeSlider.d.ts.map +1 -1
  41. package/dist/components/RangeSlider.js +122 -45
  42. package/dist/components/RangeSlider.js.map +1 -1
  43. package/dist/components/SecretKeySelector.cjs +4 -4
  44. package/dist/components/SecretKeySelector.cjs.map +1 -1
  45. package/dist/components/SecretKeySelector.js +4 -4
  46. package/dist/components/SecretKeySelector.js.map +1 -1
  47. package/dist/data/badge-variants.d.ts +2 -2
  48. package/dist/data/version-info.cjs +3 -3
  49. package/dist/data/version-info.js +3 -3
  50. package/dist/index.cjs +4 -3
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.js +2 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/lib/comment-stage.cjs +31 -0
  55. package/dist/lib/comment-stage.cjs.map +1 -0
  56. package/dist/lib/comment-stage.d.ts +8 -0
  57. package/dist/lib/comment-stage.d.ts.map +1 -0
  58. package/dist/lib/comment-stage.js +31 -0
  59. package/dist/lib/comment-stage.js.map +1 -0
  60. package/dist/styles.css +1 -1
  61. package/dist/utils.cjs +4 -0
  62. package/dist/utils.cjs.map +1 -1
  63. package/dist/utils.d.ts +1 -0
  64. package/dist/utils.d.ts.map +1 -1
  65. package/dist/utils.js +4 -0
  66. package/dist/utils.js.map +1 -1
  67. package/package.json +1 -1
@@ -11,65 +11,128 @@ function RangeSlider({
11
11
  step = 1,
12
12
  ariaLabelMin = "Minimum value",
13
13
  ariaLabelMax = "Maximum value",
14
+ editable = false,
14
15
  className,
15
16
  trackClassName,
16
17
  rangeClassName,
17
18
  thumbClassName: thumbOverrideClassName
18
19
  }) {
19
20
  const [lower, upper] = normalizeRangeValue(value, min, max);
20
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("relative h-6", className), children: [
21
- /* @__PURE__ */ jsxRuntime.jsx(
22
- "div",
23
- {
24
- className: utils.cn(
25
- "absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border",
26
- trackClassName
27
- )
28
- }
29
- ),
30
- /* @__PURE__ */ jsxRuntime.jsx(
31
- "div",
32
- {
33
- className: utils.cn(
34
- "absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70",
35
- rangeClassName
36
- ),
37
- style: {
38
- left: `${valueToPercent(lower, min, max)}%`,
39
- right: `${100 - valueToPercent(upper, min, max)}%`
21
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn(editable && "space-y-2", className), children: [
22
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-6", children: [
23
+ /* @__PURE__ */ jsxRuntime.jsx(
24
+ "div",
25
+ {
26
+ className: utils.cn(
27
+ "absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border",
28
+ trackClassName
29
+ )
40
30
  }
41
- }
42
- ),
43
- /* @__PURE__ */ jsxRuntime.jsx(
44
- "input",
45
- {
46
- type: "range",
47
- "aria-label": ariaLabelMin,
48
- min,
49
- max,
50
- step,
51
- value: lower,
52
- className: utils.cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
53
- style: { zIndex: lower >= max ? 30 : 20 },
54
- onChange: (event) => {
55
- const nextLower = clampNumber(Number(event.target.value), min, max);
56
- onChange([Math.min(nextLower, upper), upper]);
31
+ ),
32
+ /* @__PURE__ */ jsxRuntime.jsx(
33
+ "div",
34
+ {
35
+ className: utils.cn(
36
+ "absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70",
37
+ rangeClassName
38
+ ),
39
+ style: {
40
+ left: `${valueToPercent(lower, min, max)}%`,
41
+ right: `${100 - valueToPercent(upper, min, max)}%`
42
+ }
57
43
  }
58
- }
59
- ),
44
+ ),
45
+ /* @__PURE__ */ jsxRuntime.jsx(
46
+ "input",
47
+ {
48
+ type: "range",
49
+ "aria-label": ariaLabelMin,
50
+ min,
51
+ max,
52
+ step,
53
+ value: lower,
54
+ className: utils.cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
55
+ style: { zIndex: lower >= max ? 30 : 20 },
56
+ onChange: (event) => {
57
+ const nextLower = clampNumber(Number(event.target.value), min, max);
58
+ onChange([Math.min(nextLower, upper), upper]);
59
+ }
60
+ }
61
+ ),
62
+ /* @__PURE__ */ jsxRuntime.jsx(
63
+ "input",
64
+ {
65
+ type: "range",
66
+ "aria-label": ariaLabelMax,
67
+ min,
68
+ max,
69
+ step,
70
+ value: upper,
71
+ className: utils.cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
72
+ onChange: (event) => {
73
+ const nextUpper = clampNumber(Number(event.target.value), min, max);
74
+ onChange([lower, Math.max(nextUpper, lower)]);
75
+ }
76
+ }
77
+ )
78
+ ] }),
79
+ editable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
80
+ /* @__PURE__ */ jsxRuntime.jsx(
81
+ EditableBound,
82
+ {
83
+ label: "Min",
84
+ ariaLabel: `Edit ${lowercaseFirst(ariaLabelMin)}`,
85
+ min,
86
+ max: upper,
87
+ step,
88
+ stepBase: min,
89
+ value: lower,
90
+ onChange: (next) => onChange([next, upper])
91
+ }
92
+ ),
93
+ /* @__PURE__ */ jsxRuntime.jsx(
94
+ EditableBound,
95
+ {
96
+ label: "Max",
97
+ ariaLabel: `Edit ${lowercaseFirst(ariaLabelMax)}`,
98
+ min: lower,
99
+ max,
100
+ step,
101
+ stepBase: min,
102
+ value: upper,
103
+ onChange: (next) => onChange([lower, next])
104
+ }
105
+ )
106
+ ] }) : null
107
+ ] });
108
+ }
109
+ function EditableBound({
110
+ label,
111
+ ariaLabel,
112
+ min,
113
+ max,
114
+ step,
115
+ stepBase,
116
+ value,
117
+ onChange
118
+ }) {
119
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "grid grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 text-[11px] text-muted-foreground", children: [
120
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
60
121
  /* @__PURE__ */ jsxRuntime.jsx(
61
122
  "input",
62
123
  {
63
- type: "range",
64
- "aria-label": ariaLabelMax,
65
- min,
124
+ "aria-label": ariaLabel,
125
+ className: "h-7 min-w-0 rounded-md border border-input bg-background px-2 text-right font-mono text-xs tabular-nums text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring",
66
126
  max,
127
+ min,
67
128
  step,
68
- value: upper,
69
- className: utils.cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
129
+ type: "number",
130
+ value,
70
131
  onChange: (event) => {
71
- const nextUpper = clampNumber(Number(event.target.value), min, max);
72
- onChange([lower, Math.max(nextUpper, lower)]);
132
+ if (event.currentTarget.value === "") return;
133
+ const next = Number(event.currentTarget.value);
134
+ if (!Number.isFinite(next)) throw new Error(`${ariaLabel} must be a finite number`);
135
+ onChange(snapToStep(next, { base: stepBase, step, min, max }));
73
136
  }
74
137
  }
75
138
  )
@@ -84,9 +147,23 @@ function normalizeRangeValue(value, min, max) {
84
147
  function clampNumber(value, min, max) {
85
148
  return Math.min(max, Math.max(min, value));
86
149
  }
150
+ function snapToStep(value, { base, step, min, max }) {
151
+ if (!(step > 0)) return clampNumber(value, min, max);
152
+ const aligned = base + Math.round((value - base) / step) * step;
153
+ if (aligned < min) {
154
+ return clampNumber(base + Math.ceil((min - base) / step) * step, min, max);
155
+ }
156
+ if (aligned > max) {
157
+ return clampNumber(base + Math.floor((max - base) / step) * step, min, max);
158
+ }
159
+ return aligned;
160
+ }
87
161
  function valueToPercent(value, min, max) {
88
162
  if (max <= min) return 0;
89
163
  return (value - min) / (max - min) * 100;
90
164
  }
165
+ function lowercaseFirst(value) {
166
+ return value.charAt(0).toLowerCase() + value.slice(1);
167
+ }
91
168
  exports.RangeSlider = RangeSlider;
92
169
  //# sourceMappingURL=RangeSlider.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"RangeSlider.cjs","sources":["../../src/components/RangeSlider.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\n\nexport type RangeSliderValue = [number, number];\n\nexport type RangeSliderProps = {\n min: number;\n max: number;\n value: RangeSliderValue;\n onChange: (value: RangeSliderValue) => void;\n step?: number;\n ariaLabelMin?: string;\n ariaLabelMax?: string;\n className?: string;\n trackClassName?: string;\n rangeClassName?: string;\n thumbClassName?: string;\n};\n\nconst thumbClassName =\n \"[&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:mt-[-5px] [&::-webkit-slider-thumb]:size-3.5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-background/80 [&::-webkit-slider-thumb]:bg-muted-foreground [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-thumb]:pointer-events-auto [&::-moz-range-thumb]:size-3.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border [&::-moz-range-thumb]:border-background/80 [&::-moz-range-thumb]:bg-muted-foreground [&::-moz-range-thumb]:shadow-sm\";\n\nexport function RangeSlider({\n min,\n max,\n value,\n onChange,\n step = 1,\n ariaLabelMin = \"Minimum value\",\n ariaLabelMax = \"Maximum value\",\n className,\n trackClassName,\n rangeClassName,\n thumbClassName: thumbOverrideClassName,\n}: RangeSliderProps) {\n const [lower, upper] = normalizeRangeValue(value, min, max);\n\n return (\n <div className={cn(\"relative h-6\", className)}>\n <div\n className={cn(\n \"absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border\",\n trackClassName,\n )}\n />\n <div\n className={cn(\n \"absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70\",\n rangeClassName,\n )}\n style={{\n left: `${valueToPercent(lower, min, max)}%`,\n right: `${100 - valueToPercent(upper, min, max)}%`,\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMin}\n min={min}\n max={max}\n step={step}\n value={lower}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n style={{ zIndex: lower >= max ? 30 : 20 }}\n onChange={(event) => {\n const nextLower = clampNumber(Number(event.target.value), min, max);\n onChange([Math.min(nextLower, upper), upper]);\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMax}\n min={min}\n max={max}\n step={step}\n value={upper}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n onChange={(event) => {\n const nextUpper = clampNumber(Number(event.target.value), min, max);\n onChange([lower, Math.max(nextUpper, lower)]);\n }}\n />\n </div>\n );\n}\n\nconst baseSliderClassName =\n \"pointer-events-none absolute inset-0 h-6 w-full appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-transparent [&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-transparent\";\n\nfunction normalizeRangeValue(value: RangeSliderValue, min: number, max: number): RangeSliderValue {\n const lower = clampNumber(Math.min(value[0], value[1]), min, max);\n const upper = clampNumber(Math.max(value[0], value[1]), min, max);\n return [lower, upper];\n}\n\nfunction clampNumber(value: number, min: number, max: number) {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction valueToPercent(value: number, min: number, max: number) {\n if (max <= min) return 0;\n return ((value - min) / (max - min)) * 100;\n}\n"],"names":["cn","jsx"],"mappings":";;;;AAkBA,MAAM,iBACJ;AAEK,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,eAAe;AAAA,EACf,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAClB,GAAqB;AACnB,QAAM,CAAC,OAAO,KAAK,IAAI,oBAAoB,OAAO,KAAK,GAAG;AAE1D,yCACG,OAAA,EAAI,WAAWA,MAAAA,GAAG,gBAAgB,SAAS,GAC1C,UAAA;AAAA,IAAAC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWD,MAAAA;AAAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,IAEFC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWD,MAAAA;AAAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,UACL,MAAM,GAAG,eAAe,OAAO,KAAK,GAAG,CAAC;AAAA,UACxC,OAAO,GAAG,MAAM,eAAe,OAAO,KAAK,GAAG,CAAC;AAAA,QAAA;AAAA,MACjD;AAAA,IAAA;AAAA,IAEFC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,WAAWD,MAAAA,GAAG,qBAAqB,gBAAgB,sBAAsB;AAAA,QACzE,OAAO,EAAE,QAAQ,SAAS,MAAM,KAAK,GAAA;AAAA,QACrC,UAAU,CAAC,UAAU;AACnB,gBAAM,YAAY,YAAY,OAAO,MAAM,OAAO,KAAK,GAAG,KAAK,GAAG;AAClE,mBAAS,CAAC,KAAK,IAAI,WAAW,KAAK,GAAG,KAAK,CAAC;AAAA,QAC9C;AAAA,MAAA;AAAA,IAAA;AAAA,IAEFC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,WAAWD,MAAAA,GAAG,qBAAqB,gBAAgB,sBAAsB;AAAA,QACzE,UAAU,CAAC,UAAU;AACnB,gBAAM,YAAY,YAAY,OAAO,MAAM,OAAO,KAAK,GAAG,KAAK,GAAG;AAClE,mBAAS,CAAC,OAAO,KAAK,IAAI,WAAW,KAAK,CAAC,CAAC;AAAA,QAC9C;AAAA,MAAA;AAAA,IAAA;AAAA,EACF,GACF;AAEJ;AAEA,MAAM,sBACJ;AAEF,SAAS,oBAAoB,OAAyB,KAAa,KAA+B;AAChG,QAAM,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG;AAChE,QAAM,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG;AAChE,SAAO,CAAC,OAAO,KAAK;AACtB;AAEA,SAAS,YAAY,OAAe,KAAa,KAAa;AAC5D,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C;AAEA,SAAS,eAAe,OAAe,KAAa,KAAa;AAC/D,MAAI,OAAO,IAAK,QAAO;AACvB,UAAS,QAAQ,QAAQ,MAAM,OAAQ;AACzC;;"}
1
+ {"version":3,"file":"RangeSlider.cjs","sources":["../../src/components/RangeSlider.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\n\nexport type RangeSliderValue = [number, number];\n\nexport type RangeSliderProps = {\n min: number;\n max: number;\n value: RangeSliderValue;\n onChange: (value: RangeSliderValue) => void;\n step?: number;\n ariaLabelMin?: string;\n ariaLabelMax?: string;\n /** Shows number fields below the track for exact keyboard entry. */\n editable?: boolean;\n className?: string;\n trackClassName?: string;\n rangeClassName?: string;\n thumbClassName?: string;\n};\n\nconst thumbClassName =\n \"[&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:mt-[-5px] [&::-webkit-slider-thumb]:size-3.5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-background/80 [&::-webkit-slider-thumb]:bg-muted-foreground [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-thumb]:pointer-events-auto [&::-moz-range-thumb]:size-3.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border [&::-moz-range-thumb]:border-background/80 [&::-moz-range-thumb]:bg-muted-foreground [&::-moz-range-thumb]:shadow-sm\";\n\nexport function RangeSlider({\n min,\n max,\n value,\n onChange,\n step = 1,\n ariaLabelMin = \"Minimum value\",\n ariaLabelMax = \"Maximum value\",\n editable = false,\n className,\n trackClassName,\n rangeClassName,\n thumbClassName: thumbOverrideClassName,\n}: RangeSliderProps) {\n const [lower, upper] = normalizeRangeValue(value, min, max);\n\n return (\n <div className={cn(editable && \"space-y-2\", className)}>\n <div className=\"relative h-6\">\n <div\n className={cn(\n \"absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border\",\n trackClassName,\n )}\n />\n <div\n className={cn(\n \"absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70\",\n rangeClassName,\n )}\n style={{\n left: `${valueToPercent(lower, min, max)}%`,\n right: `${100 - valueToPercent(upper, min, max)}%`,\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMin}\n min={min}\n max={max}\n step={step}\n value={lower}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n style={{ zIndex: lower >= max ? 30 : 20 }}\n onChange={(event) => {\n const nextLower = clampNumber(Number(event.target.value), min, max);\n onChange([Math.min(nextLower, upper), upper]);\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMax}\n min={min}\n max={max}\n step={step}\n value={upper}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n onChange={(event) => {\n const nextUpper = clampNumber(Number(event.target.value), min, max);\n onChange([lower, Math.max(nextUpper, lower)]);\n }}\n />\n </div>\n {editable ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <EditableBound\n label=\"Min\"\n ariaLabel={`Edit ${lowercaseFirst(ariaLabelMin)}`}\n min={min}\n max={upper}\n step={step}\n stepBase={min}\n value={lower}\n onChange={(next) => onChange([next, upper])}\n />\n <EditableBound\n label=\"Max\"\n ariaLabel={`Edit ${lowercaseFirst(ariaLabelMax)}`}\n min={lower}\n max={max}\n step={step}\n stepBase={min}\n value={upper}\n onChange={(next) => onChange([lower, next])}\n />\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction EditableBound({\n label,\n ariaLabel,\n min,\n max,\n step,\n stepBase,\n value,\n onChange,\n}: {\n label: string;\n ariaLabel: string;\n min: number;\n max: number;\n step: number;\n /** Origin the `step` grid is measured from — the slider's own `min`. */\n stepBase: number;\n value: number;\n onChange: (value: number) => void;\n}) {\n return (\n <label className=\"grid grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 text-[11px] text-muted-foreground\">\n <span>{label}</span>\n <input\n aria-label={ariaLabel}\n className=\"h-7 min-w-0 rounded-md border border-input bg-background px-2 text-right font-mono text-xs tabular-nums text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n max={max}\n min={min}\n step={step}\n type=\"number\"\n value={value}\n onChange={(event) => {\n if (event.currentTarget.value === \"\") return;\n const next = Number(event.currentTarget.value);\n if (!Number.isFinite(next)) throw new Error(`${ariaLabel} must be a finite number`);\n onChange(snapToStep(next, { base: stepBase, step, min, max }));\n }}\n />\n </label>\n );\n}\n\nconst baseSliderClassName =\n \"pointer-events-none absolute inset-0 h-6 w-full appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-transparent [&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-transparent\";\n\nfunction normalizeRangeValue(value: RangeSliderValue, min: number, max: number): RangeSliderValue {\n const lower = clampNumber(Math.min(value[0], value[1]), min, max);\n const upper = clampNumber(Math.max(value[0], value[1]), min, max);\n return [lower, upper];\n}\n\nfunction clampNumber(value: number, min: number, max: number) {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * Nearest `step`-aligned value measured from `base`, kept inside `[min, max]`.\n * Mirrors what the range inputs enforce, so typed entry cannot produce a value\n * the thumbs could never reach.\n */\nfunction snapToStep(\n value: number,\n { base, step, min, max }: { base: number; step: number; min: number; max: number },\n): number {\n if (!(step > 0)) return clampNumber(value, min, max);\n const aligned = base + Math.round((value - base) / step) * step;\n if (aligned < min) {\n return clampNumber(base + Math.ceil((min - base) / step) * step, min, max);\n }\n if (aligned > max) {\n return clampNumber(base + Math.floor((max - base) / step) * step, min, max);\n }\n return aligned;\n}\n\nfunction valueToPercent(value: number, min: number, max: number) {\n if (max <= min) return 0;\n return ((value - min) / (max - min)) * 100;\n}\n\nfunction lowercaseFirst(value: string): string {\n return value.charAt(0).toLowerCase() + value.slice(1);\n}\n"],"names":["cn","jsxs","jsx"],"mappings":"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"}
@@ -7,10 +7,12 @@ export type RangeSliderProps = {
7
7
  step?: number;
8
8
  ariaLabelMin?: string;
9
9
  ariaLabelMax?: string;
10
+ /** Shows number fields below the track for exact keyboard entry. */
11
+ editable?: boolean;
10
12
  className?: string;
11
13
  trackClassName?: string;
12
14
  rangeClassName?: string;
13
15
  thumbClassName?: string;
14
16
  };
15
- export declare function RangeSlider({ min, max, value, onChange, step, ariaLabelMin, ariaLabelMax, className, trackClassName, rangeClassName, thumbClassName: thumbOverrideClassName, }: RangeSliderProps): import("react").JSX.Element;
17
+ export declare function RangeSlider({ min, max, value, onChange, step, ariaLabelMin, ariaLabelMax, editable, className, trackClassName, rangeClassName, thumbClassName: thumbOverrideClassName, }: RangeSliderProps): import("react").JSX.Element;
16
18
  //# sourceMappingURL=RangeSlider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RangeSlider.d.ts","sourceRoot":"","sources":["../../src/components/RangeSlider.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEhD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAKF,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,GAAG,EACH,KAAK,EACL,QAAQ,EACR,IAAQ,EACR,YAA8B,EAC9B,YAA8B,EAC9B,SAAS,EACT,cAAc,EACd,cAAc,EACd,cAAc,EAAE,sBAAsB,GACvC,EAAE,gBAAgB,+BAkDlB"}
1
+ {"version":3,"file":"RangeSlider.d.ts","sourceRoot":"","sources":["../../src/components/RangeSlider.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEhD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAKF,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,GAAG,EACH,KAAK,EACL,QAAQ,EACR,IAAQ,EACR,YAA8B,EAC9B,YAA8B,EAC9B,QAAgB,EAChB,SAAS,EACT,cAAc,EACd,cAAc,EACd,cAAc,EAAE,sBAAsB,GACvC,EAAE,gBAAgB,+BA4ElB"}
@@ -9,65 +9,128 @@ function RangeSlider({
9
9
  step = 1,
10
10
  ariaLabelMin = "Minimum value",
11
11
  ariaLabelMax = "Maximum value",
12
+ editable = false,
12
13
  className,
13
14
  trackClassName,
14
15
  rangeClassName,
15
16
  thumbClassName: thumbOverrideClassName
16
17
  }) {
17
18
  const [lower, upper] = normalizeRangeValue(value, min, max);
18
- return /* @__PURE__ */ jsxs("div", { className: cn("relative h-6", className), children: [
19
- /* @__PURE__ */ jsx(
20
- "div",
21
- {
22
- className: cn(
23
- "absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border",
24
- trackClassName
25
- )
26
- }
27
- ),
28
- /* @__PURE__ */ jsx(
29
- "div",
30
- {
31
- className: cn(
32
- "absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70",
33
- rangeClassName
34
- ),
35
- style: {
36
- left: `${valueToPercent(lower, min, max)}%`,
37
- right: `${100 - valueToPercent(upper, min, max)}%`
19
+ return /* @__PURE__ */ jsxs("div", { className: cn(editable && "space-y-2", className), children: [
20
+ /* @__PURE__ */ jsxs("div", { className: "relative h-6", children: [
21
+ /* @__PURE__ */ jsx(
22
+ "div",
23
+ {
24
+ className: cn(
25
+ "absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border",
26
+ trackClassName
27
+ )
38
28
  }
39
- }
40
- ),
41
- /* @__PURE__ */ jsx(
42
- "input",
43
- {
44
- type: "range",
45
- "aria-label": ariaLabelMin,
46
- min,
47
- max,
48
- step,
49
- value: lower,
50
- className: cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
51
- style: { zIndex: lower >= max ? 30 : 20 },
52
- onChange: (event) => {
53
- const nextLower = clampNumber(Number(event.target.value), min, max);
54
- onChange([Math.min(nextLower, upper), upper]);
29
+ ),
30
+ /* @__PURE__ */ jsx(
31
+ "div",
32
+ {
33
+ className: cn(
34
+ "absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70",
35
+ rangeClassName
36
+ ),
37
+ style: {
38
+ left: `${valueToPercent(lower, min, max)}%`,
39
+ right: `${100 - valueToPercent(upper, min, max)}%`
40
+ }
55
41
  }
56
- }
57
- ),
42
+ ),
43
+ /* @__PURE__ */ jsx(
44
+ "input",
45
+ {
46
+ type: "range",
47
+ "aria-label": ariaLabelMin,
48
+ min,
49
+ max,
50
+ step,
51
+ value: lower,
52
+ className: cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
53
+ style: { zIndex: lower >= max ? 30 : 20 },
54
+ onChange: (event) => {
55
+ const nextLower = clampNumber(Number(event.target.value), min, max);
56
+ onChange([Math.min(nextLower, upper), upper]);
57
+ }
58
+ }
59
+ ),
60
+ /* @__PURE__ */ jsx(
61
+ "input",
62
+ {
63
+ type: "range",
64
+ "aria-label": ariaLabelMax,
65
+ min,
66
+ max,
67
+ step,
68
+ value: upper,
69
+ className: cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
70
+ onChange: (event) => {
71
+ const nextUpper = clampNumber(Number(event.target.value), min, max);
72
+ onChange([lower, Math.max(nextUpper, lower)]);
73
+ }
74
+ }
75
+ )
76
+ ] }),
77
+ editable ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
78
+ /* @__PURE__ */ jsx(
79
+ EditableBound,
80
+ {
81
+ label: "Min",
82
+ ariaLabel: `Edit ${lowercaseFirst(ariaLabelMin)}`,
83
+ min,
84
+ max: upper,
85
+ step,
86
+ stepBase: min,
87
+ value: lower,
88
+ onChange: (next) => onChange([next, upper])
89
+ }
90
+ ),
91
+ /* @__PURE__ */ jsx(
92
+ EditableBound,
93
+ {
94
+ label: "Max",
95
+ ariaLabel: `Edit ${lowercaseFirst(ariaLabelMax)}`,
96
+ min: lower,
97
+ max,
98
+ step,
99
+ stepBase: min,
100
+ value: upper,
101
+ onChange: (next) => onChange([lower, next])
102
+ }
103
+ )
104
+ ] }) : null
105
+ ] });
106
+ }
107
+ function EditableBound({
108
+ label,
109
+ ariaLabel,
110
+ min,
111
+ max,
112
+ step,
113
+ stepBase,
114
+ value,
115
+ onChange
116
+ }) {
117
+ return /* @__PURE__ */ jsxs("label", { className: "grid grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 text-[11px] text-muted-foreground", children: [
118
+ /* @__PURE__ */ jsx("span", { children: label }),
58
119
  /* @__PURE__ */ jsx(
59
120
  "input",
60
121
  {
61
- type: "range",
62
- "aria-label": ariaLabelMax,
63
- min,
122
+ "aria-label": ariaLabel,
123
+ className: "h-7 min-w-0 rounded-md border border-input bg-background px-2 text-right font-mono text-xs tabular-nums text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring",
64
124
  max,
125
+ min,
65
126
  step,
66
- value: upper,
67
- className: cn(baseSliderClassName, thumbClassName, thumbOverrideClassName),
127
+ type: "number",
128
+ value,
68
129
  onChange: (event) => {
69
- const nextUpper = clampNumber(Number(event.target.value), min, max);
70
- onChange([lower, Math.max(nextUpper, lower)]);
130
+ if (event.currentTarget.value === "") return;
131
+ const next = Number(event.currentTarget.value);
132
+ if (!Number.isFinite(next)) throw new Error(`${ariaLabel} must be a finite number`);
133
+ onChange(snapToStep(next, { base: stepBase, step, min, max }));
71
134
  }
72
135
  }
73
136
  )
@@ -82,10 +145,24 @@ function normalizeRangeValue(value, min, max) {
82
145
  function clampNumber(value, min, max) {
83
146
  return Math.min(max, Math.max(min, value));
84
147
  }
148
+ function snapToStep(value, { base, step, min, max }) {
149
+ if (!(step > 0)) return clampNumber(value, min, max);
150
+ const aligned = base + Math.round((value - base) / step) * step;
151
+ if (aligned < min) {
152
+ return clampNumber(base + Math.ceil((min - base) / step) * step, min, max);
153
+ }
154
+ if (aligned > max) {
155
+ return clampNumber(base + Math.floor((max - base) / step) * step, min, max);
156
+ }
157
+ return aligned;
158
+ }
85
159
  function valueToPercent(value, min, max) {
86
160
  if (max <= min) return 0;
87
161
  return (value - min) / (max - min) * 100;
88
162
  }
163
+ function lowercaseFirst(value) {
164
+ return value.charAt(0).toLowerCase() + value.slice(1);
165
+ }
89
166
  export {
90
167
  RangeSlider
91
168
  };
@@ -1 +1 @@
1
- {"version":3,"file":"RangeSlider.js","sources":["../../src/components/RangeSlider.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\n\nexport type RangeSliderValue = [number, number];\n\nexport type RangeSliderProps = {\n min: number;\n max: number;\n value: RangeSliderValue;\n onChange: (value: RangeSliderValue) => void;\n step?: number;\n ariaLabelMin?: string;\n ariaLabelMax?: string;\n className?: string;\n trackClassName?: string;\n rangeClassName?: string;\n thumbClassName?: string;\n};\n\nconst thumbClassName =\n \"[&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:mt-[-5px] [&::-webkit-slider-thumb]:size-3.5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-background/80 [&::-webkit-slider-thumb]:bg-muted-foreground [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-thumb]:pointer-events-auto [&::-moz-range-thumb]:size-3.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border [&::-moz-range-thumb]:border-background/80 [&::-moz-range-thumb]:bg-muted-foreground [&::-moz-range-thumb]:shadow-sm\";\n\nexport function RangeSlider({\n min,\n max,\n value,\n onChange,\n step = 1,\n ariaLabelMin = \"Minimum value\",\n ariaLabelMax = \"Maximum value\",\n className,\n trackClassName,\n rangeClassName,\n thumbClassName: thumbOverrideClassName,\n}: RangeSliderProps) {\n const [lower, upper] = normalizeRangeValue(value, min, max);\n\n return (\n <div className={cn(\"relative h-6\", className)}>\n <div\n className={cn(\n \"absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border\",\n trackClassName,\n )}\n />\n <div\n className={cn(\n \"absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70\",\n rangeClassName,\n )}\n style={{\n left: `${valueToPercent(lower, min, max)}%`,\n right: `${100 - valueToPercent(upper, min, max)}%`,\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMin}\n min={min}\n max={max}\n step={step}\n value={lower}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n style={{ zIndex: lower >= max ? 30 : 20 }}\n onChange={(event) => {\n const nextLower = clampNumber(Number(event.target.value), min, max);\n onChange([Math.min(nextLower, upper), upper]);\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMax}\n min={min}\n max={max}\n step={step}\n value={upper}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n onChange={(event) => {\n const nextUpper = clampNumber(Number(event.target.value), min, max);\n onChange([lower, Math.max(nextUpper, lower)]);\n }}\n />\n </div>\n );\n}\n\nconst baseSliderClassName =\n \"pointer-events-none absolute inset-0 h-6 w-full appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-transparent [&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-transparent\";\n\nfunction normalizeRangeValue(value: RangeSliderValue, min: number, max: number): RangeSliderValue {\n const lower = clampNumber(Math.min(value[0], value[1]), min, max);\n const upper = clampNumber(Math.max(value[0], value[1]), min, max);\n return [lower, upper];\n}\n\nfunction clampNumber(value: number, min: number, max: number) {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction valueToPercent(value: number, min: number, max: number) {\n if (max <= min) return 0;\n return ((value - min) / (max - min)) * 100;\n}\n"],"names":[],"mappings":";;AAkBA,MAAM,iBACJ;AAEK,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,eAAe;AAAA,EACf,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAClB,GAAqB;AACnB,QAAM,CAAC,OAAO,KAAK,IAAI,oBAAoB,OAAO,KAAK,GAAG;AAE1D,8BACG,OAAA,EAAI,WAAW,GAAG,gBAAgB,SAAS,GAC1C,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,IAEF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,UACL,MAAM,GAAG,eAAe,OAAO,KAAK,GAAG,CAAC;AAAA,UACxC,OAAO,GAAG,MAAM,eAAe,OAAO,KAAK,GAAG,CAAC;AAAA,QAAA;AAAA,MACjD;AAAA,IAAA;AAAA,IAEF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,WAAW,GAAG,qBAAqB,gBAAgB,sBAAsB;AAAA,QACzE,OAAO,EAAE,QAAQ,SAAS,MAAM,KAAK,GAAA;AAAA,QACrC,UAAU,CAAC,UAAU;AACnB,gBAAM,YAAY,YAAY,OAAO,MAAM,OAAO,KAAK,GAAG,KAAK,GAAG;AAClE,mBAAS,CAAC,KAAK,IAAI,WAAW,KAAK,GAAG,KAAK,CAAC;AAAA,QAC9C;AAAA,MAAA;AAAA,IAAA;AAAA,IAEF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,WAAW,GAAG,qBAAqB,gBAAgB,sBAAsB;AAAA,QACzE,UAAU,CAAC,UAAU;AACnB,gBAAM,YAAY,YAAY,OAAO,MAAM,OAAO,KAAK,GAAG,KAAK,GAAG;AAClE,mBAAS,CAAC,OAAO,KAAK,IAAI,WAAW,KAAK,CAAC,CAAC;AAAA,QAC9C;AAAA,MAAA;AAAA,IAAA;AAAA,EACF,GACF;AAEJ;AAEA,MAAM,sBACJ;AAEF,SAAS,oBAAoB,OAAyB,KAAa,KAA+B;AAChG,QAAM,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG;AAChE,QAAM,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG;AAChE,SAAO,CAAC,OAAO,KAAK;AACtB;AAEA,SAAS,YAAY,OAAe,KAAa,KAAa;AAC5D,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C;AAEA,SAAS,eAAe,OAAe,KAAa,KAAa;AAC/D,MAAI,OAAO,IAAK,QAAO;AACvB,UAAS,QAAQ,QAAQ,MAAM,OAAQ;AACzC;"}
1
+ {"version":3,"file":"RangeSlider.js","sources":["../../src/components/RangeSlider.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\n\nexport type RangeSliderValue = [number, number];\n\nexport type RangeSliderProps = {\n min: number;\n max: number;\n value: RangeSliderValue;\n onChange: (value: RangeSliderValue) => void;\n step?: number;\n ariaLabelMin?: string;\n ariaLabelMax?: string;\n /** Shows number fields below the track for exact keyboard entry. */\n editable?: boolean;\n className?: string;\n trackClassName?: string;\n rangeClassName?: string;\n thumbClassName?: string;\n};\n\nconst thumbClassName =\n \"[&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:mt-[-5px] [&::-webkit-slider-thumb]:size-3.5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-background/80 [&::-webkit-slider-thumb]:bg-muted-foreground [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-thumb]:pointer-events-auto [&::-moz-range-thumb]:size-3.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border [&::-moz-range-thumb]:border-background/80 [&::-moz-range-thumb]:bg-muted-foreground [&::-moz-range-thumb]:shadow-sm\";\n\nexport function RangeSlider({\n min,\n max,\n value,\n onChange,\n step = 1,\n ariaLabelMin = \"Minimum value\",\n ariaLabelMax = \"Maximum value\",\n editable = false,\n className,\n trackClassName,\n rangeClassName,\n thumbClassName: thumbOverrideClassName,\n}: RangeSliderProps) {\n const [lower, upper] = normalizeRangeValue(value, min, max);\n\n return (\n <div className={cn(editable && \"space-y-2\", className)}>\n <div className=\"relative h-6\">\n <div\n className={cn(\n \"absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border\",\n trackClassName,\n )}\n />\n <div\n className={cn(\n \"absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70\",\n rangeClassName,\n )}\n style={{\n left: `${valueToPercent(lower, min, max)}%`,\n right: `${100 - valueToPercent(upper, min, max)}%`,\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMin}\n min={min}\n max={max}\n step={step}\n value={lower}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n style={{ zIndex: lower >= max ? 30 : 20 }}\n onChange={(event) => {\n const nextLower = clampNumber(Number(event.target.value), min, max);\n onChange([Math.min(nextLower, upper), upper]);\n }}\n />\n <input\n type=\"range\"\n aria-label={ariaLabelMax}\n min={min}\n max={max}\n step={step}\n value={upper}\n className={cn(baseSliderClassName, thumbClassName, thumbOverrideClassName)}\n onChange={(event) => {\n const nextUpper = clampNumber(Number(event.target.value), min, max);\n onChange([lower, Math.max(nextUpper, lower)]);\n }}\n />\n </div>\n {editable ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <EditableBound\n label=\"Min\"\n ariaLabel={`Edit ${lowercaseFirst(ariaLabelMin)}`}\n min={min}\n max={upper}\n step={step}\n stepBase={min}\n value={lower}\n onChange={(next) => onChange([next, upper])}\n />\n <EditableBound\n label=\"Max\"\n ariaLabel={`Edit ${lowercaseFirst(ariaLabelMax)}`}\n min={lower}\n max={max}\n step={step}\n stepBase={min}\n value={upper}\n onChange={(next) => onChange([lower, next])}\n />\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction EditableBound({\n label,\n ariaLabel,\n min,\n max,\n step,\n stepBase,\n value,\n onChange,\n}: {\n label: string;\n ariaLabel: string;\n min: number;\n max: number;\n step: number;\n /** Origin the `step` grid is measured from — the slider's own `min`. */\n stepBase: number;\n value: number;\n onChange: (value: number) => void;\n}) {\n return (\n <label className=\"grid grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 text-[11px] text-muted-foreground\">\n <span>{label}</span>\n <input\n aria-label={ariaLabel}\n className=\"h-7 min-w-0 rounded-md border border-input bg-background px-2 text-right font-mono text-xs tabular-nums text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n max={max}\n min={min}\n step={step}\n type=\"number\"\n value={value}\n onChange={(event) => {\n if (event.currentTarget.value === \"\") return;\n const next = Number(event.currentTarget.value);\n if (!Number.isFinite(next)) throw new Error(`${ariaLabel} must be a finite number`);\n onChange(snapToStep(next, { base: stepBase, step, min, max }));\n }}\n />\n </label>\n );\n}\n\nconst baseSliderClassName =\n \"pointer-events-none absolute inset-0 h-6 w-full appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-transparent [&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-transparent\";\n\nfunction normalizeRangeValue(value: RangeSliderValue, min: number, max: number): RangeSliderValue {\n const lower = clampNumber(Math.min(value[0], value[1]), min, max);\n const upper = clampNumber(Math.max(value[0], value[1]), min, max);\n return [lower, upper];\n}\n\nfunction clampNumber(value: number, min: number, max: number) {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * Nearest `step`-aligned value measured from `base`, kept inside `[min, max]`.\n * Mirrors what the range inputs enforce, so typed entry cannot produce a value\n * the thumbs could never reach.\n */\nfunction snapToStep(\n value: number,\n { base, step, min, max }: { base: number; step: number; min: number; max: number },\n): number {\n if (!(step > 0)) return clampNumber(value, min, max);\n const aligned = base + Math.round((value - base) / step) * step;\n if (aligned < min) {\n return clampNumber(base + Math.ceil((min - base) / step) * step, min, max);\n }\n if (aligned > max) {\n return clampNumber(base + Math.floor((max - base) / step) * step, min, max);\n }\n return aligned;\n}\n\nfunction valueToPercent(value: number, min: number, max: number) {\n if (max <= min) return 0;\n return ((value - min) / (max - min)) * 100;\n}\n\nfunction lowercaseFirst(value: string): string {\n return value.charAt(0).toLowerCase() + value.slice(1);\n}\n"],"names":[],"mappings":"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"}
@@ -11,8 +11,8 @@ const UiEdit = require("../icons/components/UiEdit.cjs");
11
11
  const DEFAULT_SOURCES = ["secret", "configmap", "value"];
12
12
  const SHRINKABLE_FIELD = "max-w-full min-w-0 shrink";
13
13
  const SOURCE_FIELD = `${SHRINKABLE_FIELD} basis-40 grow-0`;
14
- const RESOURCE_FIELD = `${SHRINKABLE_FIELD} basis-40 grow-0`;
15
- const KEY_FIELD = `${SHRINKABLE_FIELD} basis-72 grow`;
14
+ const RESOURCE_FIELD = `${SHRINKABLE_FIELD} w-full basis-auto grow-0 @min-[22rem]/secret:basis-40`;
15
+ const KEY_FIELD = `${SHRINKABLE_FIELD} w-full basis-auto grow @min-[22rem]/secret:basis-72`;
16
16
  const VALUE_FIELD = `${SHRINKABLE_FIELD} basis-64 grow`;
17
17
  function SecretKeySelector({
18
18
  value,
@@ -126,7 +126,7 @@ function SecretKeySelector({
126
126
  "div",
127
127
  {
128
128
  "data-slot": "secret-key-selector",
129
- className: utils.cn("@container w-full min-w-0", className),
129
+ className: utils.cn("@container/secret w-full min-w-0", className),
130
130
  children: /* @__PURE__ */ jsxRuntime.jsxs(
131
131
  "div",
132
132
  {
@@ -213,7 +213,7 @@ function SecretKeySelector({
213
213
  "div",
214
214
  {
215
215
  className: utils.cn(
216
- "flex flex-nowrap items-center gap-2",
216
+ "flex flex-col items-center gap-2 @min-[22rem]/secret:flex-row",
217
217
  SHRINKABLE_FIELD,
218
218
  "grow"
219
219
  ),