dialkit 0.2.1 → 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/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
- getSpringMode(panelId, path) {
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,27 +256,43 @@ 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)) {
277
+ if (key === "_collapsed") continue;
200
278
  const path = prefix ? `${prefix}.${key}` : key;
201
279
  const label = this.formatLabel(key);
202
- if (Array.isArray(value) && value.length === 3 && typeof value[0] === "number") {
280
+ if (Array.isArray(value) && value.length <= 4 && typeof value[0] === "number") {
203
281
  controls.push({
204
282
  type: "slider",
205
283
  path,
206
284
  label,
207
285
  min: value[1],
208
286
  max: value[2],
209
- step: this.inferStep(value[1], value[2])
287
+ step: value[3] ?? this.inferStep(value[1], value[2])
210
288
  });
211
289
  } else if (typeof value === "number") {
212
290
  const { min, max, step } = this.inferRange(value);
213
291
  controls.push({ type: "slider", path, label, min, max, step });
214
292
  } else if (typeof value === "boolean") {
215
293
  controls.push({ type: "toggle", path, label });
216
- } else if (this.isSpringConfig(value)) {
217
- controls.push({ type: "spring", path, label });
294
+ } else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
295
+ controls.push({ type: "transition", path, label });
218
296
  } else if (this.isActionConfig(value)) {
219
297
  controls.push({ type: "action", path, label: value.label || label });
220
298
  } else if (this.isSelectConfig(value)) {
@@ -230,11 +308,14 @@ var DialStoreClass = class {
230
308
  controls.push({ type: "text", path, label });
231
309
  }
232
310
  } else if (typeof value === "object" && value !== null) {
311
+ const folderConfig = value;
312
+ const defaultOpen = "_collapsed" in folderConfig ? !folderConfig._collapsed : true;
233
313
  controls.push({
234
314
  type: "folder",
235
315
  path,
236
316
  label,
237
- children: this.parseConfig(value, path)
317
+ defaultOpen,
318
+ children: this.parseConfig(folderConfig, path)
238
319
  });
239
320
  }
240
321
  }
