dialkit 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -74
- package/dist/index.cjs +884 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -17
- package/dist/index.d.ts +82 -17
- package/dist/index.js +891 -275
- package/dist/index.js.map +1 -1
- package/dist/styles.css +619 -44
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,12 +12,16 @@ var DialStoreClass = class {
|
|
|
12
12
|
this.globalListeners = /* @__PURE__ */ new Set();
|
|
13
13
|
this.snapshots = /* @__PURE__ */ new Map();
|
|
14
14
|
this.actionListeners = /* @__PURE__ */ new Map();
|
|
15
|
+
this.presets = /* @__PURE__ */ new Map();
|
|
16
|
+
this.activePreset = /* @__PURE__ */ new Map();
|
|
17
|
+
this.baseValues = /* @__PURE__ */ new Map();
|
|
15
18
|
}
|
|
16
19
|
registerPanel(id, name, config) {
|
|
17
20
|
const controls = this.parseConfig(config, "");
|
|
18
21
|
const values = this.flattenValues(config, "");
|
|
19
22
|
this.panels.set(id, { id, name, controls, values });
|
|
20
23
|
this.snapshots.set(id, { ...values });
|
|
24
|
+
this.baseValues.set(id, { ...values });
|
|
21
25
|
this.notifyGlobal();
|
|
22
26
|
}
|
|
23
27
|
unregisterPanel(id) {
|
|
@@ -30,6 +34,15 @@ var DialStoreClass = class {
|
|
|
30
34
|
const panel = this.panels.get(panelId);
|
|
31
35
|
if (!panel) return;
|
|
32
36
|
panel.values[path] = value;
|
|
37
|
+
const activeId = this.activePreset.get(panelId);
|
|
38
|
+
if (activeId) {
|
|
39
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
40
|
+
const preset = presets.find((p) => p.id === activeId);
|
|
41
|
+
if (preset) preset.values[path] = value;
|
|
42
|
+
} else {
|
|
43
|
+
const base = this.baseValues.get(panelId);
|
|
44
|
+
if (base) base[path] = value;
|
|
45
|
+
}
|
|
33
46
|
this.snapshots.set(panelId, { ...panel.values });
|
|
34
47
|
this.notify(panelId);
|
|
35
48
|
}
|
|
@@ -83,6 +96,61 @@ var DialStoreClass = class {
|
|
|
83
96
|
triggerAction(panelId, path) {
|
|
84
97
|
this.actionListeners.get(panelId)?.forEach((fn) => fn(path));
|
|
85
98
|
}
|
|
99
|
+
savePreset(panelId, name) {
|
|
100
|
+
const panel = this.panels.get(panelId);
|
|
101
|
+
if (!panel) throw new Error(`Panel ${panelId} not found`);
|
|
102
|
+
const id = `preset-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
103
|
+
const preset = {
|
|
104
|
+
id,
|
|
105
|
+
name,
|
|
106
|
+
values: { ...panel.values }
|
|
107
|
+
};
|
|
108
|
+
const existing = this.presets.get(panelId) ?? [];
|
|
109
|
+
this.presets.set(panelId, [...existing, preset]);
|
|
110
|
+
this.activePreset.set(panelId, id);
|
|
111
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
112
|
+
this.notify(panelId);
|
|
113
|
+
return id;
|
|
114
|
+
}
|
|
115
|
+
loadPreset(panelId, presetId) {
|
|
116
|
+
const panel = this.panels.get(panelId);
|
|
117
|
+
if (!panel) return;
|
|
118
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
119
|
+
const preset = presets.find((p) => p.id === presetId);
|
|
120
|
+
if (!preset) return;
|
|
121
|
+
panel.values = { ...preset.values };
|
|
122
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
123
|
+
this.activePreset.set(panelId, presetId);
|
|
124
|
+
this.notify(panelId);
|
|
125
|
+
}
|
|
126
|
+
deletePreset(panelId, presetId) {
|
|
127
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
128
|
+
this.presets.set(panelId, presets.filter((p) => p.id !== presetId));
|
|
129
|
+
if (this.activePreset.get(panelId) === presetId) {
|
|
130
|
+
this.activePreset.set(panelId, null);
|
|
131
|
+
}
|
|
132
|
+
const panel = this.panels.get(panelId);
|
|
133
|
+
if (panel) {
|
|
134
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
135
|
+
}
|
|
136
|
+
this.notify(panelId);
|
|
137
|
+
}
|
|
138
|
+
getPresets(panelId) {
|
|
139
|
+
return this.presets.get(panelId) ?? [];
|
|
140
|
+
}
|
|
141
|
+
getActivePresetId(panelId) {
|
|
142
|
+
return this.activePreset.get(panelId) ?? null;
|
|
143
|
+
}
|
|
144
|
+
clearActivePreset(panelId) {
|
|
145
|
+
const panel = this.panels.get(panelId);
|
|
146
|
+
const base = this.baseValues.get(panelId);
|
|
147
|
+
if (panel && base) {
|
|
148
|
+
panel.values = { ...base };
|
|
149
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
150
|
+
}
|
|
151
|
+
this.activePreset.set(panelId, null);
|
|
152
|
+
this.notify(panelId);
|
|
153
|
+
}
|
|
86
154
|
notify(panelId) {
|
|
87
155
|
this.listeners.get(panelId)?.forEach((fn) => fn());
|
|
88
156
|
}
|
|
@@ -112,6 +180,18 @@ var DialStoreClass = class {
|
|
|
112
180
|
controls.push({ type: "spring", path, label });
|
|
113
181
|
} else if (this.isActionConfig(value)) {
|
|
114
182
|
controls.push({ type: "action", path, label: value.label || label });
|
|
183
|
+
} else if (this.isSelectConfig(value)) {
|
|
184
|
+
controls.push({ type: "select", path, label, options: value.options });
|
|
185
|
+
} else if (this.isColorConfig(value)) {
|
|
186
|
+
controls.push({ type: "color", path, label });
|
|
187
|
+
} else if (this.isTextConfig(value)) {
|
|
188
|
+
controls.push({ type: "text", path, label, placeholder: value.placeholder });
|
|
189
|
+
} else if (typeof value === "string") {
|
|
190
|
+
if (this.isHexColor(value)) {
|
|
191
|
+
controls.push({ type: "color", path, label });
|
|
192
|
+
} else {
|
|
193
|
+
controls.push({ type: "text", path, label });
|
|
194
|
+
}
|
|
115
195
|
} else if (typeof value === "object" && value !== null) {
|
|
116
196
|
controls.push({
|
|
117
197
|
type: "folder",
|
|
@@ -135,6 +215,14 @@ var DialStoreClass = class {
|
|
|
135
215
|
values[path] = value;
|
|
136
216
|
} else if (this.isActionConfig(value)) {
|
|
137
217
|
values[path] = value;
|
|
218
|
+
} else if (this.isSelectConfig(value)) {
|
|
219
|
+
const firstOption = value.options[0];
|
|
220
|
+
const firstValue = typeof firstOption === "string" ? firstOption : firstOption.value;
|
|
221
|
+
values[path] = value.default ?? firstValue;
|
|
222
|
+
} else if (this.isColorConfig(value)) {
|
|
223
|
+
values[path] = value.default ?? "#000000";
|
|
224
|
+
} else if (this.isTextConfig(value)) {
|
|
225
|
+
values[path] = value.default ?? "";
|
|
138
226
|
} else if (typeof value === "object" && value !== null) {
|
|
139
227
|
Object.assign(values, this.flattenValues(value, path));
|
|
140
228
|
}
|
|
@@ -147,6 +235,18 @@ var DialStoreClass = class {
|
|
|
147
235
|
isActionConfig(value) {
|
|
148
236
|
return typeof value === "object" && value !== null && "type" in value && value.type === "action";
|
|
149
237
|
}
|
|
238
|
+
isSelectConfig(value) {
|
|
239
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "select" && "options" in value && Array.isArray(value.options);
|
|
240
|
+
}
|
|
241
|
+
isColorConfig(value) {
|
|
242
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "color";
|
|
243
|
+
}
|
|
244
|
+
isTextConfig(value) {
|
|
245
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "text";
|
|
246
|
+
}
|
|
247
|
+
isHexColor(value) {
|
|
248
|
+
return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(value);
|
|
249
|
+
}
|
|
150
250
|
formatLabel(key) {
|
|
151
251
|
return key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
|
|
152
252
|
}
|
|
@@ -154,13 +254,13 @@ var DialStoreClass = class {
|
|
|
154
254
|
if (value >= 0 && value <= 1) {
|
|
155
255
|
return { min: 0, max: 1, step: 0.01 };
|
|
156
256
|
} else if (value >= 0 && value <= 10) {
|
|
157
|
-
return { min: 0, max: value *
|
|
257
|
+
return { min: 0, max: value * 3 || 10, step: 0.1 };
|
|
158
258
|
} else if (value >= 0 && value <= 100) {
|
|
159
|
-
return { min: 0, max: value *
|
|
259
|
+
return { min: 0, max: value * 3 || 100, step: 1 };
|
|
160
260
|
} else if (value >= 0) {
|
|
161
|
-
return { min: 0, max: value *
|
|
261
|
+
return { min: 0, max: value * 3 || 1e3, step: 10 };
|
|
162
262
|
} else {
|
|
163
|
-
return { min: value *
|
|
263
|
+
return { min: value * 3, max: -value * 3, step: 1 };
|
|
164
264
|
}
|
|
165
265
|
}
|
|
166
266
|
inferStep(min, max) {
|
|
@@ -206,204 +306,149 @@ function buildResolvedValues(config, flatValues, prefix) {
|
|
|
206
306
|
result[key] = flatValues[path] ?? configValue;
|
|
207
307
|
} else if (isSpringConfig(configValue)) {
|
|
208
308
|
result[key] = flatValues[path] ?? configValue;
|
|
309
|
+
} else if (isActionConfig(configValue)) {
|
|
310
|
+
result[key] = flatValues[path] ?? configValue;
|
|
311
|
+
} else if (isSelectConfig(configValue)) {
|
|
312
|
+
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
313
|
+
result[key] = flatValues[path] ?? defaultValue;
|
|
314
|
+
} else if (isColorConfig(configValue)) {
|
|
315
|
+
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
316
|
+
} else if (isTextConfig(configValue)) {
|
|
317
|
+
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
209
318
|
} else if (typeof configValue === "object" && configValue !== null) {
|
|
210
319
|
result[key] = buildResolvedValues(configValue, flatValues, path);
|
|
211
320
|
}
|
|
212
321
|
}
|
|
213
322
|
return result;
|
|
214
323
|
}
|
|
324
|
+
function hasType(value, type) {
|
|
325
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
326
|
+
}
|
|
215
327
|
function isSpringConfig(value) {
|
|
216
|
-
return
|
|
328
|
+
return hasType(value, "spring");
|
|
329
|
+
}
|
|
330
|
+
function isActionConfig(value) {
|
|
331
|
+
return hasType(value, "action");
|
|
332
|
+
}
|
|
333
|
+
function isSelectConfig(value) {
|
|
334
|
+
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
335
|
+
}
|
|
336
|
+
function isColorConfig(value) {
|
|
337
|
+
return hasType(value, "color");
|
|
338
|
+
}
|
|
339
|
+
function isTextConfig(value) {
|
|
340
|
+
return hasType(value, "text");
|
|
341
|
+
}
|
|
342
|
+
function getFirstOptionValue(options) {
|
|
343
|
+
const first = options[0];
|
|
344
|
+
return typeof first === "string" ? first : first.value;
|
|
217
345
|
}
|
|
218
346
|
|
|
219
347
|
// src/components/DialRoot.tsx
|
|
220
|
-
import { useEffect as
|
|
221
|
-
import { createPortal } from "react-dom";
|
|
348
|
+
import { useEffect as useEffect7, useState as useState8 } from "react";
|
|
349
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
350
|
+
|
|
351
|
+
// src/components/Panel.tsx
|
|
352
|
+
import { useState as useState7, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
353
|
+
import { motion as motion6, AnimatePresence as AnimatePresence4 } from "motion/react";
|
|
222
354
|
|
|
223
355
|
// src/components/Folder.tsx
|
|
224
|
-
import { useState } from "react";
|
|
356
|
+
import { useState, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
225
357
|
import { motion, AnimatePresence } from "motion/react";
|
|
226
358
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
227
|
-
function Folder({ title, children, defaultOpen = true, isRoot = false,
|
|
359
|
+
function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenChange, toolbar }) {
|
|
228
360
|
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
229
|
-
const [
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
361
|
+
const [isCollapsed, setIsCollapsed] = useState(!defaultOpen);
|
|
362
|
+
const contentRef = useRef2(null);
|
|
363
|
+
const [contentHeight, setContentHeight] = useState(void 0);
|
|
364
|
+
useEffect2(() => {
|
|
365
|
+
const el = contentRef.current;
|
|
366
|
+
if (!el) return;
|
|
367
|
+
const ro = new ResizeObserver(() => {
|
|
368
|
+
if (isOpen) {
|
|
369
|
+
const h = el.offsetHeight;
|
|
370
|
+
setContentHeight((prev) => prev === h ? prev : h);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
ro.observe(el);
|
|
374
|
+
return () => ro.disconnect();
|
|
375
|
+
}, [isOpen]);
|
|
376
|
+
const handleToggle = () => {
|
|
377
|
+
const next = !isOpen;
|
|
378
|
+
setIsOpen(next);
|
|
379
|
+
if (next) {
|
|
380
|
+
setIsCollapsed(false);
|
|
381
|
+
} else {
|
|
382
|
+
setIsCollapsed(true);
|
|
383
|
+
}
|
|
384
|
+
onOpenChange?.(next);
|
|
245
385
|
};
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
className: "dialkit-folder-copy",
|
|
255
|
-
onClick: handleCopy,
|
|
256
|
-
title: "Copy parameters",
|
|
257
|
-
initial: false,
|
|
258
|
-
animate: {
|
|
259
|
-
opacity: isOpen ? 1 : 0,
|
|
260
|
-
scale: isOpen ? 1 : 0.7,
|
|
261
|
-
filter: isOpen ? "blur(0px)" : "blur(6px)"
|
|
262
|
-
},
|
|
263
|
-
transition: iconTransition,
|
|
264
|
-
style: { pointerEvents: isOpen ? "auto" : "none" },
|
|
265
|
-
children: /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: 14, height: 14 }, children: [
|
|
266
|
-
/* @__PURE__ */ jsxs(
|
|
267
|
-
motion.svg,
|
|
268
|
-
{
|
|
269
|
-
viewBox: "0 0 24 24",
|
|
270
|
-
fill: "none",
|
|
271
|
-
stroke: "currentColor",
|
|
272
|
-
strokeWidth: "2",
|
|
273
|
-
strokeLinecap: "round",
|
|
274
|
-
strokeLinejoin: "round",
|
|
275
|
-
style: { position: "absolute", inset: 0 },
|
|
276
|
-
initial: false,
|
|
277
|
-
animate: {
|
|
278
|
-
opacity: copied ? 0 : 1,
|
|
279
|
-
scale: copied ? 0.7 : 1,
|
|
280
|
-
filter: copied ? "blur(6px)" : "blur(0px)"
|
|
281
|
-
},
|
|
282
|
-
transition: iconTransition,
|
|
283
|
-
children: [
|
|
284
|
-
/* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
285
|
-
/* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
286
|
-
]
|
|
287
|
-
}
|
|
288
|
-
),
|
|
289
|
-
/* @__PURE__ */ jsx(
|
|
290
|
-
motion.svg,
|
|
291
|
-
{
|
|
292
|
-
viewBox: "0 0 24 24",
|
|
293
|
-
fill: "none",
|
|
294
|
-
stroke: "currentColor",
|
|
295
|
-
strokeWidth: "2",
|
|
296
|
-
strokeLinecap: "round",
|
|
297
|
-
strokeLinejoin: "round",
|
|
298
|
-
style: { position: "absolute", inset: 0 },
|
|
299
|
-
initial: false,
|
|
300
|
-
animate: {
|
|
301
|
-
opacity: copied ? 1 : 0,
|
|
302
|
-
scale: copied ? 1 : 0.7,
|
|
303
|
-
filter: copied ? "blur(0px)" : "blur(6px)"
|
|
304
|
-
},
|
|
305
|
-
transition: iconTransition,
|
|
306
|
-
children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
|
|
307
|
-
}
|
|
308
|
-
)
|
|
309
|
-
] })
|
|
310
|
-
}
|
|
311
|
-
)
|
|
312
|
-
] }),
|
|
313
|
-
isRoot ? (
|
|
314
|
-
// Root panel uses minus/plus icons with crossfade
|
|
315
|
-
/* @__PURE__ */ jsxs("div", { className: "dialkit-folder-icon", style: { position: "relative" }, children: [
|
|
316
|
-
/* @__PURE__ */ jsx(
|
|
317
|
-
motion.svg,
|
|
386
|
+
const folderContent = /* @__PURE__ */ jsxs("div", { ref: isRoot ? contentRef : void 0, className: `dialkit-folder ${isRoot ? "dialkit-folder-root" : ""}`, children: [
|
|
387
|
+
/* @__PURE__ */ jsxs("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
|
|
388
|
+
/* @__PURE__ */ jsxs("div", { className: "dialkit-folder-header-top", children: [
|
|
389
|
+
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 }) }),
|
|
390
|
+
isRoot ? (
|
|
391
|
+
// Root panel icon — fixed position, container morphs around it
|
|
392
|
+
/* @__PURE__ */ jsxs(
|
|
393
|
+
"svg",
|
|
318
394
|
{
|
|
319
|
-
|
|
395
|
+
className: "dialkit-panel-icon",
|
|
396
|
+
viewBox: "0 0 16 16",
|
|
320
397
|
fill: "none",
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
animate: {
|
|
328
|
-
opacity: isOpen ? 1 : 0,
|
|
329
|
-
scale: isOpen ? 1 : 0.7,
|
|
330
|
-
filter: isOpen ? "blur(0px)" : "blur(6px)"
|
|
331
|
-
},
|
|
332
|
-
transition: iconTransition,
|
|
333
|
-
children: /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
398
|
+
children: [
|
|
399
|
+
/* @__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" }),
|
|
400
|
+
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "8", r: "0.998596", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
|
|
401
|
+
/* @__PURE__ */ jsx("circle", { cx: "10.4999", cy: "3.5", r: "0.998657", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
|
|
402
|
+
/* @__PURE__ */ jsx("circle", { cx: "9.75015", cy: "12.5", r: "0.997986", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" })
|
|
403
|
+
]
|
|
334
404
|
}
|
|
335
|
-
)
|
|
336
|
-
|
|
405
|
+
)
|
|
406
|
+
) : (
|
|
407
|
+
// Section folders use rotating chevron with gentle spring
|
|
408
|
+
/* @__PURE__ */ jsx(
|
|
337
409
|
motion.svg,
|
|
338
410
|
{
|
|
411
|
+
className: "dialkit-folder-icon",
|
|
339
412
|
viewBox: "0 0 24 24",
|
|
340
413
|
fill: "none",
|
|
341
414
|
stroke: "currentColor",
|
|
342
|
-
strokeWidth: "2",
|
|
415
|
+
strokeWidth: "2.5",
|
|
343
416
|
strokeLinecap: "round",
|
|
344
417
|
strokeLinejoin: "round",
|
|
345
|
-
style: { position: "absolute", inset: 0, width: "100%", height: "100%" },
|
|
346
418
|
initial: false,
|
|
347
|
-
animate: {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
filter: isOpen ? "blur(6px)" : "blur(0px)"
|
|
351
|
-
},
|
|
352
|
-
transition: iconTransition,
|
|
353
|
-
children: [
|
|
354
|
-
/* @__PURE__ */ jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
355
|
-
/* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
356
|
-
]
|
|
419
|
+
animate: { rotate: isOpen ? 0 : 180 },
|
|
420
|
+
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
421
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
357
422
|
}
|
|
358
423
|
)
|
|
359
|
-
] })
|
|
360
|
-
) : (
|
|
361
|
-
// Section folders use rotating chevron with gentle spring
|
|
362
|
-
/* @__PURE__ */ jsxs(
|
|
363
|
-
motion.svg,
|
|
364
|
-
{
|
|
365
|
-
className: "dialkit-folder-icon",
|
|
366
|
-
viewBox: "0 0 24 24",
|
|
367
|
-
fill: "none",
|
|
368
|
-
stroke: "currentColor",
|
|
369
|
-
strokeWidth: "1.5",
|
|
370
|
-
strokeLinecap: "round",
|
|
371
|
-
strokeLinejoin: "round",
|
|
372
|
-
initial: false,
|
|
373
|
-
animate: { rotate: isOpen ? 0 : 180 },
|
|
374
|
-
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
375
|
-
children: [
|
|
376
|
-
/* @__PURE__ */ jsx("line", { x1: "5", y1: "9", x2: "12", y2: "16" }),
|
|
377
|
-
/* @__PURE__ */ jsx("line", { x1: "19", y1: "9", x2: "12", y2: "16" })
|
|
378
|
-
]
|
|
379
|
-
}
|
|
380
424
|
)
|
|
381
|
-
)
|
|
425
|
+
] }),
|
|
426
|
+
isRoot && toolbar && isOpen && /* @__PURE__ */ jsx("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
382
427
|
] }),
|
|
383
428
|
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ jsx(
|
|
384
429
|
motion.div,
|
|
385
430
|
{
|
|
386
431
|
className: "dialkit-folder-content",
|
|
387
|
-
initial: { height: 0, opacity: 0 },
|
|
388
|
-
animate: { height: "auto", opacity: 1 },
|
|
389
|
-
exit: { height: 0, opacity: 0 },
|
|
390
|
-
transition: { type: "spring", visualDuration: 0.
|
|
432
|
+
initial: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
433
|
+
animate: isRoot ? void 0 : { height: "auto", opacity: 1 },
|
|
434
|
+
exit: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
435
|
+
transition: isRoot ? void 0 : { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
436
|
+
style: isRoot ? void 0 : { clipPath: "inset(0 -20px)" },
|
|
391
437
|
children: /* @__PURE__ */ jsx("div", { className: "dialkit-folder-inner", children })
|
|
392
438
|
}
|
|
393
439
|
) })
|
|
394
440
|
] });
|
|
395
441
|
if (isRoot) {
|
|
442
|
+
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" };
|
|
396
443
|
return /* @__PURE__ */ jsx(
|
|
397
444
|
motion.div,
|
|
398
445
|
{
|
|
399
446
|
className: "dialkit-panel-inner",
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
},
|
|
405
|
-
transition: { type: "spring", visualDuration: 0.4, bounce: 0.05 },
|
|
406
|
-
"data-collapsed": !isOpen,
|
|
447
|
+
style: panelStyle,
|
|
448
|
+
onClick: !isOpen ? handleToggle : void 0,
|
|
449
|
+
"data-collapsed": isCollapsed,
|
|
450
|
+
whileTap: !isOpen ? { scale: 0.9 } : void 0,
|
|
451
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
407
452
|
children: folderContent
|
|
408
453
|
}
|
|
409
454
|
);
|
|
@@ -412,9 +457,26 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
412
457
|
}
|
|
413
458
|
|
|
414
459
|
// src/components/Slider.tsx
|
|
415
|
-
import { useRef as
|
|
416
|
-
import { motion as motion2 } from "motion/react";
|
|
460
|
+
import { useRef as useRef3, useState as useState2, useCallback, useEffect as useEffect3 } from "react";
|
|
461
|
+
import { motion as motion2, useMotionValue, useTransform, animate } from "motion/react";
|
|
417
462
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
463
|
+
var CLICK_THRESHOLD = 3;
|
|
464
|
+
var DEAD_ZONE = 32;
|
|
465
|
+
var MAX_CURSOR_RANGE = 200;
|
|
466
|
+
var MAX_STRETCH = 8;
|
|
467
|
+
function roundValue(val, step) {
|
|
468
|
+
const decimals = step >= 1 ? 0 : 2;
|
|
469
|
+
const factor = 10 ** decimals;
|
|
470
|
+
return Math.round(val * factor) / factor;
|
|
471
|
+
}
|
|
472
|
+
function snapToDecile(rawValue, min, max) {
|
|
473
|
+
const normalized = (rawValue - min) / (max - min);
|
|
474
|
+
const nearest = Math.round(normalized * 10) / 10;
|
|
475
|
+
if (Math.abs(normalized - nearest) <= 0.03125) {
|
|
476
|
+
return min + nearest * (max - min);
|
|
477
|
+
}
|
|
478
|
+
return rawValue;
|
|
479
|
+
}
|
|
418
480
|
function Slider({
|
|
419
481
|
label,
|
|
420
482
|
value,
|
|
@@ -424,8 +486,11 @@ function Slider({
|
|
|
424
486
|
step = 0.01,
|
|
425
487
|
unit
|
|
426
488
|
}) {
|
|
427
|
-
const
|
|
428
|
-
const
|
|
489
|
+
const wrapperRef = useRef3(null);
|
|
490
|
+
const trackRef = useRef3(null);
|
|
491
|
+
const inputRef = useRef3(null);
|
|
492
|
+
const labelRef = useRef3(null);
|
|
493
|
+
const valueSpanRef = useRef3(null);
|
|
429
494
|
const [isInteracting, setIsInteracting] = useState2(false);
|
|
430
495
|
const [isDragging, setIsDragging] = useState2(false);
|
|
431
496
|
const [isHovered, setIsHovered] = useState2(false);
|
|
@@ -433,80 +498,162 @@ function Slider({
|
|
|
433
498
|
const [isValueEditable, setIsValueEditable] = useState2(false);
|
|
434
499
|
const [showInput, setShowInput] = useState2(false);
|
|
435
500
|
const [inputValue, setInputValue] = useState2("");
|
|
436
|
-
const hoverTimeoutRef =
|
|
501
|
+
const hoverTimeoutRef = useRef3(null);
|
|
502
|
+
const pointerDownPos = useRef3(null);
|
|
503
|
+
const isClickRef = useRef3(true);
|
|
504
|
+
const animRef = useRef3(null);
|
|
505
|
+
const wrapperRectRef = useRef3(null);
|
|
506
|
+
const scaleRef = useRef3(1);
|
|
437
507
|
const percentage = (value - min) / (max - min) * 100;
|
|
438
|
-
const isAtMinimum = value <= min;
|
|
439
508
|
const isActive = isInteracting || isHovered;
|
|
509
|
+
const fillPercent = useMotionValue(percentage);
|
|
510
|
+
const fillWidth = useTransform(fillPercent, (pct) => `${pct}%`);
|
|
511
|
+
const handleLeft = useTransform(
|
|
512
|
+
fillPercent,
|
|
513
|
+
(pct) => `max(5px, calc(${pct}% - 9px))`
|
|
514
|
+
);
|
|
515
|
+
const rubberStretchPx = useMotionValue(0);
|
|
516
|
+
const rubberBandWidth = useTransform(
|
|
517
|
+
rubberStretchPx,
|
|
518
|
+
(stretch) => `calc(100% + ${Math.abs(stretch)}px)`
|
|
519
|
+
);
|
|
520
|
+
const rubberBandX = useTransform(
|
|
521
|
+
rubberStretchPx,
|
|
522
|
+
(stretch) => stretch < 0 ? stretch : 0
|
|
523
|
+
);
|
|
524
|
+
useEffect3(() => {
|
|
525
|
+
if (!isInteracting && !animRef.current) {
|
|
526
|
+
fillPercent.jump(percentage);
|
|
527
|
+
}
|
|
528
|
+
}, [percentage, isInteracting, fillPercent]);
|
|
440
529
|
const positionToValue = useCallback(
|
|
441
530
|
(clientX) => {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
const
|
|
445
|
-
const
|
|
531
|
+
const rect = wrapperRectRef.current;
|
|
532
|
+
if (!rect) return value;
|
|
533
|
+
const screenX = clientX - rect.left;
|
|
534
|
+
const sceneX = screenX / scaleRef.current;
|
|
535
|
+
const nativeWidth = wrapperRef.current ? wrapperRef.current.offsetWidth : rect.width;
|
|
536
|
+
const percent = Math.max(0, Math.min(1, sceneX / nativeWidth));
|
|
446
537
|
const rawValue = min + percent * (max - min);
|
|
447
538
|
return Math.max(min, Math.min(max, rawValue));
|
|
448
539
|
},
|
|
449
540
|
[min, max, value]
|
|
450
541
|
);
|
|
451
|
-
const
|
|
452
|
-
(
|
|
453
|
-
|
|
454
|
-
e.preventDefault();
|
|
455
|
-
setIsInteracting(true);
|
|
456
|
-
onChange(positionToValue(e.clientX));
|
|
457
|
-
},
|
|
458
|
-
[positionToValue, onChange, showInput]
|
|
542
|
+
const percentFromValue = useCallback(
|
|
543
|
+
(v) => (v - min) / (max - min) * 100,
|
|
544
|
+
[min, max]
|
|
459
545
|
);
|
|
460
|
-
const
|
|
461
|
-
(
|
|
462
|
-
|
|
463
|
-
if (!
|
|
464
|
-
|
|
546
|
+
const computeRubberStretch = useCallback(
|
|
547
|
+
(clientX, sign) => {
|
|
548
|
+
const rect = wrapperRectRef.current;
|
|
549
|
+
if (!rect) return 0;
|
|
550
|
+
const distancePast = sign < 0 ? rect.left - clientX : clientX - rect.right;
|
|
551
|
+
const overflow = Math.max(0, distancePast - DEAD_ZONE);
|
|
552
|
+
return sign * MAX_STRETCH * Math.sqrt(Math.min(overflow / MAX_CURSOR_RANGE, 1));
|
|
465
553
|
},
|
|
466
|
-
[
|
|
554
|
+
[]
|
|
467
555
|
);
|
|
468
|
-
const
|
|
469
|
-
setIsInteracting(false);
|
|
470
|
-
setIsDragging(false);
|
|
471
|
-
}, []);
|
|
472
|
-
const handleTouchStart = useCallback(
|
|
556
|
+
const handlePointerDown = useCallback(
|
|
473
557
|
(e) => {
|
|
474
558
|
if (showInput) return;
|
|
475
559
|
e.preventDefault();
|
|
560
|
+
e.target.setPointerCapture(e.pointerId);
|
|
561
|
+
pointerDownPos.current = { x: e.clientX, y: e.clientY };
|
|
562
|
+
isClickRef.current = true;
|
|
476
563
|
setIsInteracting(true);
|
|
477
|
-
|
|
478
|
-
|
|
564
|
+
if (wrapperRef.current) {
|
|
565
|
+
wrapperRectRef.current = wrapperRef.current.getBoundingClientRect();
|
|
566
|
+
const nativeWidth = wrapperRef.current.offsetWidth;
|
|
567
|
+
scaleRef.current = wrapperRectRef.current.width / nativeWidth;
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
[showInput]
|
|
571
|
+
);
|
|
572
|
+
const handlePointerMove = useCallback(
|
|
573
|
+
(e) => {
|
|
574
|
+
if (!isInteracting || !pointerDownPos.current) return;
|
|
575
|
+
const dx = e.clientX - pointerDownPos.current.x;
|
|
576
|
+
const dy = e.clientY - pointerDownPos.current.y;
|
|
577
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
578
|
+
if (isClickRef.current && distance > CLICK_THRESHOLD) {
|
|
579
|
+
isClickRef.current = false;
|
|
580
|
+
setIsDragging(true);
|
|
581
|
+
}
|
|
582
|
+
if (!isClickRef.current) {
|
|
583
|
+
const rect = wrapperRectRef.current;
|
|
584
|
+
if (rect) {
|
|
585
|
+
if (e.clientX < rect.left) {
|
|
586
|
+
rubberStretchPx.jump(computeRubberStretch(e.clientX, -1));
|
|
587
|
+
} else if (e.clientX > rect.right) {
|
|
588
|
+
rubberStretchPx.jump(computeRubberStretch(e.clientX, 1));
|
|
589
|
+
} else {
|
|
590
|
+
rubberStretchPx.jump(0);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
const newValue = positionToValue(e.clientX);
|
|
594
|
+
const newPct = percentFromValue(newValue);
|
|
595
|
+
if (animRef.current) {
|
|
596
|
+
animRef.current.stop();
|
|
597
|
+
animRef.current = null;
|
|
598
|
+
}
|
|
599
|
+
fillPercent.jump(newPct);
|
|
600
|
+
onChange(roundValue(newValue, step));
|
|
601
|
+
}
|
|
479
602
|
},
|
|
480
|
-
[
|
|
603
|
+
[
|
|
604
|
+
isInteracting,
|
|
605
|
+
positionToValue,
|
|
606
|
+
percentFromValue,
|
|
607
|
+
onChange,
|
|
608
|
+
fillPercent,
|
|
609
|
+
rubberStretchPx,
|
|
610
|
+
computeRubberStretch
|
|
611
|
+
]
|
|
481
612
|
);
|
|
482
|
-
const
|
|
613
|
+
const handlePointerUp = useCallback(
|
|
483
614
|
(e) => {
|
|
484
615
|
if (!isInteracting) return;
|
|
485
|
-
if (
|
|
486
|
-
|
|
487
|
-
|
|
616
|
+
if (isClickRef.current) {
|
|
617
|
+
const rawValue = positionToValue(e.clientX);
|
|
618
|
+
const snappedValue = snapToDecile(rawValue, min, max);
|
|
619
|
+
const newPct = percentFromValue(snappedValue);
|
|
620
|
+
if (animRef.current) {
|
|
621
|
+
animRef.current.stop();
|
|
622
|
+
}
|
|
623
|
+
animRef.current = animate(fillPercent, newPct, {
|
|
624
|
+
type: "spring",
|
|
625
|
+
stiffness: 300,
|
|
626
|
+
damping: 25,
|
|
627
|
+
mass: 0.8,
|
|
628
|
+
onComplete: () => {
|
|
629
|
+
animRef.current = null;
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
onChange(roundValue(snappedValue, step));
|
|
633
|
+
}
|
|
634
|
+
if (rubberStretchPx.get() !== 0) {
|
|
635
|
+
animate(rubberStretchPx, 0, {
|
|
636
|
+
type: "spring",
|
|
637
|
+
visualDuration: 0.35,
|
|
638
|
+
bounce: 0.15
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
setIsInteracting(false);
|
|
642
|
+
setIsDragging(false);
|
|
643
|
+
pointerDownPos.current = null;
|
|
488
644
|
},
|
|
489
|
-
[
|
|
645
|
+
[
|
|
646
|
+
isInteracting,
|
|
647
|
+
positionToValue,
|
|
648
|
+
percentFromValue,
|
|
649
|
+
onChange,
|
|
650
|
+
min,
|
|
651
|
+
max,
|
|
652
|
+
fillPercent,
|
|
653
|
+
rubberStretchPx
|
|
654
|
+
]
|
|
490
655
|
);
|
|
491
|
-
|
|
492
|
-
setIsInteracting(false);
|
|
493
|
-
setIsDragging(false);
|
|
494
|
-
}, []);
|
|
495
|
-
useEffect2(() => {
|
|
496
|
-
if (isInteracting) {
|
|
497
|
-
document.addEventListener("mousemove", handleMouseMove);
|
|
498
|
-
document.addEventListener("mouseup", handleMouseUp);
|
|
499
|
-
document.addEventListener("touchmove", handleTouchMove, { passive: false });
|
|
500
|
-
document.addEventListener("touchend", handleTouchEnd);
|
|
501
|
-
return () => {
|
|
502
|
-
document.removeEventListener("mousemove", handleMouseMove);
|
|
503
|
-
document.removeEventListener("mouseup", handleMouseUp);
|
|
504
|
-
document.removeEventListener("touchmove", handleTouchMove);
|
|
505
|
-
document.removeEventListener("touchend", handleTouchEnd);
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
}, [isInteracting, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
|
|
509
|
-
useEffect2(() => {
|
|
656
|
+
useEffect3(() => {
|
|
510
657
|
if (isValueHovered && !showInput && !isValueEditable) {
|
|
511
658
|
hoverTimeoutRef.current = setTimeout(() => {
|
|
512
659
|
setIsValueEditable(true);
|
|
@@ -524,7 +671,7 @@ function Slider({
|
|
|
524
671
|
}
|
|
525
672
|
};
|
|
526
673
|
}, [isValueHovered, showInput, isValueEditable]);
|
|
527
|
-
|
|
674
|
+
useEffect3(() => {
|
|
528
675
|
if (showInput && inputRef.current) {
|
|
529
676
|
inputRef.current.focus();
|
|
530
677
|
inputRef.current.select();
|
|
@@ -537,7 +684,7 @@ function Slider({
|
|
|
537
684
|
const parsed = parseFloat(inputValue);
|
|
538
685
|
if (!isNaN(parsed)) {
|
|
539
686
|
const clamped = Math.max(min, Math.min(max, parsed));
|
|
540
|
-
onChange(clamped);
|
|
687
|
+
onChange(roundValue(clamped, step));
|
|
541
688
|
}
|
|
542
689
|
setShowInput(false);
|
|
543
690
|
setIsValueHovered(false);
|
|
@@ -563,29 +710,56 @@ function Slider({
|
|
|
563
710
|
handleInputSubmit();
|
|
564
711
|
};
|
|
565
712
|
const displayValue = step >= 1 ? value.toFixed(0) : value.toFixed(2);
|
|
566
|
-
const
|
|
567
|
-
const
|
|
568
|
-
const
|
|
713
|
+
const HANDLE_BUFFER = 8;
|
|
714
|
+
const LABEL_CSS_LEFT = 10;
|
|
715
|
+
const VALUE_CSS_RIGHT = 10;
|
|
716
|
+
let leftThreshold = 30;
|
|
717
|
+
let rightThreshold = 78;
|
|
718
|
+
const trackWidth = wrapperRef.current?.offsetWidth;
|
|
719
|
+
if (trackWidth && trackWidth > 0) {
|
|
720
|
+
if (labelRef.current) {
|
|
721
|
+
leftThreshold = (LABEL_CSS_LEFT + labelRef.current.offsetWidth + HANDLE_BUFFER) / trackWidth * 100;
|
|
722
|
+
}
|
|
723
|
+
if (valueSpanRef.current) {
|
|
724
|
+
rightThreshold = (trackWidth - VALUE_CSS_RIGHT - valueSpanRef.current.offsetWidth - HANDLE_BUFFER) / trackWidth * 100;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
const valueDodge = percentage < leftThreshold || percentage > rightThreshold;
|
|
728
|
+
const handleOpacity = !isActive ? 0 : valueDodge ? 0.1 : isDragging ? 0.9 : 0.5;
|
|
569
729
|
const fillBackground = isActive ? "rgba(255, 255, 255, 0.15)" : "rgba(255, 255, 255, 0.11)";
|
|
570
|
-
const hashMarks = Array.from({ length:
|
|
571
|
-
|
|
572
|
-
|
|
730
|
+
const hashMarks = Array.from({ length: 9 }, (_, i) => {
|
|
731
|
+
const pct = (i + 1) * 10;
|
|
732
|
+
return /* @__PURE__ */ jsx2(
|
|
733
|
+
"div",
|
|
734
|
+
{
|
|
735
|
+
className: "dialkit-slider-hashmark",
|
|
736
|
+
style: { left: `${pct}%` }
|
|
737
|
+
},
|
|
738
|
+
i
|
|
739
|
+
);
|
|
740
|
+
});
|
|
741
|
+
return /* @__PURE__ */ jsx2("div", { ref: wrapperRef, className: "dialkit-slider-wrapper", children: /* @__PURE__ */ jsxs2(
|
|
742
|
+
motion2.div,
|
|
573
743
|
{
|
|
574
744
|
ref: trackRef,
|
|
575
745
|
className: `dialkit-slider ${isActive ? "dialkit-slider-active" : ""}`,
|
|
576
|
-
|
|
577
|
-
|
|
746
|
+
onPointerDown: handlePointerDown,
|
|
747
|
+
onPointerMove: handlePointerMove,
|
|
748
|
+
onPointerUp: handlePointerUp,
|
|
578
749
|
onMouseEnter: () => setIsHovered(true),
|
|
579
750
|
onMouseLeave: () => setIsHovered(false),
|
|
751
|
+
style: { width: rubberBandWidth, x: rubberBandX },
|
|
580
752
|
children: [
|
|
581
753
|
/* @__PURE__ */ jsx2("div", { className: "dialkit-slider-hashmarks", children: hashMarks }),
|
|
582
754
|
/* @__PURE__ */ jsx2(
|
|
583
755
|
motion2.div,
|
|
584
756
|
{
|
|
585
757
|
className: "dialkit-slider-fill",
|
|
586
|
-
style: {
|
|
587
|
-
|
|
588
|
-
|
|
758
|
+
style: {
|
|
759
|
+
background: fillBackground,
|
|
760
|
+
width: fillWidth,
|
|
761
|
+
transition: "background 0.15s"
|
|
762
|
+
}
|
|
589
763
|
}
|
|
590
764
|
),
|
|
591
765
|
/* @__PURE__ */ jsx2(
|
|
@@ -593,15 +767,23 @@ function Slider({
|
|
|
593
767
|
{
|
|
594
768
|
className: "dialkit-slider-handle",
|
|
595
769
|
style: {
|
|
596
|
-
background: isInteracting ? "rgba(255, 255, 255, 1)" : "rgba(255, 255, 255, 0.5)",
|
|
597
770
|
left: handleLeft,
|
|
598
|
-
|
|
771
|
+
y: "-50%",
|
|
772
|
+
background: "rgba(255, 255, 255, 0.9)"
|
|
599
773
|
},
|
|
600
|
-
animate: {
|
|
601
|
-
|
|
774
|
+
animate: {
|
|
775
|
+
opacity: handleOpacity,
|
|
776
|
+
scaleX: isActive ? 1 : 0.25,
|
|
777
|
+
scaleY: isActive && valueDodge ? 0.75 : 1
|
|
778
|
+
},
|
|
779
|
+
transition: {
|
|
780
|
+
scaleX: { type: "spring", visualDuration: 0.25, bounce: 0.15 },
|
|
781
|
+
scaleY: { type: "spring", visualDuration: 0.2, bounce: 0.1 },
|
|
782
|
+
opacity: { duration: 0.15 }
|
|
783
|
+
}
|
|
602
784
|
}
|
|
603
785
|
),
|
|
604
|
-
/* @__PURE__ */ jsx2("span", { className: "dialkit-slider-label", children: label }),
|
|
786
|
+
/* @__PURE__ */ jsx2("span", { ref: labelRef, className: "dialkit-slider-label", children: label }),
|
|
605
787
|
showInput ? /* @__PURE__ */ jsx2(
|
|
606
788
|
"input",
|
|
607
789
|
{
|
|
@@ -615,28 +797,26 @@ function Slider({
|
|
|
615
797
|
onClick: (e) => e.stopPropagation(),
|
|
616
798
|
onMouseDown: (e) => e.stopPropagation()
|
|
617
799
|
}
|
|
618
|
-
) : /* @__PURE__ */
|
|
800
|
+
) : /* @__PURE__ */ jsx2(
|
|
619
801
|
"span",
|
|
620
802
|
{
|
|
803
|
+
ref: valueSpanRef,
|
|
621
804
|
className: `dialkit-slider-value ${isValueEditable ? "dialkit-slider-value-editable" : ""}`,
|
|
622
805
|
onMouseEnter: () => setIsValueHovered(true),
|
|
623
806
|
onMouseLeave: () => setIsValueHovered(false),
|
|
624
807
|
onClick: handleValueClick,
|
|
625
808
|
onMouseDown: (e) => isValueEditable && e.stopPropagation(),
|
|
626
809
|
style: { cursor: isValueEditable ? "text" : "default" },
|
|
627
|
-
children:
|
|
628
|
-
displayValue,
|
|
629
|
-
unit
|
|
630
|
-
]
|
|
810
|
+
children: displayValue
|
|
631
811
|
}
|
|
632
812
|
)
|
|
633
813
|
]
|
|
634
814
|
}
|
|
635
|
-
);
|
|
815
|
+
) });
|
|
636
816
|
}
|
|
637
817
|
|
|
638
818
|
// src/components/SegmentedControl.tsx
|
|
639
|
-
import { useRef as
|
|
819
|
+
import { useRef as useRef4, useState as useState3, useLayoutEffect } from "react";
|
|
640
820
|
import { motion as motion3 } from "motion/react";
|
|
641
821
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
642
822
|
function SegmentedControl({
|
|
@@ -644,10 +824,10 @@ function SegmentedControl({
|
|
|
644
824
|
value,
|
|
645
825
|
onChange
|
|
646
826
|
}) {
|
|
647
|
-
const containerRef =
|
|
648
|
-
const buttonRefs =
|
|
827
|
+
const containerRef = useRef4(null);
|
|
828
|
+
const buttonRefs = useRef4(/* @__PURE__ */ new Map());
|
|
649
829
|
const [pillStyle, setPillStyle] = useState3(null);
|
|
650
|
-
const hasAnimated =
|
|
830
|
+
const hasAnimated = useRef4(false);
|
|
651
831
|
useLayoutEffect(() => {
|
|
652
832
|
const button = buttonRefs.current.get(value);
|
|
653
833
|
const container = containerRef.current;
|
|
@@ -917,20 +1097,352 @@ function SpringControl({ panelId, path, label, spring, onChange }) {
|
|
|
917
1097
|
] }) });
|
|
918
1098
|
}
|
|
919
1099
|
|
|
920
|
-
// src/components/
|
|
921
|
-
import { useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1100
|
+
// src/components/TextControl.tsx
|
|
922
1101
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1102
|
+
function TextControl({ label, value, onChange, placeholder }) {
|
|
1103
|
+
return /* @__PURE__ */ jsxs7("div", { className: "dialkit-text-control", children: [
|
|
1104
|
+
/* @__PURE__ */ jsx7("label", { className: "dialkit-text-label", children: label }),
|
|
1105
|
+
/* @__PURE__ */ jsx7(
|
|
1106
|
+
"input",
|
|
1107
|
+
{
|
|
1108
|
+
type: "text",
|
|
1109
|
+
className: "dialkit-text-input",
|
|
1110
|
+
value,
|
|
1111
|
+
onChange: (e) => onChange(e.target.value),
|
|
1112
|
+
placeholder
|
|
1113
|
+
}
|
|
1114
|
+
)
|
|
1115
|
+
] });
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// src/components/SelectControl.tsx
|
|
1119
|
+
import { useState as useState4, useRef as useRef5, useEffect as useEffect4 } from "react";
|
|
1120
|
+
import { motion as motion4, AnimatePresence as AnimatePresence2 } from "motion/react";
|
|
1121
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1122
|
+
function toTitleCase(s) {
|
|
1123
|
+
return s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1124
|
+
}
|
|
1125
|
+
function normalizeOptions(options) {
|
|
1126
|
+
return options.map(
|
|
1127
|
+
(opt) => typeof opt === "string" ? { value: opt, label: toTitleCase(opt) } : opt
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
function SelectControl({ label, value, options, onChange }) {
|
|
1131
|
+
const [isOpen, setIsOpen] = useState4(false);
|
|
1132
|
+
const containerRef = useRef5(null);
|
|
1133
|
+
const normalized = normalizeOptions(options);
|
|
1134
|
+
const selectedOption = normalized.find((o) => o.value === value);
|
|
1135
|
+
useEffect4(() => {
|
|
1136
|
+
if (!isOpen) return;
|
|
1137
|
+
const handleClick = (e) => {
|
|
1138
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
1139
|
+
setIsOpen(false);
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
document.addEventListener("mousedown", handleClick);
|
|
1143
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1144
|
+
}, [isOpen]);
|
|
1145
|
+
return /* @__PURE__ */ jsxs8("div", { ref: containerRef, className: "dialkit-select-row", children: [
|
|
1146
|
+
/* @__PURE__ */ jsxs8(
|
|
1147
|
+
"button",
|
|
1148
|
+
{
|
|
1149
|
+
className: "dialkit-select-trigger",
|
|
1150
|
+
onClick: () => setIsOpen(!isOpen),
|
|
1151
|
+
"data-open": String(isOpen),
|
|
1152
|
+
children: [
|
|
1153
|
+
/* @__PURE__ */ jsx8("span", { className: "dialkit-select-label", children: label }),
|
|
1154
|
+
/* @__PURE__ */ jsxs8("div", { className: "dialkit-select-right", children: [
|
|
1155
|
+
/* @__PURE__ */ jsx8("span", { className: "dialkit-select-value", children: selectedOption?.label ?? value }),
|
|
1156
|
+
/* @__PURE__ */ jsx8(
|
|
1157
|
+
motion4.svg,
|
|
1158
|
+
{
|
|
1159
|
+
className: "dialkit-select-chevron",
|
|
1160
|
+
viewBox: "0 0 24 24",
|
|
1161
|
+
fill: "none",
|
|
1162
|
+
stroke: "currentColor",
|
|
1163
|
+
strokeWidth: "2.5",
|
|
1164
|
+
strokeLinecap: "round",
|
|
1165
|
+
strokeLinejoin: "round",
|
|
1166
|
+
animate: { rotate: isOpen ? 180 : 0 },
|
|
1167
|
+
transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
|
|
1168
|
+
children: /* @__PURE__ */ jsx8("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
1169
|
+
}
|
|
1170
|
+
)
|
|
1171
|
+
] })
|
|
1172
|
+
]
|
|
1173
|
+
}
|
|
1174
|
+
),
|
|
1175
|
+
/* @__PURE__ */ jsx8(AnimatePresence2, { children: isOpen && /* @__PURE__ */ jsx8(
|
|
1176
|
+
motion4.div,
|
|
1177
|
+
{
|
|
1178
|
+
className: "dialkit-select-dropdown",
|
|
1179
|
+
initial: { opacity: 0, y: -8, scale: 0.95 },
|
|
1180
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1181
|
+
exit: { opacity: 0, y: -8, scale: 0.95 },
|
|
1182
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1183
|
+
children: normalized.map((option) => /* @__PURE__ */ jsx8(
|
|
1184
|
+
"button",
|
|
1185
|
+
{
|
|
1186
|
+
className: "dialkit-select-option",
|
|
1187
|
+
"data-selected": String(option.value === value),
|
|
1188
|
+
onClick: () => {
|
|
1189
|
+
onChange(option.value);
|
|
1190
|
+
setIsOpen(false);
|
|
1191
|
+
},
|
|
1192
|
+
children: option.label
|
|
1193
|
+
},
|
|
1194
|
+
option.value
|
|
1195
|
+
))
|
|
1196
|
+
}
|
|
1197
|
+
) })
|
|
1198
|
+
] });
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// src/components/ColorControl.tsx
|
|
1202
|
+
import { useState as useState5, useRef as useRef6, useEffect as useEffect5 } from "react";
|
|
1203
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1204
|
+
var HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
1205
|
+
function ColorControl({ label, value, onChange }) {
|
|
1206
|
+
const [isEditing, setIsEditing] = useState5(false);
|
|
1207
|
+
const [editValue, setEditValue] = useState5(value);
|
|
1208
|
+
const colorInputRef = useRef6(null);
|
|
1209
|
+
useEffect5(() => {
|
|
1210
|
+
if (!isEditing) {
|
|
1211
|
+
setEditValue(value);
|
|
1212
|
+
}
|
|
1213
|
+
}, [value, isEditing]);
|
|
1214
|
+
function handleTextSubmit() {
|
|
1215
|
+
setIsEditing(false);
|
|
1216
|
+
if (HEX_COLOR_REGEX.test(editValue)) {
|
|
1217
|
+
onChange(editValue);
|
|
1218
|
+
} else {
|
|
1219
|
+
setEditValue(value);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function handleKeyDown(e) {
|
|
1223
|
+
if (e.key === "Enter") {
|
|
1224
|
+
handleTextSubmit();
|
|
1225
|
+
} else if (e.key === "Escape") {
|
|
1226
|
+
setIsEditing(false);
|
|
1227
|
+
setEditValue(value);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return /* @__PURE__ */ jsxs9("div", { className: "dialkit-color-control", children: [
|
|
1231
|
+
/* @__PURE__ */ jsx9("span", { className: "dialkit-color-label", children: label }),
|
|
1232
|
+
/* @__PURE__ */ jsxs9("div", { className: "dialkit-color-inputs", children: [
|
|
1233
|
+
isEditing ? /* @__PURE__ */ jsx9(
|
|
1234
|
+
"input",
|
|
1235
|
+
{
|
|
1236
|
+
type: "text",
|
|
1237
|
+
className: "dialkit-color-hex-input",
|
|
1238
|
+
value: editValue,
|
|
1239
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
1240
|
+
onBlur: handleTextSubmit,
|
|
1241
|
+
onKeyDown: handleKeyDown,
|
|
1242
|
+
autoFocus: true
|
|
1243
|
+
}
|
|
1244
|
+
) : /* @__PURE__ */ jsx9(
|
|
1245
|
+
"span",
|
|
1246
|
+
{
|
|
1247
|
+
className: "dialkit-color-hex",
|
|
1248
|
+
onClick: () => setIsEditing(true),
|
|
1249
|
+
children: (value ?? "").toUpperCase()
|
|
1250
|
+
}
|
|
1251
|
+
),
|
|
1252
|
+
/* @__PURE__ */ jsx9(
|
|
1253
|
+
"button",
|
|
1254
|
+
{
|
|
1255
|
+
className: "dialkit-color-swatch",
|
|
1256
|
+
style: { backgroundColor: value },
|
|
1257
|
+
onClick: () => colorInputRef.current?.click(),
|
|
1258
|
+
title: "Pick color"
|
|
1259
|
+
}
|
|
1260
|
+
),
|
|
1261
|
+
/* @__PURE__ */ jsx9(
|
|
1262
|
+
"input",
|
|
1263
|
+
{
|
|
1264
|
+
ref: colorInputRef,
|
|
1265
|
+
type: "color",
|
|
1266
|
+
className: "dialkit-color-picker-native",
|
|
1267
|
+
value: value.length === 4 ? expandShorthandHex(value) : value.slice(0, 7),
|
|
1268
|
+
onChange: (e) => onChange(e.target.value)
|
|
1269
|
+
}
|
|
1270
|
+
)
|
|
1271
|
+
] })
|
|
1272
|
+
] });
|
|
1273
|
+
}
|
|
1274
|
+
function expandShorthandHex(hex) {
|
|
1275
|
+
if (hex.length !== 4) return hex;
|
|
1276
|
+
return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// src/components/PresetManager.tsx
|
|
1280
|
+
import { useState as useState6, useRef as useRef7, useEffect as useEffect6, useCallback as useCallback2 } from "react";
|
|
1281
|
+
import { createPortal } from "react-dom";
|
|
1282
|
+
import { motion as motion5, AnimatePresence as AnimatePresence3 } from "motion/react";
|
|
1283
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1284
|
+
function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
1285
|
+
const [isOpen, setIsOpen] = useState6(false);
|
|
1286
|
+
const triggerRef = useRef7(null);
|
|
1287
|
+
const dropdownRef = useRef7(null);
|
|
1288
|
+
const [pos, setPos] = useState6({ top: 0, left: 0, width: 0 });
|
|
1289
|
+
const hasPresets = presets.length > 0;
|
|
1290
|
+
const activePreset = presets.find((p) => p.id === activePresetId);
|
|
1291
|
+
const open = useCallback2(() => {
|
|
1292
|
+
if (!hasPresets) return;
|
|
1293
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1294
|
+
if (rect) {
|
|
1295
|
+
setPos({ top: rect.bottom + 4, left: rect.left, width: rect.width });
|
|
1296
|
+
}
|
|
1297
|
+
setIsOpen(true);
|
|
1298
|
+
}, [hasPresets]);
|
|
1299
|
+
const close = useCallback2(() => setIsOpen(false), []);
|
|
1300
|
+
const toggle = useCallback2(() => {
|
|
1301
|
+
if (isOpen) close();
|
|
1302
|
+
else open();
|
|
1303
|
+
}, [isOpen, open, close]);
|
|
1304
|
+
useEffect6(() => {
|
|
1305
|
+
if (!isOpen) return;
|
|
1306
|
+
const handler = (e) => {
|
|
1307
|
+
const target = e.target;
|
|
1308
|
+
if (triggerRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;
|
|
1309
|
+
close();
|
|
1310
|
+
};
|
|
1311
|
+
document.addEventListener("mousedown", handler);
|
|
1312
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
1313
|
+
}, [isOpen, close]);
|
|
1314
|
+
const handleSelect = (presetId) => {
|
|
1315
|
+
if (presetId) {
|
|
1316
|
+
DialStore.loadPreset(panelId, presetId);
|
|
1317
|
+
} else {
|
|
1318
|
+
DialStore.clearActivePreset(panelId);
|
|
1319
|
+
}
|
|
1320
|
+
close();
|
|
1321
|
+
};
|
|
1322
|
+
const handleDelete = (e, presetId) => {
|
|
1323
|
+
e.stopPropagation();
|
|
1324
|
+
DialStore.deletePreset(panelId, presetId);
|
|
1325
|
+
};
|
|
1326
|
+
return /* @__PURE__ */ jsxs10("div", { className: "dialkit-preset-manager", children: [
|
|
1327
|
+
/* @__PURE__ */ jsxs10(
|
|
1328
|
+
"button",
|
|
1329
|
+
{
|
|
1330
|
+
ref: triggerRef,
|
|
1331
|
+
className: "dialkit-preset-trigger",
|
|
1332
|
+
onClick: toggle,
|
|
1333
|
+
"data-open": String(isOpen),
|
|
1334
|
+
"data-has-preset": String(!!activePreset),
|
|
1335
|
+
"data-disabled": String(!hasPresets),
|
|
1336
|
+
children: [
|
|
1337
|
+
/* @__PURE__ */ jsx10("span", { className: "dialkit-preset-label", children: activePreset ? activePreset.name : "Version 1" }),
|
|
1338
|
+
/* @__PURE__ */ jsx10(
|
|
1339
|
+
motion5.svg,
|
|
1340
|
+
{
|
|
1341
|
+
className: "dialkit-select-chevron",
|
|
1342
|
+
viewBox: "0 0 24 24",
|
|
1343
|
+
fill: "none",
|
|
1344
|
+
stroke: "currentColor",
|
|
1345
|
+
strokeWidth: "2.5",
|
|
1346
|
+
strokeLinecap: "round",
|
|
1347
|
+
strokeLinejoin: "round",
|
|
1348
|
+
animate: { rotate: isOpen ? 180 : 0, opacity: hasPresets ? 0.6 : 0.25 },
|
|
1349
|
+
transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
|
|
1350
|
+
children: /* @__PURE__ */ jsx10("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
1351
|
+
}
|
|
1352
|
+
)
|
|
1353
|
+
]
|
|
1354
|
+
}
|
|
1355
|
+
),
|
|
1356
|
+
createPortal(
|
|
1357
|
+
/* @__PURE__ */ jsx10(AnimatePresence3, { children: isOpen && /* @__PURE__ */ jsxs10(
|
|
1358
|
+
motion5.div,
|
|
1359
|
+
{
|
|
1360
|
+
ref: dropdownRef,
|
|
1361
|
+
className: "dialkit-preset-dropdown",
|
|
1362
|
+
style: { position: "fixed", top: pos.top, left: pos.left, minWidth: pos.width },
|
|
1363
|
+
initial: { opacity: 0, y: 4, scale: 0.97 },
|
|
1364
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1365
|
+
exit: { opacity: 0, y: 4, scale: 0.97, pointerEvents: "none" },
|
|
1366
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1367
|
+
children: [
|
|
1368
|
+
/* @__PURE__ */ jsx10(
|
|
1369
|
+
"div",
|
|
1370
|
+
{
|
|
1371
|
+
className: "dialkit-preset-item",
|
|
1372
|
+
"data-active": String(!activePresetId),
|
|
1373
|
+
onClick: () => handleSelect(null),
|
|
1374
|
+
children: /* @__PURE__ */ jsx10("span", { className: "dialkit-preset-name", children: "Version 1" })
|
|
1375
|
+
}
|
|
1376
|
+
),
|
|
1377
|
+
presets.map((preset) => /* @__PURE__ */ jsxs10(
|
|
1378
|
+
"div",
|
|
1379
|
+
{
|
|
1380
|
+
className: "dialkit-preset-item",
|
|
1381
|
+
"data-active": String(preset.id === activePresetId),
|
|
1382
|
+
onClick: () => handleSelect(preset.id),
|
|
1383
|
+
children: [
|
|
1384
|
+
/* @__PURE__ */ jsx10("span", { className: "dialkit-preset-name", children: preset.name }),
|
|
1385
|
+
/* @__PURE__ */ jsx10(
|
|
1386
|
+
"button",
|
|
1387
|
+
{
|
|
1388
|
+
className: "dialkit-preset-delete",
|
|
1389
|
+
onClick: (e) => handleDelete(e, preset.id),
|
|
1390
|
+
title: "Delete preset",
|
|
1391
|
+
children: /* @__PURE__ */ jsxs10("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1392
|
+
/* @__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" }),
|
|
1393
|
+
/* @__PURE__ */ jsx10("path", { d: "M10 11V16" }),
|
|
1394
|
+
/* @__PURE__ */ jsx10("path", { d: "M14 11V16" }),
|
|
1395
|
+
/* @__PURE__ */ jsx10("path", { d: "M3.5 6H20.5" }),
|
|
1396
|
+
/* @__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" })
|
|
1397
|
+
] })
|
|
1398
|
+
}
|
|
1399
|
+
)
|
|
1400
|
+
]
|
|
1401
|
+
},
|
|
1402
|
+
preset.id
|
|
1403
|
+
))
|
|
1404
|
+
]
|
|
1405
|
+
}
|
|
1406
|
+
) }),
|
|
1407
|
+
document.body
|
|
1408
|
+
)
|
|
1409
|
+
] });
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// src/components/Panel.tsx
|
|
1413
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
923
1414
|
function Panel({ panel }) {
|
|
1415
|
+
const [copied, setCopied] = useState7(false);
|
|
1416
|
+
const [isPanelOpen, setIsPanelOpen] = useState7(true);
|
|
924
1417
|
const values = useSyncExternalStore3(
|
|
925
1418
|
(cb) => DialStore.subscribe(panel.id, cb),
|
|
926
1419
|
() => DialStore.getValues(panel.id),
|
|
927
1420
|
() => DialStore.getValues(panel.id)
|
|
928
1421
|
);
|
|
1422
|
+
const presets = DialStore.getPresets(panel.id);
|
|
1423
|
+
const activePresetId = DialStore.getActivePresetId(panel.id);
|
|
1424
|
+
const handleAddPreset = () => {
|
|
1425
|
+
const nextNum = presets.length + 2;
|
|
1426
|
+
DialStore.savePreset(panel.id, `Version ${nextNum}`);
|
|
1427
|
+
};
|
|
1428
|
+
const handleCopy = () => {
|
|
1429
|
+
const jsonStr = JSON.stringify(values, null, 2);
|
|
1430
|
+
const instruction = `Update the useDialKit configuration for "${panel.name}" with these values:
|
|
1431
|
+
|
|
1432
|
+
\`\`\`json
|
|
1433
|
+
${jsonStr}
|
|
1434
|
+
\`\`\`
|
|
1435
|
+
|
|
1436
|
+
Apply these values as the new defaults in the useDialKit call.`;
|
|
1437
|
+
navigator.clipboard.writeText(instruction);
|
|
1438
|
+
setCopied(true);
|
|
1439
|
+
setTimeout(() => setCopied(false), 1500);
|
|
1440
|
+
};
|
|
929
1441
|
const renderControl = (control) => {
|
|
930
1442
|
const value = values[control.path];
|
|
931
1443
|
switch (control.type) {
|
|
932
1444
|
case "slider":
|
|
933
|
-
return /* @__PURE__ */
|
|
1445
|
+
return /* @__PURE__ */ jsx11(
|
|
934
1446
|
Slider,
|
|
935
1447
|
{
|
|
936
1448
|
label: control.label,
|
|
@@ -943,7 +1455,7 @@ function Panel({ panel }) {
|
|
|
943
1455
|
control.path
|
|
944
1456
|
);
|
|
945
1457
|
case "toggle":
|
|
946
|
-
return /* @__PURE__ */
|
|
1458
|
+
return /* @__PURE__ */ jsx11(
|
|
947
1459
|
Toggle,
|
|
948
1460
|
{
|
|
949
1461
|
label: control.label,
|
|
@@ -953,7 +1465,7 @@ function Panel({ panel }) {
|
|
|
953
1465
|
control.path
|
|
954
1466
|
);
|
|
955
1467
|
case "spring":
|
|
956
|
-
return /* @__PURE__ */
|
|
1468
|
+
return /* @__PURE__ */ jsx11(
|
|
957
1469
|
SpringControl,
|
|
958
1470
|
{
|
|
959
1471
|
panelId: panel.id,
|
|
@@ -965,7 +1477,39 @@ function Panel({ panel }) {
|
|
|
965
1477
|
control.path
|
|
966
1478
|
);
|
|
967
1479
|
case "folder":
|
|
968
|
-
return /* @__PURE__ */
|
|
1480
|
+
return /* @__PURE__ */ jsx11(Folder, { title: control.label, children: control.children?.map(renderControl) }, control.path);
|
|
1481
|
+
case "text":
|
|
1482
|
+
return /* @__PURE__ */ jsx11(
|
|
1483
|
+
TextControl,
|
|
1484
|
+
{
|
|
1485
|
+
label: control.label,
|
|
1486
|
+
value,
|
|
1487
|
+
onChange: (v) => DialStore.updateValue(panel.id, control.path, v),
|
|
1488
|
+
placeholder: control.placeholder
|
|
1489
|
+
},
|
|
1490
|
+
control.path
|
|
1491
|
+
);
|
|
1492
|
+
case "select":
|
|
1493
|
+
return /* @__PURE__ */ jsx11(
|
|
1494
|
+
SelectControl,
|
|
1495
|
+
{
|
|
1496
|
+
label: control.label,
|
|
1497
|
+
value,
|
|
1498
|
+
options: control.options ?? [],
|
|
1499
|
+
onChange: (v) => DialStore.updateValue(panel.id, control.path, v)
|
|
1500
|
+
},
|
|
1501
|
+
control.path
|
|
1502
|
+
);
|
|
1503
|
+
case "color":
|
|
1504
|
+
return /* @__PURE__ */ jsx11(
|
|
1505
|
+
ColorControl,
|
|
1506
|
+
{
|
|
1507
|
+
label: control.label,
|
|
1508
|
+
value,
|
|
1509
|
+
onChange: (v) => DialStore.updateValue(panel.id, control.path, v)
|
|
1510
|
+
},
|
|
1511
|
+
control.path
|
|
1512
|
+
);
|
|
969
1513
|
default:
|
|
970
1514
|
return null;
|
|
971
1515
|
}
|
|
@@ -976,24 +1520,16 @@ function Panel({ panel }) {
|
|
|
976
1520
|
while (i < panel.controls.length) {
|
|
977
1521
|
const control = panel.controls[i];
|
|
978
1522
|
if (control.type === "action") {
|
|
979
|
-
const actions = [control];
|
|
980
|
-
while (i + 1 < panel.controls.length && panel.controls[i + 1].type === "action") {
|
|
981
|
-
i++;
|
|
982
|
-
actions.push(panel.controls[i]);
|
|
983
|
-
}
|
|
984
1523
|
result.push(
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
"button",
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
action.path
|
|
995
|
-
)) })
|
|
996
|
-
] }, `actions-${actions[0].path}`)
|
|
1524
|
+
/* @__PURE__ */ jsx11(
|
|
1525
|
+
"button",
|
|
1526
|
+
{
|
|
1527
|
+
className: "dialkit-button",
|
|
1528
|
+
onClick: () => DialStore.triggerAction(panel.id, control.path),
|
|
1529
|
+
children: control.label
|
|
1530
|
+
},
|
|
1531
|
+
control.path
|
|
1532
|
+
)
|
|
997
1533
|
);
|
|
998
1534
|
} else {
|
|
999
1535
|
result.push(renderControl(control));
|
|
@@ -1002,15 +1538,92 @@ function Panel({ panel }) {
|
|
|
1002
1538
|
}
|
|
1003
1539
|
return result;
|
|
1004
1540
|
};
|
|
1005
|
-
|
|
1541
|
+
const iconTransition = { type: "spring", visualDuration: 0.4, bounce: 0.1 };
|
|
1542
|
+
const toolbar = /* @__PURE__ */ jsxs11(Fragment2, { children: [
|
|
1543
|
+
/* @__PURE__ */ jsx11(
|
|
1544
|
+
motion6.button,
|
|
1545
|
+
{
|
|
1546
|
+
className: "dialkit-toolbar-add",
|
|
1547
|
+
onClick: handleAddPreset,
|
|
1548
|
+
title: "Add preset",
|
|
1549
|
+
whileTap: { scale: 0.9 },
|
|
1550
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1551
|
+
children: /* @__PURE__ */ jsxs11("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1552
|
+
/* @__PURE__ */ jsx11("path", { d: "M4 6H20" }),
|
|
1553
|
+
/* @__PURE__ */ jsx11("path", { d: "M4 12H10" }),
|
|
1554
|
+
/* @__PURE__ */ jsx11("path", { d: "M15 15L21 15" }),
|
|
1555
|
+
/* @__PURE__ */ jsx11("path", { d: "M18 12V18" }),
|
|
1556
|
+
/* @__PURE__ */ jsx11("path", { d: "M4 18H10" })
|
|
1557
|
+
] })
|
|
1558
|
+
}
|
|
1559
|
+
),
|
|
1560
|
+
/* @__PURE__ */ jsx11(
|
|
1561
|
+
PresetManager,
|
|
1562
|
+
{
|
|
1563
|
+
panelId: panel.id,
|
|
1564
|
+
presets,
|
|
1565
|
+
activePresetId,
|
|
1566
|
+
onAdd: handleAddPreset
|
|
1567
|
+
}
|
|
1568
|
+
),
|
|
1569
|
+
/* @__PURE__ */ jsxs11(
|
|
1570
|
+
motion6.button,
|
|
1571
|
+
{
|
|
1572
|
+
className: "dialkit-toolbar-copy",
|
|
1573
|
+
onClick: handleCopy,
|
|
1574
|
+
title: "Copy parameters",
|
|
1575
|
+
whileTap: { scale: 0.95 },
|
|
1576
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1577
|
+
children: [
|
|
1578
|
+
/* @__PURE__ */ jsx11("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ jsx11(AnimatePresence4, { initial: false, mode: "popLayout", children: copied ? /* @__PURE__ */ jsx11(
|
|
1579
|
+
motion6.svg,
|
|
1580
|
+
{
|
|
1581
|
+
className: "dialkit-toolbar-copy-icon",
|
|
1582
|
+
viewBox: "0 0 24 24",
|
|
1583
|
+
fill: "none",
|
|
1584
|
+
stroke: "currentColor",
|
|
1585
|
+
strokeWidth: "2",
|
|
1586
|
+
strokeLinecap: "round",
|
|
1587
|
+
strokeLinejoin: "round",
|
|
1588
|
+
initial: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1589
|
+
animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
|
|
1590
|
+
exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1591
|
+
transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
1592
|
+
children: /* @__PURE__ */ jsx11("path", { d: "M5 12.75L10 19L19 5" })
|
|
1593
|
+
},
|
|
1594
|
+
"check"
|
|
1595
|
+
) : /* @__PURE__ */ jsxs11(
|
|
1596
|
+
motion6.svg,
|
|
1597
|
+
{
|
|
1598
|
+
className: "dialkit-toolbar-copy-icon",
|
|
1599
|
+
viewBox: "0 0 24 24",
|
|
1600
|
+
fill: "none",
|
|
1601
|
+
initial: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1602
|
+
animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
|
|
1603
|
+
exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1604
|
+
transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
1605
|
+
children: [
|
|
1606
|
+
/* @__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" }),
|
|
1607
|
+
/* @__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" }),
|
|
1608
|
+
/* @__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" })
|
|
1609
|
+
]
|
|
1610
|
+
},
|
|
1611
|
+
"clipboard"
|
|
1612
|
+
) }) }),
|
|
1613
|
+
"Copy"
|
|
1614
|
+
]
|
|
1615
|
+
}
|
|
1616
|
+
)
|
|
1617
|
+
] });
|
|
1618
|
+
return /* @__PURE__ */ jsx11("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ jsx11(Folder, { title: panel.name, defaultOpen: true, isRoot: true, onOpenChange: setIsPanelOpen, toolbar, children: renderControls() }) });
|
|
1006
1619
|
}
|
|
1007
1620
|
|
|
1008
1621
|
// src/components/DialRoot.tsx
|
|
1009
|
-
import { jsx as
|
|
1622
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
1010
1623
|
function DialRoot({ position = "top-right" }) {
|
|
1011
|
-
const [panels, setPanels] =
|
|
1012
|
-
const [mounted, setMounted] =
|
|
1013
|
-
|
|
1624
|
+
const [panels, setPanels] = useState8([]);
|
|
1625
|
+
const [mounted, setMounted] = useState8(false);
|
|
1626
|
+
useEffect7(() => {
|
|
1014
1627
|
setMounted(true);
|
|
1015
1628
|
setPanels(DialStore.getPanels());
|
|
1016
1629
|
const unsubscribe = DialStore.subscribeGlobal(() => {
|
|
@@ -1024,14 +1637,14 @@ function DialRoot({ position = "top-right" }) {
|
|
|
1024
1637
|
if (panels.length === 0) {
|
|
1025
1638
|
return null;
|
|
1026
1639
|
}
|
|
1027
|
-
const content = /* @__PURE__ */
|
|
1028
|
-
return
|
|
1640
|
+
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)) }) });
|
|
1641
|
+
return createPortal2(content, document.body);
|
|
1029
1642
|
}
|
|
1030
1643
|
|
|
1031
1644
|
// src/components/ButtonGroup.tsx
|
|
1032
|
-
import { jsx as
|
|
1645
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1033
1646
|
function ButtonGroup({ buttons }) {
|
|
1034
|
-
return /* @__PURE__ */
|
|
1647
|
+
return /* @__PURE__ */ jsx13("div", { className: "dialkit-button-group", children: buttons.map((button, index) => /* @__PURE__ */ jsx13(
|
|
1035
1648
|
"button",
|
|
1036
1649
|
{
|
|
1037
1650
|
className: "dialkit-button",
|
|
@@ -1043,13 +1656,16 @@ function ButtonGroup({ buttons }) {
|
|
|
1043
1656
|
}
|
|
1044
1657
|
export {
|
|
1045
1658
|
ButtonGroup,
|
|
1659
|
+
ColorControl,
|
|
1046
1660
|
DialRoot,
|
|
1047
1661
|
DialStore,
|
|
1048
1662
|
Folder,
|
|
1049
|
-
|
|
1663
|
+
PresetManager,
|
|
1664
|
+
SelectControl,
|
|
1050
1665
|
Slider,
|
|
1051
1666
|
SpringControl,
|
|
1052
1667
|
SpringVisualization,
|
|
1668
|
+
TextControl,
|
|
1053
1669
|
Toggle,
|
|
1054
1670
|
useDialKit
|
|
1055
1671
|
};
|