@bug-on/m3-expressive 1.0.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/CHANGELOG.md +110 -0
- package/README.md +110 -0
- package/dist/assets/fonts/GoogleSansFlex-VariableFont.woff2 +0 -0
- package/dist/assets/fonts/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/fonts/MaterialSymbolsRounded-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/fonts/MaterialSymbolsSharp-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/loading-indicator.svg +19 -0
- package/dist/assets/material-symbols-cdn.css +65 -0
- package/dist/assets/material-symbols-self-hosted.css +94 -0
- package/dist/buttons.d.mts +180 -0
- package/dist/buttons.d.ts +180 -0
- package/dist/buttons.js +4282 -0
- package/dist/buttons.js.map +1 -0
- package/dist/buttons.mjs +4227 -0
- package/dist/buttons.mjs.map +1 -0
- package/dist/core.d.mts +422 -0
- package/dist/core.d.ts +422 -0
- package/dist/core.js +2581 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +2547 -0
- package/dist/core.mjs.map +1 -0
- package/dist/feedback.d.mts +600 -0
- package/dist/feedback.d.ts +600 -0
- package/dist/feedback.js +2357 -0
- package/dist/feedback.js.map +1 -0
- package/dist/feedback.mjs +2321 -0
- package/dist/feedback.mjs.map +1 -0
- package/dist/forms.d.mts +40 -0
- package/dist/forms.d.ts +40 -0
- package/dist/forms.js +4263 -0
- package/dist/forms.js.map +1 -0
- package/dist/forms.mjs +4228 -0
- package/dist/forms.mjs.map +1 -0
- package/dist/icon-button-D-gs0gfj.d.mts +136 -0
- package/dist/icon-button-D-gs0gfj.d.ts +136 -0
- package/dist/index.css +309 -0
- package/dist/index.css.d.ts +2 -0
- package/dist/index.d.mts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +23972 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +23668 -0
- package/dist/index.mjs.map +1 -0
- package/dist/layout.d.mts +610 -0
- package/dist/layout.d.ts +610 -0
- package/dist/layout.js +5091 -0
- package/dist/layout.js.map +1 -0
- package/dist/layout.mjs +5042 -0
- package/dist/layout.mjs.map +1 -0
- package/dist/material-symbols-cdn.css +65 -0
- package/dist/material-symbols-cdn.css.d.ts +2 -0
- package/dist/material-symbols-self-hosted.css +94 -0
- package/dist/material-symbols-self-hosted.css.d.ts +2 -0
- package/dist/md3-DFhj-NZj.d.mts +17 -0
- package/dist/md3-DFhj-NZj.d.ts +17 -0
- package/dist/navigation.d.mts +2766 -0
- package/dist/navigation.d.ts +2766 -0
- package/dist/navigation.js +6684 -0
- package/dist/navigation.js.map +1 -0
- package/dist/navigation.mjs +6573 -0
- package/dist/navigation.mjs.map +1 -0
- package/dist/overlays.d.mts +161 -0
- package/dist/overlays.d.ts +161 -0
- package/dist/overlays.js +3298 -0
- package/dist/overlays.js.map +1 -0
- package/dist/overlays.mjs +3244 -0
- package/dist/overlays.mjs.map +1 -0
- package/dist/pickers.d.mts +1074 -0
- package/dist/pickers.d.ts +1074 -0
- package/dist/pickers.js +4240 -0
- package/dist/pickers.js.map +1 -0
- package/dist/pickers.mjs +4200 -0
- package/dist/pickers.mjs.map +1 -0
- package/dist/plugin.d.mts +1 -0
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +13 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugin.mjs +3 -0
- package/dist/plugin.mjs.map +1 -0
- package/dist/scroll-area-CVS6HyLl.d.mts +33 -0
- package/dist/scroll-area-CVS6HyLl.d.ts +33 -0
- package/dist/shapes.d.mts +1119 -0
- package/dist/shapes.d.ts +1119 -0
- package/dist/shapes.js +2941 -0
- package/dist/shapes.js.map +1 -0
- package/dist/shapes.mjs +2889 -0
- package/dist/shapes.mjs.map +1 -0
- package/dist/side-sheet-modal-BY6VCC8p.d.mts +553 -0
- package/dist/side-sheet-modal-CglP6KYA.d.ts +553 -0
- package/dist/split-button-trailing-uncheckable-C5CLCIKP.d.ts +731 -0
- package/dist/split-button-trailing-uncheckable-MXj_kyNt.d.mts +731 -0
- package/dist/text-field-eAIpz9z1.d.mts +1038 -0
- package/dist/text-field-eAIpz9z1.d.ts +1038 -0
- package/dist/typography-339RV6v7.d.mts +486 -0
- package/dist/typography-339RV6v7.d.ts +486 -0
- package/dist/typography.css +22 -0
- package/dist/typography.css.d.ts +2 -0
- package/package.json +207 -0
package/dist/forms.mjs
ADDED
|
@@ -0,0 +1,4228 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { m, AnimatePresence, useReducedMotion, LazyMotion, domMax } from 'motion/react';
|
|
3
|
+
import * as React4 from 'react';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import { clsx } from 'clsx';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
import { cva } from 'class-variance-authority';
|
|
9
|
+
import * as RadixScrollArea from '@radix-ui/react-scroll-area';
|
|
10
|
+
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __defProps = Object.defineProperties;
|
|
13
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
14
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
17
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
18
|
+
var __spreadValues = (a, b) => {
|
|
19
|
+
for (var prop in b || (b = {}))
|
|
20
|
+
if (__hasOwnProp.call(b, prop))
|
|
21
|
+
__defNormalProp(a, prop, b[prop]);
|
|
22
|
+
if (__getOwnPropSymbols)
|
|
23
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
24
|
+
if (__propIsEnum.call(b, prop))
|
|
25
|
+
__defNormalProp(a, prop, b[prop]);
|
|
26
|
+
}
|
|
27
|
+
return a;
|
|
28
|
+
};
|
|
29
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
30
|
+
var __objRest = (source, exclude) => {
|
|
31
|
+
var target = {};
|
|
32
|
+
for (var prop in source)
|
|
33
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
34
|
+
target[prop] = source[prop];
|
|
35
|
+
if (source != null && __getOwnPropSymbols)
|
|
36
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
37
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
38
|
+
target[prop] = source[prop];
|
|
39
|
+
}
|
|
40
|
+
return target;
|
|
41
|
+
};
|
|
42
|
+
function cn(...inputs) {
|
|
43
|
+
return twMerge(clsx(inputs));
|
|
44
|
+
}
|
|
45
|
+
var RippleItem = React4.memo(function RippleItem2({
|
|
46
|
+
ripple,
|
|
47
|
+
onDone
|
|
48
|
+
}) {
|
|
49
|
+
return /* @__PURE__ */ jsx(
|
|
50
|
+
m.span,
|
|
51
|
+
{
|
|
52
|
+
"aria-hidden": "true",
|
|
53
|
+
style: {
|
|
54
|
+
position: "absolute",
|
|
55
|
+
left: ripple.x - ripple.size / 2,
|
|
56
|
+
top: ripple.y - ripple.size / 2,
|
|
57
|
+
width: ripple.size,
|
|
58
|
+
height: ripple.size,
|
|
59
|
+
borderRadius: "50%",
|
|
60
|
+
backgroundColor: "currentColor",
|
|
61
|
+
pointerEvents: "none",
|
|
62
|
+
transformOrigin: "center"
|
|
63
|
+
},
|
|
64
|
+
initial: { scale: 0, opacity: 0.12 },
|
|
65
|
+
animate: { scale: 1, opacity: 0 },
|
|
66
|
+
exit: { opacity: 0 },
|
|
67
|
+
transition: {
|
|
68
|
+
scale: { duration: 0.5, ease: [0.2, 0, 0, 1] },
|
|
69
|
+
opacity: { duration: 0.4, ease: "easeOut", delay: 0.1 }
|
|
70
|
+
},
|
|
71
|
+
onAnimationComplete: () => onDone(ripple.id)
|
|
72
|
+
},
|
|
73
|
+
ripple.id
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
function Ripple({
|
|
77
|
+
ripples,
|
|
78
|
+
onRippleDone,
|
|
79
|
+
disabled = false,
|
|
80
|
+
respectSystemMotion = true
|
|
81
|
+
}) {
|
|
82
|
+
const prefersReduced = useReducedMotion();
|
|
83
|
+
if (disabled) return null;
|
|
84
|
+
if (respectSystemMotion && prefersReduced) return null;
|
|
85
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: ripples.map((r) => /* @__PURE__ */ jsx(RippleItem, { ripple: r, onDone: onRippleDone }, r.id)) });
|
|
86
|
+
}
|
|
87
|
+
function useRippleState(options = {}) {
|
|
88
|
+
const { disabled = false } = options;
|
|
89
|
+
const [ripples, setRipples] = React4.useState([]);
|
|
90
|
+
const onPointerDown = React4.useCallback(
|
|
91
|
+
(e) => {
|
|
92
|
+
if (disabled) return;
|
|
93
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
94
|
+
const x = e.clientX - rect.left;
|
|
95
|
+
const y = e.clientY - rect.top;
|
|
96
|
+
const rippleSize = Math.hypot(rect.width, rect.height) * 2;
|
|
97
|
+
setRipples((prev) => [
|
|
98
|
+
...prev,
|
|
99
|
+
{ id: Date.now(), x, y, size: rippleSize }
|
|
100
|
+
]);
|
|
101
|
+
},
|
|
102
|
+
[disabled]
|
|
103
|
+
);
|
|
104
|
+
const removeRipple = React4.useCallback((id) => {
|
|
105
|
+
setRipples((prev) => prev.filter((r) => r.id !== id));
|
|
106
|
+
}, []);
|
|
107
|
+
return { ripples, onPointerDown, removeRipple };
|
|
108
|
+
}
|
|
109
|
+
var MD3_STANDARD = [0.2, 0, 0, 1];
|
|
110
|
+
var MD3_FAST_EFFECTS = [0.3, 0, 1, 1];
|
|
111
|
+
var CHECKMARK_PATH = "M 4.5 9.5 L 7.5 12.5 L 13.5 5.5";
|
|
112
|
+
var DASH_PATH = "M 4.5 9 L 9 9 L 13.5 9";
|
|
113
|
+
function resolveState(checked, indeterminate, state) {
|
|
114
|
+
if (state !== void 0) return state;
|
|
115
|
+
return checked ? "checked" : "unchecked";
|
|
116
|
+
}
|
|
117
|
+
var NEXT_STATE = {
|
|
118
|
+
unchecked: "checked",
|
|
119
|
+
checked: "indeterminate",
|
|
120
|
+
indeterminate: "unchecked"
|
|
121
|
+
};
|
|
122
|
+
var CheckboxVisual = React4.memo(function CheckboxVisual2({
|
|
123
|
+
isSelected,
|
|
124
|
+
isIndeterminate,
|
|
125
|
+
containerBg,
|
|
126
|
+
containerBorderColor,
|
|
127
|
+
containerBorderWidth,
|
|
128
|
+
iconColor,
|
|
129
|
+
svgPath,
|
|
130
|
+
pathLength,
|
|
131
|
+
fillDuration,
|
|
132
|
+
drawDuration,
|
|
133
|
+
morphDuration,
|
|
134
|
+
prefersReduced
|
|
135
|
+
}) {
|
|
136
|
+
return /* @__PURE__ */ jsx(
|
|
137
|
+
m.div,
|
|
138
|
+
{
|
|
139
|
+
"aria-hidden": "true",
|
|
140
|
+
className: "relative flex items-center justify-center w-4.5 h-4.5 rounded-sm overflow-hidden",
|
|
141
|
+
animate: {
|
|
142
|
+
backgroundColor: containerBg,
|
|
143
|
+
borderColor: containerBorderColor,
|
|
144
|
+
borderWidth: containerBorderWidth
|
|
145
|
+
},
|
|
146
|
+
transition: {
|
|
147
|
+
backgroundColor: {
|
|
148
|
+
duration: fillDuration,
|
|
149
|
+
ease: isSelected ? MD3_FAST_EFFECTS : "easeOut"
|
|
150
|
+
},
|
|
151
|
+
borderColor: { duration: fillDuration, ease: "easeOut" },
|
|
152
|
+
borderWidth: { duration: fillDuration, ease: "easeOut" }
|
|
153
|
+
},
|
|
154
|
+
style: { borderStyle: "solid" },
|
|
155
|
+
children: /* @__PURE__ */ jsx(AnimatePresence, { children: isSelected && /* @__PURE__ */ jsx(
|
|
156
|
+
m.svg,
|
|
157
|
+
{
|
|
158
|
+
viewBox: "0 0 18 18",
|
|
159
|
+
fill: "none",
|
|
160
|
+
strokeLinecap: "round",
|
|
161
|
+
strokeLinejoin: "round",
|
|
162
|
+
width: 18,
|
|
163
|
+
height: 18,
|
|
164
|
+
initial: { opacity: 0 },
|
|
165
|
+
animate: { opacity: 1 },
|
|
166
|
+
exit: { opacity: 0 },
|
|
167
|
+
transition: { duration: prefersReduced ? 0 : 0.1 },
|
|
168
|
+
"aria-hidden": "true",
|
|
169
|
+
children: /* @__PURE__ */ jsx(
|
|
170
|
+
m.path,
|
|
171
|
+
{
|
|
172
|
+
d: svgPath,
|
|
173
|
+
stroke: iconColor,
|
|
174
|
+
strokeWidth: 2,
|
|
175
|
+
animate: {
|
|
176
|
+
d: svgPath,
|
|
177
|
+
pathLength: isIndeterminate ? 1 : pathLength
|
|
178
|
+
},
|
|
179
|
+
initial: { pathLength: 0 },
|
|
180
|
+
transition: {
|
|
181
|
+
d: { duration: morphDuration, ease: MD3_STANDARD },
|
|
182
|
+
pathLength: { duration: drawDuration, ease: MD3_STANDARD }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
},
|
|
187
|
+
"icon"
|
|
188
|
+
) })
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
function useMergedRef(externalRef, internalRef) {
|
|
193
|
+
return React4.useCallback(
|
|
194
|
+
(node) => {
|
|
195
|
+
internalRef.current = node;
|
|
196
|
+
if (!externalRef) return;
|
|
197
|
+
if (typeof externalRef === "function") {
|
|
198
|
+
externalRef(node);
|
|
199
|
+
} else {
|
|
200
|
+
externalRef.current = node;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
[externalRef, internalRef]
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
var CheckboxComponent = React4.forwardRef(
|
|
207
|
+
({
|
|
208
|
+
checked,
|
|
209
|
+
defaultChecked = false,
|
|
210
|
+
indeterminate = false,
|
|
211
|
+
onCheckedChange,
|
|
212
|
+
state: stateProp,
|
|
213
|
+
onStateChange,
|
|
214
|
+
disabled = false,
|
|
215
|
+
error = false,
|
|
216
|
+
label,
|
|
217
|
+
"aria-label": ariaLabel,
|
|
218
|
+
"aria-labelledby": ariaLabelledby,
|
|
219
|
+
"aria-describedby": ariaDescribedby,
|
|
220
|
+
"aria-required": ariaRequired,
|
|
221
|
+
name,
|
|
222
|
+
value,
|
|
223
|
+
id: idProp,
|
|
224
|
+
className
|
|
225
|
+
}, ref) => {
|
|
226
|
+
var _a;
|
|
227
|
+
const prefersReduced = (_a = useReducedMotion()) != null ? _a : false;
|
|
228
|
+
const generatedId = React4.useId();
|
|
229
|
+
const inputId = idProp != null ? idProp : label ? `checkbox-${generatedId}` : void 0;
|
|
230
|
+
const [internalState, setInternalState] = React4.useState(
|
|
231
|
+
() => defaultChecked ? "checked" : "unchecked"
|
|
232
|
+
);
|
|
233
|
+
const isControlled = stateProp !== void 0 || checked !== void 0;
|
|
234
|
+
const baseState = isControlled ? resolveState(checked, false, stateProp) : internalState;
|
|
235
|
+
const effectiveState = indeterminate ? "indeterminate" : baseState;
|
|
236
|
+
const [ripples, setRipples] = React4.useState([]);
|
|
237
|
+
const removeRipple = React4.useCallback(
|
|
238
|
+
(id) => setRipples((prev) => prev.filter((r) => r.id !== id)),
|
|
239
|
+
[]
|
|
240
|
+
);
|
|
241
|
+
const onPointerDown = React4.useCallback(
|
|
242
|
+
(e) => {
|
|
243
|
+
if (disabled) return;
|
|
244
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
245
|
+
const x = e.clientX - rect.left - 4;
|
|
246
|
+
const y = e.clientY - rect.top - 4;
|
|
247
|
+
const rippleSize = Math.hypot(40, 40) * 2;
|
|
248
|
+
setRipples((prev) => [
|
|
249
|
+
...prev,
|
|
250
|
+
{ id: Date.now(), x, y, size: rippleSize }
|
|
251
|
+
]);
|
|
252
|
+
},
|
|
253
|
+
[disabled]
|
|
254
|
+
);
|
|
255
|
+
const handleChange = React4.useCallback(
|
|
256
|
+
(e) => {
|
|
257
|
+
if (disabled) return;
|
|
258
|
+
if (stateProp !== void 0) {
|
|
259
|
+
onStateChange == null ? void 0 : onStateChange(NEXT_STATE[effectiveState]);
|
|
260
|
+
} else if (checked !== void 0) {
|
|
261
|
+
onCheckedChange == null ? void 0 : onCheckedChange(e.target.checked);
|
|
262
|
+
} else {
|
|
263
|
+
const next = NEXT_STATE[effectiveState];
|
|
264
|
+
setInternalState(next);
|
|
265
|
+
if (next === "indeterminate") {
|
|
266
|
+
onStateChange == null ? void 0 : onStateChange(next);
|
|
267
|
+
} else {
|
|
268
|
+
onCheckedChange == null ? void 0 : onCheckedChange(next === "checked");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
[
|
|
273
|
+
disabled,
|
|
274
|
+
stateProp,
|
|
275
|
+
checked,
|
|
276
|
+
effectiveState,
|
|
277
|
+
onStateChange,
|
|
278
|
+
onCheckedChange
|
|
279
|
+
]
|
|
280
|
+
);
|
|
281
|
+
const inputRef = React4.useRef(null);
|
|
282
|
+
const mergedRef = useMergedRef(ref, inputRef);
|
|
283
|
+
React4.useEffect(() => {
|
|
284
|
+
if (inputRef.current) {
|
|
285
|
+
inputRef.current.indeterminate = effectiveState === "indeterminate";
|
|
286
|
+
}
|
|
287
|
+
}, [effectiveState]);
|
|
288
|
+
const isChecked = effectiveState === "checked";
|
|
289
|
+
const isIndeterminate = effectiveState === "indeterminate";
|
|
290
|
+
const isSelected = isChecked || isIndeterminate;
|
|
291
|
+
const ariaChecked = isIndeterminate ? "mixed" : isChecked;
|
|
292
|
+
const accentColor = error ? "var(--color-m3-error)" : "var(--color-m3-primary)";
|
|
293
|
+
const onAccentColor = error ? "var(--color-m3-on-error)" : "var(--color-m3-on-primary)";
|
|
294
|
+
const outlineColor = error ? "var(--color-m3-error)" : "rgba(0, 0, 0, 0.38)";
|
|
295
|
+
const containerBg = isSelected ? accentColor : "rgba(0, 0, 0, 0)";
|
|
296
|
+
const containerBorderColor = isSelected ? "rgba(0, 0, 0, 0)" : outlineColor;
|
|
297
|
+
const containerBorderWidth = isSelected ? 0 : 2;
|
|
298
|
+
const iconColor = isSelected ? onAccentColor : "rgba(0, 0, 0, 0)";
|
|
299
|
+
const svgPath = isIndeterminate ? DASH_PATH : CHECKMARK_PATH;
|
|
300
|
+
const pathLength = isSelected ? 1 : 0;
|
|
301
|
+
const fillDuration = prefersReduced ? 0 : isSelected ? 0.15 : 0.1;
|
|
302
|
+
const drawDuration = prefersReduced ? 0 : isSelected ? 0.2 : 0.1;
|
|
303
|
+
const morphDuration = prefersReduced ? 0 : 0.2;
|
|
304
|
+
const stateLayerBg = isSelected ? error ? "before:bg-m3-error" : "before:bg-m3-primary" : error ? "before:bg-m3-error" : "before:bg-m3-on-surface";
|
|
305
|
+
const stateLayerClass = cn(
|
|
306
|
+
"before:absolute before:inset-0 before:rounded-full before:pointer-events-none",
|
|
307
|
+
"before:transition-opacity before:duration-150 before:opacity-0",
|
|
308
|
+
"group-hover/cbx:before:opacity-[0.08]",
|
|
309
|
+
"group-focus-within/cbx:before:opacity-[0.10]",
|
|
310
|
+
"group-active/cbx:before:opacity-[0.10]",
|
|
311
|
+
stateLayerBg
|
|
312
|
+
);
|
|
313
|
+
const visualProps = {
|
|
314
|
+
isSelected,
|
|
315
|
+
isIndeterminate,
|
|
316
|
+
containerBg,
|
|
317
|
+
containerBorderColor,
|
|
318
|
+
containerBorderWidth,
|
|
319
|
+
iconColor,
|
|
320
|
+
svgPath,
|
|
321
|
+
pathLength,
|
|
322
|
+
fillDuration,
|
|
323
|
+
drawDuration,
|
|
324
|
+
morphDuration,
|
|
325
|
+
prefersReduced
|
|
326
|
+
};
|
|
327
|
+
const touchTargetClass = cn(
|
|
328
|
+
"relative inline-flex items-center justify-center outline-none shrink-0",
|
|
329
|
+
"w-12 h-12 group/cbx",
|
|
330
|
+
disabled && "pointer-events-none"
|
|
331
|
+
);
|
|
332
|
+
const stateLayerAndRipple = /* @__PURE__ */ jsx(
|
|
333
|
+
"div",
|
|
334
|
+
{
|
|
335
|
+
className: cn(
|
|
336
|
+
"absolute flex items-center justify-center w-10 h-10 m-auto inset-0 rounded-full overflow-hidden pointer-events-none",
|
|
337
|
+
stateLayerClass
|
|
338
|
+
),
|
|
339
|
+
"aria-hidden": "true",
|
|
340
|
+
children: /* @__PURE__ */ jsx(
|
|
341
|
+
Ripple,
|
|
342
|
+
{
|
|
343
|
+
ripples,
|
|
344
|
+
onRippleDone: removeRipple,
|
|
345
|
+
disabled
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
const hiddenInput = /* @__PURE__ */ jsx(
|
|
351
|
+
"input",
|
|
352
|
+
{
|
|
353
|
+
ref: mergedRef,
|
|
354
|
+
type: "checkbox",
|
|
355
|
+
id: inputId,
|
|
356
|
+
name,
|
|
357
|
+
value,
|
|
358
|
+
checked: isChecked,
|
|
359
|
+
disabled,
|
|
360
|
+
"aria-checked": ariaChecked,
|
|
361
|
+
"aria-disabled": disabled || void 0,
|
|
362
|
+
"aria-invalid": error || void 0,
|
|
363
|
+
"aria-label": ariaLabel,
|
|
364
|
+
"aria-labelledby": ariaLabelledby,
|
|
365
|
+
"aria-describedby": ariaDescribedby,
|
|
366
|
+
"aria-required": ariaRequired,
|
|
367
|
+
onChange: handleChange,
|
|
368
|
+
className: "sr-only"
|
|
369
|
+
}
|
|
370
|
+
);
|
|
371
|
+
if (label) {
|
|
372
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
|
|
373
|
+
"label",
|
|
374
|
+
{
|
|
375
|
+
htmlFor: inputId,
|
|
376
|
+
className: cn(
|
|
377
|
+
"inline-flex items-center gap-2 cursor-pointer select-none",
|
|
378
|
+
disabled && "cursor-not-allowed opacity-[0.38] pointer-events-none",
|
|
379
|
+
className
|
|
380
|
+
),
|
|
381
|
+
children: [
|
|
382
|
+
/* @__PURE__ */ jsxs("div", { className: touchTargetClass, onPointerDown, children: [
|
|
383
|
+
stateLayerAndRipple,
|
|
384
|
+
hiddenInput,
|
|
385
|
+
/* @__PURE__ */ jsx(CheckboxVisual, __spreadValues({}, visualProps))
|
|
386
|
+
] }),
|
|
387
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm leading-none text-m3-on-surface", children: label })
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
) });
|
|
391
|
+
}
|
|
392
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
|
|
393
|
+
"label",
|
|
394
|
+
{
|
|
395
|
+
htmlFor: inputId,
|
|
396
|
+
className: cn(touchTargetClass, "cursor-pointer", className),
|
|
397
|
+
onPointerDown,
|
|
398
|
+
children: [
|
|
399
|
+
stateLayerAndRipple,
|
|
400
|
+
hiddenInput,
|
|
401
|
+
/* @__PURE__ */ jsx(CheckboxVisual, __spreadValues({}, visualProps))
|
|
402
|
+
]
|
|
403
|
+
}
|
|
404
|
+
) });
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
CheckboxComponent.displayName = "Checkbox";
|
|
408
|
+
var Checkbox = React4.memo(CheckboxComponent);
|
|
409
|
+
var TriStateCheckboxComponent = React4.forwardRef((_a, ref) => {
|
|
410
|
+
var _b = _a, { state, onStateChange } = _b, rest = __objRest(_b, ["state", "onStateChange"]);
|
|
411
|
+
return /* @__PURE__ */ jsx(Checkbox, __spreadValues({ ref, state, onStateChange }, rest));
|
|
412
|
+
});
|
|
413
|
+
TriStateCheckboxComponent.displayName = "TriStateCheckbox";
|
|
414
|
+
var TriStateCheckbox = React4.memo(TriStateCheckboxComponent);
|
|
415
|
+
function CheckIcon({ className }) {
|
|
416
|
+
return /* @__PURE__ */ jsx(
|
|
417
|
+
"svg",
|
|
418
|
+
{
|
|
419
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
420
|
+
viewBox: "0 0 24 24",
|
|
421
|
+
width: 18,
|
|
422
|
+
height: 18,
|
|
423
|
+
fill: "none",
|
|
424
|
+
stroke: "currentColor",
|
|
425
|
+
strokeWidth: 2.5,
|
|
426
|
+
strokeLinecap: "round",
|
|
427
|
+
strokeLinejoin: "round",
|
|
428
|
+
"aria-hidden": "true",
|
|
429
|
+
className,
|
|
430
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
function CloseIcon({ className }) {
|
|
435
|
+
return /* @__PURE__ */ jsxs(
|
|
436
|
+
"svg",
|
|
437
|
+
{
|
|
438
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
439
|
+
viewBox: "0 0 24 24",
|
|
440
|
+
width: 18,
|
|
441
|
+
height: 18,
|
|
442
|
+
fill: "none",
|
|
443
|
+
stroke: "currentColor",
|
|
444
|
+
strokeWidth: 2.5,
|
|
445
|
+
strokeLinecap: "round",
|
|
446
|
+
strokeLinejoin: "round",
|
|
447
|
+
"aria-hidden": "true",
|
|
448
|
+
className,
|
|
449
|
+
children: [
|
|
450
|
+
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
451
|
+
/* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
452
|
+
]
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
var chipVariants = cva(
|
|
457
|
+
[
|
|
458
|
+
// Base layout
|
|
459
|
+
"inline-flex items-center h-8 rounded-lg",
|
|
460
|
+
// Typography: LabelLarge
|
|
461
|
+
"text-sm font-medium leading-none",
|
|
462
|
+
// Interaction
|
|
463
|
+
"relative overflow-hidden cursor-pointer select-none",
|
|
464
|
+
"transition-all duration-200 ease-in-out",
|
|
465
|
+
// Remove browser default focus; use MD3 focus ring
|
|
466
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1",
|
|
467
|
+
"focus-visible:ring-m3-secondary",
|
|
468
|
+
// Expressive scale feedback (MD3 "bouncy" press)
|
|
469
|
+
"active:scale-[0.98]",
|
|
470
|
+
// MD3 State Layer (pseudo-element overlay)
|
|
471
|
+
// Use inset-[-1px] to ensure the state layer covers the 1px border perfectly
|
|
472
|
+
"before:absolute before:inset-[-1px] before:pointer-events-none before:rounded-lg",
|
|
473
|
+
"before:transition-opacity before:duration-200 before:opacity-0",
|
|
474
|
+
"hover:before:opacity-[0.08] focus-visible:before:opacity-[0.10] active:before:opacity-[0.10]"
|
|
475
|
+
].join(" "),
|
|
476
|
+
{
|
|
477
|
+
variants: {
|
|
478
|
+
/**
|
|
479
|
+
* Chip variant controlling default colors and border behavior.
|
|
480
|
+
* Selected/elevated state overrides are applied via `cn()` at runtime.
|
|
481
|
+
*/
|
|
482
|
+
variant: {
|
|
483
|
+
/**
|
|
484
|
+
* Assist chip – FlatOutlineColor: outline-variant, LabelTextColor: on-surface
|
|
485
|
+
* Leading icon color: primary (AssistChipTokens.IconColor)
|
|
486
|
+
*/
|
|
487
|
+
assist: "border border-m3-outline-variant text-m3-on-surface before:bg-m3-on-surface",
|
|
488
|
+
/**
|
|
489
|
+
* Filter chip (unselected) – FlatUnselectedOutlineColor: outline-variant
|
|
490
|
+
* UnselectedLabelTextColor: on-surface-variant
|
|
491
|
+
*/
|
|
492
|
+
filter: "border border-m3-outline-variant text-m3-on-surface-variant before:bg-m3-on-surface-variant",
|
|
493
|
+
/**
|
|
494
|
+
* Input chip (unselected) – UnselectedOutlineColor: outline-variant
|
|
495
|
+
* UnselectedLabelTextColor: on-surface-variant
|
|
496
|
+
*/
|
|
497
|
+
input: "border border-m3-outline-variant text-m3-on-surface-variant before:bg-m3-on-surface-variant",
|
|
498
|
+
/**
|
|
499
|
+
* Suggestion chip – FlatOutlineColor: outline-variant
|
|
500
|
+
* LabelTextColor: on-surface-variant (SuggestionChipTokens)
|
|
501
|
+
*/
|
|
502
|
+
suggestion: "border border-m3-outline-variant text-m3-on-surface-variant before:bg-m3-on-surface-variant"
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
defaultVariants: { variant: "assist" }
|
|
506
|
+
}
|
|
507
|
+
);
|
|
508
|
+
var ChipImpl = React4.forwardRef(
|
|
509
|
+
(_a, ref) => {
|
|
510
|
+
var _b = _a, {
|
|
511
|
+
variant = "assist",
|
|
512
|
+
elevated = false,
|
|
513
|
+
selected = false,
|
|
514
|
+
disabled = false,
|
|
515
|
+
label,
|
|
516
|
+
leadingIcon,
|
|
517
|
+
trailingIcon,
|
|
518
|
+
avatar,
|
|
519
|
+
onRemove,
|
|
520
|
+
className,
|
|
521
|
+
onClick
|
|
522
|
+
} = _b, props = __objRest(_b, [
|
|
523
|
+
"variant",
|
|
524
|
+
"elevated",
|
|
525
|
+
"selected",
|
|
526
|
+
"disabled",
|
|
527
|
+
"label",
|
|
528
|
+
"leadingIcon",
|
|
529
|
+
"trailingIcon",
|
|
530
|
+
"avatar",
|
|
531
|
+
"onRemove",
|
|
532
|
+
"className",
|
|
533
|
+
"onClick"
|
|
534
|
+
]);
|
|
535
|
+
const { ripples, onPointerDown, removeRipple } = useRippleState({
|
|
536
|
+
disabled
|
|
537
|
+
});
|
|
538
|
+
const isFilter = variant === "filter";
|
|
539
|
+
const isInput = variant === "input";
|
|
540
|
+
const resolvedLeadingIcon = isInput && avatar ? avatar : leadingIcon;
|
|
541
|
+
const showCheckmark = isFilter && selected;
|
|
542
|
+
const hasTrailingContent = !!trailingIcon || !!onRemove;
|
|
543
|
+
const hasLeadingContent = isFilter || !!resolvedLeadingIcon;
|
|
544
|
+
const paddingClass = React4.useMemo(
|
|
545
|
+
() => cn(
|
|
546
|
+
!isInput && !hasLeadingContent && !hasTrailingContent && "px-4",
|
|
547
|
+
!isInput && hasLeadingContent && !hasTrailingContent && "pl-2 pr-4",
|
|
548
|
+
!isInput && !hasLeadingContent && hasTrailingContent && "pl-4 pr-2",
|
|
549
|
+
!isInput && hasLeadingContent && hasTrailingContent && "px-2",
|
|
550
|
+
isInput && !hasLeadingContent && !hasTrailingContent && "px-3",
|
|
551
|
+
isInput && hasLeadingContent && !hasTrailingContent && "pl-1 pr-3",
|
|
552
|
+
isInput && !hasLeadingContent && hasTrailingContent && "pl-3 pr-2",
|
|
553
|
+
isInput && hasLeadingContent && hasTrailingContent && "pl-1 pr-2"
|
|
554
|
+
),
|
|
555
|
+
[isInput, hasLeadingContent, hasTrailingContent]
|
|
556
|
+
);
|
|
557
|
+
const stateClass = React4.useMemo(
|
|
558
|
+
() => cn(
|
|
559
|
+
(isFilter || isInput) && selected && "bg-m3-secondary-container text-m3-on-secondary-container border-none before:bg-m3-on-secondary-container",
|
|
560
|
+
elevated && !selected && "bg-m3-surface-container-low border-none elevation-1",
|
|
561
|
+
elevated && isFilter && selected && "elevation-1",
|
|
562
|
+
disabled && "opacity-[0.38] pointer-events-none cursor-not-allowed",
|
|
563
|
+
disabled && !selected && "border-m3-outline-variant/[.12]",
|
|
564
|
+
disabled && selected && "bg-m3-on-surface/[.12] text-m3-on-surface border-none"
|
|
565
|
+
),
|
|
566
|
+
[isFilter, isInput, selected, elevated, disabled]
|
|
567
|
+
);
|
|
568
|
+
const leadingIconColorClass = React4.useMemo(
|
|
569
|
+
() => cn(
|
|
570
|
+
(variant === "assist" || variant === "suggestion") && "text-m3-primary",
|
|
571
|
+
isFilter && !selected && "text-m3-primary",
|
|
572
|
+
isFilter && selected && "text-m3-on-secondary-container",
|
|
573
|
+
isInput && !selected && "text-m3-on-surface-variant",
|
|
574
|
+
isInput && selected && "text-m3-primary"
|
|
575
|
+
),
|
|
576
|
+
[variant, isFilter, isInput, selected]
|
|
577
|
+
);
|
|
578
|
+
const isCompound = !!onRemove;
|
|
579
|
+
const Root2 = isCompound ? "div" : "button";
|
|
580
|
+
const containerClass = cn(
|
|
581
|
+
chipVariants({ variant }),
|
|
582
|
+
!isCompound && paddingClass,
|
|
583
|
+
!isCompound && "gap-2",
|
|
584
|
+
stateClass,
|
|
585
|
+
// When compound, the root div handles the overall shape but not the main interaction
|
|
586
|
+
// We disable the root's state layer (hover/focus) to avoid the 1px gap issue
|
|
587
|
+
isCompound && "items-stretch cursor-default active:scale-100 before:opacity-0 gap-0",
|
|
588
|
+
className
|
|
589
|
+
);
|
|
590
|
+
const mainContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
591
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: isFilter ? showCheckmark ? /* @__PURE__ */ jsx(
|
|
592
|
+
m.span,
|
|
593
|
+
{
|
|
594
|
+
initial: { width: 0, opacity: 0 },
|
|
595
|
+
animate: { width: 18, opacity: 1 },
|
|
596
|
+
exit: { width: 0, opacity: 0 },
|
|
597
|
+
transition: {
|
|
598
|
+
width: { duration: 0.2, ease: [0.2, 0, 0, 1] },
|
|
599
|
+
opacity: { duration: 0.15, ease: "easeOut" }
|
|
600
|
+
},
|
|
601
|
+
className: "flex items-center justify-center shrink-0 overflow-hidden",
|
|
602
|
+
"aria-hidden": "true",
|
|
603
|
+
children: /* @__PURE__ */ jsx(CheckIcon, {})
|
|
604
|
+
},
|
|
605
|
+
"checkmark"
|
|
606
|
+
) : resolvedLeadingIcon ? /* @__PURE__ */ jsx(
|
|
607
|
+
m.span,
|
|
608
|
+
{
|
|
609
|
+
initial: { width: 0, opacity: 0 },
|
|
610
|
+
animate: { width: 18, opacity: 1 },
|
|
611
|
+
exit: { width: 0, opacity: 0 },
|
|
612
|
+
transition: {
|
|
613
|
+
width: { duration: 0.2, ease: [0.2, 0, 0, 1] },
|
|
614
|
+
opacity: { duration: 0.15, ease: "easeOut" }
|
|
615
|
+
},
|
|
616
|
+
className: cn(
|
|
617
|
+
"flex items-center justify-center shrink-0 overflow-hidden [&_.md-icon]:text-[length:inherit]!",
|
|
618
|
+
leadingIconColorClass
|
|
619
|
+
),
|
|
620
|
+
style: { fontSize: 18 },
|
|
621
|
+
"aria-hidden": "true",
|
|
622
|
+
children: resolvedLeadingIcon
|
|
623
|
+
},
|
|
624
|
+
"leading-icon"
|
|
625
|
+
) : null : resolvedLeadingIcon ? isInput && avatar ? /* @__PURE__ */ jsx(
|
|
626
|
+
"span",
|
|
627
|
+
{
|
|
628
|
+
className: "flex items-center justify-center shrink-0 w-6 h-6 rounded-full overflow-hidden",
|
|
629
|
+
"aria-hidden": "true",
|
|
630
|
+
children: resolvedLeadingIcon
|
|
631
|
+
},
|
|
632
|
+
"avatar"
|
|
633
|
+
) : /* @__PURE__ */ jsx(
|
|
634
|
+
"span",
|
|
635
|
+
{
|
|
636
|
+
className: cn(
|
|
637
|
+
"flex items-center justify-center shrink-0 w-4.5 h-4.5 [&_.md-icon]:text-[length:inherit]!",
|
|
638
|
+
leadingIconColorClass
|
|
639
|
+
),
|
|
640
|
+
style: { fontSize: 18 },
|
|
641
|
+
"aria-hidden": "true",
|
|
642
|
+
children: resolvedLeadingIcon
|
|
643
|
+
},
|
|
644
|
+
"leading-icon"
|
|
645
|
+
) : null }),
|
|
646
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: label })
|
|
647
|
+
] });
|
|
648
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
|
|
649
|
+
Root2,
|
|
650
|
+
__spreadProps(__spreadValues(__spreadProps(__spreadValues({
|
|
651
|
+
ref: !isCompound ? ref : void 0,
|
|
652
|
+
type: !isCompound ? "button" : void 0
|
|
653
|
+
}, isFilter ? {
|
|
654
|
+
role: "checkbox",
|
|
655
|
+
"aria-checked": selected
|
|
656
|
+
} : isInput && !isCompound && selected ? { role: "button", "aria-pressed": true } : isCompound ? { role: "group" } : { role: "button" }), {
|
|
657
|
+
"aria-disabled": disabled || void 0,
|
|
658
|
+
tabIndex: isCompound ? -1 : disabled ? -1 : 0,
|
|
659
|
+
disabled: !isCompound ? disabled : void 0,
|
|
660
|
+
onClick: !isCompound ? onClick : void 0,
|
|
661
|
+
onPointerDown: !isCompound ? onPointerDown : void 0,
|
|
662
|
+
className: containerClass
|
|
663
|
+
}), isCompound ? {} : props), {
|
|
664
|
+
children: [
|
|
665
|
+
!isCompound && /* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone: removeRipple }),
|
|
666
|
+
isCompound ? /* @__PURE__ */ jsxs(
|
|
667
|
+
"button",
|
|
668
|
+
{
|
|
669
|
+
ref,
|
|
670
|
+
type: "button",
|
|
671
|
+
tabIndex: disabled ? -1 : 0,
|
|
672
|
+
disabled,
|
|
673
|
+
onClick,
|
|
674
|
+
onPointerDown,
|
|
675
|
+
className: cn(
|
|
676
|
+
"flex items-center h-full grow focus:outline-none appearance-none bg-transparent border-none",
|
|
677
|
+
"text-inherit font-inherit cursor-pointer",
|
|
678
|
+
// Move padding here; keep horizontal padding but remove trailing to fit next to X
|
|
679
|
+
paddingClass,
|
|
680
|
+
"gap-2",
|
|
681
|
+
"pr-0",
|
|
682
|
+
// Re-apply focus ring to internal button instead of root div
|
|
683
|
+
"focus-visible:ring-2 focus-visible:ring-m3-secondary focus-visible:ring-inset",
|
|
684
|
+
"rounded-l-[7px] rounded-r-none",
|
|
685
|
+
// State layer for main area
|
|
686
|
+
"relative overflow-hidden",
|
|
687
|
+
"before:absolute before:-inset-px before:pointer-events-none before:bg-current",
|
|
688
|
+
"before:transition-opacity before:duration-200 before:opacity-0 before:rounded-l-[7px]",
|
|
689
|
+
"hover:before:opacity-[0.08] focus-visible:before:opacity-[0.10] active:before:opacity-[0.10]"
|
|
690
|
+
),
|
|
691
|
+
children: [
|
|
692
|
+
/* @__PURE__ */ jsx(Ripple, { ripples, onRippleDone: removeRipple }),
|
|
693
|
+
mainContent
|
|
694
|
+
]
|
|
695
|
+
}
|
|
696
|
+
) : mainContent,
|
|
697
|
+
hasTrailingContent && /* @__PURE__ */ jsx("span", { className: "flex items-center justify-center shrink-0", children: onRemove ? /* @__PURE__ */ jsx(
|
|
698
|
+
"button",
|
|
699
|
+
{
|
|
700
|
+
type: "button",
|
|
701
|
+
tabIndex: disabled ? -1 : 0,
|
|
702
|
+
"aria-label": typeof label === "string" ? `Remove ${label}` : "Remove",
|
|
703
|
+
onClick: (e) => {
|
|
704
|
+
e.stopPropagation();
|
|
705
|
+
onRemove(e);
|
|
706
|
+
},
|
|
707
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
708
|
+
className: cn(
|
|
709
|
+
"flex items-center justify-center w-8.5 h-full",
|
|
710
|
+
// 18px icon + 8px left + 8px right padding
|
|
711
|
+
"cursor-pointer focus-visible:outline-none",
|
|
712
|
+
"transition-all duration-150",
|
|
713
|
+
"relative overflow-hidden rounded-r-[7px] rounded-l-none",
|
|
714
|
+
"before:absolute before:-inset-px before:pointer-events-none before:bg-current",
|
|
715
|
+
"before:transition-opacity before:duration-200 before:opacity-0 before:rounded-r-[7px]",
|
|
716
|
+
"hover:before:opacity-[0.08] active:before:opacity-[0.12]",
|
|
717
|
+
// TrailingIcon color tokens
|
|
718
|
+
selected ? "text-m3-on-secondary-container" : "text-m3-on-surface-variant"
|
|
719
|
+
),
|
|
720
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
721
|
+
}
|
|
722
|
+
) : trailingIcon ? /* @__PURE__ */ jsx(
|
|
723
|
+
"span",
|
|
724
|
+
{
|
|
725
|
+
className: cn(
|
|
726
|
+
"flex items-center justify-center w-4.5 h-4.5 [&_.md-icon]:text-[length:inherit]!",
|
|
727
|
+
selected ? "text-m3-on-secondary-container" : "text-m3-on-surface-variant"
|
|
728
|
+
),
|
|
729
|
+
style: { fontSize: 18 },
|
|
730
|
+
"aria-hidden": "true",
|
|
731
|
+
children: trailingIcon
|
|
732
|
+
}
|
|
733
|
+
) : null })
|
|
734
|
+
]
|
|
735
|
+
})
|
|
736
|
+
) });
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
ChipImpl.displayName = "Chip";
|
|
740
|
+
var Chip = React4.memo(ChipImpl);
|
|
741
|
+
var MD3_FAST_EFFECTS2 = [0.3, 0, 1, 1];
|
|
742
|
+
var RadioGroupContext = React4.createContext(
|
|
743
|
+
null
|
|
744
|
+
);
|
|
745
|
+
function useMergedRef2(externalRef, internalRef) {
|
|
746
|
+
return React4.useCallback(
|
|
747
|
+
(node) => {
|
|
748
|
+
internalRef.current = node;
|
|
749
|
+
if (!externalRef) return;
|
|
750
|
+
if (typeof externalRef === "function") {
|
|
751
|
+
externalRef(node);
|
|
752
|
+
} else {
|
|
753
|
+
externalRef.current = node;
|
|
754
|
+
}
|
|
755
|
+
},
|
|
756
|
+
[externalRef, internalRef]
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
var RadioVisual = React4.memo(function RadioVisual2({
|
|
760
|
+
isSelected,
|
|
761
|
+
disabled,
|
|
762
|
+
error,
|
|
763
|
+
isHovered,
|
|
764
|
+
prefersReduced
|
|
765
|
+
}) {
|
|
766
|
+
const accentColor = error ? "var(--color-m3-error)" : "var(--color-m3-primary)";
|
|
767
|
+
const disabledColor = "rgba(0, 0, 0, 0.38)";
|
|
768
|
+
const outerStroke = disabled ? disabledColor : isSelected ? accentColor : isHovered ? "var(--color-m3-on-surface)" : "var(--color-m3-on-surface-variant)";
|
|
769
|
+
const dotFill = disabled ? disabledColor : isSelected ? accentColor : "rgba(0, 0, 0, 0)";
|
|
770
|
+
const ringDuration = prefersReduced ? 0 : 0.15;
|
|
771
|
+
const dotDuration = prefersReduced ? 0 : isSelected ? 0.2 : 0.1;
|
|
772
|
+
const dotEase = isSelected ? MD3_FAST_EFFECTS2 : "easeOut";
|
|
773
|
+
return /* @__PURE__ */ jsxs(
|
|
774
|
+
"svg",
|
|
775
|
+
{
|
|
776
|
+
viewBox: "0 0 20 20",
|
|
777
|
+
width: 20,
|
|
778
|
+
height: 20,
|
|
779
|
+
fill: "none",
|
|
780
|
+
"aria-hidden": "true",
|
|
781
|
+
children: [
|
|
782
|
+
/* @__PURE__ */ jsx(
|
|
783
|
+
m.circle,
|
|
784
|
+
{
|
|
785
|
+
cx: 10,
|
|
786
|
+
cy: 10,
|
|
787
|
+
r: 9,
|
|
788
|
+
strokeWidth: 2,
|
|
789
|
+
fill: "none",
|
|
790
|
+
animate: { stroke: outerStroke },
|
|
791
|
+
transition: { duration: ringDuration, ease: "easeOut" }
|
|
792
|
+
}
|
|
793
|
+
),
|
|
794
|
+
/* @__PURE__ */ jsx(
|
|
795
|
+
m.circle,
|
|
796
|
+
{
|
|
797
|
+
cx: 10,
|
|
798
|
+
cy: 10,
|
|
799
|
+
initial: { r: 0 },
|
|
800
|
+
animate: { r: isSelected ? 5 : 0, fill: dotFill },
|
|
801
|
+
transition: {
|
|
802
|
+
r: { duration: dotDuration, ease: dotEase },
|
|
803
|
+
fill: { duration: ringDuration, ease: "easeOut" }
|
|
804
|
+
},
|
|
805
|
+
stroke: "none"
|
|
806
|
+
}
|
|
807
|
+
)
|
|
808
|
+
]
|
|
809
|
+
}
|
|
810
|
+
);
|
|
811
|
+
});
|
|
812
|
+
var RadioButtonComponent = React4.forwardRef(
|
|
813
|
+
({
|
|
814
|
+
selected,
|
|
815
|
+
defaultSelected = false,
|
|
816
|
+
onClick,
|
|
817
|
+
disabled: disabledProp = false,
|
|
818
|
+
color,
|
|
819
|
+
error: errorProp = false,
|
|
820
|
+
label,
|
|
821
|
+
value,
|
|
822
|
+
name: nameProp,
|
|
823
|
+
id: idProp,
|
|
824
|
+
className,
|
|
825
|
+
"aria-label": ariaLabel,
|
|
826
|
+
"aria-labelledby": ariaLabelledby,
|
|
827
|
+
"aria-describedby": ariaDescribedby,
|
|
828
|
+
required: requiredProp
|
|
829
|
+
}, ref) => {
|
|
830
|
+
var _a, _b;
|
|
831
|
+
const group = React4.useContext(RadioGroupContext);
|
|
832
|
+
const prefersReduced = (_a = useReducedMotion()) != null ? _a : false;
|
|
833
|
+
const generatedId = React4.useId();
|
|
834
|
+
const inputId = idProp != null ? idProp : label ? `radio-${generatedId}` : void 0;
|
|
835
|
+
const name = (_b = group == null ? void 0 : group.name) != null ? _b : nameProp;
|
|
836
|
+
const disabled = (group == null ? void 0 : group.disabled) || disabledProp;
|
|
837
|
+
const error = (group == null ? void 0 : group.error) || errorProp || color === "error";
|
|
838
|
+
const required = (group == null ? void 0 : group.required) || requiredProp;
|
|
839
|
+
const [internalSelected, setInternalSelected] = React4.useState(defaultSelected);
|
|
840
|
+
const isControlled = selected !== void 0;
|
|
841
|
+
const isSelected = group ? group.selectedValue === value : isControlled ? selected != null ? selected : false : internalSelected;
|
|
842
|
+
const [ripples, setRipples] = React4.useState([]);
|
|
843
|
+
const removeRipple = React4.useCallback(
|
|
844
|
+
(id) => setRipples((prev) => prev.filter((r) => r.id !== id)),
|
|
845
|
+
[]
|
|
846
|
+
);
|
|
847
|
+
const onPointerDown = React4.useCallback(
|
|
848
|
+
(e) => {
|
|
849
|
+
if (disabled) return;
|
|
850
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
851
|
+
const x = e.clientX - rect.left - 4;
|
|
852
|
+
const y = e.clientY - rect.top - 4;
|
|
853
|
+
const rippleSize = Math.hypot(40, 40) * 2;
|
|
854
|
+
setRipples((prev) => [
|
|
855
|
+
...prev,
|
|
856
|
+
{ id: Date.now(), x, y, size: rippleSize }
|
|
857
|
+
]);
|
|
858
|
+
},
|
|
859
|
+
[disabled]
|
|
860
|
+
);
|
|
861
|
+
const [isHovered, setIsHovered] = React4.useState(false);
|
|
862
|
+
const onPointerEnter = React4.useCallback(() => {
|
|
863
|
+
if (!disabled) setIsHovered(true);
|
|
864
|
+
}, [disabled]);
|
|
865
|
+
const onPointerLeave = React4.useCallback(() => setIsHovered(false), []);
|
|
866
|
+
const handleChange = React4.useCallback(
|
|
867
|
+
(_e) => {
|
|
868
|
+
if (disabled || onClick === null) return;
|
|
869
|
+
if (group) {
|
|
870
|
+
if (value !== void 0) group.onValueChange(value);
|
|
871
|
+
} else if (!isControlled) {
|
|
872
|
+
setInternalSelected(true);
|
|
873
|
+
onClick == null ? void 0 : onClick();
|
|
874
|
+
} else {
|
|
875
|
+
onClick == null ? void 0 : onClick();
|
|
876
|
+
}
|
|
877
|
+
},
|
|
878
|
+
[disabled, onClick, group, value, isControlled]
|
|
879
|
+
);
|
|
880
|
+
const inputRef = React4.useRef(null);
|
|
881
|
+
const mergedRef = useMergedRef2(ref, inputRef);
|
|
882
|
+
const stateLayerBg = error ? "before:bg-m3-error" : "before:bg-m3-primary";
|
|
883
|
+
const stateLayerClass = cn(
|
|
884
|
+
"before:absolute before:inset-0 before:rounded-full before:pointer-events-none",
|
|
885
|
+
"before:transition-opacity before:duration-150 before:opacity-0",
|
|
886
|
+
"group-hover/radio:before:opacity-[0.08]",
|
|
887
|
+
"group-focus-within/radio:before:opacity-[0.10]",
|
|
888
|
+
"group-active/radio:before:opacity-[0.10]",
|
|
889
|
+
stateLayerBg
|
|
890
|
+
);
|
|
891
|
+
const touchTargetClass = cn(
|
|
892
|
+
"relative inline-flex items-center justify-center outline-none shrink-0",
|
|
893
|
+
"w-12 h-12 group/radio cursor-pointer",
|
|
894
|
+
disabled && "pointer-events-none"
|
|
895
|
+
);
|
|
896
|
+
const stateLayerAndRipple = /* @__PURE__ */ jsx(
|
|
897
|
+
"div",
|
|
898
|
+
{
|
|
899
|
+
className: cn(
|
|
900
|
+
"absolute flex items-center justify-center w-10 h-10 m-auto inset-0 rounded-full overflow-hidden pointer-events-none",
|
|
901
|
+
stateLayerClass
|
|
902
|
+
),
|
|
903
|
+
"aria-hidden": "true",
|
|
904
|
+
children: /* @__PURE__ */ jsx(
|
|
905
|
+
Ripple,
|
|
906
|
+
{
|
|
907
|
+
ripples,
|
|
908
|
+
onRippleDone: removeRipple,
|
|
909
|
+
disabled
|
|
910
|
+
}
|
|
911
|
+
)
|
|
912
|
+
}
|
|
913
|
+
);
|
|
914
|
+
const hiddenInput = /* @__PURE__ */ jsx(
|
|
915
|
+
"input",
|
|
916
|
+
{
|
|
917
|
+
ref: mergedRef,
|
|
918
|
+
type: "radio",
|
|
919
|
+
id: inputId,
|
|
920
|
+
name,
|
|
921
|
+
value,
|
|
922
|
+
checked: isSelected,
|
|
923
|
+
disabled,
|
|
924
|
+
"aria-disabled": disabled || void 0,
|
|
925
|
+
"aria-label": ariaLabel,
|
|
926
|
+
"aria-labelledby": ariaLabelledby,
|
|
927
|
+
"aria-describedby": ariaDescribedby,
|
|
928
|
+
required,
|
|
929
|
+
onChange: handleChange,
|
|
930
|
+
className: "sr-only"
|
|
931
|
+
}
|
|
932
|
+
);
|
|
933
|
+
const visual = /* @__PURE__ */ jsx(
|
|
934
|
+
RadioVisual,
|
|
935
|
+
{
|
|
936
|
+
isSelected,
|
|
937
|
+
disabled,
|
|
938
|
+
error,
|
|
939
|
+
isHovered,
|
|
940
|
+
prefersReduced
|
|
941
|
+
}
|
|
942
|
+
);
|
|
943
|
+
if (label) {
|
|
944
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
|
|
945
|
+
"label",
|
|
946
|
+
{
|
|
947
|
+
htmlFor: inputId,
|
|
948
|
+
className: cn(
|
|
949
|
+
"inline-flex items-center gap-2 cursor-pointer select-none",
|
|
950
|
+
disabled && "cursor-not-allowed opacity-[0.38] pointer-events-none",
|
|
951
|
+
className
|
|
952
|
+
),
|
|
953
|
+
children: [
|
|
954
|
+
/* @__PURE__ */ jsxs(
|
|
955
|
+
"div",
|
|
956
|
+
{
|
|
957
|
+
className: touchTargetClass,
|
|
958
|
+
onPointerDown,
|
|
959
|
+
onPointerEnter,
|
|
960
|
+
onPointerLeave,
|
|
961
|
+
children: [
|
|
962
|
+
stateLayerAndRipple,
|
|
963
|
+
hiddenInput,
|
|
964
|
+
visual
|
|
965
|
+
]
|
|
966
|
+
}
|
|
967
|
+
),
|
|
968
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm leading-none text-m3-on-surface", children: label })
|
|
969
|
+
]
|
|
970
|
+
}
|
|
971
|
+
) });
|
|
972
|
+
}
|
|
973
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
|
|
974
|
+
"label",
|
|
975
|
+
{
|
|
976
|
+
htmlFor: inputId,
|
|
977
|
+
className: cn(touchTargetClass, className),
|
|
978
|
+
onPointerDown,
|
|
979
|
+
onPointerEnter,
|
|
980
|
+
onPointerLeave,
|
|
981
|
+
children: [
|
|
982
|
+
stateLayerAndRipple,
|
|
983
|
+
hiddenInput,
|
|
984
|
+
visual
|
|
985
|
+
]
|
|
986
|
+
}
|
|
987
|
+
) });
|
|
988
|
+
}
|
|
989
|
+
);
|
|
990
|
+
RadioButtonComponent.displayName = "RadioButton";
|
|
991
|
+
var RadioButton = React4.memo(RadioButtonComponent);
|
|
992
|
+
var RadioGroupComponent = React4.forwardRef(
|
|
993
|
+
({
|
|
994
|
+
name,
|
|
995
|
+
value: valueProp,
|
|
996
|
+
defaultValue,
|
|
997
|
+
onValueChange,
|
|
998
|
+
disabled = false,
|
|
999
|
+
error = false,
|
|
1000
|
+
label,
|
|
1001
|
+
"aria-labelledby": ariaLabelledby,
|
|
1002
|
+
required = false,
|
|
1003
|
+
orientation = "vertical",
|
|
1004
|
+
children,
|
|
1005
|
+
className
|
|
1006
|
+
}, ref) => {
|
|
1007
|
+
const [internalValue, setInternalValue] = React4.useState(defaultValue);
|
|
1008
|
+
const isControlled = valueProp !== void 0;
|
|
1009
|
+
const selectedValue = isControlled ? valueProp : internalValue;
|
|
1010
|
+
const handleValueChange = React4.useCallback(
|
|
1011
|
+
(val) => {
|
|
1012
|
+
if (!isControlled) setInternalValue(val);
|
|
1013
|
+
onValueChange == null ? void 0 : onValueChange(val);
|
|
1014
|
+
},
|
|
1015
|
+
[isControlled, onValueChange]
|
|
1016
|
+
);
|
|
1017
|
+
const groupRef = React4.useRef(null);
|
|
1018
|
+
const mergedRef = useMergedRef2(ref, groupRef);
|
|
1019
|
+
const onKeyDown = React4.useCallback(
|
|
1020
|
+
(e) => {
|
|
1021
|
+
var _a, _b;
|
|
1022
|
+
if (disabled) return;
|
|
1023
|
+
const isNext = e.key === "ArrowDown" || e.key === "ArrowRight";
|
|
1024
|
+
const isPrev = e.key === "ArrowUp" || e.key === "ArrowLeft";
|
|
1025
|
+
if (!isNext && !isPrev) return;
|
|
1026
|
+
e.preventDefault();
|
|
1027
|
+
const inputs = Array.from(
|
|
1028
|
+
(_b = (_a = groupRef.current) == null ? void 0 : _a.querySelectorAll(
|
|
1029
|
+
'input[type="radio"]:not(:disabled)'
|
|
1030
|
+
)) != null ? _b : []
|
|
1031
|
+
);
|
|
1032
|
+
if (inputs.length === 0) return;
|
|
1033
|
+
const currentIdx = inputs.indexOf(
|
|
1034
|
+
document.activeElement
|
|
1035
|
+
);
|
|
1036
|
+
const nextIdx = isNext ? currentIdx < inputs.length - 1 ? currentIdx + 1 : 0 : currentIdx > 0 ? currentIdx - 1 : inputs.length - 1;
|
|
1037
|
+
const target = inputs[nextIdx];
|
|
1038
|
+
target.focus();
|
|
1039
|
+
handleValueChange(target.value);
|
|
1040
|
+
},
|
|
1041
|
+
[disabled, handleValueChange]
|
|
1042
|
+
);
|
|
1043
|
+
const contextValue = React4.useMemo(
|
|
1044
|
+
() => ({
|
|
1045
|
+
name,
|
|
1046
|
+
selectedValue,
|
|
1047
|
+
onValueChange: handleValueChange,
|
|
1048
|
+
disabled,
|
|
1049
|
+
error,
|
|
1050
|
+
required
|
|
1051
|
+
}),
|
|
1052
|
+
[name, selectedValue, handleValueChange, disabled, error, required]
|
|
1053
|
+
);
|
|
1054
|
+
return /* @__PURE__ */ jsx(RadioGroupContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
|
|
1055
|
+
"div",
|
|
1056
|
+
{
|
|
1057
|
+
ref: mergedRef,
|
|
1058
|
+
role: "radiogroup",
|
|
1059
|
+
"aria-label": label && !ariaLabelledby ? label : void 0,
|
|
1060
|
+
"aria-labelledby": ariaLabelledby,
|
|
1061
|
+
"aria-disabled": disabled || void 0,
|
|
1062
|
+
"aria-required": required || void 0,
|
|
1063
|
+
className: cn(
|
|
1064
|
+
"flex",
|
|
1065
|
+
orientation === "horizontal" ? "flex-row gap-4" : "flex-col gap-1",
|
|
1066
|
+
className
|
|
1067
|
+
),
|
|
1068
|
+
onKeyDown,
|
|
1069
|
+
children: [
|
|
1070
|
+
label && !ariaLabelledby && /* @__PURE__ */ jsx("span", { className: "sr-only", children: label }),
|
|
1071
|
+
children
|
|
1072
|
+
]
|
|
1073
|
+
}
|
|
1074
|
+
) });
|
|
1075
|
+
}
|
|
1076
|
+
);
|
|
1077
|
+
RadioGroupComponent.displayName = "RadioGroup";
|
|
1078
|
+
var RadioGroup = React4.memo(RadioGroupComponent);
|
|
1079
|
+
function coerceValue(value, min, max) {
|
|
1080
|
+
return Math.max(min, Math.min(max, value));
|
|
1081
|
+
}
|
|
1082
|
+
function snapToStep(value, min, step) {
|
|
1083
|
+
if (step <= 0) return value;
|
|
1084
|
+
const steps = Math.round((value - min) / step);
|
|
1085
|
+
return Number((min + steps * step).toPrecision(10));
|
|
1086
|
+
}
|
|
1087
|
+
function valueToPercent(value, min, max) {
|
|
1088
|
+
if (max === min) return 0;
|
|
1089
|
+
return (value - min) / (max - min);
|
|
1090
|
+
}
|
|
1091
|
+
function percentToValue(percent, min, max, step) {
|
|
1092
|
+
const raw = min + percent * (max - min);
|
|
1093
|
+
const snapped = snapToStep(raw, min, step);
|
|
1094
|
+
return coerceValue(snapped, min, max);
|
|
1095
|
+
}
|
|
1096
|
+
function getKeyboardDelta(key, step, min, max) {
|
|
1097
|
+
const range = max - min;
|
|
1098
|
+
const discreteStep = step > 0 ? step : range / 100;
|
|
1099
|
+
switch (key) {
|
|
1100
|
+
case "ArrowRight":
|
|
1101
|
+
case "ArrowUp":
|
|
1102
|
+
return discreteStep;
|
|
1103
|
+
case "ArrowLeft":
|
|
1104
|
+
case "ArrowDown":
|
|
1105
|
+
return -discreteStep;
|
|
1106
|
+
case "PageUp":
|
|
1107
|
+
return step > 0 ? snapToStep(range * 0.1, 0, step) : range * 0.1;
|
|
1108
|
+
case "PageDown":
|
|
1109
|
+
return step > 0 ? -snapToStep(range * 0.1, 0, step) : -(range * 0.1);
|
|
1110
|
+
default:
|
|
1111
|
+
return null;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
function generateTicks(min, max, step) {
|
|
1115
|
+
if (step <= 0) return [];
|
|
1116
|
+
const ticks = [];
|
|
1117
|
+
let current = min;
|
|
1118
|
+
while (current <= max) {
|
|
1119
|
+
ticks.push(Number(current.toPrecision(10)));
|
|
1120
|
+
current += step;
|
|
1121
|
+
}
|
|
1122
|
+
if (ticks[ticks.length - 1] !== max) {
|
|
1123
|
+
ticks.push(max);
|
|
1124
|
+
}
|
|
1125
|
+
return ticks;
|
|
1126
|
+
}
|
|
1127
|
+
function useSliderMath({
|
|
1128
|
+
min,
|
|
1129
|
+
max,
|
|
1130
|
+
step
|
|
1131
|
+
}) {
|
|
1132
|
+
return useMemo(
|
|
1133
|
+
() => ({
|
|
1134
|
+
coerce: (v) => coerceValue(v, min, max),
|
|
1135
|
+
snap: (v) => snapToStep(v, min, step),
|
|
1136
|
+
toPercent: (v) => valueToPercent(v, min, max),
|
|
1137
|
+
fromPercent: (pct) => percentToValue(pct, min, max, step),
|
|
1138
|
+
getKeyDelta: (key) => getKeyboardDelta(key, step, min, max),
|
|
1139
|
+
ticks: generateTicks(min, max, step)
|
|
1140
|
+
}),
|
|
1141
|
+
[min, max, step]
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// src/ui/slider/slider.tokens.ts
|
|
1146
|
+
var SliderTokens = {
|
|
1147
|
+
// ── Track sizes (height for horizontal, width for vertical) ────────────────
|
|
1148
|
+
trackSizes: {
|
|
1149
|
+
xs: 16,
|
|
1150
|
+
s: 24,
|
|
1151
|
+
m: 40,
|
|
1152
|
+
l: 56,
|
|
1153
|
+
xl: 96
|
|
1154
|
+
},
|
|
1155
|
+
// ── Track shapes (border radius) ──────────────────────────────────────────
|
|
1156
|
+
trackShapes: {
|
|
1157
|
+
xs: 8,
|
|
1158
|
+
s: 8,
|
|
1159
|
+
m: 12,
|
|
1160
|
+
l: 16,
|
|
1161
|
+
xl: 28
|
|
1162
|
+
},
|
|
1163
|
+
// ── Thumb (handle) ────────────────────────────────────────────────────────
|
|
1164
|
+
/** Thumb height grows with track size */
|
|
1165
|
+
thumbHeights: {
|
|
1166
|
+
xs: 44,
|
|
1167
|
+
s: 44,
|
|
1168
|
+
m: 52,
|
|
1169
|
+
l: 68,
|
|
1170
|
+
xl: 108
|
|
1171
|
+
},
|
|
1172
|
+
/**
|
|
1173
|
+
* Thumb width at rest and on hover.
|
|
1174
|
+
* MD3 Expressive handle pill: 4dp wide.
|
|
1175
|
+
*/
|
|
1176
|
+
thumbWidthDefault: 4,
|
|
1177
|
+
/**
|
|
1178
|
+
* Thumb width while pressed/dragging.
|
|
1179
|
+
* "Squeeze" animation: 4dp → 2dp (M3 Expressive behavior).
|
|
1180
|
+
*/
|
|
1181
|
+
thumbWidthPressed: 2,
|
|
1182
|
+
// ── Track–thumb gap ───────────────────────────────────────────────────────
|
|
1183
|
+
/**
|
|
1184
|
+
* Transparent gap between the active/inactive track segments and the thumb.
|
|
1185
|
+
* Maps to ActiveHandleLeadingSpace / ActiveHandleTrailingSpace = 6dp.
|
|
1186
|
+
*
|
|
1187
|
+
* This gap is rendered by mathematically subtracting it from the track
|
|
1188
|
+
* segment width — NOT using margin/padding.
|
|
1189
|
+
*/
|
|
1190
|
+
thumbGap: 6,
|
|
1191
|
+
// ── Track corner radii ────────────────────────────────────────────────────
|
|
1192
|
+
/**
|
|
1193
|
+
* Corner radius on the INNER ends of each track segment (facing the thumb).
|
|
1194
|
+
* Fixed to 2px according to MD3 Expressive Slider specs (TrackInsideCornerSize).
|
|
1195
|
+
* Outer ends use `trackSize / 2` (pill cap) — computed inline per component.
|
|
1196
|
+
*/
|
|
1197
|
+
trackInnerRadius: 2,
|
|
1198
|
+
// ── Stop indicator / Tick ─────────────────────────────────────────────────
|
|
1199
|
+
/** Tick dot size (width and height). = 4dp. */
|
|
1200
|
+
tickSize: 4,
|
|
1201
|
+
// ── Touch target ─────────────────────────────────────────────────────────
|
|
1202
|
+
/**
|
|
1203
|
+
* Minimum touch target for the thumb wrapper.
|
|
1204
|
+
* MD3 requires 48dp minimum touch target for interactive elements.
|
|
1205
|
+
*/
|
|
1206
|
+
thumbTouchTarget: 48,
|
|
1207
|
+
// ── Value indicator ───────────────────────────────────────────────────────
|
|
1208
|
+
/** Offset above the thumb center for the value indicator tooltip. */
|
|
1209
|
+
valueIndicatorOffset: 52,
|
|
1210
|
+
// ── Inset icon ────────────────────────────────────────────────────────────
|
|
1211
|
+
/** Standard icon size map for inset icons inside the track. */
|
|
1212
|
+
insetIconSizes: {
|
|
1213
|
+
xs: 0,
|
|
1214
|
+
s: 0,
|
|
1215
|
+
m: 24,
|
|
1216
|
+
l: 24,
|
|
1217
|
+
xl: 32
|
|
1218
|
+
},
|
|
1219
|
+
/**
|
|
1220
|
+
* Padding between icon and track edge (horizontal).
|
|
1221
|
+
* Keeps the icon visually centered within the pill track.
|
|
1222
|
+
*/
|
|
1223
|
+
insetIconPadding: 4
|
|
1224
|
+
};
|
|
1225
|
+
var SliderColors = {
|
|
1226
|
+
// ── Track ─────────────────────────────────────────────────────────────────
|
|
1227
|
+
/** Active track color. Maps to ActiveTrackColor token. */
|
|
1228
|
+
activeTrack: "var(--md-sys-color-primary)",
|
|
1229
|
+
/** Inactive track color. Maps to InactiveTrackColor token. */
|
|
1230
|
+
inactiveTrack: "var(--md-sys-color-secondary-container)",
|
|
1231
|
+
/**
|
|
1232
|
+
* Disabled track color.
|
|
1233
|
+
* Uses opacity + on-surface per MD3 disabled state spec.
|
|
1234
|
+
*/
|
|
1235
|
+
disabledActiveTrack: "var(--md-sys-color-on-surface)",
|
|
1236
|
+
disabledInactiveTrack: "var(--md-sys-color-on-surface)",
|
|
1237
|
+
// ── Thumb ─────────────────────────────────────────────────────────────────
|
|
1238
|
+
/** Thumb (handle) color. Maps to HandleColor token. */
|
|
1239
|
+
thumb: "var(--md-sys-color-primary)",
|
|
1240
|
+
/** Disabled thumb color. */
|
|
1241
|
+
disabledThumb: "var(--md-sys-color-on-surface)",
|
|
1242
|
+
// ── Value indicator ───────────────────────────────────────────────────────
|
|
1243
|
+
/** Value indicator (tooltip) background. Maps to InverseSurface. */
|
|
1244
|
+
valueIndicatorBg: "var(--md-sys-color-inverse-surface)",
|
|
1245
|
+
/** Value indicator (tooltip) text. Maps to InverseOnSurface. */
|
|
1246
|
+
valueIndicatorText: "var(--md-sys-color-inverse-on-surface)",
|
|
1247
|
+
// ── Ticks ────────────────────────────────────────────────────────────────
|
|
1248
|
+
/**
|
|
1249
|
+
* Tick on the INACTIVE portion of the track.
|
|
1250
|
+
* Maps to TickMarkActiveContainerColor (in spec: primary color stands out).
|
|
1251
|
+
*/
|
|
1252
|
+
tickOnInactive: "var(--md-sys-color-primary)",
|
|
1253
|
+
/**
|
|
1254
|
+
* Tick on the ACTIVE portion of the track.
|
|
1255
|
+
* Maps to TickMarkInactiveContainerColor (secondary-container blends in).
|
|
1256
|
+
*/
|
|
1257
|
+
tickOnActive: "var(--md-sys-color-secondary-container)",
|
|
1258
|
+
disabledTick: "var(--md-sys-color-on-surface)"
|
|
1259
|
+
};
|
|
1260
|
+
var SLIDER_THUMB_SPRING = {
|
|
1261
|
+
type: "spring",
|
|
1262
|
+
stiffness: 500,
|
|
1263
|
+
damping: 40
|
|
1264
|
+
};
|
|
1265
|
+
var SLIDER_INDICATOR_TRANSITION = {
|
|
1266
|
+
type: "spring",
|
|
1267
|
+
stiffness: 450,
|
|
1268
|
+
damping: 32
|
|
1269
|
+
};
|
|
1270
|
+
var ValueIndicator = React4.memo(function ValueIndicator2({
|
|
1271
|
+
value,
|
|
1272
|
+
visible,
|
|
1273
|
+
orientation,
|
|
1274
|
+
formatValue,
|
|
1275
|
+
prefersReduced,
|
|
1276
|
+
trackSize
|
|
1277
|
+
}) {
|
|
1278
|
+
const label = formatValue ? formatValue(value) : String(Math.round(value));
|
|
1279
|
+
const isHorizontal = orientation === "horizontal";
|
|
1280
|
+
const thumbHeight = SliderTokens.thumbHeights[trackSize];
|
|
1281
|
+
const offsetFromCenter = thumbHeight / 2 + 8;
|
|
1282
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: visible && /* @__PURE__ */ jsx(
|
|
1283
|
+
m.div,
|
|
1284
|
+
{
|
|
1285
|
+
role: "tooltip",
|
|
1286
|
+
"aria-hidden": "true",
|
|
1287
|
+
initial: prefersReduced ? false : {
|
|
1288
|
+
scale: 0,
|
|
1289
|
+
opacity: 0,
|
|
1290
|
+
y: isHorizontal ? 6 : 0,
|
|
1291
|
+
x: !isHorizontal ? -6 : 0
|
|
1292
|
+
},
|
|
1293
|
+
animate: { scale: 1, opacity: 1, y: 0, x: 0 },
|
|
1294
|
+
exit: prefersReduced ? {} : {
|
|
1295
|
+
scale: 0,
|
|
1296
|
+
opacity: 0,
|
|
1297
|
+
y: isHorizontal ? 6 : 0,
|
|
1298
|
+
x: !isHorizontal ? -6 : 0
|
|
1299
|
+
},
|
|
1300
|
+
transition: prefersReduced ? { duration: 0 } : SLIDER_INDICATOR_TRANSITION,
|
|
1301
|
+
className: cn(
|
|
1302
|
+
"absolute pointer-events-none select-none",
|
|
1303
|
+
"rounded-full px-2.5 py-1 text-xs font-medium leading-none whitespace-nowrap",
|
|
1304
|
+
// Position: above for horizontal, right for vertical
|
|
1305
|
+
isHorizontal ? "-translate-x-1/2 left-1/2" : "translate-y-1/2 bottom-1/2"
|
|
1306
|
+
),
|
|
1307
|
+
style: __spreadValues({
|
|
1308
|
+
backgroundColor: SliderColors.valueIndicatorBg,
|
|
1309
|
+
color: SliderColors.valueIndicatorText,
|
|
1310
|
+
transformOrigin: isHorizontal ? "bottom center" : "center left"
|
|
1311
|
+
}, isHorizontal ? { bottom: `calc(50% + ${offsetFromCenter}px)` } : { left: `calc(50% + ${offsetFromCenter}px)` }),
|
|
1312
|
+
children: label
|
|
1313
|
+
},
|
|
1314
|
+
"value-indicator"
|
|
1315
|
+
) });
|
|
1316
|
+
});
|
|
1317
|
+
var SliderThumb = React4.memo(function SliderThumb2({
|
|
1318
|
+
value,
|
|
1319
|
+
percent,
|
|
1320
|
+
min,
|
|
1321
|
+
max,
|
|
1322
|
+
step,
|
|
1323
|
+
disabled,
|
|
1324
|
+
orientation,
|
|
1325
|
+
showValueIndicator,
|
|
1326
|
+
trackRef,
|
|
1327
|
+
onValueChange,
|
|
1328
|
+
onValueChangeEnd,
|
|
1329
|
+
formatValue,
|
|
1330
|
+
thumbId,
|
|
1331
|
+
trackSize,
|
|
1332
|
+
variant,
|
|
1333
|
+
zIndex = 1,
|
|
1334
|
+
"aria-label": ariaLabel,
|
|
1335
|
+
"aria-labelledby": ariaLabelledBy
|
|
1336
|
+
}) {
|
|
1337
|
+
var _a;
|
|
1338
|
+
const isHorizontal = orientation === "horizontal";
|
|
1339
|
+
const insetLimit = SliderTokens.thumbGap + SliderTokens.thumbWidthDefault / 2;
|
|
1340
|
+
const trackInset = Math.min(
|
|
1341
|
+
SliderTokens.trackSizes[trackSize] / 2,
|
|
1342
|
+
insetLimit
|
|
1343
|
+
);
|
|
1344
|
+
const posTarget = isHorizontal ? "left" : "bottom";
|
|
1345
|
+
const motionStyle = {
|
|
1346
|
+
[posTarget]: `calc(${trackInset}px + ${percent} * (100% - ${trackInset * 2}px))`
|
|
1347
|
+
};
|
|
1348
|
+
const prefersReduced = (_a = useReducedMotion()) != null ? _a : false;
|
|
1349
|
+
const [isDragging, setIsDragging] = React4.useState(false);
|
|
1350
|
+
const [isHovered, setIsHovered] = React4.useState(false);
|
|
1351
|
+
const [isFocused, setIsFocused] = React4.useState(false);
|
|
1352
|
+
const pointerIdRef = React4.useRef(null);
|
|
1353
|
+
const thumbRef = React4.useRef(null);
|
|
1354
|
+
const showIndicator = showValueIndicator && (isDragging || isHovered || isFocused);
|
|
1355
|
+
const positionStyle = isHorizontal ? __spreadProps(__spreadValues({
|
|
1356
|
+
position: "absolute"
|
|
1357
|
+
}, motionStyle), {
|
|
1358
|
+
top: "50%",
|
|
1359
|
+
transform: "translate(-50%, -50%)",
|
|
1360
|
+
zIndex
|
|
1361
|
+
}) : __spreadProps(__spreadValues({
|
|
1362
|
+
position: "absolute"
|
|
1363
|
+
}, motionStyle), {
|
|
1364
|
+
left: "50%",
|
|
1365
|
+
transform: "translate(-50%, 50%)",
|
|
1366
|
+
zIndex
|
|
1367
|
+
});
|
|
1368
|
+
const getDeltaFromPointer = React4.useCallback(
|
|
1369
|
+
(e) => {
|
|
1370
|
+
const trackEl = trackRef.current;
|
|
1371
|
+
if (!trackEl) return percent;
|
|
1372
|
+
const rect = trackEl.getBoundingClientRect();
|
|
1373
|
+
const space = isHorizontal ? rect.width : rect.height;
|
|
1374
|
+
const insetLimit2 = SliderTokens.thumbGap + SliderTokens.thumbWidthDefault / 2;
|
|
1375
|
+
const trackInset2 = Math.min(
|
|
1376
|
+
SliderTokens.trackSizes[trackSize] / 2,
|
|
1377
|
+
insetLimit2
|
|
1378
|
+
);
|
|
1379
|
+
const safeSpace = space - trackInset2 * 2;
|
|
1380
|
+
if (safeSpace <= 0) return percent;
|
|
1381
|
+
let rawPercent;
|
|
1382
|
+
if (isHorizontal) {
|
|
1383
|
+
rawPercent = (e.clientX - rect.left - trackInset2) / safeSpace;
|
|
1384
|
+
} else {
|
|
1385
|
+
rawPercent = (rect.bottom - e.clientY - trackInset2) / safeSpace;
|
|
1386
|
+
}
|
|
1387
|
+
const clamped = Math.max(0, Math.min(1, rawPercent));
|
|
1388
|
+
const range = max - min;
|
|
1389
|
+
const rawValue = min + clamped * range;
|
|
1390
|
+
const snapped = step > 0 ? Math.round((rawValue - min) / step) * step + min : rawValue;
|
|
1391
|
+
return Math.max(min, Math.min(max, snapped));
|
|
1392
|
+
},
|
|
1393
|
+
[isHorizontal, max, min, percent, step, trackRef, trackSize]
|
|
1394
|
+
);
|
|
1395
|
+
const handlePointerDown = React4.useCallback(
|
|
1396
|
+
(e) => {
|
|
1397
|
+
if (disabled) return;
|
|
1398
|
+
e.preventDefault();
|
|
1399
|
+
e.stopPropagation();
|
|
1400
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1401
|
+
pointerIdRef.current = e.pointerId;
|
|
1402
|
+
setIsDragging(true);
|
|
1403
|
+
},
|
|
1404
|
+
[disabled]
|
|
1405
|
+
);
|
|
1406
|
+
const handlePointerMove = React4.useCallback(
|
|
1407
|
+
(e) => {
|
|
1408
|
+
if (!isDragging || e.pointerId !== pointerIdRef.current) return;
|
|
1409
|
+
const newValue = getDeltaFromPointer(e.nativeEvent);
|
|
1410
|
+
onValueChange(newValue);
|
|
1411
|
+
},
|
|
1412
|
+
[isDragging, getDeltaFromPointer, onValueChange]
|
|
1413
|
+
);
|
|
1414
|
+
const handlePointerUp = React4.useCallback(
|
|
1415
|
+
(e) => {
|
|
1416
|
+
if (e.pointerId !== pointerIdRef.current) return;
|
|
1417
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
1418
|
+
pointerIdRef.current = null;
|
|
1419
|
+
setIsDragging(false);
|
|
1420
|
+
onValueChangeEnd == null ? void 0 : onValueChangeEnd(value);
|
|
1421
|
+
},
|
|
1422
|
+
[onValueChangeEnd, value]
|
|
1423
|
+
);
|
|
1424
|
+
const handleKeyDown = React4.useCallback(
|
|
1425
|
+
(e) => {
|
|
1426
|
+
if (disabled) return;
|
|
1427
|
+
if (e.key === "Home") {
|
|
1428
|
+
e.preventDefault();
|
|
1429
|
+
onValueChange(min);
|
|
1430
|
+
onValueChangeEnd == null ? void 0 : onValueChangeEnd(min);
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
if (e.key === "End") {
|
|
1434
|
+
e.preventDefault();
|
|
1435
|
+
onValueChange(max);
|
|
1436
|
+
onValueChangeEnd == null ? void 0 : onValueChangeEnd(max);
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
const delta = getKeyboardDelta(e.key, step, min, max);
|
|
1440
|
+
if (delta === null) return;
|
|
1441
|
+
e.preventDefault();
|
|
1442
|
+
const newValue = Math.max(min, Math.min(max, value + delta));
|
|
1443
|
+
onValueChange(newValue);
|
|
1444
|
+
onValueChangeEnd == null ? void 0 : onValueChangeEnd(newValue);
|
|
1445
|
+
},
|
|
1446
|
+
[disabled, max, min, onValueChange, onValueChangeEnd, step, value]
|
|
1447
|
+
);
|
|
1448
|
+
const thumbColor = disabled ? SliderColors.disabledThumb : `var(--md-sys-color-${variant})`;
|
|
1449
|
+
const squeezeSize = isDragging ? SliderTokens.thumbWidthPressed : SliderTokens.thumbWidthDefault;
|
|
1450
|
+
return /* @__PURE__ */ jsxs(
|
|
1451
|
+
"div",
|
|
1452
|
+
{
|
|
1453
|
+
style: __spreadProps(__spreadValues({}, positionStyle), {
|
|
1454
|
+
width: SliderTokens.thumbTouchTarget,
|
|
1455
|
+
height: SliderTokens.thumbTouchTarget,
|
|
1456
|
+
display: "flex",
|
|
1457
|
+
alignItems: "center",
|
|
1458
|
+
justifyContent: "center",
|
|
1459
|
+
touchAction: "none"
|
|
1460
|
+
}),
|
|
1461
|
+
className: cn(
|
|
1462
|
+
"cursor-grab",
|
|
1463
|
+
isDragging && "cursor-grabbing",
|
|
1464
|
+
disabled && "cursor-not-allowed"
|
|
1465
|
+
),
|
|
1466
|
+
onPointerDown: handlePointerDown,
|
|
1467
|
+
onPointerMove: handlePointerMove,
|
|
1468
|
+
onPointerUp: handlePointerUp,
|
|
1469
|
+
onPointerCancel: handlePointerUp,
|
|
1470
|
+
children: [
|
|
1471
|
+
/* @__PURE__ */ jsx(
|
|
1472
|
+
ValueIndicator,
|
|
1473
|
+
{
|
|
1474
|
+
value,
|
|
1475
|
+
visible: showIndicator,
|
|
1476
|
+
orientation,
|
|
1477
|
+
formatValue,
|
|
1478
|
+
prefersReduced,
|
|
1479
|
+
trackSize
|
|
1480
|
+
}
|
|
1481
|
+
),
|
|
1482
|
+
/* @__PURE__ */ jsx(
|
|
1483
|
+
m.div,
|
|
1484
|
+
{
|
|
1485
|
+
ref: thumbRef,
|
|
1486
|
+
id: thumbId,
|
|
1487
|
+
role: "slider",
|
|
1488
|
+
"aria-valuemin": min,
|
|
1489
|
+
"aria-valuemax": max,
|
|
1490
|
+
"aria-valuenow": value,
|
|
1491
|
+
"aria-orientation": orientation,
|
|
1492
|
+
"aria-disabled": disabled || void 0,
|
|
1493
|
+
"aria-label": ariaLabel,
|
|
1494
|
+
"aria-labelledby": ariaLabelledBy,
|
|
1495
|
+
tabIndex: disabled ? -1 : 0,
|
|
1496
|
+
onKeyDown: handleKeyDown,
|
|
1497
|
+
onFocus: () => setIsFocused(true),
|
|
1498
|
+
onBlur: () => setIsFocused(false),
|
|
1499
|
+
onMouseEnter: () => !disabled && setIsHovered(true),
|
|
1500
|
+
onMouseLeave: () => setIsHovered(false),
|
|
1501
|
+
animate: __spreadProps(__spreadValues({}, isHorizontal ? { width: squeezeSize } : { height: squeezeSize }), {
|
|
1502
|
+
backgroundColor: thumbColor,
|
|
1503
|
+
opacity: disabled ? 0.38 : 1
|
|
1504
|
+
}),
|
|
1505
|
+
transition: prefersReduced ? { duration: 0 } : SLIDER_THUMB_SPRING,
|
|
1506
|
+
className: cn(
|
|
1507
|
+
"relative shrink-0 rounded-full select-none outline-none",
|
|
1508
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
1509
|
+
"focus-visible:outline-(--md-sys-color-secondary)"
|
|
1510
|
+
),
|
|
1511
|
+
style: __spreadProps(__spreadValues({}, isHorizontal ? {
|
|
1512
|
+
height: SliderTokens.thumbHeights[trackSize],
|
|
1513
|
+
width: SliderTokens.thumbWidthDefault,
|
|
1514
|
+
willChange: "width"
|
|
1515
|
+
} : {
|
|
1516
|
+
width: SliderTokens.thumbHeights[trackSize],
|
|
1517
|
+
height: SliderTokens.thumbWidthDefault,
|
|
1518
|
+
willChange: "height"
|
|
1519
|
+
}), {
|
|
1520
|
+
backgroundColor: thumbColor
|
|
1521
|
+
})
|
|
1522
|
+
}
|
|
1523
|
+
)
|
|
1524
|
+
]
|
|
1525
|
+
}
|
|
1526
|
+
);
|
|
1527
|
+
});
|
|
1528
|
+
var RangeTrack = React4.memo(function RangeTrack2({
|
|
1529
|
+
startPercent,
|
|
1530
|
+
endPercent,
|
|
1531
|
+
trackSize,
|
|
1532
|
+
orientation,
|
|
1533
|
+
variant,
|
|
1534
|
+
disabled,
|
|
1535
|
+
ticks,
|
|
1536
|
+
min,
|
|
1537
|
+
max,
|
|
1538
|
+
trackShape = "md3",
|
|
1539
|
+
trackRef,
|
|
1540
|
+
onTrackPointerDown
|
|
1541
|
+
}) {
|
|
1542
|
+
const isHorizontal = orientation === "horizontal";
|
|
1543
|
+
const size = SliderTokens.trackSizes[trackSize];
|
|
1544
|
+
const thumbHeight = SliderTokens.thumbHeights[trackSize];
|
|
1545
|
+
const { thumbGap, thumbWidthDefault, tickSize } = SliderTokens;
|
|
1546
|
+
const thumbHalfWidth = thumbWidthDefault / 2;
|
|
1547
|
+
const activeTrack = disabled ? SliderColors.disabledActiveTrack : `var(--md-sys-color-${variant})`;
|
|
1548
|
+
const inactiveTrack = disabled ? SliderColors.disabledInactiveTrack : `var(--md-sys-color-${variant}-container)`;
|
|
1549
|
+
const innerR = SliderTokens.trackInnerRadius;
|
|
1550
|
+
let outerR = size / 2;
|
|
1551
|
+
if (trackShape === "md3") {
|
|
1552
|
+
outerR = Math.min(SliderTokens.trackShapes[trackSize], size / 2);
|
|
1553
|
+
} else if (typeof trackShape === "number") {
|
|
1554
|
+
outerR = Math.min(trackShape, size / 2);
|
|
1555
|
+
}
|
|
1556
|
+
if (isHorizontal) {
|
|
1557
|
+
const insetLimit2 = thumbGap + thumbWidthDefault / 2;
|
|
1558
|
+
const trackInset2 = Math.min(size / 2, insetLimit2);
|
|
1559
|
+
const cxStart = `calc(${trackInset2}px + ${startPercent} * (100% - ${trackInset2 * 2}px))`;
|
|
1560
|
+
const cxEnd = `calc(${trackInset2}px + ${endPercent} * (100% - ${trackInset2 * 2}px))`;
|
|
1561
|
+
const gapWithThumbStr2 = `${thumbGap + thumbHalfWidth}px`;
|
|
1562
|
+
const leadingWidth = `max(0px, calc(${cxStart} - ${gapWithThumbStr2}))`;
|
|
1563
|
+
const activeLeft = `calc(${cxStart} + ${gapWithThumbStr2})`;
|
|
1564
|
+
const activeWidth = `max(0px, calc(${cxEnd} - ${cxStart} - ${gapWithThumbStr2} * 2))`;
|
|
1565
|
+
const trailingLeft = `calc(${cxEnd} + ${gapWithThumbStr2})`;
|
|
1566
|
+
const trailingWidth = `max(0px, calc(100% - (${cxEnd} + ${gapWithThumbStr2})))`;
|
|
1567
|
+
return /* @__PURE__ */ jsxs(
|
|
1568
|
+
"div",
|
|
1569
|
+
{
|
|
1570
|
+
ref: trackRef,
|
|
1571
|
+
className: cn(
|
|
1572
|
+
"relative w-full",
|
|
1573
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
1574
|
+
),
|
|
1575
|
+
style: { height: thumbHeight },
|
|
1576
|
+
onPointerDown: onTrackPointerDown,
|
|
1577
|
+
"aria-hidden": "true",
|
|
1578
|
+
children: [
|
|
1579
|
+
/* @__PURE__ */ jsx(
|
|
1580
|
+
"div",
|
|
1581
|
+
{
|
|
1582
|
+
"aria-hidden": "true",
|
|
1583
|
+
style: {
|
|
1584
|
+
position: "absolute",
|
|
1585
|
+
left: 0,
|
|
1586
|
+
top: "50%",
|
|
1587
|
+
transform: "translateY(-50%)",
|
|
1588
|
+
width: leadingWidth,
|
|
1589
|
+
height: size,
|
|
1590
|
+
backgroundColor: inactiveTrack,
|
|
1591
|
+
opacity: disabled ? 0.38 : 1,
|
|
1592
|
+
borderTopLeftRadius: outerR,
|
|
1593
|
+
borderBottomLeftRadius: outerR,
|
|
1594
|
+
borderTopRightRadius: innerR,
|
|
1595
|
+
borderBottomRightRadius: innerR
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
),
|
|
1599
|
+
/* @__PURE__ */ jsx(
|
|
1600
|
+
"div",
|
|
1601
|
+
{
|
|
1602
|
+
"aria-hidden": "true",
|
|
1603
|
+
style: {
|
|
1604
|
+
position: "absolute",
|
|
1605
|
+
left: activeLeft,
|
|
1606
|
+
top: "50%",
|
|
1607
|
+
transform: "translateY(-50%)",
|
|
1608
|
+
width: activeWidth,
|
|
1609
|
+
height: size,
|
|
1610
|
+
backgroundColor: activeTrack,
|
|
1611
|
+
opacity: disabled ? 0.38 : 1,
|
|
1612
|
+
borderTopLeftRadius: startPercent <= 0 ? outerR : innerR,
|
|
1613
|
+
borderBottomLeftRadius: startPercent <= 0 ? outerR : innerR,
|
|
1614
|
+
borderTopRightRadius: endPercent >= 1 ? outerR : innerR,
|
|
1615
|
+
borderBottomRightRadius: endPercent >= 1 ? outerR : innerR
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
),
|
|
1619
|
+
/* @__PURE__ */ jsx(
|
|
1620
|
+
"div",
|
|
1621
|
+
{
|
|
1622
|
+
"aria-hidden": "true",
|
|
1623
|
+
style: {
|
|
1624
|
+
position: "absolute",
|
|
1625
|
+
left: trailingLeft,
|
|
1626
|
+
top: "50%",
|
|
1627
|
+
transform: "translateY(-50%)",
|
|
1628
|
+
width: trailingWidth,
|
|
1629
|
+
height: size,
|
|
1630
|
+
backgroundColor: inactiveTrack,
|
|
1631
|
+
opacity: disabled ? 0.38 : 1,
|
|
1632
|
+
borderTopLeftRadius: innerR,
|
|
1633
|
+
borderBottomLeftRadius: innerR,
|
|
1634
|
+
borderTopRightRadius: outerR,
|
|
1635
|
+
borderBottomRightRadius: outerR
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
),
|
|
1639
|
+
ticks.map((tick) => {
|
|
1640
|
+
const tickPct = (tick - min) / (max - min);
|
|
1641
|
+
const isActive = tickPct > startPercent && tickPct < endPercent;
|
|
1642
|
+
return /* @__PURE__ */ jsx(
|
|
1643
|
+
"div",
|
|
1644
|
+
{
|
|
1645
|
+
"aria-hidden": "true",
|
|
1646
|
+
style: {
|
|
1647
|
+
position: "absolute",
|
|
1648
|
+
width: tickSize,
|
|
1649
|
+
height: tickSize,
|
|
1650
|
+
borderRadius: "50%",
|
|
1651
|
+
backgroundColor: disabled ? SliderColors.disabledTick : isActive ? `var(--md-sys-color-${variant}-container)` : `var(--md-sys-color-${variant})`,
|
|
1652
|
+
opacity: disabled ? 0.38 : 1,
|
|
1653
|
+
left: `calc(${trackInset2}px + ${tickPct} * (100% - ${trackInset2 * 2}px) - ${tickSize / 2}px)`,
|
|
1654
|
+
top: "50%",
|
|
1655
|
+
transform: "translateY(-50%)"
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
tick
|
|
1659
|
+
);
|
|
1660
|
+
})
|
|
1661
|
+
]
|
|
1662
|
+
}
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
const insetLimit = thumbGap + thumbWidthDefault / 2;
|
|
1666
|
+
const trackInset = Math.min(size / 2, insetLimit);
|
|
1667
|
+
const cyStart = `calc(${trackInset}px + ${startPercent} * (100% - ${trackInset * 2}px))`;
|
|
1668
|
+
const cyEnd = `calc(${trackInset}px + ${endPercent} * (100% - ${trackInset * 2}px))`;
|
|
1669
|
+
const gapWithThumbStr = `${thumbGap + thumbHalfWidth}px`;
|
|
1670
|
+
const leadingHeight = `max(0px, calc(${cyStart} - ${gapWithThumbStr}))`;
|
|
1671
|
+
const activeBottom = `calc(${cyStart} + ${gapWithThumbStr})`;
|
|
1672
|
+
const activeHeight = `max(0px, calc(${cyEnd} - ${cyStart} - ${gapWithThumbStr} * 2))`;
|
|
1673
|
+
const trailingBottom = `calc(${cyEnd} + ${gapWithThumbStr})`;
|
|
1674
|
+
const trailingHeight = `max(0px, calc(100% - (${cyEnd} + ${gapWithThumbStr})))`;
|
|
1675
|
+
return /* @__PURE__ */ jsxs(
|
|
1676
|
+
"div",
|
|
1677
|
+
{
|
|
1678
|
+
ref: trackRef,
|
|
1679
|
+
className: cn(
|
|
1680
|
+
"relative h-full",
|
|
1681
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
1682
|
+
),
|
|
1683
|
+
style: { width: thumbHeight },
|
|
1684
|
+
onPointerDown: onTrackPointerDown,
|
|
1685
|
+
"aria-hidden": "true",
|
|
1686
|
+
children: [
|
|
1687
|
+
/* @__PURE__ */ jsx(
|
|
1688
|
+
"div",
|
|
1689
|
+
{
|
|
1690
|
+
"aria-hidden": "true",
|
|
1691
|
+
style: {
|
|
1692
|
+
position: "absolute",
|
|
1693
|
+
bottom: 0,
|
|
1694
|
+
left: "50%",
|
|
1695
|
+
transform: "translateX(-50%)",
|
|
1696
|
+
height: leadingHeight,
|
|
1697
|
+
width: size,
|
|
1698
|
+
backgroundColor: inactiveTrack,
|
|
1699
|
+
opacity: disabled ? 0.38 : 1,
|
|
1700
|
+
borderBottomLeftRadius: outerR,
|
|
1701
|
+
borderBottomRightRadius: outerR,
|
|
1702
|
+
borderTopLeftRadius: innerR,
|
|
1703
|
+
borderTopRightRadius: innerR
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
),
|
|
1707
|
+
/* @__PURE__ */ jsx(
|
|
1708
|
+
"div",
|
|
1709
|
+
{
|
|
1710
|
+
"aria-hidden": "true",
|
|
1711
|
+
style: {
|
|
1712
|
+
position: "absolute",
|
|
1713
|
+
bottom: activeBottom,
|
|
1714
|
+
left: "50%",
|
|
1715
|
+
transform: "translateX(-50%)",
|
|
1716
|
+
height: activeHeight,
|
|
1717
|
+
width: size,
|
|
1718
|
+
backgroundColor: activeTrack,
|
|
1719
|
+
opacity: disabled ? 0.38 : 1,
|
|
1720
|
+
borderBottomLeftRadius: startPercent <= 0 ? outerR : innerR,
|
|
1721
|
+
borderBottomRightRadius: startPercent <= 0 ? outerR : innerR,
|
|
1722
|
+
borderTopLeftRadius: endPercent >= 1 ? outerR : innerR,
|
|
1723
|
+
borderTopRightRadius: endPercent >= 1 ? outerR : innerR
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
),
|
|
1727
|
+
/* @__PURE__ */ jsx(
|
|
1728
|
+
"div",
|
|
1729
|
+
{
|
|
1730
|
+
"aria-hidden": "true",
|
|
1731
|
+
style: {
|
|
1732
|
+
position: "absolute",
|
|
1733
|
+
bottom: trailingBottom,
|
|
1734
|
+
left: "50%",
|
|
1735
|
+
transform: "translateX(-50%)",
|
|
1736
|
+
height: trailingHeight,
|
|
1737
|
+
width: size,
|
|
1738
|
+
backgroundColor: inactiveTrack,
|
|
1739
|
+
opacity: disabled ? 0.38 : 1,
|
|
1740
|
+
borderTopLeftRadius: outerR,
|
|
1741
|
+
borderTopRightRadius: outerR,
|
|
1742
|
+
borderBottomLeftRadius: innerR,
|
|
1743
|
+
borderBottomRightRadius: innerR
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
),
|
|
1747
|
+
ticks.map((tick) => {
|
|
1748
|
+
const tickPct = (tick - min) / (max - min);
|
|
1749
|
+
const isActive = tickPct > startPercent && tickPct < endPercent;
|
|
1750
|
+
return /* @__PURE__ */ jsx(
|
|
1751
|
+
"div",
|
|
1752
|
+
{
|
|
1753
|
+
"aria-hidden": "true",
|
|
1754
|
+
style: {
|
|
1755
|
+
position: "absolute",
|
|
1756
|
+
width: tickSize,
|
|
1757
|
+
height: tickSize,
|
|
1758
|
+
borderRadius: "50%",
|
|
1759
|
+
backgroundColor: disabled ? SliderColors.disabledTick : isActive ? `var(--md-sys-color-${variant}-container)` : `var(--md-sys-color-${variant})`,
|
|
1760
|
+
opacity: disabled ? 0.38 : 1,
|
|
1761
|
+
bottom: `calc(${trackInset}px + ${tickPct} * (100% - ${trackInset * 2}px) - ${tickSize / 2}px)`,
|
|
1762
|
+
left: "50%",
|
|
1763
|
+
transform: "translateX(-50%)"
|
|
1764
|
+
}
|
|
1765
|
+
},
|
|
1766
|
+
tick
|
|
1767
|
+
);
|
|
1768
|
+
})
|
|
1769
|
+
]
|
|
1770
|
+
}
|
|
1771
|
+
);
|
|
1772
|
+
});
|
|
1773
|
+
var RangeSliderComponent = React4.forwardRef(
|
|
1774
|
+
({
|
|
1775
|
+
value: controlledValue,
|
|
1776
|
+
defaultValue,
|
|
1777
|
+
onValueChange,
|
|
1778
|
+
onValueChangeEnd,
|
|
1779
|
+
min = 0,
|
|
1780
|
+
max = 100,
|
|
1781
|
+
step = 0,
|
|
1782
|
+
orientation = "horizontal",
|
|
1783
|
+
trackSize = "m",
|
|
1784
|
+
trackShape = "md3",
|
|
1785
|
+
variant = "primary",
|
|
1786
|
+
disabled = false,
|
|
1787
|
+
showValueIndicator = false,
|
|
1788
|
+
showTicks = false,
|
|
1789
|
+
formatValue,
|
|
1790
|
+
className,
|
|
1791
|
+
"aria-label": ariaLabel
|
|
1792
|
+
}, ref) => {
|
|
1793
|
+
var _a, _b;
|
|
1794
|
+
const isHorizontal = orientation === "horizontal";
|
|
1795
|
+
const defaultStart = (_a = defaultValue == null ? void 0 : defaultValue[0]) != null ? _a : min;
|
|
1796
|
+
const defaultEnd = (_b = defaultValue == null ? void 0 : defaultValue[1]) != null ? _b : max;
|
|
1797
|
+
const [internalValue, setInternalValue] = React4.useState([
|
|
1798
|
+
defaultStart,
|
|
1799
|
+
defaultEnd
|
|
1800
|
+
]);
|
|
1801
|
+
const resolvedValue = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
1802
|
+
const { coerce, snap, toPercent, ticks } = useSliderMath({
|
|
1803
|
+
min,
|
|
1804
|
+
max,
|
|
1805
|
+
step
|
|
1806
|
+
});
|
|
1807
|
+
const startValue = snap(coerce(resolvedValue[0]));
|
|
1808
|
+
const endValue = snap(coerce(resolvedValue[1]));
|
|
1809
|
+
const startPercent = toPercent(startValue);
|
|
1810
|
+
const endPercent = toPercent(endValue);
|
|
1811
|
+
const [topThumb, setTopThumb] = React4.useState("end");
|
|
1812
|
+
const trackRef = React4.useRef(null);
|
|
1813
|
+
const minGap = step > 0 ? step : (max - min) / 1e3;
|
|
1814
|
+
const handleStartChange = React4.useCallback(
|
|
1815
|
+
(newStart) => {
|
|
1816
|
+
setTopThumb("start");
|
|
1817
|
+
const clamped = Math.min(newStart, endValue - minGap);
|
|
1818
|
+
const final = snap(coerce(clamped));
|
|
1819
|
+
if (controlledValue === void 0) {
|
|
1820
|
+
setInternalValue([final, endValue]);
|
|
1821
|
+
}
|
|
1822
|
+
onValueChange == null ? void 0 : onValueChange([final, endValue]);
|
|
1823
|
+
},
|
|
1824
|
+
[controlledValue, coerce, endValue, minGap, onValueChange, snap]
|
|
1825
|
+
);
|
|
1826
|
+
const handleEndChange = React4.useCallback(
|
|
1827
|
+
(newEnd) => {
|
|
1828
|
+
setTopThumb("end");
|
|
1829
|
+
const clamped = Math.max(newEnd, startValue + minGap);
|
|
1830
|
+
const final = snap(coerce(clamped));
|
|
1831
|
+
if (controlledValue === void 0) {
|
|
1832
|
+
setInternalValue([startValue, final]);
|
|
1833
|
+
}
|
|
1834
|
+
onValueChange == null ? void 0 : onValueChange([startValue, final]);
|
|
1835
|
+
},
|
|
1836
|
+
[controlledValue, coerce, minGap, onValueChange, snap, startValue]
|
|
1837
|
+
);
|
|
1838
|
+
const handleStartChangeEnd = React4.useCallback(
|
|
1839
|
+
(v) => onValueChangeEnd == null ? void 0 : onValueChangeEnd([v, endValue]),
|
|
1840
|
+
[endValue, onValueChangeEnd]
|
|
1841
|
+
);
|
|
1842
|
+
const handleEndChangeEnd = React4.useCallback(
|
|
1843
|
+
(v) => onValueChangeEnd == null ? void 0 : onValueChangeEnd([startValue, v]),
|
|
1844
|
+
[onValueChangeEnd, startValue]
|
|
1845
|
+
);
|
|
1846
|
+
const handleTrackPointerDown = React4.useCallback(
|
|
1847
|
+
(e) => {
|
|
1848
|
+
if (disabled) return;
|
|
1849
|
+
const trackEl = trackRef.current;
|
|
1850
|
+
if (!trackEl) return;
|
|
1851
|
+
const rect = trackEl.getBoundingClientRect();
|
|
1852
|
+
let clickPercent;
|
|
1853
|
+
const insetLimit = SliderTokens.thumbGap + SliderTokens.thumbWidthDefault / 2;
|
|
1854
|
+
const trackInset = Math.min(
|
|
1855
|
+
SliderTokens.trackSizes[trackSize] / 2,
|
|
1856
|
+
insetLimit
|
|
1857
|
+
);
|
|
1858
|
+
if (isHorizontal) {
|
|
1859
|
+
const x = e.clientX - rect.left;
|
|
1860
|
+
clickPercent = (x - trackInset) / (rect.width - trackInset * 2);
|
|
1861
|
+
} else {
|
|
1862
|
+
const y = rect.bottom - e.clientY;
|
|
1863
|
+
clickPercent = (y - trackInset) / (rect.height - trackInset * 2);
|
|
1864
|
+
}
|
|
1865
|
+
const clamped = Math.max(0, Math.min(1, clickPercent));
|
|
1866
|
+
const rawValue = min + clamped * (max - min);
|
|
1867
|
+
const clickValue = snap(coerce(rawValue));
|
|
1868
|
+
const distStart = Math.abs(clickValue - startValue);
|
|
1869
|
+
const distEnd = Math.abs(clickValue - endValue);
|
|
1870
|
+
if (distStart <= distEnd) {
|
|
1871
|
+
handleStartChange(clickValue);
|
|
1872
|
+
} else {
|
|
1873
|
+
handleEndChange(clickValue);
|
|
1874
|
+
}
|
|
1875
|
+
},
|
|
1876
|
+
[
|
|
1877
|
+
coerce,
|
|
1878
|
+
disabled,
|
|
1879
|
+
endValue,
|
|
1880
|
+
handleEndChange,
|
|
1881
|
+
handleStartChange,
|
|
1882
|
+
isHorizontal,
|
|
1883
|
+
max,
|
|
1884
|
+
min,
|
|
1885
|
+
snap,
|
|
1886
|
+
startValue,
|
|
1887
|
+
trackSize
|
|
1888
|
+
]
|
|
1889
|
+
);
|
|
1890
|
+
const id = React4.useId();
|
|
1891
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
|
|
1892
|
+
"div",
|
|
1893
|
+
{
|
|
1894
|
+
ref,
|
|
1895
|
+
className: cn(
|
|
1896
|
+
"relative flex items-center",
|
|
1897
|
+
isHorizontal ? "w-full flex-row" : "h-full flex-col",
|
|
1898
|
+
disabled && "pointer-events-none",
|
|
1899
|
+
className
|
|
1900
|
+
),
|
|
1901
|
+
style: isHorizontal ? { minWidth: 0 } : { minHeight: 0 },
|
|
1902
|
+
children: [
|
|
1903
|
+
/* @__PURE__ */ jsx(
|
|
1904
|
+
RangeTrack,
|
|
1905
|
+
{
|
|
1906
|
+
startPercent,
|
|
1907
|
+
endPercent,
|
|
1908
|
+
trackSize,
|
|
1909
|
+
trackShape,
|
|
1910
|
+
orientation,
|
|
1911
|
+
variant,
|
|
1912
|
+
disabled,
|
|
1913
|
+
ticks: showTicks ? ticks : [],
|
|
1914
|
+
min,
|
|
1915
|
+
max,
|
|
1916
|
+
trackRef,
|
|
1917
|
+
onTrackPointerDown: handleTrackPointerDown
|
|
1918
|
+
}
|
|
1919
|
+
),
|
|
1920
|
+
/* @__PURE__ */ jsx(
|
|
1921
|
+
SliderThumb,
|
|
1922
|
+
{
|
|
1923
|
+
value: startValue,
|
|
1924
|
+
percent: startPercent,
|
|
1925
|
+
min,
|
|
1926
|
+
max,
|
|
1927
|
+
step,
|
|
1928
|
+
disabled,
|
|
1929
|
+
orientation,
|
|
1930
|
+
trackSize,
|
|
1931
|
+
variant,
|
|
1932
|
+
showValueIndicator,
|
|
1933
|
+
trackRef,
|
|
1934
|
+
onValueChange: handleStartChange,
|
|
1935
|
+
onValueChangeEnd: handleStartChangeEnd,
|
|
1936
|
+
formatValue,
|
|
1937
|
+
thumbId: `${id}-start`,
|
|
1938
|
+
zIndex: topThumb === "start" ? 2 : 1,
|
|
1939
|
+
"aria-label": ariaLabel ? `${ariaLabel} start` : "Range start"
|
|
1940
|
+
}
|
|
1941
|
+
),
|
|
1942
|
+
/* @__PURE__ */ jsx(
|
|
1943
|
+
SliderThumb,
|
|
1944
|
+
{
|
|
1945
|
+
value: endValue,
|
|
1946
|
+
percent: endPercent,
|
|
1947
|
+
min,
|
|
1948
|
+
max,
|
|
1949
|
+
step,
|
|
1950
|
+
disabled,
|
|
1951
|
+
orientation,
|
|
1952
|
+
trackSize,
|
|
1953
|
+
variant,
|
|
1954
|
+
showValueIndicator,
|
|
1955
|
+
trackRef,
|
|
1956
|
+
onValueChange: handleEndChange,
|
|
1957
|
+
onValueChangeEnd: handleEndChangeEnd,
|
|
1958
|
+
formatValue,
|
|
1959
|
+
thumbId: `${id}-end`,
|
|
1960
|
+
zIndex: topThumb === "end" ? 2 : 1,
|
|
1961
|
+
"aria-label": ariaLabel ? `${ariaLabel} end` : "Range end"
|
|
1962
|
+
}
|
|
1963
|
+
)
|
|
1964
|
+
]
|
|
1965
|
+
}
|
|
1966
|
+
) });
|
|
1967
|
+
}
|
|
1968
|
+
);
|
|
1969
|
+
RangeSliderComponent.displayName = "RangeSlider";
|
|
1970
|
+
var RangeSlider = React4.memo(RangeSliderComponent);
|
|
1971
|
+
function getHorizontalRadius(isLeading, innerR, outerR) {
|
|
1972
|
+
if (isLeading) {
|
|
1973
|
+
return {
|
|
1974
|
+
borderTopLeftRadius: outerR,
|
|
1975
|
+
borderBottomLeftRadius: outerR,
|
|
1976
|
+
borderTopRightRadius: innerR,
|
|
1977
|
+
borderBottomRightRadius: innerR
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
return {
|
|
1981
|
+
borderTopLeftRadius: innerR,
|
|
1982
|
+
borderBottomLeftRadius: innerR,
|
|
1983
|
+
borderTopRightRadius: outerR,
|
|
1984
|
+
borderBottomRightRadius: outerR
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
function getVerticalRadius(isLeading, innerR, outerR) {
|
|
1988
|
+
if (isLeading) {
|
|
1989
|
+
return {
|
|
1990
|
+
borderBottomLeftRadius: outerR,
|
|
1991
|
+
borderBottomRightRadius: outerR,
|
|
1992
|
+
borderTopLeftRadius: innerR,
|
|
1993
|
+
borderTopRightRadius: innerR
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
return {
|
|
1997
|
+
borderTopLeftRadius: outerR,
|
|
1998
|
+
borderTopRightRadius: outerR,
|
|
1999
|
+
borderBottomLeftRadius: innerR,
|
|
2000
|
+
borderBottomRightRadius: innerR
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
var allInnerRadius = (innerR) => ({
|
|
2004
|
+
borderTopLeftRadius: innerR,
|
|
2005
|
+
borderBottomLeftRadius: innerR,
|
|
2006
|
+
borderTopRightRadius: innerR,
|
|
2007
|
+
borderBottomRightRadius: innerR
|
|
2008
|
+
});
|
|
2009
|
+
var InsetIcon = React4.memo(function InsetIcon2({
|
|
2010
|
+
icon,
|
|
2011
|
+
isOnActiveSegment,
|
|
2012
|
+
position,
|
|
2013
|
+
orientation,
|
|
2014
|
+
trackSize,
|
|
2015
|
+
trackSizeToken,
|
|
2016
|
+
disabled,
|
|
2017
|
+
variant,
|
|
2018
|
+
prefersReduced
|
|
2019
|
+
}) {
|
|
2020
|
+
const iconSize = Math.min(
|
|
2021
|
+
SliderTokens.insetIconSizes[trackSizeToken],
|
|
2022
|
+
Math.max(4, trackSize - SliderTokens.insetIconPadding * 2)
|
|
2023
|
+
);
|
|
2024
|
+
const activeColor = `var(--md-sys-color-on-${variant})`;
|
|
2025
|
+
const inactiveColor = `var(--md-sys-color-${variant})`;
|
|
2026
|
+
const isHorizontal = orientation === "horizontal";
|
|
2027
|
+
const fastFade = prefersReduced ? { duration: 0 } : { duration: 0.12 };
|
|
2028
|
+
return /* @__PURE__ */ jsx(
|
|
2029
|
+
m.div,
|
|
2030
|
+
{
|
|
2031
|
+
"aria-hidden": "true",
|
|
2032
|
+
className: "[&_svg]:w-full [&_svg]:h-full",
|
|
2033
|
+
initial: __spreadValues({
|
|
2034
|
+
opacity: 0
|
|
2035
|
+
}, isHorizontal ? { left: position } : { bottom: position }),
|
|
2036
|
+
animate: {
|
|
2037
|
+
[isHorizontal ? "left" : "bottom"]: position,
|
|
2038
|
+
opacity: disabled ? 0.38 : 1,
|
|
2039
|
+
color: isOnActiveSegment ? activeColor : inactiveColor
|
|
2040
|
+
},
|
|
2041
|
+
exit: { opacity: 0, transition: fastFade },
|
|
2042
|
+
transition: prefersReduced ? { duration: 0 } : {
|
|
2043
|
+
left: { type: "spring", stiffness: 500, damping: 40 },
|
|
2044
|
+
bottom: { type: "spring", stiffness: 500, damping: 40 },
|
|
2045
|
+
opacity: fastFade,
|
|
2046
|
+
color: fastFade
|
|
2047
|
+
},
|
|
2048
|
+
style: __spreadValues({
|
|
2049
|
+
position: "absolute",
|
|
2050
|
+
width: iconSize,
|
|
2051
|
+
height: iconSize,
|
|
2052
|
+
display: "flex",
|
|
2053
|
+
alignItems: "center",
|
|
2054
|
+
justifyContent: "center",
|
|
2055
|
+
pointerEvents: "none",
|
|
2056
|
+
zIndex: 1,
|
|
2057
|
+
willChange: isHorizontal ? "left" : "bottom"
|
|
2058
|
+
}, isHorizontal ? { top: "50%", transform: "translateY(-50%)" } : { left: "50%", transform: "translateX(-50%)" }),
|
|
2059
|
+
children: icon
|
|
2060
|
+
}
|
|
2061
|
+
);
|
|
2062
|
+
});
|
|
2063
|
+
function Ticks({
|
|
2064
|
+
ticks,
|
|
2065
|
+
min,
|
|
2066
|
+
max,
|
|
2067
|
+
percent,
|
|
2068
|
+
orientation,
|
|
2069
|
+
variant,
|
|
2070
|
+
isCentered,
|
|
2071
|
+
disabled,
|
|
2072
|
+
trackInset
|
|
2073
|
+
}) {
|
|
2074
|
+
if (ticks.length === 0) return null;
|
|
2075
|
+
const { thumbGap, thumbWidthDefault, tickSize } = SliderTokens;
|
|
2076
|
+
return /* @__PURE__ */ jsx(Fragment, { children: ticks.map((tick) => {
|
|
2077
|
+
const tickPercent = (tick - min) / (max - min);
|
|
2078
|
+
const isOnActive = isCentered ? percent >= 0.5 ? tickPercent >= 0.5 && tickPercent <= percent : tickPercent <= 0.5 && tickPercent >= percent : tickPercent <= percent;
|
|
2079
|
+
const thumbStart = percent - (thumbGap + thumbWidthDefault / 2) / 100;
|
|
2080
|
+
const thumbEnd = percent + (thumbGap + thumbWidthDefault / 2) / 100;
|
|
2081
|
+
if (tickPercent > thumbStart && tickPercent < thumbEnd) return null;
|
|
2082
|
+
const color = disabled ? SliderColors.disabledTick : isOnActive ? `var(--md-sys-color-${variant}-container)` : `var(--md-sys-color-${variant})`;
|
|
2083
|
+
const style = __spreadValues({
|
|
2084
|
+
position: "absolute",
|
|
2085
|
+
width: tickSize,
|
|
2086
|
+
height: tickSize,
|
|
2087
|
+
borderRadius: "50%",
|
|
2088
|
+
backgroundColor: color,
|
|
2089
|
+
opacity: disabled ? 0.38 : 1
|
|
2090
|
+
}, orientation === "horizontal" ? {
|
|
2091
|
+
left: `calc(${trackInset}px + ${tickPercent} * (100% - ${trackInset * 2}px) - ${tickSize / 2}px)`,
|
|
2092
|
+
top: "50%",
|
|
2093
|
+
transform: "translateY(-50%)"
|
|
2094
|
+
} : {
|
|
2095
|
+
// Vertical: bottom=0%, top=100% (inverted Y-axis)
|
|
2096
|
+
bottom: `calc(${trackInset}px + ${tickPercent} * (100% - ${trackInset * 2}px) - ${tickSize / 2}px)`,
|
|
2097
|
+
left: "50%",
|
|
2098
|
+
transform: "translateX(-50%)"
|
|
2099
|
+
});
|
|
2100
|
+
return /* @__PURE__ */ jsx("div", { style, "aria-hidden": "true" }, tick);
|
|
2101
|
+
}) });
|
|
2102
|
+
}
|
|
2103
|
+
var SliderTrack = React4.memo(function SliderTrack2({
|
|
2104
|
+
percent,
|
|
2105
|
+
trackSize,
|
|
2106
|
+
orientation,
|
|
2107
|
+
variant,
|
|
2108
|
+
isCentered,
|
|
2109
|
+
min,
|
|
2110
|
+
max,
|
|
2111
|
+
disabled,
|
|
2112
|
+
trackRef,
|
|
2113
|
+
onTrackPointerDown,
|
|
2114
|
+
ticks = [],
|
|
2115
|
+
insetIcon,
|
|
2116
|
+
insetIconAtMin,
|
|
2117
|
+
insetIconTrailing,
|
|
2118
|
+
insetIconAtMax,
|
|
2119
|
+
value,
|
|
2120
|
+
trackShape = "md3"
|
|
2121
|
+
}) {
|
|
2122
|
+
var _a;
|
|
2123
|
+
const isHorizontal = orientation === "horizontal";
|
|
2124
|
+
const size = SliderTokens.trackSizes[trackSize];
|
|
2125
|
+
const thumbHeight = SliderTokens.thumbHeights[trackSize];
|
|
2126
|
+
const { thumbGap, thumbWidthDefault, trackInnerRadius } = SliderTokens;
|
|
2127
|
+
const innerR = trackInnerRadius;
|
|
2128
|
+
let outerR = size / 2;
|
|
2129
|
+
if (trackShape === "md3") {
|
|
2130
|
+
outerR = Math.min(SliderTokens.trackShapes[trackSize], size / 2);
|
|
2131
|
+
} else if (typeof trackShape === "number") {
|
|
2132
|
+
outerR = Math.min(trackShape, size / 2);
|
|
2133
|
+
}
|
|
2134
|
+
const thumbHalfWidth = thumbWidthDefault / 2;
|
|
2135
|
+
const gapWithThumbStr = `${thumbGap + thumbHalfWidth}px`;
|
|
2136
|
+
const hasAnyInsetIcon = Boolean(insetIcon || insetIconTrailing);
|
|
2137
|
+
const prefersReduced = (_a = useReducedMotion()) != null ? _a : false;
|
|
2138
|
+
const [trackWidth, setTrackWidth] = React4.useState(0);
|
|
2139
|
+
React4.useLayoutEffect(() => {
|
|
2140
|
+
const el = trackRef.current;
|
|
2141
|
+
if (!el || !hasAnyInsetIcon) return;
|
|
2142
|
+
setTrackWidth(isHorizontal ? el.clientWidth : el.clientHeight);
|
|
2143
|
+
const ro = new ResizeObserver(() => {
|
|
2144
|
+
setTrackWidth(isHorizontal ? el.clientWidth : el.clientHeight);
|
|
2145
|
+
});
|
|
2146
|
+
ro.observe(el);
|
|
2147
|
+
return () => ro.disconnect();
|
|
2148
|
+
}, [hasAnyInsetIcon, isHorizontal, trackRef]);
|
|
2149
|
+
const activeIconSize = Math.min(
|
|
2150
|
+
SliderTokens.insetIconSizes[trackSize],
|
|
2151
|
+
Math.max(4, size - SliderTokens.insetIconPadding * 2)
|
|
2152
|
+
);
|
|
2153
|
+
const iconTotalWidth = activeIconSize + SliderTokens.insetIconPadding * 2 + thumbGap + thumbHalfWidth;
|
|
2154
|
+
const iconThreshold = trackWidth > 0 ? iconTotalWidth / trackWidth : 0.15;
|
|
2155
|
+
const HYSTERESIS_GAP = 0.04;
|
|
2156
|
+
const trailingActiveRef = React4.useRef(1 - percent <= iconThreshold);
|
|
2157
|
+
const leadingActiveRef = React4.useRef(percent > iconThreshold);
|
|
2158
|
+
const trailingPercent = 1 - percent;
|
|
2159
|
+
if (trailingActiveRef.current) {
|
|
2160
|
+
if (trailingPercent > iconThreshold + HYSTERESIS_GAP) {
|
|
2161
|
+
trailingActiveRef.current = false;
|
|
2162
|
+
}
|
|
2163
|
+
} else {
|
|
2164
|
+
if (trailingPercent <= iconThreshold) {
|
|
2165
|
+
trailingActiveRef.current = true;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
const trailingOnActive = trailingActiveRef.current;
|
|
2169
|
+
if (leadingActiveRef.current) {
|
|
2170
|
+
if (percent <= iconThreshold - HYSTERESIS_GAP) {
|
|
2171
|
+
leadingActiveRef.current = false;
|
|
2172
|
+
}
|
|
2173
|
+
} else {
|
|
2174
|
+
if (percent > iconThreshold) {
|
|
2175
|
+
leadingActiveRef.current = true;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
const leadingOnActive = leadingActiveRef.current;
|
|
2179
|
+
const isAtMin = value !== void 0 && value <= min;
|
|
2180
|
+
const resolvedLeadingIcon = isAtMin && insetIconAtMin ? insetIconAtMin : insetIcon;
|
|
2181
|
+
const isAtMax = value !== void 0 && value >= max;
|
|
2182
|
+
const resolvedTrailingIcon = isAtMax && insetIconAtMax ? insetIconAtMax : insetIconTrailing;
|
|
2183
|
+
const activeColor = disabled ? SliderColors.disabledActiveTrack : `var(--md-sys-color-${variant})`;
|
|
2184
|
+
const inactiveColor = disabled ? SliderColors.disabledInactiveTrack : `var(--md-sys-color-${variant}-container)`;
|
|
2185
|
+
const insetLimit = SliderTokens.thumbGap + SliderTokens.thumbWidthDefault / 2;
|
|
2186
|
+
const trackInset = Math.min(size / 2, insetLimit);
|
|
2187
|
+
const gapTotal = thumbGap + thumbHalfWidth;
|
|
2188
|
+
const thumbCenter = `calc(${trackInset}px + ${percent} * (100% - ${trackInset * 2}px))`;
|
|
2189
|
+
const leadingActiveLeft = `${trackInset + SliderTokens.insetIconPadding}px`;
|
|
2190
|
+
const leadingInactiveLeft = `calc(${thumbCenter} + ${gapTotal}px + ${SliderTokens.insetIconPadding}px)`;
|
|
2191
|
+
const trailingInactiveLeft = `calc(100% - ${trackInset}px - ${activeIconSize}px - ${SliderTokens.insetIconPadding}px)`;
|
|
2192
|
+
const trailingActiveLeft = `calc(${thumbCenter} - ${gapTotal}px - ${activeIconSize}px - ${SliderTokens.insetIconPadding}px)`;
|
|
2193
|
+
if (isHorizontal) {
|
|
2194
|
+
const cxStr = `calc(${trackInset}px + ${percent} * (100% - ${trackInset * 2}px))`;
|
|
2195
|
+
const segments2 = [];
|
|
2196
|
+
if (!isCentered) {
|
|
2197
|
+
const leftSegmentWidth = `max(0px, calc(${cxStr} - ${gapWithThumbStr}))`;
|
|
2198
|
+
const rightSegmentLeft = `calc(${cxStr} + ${gapWithThumbStr})`;
|
|
2199
|
+
const rightSegmentWidth = `max(0px, calc(100% - (${cxStr} + ${gapWithThumbStr})))`;
|
|
2200
|
+
segments2.push(
|
|
2201
|
+
/* @__PURE__ */ jsx(
|
|
2202
|
+
"div",
|
|
2203
|
+
{
|
|
2204
|
+
"aria-hidden": "true",
|
|
2205
|
+
style: __spreadValues({
|
|
2206
|
+
position: "absolute",
|
|
2207
|
+
left: 0,
|
|
2208
|
+
top: "50%",
|
|
2209
|
+
transform: "translateY(-50%)",
|
|
2210
|
+
width: leftSegmentWidth,
|
|
2211
|
+
height: size,
|
|
2212
|
+
backgroundColor: activeColor,
|
|
2213
|
+
opacity: disabled ? 0.38 : 1
|
|
2214
|
+
}, getHorizontalRadius(true, innerR, outerR))
|
|
2215
|
+
},
|
|
2216
|
+
"left"
|
|
2217
|
+
)
|
|
2218
|
+
);
|
|
2219
|
+
segments2.push(
|
|
2220
|
+
/* @__PURE__ */ jsx(
|
|
2221
|
+
"div",
|
|
2222
|
+
{
|
|
2223
|
+
"aria-hidden": "true",
|
|
2224
|
+
style: __spreadValues({
|
|
2225
|
+
position: "absolute",
|
|
2226
|
+
left: rightSegmentLeft,
|
|
2227
|
+
top: "50%",
|
|
2228
|
+
transform: "translateY(-50%)",
|
|
2229
|
+
width: rightSegmentWidth,
|
|
2230
|
+
height: size,
|
|
2231
|
+
backgroundColor: inactiveColor,
|
|
2232
|
+
opacity: disabled ? 0.38 : 1
|
|
2233
|
+
}, getHorizontalRadius(false, innerR, outerR))
|
|
2234
|
+
},
|
|
2235
|
+
"right"
|
|
2236
|
+
)
|
|
2237
|
+
);
|
|
2238
|
+
} else {
|
|
2239
|
+
const halfCenterGap = SliderTokens.thumbGap / 2;
|
|
2240
|
+
if (percent >= 0.5) {
|
|
2241
|
+
const leftBaseWidth = `max(0px, min(calc(50% - ${halfCenterGap}px), calc(${cxStr} - ${gapWithThumbStr})))`;
|
|
2242
|
+
segments2.push(
|
|
2243
|
+
/* @__PURE__ */ jsx(
|
|
2244
|
+
"div",
|
|
2245
|
+
{
|
|
2246
|
+
"aria-hidden": "true",
|
|
2247
|
+
style: __spreadValues({
|
|
2248
|
+
position: "absolute",
|
|
2249
|
+
left: 0,
|
|
2250
|
+
top: "50%",
|
|
2251
|
+
transform: "translateY(-50%)",
|
|
2252
|
+
width: leftBaseWidth,
|
|
2253
|
+
height: size,
|
|
2254
|
+
backgroundColor: inactiveColor,
|
|
2255
|
+
opacity: disabled ? 0.38 : 1
|
|
2256
|
+
}, getHorizontalRadius(true, innerR, outerR))
|
|
2257
|
+
},
|
|
2258
|
+
"left-base"
|
|
2259
|
+
)
|
|
2260
|
+
);
|
|
2261
|
+
const centerActiveLeft = `calc(50% + ${halfCenterGap}px)`;
|
|
2262
|
+
const centerActiveWidth = `max(0px, calc(${cxStr} - ${gapWithThumbStr} - (50% + ${halfCenterGap}px)))`;
|
|
2263
|
+
segments2.push(
|
|
2264
|
+
/* @__PURE__ */ jsx(
|
|
2265
|
+
"div",
|
|
2266
|
+
{
|
|
2267
|
+
"aria-hidden": "true",
|
|
2268
|
+
style: __spreadValues({
|
|
2269
|
+
position: "absolute",
|
|
2270
|
+
left: centerActiveLeft,
|
|
2271
|
+
top: "50%",
|
|
2272
|
+
transform: "translateY(-50%)",
|
|
2273
|
+
width: centerActiveWidth,
|
|
2274
|
+
height: size,
|
|
2275
|
+
backgroundColor: activeColor,
|
|
2276
|
+
opacity: disabled ? 0.38 : 1
|
|
2277
|
+
}, allInnerRadius(innerR))
|
|
2278
|
+
},
|
|
2279
|
+
"center-active"
|
|
2280
|
+
)
|
|
2281
|
+
);
|
|
2282
|
+
const rightBaseLeft = `calc(${cxStr} + ${gapWithThumbStr})`;
|
|
2283
|
+
const rightBaseWidth = `max(0px, calc(100% - (${cxStr} + ${gapWithThumbStr})))`;
|
|
2284
|
+
segments2.push(
|
|
2285
|
+
/* @__PURE__ */ jsx(
|
|
2286
|
+
"div",
|
|
2287
|
+
{
|
|
2288
|
+
"aria-hidden": "true",
|
|
2289
|
+
style: __spreadValues({
|
|
2290
|
+
position: "absolute",
|
|
2291
|
+
left: rightBaseLeft,
|
|
2292
|
+
top: "50%",
|
|
2293
|
+
transform: "translateY(-50%)",
|
|
2294
|
+
width: rightBaseWidth,
|
|
2295
|
+
height: size,
|
|
2296
|
+
backgroundColor: inactiveColor,
|
|
2297
|
+
opacity: disabled ? 0.38 : 1
|
|
2298
|
+
}, getHorizontalRadius(false, innerR, outerR))
|
|
2299
|
+
},
|
|
2300
|
+
"right-base"
|
|
2301
|
+
)
|
|
2302
|
+
);
|
|
2303
|
+
} else {
|
|
2304
|
+
const leftBaseWidth = `max(0px, calc(${cxStr} - ${gapWithThumbStr}))`;
|
|
2305
|
+
segments2.push(
|
|
2306
|
+
/* @__PURE__ */ jsx(
|
|
2307
|
+
"div",
|
|
2308
|
+
{
|
|
2309
|
+
"aria-hidden": "true",
|
|
2310
|
+
style: __spreadValues({
|
|
2311
|
+
position: "absolute",
|
|
2312
|
+
left: 0,
|
|
2313
|
+
top: "50%",
|
|
2314
|
+
transform: "translateY(-50%)",
|
|
2315
|
+
width: leftBaseWidth,
|
|
2316
|
+
height: size,
|
|
2317
|
+
backgroundColor: inactiveColor,
|
|
2318
|
+
opacity: disabled ? 0.38 : 1
|
|
2319
|
+
}, getHorizontalRadius(true, innerR, outerR))
|
|
2320
|
+
},
|
|
2321
|
+
"left-base"
|
|
2322
|
+
)
|
|
2323
|
+
);
|
|
2324
|
+
const centerActiveLeft = `calc(${cxStr} + ${gapWithThumbStr})`;
|
|
2325
|
+
const centerActiveWidth = `max(0px, calc(50% - ${halfCenterGap}px - (${cxStr} + ${gapWithThumbStr})))`;
|
|
2326
|
+
segments2.push(
|
|
2327
|
+
/* @__PURE__ */ jsx(
|
|
2328
|
+
"div",
|
|
2329
|
+
{
|
|
2330
|
+
"aria-hidden": "true",
|
|
2331
|
+
style: __spreadValues({
|
|
2332
|
+
position: "absolute",
|
|
2333
|
+
left: centerActiveLeft,
|
|
2334
|
+
top: "50%",
|
|
2335
|
+
transform: "translateY(-50%)",
|
|
2336
|
+
width: centerActiveWidth,
|
|
2337
|
+
height: size,
|
|
2338
|
+
backgroundColor: activeColor,
|
|
2339
|
+
opacity: disabled ? 0.38 : 1
|
|
2340
|
+
}, allInnerRadius(innerR))
|
|
2341
|
+
},
|
|
2342
|
+
"center-active"
|
|
2343
|
+
)
|
|
2344
|
+
);
|
|
2345
|
+
const rightBaseLeft = `max(calc(50% + ${halfCenterGap}px), calc(${cxStr} + ${gapWithThumbStr}))`;
|
|
2346
|
+
const rightBaseWidth = `max(0px, calc(100% - max(calc(50% + ${halfCenterGap}px), calc(${cxStr} + ${gapWithThumbStr}))))`;
|
|
2347
|
+
segments2.push(
|
|
2348
|
+
/* @__PURE__ */ jsx(
|
|
2349
|
+
"div",
|
|
2350
|
+
{
|
|
2351
|
+
"aria-hidden": "true",
|
|
2352
|
+
style: __spreadValues({
|
|
2353
|
+
position: "absolute",
|
|
2354
|
+
left: rightBaseLeft,
|
|
2355
|
+
top: "50%",
|
|
2356
|
+
transform: "translateY(-50%)",
|
|
2357
|
+
width: rightBaseWidth,
|
|
2358
|
+
height: size,
|
|
2359
|
+
backgroundColor: inactiveColor,
|
|
2360
|
+
opacity: disabled ? 0.38 : 1
|
|
2361
|
+
}, getHorizontalRadius(false, innerR, outerR))
|
|
2362
|
+
},
|
|
2363
|
+
"right-base"
|
|
2364
|
+
)
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
return /* @__PURE__ */ jsxs(
|
|
2369
|
+
"div",
|
|
2370
|
+
{
|
|
2371
|
+
ref: trackRef,
|
|
2372
|
+
className: cn(
|
|
2373
|
+
"relative w-full",
|
|
2374
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
2375
|
+
),
|
|
2376
|
+
style: { height: thumbHeight },
|
|
2377
|
+
onPointerDown: onTrackPointerDown,
|
|
2378
|
+
"aria-hidden": "true",
|
|
2379
|
+
children: [
|
|
2380
|
+
segments2,
|
|
2381
|
+
ticks.length > 0 && /* @__PURE__ */ jsx(
|
|
2382
|
+
Ticks,
|
|
2383
|
+
{
|
|
2384
|
+
ticks,
|
|
2385
|
+
min,
|
|
2386
|
+
max,
|
|
2387
|
+
percent,
|
|
2388
|
+
orientation,
|
|
2389
|
+
disabled,
|
|
2390
|
+
variant,
|
|
2391
|
+
isCentered,
|
|
2392
|
+
trackInset
|
|
2393
|
+
}
|
|
2394
|
+
),
|
|
2395
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: resolvedLeadingIcon && /* @__PURE__ */ jsx(
|
|
2396
|
+
InsetIcon,
|
|
2397
|
+
{
|
|
2398
|
+
icon: resolvedLeadingIcon,
|
|
2399
|
+
isOnActiveSegment: leadingOnActive,
|
|
2400
|
+
position: leadingOnActive ? leadingActiveLeft : leadingInactiveLeft,
|
|
2401
|
+
orientation,
|
|
2402
|
+
trackSize: size,
|
|
2403
|
+
trackSizeToken: trackSize,
|
|
2404
|
+
disabled,
|
|
2405
|
+
variant,
|
|
2406
|
+
prefersReduced
|
|
2407
|
+
},
|
|
2408
|
+
isAtMin ? "lead-min" : leadingOnActive ? "lead-active" : "lead-inactive"
|
|
2409
|
+
) }),
|
|
2410
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: resolvedTrailingIcon && /* @__PURE__ */ jsx(
|
|
2411
|
+
InsetIcon,
|
|
2412
|
+
{
|
|
2413
|
+
icon: resolvedTrailingIcon,
|
|
2414
|
+
isOnActiveSegment: trailingOnActive,
|
|
2415
|
+
position: trailingOnActive ? trailingActiveLeft : trailingInactiveLeft,
|
|
2416
|
+
orientation,
|
|
2417
|
+
trackSize: size,
|
|
2418
|
+
trackSizeToken: trackSize,
|
|
2419
|
+
disabled,
|
|
2420
|
+
variant,
|
|
2421
|
+
prefersReduced
|
|
2422
|
+
},
|
|
2423
|
+
isAtMax ? "trail-max" : trailingOnActive ? "trail-active" : "trail-inactive"
|
|
2424
|
+
) })
|
|
2425
|
+
]
|
|
2426
|
+
}
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
const cyStr = `calc(${trackInset}px + ${percent} * (100% - ${trackInset * 2}px))`;
|
|
2430
|
+
const segments = [];
|
|
2431
|
+
if (!isCentered) {
|
|
2432
|
+
const bottomSegmentHeight = `max(0px, calc(${cyStr} - ${gapWithThumbStr}))`;
|
|
2433
|
+
const topSegmentBottom = `calc(${cyStr} + ${gapWithThumbStr})`;
|
|
2434
|
+
const topSegmentHeight = `max(0px, calc(100% - (${cyStr} + ${gapWithThumbStr})))`;
|
|
2435
|
+
segments.push(
|
|
2436
|
+
/* @__PURE__ */ jsx(
|
|
2437
|
+
"div",
|
|
2438
|
+
{
|
|
2439
|
+
"aria-hidden": "true",
|
|
2440
|
+
style: __spreadValues({
|
|
2441
|
+
position: "absolute",
|
|
2442
|
+
bottom: 0,
|
|
2443
|
+
left: "50%",
|
|
2444
|
+
transform: "translateX(-50%)",
|
|
2445
|
+
height: bottomSegmentHeight,
|
|
2446
|
+
width: size,
|
|
2447
|
+
backgroundColor: activeColor,
|
|
2448
|
+
opacity: disabled ? 0.38 : 1
|
|
2449
|
+
}, getVerticalRadius(true, innerR, outerR))
|
|
2450
|
+
},
|
|
2451
|
+
"bottom"
|
|
2452
|
+
)
|
|
2453
|
+
);
|
|
2454
|
+
segments.push(
|
|
2455
|
+
/* @__PURE__ */ jsx(
|
|
2456
|
+
"div",
|
|
2457
|
+
{
|
|
2458
|
+
"aria-hidden": "true",
|
|
2459
|
+
style: __spreadValues({
|
|
2460
|
+
position: "absolute",
|
|
2461
|
+
bottom: topSegmentBottom,
|
|
2462
|
+
left: "50%",
|
|
2463
|
+
transform: "translateX(-50%)",
|
|
2464
|
+
height: topSegmentHeight,
|
|
2465
|
+
width: size,
|
|
2466
|
+
backgroundColor: inactiveColor,
|
|
2467
|
+
opacity: disabled ? 0.38 : 1
|
|
2468
|
+
}, getVerticalRadius(false, innerR, outerR))
|
|
2469
|
+
},
|
|
2470
|
+
"top"
|
|
2471
|
+
)
|
|
2472
|
+
);
|
|
2473
|
+
} else {
|
|
2474
|
+
const halfCenterGap = SliderTokens.thumbGap / 2;
|
|
2475
|
+
if (percent >= 0.5) {
|
|
2476
|
+
const bottomBaseHeight = `max(0px, min(calc(50% - ${halfCenterGap}px), calc(${cyStr} - ${gapWithThumbStr})))`;
|
|
2477
|
+
segments.push(
|
|
2478
|
+
/* @__PURE__ */ jsx(
|
|
2479
|
+
"div",
|
|
2480
|
+
{
|
|
2481
|
+
"aria-hidden": "true",
|
|
2482
|
+
style: __spreadValues({
|
|
2483
|
+
position: "absolute",
|
|
2484
|
+
bottom: 0,
|
|
2485
|
+
left: "50%",
|
|
2486
|
+
transform: "translateX(-50%)",
|
|
2487
|
+
height: bottomBaseHeight,
|
|
2488
|
+
width: size,
|
|
2489
|
+
backgroundColor: inactiveColor,
|
|
2490
|
+
opacity: disabled ? 0.38 : 1
|
|
2491
|
+
}, getVerticalRadius(true, innerR, outerR))
|
|
2492
|
+
},
|
|
2493
|
+
"bottom-base"
|
|
2494
|
+
)
|
|
2495
|
+
);
|
|
2496
|
+
const centerActiveBottom = `calc(50% + ${halfCenterGap}px)`;
|
|
2497
|
+
const centerActiveHeight = `max(0px, calc(${cyStr} - ${gapWithThumbStr} - (50% + ${halfCenterGap}px)))`;
|
|
2498
|
+
segments.push(
|
|
2499
|
+
/* @__PURE__ */ jsx(
|
|
2500
|
+
"div",
|
|
2501
|
+
{
|
|
2502
|
+
"aria-hidden": "true",
|
|
2503
|
+
style: __spreadValues({
|
|
2504
|
+
position: "absolute",
|
|
2505
|
+
bottom: centerActiveBottom,
|
|
2506
|
+
left: "50%",
|
|
2507
|
+
transform: "translateX(-50%)",
|
|
2508
|
+
height: centerActiveHeight,
|
|
2509
|
+
width: size,
|
|
2510
|
+
backgroundColor: activeColor,
|
|
2511
|
+
opacity: disabled ? 0.38 : 1
|
|
2512
|
+
}, allInnerRadius(innerR))
|
|
2513
|
+
},
|
|
2514
|
+
"center-active"
|
|
2515
|
+
)
|
|
2516
|
+
);
|
|
2517
|
+
const topBaseBottom = `calc(${cyStr} + ${gapWithThumbStr})`;
|
|
2518
|
+
const topBaseHeight = `max(0px, calc(100% - (${cyStr} + ${gapWithThumbStr})))`;
|
|
2519
|
+
segments.push(
|
|
2520
|
+
/* @__PURE__ */ jsx(
|
|
2521
|
+
"div",
|
|
2522
|
+
{
|
|
2523
|
+
"aria-hidden": "true",
|
|
2524
|
+
style: __spreadValues({
|
|
2525
|
+
position: "absolute",
|
|
2526
|
+
bottom: topBaseBottom,
|
|
2527
|
+
left: "50%",
|
|
2528
|
+
transform: "translateX(-50%)",
|
|
2529
|
+
height: topBaseHeight,
|
|
2530
|
+
width: size,
|
|
2531
|
+
backgroundColor: inactiveColor,
|
|
2532
|
+
opacity: disabled ? 0.38 : 1
|
|
2533
|
+
}, getVerticalRadius(false, innerR, outerR))
|
|
2534
|
+
},
|
|
2535
|
+
"top-base"
|
|
2536
|
+
)
|
|
2537
|
+
);
|
|
2538
|
+
} else {
|
|
2539
|
+
const bottomBaseHeight = `max(0px, calc(${cyStr} - ${gapWithThumbStr}))`;
|
|
2540
|
+
segments.push(
|
|
2541
|
+
/* @__PURE__ */ jsx(
|
|
2542
|
+
"div",
|
|
2543
|
+
{
|
|
2544
|
+
"aria-hidden": "true",
|
|
2545
|
+
style: __spreadValues({
|
|
2546
|
+
position: "absolute",
|
|
2547
|
+
bottom: 0,
|
|
2548
|
+
left: "50%",
|
|
2549
|
+
transform: "translateX(-50%)",
|
|
2550
|
+
height: bottomBaseHeight,
|
|
2551
|
+
width: size,
|
|
2552
|
+
backgroundColor: inactiveColor,
|
|
2553
|
+
opacity: disabled ? 0.38 : 1
|
|
2554
|
+
}, getVerticalRadius(true, innerR, outerR))
|
|
2555
|
+
},
|
|
2556
|
+
"bottom-base"
|
|
2557
|
+
)
|
|
2558
|
+
);
|
|
2559
|
+
const centerActiveBottom = `calc(${cyStr} + ${gapWithThumbStr})`;
|
|
2560
|
+
const centerActiveHeight = `max(0px, calc(50% - ${halfCenterGap}px - (${cyStr} + ${gapWithThumbStr})))`;
|
|
2561
|
+
segments.push(
|
|
2562
|
+
/* @__PURE__ */ jsx(
|
|
2563
|
+
"div",
|
|
2564
|
+
{
|
|
2565
|
+
"aria-hidden": "true",
|
|
2566
|
+
style: __spreadValues({
|
|
2567
|
+
position: "absolute",
|
|
2568
|
+
bottom: centerActiveBottom,
|
|
2569
|
+
left: "50%",
|
|
2570
|
+
transform: "translateX(-50%)",
|
|
2571
|
+
height: centerActiveHeight,
|
|
2572
|
+
width: size,
|
|
2573
|
+
backgroundColor: activeColor,
|
|
2574
|
+
opacity: disabled ? 0.38 : 1
|
|
2575
|
+
}, allInnerRadius(innerR))
|
|
2576
|
+
},
|
|
2577
|
+
"center-active"
|
|
2578
|
+
)
|
|
2579
|
+
);
|
|
2580
|
+
const topBaseBottom = `max(calc(50% + ${halfCenterGap}px), calc(${cyStr} + ${gapWithThumbStr}))`;
|
|
2581
|
+
const topBaseHeight = `max(0px, calc(100% - max(calc(50% + ${halfCenterGap}px), calc(${cyStr} + ${gapWithThumbStr}))))`;
|
|
2582
|
+
segments.push(
|
|
2583
|
+
/* @__PURE__ */ jsx(
|
|
2584
|
+
"div",
|
|
2585
|
+
{
|
|
2586
|
+
"aria-hidden": "true",
|
|
2587
|
+
style: __spreadValues({
|
|
2588
|
+
position: "absolute",
|
|
2589
|
+
bottom: topBaseBottom,
|
|
2590
|
+
left: "50%",
|
|
2591
|
+
transform: "translateX(-50%)",
|
|
2592
|
+
height: topBaseHeight,
|
|
2593
|
+
width: size,
|
|
2594
|
+
backgroundColor: inactiveColor,
|
|
2595
|
+
opacity: disabled ? 0.38 : 1
|
|
2596
|
+
}, getVerticalRadius(false, innerR, outerR))
|
|
2597
|
+
},
|
|
2598
|
+
"top-base"
|
|
2599
|
+
)
|
|
2600
|
+
);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
return /* @__PURE__ */ jsxs(
|
|
2604
|
+
"div",
|
|
2605
|
+
{
|
|
2606
|
+
ref: trackRef,
|
|
2607
|
+
className: cn(
|
|
2608
|
+
"relative h-full",
|
|
2609
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
2610
|
+
),
|
|
2611
|
+
style: { width: thumbHeight },
|
|
2612
|
+
onPointerDown: onTrackPointerDown,
|
|
2613
|
+
"aria-hidden": "true",
|
|
2614
|
+
children: [
|
|
2615
|
+
segments,
|
|
2616
|
+
ticks.length > 0 && /* @__PURE__ */ jsx(
|
|
2617
|
+
Ticks,
|
|
2618
|
+
{
|
|
2619
|
+
ticks,
|
|
2620
|
+
min,
|
|
2621
|
+
max,
|
|
2622
|
+
percent,
|
|
2623
|
+
orientation,
|
|
2624
|
+
disabled,
|
|
2625
|
+
variant,
|
|
2626
|
+
isCentered,
|
|
2627
|
+
trackInset
|
|
2628
|
+
}
|
|
2629
|
+
),
|
|
2630
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: resolvedLeadingIcon && /* @__PURE__ */ jsx(
|
|
2631
|
+
InsetIcon,
|
|
2632
|
+
{
|
|
2633
|
+
icon: resolvedLeadingIcon,
|
|
2634
|
+
isOnActiveSegment: leadingOnActive,
|
|
2635
|
+
position: leadingOnActive ? leadingActiveLeft : leadingInactiveLeft,
|
|
2636
|
+
orientation,
|
|
2637
|
+
trackSize: size,
|
|
2638
|
+
trackSizeToken: trackSize,
|
|
2639
|
+
disabled,
|
|
2640
|
+
variant,
|
|
2641
|
+
prefersReduced
|
|
2642
|
+
},
|
|
2643
|
+
isAtMin ? "lead-min" : leadingOnActive ? "lead-active" : "lead-inactive"
|
|
2644
|
+
) }),
|
|
2645
|
+
/* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: resolvedTrailingIcon && /* @__PURE__ */ jsx(
|
|
2646
|
+
InsetIcon,
|
|
2647
|
+
{
|
|
2648
|
+
icon: resolvedTrailingIcon,
|
|
2649
|
+
isOnActiveSegment: trailingOnActive,
|
|
2650
|
+
position: trailingOnActive ? trailingActiveLeft : trailingInactiveLeft,
|
|
2651
|
+
orientation,
|
|
2652
|
+
trackSize: size,
|
|
2653
|
+
trackSizeToken: trackSize,
|
|
2654
|
+
disabled,
|
|
2655
|
+
variant,
|
|
2656
|
+
prefersReduced
|
|
2657
|
+
},
|
|
2658
|
+
isAtMax ? "trail-max" : trailingOnActive ? "trail-active" : "trail-inactive"
|
|
2659
|
+
) })
|
|
2660
|
+
]
|
|
2661
|
+
}
|
|
2662
|
+
);
|
|
2663
|
+
});
|
|
2664
|
+
var SliderComponent = React4.forwardRef(
|
|
2665
|
+
({
|
|
2666
|
+
value: controlledValue,
|
|
2667
|
+
defaultValue,
|
|
2668
|
+
onValueChange,
|
|
2669
|
+
onValueChangeEnd,
|
|
2670
|
+
min = 0,
|
|
2671
|
+
max = 100,
|
|
2672
|
+
step = 0,
|
|
2673
|
+
orientation = "horizontal",
|
|
2674
|
+
trackSize = "m",
|
|
2675
|
+
trackShape = "md3",
|
|
2676
|
+
variant = "primary",
|
|
2677
|
+
isCentered = false,
|
|
2678
|
+
disabled = false,
|
|
2679
|
+
showValueIndicator = false,
|
|
2680
|
+
showTicks = false,
|
|
2681
|
+
insetIcon,
|
|
2682
|
+
insetIconAtMin,
|
|
2683
|
+
insetIconTrailing,
|
|
2684
|
+
insetIconAtMax,
|
|
2685
|
+
formatValue,
|
|
2686
|
+
className,
|
|
2687
|
+
"aria-label": ariaLabel,
|
|
2688
|
+
"aria-labelledby": ariaLabelledBy
|
|
2689
|
+
}, ref) => {
|
|
2690
|
+
const isHorizontal = orientation === "horizontal";
|
|
2691
|
+
const midpoint = min + (max - min) / 2;
|
|
2692
|
+
const initialValue = defaultValue != null ? defaultValue : midpoint;
|
|
2693
|
+
const [internalValue, setInternalValue] = React4.useState(initialValue);
|
|
2694
|
+
const resolvedValue = controlledValue !== void 0 ? controlledValue : internalValue;
|
|
2695
|
+
const { coerce, snap, toPercent, ticks } = useSliderMath({
|
|
2696
|
+
min,
|
|
2697
|
+
max,
|
|
2698
|
+
step
|
|
2699
|
+
});
|
|
2700
|
+
const safeValue = snap(coerce(resolvedValue));
|
|
2701
|
+
const percent = toPercent(safeValue);
|
|
2702
|
+
const trackRef = React4.useRef(null);
|
|
2703
|
+
const handleValueChange = React4.useCallback(
|
|
2704
|
+
(newValue) => {
|
|
2705
|
+
const clamped = snap(coerce(newValue));
|
|
2706
|
+
if (controlledValue === void 0) {
|
|
2707
|
+
setInternalValue(clamped);
|
|
2708
|
+
}
|
|
2709
|
+
onValueChange == null ? void 0 : onValueChange(clamped);
|
|
2710
|
+
},
|
|
2711
|
+
[coerce, controlledValue, onValueChange, snap]
|
|
2712
|
+
);
|
|
2713
|
+
const handleValueChangeEnd = React4.useCallback(
|
|
2714
|
+
(newValue) => {
|
|
2715
|
+
onValueChangeEnd == null ? void 0 : onValueChangeEnd(snap(coerce(newValue)));
|
|
2716
|
+
},
|
|
2717
|
+
[coerce, onValueChangeEnd, snap]
|
|
2718
|
+
);
|
|
2719
|
+
const handleTrackPointerDown = React4.useCallback(
|
|
2720
|
+
(e) => {
|
|
2721
|
+
if (disabled) return;
|
|
2722
|
+
const trackEl = trackRef.current;
|
|
2723
|
+
if (!trackEl) return;
|
|
2724
|
+
const rect = trackEl.getBoundingClientRect();
|
|
2725
|
+
let clickPercent;
|
|
2726
|
+
const insetLimit = SliderTokens.thumbGap + SliderTokens.thumbWidthDefault / 2;
|
|
2727
|
+
const trackInset = Math.min(
|
|
2728
|
+
SliderTokens.trackSizes[trackSize] / 2,
|
|
2729
|
+
insetLimit
|
|
2730
|
+
);
|
|
2731
|
+
if (isHorizontal) {
|
|
2732
|
+
const x = e.clientX - rect.left;
|
|
2733
|
+
clickPercent = (x - trackInset) / (rect.width - trackInset * 2);
|
|
2734
|
+
} else {
|
|
2735
|
+
const y = rect.bottom - e.clientY;
|
|
2736
|
+
clickPercent = (y - trackInset) / (rect.height - trackInset * 2);
|
|
2737
|
+
}
|
|
2738
|
+
const clamped = Math.max(0, Math.min(1, clickPercent));
|
|
2739
|
+
const rawValue = min + clamped * (max - min);
|
|
2740
|
+
const newValue = snap(coerce(rawValue));
|
|
2741
|
+
handleValueChange(newValue);
|
|
2742
|
+
},
|
|
2743
|
+
[
|
|
2744
|
+
coerce,
|
|
2745
|
+
disabled,
|
|
2746
|
+
handleValueChange,
|
|
2747
|
+
isHorizontal,
|
|
2748
|
+
max,
|
|
2749
|
+
min,
|
|
2750
|
+
snap,
|
|
2751
|
+
trackSize
|
|
2752
|
+
]
|
|
2753
|
+
);
|
|
2754
|
+
const id = React4.useId();
|
|
2755
|
+
const thumbId = `slider-thumb-${id}`;
|
|
2756
|
+
const supportsInsetIcon = !isCentered && SliderTokens.trackSizes[trackSize] >= 40;
|
|
2757
|
+
const hasAnyInsetIcon = !!(insetIcon || insetIconTrailing);
|
|
2758
|
+
if (hasAnyInsetIcon && !supportsInsetIcon) {
|
|
2759
|
+
console.warn(
|
|
2760
|
+
"[Slider] insetIcon is only supported on track sizes >= 40dp (e.g. xl track sizes). See MD3 spec: https://m3.material.io/components/sliders/specs"
|
|
2761
|
+
);
|
|
2762
|
+
}
|
|
2763
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs(
|
|
2764
|
+
"div",
|
|
2765
|
+
{
|
|
2766
|
+
ref,
|
|
2767
|
+
className: cn(
|
|
2768
|
+
"relative flex items-center",
|
|
2769
|
+
isHorizontal ? "w-full flex-row" : "h-full flex-col",
|
|
2770
|
+
disabled && "pointer-events-none",
|
|
2771
|
+
className
|
|
2772
|
+
),
|
|
2773
|
+
style: isHorizontal ? { minWidth: 0 } : { minHeight: 0 },
|
|
2774
|
+
children: [
|
|
2775
|
+
/* @__PURE__ */ jsx(
|
|
2776
|
+
SliderTrack,
|
|
2777
|
+
{
|
|
2778
|
+
percent,
|
|
2779
|
+
trackSize,
|
|
2780
|
+
trackShape,
|
|
2781
|
+
orientation,
|
|
2782
|
+
isCentered,
|
|
2783
|
+
min,
|
|
2784
|
+
max,
|
|
2785
|
+
disabled,
|
|
2786
|
+
variant,
|
|
2787
|
+
trackRef,
|
|
2788
|
+
onTrackPointerDown: handleTrackPointerDown,
|
|
2789
|
+
ticks: showTicks ? ticks : [],
|
|
2790
|
+
insetIcon: supportsInsetIcon ? insetIcon : void 0,
|
|
2791
|
+
insetIconAtMin: supportsInsetIcon ? insetIconAtMin : void 0,
|
|
2792
|
+
insetIconTrailing: supportsInsetIcon ? insetIconTrailing : void 0,
|
|
2793
|
+
insetIconAtMax: supportsInsetIcon ? insetIconAtMax : void 0,
|
|
2794
|
+
value: safeValue
|
|
2795
|
+
}
|
|
2796
|
+
),
|
|
2797
|
+
/* @__PURE__ */ jsx(
|
|
2798
|
+
SliderThumb,
|
|
2799
|
+
{
|
|
2800
|
+
value: safeValue,
|
|
2801
|
+
percent,
|
|
2802
|
+
min,
|
|
2803
|
+
max,
|
|
2804
|
+
step,
|
|
2805
|
+
disabled,
|
|
2806
|
+
orientation,
|
|
2807
|
+
trackSize,
|
|
2808
|
+
variant,
|
|
2809
|
+
showValueIndicator,
|
|
2810
|
+
trackRef,
|
|
2811
|
+
onValueChange: handleValueChange,
|
|
2812
|
+
onValueChangeEnd: handleValueChangeEnd,
|
|
2813
|
+
formatValue,
|
|
2814
|
+
thumbId,
|
|
2815
|
+
zIndex: 1,
|
|
2816
|
+
"aria-label": ariaLabel,
|
|
2817
|
+
"aria-labelledby": ariaLabelledBy
|
|
2818
|
+
}
|
|
2819
|
+
)
|
|
2820
|
+
]
|
|
2821
|
+
}
|
|
2822
|
+
) });
|
|
2823
|
+
}
|
|
2824
|
+
);
|
|
2825
|
+
SliderComponent.displayName = "Slider";
|
|
2826
|
+
var Slider = React4.memo(SliderComponent);
|
|
2827
|
+
|
|
2828
|
+
// src/ui/shared/motion-tokens.ts
|
|
2829
|
+
var FAST_SPATIAL_SPRING = {
|
|
2830
|
+
type: "spring",
|
|
2831
|
+
stiffness: 800,
|
|
2832
|
+
damping: 33.94
|
|
2833
|
+
};
|
|
2834
|
+
var FAST_EFFECTS_SPRING = {
|
|
2835
|
+
type: "spring",
|
|
2836
|
+
stiffness: 3800,
|
|
2837
|
+
damping: 123.29
|
|
2838
|
+
};
|
|
2839
|
+
|
|
2840
|
+
// src/ui/switch/switch.tokens.ts
|
|
2841
|
+
var SwitchTokens = {
|
|
2842
|
+
// ── Track ─────────────────────────────────────────────────────────────────
|
|
2843
|
+
/** SwitchTokens.TrackWidth = 52dp */
|
|
2844
|
+
trackWidth: 52,
|
|
2845
|
+
/** SwitchTokens.TrackHeight = 32dp */
|
|
2846
|
+
trackHeight: 32,
|
|
2847
|
+
/** SwitchTokens.TrackOutlineWidth = 2dp */
|
|
2848
|
+
trackOutlineWidth: 2,
|
|
2849
|
+
// ── Handle (Thumb) ────────────────────────────────────────────────────────
|
|
2850
|
+
/** SwitchTokens.SelectedHandleWidth/Height = 24dp */
|
|
2851
|
+
selectedHandleSize: 24,
|
|
2852
|
+
/** SwitchTokens.UnselectedHandleWidth/Height = 16dp */
|
|
2853
|
+
unselectedHandleSize: 16,
|
|
2854
|
+
/** SwitchTokens.IconHandleWidth/Height = 24dp (when thumb has icon content) */
|
|
2855
|
+
iconHandleSize: 24,
|
|
2856
|
+
/** SwitchTokens.PressedHandleWidth/Height = 28dp */
|
|
2857
|
+
pressedHandleSize: 28,
|
|
2858
|
+
// ── State Layer ───────────────────────────────────────────────────────────
|
|
2859
|
+
/** SwitchTokens.StateLayerSize = 40dp */
|
|
2860
|
+
stateLayerSize: 40,
|
|
2861
|
+
// ── Icon ──────────────────────────────────────────────────────────────────
|
|
2862
|
+
/** SwitchTokens.SelectedIconSize / UnselectedIconSize = 16dp */
|
|
2863
|
+
iconSize: 16,
|
|
2864
|
+
// ── Opacity (disabled states) ─────────────────────────────────────────────
|
|
2865
|
+
/** SwitchTokens.DisabledTrackOpacity = 0.12 */
|
|
2866
|
+
disabledTrackOpacity: 0.12,
|
|
2867
|
+
/** SwitchTokens.DisabledSelectedHandleOpacity = 1.0 */
|
|
2868
|
+
disabledSelectedHandleOpacity: 1,
|
|
2869
|
+
/** SwitchTokens.DisabledUnselectedHandleOpacity = 0.38 */
|
|
2870
|
+
disabledUnselectedHandleOpacity: 0.38,
|
|
2871
|
+
/** SwitchTokens.DisabledSelectedIconOpacity = 0.38 */
|
|
2872
|
+
disabledSelectedIconOpacity: 0.38,
|
|
2873
|
+
/** SwitchTokens.DisabledUnselectedIconOpacity = 0.38 */
|
|
2874
|
+
disabledUnselectedIconOpacity: 0.38
|
|
2875
|
+
};
|
|
2876
|
+
var SwitchColors = {
|
|
2877
|
+
// Track
|
|
2878
|
+
checkedTrack: "var(--md-sys-color-primary)",
|
|
2879
|
+
uncheckedTrack: "var(--md-sys-color-surface-container-highest)",
|
|
2880
|
+
uncheckedTrackOutline: "var(--md-sys-color-outline)",
|
|
2881
|
+
// Thumb
|
|
2882
|
+
checkedThumb: "var(--md-sys-color-on-primary)",
|
|
2883
|
+
uncheckedThumb: "var(--md-sys-color-outline)",
|
|
2884
|
+
hoverCheckedThumb: "var(--md-sys-color-primary-container)",
|
|
2885
|
+
hoverUncheckedThumb: "var(--md-sys-color-on-surface-variant)",
|
|
2886
|
+
disabledCheckedThumb: "var(--md-sys-color-surface)",
|
|
2887
|
+
// Icon
|
|
2888
|
+
checkedIcon: "var(--md-sys-color-on-primary-container)",
|
|
2889
|
+
uncheckedIcon: "var(--md-sys-color-surface-container-highest)",
|
|
2890
|
+
// State layer
|
|
2891
|
+
checkedStateLayer: "var(--md-sys-color-primary)",
|
|
2892
|
+
uncheckedStateLayer: "var(--md-sys-color-on-surface)",
|
|
2893
|
+
// Focus indicator
|
|
2894
|
+
focusIndicator: "var(--md-sys-color-secondary)"
|
|
2895
|
+
};
|
|
2896
|
+
var SNAP_TRANSITION = { duration: 0 };
|
|
2897
|
+
var COLOR_TRANSITION = {
|
|
2898
|
+
duration: 0.15,
|
|
2899
|
+
ease: [0.31, 0.94, 0.34, 1]
|
|
2900
|
+
};
|
|
2901
|
+
function resolveThumbSize(isPressed, checked, hasIcon) {
|
|
2902
|
+
if (isPressed) return SwitchTokens.pressedHandleSize;
|
|
2903
|
+
if (checked || hasIcon) return SwitchTokens.selectedHandleSize;
|
|
2904
|
+
return SwitchTokens.unselectedHandleSize;
|
|
2905
|
+
}
|
|
2906
|
+
function resolveThumbX(checked, isPressed, thumbSize) {
|
|
2907
|
+
const { trackHeight, trackWidth, trackOutlineWidth, selectedHandleSize } = SwitchTokens;
|
|
2908
|
+
const thumbPaddingStart = (trackHeight - thumbSize) / 2;
|
|
2909
|
+
const thumbPadding = (trackHeight - selectedHandleSize) / 2;
|
|
2910
|
+
const maxBound = trackWidth - selectedHandleSize - thumbPadding;
|
|
2911
|
+
if (isPressed && checked) return maxBound - trackOutlineWidth;
|
|
2912
|
+
if (isPressed) return thumbPaddingStart + trackOutlineWidth;
|
|
2913
|
+
if (checked) return maxBound;
|
|
2914
|
+
return thumbPaddingStart;
|
|
2915
|
+
}
|
|
2916
|
+
function resolveThumbColor(checked, disabled, isInteracting, checkedThumbColor, uncheckedThumbColor) {
|
|
2917
|
+
if (disabled) {
|
|
2918
|
+
return checked ? SwitchColors.disabledCheckedThumb : "rgba(28, 27, 31, 0.38)";
|
|
2919
|
+
}
|
|
2920
|
+
if (checked) {
|
|
2921
|
+
return isInteracting ? checkedThumbColor != null ? checkedThumbColor : SwitchColors.hoverCheckedThumb : checkedThumbColor != null ? checkedThumbColor : SwitchColors.checkedThumb;
|
|
2922
|
+
}
|
|
2923
|
+
return isInteracting ? uncheckedThumbColor != null ? uncheckedThumbColor : SwitchColors.hoverUncheckedThumb : uncheckedThumbColor != null ? uncheckedThumbColor : SwitchColors.uncheckedThumb;
|
|
2924
|
+
}
|
|
2925
|
+
function isIconVisible(thumbContent, icons, showOnlySelectedIcon, checked) {
|
|
2926
|
+
if (thumbContent == null) return false;
|
|
2927
|
+
if (icons) return true;
|
|
2928
|
+
return showOnlySelectedIcon && checked;
|
|
2929
|
+
}
|
|
2930
|
+
var SwitchVisual = React4.memo(function SwitchVisual2({
|
|
2931
|
+
checked,
|
|
2932
|
+
disabled,
|
|
2933
|
+
isPressed,
|
|
2934
|
+
isHovered,
|
|
2935
|
+
isFocused,
|
|
2936
|
+
thumbContent,
|
|
2937
|
+
icons,
|
|
2938
|
+
showOnlySelectedIcon,
|
|
2939
|
+
prefersReduced,
|
|
2940
|
+
checkedTrackColor,
|
|
2941
|
+
uncheckedTrackColor,
|
|
2942
|
+
checkedThumbColor,
|
|
2943
|
+
uncheckedThumbColor
|
|
2944
|
+
}) {
|
|
2945
|
+
const hasIcon = icons && thumbContent != null;
|
|
2946
|
+
const thumbSize = resolveThumbSize(isPressed, checked, hasIcon);
|
|
2947
|
+
const thumbX = resolveThumbX(checked, isPressed, thumbSize);
|
|
2948
|
+
const trackBg = checked ? checkedTrackColor != null ? checkedTrackColor : SwitchColors.checkedTrack : uncheckedTrackColor != null ? uncheckedTrackColor : SwitchColors.uncheckedTrack;
|
|
2949
|
+
const trackBorderColor = checked ? "rgba(0, 0, 0, 0)" : SwitchColors.uncheckedTrackOutline;
|
|
2950
|
+
const trackBorderWidth = checked ? 0 : SwitchTokens.trackOutlineWidth;
|
|
2951
|
+
const trackOpacity = disabled ? SwitchTokens.disabledTrackOpacity : 1;
|
|
2952
|
+
const isInteracting = isHovered || isFocused || isPressed;
|
|
2953
|
+
const thumbBg = resolveThumbColor(
|
|
2954
|
+
checked,
|
|
2955
|
+
disabled,
|
|
2956
|
+
isInteracting,
|
|
2957
|
+
checkedThumbColor,
|
|
2958
|
+
uncheckedThumbColor
|
|
2959
|
+
);
|
|
2960
|
+
const iconColor = disabled ? checked ? "rgba(28, 27, 31, 0.38)" : "rgba(230, 225, 229, 0.38)" : checked ? SwitchColors.checkedIcon : SwitchColors.uncheckedIcon;
|
|
2961
|
+
const stateLayerColor = checked ? SwitchColors.checkedStateLayer : SwitchColors.uncheckedStateLayer;
|
|
2962
|
+
const stateLayerOpacity = isPressed || isFocused ? 0.12 : isHovered ? 0.08 : 0;
|
|
2963
|
+
const stateLayerX = thumbX + thumbSize / 2 - SwitchTokens.stateLayerSize / 2;
|
|
2964
|
+
const showIcon = isIconVisible(
|
|
2965
|
+
thumbContent,
|
|
2966
|
+
icons,
|
|
2967
|
+
showOnlySelectedIcon,
|
|
2968
|
+
checked
|
|
2969
|
+
);
|
|
2970
|
+
const colorTransition = prefersReduced ? { duration: 0 } : COLOR_TRANSITION;
|
|
2971
|
+
const stateLayerTransition = prefersReduced ? { duration: 0 } : FAST_EFFECTS_SPRING;
|
|
2972
|
+
return /* @__PURE__ */ jsxs(
|
|
2973
|
+
"div",
|
|
2974
|
+
{
|
|
2975
|
+
className: "relative",
|
|
2976
|
+
style: {
|
|
2977
|
+
width: SwitchTokens.trackWidth,
|
|
2978
|
+
height: SwitchTokens.trackHeight
|
|
2979
|
+
},
|
|
2980
|
+
"aria-hidden": "true",
|
|
2981
|
+
children: [
|
|
2982
|
+
/* @__PURE__ */ jsx(
|
|
2983
|
+
m.div,
|
|
2984
|
+
{
|
|
2985
|
+
className: "absolute inset-0 rounded-full",
|
|
2986
|
+
style: { borderStyle: "solid", opacity: trackOpacity },
|
|
2987
|
+
animate: {
|
|
2988
|
+
backgroundColor: trackBg,
|
|
2989
|
+
borderColor: trackBorderColor,
|
|
2990
|
+
borderWidth: trackBorderWidth
|
|
2991
|
+
},
|
|
2992
|
+
transition: colorTransition
|
|
2993
|
+
}
|
|
2994
|
+
),
|
|
2995
|
+
/* @__PURE__ */ jsx(
|
|
2996
|
+
m.div,
|
|
2997
|
+
{
|
|
2998
|
+
className: "absolute rounded-full pointer-events-none",
|
|
2999
|
+
style: {
|
|
3000
|
+
width: SwitchTokens.stateLayerSize,
|
|
3001
|
+
height: SwitchTokens.stateLayerSize,
|
|
3002
|
+
top: (SwitchTokens.trackHeight - SwitchTokens.stateLayerSize) / 2,
|
|
3003
|
+
backgroundColor: stateLayerColor
|
|
3004
|
+
},
|
|
3005
|
+
animate: { x: stateLayerX, opacity: stateLayerOpacity },
|
|
3006
|
+
transition: stateLayerTransition
|
|
3007
|
+
}
|
|
3008
|
+
),
|
|
3009
|
+
/* @__PURE__ */ jsx(
|
|
3010
|
+
m.div,
|
|
3011
|
+
{
|
|
3012
|
+
className: "absolute rounded-full flex items-center justify-center overflow-hidden",
|
|
3013
|
+
style: { top: "50%", left: 0, y: "-50%" },
|
|
3014
|
+
animate: {
|
|
3015
|
+
x: thumbX,
|
|
3016
|
+
width: thumbSize,
|
|
3017
|
+
height: thumbSize,
|
|
3018
|
+
backgroundColor: thumbBg
|
|
3019
|
+
},
|
|
3020
|
+
transition: prefersReduced ? { duration: 0 } : isPressed ? SNAP_TRANSITION : {
|
|
3021
|
+
x: FAST_SPATIAL_SPRING,
|
|
3022
|
+
width: FAST_SPATIAL_SPRING,
|
|
3023
|
+
height: FAST_SPATIAL_SPRING,
|
|
3024
|
+
backgroundColor: colorTransition
|
|
3025
|
+
},
|
|
3026
|
+
children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: showIcon && /* @__PURE__ */ jsx(
|
|
3027
|
+
m.span,
|
|
3028
|
+
{
|
|
3029
|
+
className: "flex items-center justify-center",
|
|
3030
|
+
style: {
|
|
3031
|
+
width: SwitchTokens.iconSize,
|
|
3032
|
+
height: SwitchTokens.iconSize,
|
|
3033
|
+
color: iconColor,
|
|
3034
|
+
fontSize: SwitchTokens.iconSize
|
|
3035
|
+
},
|
|
3036
|
+
initial: prefersReduced ? false : { opacity: 0, scale: 0.5 },
|
|
3037
|
+
animate: { opacity: 1, scale: 1 },
|
|
3038
|
+
exit: prefersReduced ? {} : { opacity: 0, scale: 0.5 },
|
|
3039
|
+
transition: prefersReduced ? { duration: 0 } : { duration: 0.15 },
|
|
3040
|
+
children: thumbContent
|
|
3041
|
+
},
|
|
3042
|
+
checked ? "icon-on" : "icon-off"
|
|
3043
|
+
) })
|
|
3044
|
+
}
|
|
3045
|
+
)
|
|
3046
|
+
]
|
|
3047
|
+
}
|
|
3048
|
+
);
|
|
3049
|
+
});
|
|
3050
|
+
var SwitchComponent = React4.forwardRef(
|
|
3051
|
+
({
|
|
3052
|
+
checked,
|
|
3053
|
+
onCheckedChange,
|
|
3054
|
+
disabled = false,
|
|
3055
|
+
thumbContent,
|
|
3056
|
+
icons = false,
|
|
3057
|
+
showOnlySelectedIcon = false,
|
|
3058
|
+
label,
|
|
3059
|
+
ariaLabel,
|
|
3060
|
+
className,
|
|
3061
|
+
checkedTrackColor,
|
|
3062
|
+
uncheckedTrackColor,
|
|
3063
|
+
checkedThumbColor,
|
|
3064
|
+
uncheckedThumbColor
|
|
3065
|
+
}, ref) => {
|
|
3066
|
+
var _a;
|
|
3067
|
+
const prefersReduced = (_a = useReducedMotion()) != null ? _a : false;
|
|
3068
|
+
const [isPressed, setIsPressed] = React4.useState(false);
|
|
3069
|
+
const [isHovered, setIsHovered] = React4.useState(false);
|
|
3070
|
+
const [isFocused, setIsFocused] = React4.useState(false);
|
|
3071
|
+
const [ripples, setRipples] = React4.useState([]);
|
|
3072
|
+
const generatedId = React4.useId();
|
|
3073
|
+
const switchId = label ? `switch-${generatedId}` : void 0;
|
|
3074
|
+
const handleClick = React4.useCallback(() => {
|
|
3075
|
+
if (!disabled) onCheckedChange(!checked);
|
|
3076
|
+
}, [disabled, checked, onCheckedChange]);
|
|
3077
|
+
const handleKeyDown = React4.useCallback(
|
|
3078
|
+
(e) => {
|
|
3079
|
+
if (disabled) return;
|
|
3080
|
+
if (e.key === " " || e.key === "Enter") {
|
|
3081
|
+
e.preventDefault();
|
|
3082
|
+
onCheckedChange(!checked);
|
|
3083
|
+
}
|
|
3084
|
+
},
|
|
3085
|
+
[disabled, checked, onCheckedChange]
|
|
3086
|
+
);
|
|
3087
|
+
const handlePointerDown = React4.useCallback(
|
|
3088
|
+
(e) => {
|
|
3089
|
+
if (disabled) return;
|
|
3090
|
+
setIsPressed(true);
|
|
3091
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
3092
|
+
const x = e.clientX - rect.left;
|
|
3093
|
+
const y = e.clientY - rect.top;
|
|
3094
|
+
const rippleSize = Math.hypot(rect.width, rect.height) * 2;
|
|
3095
|
+
setRipples((prev) => [
|
|
3096
|
+
...prev,
|
|
3097
|
+
{ id: Date.now(), x, y, size: rippleSize }
|
|
3098
|
+
]);
|
|
3099
|
+
},
|
|
3100
|
+
[disabled]
|
|
3101
|
+
);
|
|
3102
|
+
const handlePointerUp = React4.useCallback(() => {
|
|
3103
|
+
setIsPressed(false);
|
|
3104
|
+
}, []);
|
|
3105
|
+
const handlePointerEnter = React4.useCallback(() => {
|
|
3106
|
+
if (!disabled) setIsHovered(true);
|
|
3107
|
+
}, [disabled]);
|
|
3108
|
+
const handlePointerLeave = React4.useCallback(() => {
|
|
3109
|
+
setIsHovered(false);
|
|
3110
|
+
setIsPressed(false);
|
|
3111
|
+
}, []);
|
|
3112
|
+
const handleFocus = React4.useCallback(() => setIsFocused(true), []);
|
|
3113
|
+
const handleBlur = React4.useCallback(() => setIsFocused(false), []);
|
|
3114
|
+
const removeRipple = React4.useCallback(
|
|
3115
|
+
(id) => setRipples((prev) => prev.filter((r) => r.id !== id)),
|
|
3116
|
+
[]
|
|
3117
|
+
);
|
|
3118
|
+
const buttonAriaLabel = label ? void 0 : ariaLabel;
|
|
3119
|
+
const switchButton = /* @__PURE__ */ jsx(
|
|
3120
|
+
"button",
|
|
3121
|
+
{
|
|
3122
|
+
ref,
|
|
3123
|
+
id: switchId,
|
|
3124
|
+
type: "button",
|
|
3125
|
+
role: "switch",
|
|
3126
|
+
"aria-checked": checked,
|
|
3127
|
+
"aria-disabled": disabled || void 0,
|
|
3128
|
+
"aria-label": buttonAriaLabel,
|
|
3129
|
+
tabIndex: disabled ? -1 : 0,
|
|
3130
|
+
disabled,
|
|
3131
|
+
onClick: handleClick,
|
|
3132
|
+
onKeyDown: handleKeyDown,
|
|
3133
|
+
onPointerDown: handlePointerDown,
|
|
3134
|
+
onPointerUp: handlePointerUp,
|
|
3135
|
+
onPointerLeave: handlePointerLeave,
|
|
3136
|
+
onPointerEnter: handlePointerEnter,
|
|
3137
|
+
onFocus: handleFocus,
|
|
3138
|
+
onBlur: handleBlur,
|
|
3139
|
+
className: cn(
|
|
3140
|
+
"relative inline-flex items-center justify-center cursor-pointer select-none",
|
|
3141
|
+
// Touch target: 48×48 minimum (pad around 32px track)
|
|
3142
|
+
"min-w-12 min-h-12",
|
|
3143
|
+
// Focus ring — MD3 FocusIndicatorColor = secondary
|
|
3144
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 rounded-full",
|
|
3145
|
+
"focus-visible:outline-(--md-sys-color-secondary)",
|
|
3146
|
+
// Disabled
|
|
3147
|
+
disabled && "pointer-events-none cursor-not-allowed",
|
|
3148
|
+
!label && className
|
|
3149
|
+
),
|
|
3150
|
+
children: /* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden rounded-full", children: [
|
|
3151
|
+
/* @__PURE__ */ jsx(
|
|
3152
|
+
SwitchVisual,
|
|
3153
|
+
{
|
|
3154
|
+
checked,
|
|
3155
|
+
disabled,
|
|
3156
|
+
isPressed,
|
|
3157
|
+
isHovered,
|
|
3158
|
+
isFocused,
|
|
3159
|
+
thumbContent,
|
|
3160
|
+
icons,
|
|
3161
|
+
showOnlySelectedIcon,
|
|
3162
|
+
prefersReduced,
|
|
3163
|
+
checkedTrackColor,
|
|
3164
|
+
uncheckedTrackColor,
|
|
3165
|
+
checkedThumbColor,
|
|
3166
|
+
uncheckedThumbColor
|
|
3167
|
+
}
|
|
3168
|
+
),
|
|
3169
|
+
/* @__PURE__ */ jsx(
|
|
3170
|
+
Ripple,
|
|
3171
|
+
{
|
|
3172
|
+
ripples,
|
|
3173
|
+
onRippleDone: removeRipple,
|
|
3174
|
+
disabled
|
|
3175
|
+
}
|
|
3176
|
+
)
|
|
3177
|
+
] })
|
|
3178
|
+
}
|
|
3179
|
+
);
|
|
3180
|
+
const content = label ? /* @__PURE__ */ jsxs(
|
|
3181
|
+
"label",
|
|
3182
|
+
{
|
|
3183
|
+
htmlFor: switchId,
|
|
3184
|
+
className: cn(
|
|
3185
|
+
"inline-flex items-center gap-3 cursor-pointer select-none",
|
|
3186
|
+
disabled && "cursor-not-allowed pointer-events-none opacity-[0.38]",
|
|
3187
|
+
className
|
|
3188
|
+
),
|
|
3189
|
+
children: [
|
|
3190
|
+
switchButton,
|
|
3191
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm leading-none text-(--md-sys-color-on-surface)", children: label })
|
|
3192
|
+
]
|
|
3193
|
+
}
|
|
3194
|
+
) : switchButton;
|
|
3195
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: content });
|
|
3196
|
+
}
|
|
3197
|
+
);
|
|
3198
|
+
SwitchComponent.displayName = "Switch";
|
|
3199
|
+
var Switch = React4.memo(SwitchComponent);
|
|
3200
|
+
var ScrollArea = React4.forwardRef(
|
|
3201
|
+
(_a, ref) => {
|
|
3202
|
+
var _b = _a, {
|
|
3203
|
+
className,
|
|
3204
|
+
viewportClassName,
|
|
3205
|
+
children,
|
|
3206
|
+
type = "hover",
|
|
3207
|
+
orientation = "vertical",
|
|
3208
|
+
scrollHideDelay = 600,
|
|
3209
|
+
viewportRef,
|
|
3210
|
+
viewportProps
|
|
3211
|
+
} = _b, props = __objRest(_b, [
|
|
3212
|
+
"className",
|
|
3213
|
+
"viewportClassName",
|
|
3214
|
+
"children",
|
|
3215
|
+
"type",
|
|
3216
|
+
"orientation",
|
|
3217
|
+
"scrollHideDelay",
|
|
3218
|
+
"viewportRef",
|
|
3219
|
+
"viewportProps"
|
|
3220
|
+
]);
|
|
3221
|
+
const [isTouchDevice, setIsTouchDevice] = React4.useState(false);
|
|
3222
|
+
React4.useEffect(() => {
|
|
3223
|
+
if (typeof window !== "undefined") {
|
|
3224
|
+
setIsTouchDevice(
|
|
3225
|
+
"ontouchstart" in window || navigator.maxTouchPoints > 0
|
|
3226
|
+
);
|
|
3227
|
+
}
|
|
3228
|
+
}, []);
|
|
3229
|
+
const resolvedType = React4.useMemo(() => {
|
|
3230
|
+
if (type === "hover" && isTouchDevice) {
|
|
3231
|
+
return "scroll";
|
|
3232
|
+
}
|
|
3233
|
+
return type;
|
|
3234
|
+
}, [type, isTouchDevice]);
|
|
3235
|
+
const radixType = resolvedType === "none" ? "always" : resolvedType;
|
|
3236
|
+
return /* @__PURE__ */ jsxs(
|
|
3237
|
+
RadixScrollArea.Root,
|
|
3238
|
+
__spreadProps(__spreadValues({
|
|
3239
|
+
ref,
|
|
3240
|
+
type: radixType,
|
|
3241
|
+
scrollHideDelay,
|
|
3242
|
+
className: cn("relative overflow-hidden flex flex-col", className)
|
|
3243
|
+
}, props), {
|
|
3244
|
+
children: [
|
|
3245
|
+
/* @__PURE__ */ jsx(
|
|
3246
|
+
RadixScrollArea.Viewport,
|
|
3247
|
+
__spreadProps(__spreadValues({
|
|
3248
|
+
ref: viewportRef
|
|
3249
|
+
}, viewportProps), {
|
|
3250
|
+
className: cn(
|
|
3251
|
+
"h-full w-full flex-1 min-h-0 min-w-0 rounded-[inherit]",
|
|
3252
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-m3-primary focus-visible:ring-offset-1",
|
|
3253
|
+
viewportClassName,
|
|
3254
|
+
viewportProps == null ? void 0 : viewportProps.className
|
|
3255
|
+
),
|
|
3256
|
+
children
|
|
3257
|
+
})
|
|
3258
|
+
),
|
|
3259
|
+
(orientation === "vertical" || orientation === "both") && /* @__PURE__ */ jsx(
|
|
3260
|
+
ScrollAreaScrollbar,
|
|
3261
|
+
{
|
|
3262
|
+
orientation: "vertical",
|
|
3263
|
+
className: resolvedType === "none" ? "hidden" : void 0
|
|
3264
|
+
}
|
|
3265
|
+
),
|
|
3266
|
+
(orientation === "horizontal" || orientation === "both") && /* @__PURE__ */ jsx(
|
|
3267
|
+
ScrollAreaScrollbar,
|
|
3268
|
+
{
|
|
3269
|
+
orientation: "horizontal",
|
|
3270
|
+
className: resolvedType === "none" ? "hidden" : void 0
|
|
3271
|
+
}
|
|
3272
|
+
),
|
|
3273
|
+
/* @__PURE__ */ jsx(RadixScrollArea.Corner, { className: "bg-m3-surface-container" })
|
|
3274
|
+
]
|
|
3275
|
+
})
|
|
3276
|
+
);
|
|
3277
|
+
}
|
|
3278
|
+
);
|
|
3279
|
+
ScrollArea.displayName = "ScrollArea";
|
|
3280
|
+
var ScrollAreaScrollbar = React4.forwardRef((_a, ref) => {
|
|
3281
|
+
var _b = _a, { className, orientation = "vertical" } = _b, props = __objRest(_b, ["className", "orientation"]);
|
|
3282
|
+
return /* @__PURE__ */ jsx(
|
|
3283
|
+
RadixScrollArea.Scrollbar,
|
|
3284
|
+
__spreadProps(__spreadValues({
|
|
3285
|
+
ref,
|
|
3286
|
+
orientation,
|
|
3287
|
+
className: cn(
|
|
3288
|
+
"flex touch-none select-none transition-all duration-300 ease-in-out",
|
|
3289
|
+
"absolute z-50",
|
|
3290
|
+
orientation === "vertical" && "right-0 top-0 bottom-0 w-2.5 border-l border-l-transparent p-px",
|
|
3291
|
+
orientation === "horizontal" && "bottom-0 left-0 right-0 h-2.5 flex-col border-t border-t-transparent p-px",
|
|
3292
|
+
"data-[state=hidden]:opacity-0 data-[state=visible]:opacity-100",
|
|
3293
|
+
className
|
|
3294
|
+
)
|
|
3295
|
+
}, props), {
|
|
3296
|
+
children: /* @__PURE__ */ jsx(
|
|
3297
|
+
RadixScrollArea.Thumb,
|
|
3298
|
+
{
|
|
3299
|
+
className: cn(
|
|
3300
|
+
"relative flex-1 rounded-full bg-m3-on-surface/25 transition-colors duration-200",
|
|
3301
|
+
"hover:bg-m3-on-surface/40 active:bg-m3-on-surface/55",
|
|
3302
|
+
"before:absolute before:left-1/2 before:top-1/2 before:min-h-11 before:min-w-11 before:-translate-x-1/2 before:-translate-y-1/2"
|
|
3303
|
+
)
|
|
3304
|
+
}
|
|
3305
|
+
)
|
|
3306
|
+
})
|
|
3307
|
+
);
|
|
3308
|
+
});
|
|
3309
|
+
ScrollAreaScrollbar.displayName = RadixScrollArea.Scrollbar.displayName;
|
|
3310
|
+
var ScrollAreaCorner = React4.forwardRef((_a, ref) => {
|
|
3311
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
3312
|
+
return /* @__PURE__ */ jsx(
|
|
3313
|
+
RadixScrollArea.Corner,
|
|
3314
|
+
__spreadValues({
|
|
3315
|
+
ref,
|
|
3316
|
+
className: cn("bg-m3-surface-container", className)
|
|
3317
|
+
}, props)
|
|
3318
|
+
);
|
|
3319
|
+
});
|
|
3320
|
+
ScrollAreaCorner.displayName = "ScrollAreaCorner";
|
|
3321
|
+
var ToolbarContext = React4.createContext(
|
|
3322
|
+
null
|
|
3323
|
+
);
|
|
3324
|
+
function useToolbarContext() {
|
|
3325
|
+
return React4.useContext(ToolbarContext);
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
// src/ui/shared/constants.ts
|
|
3329
|
+
var MD3_STANDARD_EASING = [
|
|
3330
|
+
0.2,
|
|
3331
|
+
0,
|
|
3332
|
+
0,
|
|
3333
|
+
1
|
|
3334
|
+
];
|
|
3335
|
+
var MD3_LABEL_FLOAT_DURATION = 0.15;
|
|
3336
|
+
var MD3_INDICATOR_DURATION = 0.2;
|
|
3337
|
+
var MD3_SUPPORTING_DURATION = 0.12;
|
|
3338
|
+
var MD3_ICON_SWAP_DURATION = 0.1;
|
|
3339
|
+
|
|
3340
|
+
// src/ui/text-field/text-field.tokens.ts
|
|
3341
|
+
var TF_COLORS = {
|
|
3342
|
+
/** Input text color */
|
|
3343
|
+
inputText: "var(--md-sys-color-on-surface)",
|
|
3344
|
+
/** Label (unfloated) + icons + prefix/suffix + supporting text */
|
|
3345
|
+
onSurfaceVariant: "var(--md-sys-color-on-surface-variant)",
|
|
3346
|
+
/** Focused active indicator / outline, floated label */
|
|
3347
|
+
primary: "var(--md-sys-color-primary)",
|
|
3348
|
+
/** Error indicator / outline / label / icon / supporting text */
|
|
3349
|
+
error: "var(--md-sys-color-error)",
|
|
3350
|
+
/** Outlined border (enabled) */
|
|
3351
|
+
outline: "var(--md-sys-color-outline)"};
|
|
3352
|
+
var TF_SIZE = {
|
|
3353
|
+
/** Container height — normal */
|
|
3354
|
+
height: 56,
|
|
3355
|
+
/** Container height — dense variant */
|
|
3356
|
+
denseHeight: 48,
|
|
3357
|
+
/** Active indicator height — enabled */
|
|
3358
|
+
indicatorThin: 1,
|
|
3359
|
+
/** Active indicator height — focused */
|
|
3360
|
+
indicatorThick: 2,
|
|
3361
|
+
/** Outline stroke width — enabled */
|
|
3362
|
+
outlineThin: 1,
|
|
3363
|
+
/** Outline stroke width — focused */
|
|
3364
|
+
outlineThick: 2,
|
|
3365
|
+
/** Padding inline start (no leading icon) */
|
|
3366
|
+
paddingStart: 16,
|
|
3367
|
+
/** Notch extra padding per side on outlined label gap */
|
|
3368
|
+
notchPadding: 4
|
|
3369
|
+
};
|
|
3370
|
+
var TF_TYPOGRAPHY = {
|
|
3371
|
+
/** Scale ratio when label floats: 12/16 = 0.75 */
|
|
3372
|
+
labelScaleRatio: 12 / 16
|
|
3373
|
+
};
|
|
3374
|
+
var TF_CLASSES = {
|
|
3375
|
+
// Prefix / Suffix
|
|
3376
|
+
prefixSuffix: "text-base text-[var(--md-sys-color-on-surface-variant)] select-none shrink-0"};
|
|
3377
|
+
var ActiveIndicator = React4.memo(function ActiveIndicator2({
|
|
3378
|
+
isFocused,
|
|
3379
|
+
isError,
|
|
3380
|
+
isDisabled,
|
|
3381
|
+
isHovered,
|
|
3382
|
+
prefersReduced
|
|
3383
|
+
}) {
|
|
3384
|
+
const duration = prefersReduced ? 0 : MD3_INDICATOR_DURATION;
|
|
3385
|
+
const ease = MD3_STANDARD_EASING;
|
|
3386
|
+
const height = isFocused || isError ? TF_SIZE.indicatorThick : TF_SIZE.indicatorThin;
|
|
3387
|
+
let backgroundColor;
|
|
3388
|
+
if (isError) {
|
|
3389
|
+
backgroundColor = TF_COLORS.error;
|
|
3390
|
+
} else if (isFocused) {
|
|
3391
|
+
backgroundColor = TF_COLORS.primary;
|
|
3392
|
+
} else if (isHovered && !isDisabled) {
|
|
3393
|
+
backgroundColor = TF_COLORS.inputText;
|
|
3394
|
+
} else {
|
|
3395
|
+
backgroundColor = TF_COLORS.onSurfaceVariant;
|
|
3396
|
+
}
|
|
3397
|
+
return /* @__PURE__ */ jsx(
|
|
3398
|
+
m.div,
|
|
3399
|
+
{
|
|
3400
|
+
"aria-hidden": "true",
|
|
3401
|
+
className: "absolute bottom-0 left-0 right-0 origin-center",
|
|
3402
|
+
animate: { height, backgroundColor },
|
|
3403
|
+
transition: { duration, ease }
|
|
3404
|
+
}
|
|
3405
|
+
);
|
|
3406
|
+
});
|
|
3407
|
+
ActiveIndicator.displayName = "ActiveIndicator";
|
|
3408
|
+
function getFloatedY(variant, containerHeight) {
|
|
3409
|
+
const labelSmallHeight = 16;
|
|
3410
|
+
const paddingTop = 8;
|
|
3411
|
+
if (variant === "filled") {
|
|
3412
|
+
const floatedCenter = paddingTop + labelSmallHeight / 2;
|
|
3413
|
+
const unfloatedCenter = containerHeight / 2;
|
|
3414
|
+
return -(unfloatedCenter - floatedCenter);
|
|
3415
|
+
}
|
|
3416
|
+
return -(containerHeight / 2);
|
|
3417
|
+
}
|
|
3418
|
+
function getLabelColor(isFloated, isFocused, isError, isDisabled) {
|
|
3419
|
+
if (isDisabled) return TF_COLORS.onSurfaceVariant;
|
|
3420
|
+
if (isError) return TF_COLORS.error;
|
|
3421
|
+
if (isFloated && isFocused) return TF_COLORS.primary;
|
|
3422
|
+
return TF_COLORS.onSurfaceVariant;
|
|
3423
|
+
}
|
|
3424
|
+
var FloatingLabel = React4.memo(function FloatingLabel2({
|
|
3425
|
+
text,
|
|
3426
|
+
isFloated,
|
|
3427
|
+
isFocused,
|
|
3428
|
+
isError,
|
|
3429
|
+
isDisabled,
|
|
3430
|
+
variant,
|
|
3431
|
+
containerHeight,
|
|
3432
|
+
prefersReduced,
|
|
3433
|
+
showAsterisk,
|
|
3434
|
+
htmlFor,
|
|
3435
|
+
labelRef,
|
|
3436
|
+
hasLeading = false
|
|
3437
|
+
}) {
|
|
3438
|
+
const duration = prefersReduced ? 0 : MD3_LABEL_FLOAT_DURATION;
|
|
3439
|
+
const ease = MD3_STANDARD_EASING;
|
|
3440
|
+
const y = isFloated ? getFloatedY(variant, containerHeight) : 0;
|
|
3441
|
+
const x = variant === "outlined" && isFloated && hasLeading ? -36 : 0;
|
|
3442
|
+
const scale = isFloated ? TF_TYPOGRAPHY.labelScaleRatio : 1;
|
|
3443
|
+
const color = getLabelColor(isFloated, isFocused, isError, isDisabled);
|
|
3444
|
+
return /* @__PURE__ */ jsx(
|
|
3445
|
+
m.label,
|
|
3446
|
+
{
|
|
3447
|
+
htmlFor,
|
|
3448
|
+
className: cn(
|
|
3449
|
+
"absolute pointer-events-none select-none origin-[left_center] leading-6 text-base whitespace-nowrap",
|
|
3450
|
+
"px-1 -mx-1",
|
|
3451
|
+
// Clear the notch gap and keep text aligned
|
|
3452
|
+
variant === "outlined" && isFloated && "bg-m3-surface",
|
|
3453
|
+
"left-4",
|
|
3454
|
+
isDisabled && "opacity-[0.38]"
|
|
3455
|
+
),
|
|
3456
|
+
animate: { y, x, scale, color },
|
|
3457
|
+
transition: { duration, ease },
|
|
3458
|
+
style: {
|
|
3459
|
+
top: (containerHeight - 24) / 2,
|
|
3460
|
+
// 24px is the resting line-height
|
|
3461
|
+
transformOrigin: "left center",
|
|
3462
|
+
zIndex: 1
|
|
3463
|
+
},
|
|
3464
|
+
children: /* @__PURE__ */ jsxs("span", { ref: labelRef, className: "inline-block relative", children: [
|
|
3465
|
+
text,
|
|
3466
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showAsterisk && /* @__PURE__ */ jsx(
|
|
3467
|
+
m.span,
|
|
3468
|
+
{
|
|
3469
|
+
"aria-hidden": "true",
|
|
3470
|
+
initial: { opacity: 0 },
|
|
3471
|
+
animate: { opacity: 1 },
|
|
3472
|
+
exit: { opacity: 0 },
|
|
3473
|
+
transition: { duration: prefersReduced ? 0 : 0.1 },
|
|
3474
|
+
className: "ml-0.5 text-m3-error",
|
|
3475
|
+
children: "*"
|
|
3476
|
+
},
|
|
3477
|
+
"asterisk"
|
|
3478
|
+
) })
|
|
3479
|
+
] })
|
|
3480
|
+
}
|
|
3481
|
+
);
|
|
3482
|
+
});
|
|
3483
|
+
FloatingLabel.displayName = "FloatingLabel";
|
|
3484
|
+
var LeadingIcon = React4.memo(function LeadingIcon2({
|
|
3485
|
+
children,
|
|
3486
|
+
isError,
|
|
3487
|
+
isDisabled
|
|
3488
|
+
}) {
|
|
3489
|
+
const color = isError && !isDisabled ? TF_COLORS.error : TF_COLORS.onSurfaceVariant;
|
|
3490
|
+
return /* @__PURE__ */ jsx(
|
|
3491
|
+
"div",
|
|
3492
|
+
{
|
|
3493
|
+
"aria-hidden": "true",
|
|
3494
|
+
className: "flex items-center justify-center shrink-0 w-6 h-6 ml-3",
|
|
3495
|
+
style: { color },
|
|
3496
|
+
children
|
|
3497
|
+
}
|
|
3498
|
+
);
|
|
3499
|
+
});
|
|
3500
|
+
LeadingIcon.displayName = "LeadingIcon";
|
|
3501
|
+
function getOutlineColor(isFocused, isError, isHovered, isDisabled) {
|
|
3502
|
+
if (isDisabled) return TF_COLORS.onSurfaceVariant;
|
|
3503
|
+
if (isError) return TF_COLORS.error;
|
|
3504
|
+
if (isFocused) return TF_COLORS.primary;
|
|
3505
|
+
if (isHovered) return TF_COLORS.inputText;
|
|
3506
|
+
return TF_COLORS.outline;
|
|
3507
|
+
}
|
|
3508
|
+
var OutlineContainer = React4.memo(function OutlineContainer2({
|
|
3509
|
+
isFloated,
|
|
3510
|
+
isFocused,
|
|
3511
|
+
isError,
|
|
3512
|
+
isDisabled,
|
|
3513
|
+
isHovered,
|
|
3514
|
+
labelWidth,
|
|
3515
|
+
prefersReduced
|
|
3516
|
+
}) {
|
|
3517
|
+
const colorDuration = prefersReduced ? 0 : MD3_INDICATOR_DURATION;
|
|
3518
|
+
const notchDuration = prefersReduced ? 0 : MD3_LABEL_FLOAT_DURATION;
|
|
3519
|
+
const ease = MD3_STANDARD_EASING;
|
|
3520
|
+
const borderColor = getOutlineColor(
|
|
3521
|
+
isFocused,
|
|
3522
|
+
isError,
|
|
3523
|
+
isHovered,
|
|
3524
|
+
isDisabled
|
|
3525
|
+
);
|
|
3526
|
+
const borderWidth = isFocused || isError ? TF_SIZE.outlineThick : TF_SIZE.outlineThin;
|
|
3527
|
+
const leftSegmentWidth = TF_SIZE.paddingStart;
|
|
3528
|
+
const notchWidth = isFloated ? labelWidth * TF_TYPOGRAPHY.labelScaleRatio + TF_SIZE.notchPadding * 2 : 0;
|
|
3529
|
+
const borderTransition = { duration: colorDuration, ease };
|
|
3530
|
+
const notchTransition = { duration: notchDuration, ease };
|
|
3531
|
+
return /* @__PURE__ */ jsxs(
|
|
3532
|
+
"div",
|
|
3533
|
+
{
|
|
3534
|
+
"aria-hidden": "true",
|
|
3535
|
+
className: "absolute inset-0 pointer-events-none flex rounded-[inherit]",
|
|
3536
|
+
children: [
|
|
3537
|
+
/* @__PURE__ */ jsx(
|
|
3538
|
+
m.div,
|
|
3539
|
+
{
|
|
3540
|
+
className: "rounded-tl-[inherit] rounded-bl-[inherit]",
|
|
3541
|
+
style: { width: leftSegmentWidth - TF_SIZE.notchPadding },
|
|
3542
|
+
animate: {
|
|
3543
|
+
borderColor,
|
|
3544
|
+
borderWidth,
|
|
3545
|
+
borderStyle: "solid",
|
|
3546
|
+
borderRightWidth: 0
|
|
3547
|
+
},
|
|
3548
|
+
transition: borderTransition
|
|
3549
|
+
}
|
|
3550
|
+
),
|
|
3551
|
+
/* @__PURE__ */ jsxs(
|
|
3552
|
+
m.div,
|
|
3553
|
+
{
|
|
3554
|
+
className: "flex flex-col shrink-0",
|
|
3555
|
+
style: { minWidth: 0 },
|
|
3556
|
+
animate: { width: notchWidth },
|
|
3557
|
+
transition: notchTransition,
|
|
3558
|
+
children: [
|
|
3559
|
+
/* @__PURE__ */ jsx(
|
|
3560
|
+
m.div,
|
|
3561
|
+
{
|
|
3562
|
+
className: "shrink-0",
|
|
3563
|
+
style: { height: borderWidth },
|
|
3564
|
+
animate: {
|
|
3565
|
+
borderTopColor: borderColor,
|
|
3566
|
+
opacity: isFloated ? 0 : 1,
|
|
3567
|
+
borderTopWidth: borderWidth,
|
|
3568
|
+
borderTopStyle: "solid"
|
|
3569
|
+
},
|
|
3570
|
+
transition: borderTransition
|
|
3571
|
+
}
|
|
3572
|
+
),
|
|
3573
|
+
/* @__PURE__ */ jsx(
|
|
3574
|
+
m.div,
|
|
3575
|
+
{
|
|
3576
|
+
className: "flex-1",
|
|
3577
|
+
animate: {
|
|
3578
|
+
borderBottomColor: borderColor,
|
|
3579
|
+
borderBottomWidth: borderWidth,
|
|
3580
|
+
borderBottomStyle: "solid"
|
|
3581
|
+
},
|
|
3582
|
+
transition: borderTransition
|
|
3583
|
+
}
|
|
3584
|
+
)
|
|
3585
|
+
]
|
|
3586
|
+
}
|
|
3587
|
+
),
|
|
3588
|
+
/* @__PURE__ */ jsx(
|
|
3589
|
+
m.div,
|
|
3590
|
+
{
|
|
3591
|
+
className: "flex-1 rounded-tr-[inherit] rounded-br-[inherit]",
|
|
3592
|
+
animate: {
|
|
3593
|
+
borderColor,
|
|
3594
|
+
borderWidth,
|
|
3595
|
+
borderStyle: "solid",
|
|
3596
|
+
borderLeftWidth: 0
|
|
3597
|
+
},
|
|
3598
|
+
transition: borderTransition
|
|
3599
|
+
}
|
|
3600
|
+
)
|
|
3601
|
+
]
|
|
3602
|
+
}
|
|
3603
|
+
);
|
|
3604
|
+
});
|
|
3605
|
+
OutlineContainer.displayName = "OutlineContainer";
|
|
3606
|
+
var PrefixSuffix = React4.memo(function PrefixSuffix2({
|
|
3607
|
+
text,
|
|
3608
|
+
type,
|
|
3609
|
+
visible,
|
|
3610
|
+
prefersReduced
|
|
3611
|
+
}) {
|
|
3612
|
+
const duration = prefersReduced ? 0 : MD3_LABEL_FLOAT_DURATION;
|
|
3613
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: visible && /* @__PURE__ */ jsx(
|
|
3614
|
+
m.span,
|
|
3615
|
+
{
|
|
3616
|
+
"aria-hidden": "true",
|
|
3617
|
+
className: `${TF_CLASSES.prefixSuffix} ${type === "suffix" ? "ml-0.5" : "mr-0.5"}`,
|
|
3618
|
+
initial: { opacity: 0 },
|
|
3619
|
+
animate: { opacity: 1 },
|
|
3620
|
+
exit: { opacity: 0 },
|
|
3621
|
+
transition: { duration, ease: MD3_STANDARD_EASING },
|
|
3622
|
+
children: text
|
|
3623
|
+
}
|
|
3624
|
+
) });
|
|
3625
|
+
});
|
|
3626
|
+
PrefixSuffix.displayName = "PrefixSuffix";
|
|
3627
|
+
function AnimatedText({
|
|
3628
|
+
text,
|
|
3629
|
+
motionKey,
|
|
3630
|
+
className,
|
|
3631
|
+
ariaLive,
|
|
3632
|
+
duration
|
|
3633
|
+
}) {
|
|
3634
|
+
return /* @__PURE__ */ jsx(
|
|
3635
|
+
m.span,
|
|
3636
|
+
{
|
|
3637
|
+
className,
|
|
3638
|
+
initial: { opacity: 0, y: -4 },
|
|
3639
|
+
animate: { opacity: 1, y: 0 },
|
|
3640
|
+
exit: { opacity: 0, y: -4 },
|
|
3641
|
+
transition: { duration, ease: MD3_STANDARD_EASING },
|
|
3642
|
+
"aria-live": ariaLive,
|
|
3643
|
+
children: text
|
|
3644
|
+
},
|
|
3645
|
+
motionKey
|
|
3646
|
+
);
|
|
3647
|
+
}
|
|
3648
|
+
var SupportingText = React4.memo(function SupportingText2({
|
|
3649
|
+
supportingText,
|
|
3650
|
+
errorText,
|
|
3651
|
+
isError,
|
|
3652
|
+
charCount,
|
|
3653
|
+
maxLength,
|
|
3654
|
+
id,
|
|
3655
|
+
prefersReduced
|
|
3656
|
+
}) {
|
|
3657
|
+
const duration = prefersReduced ? 0 : MD3_SUPPORTING_DURATION;
|
|
3658
|
+
const activeText = isError && errorText ? errorText : supportingText;
|
|
3659
|
+
const isOverLimit = maxLength !== void 0 && (charCount != null ? charCount : 0) > maxLength;
|
|
3660
|
+
const counterColor = isOverLimit ? TF_COLORS.error : TF_COLORS.onSurfaceVariant;
|
|
3661
|
+
if (!activeText && maxLength === void 0) return null;
|
|
3662
|
+
return /* @__PURE__ */ jsxs(
|
|
3663
|
+
m.div,
|
|
3664
|
+
{
|
|
3665
|
+
className: "flex items-start justify-between gap-2 mt-1 px-4",
|
|
3666
|
+
initial: { opacity: 0, height: 0 },
|
|
3667
|
+
animate: { opacity: 1, height: "auto" },
|
|
3668
|
+
exit: { opacity: 0, height: 0 },
|
|
3669
|
+
transition: { duration, ease: MD3_STANDARD_EASING },
|
|
3670
|
+
children: [
|
|
3671
|
+
/* @__PURE__ */ jsx("div", { id, className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: activeText && /* @__PURE__ */ jsx(
|
|
3672
|
+
AnimatedText,
|
|
3673
|
+
{
|
|
3674
|
+
motionKey: isError && errorText ? `error-${errorText}` : `helper-${supportingText}`,
|
|
3675
|
+
text: activeText,
|
|
3676
|
+
className: `text-xs leading-4 block ${isError ? "text-m3-error" : "text-m3-on-surface-variant"}`,
|
|
3677
|
+
ariaLive: "polite",
|
|
3678
|
+
duration
|
|
3679
|
+
},
|
|
3680
|
+
isError && errorText ? "error" : "helper"
|
|
3681
|
+
) }) }),
|
|
3682
|
+
maxLength !== void 0 && typeof charCount === "number" && /* @__PURE__ */ jsxs(
|
|
3683
|
+
m.span,
|
|
3684
|
+
{
|
|
3685
|
+
className: "text-xs leading-4 tabular-nums shrink-0",
|
|
3686
|
+
animate: { color: counterColor },
|
|
3687
|
+
transition: { duration, ease: MD3_STANDARD_EASING },
|
|
3688
|
+
"aria-live": "polite",
|
|
3689
|
+
"aria-atomic": "true",
|
|
3690
|
+
children: [
|
|
3691
|
+
charCount,
|
|
3692
|
+
" / ",
|
|
3693
|
+
maxLength
|
|
3694
|
+
]
|
|
3695
|
+
}
|
|
3696
|
+
)
|
|
3697
|
+
]
|
|
3698
|
+
}
|
|
3699
|
+
);
|
|
3700
|
+
});
|
|
3701
|
+
SupportingText.displayName = "SupportingText";
|
|
3702
|
+
function AnimatedIconSlot({
|
|
3703
|
+
children,
|
|
3704
|
+
motionKey,
|
|
3705
|
+
duration
|
|
3706
|
+
}) {
|
|
3707
|
+
return /* @__PURE__ */ jsx(
|
|
3708
|
+
m.span,
|
|
3709
|
+
{
|
|
3710
|
+
className: "flex items-center justify-center",
|
|
3711
|
+
initial: { opacity: 0, scale: 0 },
|
|
3712
|
+
animate: { opacity: 1, scale: 1 },
|
|
3713
|
+
exit: { opacity: 0, scale: 0 },
|
|
3714
|
+
transition: { duration, ease: MD3_STANDARD_EASING },
|
|
3715
|
+
children
|
|
3716
|
+
},
|
|
3717
|
+
motionKey
|
|
3718
|
+
);
|
|
3719
|
+
}
|
|
3720
|
+
function EyeOpenIcon() {
|
|
3721
|
+
return /* @__PURE__ */ jsx(
|
|
3722
|
+
"svg",
|
|
3723
|
+
{
|
|
3724
|
+
width: "24",
|
|
3725
|
+
height: "24",
|
|
3726
|
+
viewBox: "0 0 24 24",
|
|
3727
|
+
fill: "currentColor",
|
|
3728
|
+
"aria-hidden": "true",
|
|
3729
|
+
children: /* @__PURE__ */ jsx("path", { d: "M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" })
|
|
3730
|
+
}
|
|
3731
|
+
);
|
|
3732
|
+
}
|
|
3733
|
+
function EyeOffIcon() {
|
|
3734
|
+
return /* @__PURE__ */ jsx(
|
|
3735
|
+
"svg",
|
|
3736
|
+
{
|
|
3737
|
+
width: "24",
|
|
3738
|
+
height: "24",
|
|
3739
|
+
viewBox: "0 0 24 24",
|
|
3740
|
+
fill: "currentColor",
|
|
3741
|
+
"aria-hidden": "true",
|
|
3742
|
+
children: /* @__PURE__ */ jsx("path", { d: "M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z" })
|
|
3743
|
+
}
|
|
3744
|
+
);
|
|
3745
|
+
}
|
|
3746
|
+
function ClearIcon() {
|
|
3747
|
+
return /* @__PURE__ */ jsx(
|
|
3748
|
+
"svg",
|
|
3749
|
+
{
|
|
3750
|
+
width: "20",
|
|
3751
|
+
height: "20",
|
|
3752
|
+
viewBox: "0 0 24 24",
|
|
3753
|
+
fill: "currentColor",
|
|
3754
|
+
"aria-hidden": "true",
|
|
3755
|
+
children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
3756
|
+
}
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3759
|
+
var TrailingIcon = React4.memo(function TrailingIcon2({
|
|
3760
|
+
mode,
|
|
3761
|
+
children,
|
|
3762
|
+
value,
|
|
3763
|
+
showPassword = false,
|
|
3764
|
+
onClear,
|
|
3765
|
+
onPasswordToggle,
|
|
3766
|
+
isError,
|
|
3767
|
+
isDisabled,
|
|
3768
|
+
prefersReduced
|
|
3769
|
+
}) {
|
|
3770
|
+
const duration = prefersReduced ? 0 : MD3_ICON_SWAP_DURATION;
|
|
3771
|
+
const iconColor = isError && !isDisabled ? TF_COLORS.error : TF_COLORS.onSurfaceVariant;
|
|
3772
|
+
const btnClass = "relative flex items-center justify-center w-12 h-12 -mr-1 rounded-full cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-m3-primary)] transition-colors hover:bg-[var(--color-m3-on-surface)]/8 active:bg-[var(--color-m3-on-surface)]/12 disabled:pointer-events-none";
|
|
3773
|
+
if (mode === "clear") {
|
|
3774
|
+
const hasValue = value.length > 0;
|
|
3775
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: hasValue && /* @__PURE__ */ jsx(AnimatedIconSlot, { motionKey: "clear", duration, children: /* @__PURE__ */ jsx(
|
|
3776
|
+
"button",
|
|
3777
|
+
{
|
|
3778
|
+
type: "button",
|
|
3779
|
+
"aria-label": "Clear input",
|
|
3780
|
+
onClick: onClear,
|
|
3781
|
+
disabled: isDisabled,
|
|
3782
|
+
tabIndex: isDisabled ? -1 : 0,
|
|
3783
|
+
className: btnClass,
|
|
3784
|
+
style: { color: iconColor },
|
|
3785
|
+
children: /* @__PURE__ */ jsx(ClearIcon, {})
|
|
3786
|
+
}
|
|
3787
|
+
) }) });
|
|
3788
|
+
}
|
|
3789
|
+
if (mode === "password-toggle") {
|
|
3790
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
|
|
3791
|
+
AnimatedIconSlot,
|
|
3792
|
+
{
|
|
3793
|
+
motionKey: showPassword ? "eye-off" : "eye-on",
|
|
3794
|
+
duration,
|
|
3795
|
+
children: /* @__PURE__ */ jsx(
|
|
3796
|
+
"button",
|
|
3797
|
+
{
|
|
3798
|
+
type: "button",
|
|
3799
|
+
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
3800
|
+
onClick: onPasswordToggle,
|
|
3801
|
+
disabled: isDisabled,
|
|
3802
|
+
tabIndex: isDisabled ? -1 : 0,
|
|
3803
|
+
className: btnClass,
|
|
3804
|
+
style: { color: iconColor },
|
|
3805
|
+
children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeOpenIcon, {})
|
|
3806
|
+
}
|
|
3807
|
+
)
|
|
3808
|
+
}
|
|
3809
|
+
) });
|
|
3810
|
+
}
|
|
3811
|
+
if (mode === "custom" && children) {
|
|
3812
|
+
return /* @__PURE__ */ jsx(
|
|
3813
|
+
"div",
|
|
3814
|
+
{
|
|
3815
|
+
className: "flex items-center justify-center w-6 h-6 mr-3",
|
|
3816
|
+
style: { color: iconColor },
|
|
3817
|
+
children
|
|
3818
|
+
}
|
|
3819
|
+
);
|
|
3820
|
+
}
|
|
3821
|
+
return null;
|
|
3822
|
+
});
|
|
3823
|
+
TrailingIcon.displayName = "TrailingIcon";
|
|
3824
|
+
var LINE_HEIGHT_PX = 24;
|
|
3825
|
+
var TextFieldComponent = React4.forwardRef(
|
|
3826
|
+
({
|
|
3827
|
+
// Core
|
|
3828
|
+
variant = "filled",
|
|
3829
|
+
label,
|
|
3830
|
+
value: valueProp,
|
|
3831
|
+
defaultValue = "",
|
|
3832
|
+
onChange,
|
|
3833
|
+
// Input config
|
|
3834
|
+
type = "text",
|
|
3835
|
+
placeholder,
|
|
3836
|
+
name,
|
|
3837
|
+
id: idProp,
|
|
3838
|
+
autoComplete,
|
|
3839
|
+
inputMode,
|
|
3840
|
+
autoResize = false,
|
|
3841
|
+
maxRows,
|
|
3842
|
+
rows = autoResize ? 1 : 2,
|
|
3843
|
+
cols,
|
|
3844
|
+
textDirection,
|
|
3845
|
+
// Validation
|
|
3846
|
+
required = false,
|
|
3847
|
+
noAsterisk = false,
|
|
3848
|
+
error: errorProp = false,
|
|
3849
|
+
errorText,
|
|
3850
|
+
minLength,
|
|
3851
|
+
maxLength,
|
|
3852
|
+
min,
|
|
3853
|
+
max,
|
|
3854
|
+
step,
|
|
3855
|
+
pattern,
|
|
3856
|
+
multiple,
|
|
3857
|
+
// Supporting text
|
|
3858
|
+
supportingText,
|
|
3859
|
+
// Decorators
|
|
3860
|
+
prefixText,
|
|
3861
|
+
suffixText,
|
|
3862
|
+
leadingIcon,
|
|
3863
|
+
trailingIcon,
|
|
3864
|
+
trailingIconMode = "none",
|
|
3865
|
+
// States
|
|
3866
|
+
disabled = false,
|
|
3867
|
+
readOnly = false,
|
|
3868
|
+
noSpinner = false,
|
|
3869
|
+
// Form
|
|
3870
|
+
form,
|
|
3871
|
+
// Accessibility
|
|
3872
|
+
"aria-label": ariaLabel,
|
|
3873
|
+
"aria-describedby": ariaDescribedby,
|
|
3874
|
+
"aria-labelledby": ariaLabelledby,
|
|
3875
|
+
// Layout
|
|
3876
|
+
className,
|
|
3877
|
+
fullWidth = true,
|
|
3878
|
+
dense = false,
|
|
3879
|
+
// ScrollArea
|
|
3880
|
+
scrollAreaType = "hover",
|
|
3881
|
+
// Callbacks
|
|
3882
|
+
onFocus,
|
|
3883
|
+
onBlur,
|
|
3884
|
+
onKeyDown,
|
|
3885
|
+
onKeyUp
|
|
3886
|
+
}, ref) => {
|
|
3887
|
+
var _a;
|
|
3888
|
+
const prefersReduced = (_a = useReducedMotion()) != null ? _a : false;
|
|
3889
|
+
const toolbarContext = useToolbarContext();
|
|
3890
|
+
const isInToolbar = !!toolbarContext;
|
|
3891
|
+
const resolvedDense = isInToolbar ? true : dense;
|
|
3892
|
+
const resolvedLabel = isInToolbar ? void 0 : label;
|
|
3893
|
+
const generatedId = React4.useId();
|
|
3894
|
+
const inputId = idProp != null ? idProp : `tf-${generatedId}`;
|
|
3895
|
+
const supportingId = `${inputId}-supporting`;
|
|
3896
|
+
const isControlled = valueProp !== void 0;
|
|
3897
|
+
const [internalValue, setInternalValue] = React4.useState(defaultValue);
|
|
3898
|
+
const currentValue = isControlled ? valueProp : internalValue;
|
|
3899
|
+
const [isFocused, setIsFocused] = React4.useState(false);
|
|
3900
|
+
const [showPassword, setShowPassword] = React4.useState(false);
|
|
3901
|
+
const resolvedInputType = type === "password" && showPassword ? "text" : type;
|
|
3902
|
+
const [nativeError, setNativeError] = React4.useState("");
|
|
3903
|
+
const [labelWidth, setLabelWidth] = React4.useState(0);
|
|
3904
|
+
const hasValue = currentValue.length > 0;
|
|
3905
|
+
const isFloated = isFocused || hasValue;
|
|
3906
|
+
const isError = errorProp || !!nativeError || maxLength !== void 0 && currentValue.length > maxLength;
|
|
3907
|
+
const containerHeight = resolvedDense ? TF_SIZE.denseHeight : TF_SIZE.height;
|
|
3908
|
+
const showAsterisk = required && !noAsterisk;
|
|
3909
|
+
const inputRef = React4.useRef(null);
|
|
3910
|
+
const labelSpanRef = React4.useRef(null);
|
|
3911
|
+
React4.useLayoutEffect(() => {
|
|
3912
|
+
if (labelSpanRef.current) {
|
|
3913
|
+
setLabelWidth(labelSpanRef.current.offsetWidth);
|
|
3914
|
+
}
|
|
3915
|
+
}, []);
|
|
3916
|
+
React4.useLayoutEffect(() => {
|
|
3917
|
+
if (type !== "textarea" || !inputRef.current) return;
|
|
3918
|
+
const textarea = inputRef.current;
|
|
3919
|
+
if (autoResize) {
|
|
3920
|
+
textarea.style.height = "auto";
|
|
3921
|
+
textarea.style.height = `${textarea.scrollHeight}px`;
|
|
3922
|
+
if (maxRows) {
|
|
3923
|
+
textarea.style.maxHeight = `${maxRows * LINE_HEIGHT_PX}px`;
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
textarea.style.overflowY = "hidden";
|
|
3927
|
+
}, [type, autoResize, maxRows, currentValue]);
|
|
3928
|
+
const handleValueChange = React4.useCallback(
|
|
3929
|
+
(newValue) => {
|
|
3930
|
+
var _a2, _b;
|
|
3931
|
+
if (!isControlled) setInternalValue(newValue);
|
|
3932
|
+
setNativeError("");
|
|
3933
|
+
(_b = (_a2 = inputRef.current) == null ? void 0 : _a2.setCustomValidity) == null ? void 0 : _b.call(_a2, "");
|
|
3934
|
+
},
|
|
3935
|
+
[isControlled]
|
|
3936
|
+
);
|
|
3937
|
+
const handleChange = React4.useCallback(
|
|
3938
|
+
(e) => {
|
|
3939
|
+
const newVal = e.target.value;
|
|
3940
|
+
handleValueChange(newVal);
|
|
3941
|
+
onChange == null ? void 0 : onChange(newVal, e);
|
|
3942
|
+
},
|
|
3943
|
+
[handleValueChange, onChange]
|
|
3944
|
+
);
|
|
3945
|
+
const handleFocus = React4.useCallback(
|
|
3946
|
+
(e) => {
|
|
3947
|
+
setIsFocused(true);
|
|
3948
|
+
onFocus == null ? void 0 : onFocus(e);
|
|
3949
|
+
},
|
|
3950
|
+
[onFocus]
|
|
3951
|
+
);
|
|
3952
|
+
const handleBlur = React4.useCallback(
|
|
3953
|
+
(e) => {
|
|
3954
|
+
setIsFocused(false);
|
|
3955
|
+
const el = inputRef.current;
|
|
3956
|
+
if (el && !el.validity.valid) {
|
|
3957
|
+
setNativeError(el.validationMessage);
|
|
3958
|
+
} else {
|
|
3959
|
+
setNativeError("");
|
|
3960
|
+
}
|
|
3961
|
+
onBlur == null ? void 0 : onBlur(e);
|
|
3962
|
+
},
|
|
3963
|
+
[onBlur]
|
|
3964
|
+
);
|
|
3965
|
+
const handleClear = React4.useCallback(() => {
|
|
3966
|
+
var _a2;
|
|
3967
|
+
handleValueChange("");
|
|
3968
|
+
onChange == null ? void 0 : onChange("", {
|
|
3969
|
+
target: { value: "" }
|
|
3970
|
+
});
|
|
3971
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
3972
|
+
}, [handleValueChange, onChange]);
|
|
3973
|
+
const handlePasswordToggle = React4.useCallback(() => {
|
|
3974
|
+
var _a2;
|
|
3975
|
+
setShowPassword((prev) => !prev);
|
|
3976
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
3977
|
+
}, []);
|
|
3978
|
+
React4.useImperativeHandle(
|
|
3979
|
+
ref,
|
|
3980
|
+
() => ({
|
|
3981
|
+
focus: () => {
|
|
3982
|
+
var _a2;
|
|
3983
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
3984
|
+
},
|
|
3985
|
+
blur: () => {
|
|
3986
|
+
var _a2;
|
|
3987
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.blur();
|
|
3988
|
+
},
|
|
3989
|
+
select: () => {
|
|
3990
|
+
var _a2, _b;
|
|
3991
|
+
return (_b = (_a2 = inputRef.current) == null ? void 0 : _a2.select) == null ? void 0 : _b.call(_a2);
|
|
3992
|
+
},
|
|
3993
|
+
clear: () => handleValueChange(""),
|
|
3994
|
+
setCustomValidity: (msg) => {
|
|
3995
|
+
var _a2, _b;
|
|
3996
|
+
return (_b = (_a2 = inputRef.current) == null ? void 0 : _a2.setCustomValidity) == null ? void 0 : _b.call(_a2, msg);
|
|
3997
|
+
},
|
|
3998
|
+
checkValidity: () => {
|
|
3999
|
+
var _a2, _b, _c;
|
|
4000
|
+
return (_c = (_b = (_a2 = inputRef.current) == null ? void 0 : _a2.checkValidity) == null ? void 0 : _b.call(_a2)) != null ? _c : true;
|
|
4001
|
+
},
|
|
4002
|
+
reportValidity: () => {
|
|
4003
|
+
var _a2, _b, _c;
|
|
4004
|
+
const el = inputRef.current;
|
|
4005
|
+
const valid = (_b = (_a2 = el == null ? void 0 : el.reportValidity) == null ? void 0 : _a2.call(el)) != null ? _b : true;
|
|
4006
|
+
if (!valid) setNativeError((_c = el == null ? void 0 : el.validationMessage) != null ? _c : "");
|
|
4007
|
+
return valid;
|
|
4008
|
+
},
|
|
4009
|
+
getValue: () => currentValue,
|
|
4010
|
+
getInputElement: () => inputRef.current
|
|
4011
|
+
}),
|
|
4012
|
+
[currentValue, handleValueChange]
|
|
4013
|
+
);
|
|
4014
|
+
const hasSupporting = !!(supportingText || errorText || maxLength !== void 0);
|
|
4015
|
+
const computedDescribedby = [hasSupporting ? supportingId : "", ariaDescribedby != null ? ariaDescribedby : ""].filter(Boolean).join(" ") || void 0;
|
|
4016
|
+
const inputClass = cn(
|
|
4017
|
+
"bg-transparent outline-none w-full",
|
|
4018
|
+
isInToolbar ? "self-center" : "self-end",
|
|
4019
|
+
"text-base leading-6 text-m3-on-surface",
|
|
4020
|
+
"caret-[var(--color-m3-primary)]",
|
|
4021
|
+
"placeholder:text-m3-on-surface-variant/60",
|
|
4022
|
+
noSpinner && type === "number" && "[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
|
|
4023
|
+
disabled && "cursor-not-allowed"
|
|
4024
|
+
);
|
|
4025
|
+
const inputProps = {
|
|
4026
|
+
id: inputId,
|
|
4027
|
+
name,
|
|
4028
|
+
value: currentValue,
|
|
4029
|
+
placeholder: isFloated ? placeholder != null ? placeholder : "" : "",
|
|
4030
|
+
disabled,
|
|
4031
|
+
readOnly,
|
|
4032
|
+
required,
|
|
4033
|
+
minLength,
|
|
4034
|
+
maxLength,
|
|
4035
|
+
autoComplete,
|
|
4036
|
+
inputMode,
|
|
4037
|
+
form,
|
|
4038
|
+
"aria-label": ariaLabel,
|
|
4039
|
+
"aria-labelledby": ariaLabelledby,
|
|
4040
|
+
"aria-describedby": computedDescribedby,
|
|
4041
|
+
"aria-invalid": isError || void 0,
|
|
4042
|
+
"aria-required": required || void 0,
|
|
4043
|
+
onChange: handleChange,
|
|
4044
|
+
onFocus: handleFocus,
|
|
4045
|
+
onBlur: handleBlur,
|
|
4046
|
+
onKeyDown,
|
|
4047
|
+
onKeyUp
|
|
4048
|
+
};
|
|
4049
|
+
const hasLeading = !!leadingIcon;
|
|
4050
|
+
const paddingStart = "pl-4";
|
|
4051
|
+
const paddingEnd = "pr-4";
|
|
4052
|
+
const containerClass = cn(
|
|
4053
|
+
"relative flex items-center",
|
|
4054
|
+
variant === "filled" ? isInToolbar ? "bg-transparent" : "bg-[var(--color-m3-surface-container-highest)] rounded-tl-sm rounded-tr-sm" : "bg-transparent rounded-sm",
|
|
4055
|
+
fullWidth ? "w-full" : "w-fit"
|
|
4056
|
+
);
|
|
4057
|
+
const innerClass = cn(
|
|
4058
|
+
"relative flex flex-col flex-1 min-w-0 h-full",
|
|
4059
|
+
paddingStart,
|
|
4060
|
+
paddingEnd,
|
|
4061
|
+
isInToolbar ? "justify-center" : variant === "filled" ? resolvedDense ? "pt-5 pb-2" : "pt-6 pb-2" : resolvedDense ? "py-3" : "py-4"
|
|
4062
|
+
);
|
|
4063
|
+
const wrapperClass = cn(
|
|
4064
|
+
"group/tf inline-flex flex-col",
|
|
4065
|
+
fullWidth ? "w-full" : "w-fit",
|
|
4066
|
+
disabled && "opacity-[0.38] pointer-events-none",
|
|
4067
|
+
className
|
|
4068
|
+
);
|
|
4069
|
+
const containerHeightClass = resolvedDense ? "h-12" : "h-14";
|
|
4070
|
+
return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
|
|
4071
|
+
/* @__PURE__ */ jsxs(
|
|
4072
|
+
"div",
|
|
4073
|
+
{
|
|
4074
|
+
className: cn(
|
|
4075
|
+
containerClass,
|
|
4076
|
+
type !== "textarea" && containerHeightClass
|
|
4077
|
+
),
|
|
4078
|
+
children: [
|
|
4079
|
+
variant === "outlined" && !isInToolbar && /* @__PURE__ */ jsx(
|
|
4080
|
+
OutlineContainer,
|
|
4081
|
+
{
|
|
4082
|
+
isFloated,
|
|
4083
|
+
isFocused,
|
|
4084
|
+
isError,
|
|
4085
|
+
isDisabled: disabled,
|
|
4086
|
+
isHovered: false,
|
|
4087
|
+
labelWidth,
|
|
4088
|
+
prefersReduced
|
|
4089
|
+
}
|
|
4090
|
+
),
|
|
4091
|
+
variant === "filled" && !isInToolbar && /* @__PURE__ */ jsx(
|
|
4092
|
+
"div",
|
|
4093
|
+
{
|
|
4094
|
+
"aria-hidden": "true",
|
|
4095
|
+
className: cn(
|
|
4096
|
+
"absolute inset-0 pointer-events-none rounded-[inherit] bg-m3-on-surface",
|
|
4097
|
+
"opacity-0 transition-opacity duration-150",
|
|
4098
|
+
"group-hover/tf:opacity-[0.08]"
|
|
4099
|
+
)
|
|
4100
|
+
}
|
|
4101
|
+
),
|
|
4102
|
+
leadingIcon && /* @__PURE__ */ jsx(LeadingIcon, { isError, isDisabled: disabled, children: leadingIcon }),
|
|
4103
|
+
/* @__PURE__ */ jsxs("div", { className: innerClass, children: [
|
|
4104
|
+
resolvedLabel && /* @__PURE__ */ jsx(
|
|
4105
|
+
FloatingLabel,
|
|
4106
|
+
{
|
|
4107
|
+
text: resolvedLabel,
|
|
4108
|
+
isFloated,
|
|
4109
|
+
isFocused,
|
|
4110
|
+
isError,
|
|
4111
|
+
isDisabled: disabled,
|
|
4112
|
+
variant,
|
|
4113
|
+
containerHeight,
|
|
4114
|
+
prefersReduced,
|
|
4115
|
+
showAsterisk,
|
|
4116
|
+
htmlFor: inputId,
|
|
4117
|
+
labelRef: labelSpanRef,
|
|
4118
|
+
hasLeading
|
|
4119
|
+
}
|
|
4120
|
+
),
|
|
4121
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center w-full", children: [
|
|
4122
|
+
prefixText && /* @__PURE__ */ jsx(
|
|
4123
|
+
PrefixSuffix,
|
|
4124
|
+
{
|
|
4125
|
+
text: prefixText,
|
|
4126
|
+
type: "prefix",
|
|
4127
|
+
visible: isFloated,
|
|
4128
|
+
prefersReduced
|
|
4129
|
+
}
|
|
4130
|
+
),
|
|
4131
|
+
type === "textarea" ? /* @__PURE__ */ jsx(
|
|
4132
|
+
ScrollArea,
|
|
4133
|
+
{
|
|
4134
|
+
type: scrollAreaType,
|
|
4135
|
+
className: "w-full flex-1",
|
|
4136
|
+
style: {
|
|
4137
|
+
height: !autoResize ? rows * LINE_HEIGHT_PX : void 0,
|
|
4138
|
+
maxHeight: autoResize && maxRows ? maxRows * LINE_HEIGHT_PX : void 0
|
|
4139
|
+
},
|
|
4140
|
+
viewportClassName: "max-h-[inherit]",
|
|
4141
|
+
children: /* @__PURE__ */ jsx(
|
|
4142
|
+
"textarea",
|
|
4143
|
+
__spreadValues({
|
|
4144
|
+
ref: inputRef,
|
|
4145
|
+
rows,
|
|
4146
|
+
cols,
|
|
4147
|
+
className: cn(
|
|
4148
|
+
inputClass,
|
|
4149
|
+
"resize-none mt-2",
|
|
4150
|
+
autoResize ? "h-auto" : "h-full"
|
|
4151
|
+
),
|
|
4152
|
+
style: { direction: textDirection || void 0 }
|
|
4153
|
+
}, inputProps)
|
|
4154
|
+
)
|
|
4155
|
+
}
|
|
4156
|
+
) : /* @__PURE__ */ jsx(
|
|
4157
|
+
"input",
|
|
4158
|
+
__spreadValues({
|
|
4159
|
+
ref: inputRef,
|
|
4160
|
+
type: type === "password" ? resolvedInputType : type,
|
|
4161
|
+
min,
|
|
4162
|
+
max,
|
|
4163
|
+
step,
|
|
4164
|
+
pattern,
|
|
4165
|
+
multiple,
|
|
4166
|
+
className: inputClass,
|
|
4167
|
+
style: { direction: textDirection || void 0 }
|
|
4168
|
+
}, inputProps)
|
|
4169
|
+
),
|
|
4170
|
+
suffixText && /* @__PURE__ */ jsx(
|
|
4171
|
+
PrefixSuffix,
|
|
4172
|
+
{
|
|
4173
|
+
text: suffixText,
|
|
4174
|
+
type: "suffix",
|
|
4175
|
+
visible: isFloated,
|
|
4176
|
+
prefersReduced
|
|
4177
|
+
}
|
|
4178
|
+
)
|
|
4179
|
+
] })
|
|
4180
|
+
] }),
|
|
4181
|
+
(trailingIconMode !== "none" || trailingIcon) && /* @__PURE__ */ jsx(
|
|
4182
|
+
TrailingIcon,
|
|
4183
|
+
{
|
|
4184
|
+
mode: trailingIcon ? "custom" : trailingIconMode,
|
|
4185
|
+
value: currentValue,
|
|
4186
|
+
showPassword,
|
|
4187
|
+
onClear: handleClear,
|
|
4188
|
+
onPasswordToggle: handlePasswordToggle,
|
|
4189
|
+
isError,
|
|
4190
|
+
isDisabled: disabled,
|
|
4191
|
+
prefersReduced,
|
|
4192
|
+
children: trailingIcon
|
|
4193
|
+
}
|
|
4194
|
+
),
|
|
4195
|
+
variant === "filled" && !isInToolbar && /* @__PURE__ */ jsx(
|
|
4196
|
+
ActiveIndicator,
|
|
4197
|
+
{
|
|
4198
|
+
isFocused,
|
|
4199
|
+
isError,
|
|
4200
|
+
isDisabled: disabled,
|
|
4201
|
+
isHovered: false,
|
|
4202
|
+
prefersReduced
|
|
4203
|
+
}
|
|
4204
|
+
)
|
|
4205
|
+
]
|
|
4206
|
+
}
|
|
4207
|
+
),
|
|
4208
|
+
hasSupporting && /* @__PURE__ */ jsx(
|
|
4209
|
+
SupportingText,
|
|
4210
|
+
{
|
|
4211
|
+
supportingText,
|
|
4212
|
+
errorText: errorText != null ? errorText : nativeError || void 0,
|
|
4213
|
+
isError,
|
|
4214
|
+
charCount: maxLength !== void 0 ? currentValue.length : void 0,
|
|
4215
|
+
maxLength,
|
|
4216
|
+
id: supportingId,
|
|
4217
|
+
prefersReduced
|
|
4218
|
+
}
|
|
4219
|
+
)
|
|
4220
|
+
] }) });
|
|
4221
|
+
}
|
|
4222
|
+
);
|
|
4223
|
+
TextFieldComponent.displayName = "TextField";
|
|
4224
|
+
var TextField = React4.memo(TextFieldComponent);
|
|
4225
|
+
|
|
4226
|
+
export { Checkbox, Chip, RadioButton, RadioGroup, RangeSlider, Slider, SliderColors, SliderThumb, SliderTokens, Switch, SwitchColors, SwitchTokens, TextField, TriStateCheckbox };
|
|
4227
|
+
//# sourceMappingURL=forms.mjs.map
|
|
4228
|
+
//# sourceMappingURL=forms.mjs.map
|