dialkit 0.2.2 → 1.1.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.
Files changed (85) hide show
  1. package/README.md +135 -2
  2. package/dist/index.cjs +512 -176
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +40 -8
  5. package/dist/index.d.ts +40 -8
  6. package/dist/index.js +484 -150
  7. package/dist/index.js.map +1 -1
  8. package/dist/solid/index.cjs +2612 -0
  9. package/dist/solid/index.cjs.map +1 -0
  10. package/dist/solid/index.d.cts +228 -0
  11. package/dist/solid/index.d.ts +228 -0
  12. package/dist/solid/index.js +2573 -0
  13. package/dist/solid/index.js.map +1 -0
  14. package/dist/store/index.cjs +450 -0
  15. package/dist/store/index.cjs.map +1 -0
  16. package/dist/store/index.d.cts +124 -0
  17. package/dist/store/index.d.ts +124 -0
  18. package/dist/store/index.js +425 -0
  19. package/dist/store/index.js.map +1 -0
  20. package/dist/styles.css +38 -1
  21. package/dist/svelte/Portal.svelte +30 -0
  22. package/dist/svelte/Portal.svelte.d.ts +9 -0
  23. package/dist/svelte/Portal.svelte.d.ts.map +1 -0
  24. package/dist/svelte/components/ButtonGroup.svelte +16 -0
  25. package/dist/svelte/components/ButtonGroup.svelte.d.ts +11 -0
  26. package/dist/svelte/components/ButtonGroup.svelte.d.ts.map +1 -0
  27. package/dist/svelte/components/ColorControl.svelte +81 -0
  28. package/dist/svelte/components/ColorControl.svelte.d.ts +9 -0
  29. package/dist/svelte/components/ColorControl.svelte.d.ts.map +1 -0
  30. package/dist/svelte/components/ControlRenderer.svelte +84 -0
  31. package/dist/svelte/components/ControlRenderer.svelte.d.ts +11 -0
  32. package/dist/svelte/components/ControlRenderer.svelte.d.ts.map +1 -0
  33. package/dist/svelte/components/DialRoot.svelte +65 -0
  34. package/dist/svelte/components/DialRoot.svelte.d.ts +11 -0
  35. package/dist/svelte/components/DialRoot.svelte.d.ts.map +1 -0
  36. package/dist/svelte/components/EasingVisualization.svelte +50 -0
  37. package/dist/svelte/components/EasingVisualization.svelte.d.ts +10 -0
  38. package/dist/svelte/components/EasingVisualization.svelte.d.ts.map +1 -0
  39. package/dist/svelte/components/Folder.svelte +204 -0
  40. package/dist/svelte/components/Folder.svelte.d.ts +14 -0
  41. package/dist/svelte/components/Folder.svelte.d.ts.map +1 -0
  42. package/dist/svelte/components/Panel.svelte +144 -0
  43. package/dist/svelte/components/Panel.svelte.d.ts +10 -0
  44. package/dist/svelte/components/Panel.svelte.d.ts.map +1 -0
  45. package/dist/svelte/components/PresetManager.svelte +156 -0
  46. package/dist/svelte/components/PresetManager.svelte.d.ts +10 -0
  47. package/dist/svelte/components/PresetManager.svelte.d.ts.map +1 -0
  48. package/dist/svelte/components/SegmentedControl.svelte +106 -0
  49. package/dist/svelte/components/SegmentedControl.svelte.d.ts +13 -0
  50. package/dist/svelte/components/SegmentedControl.svelte.d.ts.map +1 -0
  51. package/dist/svelte/components/SelectControl.svelte +151 -0
  52. package/dist/svelte/components/SelectControl.svelte.d.ts +14 -0
  53. package/dist/svelte/components/SelectControl.svelte.d.ts.map +1 -0
  54. package/dist/svelte/components/Slider.svelte +345 -0
  55. package/dist/svelte/components/Slider.svelte.d.ts +13 -0
  56. package/dist/svelte/components/Slider.svelte.d.ts.map +1 -0
  57. package/dist/svelte/components/SpringControl.svelte +124 -0
  58. package/dist/svelte/components/SpringControl.svelte.d.ts +12 -0
  59. package/dist/svelte/components/SpringControl.svelte.d.ts.map +1 -0
  60. package/dist/svelte/components/SpringVisualization.svelte +115 -0
  61. package/dist/svelte/components/SpringVisualization.svelte.d.ts +9 -0
  62. package/dist/svelte/components/SpringVisualization.svelte.d.ts.map +1 -0
  63. package/dist/svelte/components/TextControl.svelte +19 -0
  64. package/dist/svelte/components/TextControl.svelte.d.ts +10 -0
  65. package/dist/svelte/components/TextControl.svelte.d.ts.map +1 -0
  66. package/dist/svelte/components/Toggle.svelte +21 -0
  67. package/dist/svelte/components/Toggle.svelte.d.ts +9 -0
  68. package/dist/svelte/components/Toggle.svelte.d.ts.map +1 -0
  69. package/dist/svelte/components/TransitionControl.svelte +200 -0
  70. package/dist/svelte/components/TransitionControl.svelte.d.ts +12 -0
  71. package/dist/svelte/components/TransitionControl.svelte.d.ts.map +1 -0
  72. package/dist/svelte/components/transitions.d.ts +6 -0
  73. package/dist/svelte/components/transitions.d.ts.map +1 -0
  74. package/dist/svelte/components/transitions.js +14 -0
  75. package/dist/svelte/createDialKit.svelte.d.ts +7 -0
  76. package/dist/svelte/createDialKit.svelte.d.ts.map +1 -0
  77. package/dist/svelte/createDialKit.svelte.js +82 -0
  78. package/dist/svelte/index.d.ts +19 -0
  79. package/dist/svelte/index.d.ts.map +1 -0
  80. package/dist/svelte/index.js +19 -0
  81. package/dist/svelte/shims.d.ts +9 -0
  82. package/dist/svelte/theme-css.d.ts +2 -0
  83. package/dist/svelte/theme-css.d.ts.map +1 -0
  84. package/dist/svelte/theme-css.js +1097 -0
  85. package/package.json +56 -10