@@ -243,12 +324,13 @@ var DialStoreClass = class {
243
324
  flattenValues(config, prefix) {
244
325
  const values = {};
245
326
  for (const [key, value] of Object.entries(config)) {
327
+ if (key === "_collapsed") continue;
246
328
  const path = prefix ? `${prefix}.${key}` : key;
247
- if (Array.isArray(value) && value.length === 3 && typeof value[0] === "number") {
329
+ if (Array.isArray(value) && value.length <= 4 && typeof value[0] === "number") {
248
330
  values[path] = value[0];
249
331
  } else if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
250
332
  values[path] = value;
251
- } else if (this.isSpringConfig(value)) {
333
+ } else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
252
334
  values[path] = value;
253
335
  } else if (this.isActionConfig(value)) {
254
336
  values[path] = value;
@@ -269,6 +351,9 @@ var DialStoreClass = class {
269
351
  isSpringConfig(value) {
270
352
  return typeof value === "object" && value !== null && "type" in value && value.type === "spring";
271
353
  }
354
+ isEasingConfig(value) {
355
+ return typeof value === "object" && value !== null && "type" in value && value.type === "easing";
356
+ }
272
357
  isActionConfig(value) {
273
358
  return typeof value === "object" && value !== null && "type" in value && value.type === "action";
274
359
  }
@@ -307,6 +392,75 @@ var DialStoreClass = class {
307
392
  if (range <= 100) return 1;
308
393
  return 10;
309
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
+ }
310
464
  };
311
465
  var DialStore = new DialStoreClass();
312
466
 
@@ -315,12 +469,22 @@ function useDialKit(name, config, options) {
315
469
  const instanceId = (0, import_react.useId)();
316
470
  const panelId = `${name}-${instanceId}`;
317
471
  const configRef = (0, import_react.useRef)(config);
472
+ const serializedConfig = JSON.stringify(config);
473
+ configRef.current = config;
318
474
  const onActionRef = (0, import_react.useRef)(options?.onAction);
319
475
  onActionRef.current = options?.onAction;
320
476
  (0, import_react.useEffect)(() => {
321
477
  DialStore.registerPanel(panelId, name, configRef.current);
322
478
  return () => DialStore.unregisterPanel(panelId);
323
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]);
324
488
  (0, import_react.useEffect)(() => {
325
489
  return DialStore.subscribeActions(panelId, (action) => {
326
490
  onActionRef.current?.(action);
@@ -336,12 +500,13 @@ function useDialKit(name, config, options) {
336
500
  function buildResolvedValues(config, flatValues, prefix) {
337
501
  const result = {};
338
502
  for (const [key, configValue] of Object.entries(config)) {
503
+ if (key === "_collapsed") continue;
339
504
  const path = prefix ? `${prefix}.${key}` : key;
340
- if (Array.isArray(configValue) && configValue.length === 3 && typeof configValue[0] === "number") {
505
+ if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
341
506
  result[key] = flatValues[path] ?? configValue[0];
342
507
  } else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
343
508
  result[key] = flatValues[path] ?? configValue;
344
- } else if (isSpringConfig(configValue)) {
509
+ } else if (isSpringConfig(configValue) || isEasingConfig(configValue)) {
345
510
  result[key] = flatValues[path] ?? configValue;
346
511
  } else if (isActionConfig(configValue)) {
347
512
  result[key] = flatValues[path] ?? configValue;
@@ -364,6 +529,9 @@ function hasType(value, type) {
364
529
  function isSpringConfig(value) {
365
530
  return hasType(value, "spring");
366
531
  }
532
+ function isEasingConfig(value) {
533
+ return hasType(value, "easing");
534
+ }
367
535
  function isActionConfig(value) {
368
536
  return hasType(value, "action");
369
537
  }
@@ -382,12 +550,12 @@ function getFirstOptionValue(options) {
382
550
  }
383
551
 
384
552
  // src/components/DialRoot.tsx
385
- var import_react16 = require("react");
386
- var import_react_dom2 = require("react-dom");
553
+ var import_react17 = require("react");
554
+ var import_react_dom3 = require("react-dom");
387
555
 
388
556
  // src/components/Panel.tsx
389
- var import_react14 = require("react");
390
- var import_react15 = require("motion/react");
557
+ var import_react15 = require("react");
558
+ var import_react16 = require("motion/react");
391
559
 
392
560
  // src/components/Folder.tsx
393
561
  var import_react2 = require("react");
@@ -501,10 +669,14 @@ var CLICK_THRESHOLD = 3;
501
669
  var DEAD_ZONE = 32;
502
670
  var MAX_CURSOR_RANGE = 200;
503
671
  var MAX_STRETCH = 8;
672
+ function decimalsForStep(step) {
673
+ const s = step.toString();
674
+ const dot = s.indexOf(".");
675
+ return dot === -1 ? 0 : s.length - dot - 1;
676
+ }
504
677
  function roundValue(val, step) {
505
- const decimals = step >= 1 ? 0 : 2;
506
- const factor = 10 ** decimals;
507
- return Math.round(val * factor) / factor;
678
+ const raw = Math.round(val / step) * step;
679
+ return parseFloat(raw.toFixed(decimalsForStep(step)));
508
680
  }
509
681
  function snapToDecile(rawValue, min, max) {
510
682
  const normalized = (rawValue - min) / (max - min);
@@ -652,7 +824,8 @@ function Slider({
652
824
  if (!isInteracting) return;
653
825
  if (isClickRef.current) {
654
826
  const rawValue = positionToValue(e.clientX);
655
- const snappedValue = snapToDecile(rawValue, min, max);
827
+ const discreteSteps2 = (max - min) / step;
828
+ const snappedValue = discreteSteps2 <= 10 ? Math.max(min, Math.min(max, min + Math.round((rawValue - min) / step) * step)) : snapToDecile(rawValue, min, max);
656
829
  const newPct = percentFromValue(snappedValue);
657
830
  if (animRef.current) {
658
831
  animRef.current.stop();
@@ -732,7 +905,7 @@ function Slider({
732
905
  e.stopPropagation();
733
906
  e.preventDefault();
734
907
  setShowInput(true);
735
- setInputValue(step >= 1 ? value.toFixed(0) : value.toFixed(2));
908
+ setInputValue(value.toFixed(decimalsForStep(step)));
736
909
  }
737
910
  };
738
911
  const handleInputKeyDown = (e) => {
@@ -746,7 +919,7 @@ function Slider({
746
919
  const handleInputBlur = () => {
747
920
  handleInputSubmit();
748
921
  };
749
- const displayValue = step >= 1 ? value.toFixed(0) : value.toFixed(2);
922
+ const displayValue = value.toFixed(decimalsForStep(step));
750
923
  const HANDLE_BUFFER = 8;
751
924
  const LABEL_CSS_LEFT = 10;
752
925
  const VALUE_CSS_RIGHT = 10;
@@ -764,7 +937,18 @@ function Slider({
764
937
  const valueDodge = percentage < leftThreshold || percentage > rightThreshold;
765
938
  const handleOpacity = !isActive ? 0 : valueDodge ? 0.1 : isDragging ? 0.9 : 0.5;
766
939
  const fillBackground = isActive ? "rgba(255, 255, 255, 0.15)" : "rgba(255, 255, 255, 0.11)";
767
- const hashMarks = Array.from({ length: 9 }, (_, i) => {
940
+ const discreteSteps = (max - min) / step;
941
+ const hashMarks = discreteSteps <= 10 ? Array.from({ length: discreteSteps - 1 }, (_, i) => {
942
+ const pct = (i + 1) * step / (max - min) * 100;
943
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
944
+ "div",
945
+ {
946
+ className: "dialkit-slider-hashmark",
947
+ style: { left: `${pct}%` }
948
+ },
949
+ i
950
+ );
951
+ }) : Array.from({ length: 9 }, (_, i) => {
768
952
  const pct = (i + 1) * 10;
769
953
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
770
954
  "div",
@@ -1134,12 +1318,180 @@ function SpringControl({ panelId, path, label, spring, onChange }) {
1134
1318
  ] }) });
1135
1319
  }
1136
1320
 
1137
- // src/components/TextControl.tsx
1321
+ // src/components/EasingVisualization.tsx
1138
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");
1139
1491
  function TextControl({ label, value, onChange, placeholder }) {
1140
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dialkit-text-control", children: [
1141
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "dialkit-text-label", children: label }),
1142
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
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)(
1143
1495
  "input",
1144
1496
  {
1145
1497
  type: "text",
@@ -1153,9 +1505,10 @@ function TextControl({ label, value, onChange, placeholder }) {
1153
1505
  }
1154
1506
 
1155
1507
  // src/components/SelectControl.tsx
1156
- var import_react9 = require("react");
1157
- var import_react10 = require("motion/react");
1158
- var import_jsx_runtime8 = require("react/jsx-runtime");
1508
+ var import_react10 = require("react");
1509
+ var import_react_dom = require("react-dom");
1510
+ var import_react11 = require("motion/react");
1511
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1159
1512
  function toTitleCase(s) {
1160
1513
  return s.replace(/\b\w/g, (c) => c.toUpperCase());
1161
1514
  }
@@ -1165,33 +1518,60 @@ function normalizeOptions(options) {
1165
1518
  );
1166
1519
  }
1167
1520
  function SelectControl({ label, value, options, onChange }) {
1168
- const [isOpen, setIsOpen] = (0, import_react9.useState)(false);
1169
- const containerRef = (0, import_react9.useRef)(null);
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);
1170
1526
  const normalized = normalizeOptions(options);
1171
1527
  const selectedOption = normalized.find((o) => o.value === value);
1172
- (0, import_react9.useEffect)(() => {
1528
+ const updatePos = (0, import_react10.useCallback)(() => {
1529
+ const el = triggerRef.current;
1530
+ if (!el) return;
1531
+ const rect = el.getBoundingClientRect();
1532
+ const dropdownHeight = 8 + normalized.length * 36;
1533
+ const spaceBelow = window.innerHeight - rect.bottom - 4;
1534
+ const above = spaceBelow < dropdownHeight && rect.top > spaceBelow;
1535
+ setPos({
1536
+ top: above ? rect.top - 4 : rect.bottom + 4,
1537
+ left: rect.left,
1538
+ width: rect.width,
1539
+ above
1540
+ });
1541
+ }, [normalized.length]);
1542
+ (0, import_react10.useEffect)(() => {
1543
+ const root = triggerRef.current?.closest(".dialkit-root");
1544
+ setPortalTarget(root ?? document.body);
1545
+ }, []);
1546
+ (0, import_react10.useEffect)(() => {
1547
+ if (!isOpen) return;
1548
+ updatePos();
1549
+ }, [isOpen, updatePos]);
1550
+ (0, import_react10.useEffect)(() => {
1173
1551
  if (!isOpen) return;
1174
1552
  const handleClick = (e) => {
1175
- if (containerRef.current && !containerRef.current.contains(e.target)) {
1553
+ const target = e.target;
1554
+ if (triggerRef.current && !triggerRef.current.contains(target) && dropdownRef.current && !dropdownRef.current.contains(target)) {
1176
1555
  setIsOpen(false);
1177
1556
  }
1178
1557
  };
1179
1558
  document.addEventListener("mousedown", handleClick);
1180
1559
  return () => document.removeEventListener("mousedown", handleClick);
1181
1560
  }, [isOpen]);
1182
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ref: containerRef, className: "dialkit-select-row", children: [
1183
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1561
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dialkit-select-row", children: [
1562
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1184
1563
  "button",
1185
1564
  {
1565
+ ref: triggerRef,
1186
1566
  className: "dialkit-select-trigger",
1187
1567
  onClick: () => setIsOpen(!isOpen),
1188
1568
  "data-open": String(isOpen),
1189
1569
  children: [
1190
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dialkit-select-label", children: label }),
1191
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dialkit-select-right", children: [
1192
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dialkit-select-value", children: selectedOption?.label ?? value }),
1193
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1194
- import_react10.motion.svg,
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,
1195
1575
  {
1196
1576
  className: "dialkit-select-chevron",
1197
1577
  viewBox: "0 0 24 24",
@@ -1202,48 +1582,58 @@ function SelectControl({ label, value, options, onChange }) {
1202
1582
  strokeLinejoin: "round",
1203
1583
  animate: { rotate: isOpen ? 180 : 0 },
1204
1584
  transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
1205
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
1585
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
1206
1586
  }
1207
1587
  )
1208
1588
  ] })
1209
1589
  ]
1210
1590
  }
1211
1591
  ),
1212
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1213
- import_react10.motion.div,
1214
- {
1215
- className: "dialkit-select-dropdown",
1216
- initial: { opacity: 0, y: -8, scale: 0.95 },
1217
- animate: { opacity: 1, y: 0, scale: 1 },
1218
- exit: { opacity: 0, y: -8, scale: 0.95 },
1219
- transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
1220
- children: normalized.map((option) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1221
- "button",
1222
- {
1223
- className: "dialkit-select-option",
1224
- "data-selected": String(option.value === value),
1225
- onClick: () => {
1226
- onChange(option.value);
1227
- setIsOpen(false);
1228
- },
1229
- children: option.label
1592
+ portalTarget && (0, import_react_dom.createPortal)(
1593
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.AnimatePresence, { children: isOpen && pos && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1594
+ import_react11.motion.div,
1595
+ {
1596
+ ref: dropdownRef,
1597
+ className: "dialkit-select-dropdown",
1598
+ initial: { opacity: 0, y: pos.above ? 8 : -8, scale: 0.95 },
1599
+ animate: { opacity: 1, y: 0, scale: 1 },
1600
+ exit: { opacity: 0, y: pos.above ? 8 : -8, scale: 0.95 },
1601
+ transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
1602
+ style: {
1603
+ position: "fixed",
1604
+ left: pos.left,
1605
+ width: pos.width,
1606
+ ...pos.above ? { bottom: window.innerHeight - pos.top, transformOrigin: "bottom" } : { top: pos.top, transformOrigin: "top" }
1230
1607
  },
1231
- option.value
1232
- ))
1233
- }
1234
- ) })
1608
+ children: normalized.map((option) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1609
+ "button",
1610
+ {
1611
+ className: "dialkit-select-option",
1612
+ "data-selected": String(option.value === value),
1613
+ onClick: () => {
1614
+ onChange(option.value);
1615
+ setIsOpen(false);
1616
+ },
1617
+ children: option.label
1618
+ },
1619
+ option.value
1620
+ ))
1621
+ }
1622
+ ) }),
1623
+ portalTarget
1624
+ )
1235
1625
  ] });
1236
1626
  }
1237
1627
 
1238
1628
  // src/components/ColorControl.tsx
1239
- var import_react11 = require("react");
1240
- var import_jsx_runtime9 = require("react/jsx-runtime");
1629
+ var import_react12 = require("react");
1630
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1241
1631
  var HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
1242
1632
  function ColorControl({ label, value, onChange }) {
1243
- const [isEditing, setIsEditing] = (0, import_react11.useState)(false);
1244
- const [editValue, setEditValue] = (0, import_react11.useState)(value);
1245
- const colorInputRef = (0, import_react11.useRef)(null);
1246
- (0, import_react11.useEffect)(() => {
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)(() => {
1247
1637
  if (!isEditing) {
1248
1638
  setEditValue(value);
1249
1639
  }
@@ -1264,10 +1654,10 @@ function ColorControl({ label, value, onChange }) {
1264
1654
  setEditValue(value);
1265
1655
  }
1266
1656
  }
1267
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dialkit-color-control", children: [
1268
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dialkit-color-label", children: label }),
1269
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dialkit-color-inputs", children: [
1270
- isEditing ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
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)(
1271
1661
  "input",
1272
1662
  {
1273
1663
  type: "text",
@@ -1278,7 +1668,7 @@ function ColorControl({ label, value, onChange }) {
1278
1668
  onKeyDown: handleKeyDown,
1279
1669
  autoFocus: true
1280
1670
  }
1281
- ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1671
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1282
1672
  "span",
1283
1673
  {
1284
1674
  className: "dialkit-color-hex",
@@ -1286,7 +1676,7 @@ function ColorControl({ label, value, onChange }) {
1286
1676
  children: (value ?? "").toUpperCase()
1287
1677
  }
1288
1678
  ),
1289
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1679
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1290
1680
  "button",
1291
1681
  {
1292
1682
  className: "dialkit-color-swatch",
@@ -1295,7 +1685,7 @@ function ColorControl({ label, value, onChange }) {
1295
1685
  title: "Pick color"
1296
1686
  }
1297
1687
  ),
1298
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1688
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1299
1689
  "input",
1300
1690
  {
1301
1691
  ref: colorInputRef,
@@ -1314,18 +1704,18 @@ function expandShorthandHex(hex) {
1314
1704
  }
1315
1705
 
1316
1706
  // src/components/PresetManager.tsx
1317
- var import_react12 = require("react");
1318
- var import_react_dom = require("react-dom");
1319
- var import_react13 = require("motion/react");
1320
- var import_jsx_runtime10 = require("react/jsx-runtime");
1707
+ var import_react13 = require("react");
1708
+ var import_react_dom2 = require("react-dom");
1709
+ var import_react14 = require("motion/react");
1710
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1321
1711
  function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1322
- const [isOpen, setIsOpen] = (0, import_react12.useState)(false);
1323
- const triggerRef = (0, import_react12.useRef)(null);
1324
- const dropdownRef = (0, import_react12.useRef)(null);
1325
- const [pos, setPos] = (0, import_react12.useState)({ top: 0, left: 0, width: 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 });
1326
1716
  const hasPresets = presets.length > 0;
1327
1717
  const activePreset = presets.find((p) => p.id === activePresetId);
1328
- const open = (0, import_react12.useCallback)(() => {
1718
+ const open = (0, import_react13.useCallback)(() => {
1329
1719
  if (!hasPresets) return;
1330
1720
  const rect = triggerRef.current?.getBoundingClientRect();
1331
1721
  if (rect) {
@@ -1333,12 +1723,12 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1333
1723
  }
1334
1724
  setIsOpen(true);
1335
1725
  }, [hasPresets]);
1336
- const close = (0, import_react12.useCallback)(() => setIsOpen(false), []);
1337
- const toggle = (0, import_react12.useCallback)(() => {
1726
+ const close = (0, import_react13.useCallback)(() => setIsOpen(false), []);
1727
+ const toggle = (0, import_react13.useCallback)(() => {
1338
1728
  if (isOpen) close();
1339
1729
  else open();
1340
1730
  }, [isOpen, open, close]);
1341
- (0, import_react12.useEffect)(() => {
1731
+ (0, import_react13.useEffect)(() => {
1342
1732
  if (!isOpen) return;
1343
1733
  const handler = (e) => {
1344
1734
  const target = e.target;
@@ -1360,8 +1750,8 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1360
1750
  e.stopPropagation();
1361
1751
  DialStore.deletePreset(panelId, presetId);
1362
1752
  };
1363
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dialkit-preset-manager", children: [
1364
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1753
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dialkit-preset-manager", children: [
1754
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1365
1755
  "button",
1366
1756
  {
1367
1757
  ref: triggerRef,
@@ -1371,9 +1761,9 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1371
1761
  "data-has-preset": String(!!activePreset),
1372
1762
  "data-disabled": String(!hasPresets),
1373
1763
  children: [
1374
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-preset-label", children: activePreset ? activePreset.name : "Version 1" }),
1375
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1376
- import_react13.motion.svg,
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,
1377
1767
  {
1378
1768
  className: "dialkit-select-chevron",
1379
1769
  viewBox: "0 0 24 24",
@@ -1384,53 +1774,53 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1384
1774
  strokeLinejoin: "round",
1385
1775
  animate: { rotate: isOpen ? 180 : 0, opacity: hasPresets ? 0.6 : 0.25 },
1386
1776
  transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
1387
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
1777
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
1388
1778
  }
1389
1779
  )
1390
1780
  ]
1391
1781
  }
1392
1782
  ),
1393
- (0, import_react_dom.createPortal)(
1394
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react13.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1395
- import_react13.motion.div,
1783
+ (0, import_react_dom2.createPortal)(
1784
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react14.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1785
+ import_react14.motion.div,
1396
1786
  {
1397
1787
  ref: dropdownRef,
1398
- className: "dialkit-preset-dropdown",
1788
+ className: "dialkit-root dialkit-preset-dropdown",
1399
1789
  style: { position: "fixed", top: pos.top, left: pos.left, minWidth: pos.width },
1400
1790
  initial: { opacity: 0, y: 4, scale: 0.97 },
1401
1791
  animate: { opacity: 1, y: 0, scale: 1 },
1402
1792
  exit: { opacity: 0, y: 4, scale: 0.97, pointerEvents: "none" },
1403
1793
  transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
1404
1794
  children: [
1405
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1795
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1406
1796
  "div",
1407
1797
  {
1408
1798
  className: "dialkit-preset-item",
1409
1799
  "data-active": String(!activePresetId),
1410
1800
  onClick: () => handleSelect(null),
1411
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-preset-name", children: "Version 1" })
1801
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dialkit-preset-name", children: "Version 1" })
1412
1802
  }
1413
1803
  ),
1414
- presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1804
+ presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1415
1805
  "div",
1416
1806
  {
1417
1807
  className: "dialkit-preset-item",
1418
1808
  "data-active": String(preset.id === activePresetId),
1419
1809
  onClick: () => handleSelect(preset.id),
1420
1810
  children: [
1421
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-preset-name", children: preset.name }),
1422
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1811
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dialkit-preset-name", children: preset.name }),
1812
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1423
1813
  "button",
1424
1814
  {
1425
1815
  className: "dialkit-preset-delete",
1426
1816
  onClick: (e) => handleDelete(e, preset.id),
1427
1817
  title: "Delete preset",
1428
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1429
- /* @__PURE__ */ (0, import_jsx_runtime10.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" }),
1430
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M10 11V16" }),
1431
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M14 11V16" }),
1432
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M3.5 6H20.5" }),
1433
- /* @__PURE__ */ (0, import_jsx_runtime10.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" })
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" })
1434
1824
  ] })
1435
1825
  }
1436
1826
  )
@@ -1447,11 +1837,11 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1447
1837
  }
1448
1838
 
1449
1839
  // src/components/Panel.tsx
1450
- var import_jsx_runtime11 = require("react/jsx-runtime");
1451
- function Panel({ panel }) {
1452
- const [copied, setCopied] = (0, import_react14.useState)(false);
1453
- const [isPanelOpen, setIsPanelOpen] = (0, import_react14.useState)(true);
1454
- const values = (0, import_react14.useSyncExternalStore)(
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)(
1455
1845
  (cb) => DialStore.subscribe(panel.id, cb),
1456
1846
  () => DialStore.getValues(panel.id),
1457
1847
  () => DialStore.getValues(panel.id)
@@ -1479,7 +1869,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1479
1869
  const value = values[control.path];
1480
1870
  switch (control.type) {
1481
1871
  case "slider":
1482
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1872
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1483
1873
  Slider,
1484
1874
  {
1485
1875
  label: control.label,
@@ -1492,7 +1882,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1492
1882
  control.path
1493
1883
  );
1494
1884
  case "toggle":
1495
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1885
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1496
1886
  Toggle,
1497
1887
  {
1498
1888
  label: control.label,
@@ -1502,7 +1892,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1502
1892
  control.path
1503
1893
  );
1504
1894
  case "spring":
1505
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1895
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1506
1896
  SpringControl,
1507
1897
  {
1508
1898
  panelId: panel.id,
@@ -1513,10 +1903,22 @@ Apply these values as the new defaults in the useDialKit call.`;
1513
1903
  },
1514
1904
  control.path
1515
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
+ );
1516
1918
  case "folder":
1517
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Folder, { title: control.label, children: control.children?.map(renderControl) }, control.path);
1919
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Folder, { title: control.label, defaultOpen: control.defaultOpen ?? true, children: control.children?.map(renderControl) }, control.path);
1518
1920
  case "text":
1519
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1921
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1520
1922
  TextControl,
1521
1923
  {
1522
1924
  label: control.label,
@@ -1527,7 +1929,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1527
1929
  control.path
1528
1930
  );
1529
1931
  case "select":
1530
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1932
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1531
1933
  SelectControl,
1532
1934
  {
1533
1935
  label: control.label,
@@ -1538,7 +1940,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1538
1940
  control.path
1539
1941
  );
1540
1942
  case "color":
1541
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1943
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1542
1944
  ColorControl,
1543
1945
  {
1544
1946
  label: control.label,
@@ -1547,54 +1949,43 @@ Apply these values as the new defaults in the useDialKit call.`;
1547
1949
  },
1548
1950
  control.path
1549
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
+ );
1550
1962
  default:
1551
1963
  return null;
1552
1964
  }
1553
1965
  };
1554
1966
  const renderControls = () => {
1555
- const result = [];
1556
- let i = 0;
1557
- while (i < panel.controls.length) {
1558
- const control = panel.controls[i];
1559
- if (control.type === "action") {
1560
- result.push(
1561
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1562
- "button",
1563
- {
1564
- className: "dialkit-button",
1565
- onClick: () => DialStore.triggerAction(panel.id, control.path),
1566
- children: control.label
1567
- },
1568
- control.path
1569
- )
1570
- );
1571
- } else {
1572
- result.push(renderControl(control));
1573
- }
1574
- i++;
1575
- }
1576
- return result;
1967
+ return panel.controls.map(renderControl);
1577
1968
  };
1578
1969
  const iconTransition = { type: "spring", visualDuration: 0.4, bounce: 0.1 };
1579
- const toolbar = /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1580
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1581
- import_react15.motion.button,
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,
1582
1973
  {
1583
1974
  className: "dialkit-toolbar-add",
1584
1975
  onClick: handleAddPreset,
1585
1976
  title: "Add preset",
1586
1977
  whileTap: { scale: 0.9 },
1587
1978
  transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
1588
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
1589
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 6H20" }),
1590
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 12H10" }),
1591
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M15 15L21 15" }),
1592
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M18 12V18" }),
1593
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 18H10" })
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" })
1594
1985
  ] })
1595
1986
  }
1596
1987
  ),
1597
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1988
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1598
1989
  PresetManager,
1599
1990
  {
1600
1991
  panelId: panel.id,
@@ -1603,8 +1994,8 @@ Apply these values as the new defaults in the useDialKit call.`;
1603
1994
  onAdd: handleAddPreset
1604
1995
  }
1605
1996
  ),
1606
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1607
- import_react15.motion.button,
1997
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1998
+ import_react16.motion.button,
1608
1999
  {
1609
2000
  className: "dialkit-toolbar-copy",
1610
2001
  onClick: handleCopy,
@@ -1612,8 +2003,8 @@ Apply these values as the new defaults in the useDialKit call.`;
1612
2003
  whileTap: { scale: 0.95 },
1613
2004
  transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
1614
2005
  children: [
1615
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react15.AnimatePresence, { initial: false, mode: "popLayout", children: copied ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1616
- import_react15.motion.svg,
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,
1617
2008
  {
1618
2009
  className: "dialkit-toolbar-copy-icon",
1619
2010
  viewBox: "0 0 24 24",
@@ -1626,11 +2017,11 @@ Apply these values as the new defaults in the useDialKit call.`;
1626
2017
  animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
1627
2018
  exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
1628
2019
  transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
1629
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M5 12.75L10 19L19 5" })
2020
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M5 12.75L10 19L19 5" })
1630
2021
  },
1631
2022
  "check"
1632
- ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1633
- import_react15.motion.svg,
2023
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2024
+ import_react16.motion.svg,
1634
2025
  {
1635
2026
  className: "dialkit-toolbar-copy-icon",
1636
2027
  viewBox: "0 0 24 24",
@@ -1640,9 +2031,9 @@ Apply these values as the new defaults in the useDialKit call.`;
1640
2031
  exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
1641
2032
  transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
1642
2033
  children: [
1643
- /* @__PURE__ */ (0, import_jsx_runtime11.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" }),
1644
- /* @__PURE__ */ (0, import_jsx_runtime11.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" }),
1645
- /* @__PURE__ */ (0, import_jsx_runtime11.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" })
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" })
1646
2037
  ]
1647
2038
  },
1648
2039
  "clipboard"
@@ -1652,15 +2043,15 @@ Apply these values as the new defaults in the useDialKit call.`;
1652
2043
  }
1653
2044
  )
1654
2045
  ] });
1655
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Folder, { title: panel.name, defaultOpen: true, isRoot: true, onOpenChange: setIsPanelOpen, toolbar, children: renderControls() }) });
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() }) });
1656
2047
  }
1657
2048
 
1658
2049
  // src/components/DialRoot.tsx
1659
- var import_jsx_runtime12 = require("react/jsx-runtime");
1660
- function DialRoot({ position = "top-right" }) {
1661
- const [panels, setPanels] = (0, import_react16.useState)([]);
1662
- const [mounted, setMounted] = (0, import_react16.useState)(false);
1663
- (0, import_react16.useEffect)(() => {
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)(() => {
1664
2055
  setMounted(true);
1665
2056
  setPanels(DialStore.getPanels());
1666
2057
  const unsubscribe = DialStore.subscribeGlobal(() => {
@@ -1674,14 +2065,14 @@ function DialRoot({ position = "top-right" }) {
1674
2065
  if (panels.length === 0) {
1675
2066
  return null;
1676
2067
  }
1677
- const content = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dialkit-root", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dialkit-panel", "data-position": position, children: panels.map((panel) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Panel, { panel }, panel.id)) }) });
1678
- return (0, import_react_dom2.createPortal)(content, document.body);
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)) }) });
2069
+ return (0, import_react_dom3.createPortal)(content, document.body);
1679
2070
  }
1680
2071
 
1681
2072
  // src/components/ButtonGroup.tsx
1682
- var import_jsx_runtime13 = require("react/jsx-runtime");
2073
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1683
2074
  function ButtonGroup({ buttons }) {
1684
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dialkit-button-group", children: buttons.map((button, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2075
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dialkit-button-group", children: buttons.map((button, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1685
2076
  "button",
1686
2077
  {
1687
2078
  className: "dialkit-button",
@@ -1697,6 +2088,7 @@ function ButtonGroup({ buttons }) {
1697
2088
  ColorControl,
1698
2089
  DialRoot,
1699
2090
  DialStore,
2091
+ EasingVisualization,
1700
2092
  Folder,
1701
2093
  PresetManager,
1702
2094
  SelectControl,
@@ -1705,6 +2097,7 @@ function ButtonGroup({ buttons }) {
1705
2097
  SpringVisualization,
1706
2098
  TextControl,
1707
2099
  Toggle,
2100
+ TransitionControl,
1708
2101
  useDialKit
1709
2102
  });
1710
2103
  //# sourceMappingURL=index.cjs.map