dialkit 0.2.2 → 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/README.md +12 -0
- package/dist/index.cjs +474 -141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -5
- package/dist/index.d.ts +35 -5
- package/dist/index.js +446 -115
- package/dist/index.js.map +1 -1
- package/dist/solid/index.cjs +2569 -0
- package/dist/solid/index.cjs.map +1 -0
- package/dist/solid/index.d.cts +225 -0
- package/dist/solid/index.d.ts +225 -0
- package/dist/solid/index.js +2530 -0
- package/dist/solid/index.js.map +1 -0
- package/dist/styles.css +7 -1
- package/package.json +31 -9
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
ColorControl: () => ColorControl,
|
|
26
26
|
DialRoot: () => DialRoot,
|
|
27
27
|
DialStore: () => DialStore,
|
|
28
|
+
EasingVisualization: () => EasingVisualization,
|
|
28
29
|
Folder: () => Folder,
|
|
29
30
|
PresetManager: () => PresetManager,
|
|
30
31
|
SelectControl: () => SelectControl,
|
|
@@ -33,6 +34,7 @@ __export(index_exports, {
|
|
|
33
34
|
SpringVisualization: () => SpringVisualization,
|
|
34
35
|
TextControl: () => TextControl,
|
|
35
36
|
Toggle: () => Toggle,
|
|
37
|
+
TransitionControl: () => TransitionControl,
|
|
36
38
|
useDialKit: () => useDialKit
|
|
37
39
|
});
|
|
38
40
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -56,15 +58,67 @@ var DialStoreClass = class {
|
|
|
56
58
|
registerPanel(id, name, config) {
|
|
57
59
|
const controls = this.parseConfig(config, "");
|
|
58
60
|
const values = this.flattenValues(config, "");
|
|
61
|
+
this.initTransitionModes(config, "", values);
|
|
59
62
|
this.panels.set(id, { id, name, controls, values });
|
|
60
63
|
this.snapshots.set(id, { ...values });
|
|
61
64
|
this.baseValues.set(id, { ...values });
|
|
62
65
|
this.notifyGlobal();
|
|
63
66
|
}
|
|
67
|
+
updatePanel(id, name, config) {
|
|
68
|
+
const existing = this.panels.get(id);
|
|
69
|
+
if (!existing) {
|
|
70
|
+
this.registerPanel(id, name, config);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const controls = this.parseConfig(config, "");
|
|
74
|
+
const controlsByPath = this.mapControlsByPath(controls);
|
|
75
|
+
const defaultValues = this.flattenValues(config, "");
|
|
76
|
+
const nextValues = {};
|
|
77
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
78
|
+
nextValues[path] = this.normalizePreservedValue(
|
|
79
|
+
existing.values[path],
|
|
80
|
+
defaultValue,
|
|
81
|
+
controlsByPath.get(path)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
this.initTransitionModes(config, "", nextValues);
|
|
85
|
+
for (const [path, mode] of Object.entries(existing.values)) {
|
|
86
|
+
if (!path.endsWith(".__mode")) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const transitionPath = path.slice(0, -"__mode".length - 1);
|
|
90
|
+
const transitionControl = controlsByPath.get(transitionPath);
|
|
91
|
+
if (transitionControl?.type === "transition") {
|
|
92
|
+
nextValues[path] = mode;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const nextPanel = { id, name, controls, values: nextValues };
|
|
96
|
+
this.panels.set(id, nextPanel);
|
|
97
|
+
this.snapshots.set(id, { ...nextValues });
|
|
98
|
+
const previousBaseValues = this.baseValues.get(id) ?? {};
|
|
99
|
+
const nextBaseValues = {};
|
|
100
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
101
|
+
nextBaseValues[path] = this.normalizePreservedValue(
|
|
102
|
+
previousBaseValues[path],
|
|
103
|
+
defaultValue,
|
|
104
|
+
controlsByPath.get(path)
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
for (const [path, value] of Object.entries(nextValues)) {
|
|
108
|
+
if (path.endsWith(".__mode")) {
|
|
109
|
+
nextBaseValues[path] = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
this.baseValues.set(id, nextBaseValues);
|
|
113
|
+
this.notify(id);
|
|
114
|
+
this.notifyGlobal();
|
|
115
|
+
}
|
|
64
116
|
unregisterPanel(id) {
|
|
65
117
|
this.panels.delete(id);
|
|
66
118
|
this.listeners.delete(id);
|
|
67
119
|
this.snapshots.delete(id);
|
|
120
|
+
this.actionListeners.delete(id);
|
|
121
|
+
this.baseValues.delete(id);
|
|
68
122
|
this.notifyGlobal();
|
|
69
123
|
}
|
|
70
124
|
updateValue(panelId, path, value) {
|
|
@@ -84,13 +138,21 @@ var DialStoreClass = class {
|
|
|
84
138
|
this.notify(panelId);
|
|
85
139
|
}
|
|
86
140
|
updateSpringMode(panelId, path, mode) {
|
|
141
|
+
this.updateTransitionMode(panelId, path, mode);
|
|
142
|
+
}
|
|
143
|
+
getSpringMode(panelId, path) {
|
|
144
|
+
const mode = this.getTransitionMode(panelId, path);
|
|
145
|
+
if (mode === "easing") return "simple";
|
|
146
|
+
return mode;
|
|
147
|
+
}
|
|
148
|
+
updateTransitionMode(panelId, path, mode) {
|
|
87
149
|
const panel = this.panels.get(panelId);
|
|
88
150
|
if (!panel) return;
|
|
89
151
|
panel.values[`${path}.__mode`] = mode;
|
|
90
152
|
this.snapshots.set(panelId, { ...panel.values });
|
|
91
153
|
this.notify(panelId);
|
|
92
154
|
}
|
|
93
|
-
|
|
155
|
+
getTransitionMode(panelId, path) {
|
|
94
156
|
const panel = this.panels.get(panelId);
|
|
95
157
|
if (!panel) return "simple";
|
|
96
158
|
return panel.values[`${path}.__mode`] || "simple";
|
|
@@ -194,6 +256,21 @@ var DialStoreClass = class {
|
|
|
194
256
|
notifyGlobal() {
|
|
195
257
|
this.globalListeners.forEach((fn) => fn());
|
|
196
258
|
}
|
|
259
|
+
initTransitionModes(config, prefix, values) {
|
|
260
|
+
for (const [key, value] of Object.entries(config)) {
|
|
261
|
+
if (key === "_collapsed") continue;
|
|
262
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
263
|
+
if (this.isEasingConfig(value)) {
|
|
264
|
+
values[`${path}.__mode`] = "easing";
|
|
265
|
+
} else if (this.isSpringConfig(value)) {
|
|
266
|
+
const hasPhysics = value.stiffness !== void 0 || value.damping !== void 0 || value.mass !== void 0;
|
|
267
|
+
const hasTime = value.visualDuration !== void 0 || value.bounce !== void 0;
|
|
268
|
+
values[`${path}.__mode`] = hasPhysics && !hasTime ? "advanced" : "simple";
|
|
269
|
+
} else if (typeof value === "object" && value !== null && !Array.isArray(value) && !this.isActionConfig(value) && !this.isSelectConfig(value) && !this.isColorConfig(value) && !this.isTextConfig(value)) {
|
|
270
|
+
this.initTransitionModes(value, path, values);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
197
274
|
parseConfig(config, prefix) {
|
|
198
275
|
const controls = [];
|
|
199
276
|
for (const [key, value] of Object.entries(config)) {
|
|
@@ -214,8 +291,8 @@ var DialStoreClass = class {
|
|
|
214
291
|
controls.push({ type: "slider", path, label, min, max, step });
|
|
215
292
|
} else if (typeof value === "boolean") {
|
|
216
293
|
controls.push({ type: "toggle", path, label });
|
|
217
|
-
} else if (this.isSpringConfig(value)) {
|
|
218
|
-
controls.push({ type: "
|
|
294
|
+
} else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
|
|
295
|
+
controls.push({ type: "transition", path, label });
|
|
219
296
|
} else if (this.isActionConfig(value)) {
|
|
220
297
|
controls.push({ type: "action", path, label: value.label || label });
|
|
221
298
|
} else if (this.isSelectConfig(value)) {
|
|
@@ -253,7 +330,7 @@ var DialStoreClass = class {
|
|
|
253
330
|
values[path] = value[0];
|
|
254
331
|
} else if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
|
|
255
332
|
values[path] = value;
|
|
256
|
-
} else if (this.isSpringConfig(value)) {
|
|
333
|
+
} else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
|
|
257
334
|
values[path] = value;
|
|
258
335
|
} else if (this.isActionConfig(value)) {
|
|
259
336
|
values[path] = value;
|
|
@@ -274,6 +351,9 @@ var DialStoreClass = class {
|
|
|
274
351
|
isSpringConfig(value) {
|
|
275
352
|
return typeof value === "object" && value !== null && "type" in value && value.type === "spring";
|
|
276
353
|
}
|
|
354
|
+
isEasingConfig(value) {
|
|
355
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "easing";
|
|
356
|
+
}
|
|
277
357
|
isActionConfig(value) {
|
|
278
358
|
return typeof value === "object" && value !== null && "type" in value && value.type === "action";
|
|
279
359
|
}
|
|
@@ -312,6 +392,75 @@ var DialStoreClass = class {
|
|
|
312
392
|
if (range <= 100) return 1;
|
|
313
393
|
return 10;
|
|
314
394
|
}
|
|
395
|
+
normalizePreservedValue(existingValue, defaultValue, control) {
|
|
396
|
+
if (existingValue === void 0 || !control) {
|
|
397
|
+
return defaultValue;
|
|
398
|
+
}
|
|
399
|
+
switch (control.type) {
|
|
400
|
+
case "slider": {
|
|
401
|
+
if (typeof existingValue !== "number" || typeof defaultValue !== "number") {
|
|
402
|
+
return defaultValue;
|
|
403
|
+
}
|
|
404
|
+
const min = control.min ?? Number.NEGATIVE_INFINITY;
|
|
405
|
+
const max = control.max ?? Number.POSITIVE_INFINITY;
|
|
406
|
+
const clamped = Math.min(max, Math.max(min, existingValue));
|
|
407
|
+
if (typeof control.step !== "number" || control.step <= 0) {
|
|
408
|
+
return clamped;
|
|
409
|
+
}
|
|
410
|
+
return this.roundToStep(clamped, min, max, control.step);
|
|
411
|
+
}
|
|
412
|
+
case "toggle":
|
|
413
|
+
return typeof existingValue === "boolean" ? existingValue : defaultValue;
|
|
414
|
+
case "select": {
|
|
415
|
+
if (typeof existingValue !== "string") {
|
|
416
|
+
return defaultValue;
|
|
417
|
+
}
|
|
418
|
+
const options = control.options ?? [];
|
|
419
|
+
const validValues = new Set(options.map((option) => typeof option === "string" ? option : option.value));
|
|
420
|
+
return validValues.has(existingValue) ? existingValue : defaultValue;
|
|
421
|
+
}
|
|
422
|
+
case "color":
|
|
423
|
+
case "text":
|
|
424
|
+
return typeof existingValue === "string" ? existingValue : defaultValue;
|
|
425
|
+
case "transition":
|
|
426
|
+
if (this.isSpringConfig(defaultValue)) {
|
|
427
|
+
return this.isSpringConfig(existingValue) ? existingValue : defaultValue;
|
|
428
|
+
}
|
|
429
|
+
if (this.isEasingConfig(defaultValue)) {
|
|
430
|
+
return this.isEasingConfig(existingValue) ? existingValue : defaultValue;
|
|
431
|
+
}
|
|
432
|
+
return defaultValue;
|
|
433
|
+
case "action":
|
|
434
|
+
return defaultValue;
|
|
435
|
+
default:
|
|
436
|
+
return defaultValue;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
roundToStep(value, min, max, step) {
|
|
440
|
+
const snapped = min + Math.round((value - min) / step) * step;
|
|
441
|
+
const clamped = Math.min(max, Math.max(min, snapped));
|
|
442
|
+
const precision = this.stepPrecision(step);
|
|
443
|
+
return Number(clamped.toFixed(precision));
|
|
444
|
+
}
|
|
445
|
+
stepPrecision(step) {
|
|
446
|
+
const text = String(step);
|
|
447
|
+
const decimalIndex = text.indexOf(".");
|
|
448
|
+
return decimalIndex === -1 ? 0 : text.length - decimalIndex - 1;
|
|
449
|
+
}
|
|
450
|
+
mapControlsByPath(controls) {
|
|
451
|
+
const map = /* @__PURE__ */ new Map();
|
|
452
|
+
const visit = (nodes) => {
|
|
453
|
+
for (const node of nodes) {
|
|
454
|
+
if (node.type === "folder" && node.children) {
|
|
455
|
+
visit(node.children);
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
map.set(node.path, node);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
visit(controls);
|
|
462
|
+
return map;
|
|
463
|
+
}
|
|
315
464
|
};
|
|
316
465
|
var DialStore = new DialStoreClass();
|
|
317
466
|
|
|
@@ -320,12 +469,22 @@ function useDialKit(name, config, options) {
|
|
|
320
469
|
const instanceId = (0, import_react.useId)();
|
|
321
470
|
const panelId = `${name}-${instanceId}`;
|
|
322
471
|
const configRef = (0, import_react.useRef)(config);
|
|
472
|
+
const serializedConfig = JSON.stringify(config);
|
|
473
|
+
configRef.current = config;
|
|
323
474
|
const onActionRef = (0, import_react.useRef)(options?.onAction);
|
|
324
475
|
onActionRef.current = options?.onAction;
|
|
325
476
|
(0, import_react.useEffect)(() => {
|
|
326
477
|
DialStore.registerPanel(panelId, name, configRef.current);
|
|
327
478
|
return () => DialStore.unregisterPanel(panelId);
|
|
328
479
|
}, [panelId, name]);
|
|
480
|
+
const mountedRef = (0, import_react.useRef)(false);
|
|
481
|
+
(0, import_react.useEffect)(() => {
|
|
482
|
+
if (!mountedRef.current) {
|
|
483
|
+
mountedRef.current = true;
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
DialStore.updatePanel(panelId, name, configRef.current);
|
|
487
|
+
}, [panelId, name, serializedConfig]);
|
|
329
488
|
(0, import_react.useEffect)(() => {
|
|
330
489
|
return DialStore.subscribeActions(panelId, (action) => {
|
|
331
490
|
onActionRef.current?.(action);
|
|
@@ -347,7 +506,7 @@ function buildResolvedValues(config, flatValues, prefix) {
|
|
|
347
506
|
result[key] = flatValues[path] ?? configValue[0];
|
|
348
507
|
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
349
508
|
result[key] = flatValues[path] ?? configValue;
|
|
350
|
-
} else if (isSpringConfig(configValue)) {
|
|
509
|
+
} else if (isSpringConfig(configValue) || isEasingConfig(configValue)) {
|
|
351
510
|
result[key] = flatValues[path] ?? configValue;
|
|
352
511
|
} else if (isActionConfig(configValue)) {
|
|
353
512
|
result[key] = flatValues[path] ?? configValue;
|
|
@@ -370,6 +529,9 @@ function hasType(value, type) {
|
|
|
370
529
|
function isSpringConfig(value) {
|
|
371
530
|
return hasType(value, "spring");
|
|
372
531
|
}
|
|
532
|
+
function isEasingConfig(value) {
|
|
533
|
+
return hasType(value, "easing");
|
|
534
|
+
}
|
|
373
535
|
function isActionConfig(value) {
|
|
374
536
|
return hasType(value, "action");
|
|
375
537
|
}
|
|
@@ -388,12 +550,12 @@ function getFirstOptionValue(options) {
|
|
|
388
550
|
}
|
|
389
551
|
|
|
390
552
|
// src/components/DialRoot.tsx
|
|
391
|
-
var
|
|
553
|
+
var import_react17 = require("react");
|
|
392
554
|
var import_react_dom3 = require("react-dom");
|
|
393
555
|
|
|
394
556
|
// src/components/Panel.tsx
|
|
395
|
-
var
|
|
396
|
-
var
|
|
557
|
+
var import_react15 = require("react");
|
|
558
|
+
var import_react16 = require("motion/react");
|
|
397
559
|
|
|
398
560
|
// src/components/Folder.tsx
|
|
399
561
|
var import_react2 = require("react");
|
|
@@ -1156,12 +1318,180 @@ function SpringControl({ panelId, path, label, spring, onChange }) {
|
|
|
1156
1318
|
] }) });
|
|
1157
1319
|
}
|
|
1158
1320
|
|
|
1159
|
-
// src/components/
|
|
1321
|
+
// src/components/EasingVisualization.tsx
|
|
1160
1322
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1323
|
+
function EasingVisualization({ easing }) {
|
|
1324
|
+
const ease = easing.ease;
|
|
1325
|
+
const s = 200;
|
|
1326
|
+
const pad = 10;
|
|
1327
|
+
const inner = s - pad * 2;
|
|
1328
|
+
const unit = inner / 2;
|
|
1329
|
+
const toSvg = (nx, ny) => ({
|
|
1330
|
+
x: pad + (nx + 0.5) * unit,
|
|
1331
|
+
y: pad + (1.5 - ny) * unit
|
|
1332
|
+
});
|
|
1333
|
+
const start = toSvg(0, 0);
|
|
1334
|
+
const end = toSvg(1, 1);
|
|
1335
|
+
const p1 = toSvg(ease[0], ease[1]);
|
|
1336
|
+
const p2 = toSvg(ease[2], ease[3]);
|
|
1337
|
+
const curvePath = `M ${start.x} ${start.y} C ${p1.x} ${p1.y}, ${p2.x} ${p2.y}, ${end.x} ${end.y}`;
|
|
1338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1339
|
+
"svg",
|
|
1340
|
+
{
|
|
1341
|
+
viewBox: `0 0 ${s} ${s}`,
|
|
1342
|
+
preserveAspectRatio: "xMidYMid slice",
|
|
1343
|
+
className: "dialkit-spring-viz dialkit-easing-viz",
|
|
1344
|
+
children: [
|
|
1345
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1346
|
+
"line",
|
|
1347
|
+
{
|
|
1348
|
+
x1: start.x,
|
|
1349
|
+
y1: start.y,
|
|
1350
|
+
x2: end.x,
|
|
1351
|
+
y2: end.y,
|
|
1352
|
+
stroke: "rgba(255, 255, 255, 0.15)",
|
|
1353
|
+
strokeWidth: "1",
|
|
1354
|
+
strokeDasharray: "4,4"
|
|
1355
|
+
}
|
|
1356
|
+
),
|
|
1357
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: curvePath, fill: "none", stroke: "rgba(255, 255, 255, 0.6)", strokeWidth: "2", strokeLinecap: "round" })
|
|
1358
|
+
]
|
|
1359
|
+
}
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// src/components/TransitionControl.tsx
|
|
1364
|
+
var import_react9 = require("react");
|
|
1365
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1366
|
+
function TransitionControl({ panelId, path, label, value, onChange }) {
|
|
1367
|
+
const mode = (0, import_react9.useSyncExternalStore)(
|
|
1368
|
+
(cb) => DialStore.subscribe(panelId, cb),
|
|
1369
|
+
() => DialStore.getTransitionMode(panelId, path),
|
|
1370
|
+
() => DialStore.getTransitionMode(panelId, path)
|
|
1371
|
+
);
|
|
1372
|
+
const isEasing = mode === "easing";
|
|
1373
|
+
const isSimpleSpring = mode === "simple";
|
|
1374
|
+
const spring = value.type === "spring" ? value : { type: "spring", visualDuration: 0.3, bounce: 0.2 };
|
|
1375
|
+
const easing = value.type === "easing" ? value : { type: "easing", duration: 0.3, ease: [1, -0.4, 0.5, 1] };
|
|
1376
|
+
const handleModeChange = (newMode) => {
|
|
1377
|
+
DialStore.updateTransitionMode(panelId, path, newMode);
|
|
1378
|
+
if (newMode === "easing") {
|
|
1379
|
+
const duration = value.type === "spring" ? value.visualDuration ?? 0.3 : value.duration;
|
|
1380
|
+
onChange({ type: "easing", duration, ease: easing.ease });
|
|
1381
|
+
} else if (newMode === "simple") {
|
|
1382
|
+
onChange({
|
|
1383
|
+
type: "spring",
|
|
1384
|
+
visualDuration: spring.visualDuration ?? (value.type === "easing" ? value.duration : 0.3),
|
|
1385
|
+
bounce: spring.bounce ?? 0.2
|
|
1386
|
+
});
|
|
1387
|
+
} else {
|
|
1388
|
+
onChange({
|
|
1389
|
+
type: "spring",
|
|
1390
|
+
stiffness: spring.stiffness ?? 200,
|
|
1391
|
+
damping: spring.damping ?? 25,
|
|
1392
|
+
mass: spring.mass ?? 1
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
const handleSpringUpdate = (key, val) => {
|
|
1397
|
+
if (isSimpleSpring) {
|
|
1398
|
+
const { stiffness, damping, mass, ...rest } = spring;
|
|
1399
|
+
onChange({ ...rest, [key]: val });
|
|
1400
|
+
} else {
|
|
1401
|
+
const { visualDuration, bounce, ...rest } = spring;
|
|
1402
|
+
onChange({ ...rest, [key]: val });
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
const updateEase = (index, val) => {
|
|
1406
|
+
const newEase = [...easing.ease];
|
|
1407
|
+
newEase[index] = val;
|
|
1408
|
+
onChange({ ...easing, ease: newEase });
|
|
1409
|
+
};
|
|
1410
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Folder, { title: label, defaultOpen: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
1411
|
+
isEasing ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EasingVisualization, { easing }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SpringVisualization, { spring, isSimpleMode: isSimpleSpring }),
|
|
1412
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dialkit-labeled-control", children: [
|
|
1413
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dialkit-labeled-control-label", children: "Type" }),
|
|
1414
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1415
|
+
SegmentedControl,
|
|
1416
|
+
{
|
|
1417
|
+
options: [
|
|
1418
|
+
{ value: "easing", label: "Easing" },
|
|
1419
|
+
{ value: "simple", label: "Time" },
|
|
1420
|
+
{ value: "advanced", label: "Physics" }
|
|
1421
|
+
],
|
|
1422
|
+
value: mode,
|
|
1423
|
+
onChange: handleModeChange
|
|
1424
|
+
}
|
|
1425
|
+
)
|
|
1426
|
+
] }),
|
|
1427
|
+
isEasing ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "x1", value: easing.ease[0], onChange: (v) => updateEase(0, v), min: 0, max: 1, step: 0.01 }),
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "y1", value: easing.ease[1], onChange: (v) => updateEase(1, v), min: -1, max: 2, step: 0.01 }),
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "x2", value: easing.ease[2], onChange: (v) => updateEase(2, v), min: 0, max: 1, step: 0.01 }),
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "y2", value: easing.ease[3], onChange: (v) => updateEase(3, v), min: -1, max: 2, step: 0.01 }),
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "Duration", value: easing.duration, onChange: (v) => onChange({ ...easing, duration: v }), min: 0.1, max: 2, step: 0.05, unit: "s" }),
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EaseTextInput, { ease: easing.ease, onChange: (newEase) => onChange({ ...easing, ease: newEase }) })
|
|
1434
|
+
] }) : isSimpleSpring ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "Duration", value: spring.visualDuration ?? 0.3, onChange: (v) => handleSpringUpdate("visualDuration", v), min: 0.1, max: 1, step: 0.05, unit: "s" }),
|
|
1436
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "Bounce", value: spring.bounce ?? 0.2, onChange: (v) => handleSpringUpdate("bounce", v), min: 0, max: 1, step: 0.05 })
|
|
1437
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1438
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "Stiffness", value: spring.stiffness ?? 400, onChange: (v) => handleSpringUpdate("stiffness", v), min: 1, max: 1e3, step: 10 }),
|
|
1439
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "Damping", value: spring.damping ?? 17, onChange: (v) => handleSpringUpdate("damping", v), min: 1, max: 100, step: 1 }),
|
|
1440
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slider, { label: "Mass", value: spring.mass ?? 1, onChange: (v) => handleSpringUpdate("mass", v), min: 0.1, max: 10, step: 0.1 })
|
|
1441
|
+
] })
|
|
1442
|
+
] }) });
|
|
1443
|
+
}
|
|
1444
|
+
function formatEase(ease) {
|
|
1445
|
+
return ease.map((v) => parseFloat(v.toFixed(2))).join(", ");
|
|
1446
|
+
}
|
|
1447
|
+
function parseEase(str) {
|
|
1448
|
+
const parts = str.split(",").map((s) => parseFloat(s.trim()));
|
|
1449
|
+
if (parts.length === 4 && parts.every((n) => !isNaN(n))) {
|
|
1450
|
+
return parts;
|
|
1451
|
+
}
|
|
1452
|
+
return null;
|
|
1453
|
+
}
|
|
1454
|
+
function EaseTextInput({ ease, onChange }) {
|
|
1455
|
+
const [editing, setEditing] = (0, import_react9.useState)(false);
|
|
1456
|
+
const [draft, setDraft] = (0, import_react9.useState)("");
|
|
1457
|
+
const handleFocus = () => {
|
|
1458
|
+
setDraft(formatEase(ease));
|
|
1459
|
+
setEditing(true);
|
|
1460
|
+
};
|
|
1461
|
+
const handleBlur = () => {
|
|
1462
|
+
const parsed = parseEase(draft);
|
|
1463
|
+
if (parsed) onChange(parsed);
|
|
1464
|
+
setEditing(false);
|
|
1465
|
+
};
|
|
1466
|
+
const handleKeyDown = (e) => {
|
|
1467
|
+
if (e.key === "Enter") {
|
|
1468
|
+
e.target.blur();
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dialkit-labeled-control", children: [
|
|
1472
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dialkit-labeled-control-label", children: "Ease" }),
|
|
1473
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1474
|
+
"input",
|
|
1475
|
+
{
|
|
1476
|
+
type: "text",
|
|
1477
|
+
className: "dialkit-text-input",
|
|
1478
|
+
value: editing ? draft : formatEase(ease),
|
|
1479
|
+
onChange: (e) => setDraft(e.target.value),
|
|
1480
|
+
onFocus: handleFocus,
|
|
1481
|
+
onBlur: handleBlur,
|
|
1482
|
+
onKeyDown: handleKeyDown,
|
|
1483
|
+
spellCheck: false
|
|
1484
|
+
}
|
|
1485
|
+
)
|
|
1486
|
+
] });
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
// src/components/TextControl.tsx
|
|
1490
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1161
1491
|
function TextControl({ label, value, onChange, placeholder }) {
|
|
1162
|
-
return /* @__PURE__ */ (0,
|
|
1163
|
-
/* @__PURE__ */ (0,
|
|
1164
|
-
/* @__PURE__ */ (0,
|
|
1492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dialkit-text-control", children: [
|
|
1493
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "dialkit-text-label", children: label }),
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1165
1495
|
"input",
|
|
1166
1496
|
{
|
|
1167
1497
|
type: "text",
|
|
@@ -1175,10 +1505,10 @@ function TextControl({ label, value, onChange, placeholder }) {
|
|
|
1175
1505
|
}
|
|
1176
1506
|
|
|
1177
1507
|
// src/components/SelectControl.tsx
|
|
1178
|
-
var
|
|
1508
|
+
var import_react10 = require("react");
|
|
1179
1509
|
var import_react_dom = require("react-dom");
|
|
1180
|
-
var
|
|
1181
|
-
var
|
|
1510
|
+
var import_react11 = require("motion/react");
|
|
1511
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1182
1512
|
function toTitleCase(s) {
|
|
1183
1513
|
return s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1184
1514
|
}
|
|
@@ -1188,14 +1518,14 @@ function normalizeOptions(options) {
|
|
|
1188
1518
|
);
|
|
1189
1519
|
}
|
|
1190
1520
|
function SelectControl({ label, value, options, onChange }) {
|
|
1191
|
-
const [isOpen, setIsOpen] = (0,
|
|
1192
|
-
const triggerRef = (0,
|
|
1193
|
-
const dropdownRef = (0,
|
|
1194
|
-
const [portalTarget, setPortalTarget] = (0,
|
|
1195
|
-
const [pos, setPos] = (0,
|
|
1521
|
+
const [isOpen, setIsOpen] = (0, import_react10.useState)(false);
|
|
1522
|
+
const triggerRef = (0, import_react10.useRef)(null);
|
|
1523
|
+
const dropdownRef = (0, import_react10.useRef)(null);
|
|
1524
|
+
const [portalTarget, setPortalTarget] = (0, import_react10.useState)(null);
|
|
1525
|
+
const [pos, setPos] = (0, import_react10.useState)(null);
|
|
1196
1526
|
const normalized = normalizeOptions(options);
|
|
1197
1527
|
const selectedOption = normalized.find((o) => o.value === value);
|
|
1198
|
-
const updatePos = (0,
|
|
1528
|
+
const updatePos = (0, import_react10.useCallback)(() => {
|
|
1199
1529
|
const el = triggerRef.current;
|
|
1200
1530
|
if (!el) return;
|
|
1201
1531
|
const rect = el.getBoundingClientRect();
|
|
@@ -1209,15 +1539,15 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1209
1539
|
above
|
|
1210
1540
|
});
|
|
1211
1541
|
}, [normalized.length]);
|
|
1212
|
-
(0,
|
|
1542
|
+
(0, import_react10.useEffect)(() => {
|
|
1213
1543
|
const root = triggerRef.current?.closest(".dialkit-root");
|
|
1214
1544
|
setPortalTarget(root ?? document.body);
|
|
1215
1545
|
}, []);
|
|
1216
|
-
(0,
|
|
1546
|
+
(0, import_react10.useEffect)(() => {
|
|
1217
1547
|
if (!isOpen) return;
|
|
1218
1548
|
updatePos();
|
|
1219
1549
|
}, [isOpen, updatePos]);
|
|
1220
|
-
(0,
|
|
1550
|
+
(0, import_react10.useEffect)(() => {
|
|
1221
1551
|
if (!isOpen) return;
|
|
1222
1552
|
const handleClick = (e) => {
|
|
1223
1553
|
const target = e.target;
|
|
@@ -1228,8 +1558,8 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1228
1558
|
document.addEventListener("mousedown", handleClick);
|
|
1229
1559
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
1230
1560
|
}, [isOpen]);
|
|
1231
|
-
return /* @__PURE__ */ (0,
|
|
1232
|
-
/* @__PURE__ */ (0,
|
|
1561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dialkit-select-row", children: [
|
|
1562
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1233
1563
|
"button",
|
|
1234
1564
|
{
|
|
1235
1565
|
ref: triggerRef,
|
|
@@ -1237,11 +1567,11 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1237
1567
|
onClick: () => setIsOpen(!isOpen),
|
|
1238
1568
|
"data-open": String(isOpen),
|
|
1239
1569
|
children: [
|
|
1240
|
-
/* @__PURE__ */ (0,
|
|
1241
|
-
/* @__PURE__ */ (0,
|
|
1242
|
-
/* @__PURE__ */ (0,
|
|
1243
|
-
/* @__PURE__ */ (0,
|
|
1244
|
-
|
|
1570
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-select-label", children: label }),
|
|
1571
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dialkit-select-right", children: [
|
|
1572
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-select-value", children: selectedOption?.label ?? value }),
|
|
1573
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1574
|
+
import_react11.motion.svg,
|
|
1245
1575
|
{
|
|
1246
1576
|
className: "dialkit-select-chevron",
|
|
1247
1577
|
viewBox: "0 0 24 24",
|
|
@@ -1252,7 +1582,7 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1252
1582
|
strokeLinejoin: "round",
|
|
1253
1583
|
animate: { rotate: isOpen ? 180 : 0 },
|
|
1254
1584
|
transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
|
|
1255
|
-
children: /* @__PURE__ */ (0,
|
|
1585
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
1256
1586
|
}
|
|
1257
1587
|
)
|
|
1258
1588
|
] })
|
|
@@ -1260,8 +1590,8 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1260
1590
|
}
|
|
1261
1591
|
),
|
|
1262
1592
|
portalTarget && (0, import_react_dom.createPortal)(
|
|
1263
|
-
/* @__PURE__ */ (0,
|
|
1264
|
-
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.AnimatePresence, { children: isOpen && pos && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1594
|
+
import_react11.motion.div,
|
|
1265
1595
|
{
|
|
1266
1596
|
ref: dropdownRef,
|
|
1267
1597
|
className: "dialkit-select-dropdown",
|
|
@@ -1275,7 +1605,7 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1275
1605
|
width: pos.width,
|
|
1276
1606
|
...pos.above ? { bottom: window.innerHeight - pos.top, transformOrigin: "bottom" } : { top: pos.top, transformOrigin: "top" }
|
|
1277
1607
|
},
|
|
1278
|
-
children: normalized.map((option) => /* @__PURE__ */ (0,
|
|
1608
|
+
children: normalized.map((option) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1279
1609
|
"button",
|
|
1280
1610
|
{
|
|
1281
1611
|
className: "dialkit-select-option",
|
|
@@ -1296,14 +1626,14 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1296
1626
|
}
|
|
1297
1627
|
|
|
1298
1628
|
// src/components/ColorControl.tsx
|
|
1299
|
-
var
|
|
1300
|
-
var
|
|
1629
|
+
var import_react12 = require("react");
|
|
1630
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1301
1631
|
var HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
1302
1632
|
function ColorControl({ label, value, onChange }) {
|
|
1303
|
-
const [isEditing, setIsEditing] = (0,
|
|
1304
|
-
const [editValue, setEditValue] = (0,
|
|
1305
|
-
const colorInputRef = (0,
|
|
1306
|
-
(0,
|
|
1633
|
+
const [isEditing, setIsEditing] = (0, import_react12.useState)(false);
|
|
1634
|
+
const [editValue, setEditValue] = (0, import_react12.useState)(value);
|
|
1635
|
+
const colorInputRef = (0, import_react12.useRef)(null);
|
|
1636
|
+
(0, import_react12.useEffect)(() => {
|
|
1307
1637
|
if (!isEditing) {
|
|
1308
1638
|
setEditValue(value);
|
|
1309
1639
|
}
|
|
@@ -1324,10 +1654,10 @@ function ColorControl({ label, value, onChange }) {
|
|
|
1324
1654
|
setEditValue(value);
|
|
1325
1655
|
}
|
|
1326
1656
|
}
|
|
1327
|
-
return /* @__PURE__ */ (0,
|
|
1328
|
-
/* @__PURE__ */ (0,
|
|
1329
|
-
/* @__PURE__ */ (0,
|
|
1330
|
-
isEditing ? /* @__PURE__ */ (0,
|
|
1657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dialkit-color-control", children: [
|
|
1658
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dialkit-color-label", children: label }),
|
|
1659
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dialkit-color-inputs", children: [
|
|
1660
|
+
isEditing ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1331
1661
|
"input",
|
|
1332
1662
|
{
|
|
1333
1663
|
type: "text",
|
|
@@ -1338,7 +1668,7 @@ function ColorControl({ label, value, onChange }) {
|
|
|
1338
1668
|
onKeyDown: handleKeyDown,
|
|
1339
1669
|
autoFocus: true
|
|
1340
1670
|
}
|
|
1341
|
-
) : /* @__PURE__ */ (0,
|
|
1671
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1342
1672
|
"span",
|
|
1343
1673
|
{
|
|
1344
1674
|
className: "dialkit-color-hex",
|
|
@@ -1346,7 +1676,7 @@ function ColorControl({ label, value, onChange }) {
|
|
|
1346
1676
|
children: (value ?? "").toUpperCase()
|
|
1347
1677
|
}
|
|
1348
1678
|
),
|
|
1349
|
-
/* @__PURE__ */ (0,
|
|
1679
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1350
1680
|
"button",
|
|
1351
1681
|
{
|
|
1352
1682
|
className: "dialkit-color-swatch",
|
|
@@ -1355,7 +1685,7 @@ function ColorControl({ label, value, onChange }) {
|
|
|
1355
1685
|
title: "Pick color"
|
|
1356
1686
|
}
|
|
1357
1687
|
),
|
|
1358
|
-
/* @__PURE__ */ (0,
|
|
1688
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1359
1689
|
"input",
|
|
1360
1690
|
{
|
|
1361
1691
|
ref: colorInputRef,
|
|
@@ -1374,18 +1704,18 @@ function expandShorthandHex(hex) {
|
|
|
1374
1704
|
}
|
|
1375
1705
|
|
|
1376
1706
|
// src/components/PresetManager.tsx
|
|
1377
|
-
var
|
|
1707
|
+
var import_react13 = require("react");
|
|
1378
1708
|
var import_react_dom2 = require("react-dom");
|
|
1379
|
-
var
|
|
1380
|
-
var
|
|
1709
|
+
var import_react14 = require("motion/react");
|
|
1710
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1381
1711
|
function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
1382
|
-
const [isOpen, setIsOpen] = (0,
|
|
1383
|
-
const triggerRef = (0,
|
|
1384
|
-
const dropdownRef = (0,
|
|
1385
|
-
const [pos, setPos] = (0,
|
|
1712
|
+
const [isOpen, setIsOpen] = (0, import_react13.useState)(false);
|
|
1713
|
+
const triggerRef = (0, import_react13.useRef)(null);
|
|
1714
|
+
const dropdownRef = (0, import_react13.useRef)(null);
|
|
1715
|
+
const [pos, setPos] = (0, import_react13.useState)({ top: 0, left: 0, width: 0 });
|
|
1386
1716
|
const hasPresets = presets.length > 0;
|
|
1387
1717
|
const activePreset = presets.find((p) => p.id === activePresetId);
|
|
1388
|
-
const open = (0,
|
|
1718
|
+
const open = (0, import_react13.useCallback)(() => {
|
|
1389
1719
|
if (!hasPresets) return;
|
|
1390
1720
|
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1391
1721
|
if (rect) {
|
|
@@ -1393,12 +1723,12 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1393
1723
|
}
|
|
1394
1724
|
setIsOpen(true);
|
|
1395
1725
|
}, [hasPresets]);
|
|
1396
|
-
const close = (0,
|
|
1397
|
-
const toggle = (0,
|
|
1726
|
+
const close = (0, import_react13.useCallback)(() => setIsOpen(false), []);
|
|
1727
|
+
const toggle = (0, import_react13.useCallback)(() => {
|
|
1398
1728
|
if (isOpen) close();
|
|
1399
1729
|
else open();
|
|
1400
1730
|
}, [isOpen, open, close]);
|
|
1401
|
-
(0,
|
|
1731
|
+
(0, import_react13.useEffect)(() => {
|
|
1402
1732
|
if (!isOpen) return;
|
|
1403
1733
|
const handler = (e) => {
|
|
1404
1734
|
const target = e.target;
|
|
@@ -1420,8 +1750,8 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1420
1750
|
e.stopPropagation();
|
|
1421
1751
|
DialStore.deletePreset(panelId, presetId);
|
|
1422
1752
|
};
|
|
1423
|
-
return /* @__PURE__ */ (0,
|
|
1424
|
-
/* @__PURE__ */ (0,
|
|
1753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dialkit-preset-manager", children: [
|
|
1754
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1425
1755
|
"button",
|
|
1426
1756
|
{
|
|
1427
1757
|
ref: triggerRef,
|
|
@@ -1431,9 +1761,9 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1431
1761
|
"data-has-preset": String(!!activePreset),
|
|
1432
1762
|
"data-disabled": String(!hasPresets),
|
|
1433
1763
|
children: [
|
|
1434
|
-
/* @__PURE__ */ (0,
|
|
1435
|
-
/* @__PURE__ */ (0,
|
|
1436
|
-
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dialkit-preset-label", children: activePreset ? activePreset.name : "Version 1" }),
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1766
|
+
import_react14.motion.svg,
|
|
1437
1767
|
{
|
|
1438
1768
|
className: "dialkit-select-chevron",
|
|
1439
1769
|
viewBox: "0 0 24 24",
|
|
@@ -1444,15 +1774,15 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1444
1774
|
strokeLinejoin: "round",
|
|
1445
1775
|
animate: { rotate: isOpen ? 180 : 0, opacity: hasPresets ? 0.6 : 0.25 },
|
|
1446
1776
|
transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
|
|
1447
|
-
children: /* @__PURE__ */ (0,
|
|
1777
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
1448
1778
|
}
|
|
1449
1779
|
)
|
|
1450
1780
|
]
|
|
1451
1781
|
}
|
|
1452
1782
|
),
|
|
1453
1783
|
(0, import_react_dom2.createPortal)(
|
|
1454
|
-
/* @__PURE__ */ (0,
|
|
1455
|
-
|
|
1784
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react14.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1785
|
+
import_react14.motion.div,
|
|
1456
1786
|
{
|
|
1457
1787
|
ref: dropdownRef,
|
|
1458
1788
|
className: "dialkit-root dialkit-preset-dropdown",
|
|
@@ -1462,35 +1792,35 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1462
1792
|
exit: { opacity: 0, y: 4, scale: 0.97, pointerEvents: "none" },
|
|
1463
1793
|
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1464
1794
|
children: [
|
|
1465
|
-
/* @__PURE__ */ (0,
|
|
1795
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1466
1796
|
"div",
|
|
1467
1797
|
{
|
|
1468
1798
|
className: "dialkit-preset-item",
|
|
1469
1799
|
"data-active": String(!activePresetId),
|
|
1470
1800
|
onClick: () => handleSelect(null),
|
|
1471
|
-
children: /* @__PURE__ */ (0,
|
|
1801
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dialkit-preset-name", children: "Version 1" })
|
|
1472
1802
|
}
|
|
1473
1803
|
),
|
|
1474
|
-
presets.map((preset) => /* @__PURE__ */ (0,
|
|
1804
|
+
presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1475
1805
|
"div",
|
|
1476
1806
|
{
|
|
1477
1807
|
className: "dialkit-preset-item",
|
|
1478
1808
|
"data-active": String(preset.id === activePresetId),
|
|
1479
1809
|
onClick: () => handleSelect(preset.id),
|
|
1480
1810
|
children: [
|
|
1481
|
-
/* @__PURE__ */ (0,
|
|
1482
|
-
/* @__PURE__ */ (0,
|
|
1811
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dialkit-preset-name", children: preset.name }),
|
|
1812
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1483
1813
|
"button",
|
|
1484
1814
|
{
|
|
1485
1815
|
className: "dialkit-preset-delete",
|
|
1486
1816
|
onClick: (e) => handleDelete(e, preset.id),
|
|
1487
1817
|
title: "Delete preset",
|
|
1488
|
-
children: /* @__PURE__ */ (0,
|
|
1489
|
-
/* @__PURE__ */ (0,
|
|
1490
|
-
/* @__PURE__ */ (0,
|
|
1491
|
-
/* @__PURE__ */ (0,
|
|
1492
|
-
/* @__PURE__ */ (0,
|
|
1493
|
-
/* @__PURE__ */ (0,
|
|
1818
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1819
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M5 6.5L5.80734 18.2064C5.91582 19.7794 7.22348 21 8.80023 21H15.1998C16.7765 21 18.0842 19.7794 18.1927 18.2064L19 6.5" }),
|
|
1820
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M10 11V16" }),
|
|
1821
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M14 11V16" }),
|
|
1822
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3.5 6H20.5" }),
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M8.07092 5.74621C8.42348 3.89745 10.0485 2.5 12 2.5C13.9515 2.5 15.5765 3.89745 15.9291 5.74621" })
|
|
1494
1824
|
] })
|
|
1495
1825
|
}
|
|
1496
1826
|
)
|
|
@@ -1507,11 +1837,11 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1507
1837
|
}
|
|
1508
1838
|
|
|
1509
1839
|
// src/components/Panel.tsx
|
|
1510
|
-
var
|
|
1511
|
-
function Panel({ panel }) {
|
|
1512
|
-
const [copied, setCopied] = (0,
|
|
1513
|
-
const [isPanelOpen, setIsPanelOpen] = (0,
|
|
1514
|
-
const values = (0,
|
|
1840
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1841
|
+
function Panel({ panel, defaultOpen = true }) {
|
|
1842
|
+
const [copied, setCopied] = (0, import_react15.useState)(false);
|
|
1843
|
+
const [isPanelOpen, setIsPanelOpen] = (0, import_react15.useState)(defaultOpen);
|
|
1844
|
+
const values = (0, import_react15.useSyncExternalStore)(
|
|
1515
1845
|
(cb) => DialStore.subscribe(panel.id, cb),
|
|
1516
1846
|
() => DialStore.getValues(panel.id),
|
|
1517
1847
|
() => DialStore.getValues(panel.id)
|
|
@@ -1539,7 +1869,7 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1539
1869
|
const value = values[control.path];
|
|
1540
1870
|
switch (control.type) {
|
|
1541
1871
|
case "slider":
|
|
1542
|
-
return /* @__PURE__ */ (0,
|
|
1872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1543
1873
|
Slider,
|
|
1544
1874
|
{
|
|
1545
1875
|
label: control.label,
|
|
@@ -1552,7 +1882,7 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1552
1882
|
control.path
|
|
1553
1883
|
);
|
|
1554
1884
|
case "toggle":
|
|
1555
|
-
return /* @__PURE__ */ (0,
|
|
1885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1556
1886
|
Toggle,
|
|
1557
1887
|
{
|
|
1558
1888
|
label: control.label,
|
|
@@ -1562,7 +1892,7 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1562
1892
|
control.path
|
|
1563
1893
|
);
|
|
1564
1894
|
case "spring":
|
|
1565
|
-
return /* @__PURE__ */ (0,
|
|
1895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1566
1896
|
SpringControl,
|
|
1567
1897
|
{
|
|
1568
1898
|
panelId: panel.id,
|
|
@@ -1573,10 +1903,22 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1573
1903
|
},
|
|
1574
1904
|
control.path
|
|
1575
1905
|
);
|
|
1906
|
+
case "transition":
|
|
1907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1908
|
+
TransitionControl,
|
|
1909
|
+
{
|
|
1910
|
+
panelId: panel.id,
|
|
1911
|
+
path: control.path,
|
|
1912
|
+
label: control.label,
|
|
1913
|
+
value,
|
|
1914
|
+
onChange: (v) => DialStore.updateValue(panel.id, control.path, v)
|
|
1915
|
+
},
|
|
1916
|
+
control.path
|
|
1917
|
+
);
|
|
1576
1918
|
case "folder":
|
|
1577
|
-
return /* @__PURE__ */ (0,
|
|
1919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Folder, { title: control.label, defaultOpen: control.defaultOpen ?? true, children: control.children?.map(renderControl) }, control.path);
|
|
1578
1920
|
case "text":
|
|
1579
|
-
return /* @__PURE__ */ (0,
|
|
1921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1580
1922
|
TextControl,
|
|
1581
1923
|
{
|
|
1582
1924
|
label: control.label,
|
|
@@ -1587,7 +1929,7 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1587
1929
|
control.path
|
|
1588
1930
|
);
|
|
1589
1931
|
case "select":
|
|
1590
|
-
return /* @__PURE__ */ (0,
|
|
1932
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1591
1933
|
SelectControl,
|
|
1592
1934
|
{
|
|
1593
1935
|
label: control.label,
|
|
@@ -1598,7 +1940,7 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1598
1940
|
control.path
|
|
1599
1941
|
);
|
|
1600
1942
|
case "color":
|
|
1601
|
-
return /* @__PURE__ */ (0,
|
|
1943
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1602
1944
|
ColorControl,
|
|
1603
1945
|
{
|
|
1604
1946
|
label: control.label,
|
|
@@ -1607,54 +1949,43 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1607
1949
|
},
|
|
1608
1950
|
control.path
|
|
1609
1951
|
);
|
|
1952
|
+
case "action":
|
|
1953
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1954
|
+
"button",
|
|
1955
|
+
{
|
|
1956
|
+
className: "dialkit-button",
|
|
1957
|
+
onClick: () => DialStore.triggerAction(panel.id, control.path),
|
|
1958
|
+
children: control.label
|
|
1959
|
+
},
|
|
1960
|
+
control.path
|
|
1961
|
+
);
|
|
1610
1962
|
default:
|
|
1611
1963
|
return null;
|
|
1612
1964
|
}
|
|
1613
1965
|
};
|
|
1614
1966
|
const renderControls = () => {
|
|
1615
|
-
|
|
1616
|
-
let i = 0;
|
|
1617
|
-
while (i < panel.controls.length) {
|
|
1618
|
-
const control = panel.controls[i];
|
|
1619
|
-
if (control.type === "action") {
|
|
1620
|
-
result.push(
|
|
1621
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1622
|
-
"button",
|
|
1623
|
-
{
|
|
1624
|
-
className: "dialkit-button",
|
|
1625
|
-
onClick: () => DialStore.triggerAction(panel.id, control.path),
|
|
1626
|
-
children: control.label
|
|
1627
|
-
},
|
|
1628
|
-
control.path
|
|
1629
|
-
)
|
|
1630
|
-
);
|
|
1631
|
-
} else {
|
|
1632
|
-
result.push(renderControl(control));
|
|
1633
|
-
}
|
|
1634
|
-
i++;
|
|
1635
|
-
}
|
|
1636
|
-
return result;
|
|
1967
|
+
return panel.controls.map(renderControl);
|
|
1637
1968
|
};
|
|
1638
1969
|
const iconTransition = { type: "spring", visualDuration: 0.4, bounce: 0.1 };
|
|
1639
|
-
const toolbar = /* @__PURE__ */ (0,
|
|
1640
|
-
/* @__PURE__ */ (0,
|
|
1641
|
-
|
|
1970
|
+
const toolbar = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
1971
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1972
|
+
import_react16.motion.button,
|
|
1642
1973
|
{
|
|
1643
1974
|
className: "dialkit-toolbar-add",
|
|
1644
1975
|
onClick: handleAddPreset,
|
|
1645
1976
|
title: "Add preset",
|
|
1646
1977
|
whileTap: { scale: 0.9 },
|
|
1647
1978
|
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1648
|
-
children: /* @__PURE__ */ (0,
|
|
1649
|
-
/* @__PURE__ */ (0,
|
|
1650
|
-
/* @__PURE__ */ (0,
|
|
1651
|
-
/* @__PURE__ */ (0,
|
|
1652
|
-
/* @__PURE__ */ (0,
|
|
1653
|
-
/* @__PURE__ */ (0,
|
|
1979
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1980
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M4 6H20" }),
|
|
1981
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M4 12H10" }),
|
|
1982
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M15 15L21 15" }),
|
|
1983
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M18 12V18" }),
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M4 18H10" })
|
|
1654
1985
|
] })
|
|
1655
1986
|
}
|
|
1656
1987
|
),
|
|
1657
|
-
/* @__PURE__ */ (0,
|
|
1988
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1658
1989
|
PresetManager,
|
|
1659
1990
|
{
|
|
1660
1991
|
panelId: panel.id,
|
|
@@ -1663,8 +1994,8 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1663
1994
|
onAdd: handleAddPreset
|
|
1664
1995
|
}
|
|
1665
1996
|
),
|
|
1666
|
-
/* @__PURE__ */ (0,
|
|
1667
|
-
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1998
|
+
import_react16.motion.button,
|
|
1668
1999
|
{
|
|
1669
2000
|
className: "dialkit-toolbar-copy",
|
|
1670
2001
|
onClick: handleCopy,
|
|
@@ -1672,8 +2003,8 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1672
2003
|
whileTap: { scale: 0.95 },
|
|
1673
2004
|
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1674
2005
|
children: [
|
|
1675
|
-
/* @__PURE__ */ (0,
|
|
1676
|
-
|
|
2006
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react16.AnimatePresence, { initial: false, mode: "popLayout", children: copied ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2007
|
+
import_react16.motion.svg,
|
|
1677
2008
|
{
|
|
1678
2009
|
className: "dialkit-toolbar-copy-icon",
|
|
1679
2010
|
viewBox: "0 0 24 24",
|
|
@@ -1686,11 +2017,11 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1686
2017
|
animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
|
|
1687
2018
|
exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1688
2019
|
transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
1689
|
-
children: /* @__PURE__ */ (0,
|
|
2020
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M5 12.75L10 19L19 5" })
|
|
1690
2021
|
},
|
|
1691
2022
|
"check"
|
|
1692
|
-
) : /* @__PURE__ */ (0,
|
|
1693
|
-
|
|
2023
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2024
|
+
import_react16.motion.svg,
|
|
1694
2025
|
{
|
|
1695
2026
|
className: "dialkit-toolbar-copy-icon",
|
|
1696
2027
|
viewBox: "0 0 24 24",
|
|
@@ -1700,9 +2031,9 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1700
2031
|
exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1701
2032
|
transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
1702
2033
|
children: [
|
|
1703
|
-
/* @__PURE__ */ (0,
|
|
1704
|
-
/* @__PURE__ */ (0,
|
|
1705
|
-
/* @__PURE__ */ (0,
|
|
2034
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }),
|
|
2035
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M19.2405 16.1852L18.5436 14.3733C18.4571 14.1484 18.241 14 18 14C17.759 14 17.5429 14.1484 17.4564 14.3733L16.7595 16.1852C16.658 16.4493 16.4493 16.658 16.1852 16.7595L14.3733 17.4564C14.1484 17.5429 14 17.759 14 18C14 18.241 14.1484 18.4571 14.3733 18.5436L16.1852 19.2405C16.4493 19.342 16.658 19.5507 16.7595 19.8148L17.4564 21.6267C17.5429 21.8516 17.759 22 18 22C18.241 22 18.4571 21.8516 18.5436 21.6267L19.2405 19.8148C19.342 19.5507 19.5507 19.342 19.8148 19.2405L21.6267 18.5436C21.8516 18.4571 22 18.241 22 18C22 17.759 21.8516 17.5429 21.6267 17.4564L19.8148 16.7595C19.5507 16.658 19.342 16.4493 19.2405 16.1852Z", fill: "currentColor" }),
|
|
2036
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M16 5H17C18.6569 5 20 6.34315 20 8V11M8 5H7C5.34315 5 4 6.34315 4 8V18C4 19.6569 5.34315 21 7 21H12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
1706
2037
|
]
|
|
1707
2038
|
},
|
|
1708
2039
|
"clipboard"
|
|
@@ -1712,15 +2043,15 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1712
2043
|
}
|
|
1713
2044
|
)
|
|
1714
2045
|
] });
|
|
1715
|
-
return /* @__PURE__ */ (0,
|
|
2046
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Folder, { title: panel.name, defaultOpen, isRoot: true, onOpenChange: setIsPanelOpen, toolbar, children: renderControls() }) });
|
|
1716
2047
|
}
|
|
1717
2048
|
|
|
1718
2049
|
// src/components/DialRoot.tsx
|
|
1719
|
-
var
|
|
1720
|
-
function DialRoot({ position = "top-right" }) {
|
|
1721
|
-
const [panels, setPanels] = (0,
|
|
1722
|
-
const [mounted, setMounted] = (0,
|
|
1723
|
-
(0,
|
|
2050
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2051
|
+
function DialRoot({ position = "top-right", defaultOpen = true }) {
|
|
2052
|
+
const [panels, setPanels] = (0, import_react17.useState)([]);
|
|
2053
|
+
const [mounted, setMounted] = (0, import_react17.useState)(false);
|
|
2054
|
+
(0, import_react17.useEffect)(() => {
|
|
1724
2055
|
setMounted(true);
|
|
1725
2056
|
setPanels(DialStore.getPanels());
|
|
1726
2057
|
const unsubscribe = DialStore.subscribeGlobal(() => {
|
|
@@ -1734,14 +2065,14 @@ function DialRoot({ position = "top-right" }) {
|
|
|
1734
2065
|
if (panels.length === 0) {
|
|
1735
2066
|
return null;
|
|
1736
2067
|
}
|
|
1737
|
-
const content = /* @__PURE__ */ (0,
|
|
2068
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dialkit-root", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dialkit-panel", "data-position": position, children: panels.map((panel) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Panel, { panel, defaultOpen }, panel.id)) }) });
|
|
1738
2069
|
return (0, import_react_dom3.createPortal)(content, document.body);
|
|
1739
2070
|
}
|
|
1740
2071
|
|
|
1741
2072
|
// src/components/ButtonGroup.tsx
|
|
1742
|
-
var
|
|
2073
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1743
2074
|
function ButtonGroup({ buttons }) {
|
|
1744
|
-
return /* @__PURE__ */ (0,
|
|
2075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dialkit-button-group", children: buttons.map((button, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1745
2076
|
"button",
|
|
1746
2077
|
{
|
|
1747
2078
|
className: "dialkit-button",
|
|
@@ -1757,6 +2088,7 @@ function ButtonGroup({ buttons }) {
|
|
|
1757
2088
|
ColorControl,
|
|
1758
2089
|
DialRoot,
|
|
1759
2090
|
DialStore,
|
|
2091
|
+
EasingVisualization,
|
|
1760
2092
|
Folder,
|
|
1761
2093
|
PresetManager,
|
|
1762
2094
|
SelectControl,
|
|
@@ -1765,6 +2097,7 @@ function ButtonGroup({ buttons }) {
|
|
|
1765
2097
|
SpringVisualization,
|
|
1766
2098
|
TextControl,
|
|
1767
2099
|
Toggle,
|
|
2100
|
+
TransitionControl,
|
|
1768
2101
|
useDialKit
|
|
1769
2102
|
});
|
|
1770
2103
|
//# sourceMappingURL=index.cjs.map
|