package/dist/index.js CHANGED
@@ -19,15 +19,67 @@ var DialStoreClass = class {
19
19
  registerPanel(id, name, config) {
20
20
  const controls = this.parseConfig(config, "");
21
21
  const values = this.flattenValues(config, "");
22
+ this.initTransitionModes(config, "", values);
22
23
  this.panels.set(id, { id, name, controls, values });
23
24
  this.snapshots.set(id, { ...values });
24
25
  this.baseValues.set(id, { ...values });
25
26
  this.notifyGlobal();
26
27
  }
28
+ updatePanel(id, name, config) {
29
+ const existing = this.panels.get(id);
30
+ if (!existing) {
31
+ this.registerPanel(id, name, config);
32
+ return;
33
+ }
34
+ const controls = this.parseConfig(config, "");
35
+ const controlsByPath = this.mapControlsByPath(controls);
36
+ const defaultValues = this.flattenValues(config, "");
37
+ const nextValues = {};
38
+ for (const [path, defaultValue] of Object.entries(defaultValues)) {
39
+ nextValues[path] = this.normalizePreservedValue(
40
+ existing.values[path],
41
+ defaultValue,
42
+ controlsByPath.get(path)
43
+ );
44
+ }
45
+ this.initTransitionModes(config, "", nextValues);
46
+ for (const [path, mode] of Object.entries(existing.values)) {
47
+ if (!path.endsWith(".__mode")) {
48
+ continue;
49
+ }
50
+ const transitionPath = path.slice(0, -"__mode".length - 1);
51
+ const transitionControl = controlsByPath.get(transitionPath);
52
+ if (transitionControl?.type === "transition") {
53
+ nextValues[path] = mode;
54
+ }
55
+ }
56
+ const nextPanel = { id, name, controls, values: nextValues };
57
+ this.panels.set(id, nextPanel);
58
+ this.snapshots.set(id, { ...nextValues });
59
+ const previousBaseValues = this.baseValues.get(id) ?? {};
60
+ const nextBaseValues = {};
61
+ for (const [path, defaultValue] of Object.entries(defaultValues)) {
62
+ nextBaseValues[path] = this.normalizePreservedValue(
63
+ previousBaseValues[path],
64
+ defaultValue,
65
+ controlsByPath.get(path)
66
+ );
67
+ }
68
+ for (const [path, value] of Object.entries(nextValues)) {
69
+ if (path.endsWith(".__mode")) {
70
+ nextBaseValues[path] = value;
71
+ }
72
+ }
73
+ this.baseValues.set(id, nextBaseValues);
74
+ this.notify(id);
75
+ this.notifyGlobal();
76
+ }
27
77
  unregisterPanel(id) {
28
78
  this.panels.delete(id);
29
79
  this.listeners.delete(id);
30
80
  this.snapshots.delete(id);
81
+ this.actionListeners.delete(id);
82
+ this.baseValues.delete(id);
31
83
  this.notifyGlobal();
32
84
  }
33
85
  updateValue(panelId, path, value) {
@@ -47,13 +99,21 @@ var DialStoreClass = class {
47
99
  this.notify(panelId);
48
100
  }
49
101
  updateSpringMode(panelId, path, mode) {
102
+ this.updateTransitionMode(panelId, path, mode);
103
+ }
104
+ getSpringMode(panelId, path) {
105
+ const mode = this.getTransitionMode(panelId, path);
106
+ if (mode === "easing") return "simple";
107
+ return mode;
108
+ }
109
+ updateTransitionMode(panelId, path, mode) {
50
110
  const panel = this.panels.get(panelId);
51
111
  if (!panel) return;
52
112
  panel.values[`${path}.__mode`] = mode;
53
113
  this.snapshots.set(panelId, { ...panel.values });
54
114
  this.notify(panelId);
55
115
  }
56
- getSpringMode(panelId, path) {
116
+ getTransitionMode(panelId, path) {
57
117
  const panel = this.panels.get(panelId);
58
118
  if (!panel) return "simple";
59
119
  return panel.values[`${path}.__mode`] || "simple";
@@ -157,6 +217,21 @@ var DialStoreClass = class {
157
217
  notifyGlobal() {
158
218
  this.globalListeners.forEach((fn) => fn());
159
219
  }
220
+ initTransitionModes(config, prefix, values) {
221
+ for (const [key, value] of Object.entries(config)) {
222
+ if (key === "_collapsed") continue;
223
+ const path = prefix ? `${prefix}.${key}` : key;
224
+ if (this.isEasingConfig(value)) {
225
+ values[`${path}.__mode`] = "easing";
226
+ } else if (this.isSpringConfig(value)) {
227
+ const hasPhysics = value.stiffness !== void 0 || value.damping !== void 0 || value.mass !== void 0;
228
+ const hasTime = value.visualDuration !== void 0 || value.bounce !== void 0;
229
+ values[`${path}.__mode`] = hasPhysics && !hasTime ? "advanced" : "simple";
230
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value) && !this.isActionConfig(value) && !this.isSelectConfig(value) && !this.isColorConfig(value) && !this.isTextConfig(value)) {
231
+ this.initTransitionModes(value, path, values);
232
+ }
233
+ }
234
+ }
160
235
  parseConfig(config, prefix) {
161
236
  const controls = [];
162
237
  for (const [key, value] of Object.entries(config)) {
@@ -177,8 +252,8 @@ var DialStoreClass = class {
177
252
  controls.push({ type: "slider", path, label, min, max, step });
178
253
  } else if (typeof value === "boolean") {
179
254
  controls.push({ type: "toggle", path, label });
180
- } else if (this.isSpringConfig(value)) {
181
- controls.push({ type: "spring", path, label });
255
+ } else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
256
+ controls.push({ type: "transition", path, label });
182
257
  } else if (this.isActionConfig(value)) {
183
258
  controls.push({ type: "action", path, label: value.label || label });
184
259
  } else if (this.isSelectConfig(value)) {
@@ -216,7 +291,7 @@ var DialStoreClass = class {
216
291
  values[path] = value[0];
217
292
  } else if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
218
293
  values[path] = value;
219
- } else if (this.isSpringConfig(value)) {
294
+ } else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
220
295
  values[path] = value;
221
296
  } else if (this.isActionConfig(value)) {
222
297
  values[path] = value;
@@ -237,6 +312,9 @@ var DialStoreClass = class {
237
312
  isSpringConfig(value) {
238
313
  return typeof value === "object" && value !== null && "type" in value && value.type === "spring";
239
314
  }
315
+ isEasingConfig(value) {
316
+ return typeof value === "object" && value !== null && "type" in value && value.type === "easing";
317
+ }
240
318
  isActionConfig(value) {
241
319
  return typeof value === "object" && value !== null && "type" in value && value.type === "action";
242
320
  }
@@ -275,6 +353,75 @@ var DialStoreClass = class {
275
353
  if (range <= 100) return 1;
276
354
  return 10;
277
355
  }
356
+ normalizePreservedValue(existingValue, defaultValue, control) {
357
+ if (existingValue === void 0 || !control) {
358
+ return defaultValue;
359
+ }
360
+ switch (control.type) {
361
+ case "slider": {
362
+ if (typeof existingValue !== "number" || typeof defaultValue !== "number") {
363
+ return defaultValue;
364
+ }
365
+ const min = control.min ?? Number.NEGATIVE_INFINITY;
366
+ const max = control.max ?? Number.POSITIVE_INFINITY;
367
+ const clamped = Math.min(max, Math.max(min, existingValue));
368
+ if (typeof control.step !== "number" || control.step <= 0) {
369
+ return clamped;
370
+ }
371
+ return this.roundToStep(clamped, min, max, control.step);
372
+ }
373
+ case "toggle":
374
+ return typeof existingValue === "boolean" ? existingValue : defaultValue;
375
+ case "select": {
376
+ if (typeof existingValue !== "string") {
377
+ return defaultValue;
378
+ }
379
+ const options = control.options ?? [];
380
+ const validValues = new Set(options.map((option) => typeof option === "string" ? option : option.value));
381
+ return validValues.has(existingValue) ? existingValue : defaultValue;
382
+ }
383
+ case "color":
384
+ case "text":
385
+ return typeof existingValue === "string" ? existingValue : defaultValue;
386
+ case "transition":
387
+ if (this.isSpringConfig(defaultValue)) {
388
+ return this.isSpringConfig(existingValue) ? existingValue : defaultValue;
389
+ }
390
+ if (this.isEasingConfig(defaultValue)) {
391
+ return this.isEasingConfig(existingValue) ? existingValue : defaultValue;
392
+ }
393
+ return defaultValue;
394
+ case "action":
395
+ return defaultValue;
396
+ default:
397
+ return defaultValue;
398
+ }
399
+ }
400
+ roundToStep(value, min, max, step) {
401
+ const snapped = min + Math.round((value - min) / step) * step;
402
+ const clamped = Math.min(max, Math.max(min, snapped));
403
+ const precision = this.stepPrecision(step);
404
+ return Number(clamped.toFixed(precision));
405
+ }
406
+ stepPrecision(step) {
407
+ const text = String(step);
408
+ const decimalIndex = text.indexOf(".");
409
+ return decimalIndex === -1 ? 0 : text.length - decimalIndex - 1;
410
+ }
411
+ mapControlsByPath(controls) {
412
+ const map = /* @__PURE__ */ new Map();
413
+ const visit = (nodes) => {
414
+ for (const node of nodes) {
415
+ if (node.type === "folder" && node.children) {
416
+ visit(node.children);
417
+ continue;
418
+ }
419
+ map.set(node.path, node);
420
+ }
421
+ };
422
+ visit(controls);
423
+ return map;
424
+ }
278
425
  };
279
426
  var DialStore = new DialStoreClass();
280
427
 
@@ -283,12 +430,22 @@ function useDialKit(name, config, options) {
283
430
  const instanceId = useId();
284
431
  const panelId = `${name}-${instanceId}`;
285
432
  const configRef = useRef(config);
433
+ const serializedConfig = JSON.stringify(config);
434
+ configRef.current = config;
286
435
  const onActionRef = useRef(options?.onAction);
287
436
  onActionRef.current = options?.onAction;
288
437
  useEffect(() => {
289
438
  DialStore.registerPanel(panelId, name, configRef.current);
290
439
  return () => DialStore.unregisterPanel(panelId);
291
440
  }, [panelId, name]);
441
+ const mountedRef = useRef(false);
442
+ useEffect(() => {
443
+ if (!mountedRef.current) {
444
+ mountedRef.current = true;
445
+ return;
446
+ }
447
+ DialStore.updatePanel(panelId, name, configRef.current);
448
+ }, [panelId, name, serializedConfig]);
292
449
  useEffect(() => {
293
450
  return DialStore.subscribeActions(panelId, (action) => {
294
451
  onActionRef.current?.(action);
@@ -310,7 +467,7 @@ function buildResolvedValues(config, flatValues, prefix) {
310
467
  result[key] = flatValues[path] ?? configValue[0];
311
468
  } else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
312
469
  result[key] = flatValues[path] ?? configValue;
313
- } else if (isSpringConfig(configValue)) {
470
+ } else if (isSpringConfig(configValue) || isEasingConfig(configValue)) {
314
471
  result[key] = flatValues[path] ?? configValue;
315
472
  } else if (isActionConfig(configValue)) {
316
473
  result[key] = flatValues[path] ?? configValue;
@@ -333,6 +490,9 @@ function hasType(value, type) {
333
490
  function isSpringConfig(value) {
334
491
  return hasType(value, "spring");
335
492
  }
493
+ function isEasingConfig(value) {
494
+ return hasType(value, "easing");
495
+ }
336
496
  function isActionConfig(value) {
337
497
  return hasType(value, "action");
338
498
  }
@@ -351,18 +511,18 @@ function getFirstOptionValue(options) {
351
511
  }
352
512
 
353
513
  // src/components/DialRoot.tsx
354
- import { useEffect as useEffect7, useState as useState8 } from "react";
514
+ import { useEffect as useEffect7, useState as useState9 } from "react";
355
515
  import { createPortal as createPortal3 } from "react-dom";
356
516
 
357
517
  // src/components/Panel.tsx
358
- import { useState as useState7, useSyncExternalStore as useSyncExternalStore3 } from "react";
518
+ import { useState as useState8, useSyncExternalStore as useSyncExternalStore4 } from "react";
359
519
  import { motion as motion6, AnimatePresence as AnimatePresence4 } from "motion/react";
360
520
 
361
521
  // src/components/Folder.tsx
362
522
  import { useState, useRef as useRef2, useEffect as useEffect2 } from "react";
363
523
  import { motion, AnimatePresence } from "motion/react";
364
524
  import { jsx, jsxs } from "react/jsx-runtime";
365
- function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenChange, toolbar }) {
525
+ function Folder({ title, children, defaultOpen = true, isRoot = false, inline = false, onOpenChange, toolbar }) {
366
526
  const [isOpen, setIsOpen] = useState(defaultOpen);
367
527
  const [isCollapsed, setIsCollapsed] = useState(!defaultOpen);
368
528
  const contentRef = useRef2(null);
@@ -380,6 +540,7 @@ function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenCha
380
540
  return () => ro.disconnect();
381
541
  }, [isOpen]);
382
542
  const handleToggle = () => {
543
+ if (inline && isRoot) return;
383
544
  const next = !isOpen;
384
545
  setIsOpen(next);
385
546
  if (next) {
@@ -393,40 +554,35 @@ function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenCha
393
554
  /* @__PURE__ */ jsxs("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
394
555
  /* @__PURE__ */ jsxs("div", { className: "dialkit-folder-header-top", children: [
395
556
  isRoot ? isOpen && /* @__PURE__ */ jsx("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ jsx("span", { className: "dialkit-folder-title dialkit-folder-title-root", children: title }) }) : /* @__PURE__ */ jsx("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ jsx("span", { className: "dialkit-folder-title", children: title }) }),
396
- isRoot ? (
397
- // Root panel icon — fixed position, container morphs around it
398
- /* @__PURE__ */ jsxs(
399
- "svg",
400
- {
401
- className: "dialkit-panel-icon",
402
- viewBox: "0 0 16 16",
403
- fill: "none",
404
- children: [
405
- /* @__PURE__ */ jsx("path", { opacity: "0.5", d: "M6.84766 11.75C6.78583 11.9899 6.75 12.2408 6.75 12.5C6.75 12.7592 6.78583 13.0101 6.84766 13.25H2C1.58579 13.25 1.25 12.9142 1.25 12.5C1.25 12.0858 1.58579 11.75 2 11.75H6.84766ZM14 11.75C14.4142 11.75 14.75 12.0858 14.75 12.5C14.75 12.9142 14.4142 13.25 14 13.25H12.6523C12.7142 13.0101 12.75 12.7592 12.75 12.5C12.75 12.2408 12.7142 11.9899 12.6523 11.75H14ZM3.09766 7.25C3.03583 7.48994 3 7.74075 3 8C3 8.25925 3.03583 8.51006 3.09766 8.75H2C1.58579 8.75 1.25 8.41421 1.25 8C1.25 7.58579 1.58579 7.25 2 7.25H3.09766ZM14 7.25C14.4142 7.25 14.75 7.58579 14.75 8C14.75 8.41421 14.4142 8.75 14 8.75H8.90234C8.96417 8.51006 9 8.25925 9 8C9 7.74075 8.96417 7.48994 8.90234 7.25H14ZM7.59766 2.75C7.53583 2.98994 7.5 3.24075 7.5 3.5C7.5 3.75925 7.53583 4.01006 7.59766 4.25H2C1.58579 4.25 1.25 3.91421 1.25 3.5C1.25 3.08579 1.58579 2.75 2 2.75H7.59766ZM14 2.75C14.4142 2.75 14.75 3.08579 14.75 3.5C14.75 3.91421 14.4142 4.25 14 4.25H13.4023C13.4642 4.01006 13.5 3.75925 13.5 3.5C13.5 3.24075 13.4642 2.98994 13.4023 2.75H14Z", fill: "currentColor" }),
406
- /* @__PURE__ */ jsx("circle", { cx: "6", cy: "8", r: "0.998596", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
407
- /* @__PURE__ */ jsx("circle", { cx: "10.4999", cy: "3.5", r: "0.998657", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
408
- /* @__PURE__ */ jsx("circle", { cx: "9.75015", cy: "12.5", r: "0.997986", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" })
409
- ]
410
- }
411
- )
412
- ) : (
413
- // Section folders use rotating chevron with gentle spring
414
- /* @__PURE__ */ jsx(
415
- motion.svg,
416
- {
417
- className: "dialkit-folder-icon",
418
- viewBox: "0 0 24 24",
419
- fill: "none",
420
- stroke: "currentColor",
421
- strokeWidth: "2.5",
422
- strokeLinecap: "round",
423
- strokeLinejoin: "round",
424
- initial: false,
425
- animate: { rotate: isOpen ? 0 : 180 },
426
- transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
427
- children: /* @__PURE__ */ jsx("path", { d: "M6 9.5L12 15.5L18 9.5" })
428
- }
429
- )
557
+ isRoot && !inline && /* @__PURE__ */ jsxs(
558
+ "svg",
559
+ {
560
+ className: "dialkit-panel-icon",
561
+ viewBox: "0 0 16 16",
562
+ fill: "none",
563
+ children: [
564
+ /* @__PURE__ */ jsx("path", { opacity: "0.5", d: "M6.84766 11.75C6.78583 11.9899 6.75 12.2408 6.75 12.5C6.75 12.7592 6.78583 13.0101 6.84766 13.25H2C1.58579 13.25 1.25 12.9142 1.25 12.5C1.25 12.0858 1.58579 11.75 2 11.75H6.84766ZM14 11.75C14.4142 11.75 14.75 12.0858 14.75 12.5C14.75 12.9142 14.4142 13.25 14 13.25H12.6523C12.7142 13.0101 12.75 12.7592 12.75 12.5C12.75 12.2408 12.7142 11.9899 12.6523 11.75H14ZM3.09766 7.25C3.03583 7.48994 3 7.74075 3 8C3 8.25925 3.03583 8.51006 3.09766 8.75H2C1.58579 8.75 1.25 8.41421 1.25 8C1.25 7.58579 1.58579 7.25 2 7.25H3.09766ZM14 7.25C14.4142 7.25 14.75 7.58579 14.75 8C14.75 8.41421 14.4142 8.75 14 8.75H8.90234C8.96417 8.51006 9 8.25925 9 8C9 7.74075 8.96417 7.48994 8.90234 7.25H14ZM7.59766 2.75C7.53583 2.98994 7.5 3.24075 7.5 3.5C7.5 3.75925 7.53583 4.01006 7.59766 4.25H2C1.58579 4.25 1.25 3.91421 1.25 3.5C1.25 3.08579 1.58579 2.75 2 2.75H7.59766ZM14 2.75C14.4142 2.75 14.75 3.08579 14.75 3.5C14.75 3.91421 14.4142 4.25 14 4.25H13.4023C13.4642 4.01006 13.5 3.75925 13.5 3.5C13.5 3.24075 13.4642 2.98994 13.4023 2.75H14Z", fill: "currentColor" }),
565
+ /* @__PURE__ */ jsx("circle", { cx: "6", cy: "8", r: "0.998596", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
566
+ /* @__PURE__ */ jsx("circle", { cx: "10.4999", cy: "3.5", r: "0.998657", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
567
+ /* @__PURE__ */ jsx("circle", { cx: "9.75015", cy: "12.5", r: "0.997986", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" })
568
+ ]
569
+ }
570
+ ),
571
+ !isRoot && /* @__PURE__ */ jsx(
572
+ motion.svg,
573
+ {
574
+ className: "dialkit-folder-icon",
575
+ viewBox: "0 0 24 24",
576
+ fill: "none",
577
+ stroke: "currentColor",
578
+ strokeWidth: "2.5",
579
+ strokeLinecap: "round",
580
+ strokeLinejoin: "round",
581
+ initial: false,
582
+ animate: { rotate: isOpen ? 0 : 180 },
583
+ transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
584
+ children: /* @__PURE__ */ jsx("path", { d: "M6 9.5L12 15.5L18 9.5" })
585
+ }
430
586
  )
431
587
  ] }),
432
588
  isRoot && toolbar && isOpen && /* @__PURE__ */ jsx("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
@@ -445,6 +601,9 @@ function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenCha
445
601
  ) })
446
602
  ] });
447
603
  if (isRoot) {
604
+ if (inline) {
605
+ return /* @__PURE__ */ jsx("div", { className: "dialkit-panel-inner dialkit-panel-inline", children: folderContent });
606
+ }
448
607
  const panelStyle = isOpen ? { width: 280, height: contentHeight !== void 0 ? contentHeight + 24 : "auto", borderRadius: 14, boxShadow: "0 8px 32px rgba(0, 0, 0, 0.5)", cursor: void 0 } : { width: 42, height: 42, borderRadius: 21, boxShadow: "0 4px 16px rgba(0, 0, 0, 0.25)", overflow: "hidden", cursor: "pointer" };
449
608
  return /* @__PURE__ */ jsx(
450
609
  motion.div,
@@ -1119,12 +1278,180 @@ function SpringControl({ panelId, path, label, spring, onChange }) {
1119
1278
  ] }) });
1120
1279
  }
1121
1280
 
1122
- // src/components/TextControl.tsx
1281
+ // src/components/EasingVisualization.tsx
1123
1282
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1283
+ function EasingVisualization({ easing }) {
1284
+ const ease = easing.ease;
1285
+ const s = 200;
1286
+ const pad = 10;
1287
+ const inner = s - pad * 2;
1288
+ const unit = inner / 2;
1289
+ const toSvg = (nx, ny) => ({
1290
+ x: pad + (nx + 0.5) * unit,
1291
+ y: pad + (1.5 - ny) * unit
1292
+ });
1293
+ const start = toSvg(0, 0);
1294
+ const end = toSvg(1, 1);
1295
+ const p1 = toSvg(ease[0], ease[1]);
1296
+ const p2 = toSvg(ease[2], ease[3]);
1297
+ const curvePath = `M ${start.x} ${start.y} C ${p1.x} ${p1.y}, ${p2.x} ${p2.y}, ${end.x} ${end.y}`;
1298
+ return /* @__PURE__ */ jsxs7(
1299
+ "svg",
1300
+ {
1301
+ viewBox: `0 0 ${s} ${s}`,
1302
+ preserveAspectRatio: "xMidYMid slice",
1303
+ className: "dialkit-spring-viz dialkit-easing-viz",
1304
+ children: [
1305
+ /* @__PURE__ */ jsx7(
1306
+ "line",
1307
+ {
1308
+ x1: start.x,
1309
+ y1: start.y,
1310
+ x2: end.x,
1311
+ y2: end.y,
1312
+ stroke: "rgba(255, 255, 255, 0.15)",
1313
+ strokeWidth: "1",
1314
+ strokeDasharray: "4,4"
1315
+ }
1316
+ ),
1317
+ /* @__PURE__ */ jsx7("path", { d: curvePath, fill: "none", stroke: "rgba(255, 255, 255, 0.6)", strokeWidth: "2", strokeLinecap: "round" })
1318
+ ]
1319
+ }
1320
+ );
1321
+ }
1322
+
1323
+ // src/components/TransitionControl.tsx
1324
+ import { useSyncExternalStore as useSyncExternalStore3, useState as useState4 } from "react";
1325
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1326
+ function TransitionControl({ panelId, path, label, value, onChange }) {
1327
+ const mode = useSyncExternalStore3(
1328
+ (cb) => DialStore.subscribe(panelId, cb),
1329
+ () => DialStore.getTransitionMode(panelId, path),
1330
+ () => DialStore.getTransitionMode(panelId, path)
1331
+ );
1332
+ const isEasing = mode === "easing";
1333
+ const isSimpleSpring = mode === "simple";
1334
+ const spring = value.type === "spring" ? value : { type: "spring", visualDuration: 0.3, bounce: 0.2 };
1335
+ const easing = value.type === "easing" ? value : { type: "easing", duration: 0.3, ease: [1, -0.4, 0.5, 1] };
1336
+ const handleModeChange = (newMode) => {
1337
+ DialStore.updateTransitionMode(panelId, path, newMode);
1338
+ if (newMode === "easing") {
1339
+ const duration = value.type === "spring" ? value.visualDuration ?? 0.3 : value.duration;
1340
+ onChange({ type: "easing", duration, ease: easing.ease });
1341
+ } else if (newMode === "simple") {
1342
+ onChange({
1343
+ type: "spring",
1344
+ visualDuration: spring.visualDuration ?? (value.type === "easing" ? value.duration : 0.3),
1345
+ bounce: spring.bounce ?? 0.2
1346
+ });
1347
+ } else {
1348
+ onChange({
1349
+ type: "spring",
1350
+ stiffness: spring.stiffness ?? 200,
1351
+ damping: spring.damping ?? 25,
1352
+ mass: spring.mass ?? 1
1353
+ });
1354
+ }
1355
+ };
1356
+ const handleSpringUpdate = (key, val) => {
1357
+ if (isSimpleSpring) {
1358
+ const { stiffness, damping, mass, ...rest } = spring;
1359
+ onChange({ ...rest, [key]: val });
1360
+ } else {
1361
+ const { visualDuration, bounce, ...rest } = spring;
1362
+ onChange({ ...rest, [key]: val });
1363
+ }
1364
+ };
1365
+ const updateEase = (index, val) => {
1366
+ const newEase = [...easing.ease];
1367
+ newEase[index] = val;
1368
+ onChange({ ...easing, ease: newEase });
1369
+ };
1370
+ return /* @__PURE__ */ jsx8(Folder, { title: label, defaultOpen: true, children: /* @__PURE__ */ jsxs8("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
1371
+ isEasing ? /* @__PURE__ */ jsx8(EasingVisualization, { easing }) : /* @__PURE__ */ jsx8(SpringVisualization, { spring, isSimpleMode: isSimpleSpring }),
1372
+ /* @__PURE__ */ jsxs8("div", { className: "dialkit-labeled-control", children: [
1373
+ /* @__PURE__ */ jsx8("span", { className: "dialkit-labeled-control-label", children: "Type" }),
1374
+ /* @__PURE__ */ jsx8(
1375
+ SegmentedControl,
1376
+ {
1377
+ options: [
1378
+ { value: "easing", label: "Easing" },
1379
+ { value: "simple", label: "Time" },
1380
+ { value: "advanced", label: "Physics" }
1381
+ ],
1382
+ value: mode,
1383
+ onChange: handleModeChange
1384
+ }
1385
+ )
1386
+ ] }),
1387
+ isEasing ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
1388
+ /* @__PURE__ */ jsx8(Slider, { label: "x1", value: easing.ease[0], onChange: (v) => updateEase(0, v), min: 0, max: 1, step: 0.01 }),
1389
+ /* @__PURE__ */ jsx8(Slider, { label: "y1", value: easing.ease[1], onChange: (v) => updateEase(1, v), min: -1, max: 2, step: 0.01 }),
1390
+ /* @__PURE__ */ jsx8(Slider, { label: "x2", value: easing.ease[2], onChange: (v) => updateEase(2, v), min: 0, max: 1, step: 0.01 }),
1391
+ /* @__PURE__ */ jsx8(Slider, { label: "y2", value: easing.ease[3], onChange: (v) => updateEase(3, v), min: -1, max: 2, step: 0.01 }),
1392
+ /* @__PURE__ */ jsx8(Slider, { label: "Duration", value: easing.duration, onChange: (v) => onChange({ ...easing, duration: v }), min: 0.1, max: 2, step: 0.05, unit: "s" }),
1393
+ /* @__PURE__ */ jsx8(EaseTextInput, { ease: easing.ease, onChange: (newEase) => onChange({ ...easing, ease: newEase }) })
1394
+ ] }) : isSimpleSpring ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
1395
+ /* @__PURE__ */ jsx8(Slider, { label: "Duration", value: spring.visualDuration ?? 0.3, onChange: (v) => handleSpringUpdate("visualDuration", v), min: 0.1, max: 1, step: 0.05, unit: "s" }),
1396
+ /* @__PURE__ */ jsx8(Slider, { label: "Bounce", value: spring.bounce ?? 0.2, onChange: (v) => handleSpringUpdate("bounce", v), min: 0, max: 1, step: 0.05 })
1397
+ ] }) : /* @__PURE__ */ jsxs8(Fragment2, { children: [
1398
+ /* @__PURE__ */ jsx8(Slider, { label: "Stiffness", value: spring.stiffness ?? 400, onChange: (v) => handleSpringUpdate("stiffness", v), min: 1, max: 1e3, step: 10 }),
1399
+ /* @__PURE__ */ jsx8(Slider, { label: "Damping", value: spring.damping ?? 17, onChange: (v) => handleSpringUpdate("damping", v), min: 1, max: 100, step: 1 }),
1400
+ /* @__PURE__ */ jsx8(Slider, { label: "Mass", value: spring.mass ?? 1, onChange: (v) => handleSpringUpdate("mass", v), min: 0.1, max: 10, step: 0.1 })
1401
+ ] })
1402
+ ] }) });
1403
+ }
1404
+ function formatEase(ease) {
1405
+ return ease.map((v) => parseFloat(v.toFixed(2))).join(", ");
1406
+ }
1407
+ function parseEase(str) {
1408
+ const parts = str.split(",").map((s) => parseFloat(s.trim()));
1409
+ if (parts.length === 4 && parts.every((n) => !isNaN(n))) {
1410
+ return parts;
1411
+ }
1412
+ return null;
1413
+ }
1414
+ function EaseTextInput({ ease, onChange }) {
1415
+ const [editing, setEditing] = useState4(false);
1416
+ const [draft, setDraft] = useState4("");
1417
+ const handleFocus = () => {
1418
+ setDraft(formatEase(ease));
1419
+ setEditing(true);
1420
+ };
1421
+ const handleBlur = () => {
1422
+ const parsed = parseEase(draft);
1423
+ if (parsed) onChange(parsed);
1424
+ setEditing(false);
1425
+ };
1426
+ const handleKeyDown = (e) => {
1427
+ if (e.key === "Enter") {
1428
+ e.target.blur();
1429
+ }
1430
+ };
1431
+ return /* @__PURE__ */ jsxs8("div", { className: "dialkit-labeled-control", children: [
1432
+ /* @__PURE__ */ jsx8("span", { className: "dialkit-labeled-control-label", children: "Ease" }),
1433
+ /* @__PURE__ */ jsx8(
1434
+ "input",
1435
+ {
1436
+ type: "text",
1437
+ className: "dialkit-text-input",
1438
+ value: editing ? draft : formatEase(ease),
1439
+ onChange: (e) => setDraft(e.target.value),
1440
+ onFocus: handleFocus,
1441
+ onBlur: handleBlur,
1442
+ onKeyDown: handleKeyDown,
1443
+ spellCheck: false
1444
+ }
1445
+ )
1446
+ ] });
1447
+ }
1448
+
1449
+ // src/components/TextControl.tsx
1450
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1124
1451
  function TextControl({ label, value, onChange, placeholder }) {
1125
- return /* @__PURE__ */ jsxs7("div", { className: "dialkit-text-control", children: [
1126
- /* @__PURE__ */ jsx7("label", { className: "dialkit-text-label", children: label }),
1127
- /* @__PURE__ */ jsx7(
1452
+ return /* @__PURE__ */ jsxs9("div", { className: "dialkit-text-control", children: [
1453
+ /* @__PURE__ */ jsx9("label", { className: "dialkit-text-label", children: label }),
1454
+ /* @__PURE__ */ jsx9(
1128
1455
  "input",
1129
1456
  {
1130
1457
  type: "text",
@@ -1138,10 +1465,10 @@ function TextControl({ label, value, onChange, placeholder }) {
1138
1465
  }
1139
1466
 
1140
1467
  // src/components/SelectControl.tsx
1141
- import { useState as useState4, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback2 } from "react";
1468
+ import { useState as useState5, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback2 } from "react";
1142
1469
  import { createPortal } from "react-dom";
1143
1470
  import { motion as motion4, AnimatePresence as AnimatePresence2 } from "motion/react";
1144
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1471
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1145
1472
  function toTitleCase(s) {
1146
1473
  return s.replace(/\b\w/g, (c) => c.toUpperCase());
1147
1474
  }
@@ -1151,11 +1478,11 @@ function normalizeOptions(options) {
1151
1478
  );
1152
1479
  }
1153
1480
  function SelectControl({ label, value, options, onChange }) {
1154
- const [isOpen, setIsOpen] = useState4(false);
1481
+ const [isOpen, setIsOpen] = useState5(false);
1155
1482
  const triggerRef = useRef5(null);
1156
1483
  const dropdownRef = useRef5(null);
1157
- const [portalTarget, setPortalTarget] = useState4(null);
1158
- const [pos, setPos] = useState4(null);
1484
+ const [portalTarget, setPortalTarget] = useState5(null);
1485
+ const [pos, setPos] = useState5(null);
1159
1486
  const normalized = normalizeOptions(options);
1160
1487
  const selectedOption = normalized.find((o) => o.value === value);
1161
1488
  const updatePos = useCallback2(() => {
@@ -1191,8 +1518,8 @@ function SelectControl({ label, value, options, onChange }) {
1191
1518
  document.addEventListener("mousedown", handleClick);
1192
1519
  return () => document.removeEventListener("mousedown", handleClick);
1193
1520
  }, [isOpen]);
1194
- return /* @__PURE__ */ jsxs8("div", { className: "dialkit-select-row", children: [
1195
- /* @__PURE__ */ jsxs8(
1521
+ return /* @__PURE__ */ jsxs10("div", { className: "dialkit-select-row", children: [
1522
+ /* @__PURE__ */ jsxs10(
1196
1523
  "button",
1197
1524
  {
1198
1525
  ref: triggerRef,
@@ -1200,10 +1527,10 @@ function SelectControl({ label, value, options, onChange }) {
1200
1527
  onClick: () => setIsOpen(!isOpen),
1201
1528
  "data-open": String(isOpen),
1202
1529
  children: [
1203
- /* @__PURE__ */ jsx8("span", { className: "dialkit-select-label", children: label }),
1204
- /* @__PURE__ */ jsxs8("div", { className: "dialkit-select-right", children: [
1205
- /* @__PURE__ */ jsx8("span", { className: "dialkit-select-value", children: selectedOption?.label ?? value }),
1206
- /* @__PURE__ */ jsx8(
1530
+ /* @__PURE__ */ jsx10("span", { className: "dialkit-select-label", children: label }),
1531
+ /* @__PURE__ */ jsxs10("div", { className: "dialkit-select-right", children: [
1532
+ /* @__PURE__ */ jsx10("span", { className: "dialkit-select-value", children: selectedOption?.label ?? value }),
1533
+ /* @__PURE__ */ jsx10(
1207
1534
  motion4.svg,
1208
1535
  {
1209
1536
  className: "dialkit-select-chevron",
@@ -1215,7 +1542,7 @@ function SelectControl({ label, value, options, onChange }) {
1215
1542
  strokeLinejoin: "round",
1216
1543
  animate: { rotate: isOpen ? 180 : 0 },
1217
1544
  transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
1218
- children: /* @__PURE__ */ jsx8("path", { d: "M6 9.5L12 15.5L18 9.5" })
1545
+ children: /* @__PURE__ */ jsx10("path", { d: "M6 9.5L12 15.5L18 9.5" })
1219
1546
  }
1220
1547
  )
1221
1548
  ] })
@@ -1223,7 +1550,7 @@ function SelectControl({ label, value, options, onChange }) {
1223
1550
  }
1224
1551
  ),
1225
1552
  portalTarget && createPortal(
1226
- /* @__PURE__ */ jsx8(AnimatePresence2, { children: isOpen && pos && /* @__PURE__ */ jsx8(
1553
+ /* @__PURE__ */ jsx10(AnimatePresence2, { children: isOpen && pos && /* @__PURE__ */ jsx10(
1227
1554
  motion4.div,
1228
1555
  {
1229
1556
  ref: dropdownRef,
@@ -1238,7 +1565,7 @@ function SelectControl({ label, value, options, onChange }) {
1238
1565
  width: pos.width,
1239
1566
  ...pos.above ? { bottom: window.innerHeight - pos.top, transformOrigin: "bottom" } : { top: pos.top, transformOrigin: "top" }
1240
1567
  },
1241
- children: normalized.map((option) => /* @__PURE__ */ jsx8(
1568
+ children: normalized.map((option) => /* @__PURE__ */ jsx10(
1242
1569
  "button",
1243
1570
  {
1244
1571
  className: "dialkit-select-option",
@@ -1259,12 +1586,12 @@ function SelectControl({ label, value, options, onChange }) {
1259
1586
  }
1260
1587
 
1261
1588
  // src/components/ColorControl.tsx
1262
- import { useState as useState5, useRef as useRef6, useEffect as useEffect5 } from "react";
1263
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1589
+ import { useState as useState6, useRef as useRef6, useEffect as useEffect5 } from "react";
1590
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1264
1591
  var HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
1265
1592
  function ColorControl({ label, value, onChange }) {
1266
- const [isEditing, setIsEditing] = useState5(false);
1267
- const [editValue, setEditValue] = useState5(value);
1593
+ const [isEditing, setIsEditing] = useState6(false);
1594
+ const [editValue, setEditValue] = useState6(value);
1268
1595
  const colorInputRef = useRef6(null);
1269
1596
  useEffect5(() => {
1270
1597
  if (!isEditing) {
@@ -1287,10 +1614,10 @@ function ColorControl({ label, value, onChange }) {
1287
1614
  setEditValue(value);
1288
1615
  }
1289
1616
  }
1290
- return /* @__PURE__ */ jsxs9("div", { className: "dialkit-color-control", children: [
1291
- /* @__PURE__ */ jsx9("span", { className: "dialkit-color-label", children: label }),
1292
- /* @__PURE__ */ jsxs9("div", { className: "dialkit-color-inputs", children: [
1293
- isEditing ? /* @__PURE__ */ jsx9(
1617
+ return /* @__PURE__ */ jsxs11("div", { className: "dialkit-color-control", children: [
1618
+ /* @__PURE__ */ jsx11("span", { className: "dialkit-color-label", children: label }),
1619
+ /* @__PURE__ */ jsxs11("div", { className: "dialkit-color-inputs", children: [
1620
+ isEditing ? /* @__PURE__ */ jsx11(
1294
1621
  "input",
1295
1622
  {
1296
1623
  type: "text",
@@ -1301,7 +1628,7 @@ function ColorControl({ label, value, onChange }) {
1301
1628
  onKeyDown: handleKeyDown,
1302
1629
  autoFocus: true
1303
1630
  }
1304
- ) : /* @__PURE__ */ jsx9(
1631
+ ) : /* @__PURE__ */ jsx11(
1305
1632
  "span",
1306
1633
  {
1307
1634
  className: "dialkit-color-hex",
@@ -1309,7 +1636,7 @@ function ColorControl({ label, value, onChange }) {
1309
1636
  children: (value ?? "").toUpperCase()
1310
1637
  }
1311
1638
  ),
1312
- /* @__PURE__ */ jsx9(
1639
+ /* @__PURE__ */ jsx11(
1313
1640
  "button",
1314
1641
  {
1315
1642
  className: "dialkit-color-swatch",
@@ -1318,7 +1645,7 @@ function ColorControl({ label, value, onChange }) {
1318
1645
  title: "Pick color"
1319
1646
  }
1320
1647
  ),
1321
- /* @__PURE__ */ jsx9(
1648
+ /* @__PURE__ */ jsx11(
1322
1649
  "input",
1323
1650
  {
1324
1651
  ref: colorInputRef,
@@ -1337,15 +1664,15 @@ function expandShorthandHex(hex) {
1337
1664
  }
1338
1665
 
1339
1666
  // src/components/PresetManager.tsx
1340
- import { useState as useState6, useRef as useRef7, useEffect as useEffect6, useCallback as useCallback3 } from "react";
1667
+ import { useState as useState7, useRef as useRef7, useEffect as useEffect6, useCallback as useCallback3 } from "react";
1341
1668
  import { createPortal as createPortal2 } from "react-dom";
1342
1669
  import { motion as motion5, AnimatePresence as AnimatePresence3 } from "motion/react";
1343
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1670
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1344
1671
  function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1345
- const [isOpen, setIsOpen] = useState6(false);
1672
+ const [isOpen, setIsOpen] = useState7(false);
1346
1673
  const triggerRef = useRef7(null);
1347
1674
  const dropdownRef = useRef7(null);
1348
- const [pos, setPos] = useState6({ top: 0, left: 0, width: 0 });
1675
+ const [pos, setPos] = useState7({ top: 0, left: 0, width: 0 });
1349
1676
  const hasPresets = presets.length > 0;
1350
1677
  const activePreset = presets.find((p) => p.id === activePresetId);
1351
1678
  const open = useCallback3(() => {
@@ -1383,8 +1710,8 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1383
1710
  e.stopPropagation();
1384
1711
  DialStore.deletePreset(panelId, presetId);
1385
1712
  };
1386
- return /* @__PURE__ */ jsxs10("div", { className: "dialkit-preset-manager", children: [
1387
- /* @__PURE__ */ jsxs10(
1713
+ return /* @__PURE__ */ jsxs12("div", { className: "dialkit-preset-manager", children: [
1714
+ /* @__PURE__ */ jsxs12(
1388
1715
  "button",
1389
1716
  {
1390
1717
  ref: triggerRef,
@@ -1394,8 +1721,8 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1394
1721
  "data-has-preset": String(!!activePreset),
1395
1722
  "data-disabled": String(!hasPresets),
1396
1723
  children: [
1397
- /* @__PURE__ */ jsx10("span", { className: "dialkit-preset-label", children: activePreset ? activePreset.name : "Version 1" }),
1398
- /* @__PURE__ */ jsx10(
1724
+ /* @__PURE__ */ jsx12("span", { className: "dialkit-preset-label", children: activePreset ? activePreset.name : "Version 1" }),
1725
+ /* @__PURE__ */ jsx12(
1399
1726
  motion5.svg,
1400
1727
  {
1401
1728
  className: "dialkit-select-chevron",
@@ -1407,14 +1734,14 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1407
1734
  strokeLinejoin: "round",
1408
1735
  animate: { rotate: isOpen ? 180 : 0, opacity: hasPresets ? 0.6 : 0.25 },
1409
1736
  transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
1410
- children: /* @__PURE__ */ jsx10("path", { d: "M6 9.5L12 15.5L18 9.5" })
1737
+ children: /* @__PURE__ */ jsx12("path", { d: "M6 9.5L12 15.5L18 9.5" })
1411
1738
  }
1412
1739
  )
1413
1740
  ]
1414
1741
  }
1415
1742
  ),
1416
1743
  createPortal2(
1417
- /* @__PURE__ */ jsx10(AnimatePresence3, { children: isOpen && /* @__PURE__ */ jsxs10(
1744
+ /* @__PURE__ */ jsx12(AnimatePresence3, { children: isOpen && /* @__PURE__ */ jsxs12(
1418
1745
  motion5.div,
1419
1746
  {
1420
1747
  ref: dropdownRef,
@@ -1425,35 +1752,35 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1425
1752
  exit: { opacity: 0, y: 4, scale: 0.97, pointerEvents: "none" },
1426
1753
  transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
1427
1754
  children: [
1428
- /* @__PURE__ */ jsx10(
1755
+ /* @__PURE__ */ jsx12(
1429
1756
  "div",
1430
1757
  {
1431
1758
  className: "dialkit-preset-item",
1432
1759
  "data-active": String(!activePresetId),
1433
1760
  onClick: () => handleSelect(null),
1434
- children: /* @__PURE__ */ jsx10("span", { className: "dialkit-preset-name", children: "Version 1" })
1761
+ children: /* @__PURE__ */ jsx12("span", { className: "dialkit-preset-name", children: "Version 1" })
1435
1762
  }
1436
1763
  ),
1437
- presets.map((preset) => /* @__PURE__ */ jsxs10(
1764
+ presets.map((preset) => /* @__PURE__ */ jsxs12(
1438
1765
  "div",
1439
1766
  {
1440
1767
  className: "dialkit-preset-item",
1441
1768
  "data-active": String(preset.id === activePresetId),
1442
1769
  onClick: () => handleSelect(preset.id),
1443
1770
  children: [
1444
- /* @__PURE__ */ jsx10("span", { className: "dialkit-preset-name", children: preset.name }),
1445
- /* @__PURE__ */ jsx10(
1771
+ /* @__PURE__ */ jsx12("span", { className: "dialkit-preset-name", children: preset.name }),
1772
+ /* @__PURE__ */ jsx12(
1446
1773
  "button",
1447
1774
  {
1448
1775
  className: "dialkit-preset-delete",
1449
1776
  onClick: (e) => handleDelete(e, preset.id),
1450
1777
  title: "Delete preset",
1451
- children: /* @__PURE__ */ jsxs10("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1452
- /* @__PURE__ */ jsx10("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" }),
1453
- /* @__PURE__ */ jsx10("path", { d: "M10 11V16" }),
1454
- /* @__PURE__ */ jsx10("path", { d: "M14 11V16" }),
1455
- /* @__PURE__ */ jsx10("path", { d: "M3.5 6H20.5" }),
1456
- /* @__PURE__ */ jsx10("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" })
1778
+ children: /* @__PURE__ */ jsxs12("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1779
+ /* @__PURE__ */ jsx12("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" }),
1780
+ /* @__PURE__ */ jsx12("path", { d: "M10 11V16" }),
1781
+ /* @__PURE__ */ jsx12("path", { d: "M14 11V16" }),
1782
+ /* @__PURE__ */ jsx12("path", { d: "M3.5 6H20.5" }),
1783
+ /* @__PURE__ */ jsx12("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" })
1457
1784
  ] })
1458
1785
  }
1459
1786
  )
@@ -1470,11 +1797,11 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
1470
1797
  }
1471
1798
 
1472
1799
  // src/components/Panel.tsx
1473
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1474
- function Panel({ panel }) {
1475
- const [copied, setCopied] = useState7(false);
1476
- const [isPanelOpen, setIsPanelOpen] = useState7(true);
1477
- const values = useSyncExternalStore3(
1800
+ import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1801
+ function Panel({ panel, defaultOpen = true, inline = false }) {
1802
+ const [copied, setCopied] = useState8(false);
1803
+ const [isPanelOpen, setIsPanelOpen] = useState8(defaultOpen);
1804
+ const values = useSyncExternalStore4(
1478
1805
  (cb) => DialStore.subscribe(panel.id, cb),
1479
1806
  () => DialStore.getValues(panel.id),
1480
1807
  () => DialStore.getValues(panel.id)
@@ -1502,7 +1829,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1502
1829
  const value = values[control.path];
1503
1830
  switch (control.type) {
1504
1831
  case "slider":
1505
- return /* @__PURE__ */ jsx11(
1832
+ return /* @__PURE__ */ jsx13(
1506
1833
  Slider,
1507
1834
  {
1508
1835
  label: control.label,
@@ -1515,7 +1842,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1515
1842
  control.path
1516
1843
  );
1517
1844
  case "toggle":
1518
- return /* @__PURE__ */ jsx11(
1845
+ return /* @__PURE__ */ jsx13(
1519
1846
  Toggle,
1520
1847
  {
1521
1848
  label: control.label,
@@ -1525,7 +1852,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1525
1852
  control.path
1526
1853
  );
1527
1854
  case "spring":
1528
- return /* @__PURE__ */ jsx11(
1855
+ return /* @__PURE__ */ jsx13(
1529
1856
  SpringControl,
1530
1857
  {
1531
1858
  panelId: panel.id,
@@ -1536,10 +1863,22 @@ Apply these values as the new defaults in the useDialKit call.`;
1536
1863
  },
1537
1864
  control.path
1538
1865
  );
1866
+ case "transition":
1867
+ return /* @__PURE__ */ jsx13(
1868
+ TransitionControl,
1869
+ {
1870
+ panelId: panel.id,
1871
+ path: control.path,
1872
+ label: control.label,
1873
+ value,
1874
+ onChange: (v) => DialStore.updateValue(panel.id, control.path, v)
1875
+ },
1876
+ control.path
1877
+ );
1539
1878
  case "folder":
1540
- return /* @__PURE__ */ jsx11(Folder, { title: control.label, defaultOpen: control.defaultOpen ?? true, children: control.children?.map(renderControl) }, control.path);
1879
+ return /* @__PURE__ */ jsx13(Folder, { title: control.label, defaultOpen: control.defaultOpen ?? true, children: control.children?.map(renderControl) }, control.path);
1541
1880
  case "text":
1542
- return /* @__PURE__ */ jsx11(
1881
+ return /* @__PURE__ */ jsx13(
1543
1882
  TextControl,
1544
1883
  {
1545
1884
  label: control.label,
@@ -1550,7 +1889,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1550
1889
  control.path
1551
1890
  );
1552
1891
  case "select":
1553
- return /* @__PURE__ */ jsx11(
1892
+ return /* @__PURE__ */ jsx13(
1554
1893
  SelectControl,
1555
1894
  {
1556
1895
  label: control.label,
@@ -1561,7 +1900,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1561
1900
  control.path
1562
1901
  );
1563
1902
  case "color":
1564
- return /* @__PURE__ */ jsx11(
1903
+ return /* @__PURE__ */ jsx13(
1565
1904
  ColorControl,
1566
1905
  {
1567
1906
  label: control.label,
@@ -1570,37 +1909,26 @@ Apply these values as the new defaults in the useDialKit call.`;
1570
1909
  },
1571
1910
  control.path
1572
1911
  );
1912
+ case "action":
1913
+ return /* @__PURE__ */ jsx13(
1914
+ "button",
1915
+ {
1916
+ className: "dialkit-button",
1917
+ onClick: () => DialStore.triggerAction(panel.id, control.path),
1918
+ children: control.label
1919
+ },
1920
+ control.path
1921
+ );
1573
1922
  default:
1574
1923
  return null;
1575
1924
  }
1576
1925
  };
1577
1926
  const renderControls = () => {
1578
- const result = [];
1579
- let i = 0;
1580
- while (i < panel.controls.length) {
1581
- const control = panel.controls[i];
1582
- if (control.type === "action") {
1583
- result.push(
1584
- /* @__PURE__ */ jsx11(
1585
- "button",
1586
- {
1587
- className: "dialkit-button",
1588
- onClick: () => DialStore.triggerAction(panel.id, control.path),
1589
- children: control.label
1590
- },
1591
- control.path
1592
- )
1593
- );
1594
- } else {
1595
- result.push(renderControl(control));
1596
- }
1597
- i++;
1598
- }
1599
- return result;
1927
+ return panel.controls.map(renderControl);
1600
1928
  };
1601
1929
  const iconTransition = { type: "spring", visualDuration: 0.4, bounce: 0.1 };
1602
- const toolbar = /* @__PURE__ */ jsxs11(Fragment2, { children: [
1603
- /* @__PURE__ */ jsx11(
1930
+ const toolbar = /* @__PURE__ */ jsxs13(Fragment3, { children: [
1931
+ /* @__PURE__ */ jsx13(
1604
1932
  motion6.button,
1605
1933
  {
1606
1934
  className: "dialkit-toolbar-add",
@@ -1608,16 +1936,16 @@ Apply these values as the new defaults in the useDialKit call.`;
1608
1936
  title: "Add preset",
1609
1937
  whileTap: { scale: 0.9 },
1610
1938
  transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
1611
- children: /* @__PURE__ */ jsxs11("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
1612
- /* @__PURE__ */ jsx11("path", { d: "M4 6H20" }),
1613
- /* @__PURE__ */ jsx11("path", { d: "M4 12H10" }),
1614
- /* @__PURE__ */ jsx11("path", { d: "M15 15L21 15" }),
1615
- /* @__PURE__ */ jsx11("path", { d: "M18 12V18" }),
1616
- /* @__PURE__ */ jsx11("path", { d: "M4 18H10" })
1939
+ children: /* @__PURE__ */ jsxs13("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
1940
+ /* @__PURE__ */ jsx13("path", { d: "M4 6H20" }),
1941
+ /* @__PURE__ */ jsx13("path", { d: "M4 12H10" }),
1942
+ /* @__PURE__ */ jsx13("path", { d: "M15 15L21 15" }),
1943
+ /* @__PURE__ */ jsx13("path", { d: "M18 12V18" }),
1944
+ /* @__PURE__ */ jsx13("path", { d: "M4 18H10" })
1617
1945
  ] })
1618
1946
  }
1619
1947
  ),
1620
- /* @__PURE__ */ jsx11(
1948
+ /* @__PURE__ */ jsx13(
1621
1949
  PresetManager,
1622
1950
  {
1623
1951
  panelId: panel.id,
@@ -1626,7 +1954,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1626
1954
  onAdd: handleAddPreset
1627
1955
  }
1628
1956
  ),
1629
- /* @__PURE__ */ jsxs11(
1957
+ /* @__PURE__ */ jsxs13(
1630
1958
  motion6.button,
1631
1959
  {
1632
1960
  className: "dialkit-toolbar-copy",
@@ -1635,7 +1963,7 @@ Apply these values as the new defaults in the useDialKit call.`;
1635
1963
  whileTap: { scale: 0.95 },
1636
1964
  transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
1637
1965
  children: [
1638
- /* @__PURE__ */ jsx11("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ jsx11(AnimatePresence4, { initial: false, mode: "popLayout", children: copied ? /* @__PURE__ */ jsx11(
1966
+ /* @__PURE__ */ jsx13("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ jsx13(AnimatePresence4, { initial: false, mode: "popLayout", children: copied ? /* @__PURE__ */ jsx13(
1639
1967
  motion6.svg,
1640
1968
  {
1641
1969
  className: "dialkit-toolbar-copy-icon",
@@ -1649,10 +1977,10 @@ Apply these values as the new defaults in the useDialKit call.`;
1649
1977
  animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
1650
1978
  exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
1651
1979
  transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
1652
- children: /* @__PURE__ */ jsx11("path", { d: "M5 12.75L10 19L19 5" })
1980
+ children: /* @__PURE__ */ jsx13("path", { d: "M5 12.75L10 19L19 5" })
1653
1981
  },
1654
1982
  "check"
1655
- ) : /* @__PURE__ */ jsxs11(
1983
+ ) : /* @__PURE__ */ jsxs13(
1656
1984
  motion6.svg,
1657
1985
  {
1658
1986
  className: "dialkit-toolbar-copy-icon",
@@ -1663,9 +1991,9 @@ Apply these values as the new defaults in the useDialKit call.`;
1663
1991
  exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
1664
1992
  transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
1665
1993
  children: [
1666
- /* @__PURE__ */ jsx11("path", { d: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }),
1667
- /* @__PURE__ */ jsx11("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" }),
1668
- /* @__PURE__ */ jsx11("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" })
1994
+ /* @__PURE__ */ jsx13("path", { d: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }),
1995
+ /* @__PURE__ */ jsx13("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" }),
1996
+ /* @__PURE__ */ jsx13("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" })
1669
1997
  ]
1670
1998
  },
1671
1999
  "clipboard"
@@ -1675,14 +2003,15 @@ Apply these values as the new defaults in the useDialKit call.`;
1675
2003
  }
1676
2004
  )
1677
2005
  ] });
1678
- return /* @__PURE__ */ jsx11("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ jsx11(Folder, { title: panel.name, defaultOpen: true, isRoot: true, onOpenChange: setIsPanelOpen, toolbar, children: renderControls() }) });
2006
+ return /* @__PURE__ */ jsx13("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ jsx13(Folder, { title: panel.name, defaultOpen, isRoot: true, inline, onOpenChange: setIsPanelOpen, toolbar, children: renderControls() }) });
1679
2007
  }
1680
2008
 
1681
2009
  // src/components/DialRoot.tsx
1682
- import { jsx as jsx12 } from "react/jsx-runtime";
1683
- function DialRoot({ position = "top-right" }) {
1684
- const [panels, setPanels] = useState8([]);
1685
- const [mounted, setMounted] = useState8(false);
2010
+ import { jsx as jsx14 } from "react/jsx-runtime";
2011
+ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover" }) {
2012
+ const [panels, setPanels] = useState9([]);
2013
+ const [mounted, setMounted] = useState9(false);
2014
+ const inline = mode === "inline";
1686
2015
  useEffect7(() => {
1687
2016
  setMounted(true);
1688
2017
  setPanels(DialStore.getPanels());
@@ -1697,14 +2026,17 @@ function DialRoot({ position = "top-right" }) {
1697
2026
  if (panels.length === 0) {
1698
2027
  return null;
1699
2028
  }
1700
- const content = /* @__PURE__ */ jsx12("div", { className: "dialkit-root", children: /* @__PURE__ */ jsx12("div", { className: "dialkit-panel", "data-position": position, children: panels.map((panel) => /* @__PURE__ */ jsx12(Panel, { panel }, panel.id)) }) });
2029
+ const content = /* @__PURE__ */ jsx14("div", { className: "dialkit-root", "data-mode": mode, children: /* @__PURE__ */ jsx14("div", { className: "dialkit-panel", "data-position": inline ? void 0 : position, "data-mode": mode, children: panels.map((panel) => /* @__PURE__ */ jsx14(Panel, { panel, defaultOpen: inline || defaultOpen, inline }, panel.id)) }) });
2030
+ if (inline) {
2031
+ return content;
2032
+ }
1701
2033
  return createPortal3(content, document.body);
1702
2034
  }
1703
2035
 
1704
2036
  // src/components/ButtonGroup.tsx
1705
- import { jsx as jsx13 } from "react/jsx-runtime";
2037
+ import { jsx as jsx15 } from "react/jsx-runtime";
1706
2038
  function ButtonGroup({ buttons }) {
1707
- return /* @__PURE__ */ jsx13("div", { className: "dialkit-button-group", children: buttons.map((button, index) => /* @__PURE__ */ jsx13(
2039
+ return /* @__PURE__ */ jsx15("div", { className: "dialkit-button-group", children: buttons.map((button, index) => /* @__PURE__ */ jsx15(
1708
2040
  "button",
1709
2041
  {
1710
2042
  className: "dialkit-button",
@@ -1719,6 +2051,7 @@ export {
1719
2051
  ColorControl,
1720
2052
  DialRoot,
1721
2053
  DialStore,
2054
+ EasingVisualization,
1722
2055
  Folder,
1723
2056
  PresetManager,
1724
2057
  SelectControl,
@@ -1727,6 +2060,7 @@ export {
1727
2060
  SpringVisualization,
1728
2061
  TextControl,
1729
2062
  Toggle,
2063
+ TransitionControl,
1730
2064
  useDialKit
1731
2065
  };
1732
2066
  //# sourceMappingURL=index.js.map