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.cjs
CHANGED
|
@@ -22,13 +22,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
ButtonGroup: () => ButtonGroup,
|
|
25
|
+
ColorControl: () => ColorControl,
|
|
25
26
|
DialRoot: () => DialRoot,
|
|
26
27
|
DialStore: () => DialStore,
|
|
27
28
|
Folder: () => Folder,
|
|
28
|
-
|
|
29
|
+
PresetManager: () => PresetManager,
|
|
30
|
+
SelectControl: () => SelectControl,
|
|
29
31
|
Slider: () => Slider,
|
|
30
32
|
SpringControl: () => SpringControl,
|
|
31
33
|
SpringVisualization: () => SpringVisualization,
|
|
34
|
+
TextControl: () => TextControl,
|
|
32
35
|
Toggle: () => Toggle,
|
|
33
36
|
useDialKit: () => useDialKit
|
|
34
37
|
});
|
|
@@ -46,12 +49,16 @@ var DialStoreClass = class {
|
|
|
46
49
|
this.globalListeners = /* @__PURE__ */ new Set();
|
|
47
50
|
this.snapshots = /* @__PURE__ */ new Map();
|
|
48
51
|
this.actionListeners = /* @__PURE__ */ new Map();
|
|
52
|
+
this.presets = /* @__PURE__ */ new Map();
|
|
53
|
+
this.activePreset = /* @__PURE__ */ new Map();
|
|
54
|
+
this.baseValues = /* @__PURE__ */ new Map();
|
|
49
55
|
}
|
|
50
56
|
registerPanel(id, name, config) {
|
|
51
57
|
const controls = this.parseConfig(config, "");
|
|
52
58
|
const values = this.flattenValues(config, "");
|
|
53
59
|
this.panels.set(id, { id, name, controls, values });
|
|
54
60
|
this.snapshots.set(id, { ...values });
|
|
61
|
+
this.baseValues.set(id, { ...values });
|
|
55
62
|
this.notifyGlobal();
|
|
56
63
|
}
|
|
57
64
|
unregisterPanel(id) {
|
|
@@ -64,6 +71,15 @@ var DialStoreClass = class {
|
|
|
64
71
|
const panel = this.panels.get(panelId);
|
|
65
72
|
if (!panel) return;
|
|
66
73
|
panel.values[path] = value;
|
|
74
|
+
const activeId = this.activePreset.get(panelId);
|
|
75
|
+
if (activeId) {
|
|
76
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
77
|
+
const preset = presets.find((p) => p.id === activeId);
|
|
78
|
+
if (preset) preset.values[path] = value;
|
|
79
|
+
} else {
|
|
80
|
+
const base = this.baseValues.get(panelId);
|
|
81
|
+
if (base) base[path] = value;
|
|
82
|
+
}
|
|
67
83
|
this.snapshots.set(panelId, { ...panel.values });
|
|
68
84
|
this.notify(panelId);
|
|
69
85
|
}
|
|
@@ -117,6 +133,61 @@ var DialStoreClass = class {
|
|
|
117
133
|
triggerAction(panelId, path) {
|
|
118
134
|
this.actionListeners.get(panelId)?.forEach((fn) => fn(path));
|
|
119
135
|
}
|
|
136
|
+
savePreset(panelId, name) {
|
|
137
|
+
const panel = this.panels.get(panelId);
|
|
138
|
+
if (!panel) throw new Error(`Panel ${panelId} not found`);
|
|
139
|
+
const id = `preset-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
140
|
+
const preset = {
|
|
141
|
+
id,
|
|
142
|
+
name,
|
|
143
|
+
values: { ...panel.values }
|
|
144
|
+
};
|
|
145
|
+
const existing = this.presets.get(panelId) ?? [];
|
|
146
|
+
this.presets.set(panelId, [...existing, preset]);
|
|
147
|
+
this.activePreset.set(panelId, id);
|
|
148
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
149
|
+
this.notify(panelId);
|
|
150
|
+
return id;
|
|
151
|
+
}
|
|
152
|
+
loadPreset(panelId, presetId) {
|
|
153
|
+
const panel = this.panels.get(panelId);
|
|
154
|
+
if (!panel) return;
|
|
155
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
156
|
+
const preset = presets.find((p) => p.id === presetId);
|
|
157
|
+
if (!preset) return;
|
|
158
|
+
panel.values = { ...preset.values };
|
|
159
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
160
|
+
this.activePreset.set(panelId, presetId);
|
|
161
|
+
this.notify(panelId);
|
|
162
|
+
}
|
|
163
|
+
deletePreset(panelId, presetId) {
|
|
164
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
165
|
+
this.presets.set(panelId, presets.filter((p) => p.id !== presetId));
|
|
166
|
+
if (this.activePreset.get(panelId) === presetId) {
|
|
167
|
+
this.activePreset.set(panelId, null);
|
|
168
|
+
}
|
|
169
|
+
const panel = this.panels.get(panelId);
|
|
170
|
+
if (panel) {
|
|
171
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
172
|
+
}
|
|
173
|
+
this.notify(panelId);
|
|
174
|
+
}
|
|
175
|
+
getPresets(panelId) {
|
|
176
|
+
return this.presets.get(panelId) ?? [];
|
|
177
|
+
}
|
|
178
|
+
getActivePresetId(panelId) {
|
|
179
|
+
return this.activePreset.get(panelId) ?? null;
|
|
180
|
+
}
|
|
181
|
+
clearActivePreset(panelId) {
|
|
182
|
+
const panel = this.panels.get(panelId);
|
|
183
|
+
const base = this.baseValues.get(panelId);
|
|
184
|
+
if (panel && base) {
|
|
185
|
+
panel.values = { ...base };
|
|
186
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
187
|
+
}
|
|
188
|
+
this.activePreset.set(panelId, null);
|
|
189
|
+
this.notify(panelId);
|
|
190
|
+
}
|
|
120
191
|
notify(panelId) {
|
|
121
192
|
this.listeners.get(panelId)?.forEach((fn) => fn());
|
|
122
193
|
}
|
|
@@ -146,6 +217,18 @@ var DialStoreClass = class {
|
|
|
146
217
|
controls.push({ type: "spring", path, label });
|
|
147
218
|
} else if (this.isActionConfig(value)) {
|
|
148
219
|
controls.push({ type: "action", path, label: value.label || label });
|
|
220
|
+
} else if (this.isSelectConfig(value)) {
|
|
221
|
+
controls.push({ type: "select", path, label, options: value.options });
|
|
222
|
+
} else if (this.isColorConfig(value)) {
|
|
223
|
+
controls.push({ type: "color", path, label });
|
|
224
|
+
} else if (this.isTextConfig(value)) {
|
|
225
|
+
controls.push({ type: "text", path, label, placeholder: value.placeholder });
|
|
226
|
+
} else if (typeof value === "string") {
|
|
227
|
+
if (this.isHexColor(value)) {
|
|
228
|
+
controls.push({ type: "color", path, label });
|
|
229
|
+
} else {
|
|
230
|
+
controls.push({ type: "text", path, label });
|
|
231
|
+
}
|
|
149
232
|
} else if (typeof value === "object" && value !== null) {
|
|
150
233
|
controls.push({
|
|
151
234
|
type: "folder",
|
|
@@ -169,6 +252,14 @@ var DialStoreClass = class {
|
|
|
169
252
|
values[path] = value;
|
|
170
253
|
} else if (this.isActionConfig(value)) {
|
|
171
254
|
values[path] = value;
|
|
255
|
+
} else if (this.isSelectConfig(value)) {
|
|
256
|
+
const firstOption = value.options[0];
|
|
257
|
+
const firstValue = typeof firstOption === "string" ? firstOption : firstOption.value;
|
|
258
|
+
values[path] = value.default ?? firstValue;
|
|
259
|
+
} else if (this.isColorConfig(value)) {
|
|
260
|
+
values[path] = value.default ?? "#000000";
|
|
261
|
+
} else if (this.isTextConfig(value)) {
|
|
262
|
+
values[path] = value.default ?? "";
|
|
172
263
|
} else if (typeof value === "object" && value !== null) {
|
|
173
264
|
Object.assign(values, this.flattenValues(value, path));
|
|
174
265
|
}
|
|
@@ -181,6 +272,18 @@ var DialStoreClass = class {
|
|
|
181
272
|
isActionConfig(value) {
|
|
182
273
|
return typeof value === "object" && value !== null && "type" in value && value.type === "action";
|
|
183
274
|
}
|
|
275
|
+
isSelectConfig(value) {
|
|
276
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "select" && "options" in value && Array.isArray(value.options);
|
|
277
|
+
}
|
|
278
|
+
isColorConfig(value) {
|
|
279
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "color";
|
|
280
|
+
}
|
|
281
|
+
isTextConfig(value) {
|
|
282
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "text";
|
|
283
|
+
}
|
|
284
|
+
isHexColor(value) {
|
|
285
|
+
return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(value);
|
|
286
|
+
}
|
|
184
287
|
formatLabel(key) {
|
|
185
288
|
return key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
|
|
186
289
|
}
|
|
@@ -188,13 +291,13 @@ var DialStoreClass = class {
|
|
|
188
291
|
if (value >= 0 && value <= 1) {
|
|
189
292
|
return { min: 0, max: 1, step: 0.01 };
|
|
190
293
|
} else if (value >= 0 && value <= 10) {
|
|
191
|
-
return { min: 0, max: value *
|
|
294
|
+
return { min: 0, max: value * 3 || 10, step: 0.1 };
|
|
192
295
|
} else if (value >= 0 && value <= 100) {
|
|
193
|
-
return { min: 0, max: value *
|
|
296
|
+
return { min: 0, max: value * 3 || 100, step: 1 };
|
|
194
297
|
} else if (value >= 0) {
|
|
195
|
-
return { min: 0, max: value *
|
|
298
|
+
return { min: 0, max: value * 3 || 1e3, step: 10 };
|
|
196
299
|
} else {
|
|
197
|
-
return { min: value *
|
|
300
|
+
return { min: value * 3, max: -value * 3, step: 1 };
|
|
198
301
|
}
|
|
199
302
|
}
|
|
200
303
|
inferStep(min, max) {
|
|
@@ -240,204 +343,149 @@ function buildResolvedValues(config, flatValues, prefix) {
|
|
|
240
343
|
result[key] = flatValues[path] ?? configValue;
|
|
241
344
|
} else if (isSpringConfig(configValue)) {
|
|
242
345
|
result[key] = flatValues[path] ?? configValue;
|
|
346
|
+
} else if (isActionConfig(configValue)) {
|
|
347
|
+
result[key] = flatValues[path] ?? configValue;
|
|
348
|
+
} else if (isSelectConfig(configValue)) {
|
|
349
|
+
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
350
|
+
result[key] = flatValues[path] ?? defaultValue;
|
|
351
|
+
} else if (isColorConfig(configValue)) {
|
|
352
|
+
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
353
|
+
} else if (isTextConfig(configValue)) {
|
|
354
|
+
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
243
355
|
} else if (typeof configValue === "object" && configValue !== null) {
|
|
244
356
|
result[key] = buildResolvedValues(configValue, flatValues, path);
|
|
245
357
|
}
|
|
246
358
|
}
|
|
247
359
|
return result;
|
|
248
360
|
}
|
|
361
|
+
function hasType(value, type) {
|
|
362
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
363
|
+
}
|
|
249
364
|
function isSpringConfig(value) {
|
|
250
|
-
return
|
|
365
|
+
return hasType(value, "spring");
|
|
366
|
+
}
|
|
367
|
+
function isActionConfig(value) {
|
|
368
|
+
return hasType(value, "action");
|
|
369
|
+
}
|
|
370
|
+
function isSelectConfig(value) {
|
|
371
|
+
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
372
|
+
}
|
|
373
|
+
function isColorConfig(value) {
|
|
374
|
+
return hasType(value, "color");
|
|
375
|
+
}
|
|
376
|
+
function isTextConfig(value) {
|
|
377
|
+
return hasType(value, "text");
|
|
378
|
+
}
|
|
379
|
+
function getFirstOptionValue(options) {
|
|
380
|
+
const first = options[0];
|
|
381
|
+
return typeof first === "string" ? first : first.value;
|
|
251
382
|
}
|
|
252
383
|
|
|
253
384
|
// src/components/DialRoot.tsx
|
|
254
|
-
var
|
|
255
|
-
var
|
|
385
|
+
var import_react16 = require("react");
|
|
386
|
+
var import_react_dom2 = require("react-dom");
|
|
387
|
+
|
|
388
|
+
// src/components/Panel.tsx
|
|
389
|
+
var import_react14 = require("react");
|
|
390
|
+
var import_react15 = require("motion/react");
|
|
256
391
|
|
|
257
392
|
// src/components/Folder.tsx
|
|
258
393
|
var import_react2 = require("react");
|
|
259
394
|
var import_react3 = require("motion/react");
|
|
260
395
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
261
|
-
function Folder({ title, children, defaultOpen = true, isRoot = false,
|
|
396
|
+
function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenChange, toolbar }) {
|
|
262
397
|
const [isOpen, setIsOpen] = (0, import_react2.useState)(defaultOpen);
|
|
263
|
-
const [
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
398
|
+
const [isCollapsed, setIsCollapsed] = (0, import_react2.useState)(!defaultOpen);
|
|
399
|
+
const contentRef = (0, import_react2.useRef)(null);
|
|
400
|
+
const [contentHeight, setContentHeight] = (0, import_react2.useState)(void 0);
|
|
401
|
+
(0, import_react2.useEffect)(() => {
|
|
402
|
+
const el = contentRef.current;
|
|
403
|
+
if (!el) return;
|
|
404
|
+
const ro = new ResizeObserver(() => {
|
|
405
|
+
if (isOpen) {
|
|
406
|
+
const h = el.offsetHeight;
|
|
407
|
+
setContentHeight((prev) => prev === h ? prev : h);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
ro.observe(el);
|
|
411
|
+
return () => ro.disconnect();
|
|
412
|
+
}, [isOpen]);
|
|
413
|
+
const handleToggle = () => {
|
|
414
|
+
const next = !isOpen;
|
|
415
|
+
setIsOpen(next);
|
|
416
|
+
if (next) {
|
|
417
|
+
setIsCollapsed(false);
|
|
418
|
+
} else {
|
|
419
|
+
setIsCollapsed(true);
|
|
420
|
+
}
|
|
421
|
+
onOpenChange?.(next);
|
|
279
422
|
};
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
className: "dialkit-folder-copy",
|
|
289
|
-
onClick: handleCopy,
|
|
290
|
-
title: "Copy parameters",
|
|
291
|
-
initial: false,
|
|
292
|
-
animate: {
|
|
293
|
-
opacity: isOpen ? 1 : 0,
|
|
294
|
-
scale: isOpen ? 1 : 0.7,
|
|
295
|
-
filter: isOpen ? "blur(0px)" : "blur(6px)"
|
|
296
|
-
},
|
|
297
|
-
transition: iconTransition,
|
|
298
|
-
style: { pointerEvents: isOpen ? "auto" : "none" },
|
|
299
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative", width: 14, height: 14 }, children: [
|
|
300
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
301
|
-
import_react3.motion.svg,
|
|
302
|
-
{
|
|
303
|
-
viewBox: "0 0 24 24",
|
|
304
|
-
fill: "none",
|
|
305
|
-
stroke: "currentColor",
|
|
306
|
-
strokeWidth: "2",
|
|
307
|
-
strokeLinecap: "round",
|
|
308
|
-
strokeLinejoin: "round",
|
|
309
|
-
style: { position: "absolute", inset: 0 },
|
|
310
|
-
initial: false,
|
|
311
|
-
animate: {
|
|
312
|
-
opacity: copied ? 0 : 1,
|
|
313
|
-
scale: copied ? 0.7 : 1,
|
|
314
|
-
filter: copied ? "blur(6px)" : "blur(0px)"
|
|
315
|
-
},
|
|
316
|
-
transition: iconTransition,
|
|
317
|
-
children: [
|
|
318
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
319
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
320
|
-
]
|
|
321
|
-
}
|
|
322
|
-
),
|
|
323
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
324
|
-
import_react3.motion.svg,
|
|
325
|
-
{
|
|
326
|
-
viewBox: "0 0 24 24",
|
|
327
|
-
fill: "none",
|
|
328
|
-
stroke: "currentColor",
|
|
329
|
-
strokeWidth: "2",
|
|
330
|
-
strokeLinecap: "round",
|
|
331
|
-
strokeLinejoin: "round",
|
|
332
|
-
style: { position: "absolute", inset: 0 },
|
|
333
|
-
initial: false,
|
|
334
|
-
animate: {
|
|
335
|
-
opacity: copied ? 1 : 0,
|
|
336
|
-
scale: copied ? 1 : 0.7,
|
|
337
|
-
filter: copied ? "blur(0px)" : "blur(6px)"
|
|
338
|
-
},
|
|
339
|
-
transition: iconTransition,
|
|
340
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "20 6 9 17 4 12" })
|
|
341
|
-
}
|
|
342
|
-
)
|
|
343
|
-
] })
|
|
344
|
-
}
|
|
345
|
-
)
|
|
346
|
-
] }),
|
|
347
|
-
isRoot ? (
|
|
348
|
-
// Root panel uses minus/plus icons with crossfade
|
|
349
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dialkit-folder-icon", style: { position: "relative" }, children: [
|
|
350
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
351
|
-
import_react3.motion.svg,
|
|
423
|
+
const folderContent = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: isRoot ? contentRef : void 0, className: `dialkit-folder ${isRoot ? "dialkit-folder-root" : ""}`, children: [
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
|
|
425
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dialkit-folder-header-top", children: [
|
|
426
|
+
isRoot ? isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dialkit-folder-title dialkit-folder-title-root", children: title }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dialkit-folder-title", children: title }) }),
|
|
427
|
+
isRoot ? (
|
|
428
|
+
// Root panel icon — fixed position, container morphs around it
|
|
429
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
430
|
+
"svg",
|
|
352
431
|
{
|
|
353
|
-
|
|
432
|
+
className: "dialkit-panel-icon",
|
|
433
|
+
viewBox: "0 0 16 16",
|
|
354
434
|
fill: "none",
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
animate: {
|
|
362
|
-
opacity: isOpen ? 1 : 0,
|
|
363
|
-
scale: isOpen ? 1 : 0.7,
|
|
364
|
-
filter: isOpen ? "blur(0px)" : "blur(6px)"
|
|
365
|
-
},
|
|
366
|
-
transition: iconTransition,
|
|
367
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
435
|
+
children: [
|
|
436
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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" }),
|
|
437
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "8", r: "0.998596", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
|
|
438
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "10.4999", cy: "3.5", r: "0.998657", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }),
|
|
439
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9.75015", cy: "12.5", r: "0.997986", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" })
|
|
440
|
+
]
|
|
368
441
|
}
|
|
369
|
-
)
|
|
370
|
-
|
|
442
|
+
)
|
|
443
|
+
) : (
|
|
444
|
+
// Section folders use rotating chevron with gentle spring
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
371
446
|
import_react3.motion.svg,
|
|
372
447
|
{
|
|
448
|
+
className: "dialkit-folder-icon",
|
|
373
449
|
viewBox: "0 0 24 24",
|
|
374
450
|
fill: "none",
|
|
375
451
|
stroke: "currentColor",
|
|
376
|
-
strokeWidth: "2",
|
|
452
|
+
strokeWidth: "2.5",
|
|
377
453
|
strokeLinecap: "round",
|
|
378
454
|
strokeLinejoin: "round",
|
|
379
|
-
style: { position: "absolute", inset: 0, width: "100%", height: "100%" },
|
|
380
455
|
initial: false,
|
|
381
|
-
animate: {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
filter: isOpen ? "blur(6px)" : "blur(0px)"
|
|
385
|
-
},
|
|
386
|
-
transition: iconTransition,
|
|
387
|
-
children: [
|
|
388
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
389
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
390
|
-
]
|
|
456
|
+
animate: { rotate: isOpen ? 0 : 180 },
|
|
457
|
+
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
458
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
391
459
|
}
|
|
392
460
|
)
|
|
393
|
-
] })
|
|
394
|
-
) : (
|
|
395
|
-
// Section folders use rotating chevron with gentle spring
|
|
396
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
397
|
-
import_react3.motion.svg,
|
|
398
|
-
{
|
|
399
|
-
className: "dialkit-folder-icon",
|
|
400
|
-
viewBox: "0 0 24 24",
|
|
401
|
-
fill: "none",
|
|
402
|
-
stroke: "currentColor",
|
|
403
|
-
strokeWidth: "1.5",
|
|
404
|
-
strokeLinecap: "round",
|
|
405
|
-
strokeLinejoin: "round",
|
|
406
|
-
initial: false,
|
|
407
|
-
animate: { rotate: isOpen ? 0 : 180 },
|
|
408
|
-
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
409
|
-
children: [
|
|
410
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "5", y1: "9", x2: "12", y2: "16" }),
|
|
411
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "19", y1: "9", x2: "12", y2: "16" })
|
|
412
|
-
]
|
|
413
|
-
}
|
|
414
461
|
)
|
|
415
|
-
)
|
|
462
|
+
] }),
|
|
463
|
+
isRoot && toolbar && isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
416
464
|
] }),
|
|
417
465
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react3.AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
418
466
|
import_react3.motion.div,
|
|
419
467
|
{
|
|
420
468
|
className: "dialkit-folder-content",
|
|
421
|
-
initial: { height: 0, opacity: 0 },
|
|
422
|
-
animate: { height: "auto", opacity: 1 },
|
|
423
|
-
exit: { height: 0, opacity: 0 },
|
|
424
|
-
transition: { type: "spring", visualDuration: 0.
|
|
469
|
+
initial: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
470
|
+
animate: isRoot ? void 0 : { height: "auto", opacity: 1 },
|
|
471
|
+
exit: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
472
|
+
transition: isRoot ? void 0 : { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
473
|
+
style: isRoot ? void 0 : { clipPath: "inset(0 -20px)" },
|
|
425
474
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dialkit-folder-inner", children })
|
|
426
475
|
}
|
|
427
476
|
) })
|
|
428
477
|
] });
|
|
429
478
|
if (isRoot) {
|
|
479
|
+
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" };
|
|
430
480
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
431
481
|
import_react3.motion.div,
|
|
432
482
|
{
|
|
433
483
|
className: "dialkit-panel-inner",
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
},
|
|
439
|
-
transition: { type: "spring", visualDuration: 0.4, bounce: 0.05 },
|
|
440
|
-
"data-collapsed": !isOpen,
|
|
484
|
+
style: panelStyle,
|
|
485
|
+
onClick: !isOpen ? handleToggle : void 0,
|
|
486
|
+
"data-collapsed": isCollapsed,
|
|
487
|
+
whileTap: !isOpen ? { scale: 0.9 } : void 0,
|
|
488
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
441
489
|
children: folderContent
|
|
442
490
|
}
|
|
443
491
|
);
|
|
@@ -449,6 +497,23 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
449
497
|
var import_react4 = require("react");
|
|
450
498
|
var import_react5 = require("motion/react");
|
|
451
499
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
500
|
+
var CLICK_THRESHOLD = 3;
|
|
501
|
+
var DEAD_ZONE = 32;
|
|
502
|
+
var MAX_CURSOR_RANGE = 200;
|
|
503
|
+
var MAX_STRETCH = 8;
|
|
504
|
+
function roundValue(val, step) {
|
|
505
|
+
const decimals = step >= 1 ? 0 : 2;
|
|
506
|
+
const factor = 10 ** decimals;
|
|
507
|
+
return Math.round(val * factor) / factor;
|
|
508
|
+
}
|
|
509
|
+
function snapToDecile(rawValue, min, max) {
|
|
510
|
+
const normalized = (rawValue - min) / (max - min);
|
|
511
|
+
const nearest = Math.round(normalized * 10) / 10;
|
|
512
|
+
if (Math.abs(normalized - nearest) <= 0.03125) {
|
|
513
|
+
return min + nearest * (max - min);
|
|
514
|
+
}
|
|
515
|
+
return rawValue;
|
|
516
|
+
}
|
|
452
517
|
function Slider({
|
|
453
518
|
label,
|
|
454
519
|
value,
|
|
@@ -458,8 +523,11 @@ function Slider({
|
|
|
458
523
|
step = 0.01,
|
|
459
524
|
unit
|
|
460
525
|
}) {
|
|
526
|
+
const wrapperRef = (0, import_react4.useRef)(null);
|
|
461
527
|
const trackRef = (0, import_react4.useRef)(null);
|
|
462
528
|
const inputRef = (0, import_react4.useRef)(null);
|
|
529
|
+
const labelRef = (0, import_react4.useRef)(null);
|
|
530
|
+
const valueSpanRef = (0, import_react4.useRef)(null);
|
|
463
531
|
const [isInteracting, setIsInteracting] = (0, import_react4.useState)(false);
|
|
464
532
|
const [isDragging, setIsDragging] = (0, import_react4.useState)(false);
|
|
465
533
|
const [isHovered, setIsHovered] = (0, import_react4.useState)(false);
|
|
@@ -468,78 +536,160 @@ function Slider({
|
|
|
468
536
|
const [showInput, setShowInput] = (0, import_react4.useState)(false);
|
|
469
537
|
const [inputValue, setInputValue] = (0, import_react4.useState)("");
|
|
470
538
|
const hoverTimeoutRef = (0, import_react4.useRef)(null);
|
|
539
|
+
const pointerDownPos = (0, import_react4.useRef)(null);
|
|
540
|
+
const isClickRef = (0, import_react4.useRef)(true);
|
|
541
|
+
const animRef = (0, import_react4.useRef)(null);
|
|
542
|
+
const wrapperRectRef = (0, import_react4.useRef)(null);
|
|
543
|
+
const scaleRef = (0, import_react4.useRef)(1);
|
|
471
544
|
const percentage = (value - min) / (max - min) * 100;
|
|
472
|
-
const isAtMinimum = value <= min;
|
|
473
545
|
const isActive = isInteracting || isHovered;
|
|
546
|
+
const fillPercent = (0, import_react5.useMotionValue)(percentage);
|
|
547
|
+
const fillWidth = (0, import_react5.useTransform)(fillPercent, (pct) => `${pct}%`);
|
|
548
|
+
const handleLeft = (0, import_react5.useTransform)(
|
|
549
|
+
fillPercent,
|
|
550
|
+
(pct) => `max(5px, calc(${pct}% - 9px))`
|
|
551
|
+
);
|
|
552
|
+
const rubberStretchPx = (0, import_react5.useMotionValue)(0);
|
|
553
|
+
const rubberBandWidth = (0, import_react5.useTransform)(
|
|
554
|
+
rubberStretchPx,
|
|
555
|
+
(stretch) => `calc(100% + ${Math.abs(stretch)}px)`
|
|
556
|
+
);
|
|
557
|
+
const rubberBandX = (0, import_react5.useTransform)(
|
|
558
|
+
rubberStretchPx,
|
|
559
|
+
(stretch) => stretch < 0 ? stretch : 0
|
|
560
|
+
);
|
|
561
|
+
(0, import_react4.useEffect)(() => {
|
|
562
|
+
if (!isInteracting && !animRef.current) {
|
|
563
|
+
fillPercent.jump(percentage);
|
|
564
|
+
}
|
|
565
|
+
}, [percentage, isInteracting, fillPercent]);
|
|
474
566
|
const positionToValue = (0, import_react4.useCallback)(
|
|
475
567
|
(clientX) => {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
const
|
|
479
|
-
const
|
|
568
|
+
const rect = wrapperRectRef.current;
|
|
569
|
+
if (!rect) return value;
|
|
570
|
+
const screenX = clientX - rect.left;
|
|
571
|
+
const sceneX = screenX / scaleRef.current;
|
|
572
|
+
const nativeWidth = wrapperRef.current ? wrapperRef.current.offsetWidth : rect.width;
|
|
573
|
+
const percent = Math.max(0, Math.min(1, sceneX / nativeWidth));
|
|
480
574
|
const rawValue = min + percent * (max - min);
|
|
481
575
|
return Math.max(min, Math.min(max, rawValue));
|
|
482
576
|
},
|
|
483
577
|
[min, max, value]
|
|
484
578
|
);
|
|
485
|
-
const
|
|
486
|
-
(
|
|
487
|
-
|
|
488
|
-
e.preventDefault();
|
|
489
|
-
setIsInteracting(true);
|
|
490
|
-
onChange(positionToValue(e.clientX));
|
|
491
|
-
},
|
|
492
|
-
[positionToValue, onChange, showInput]
|
|
579
|
+
const percentFromValue = (0, import_react4.useCallback)(
|
|
580
|
+
(v) => (v - min) / (max - min) * 100,
|
|
581
|
+
[min, max]
|
|
493
582
|
);
|
|
494
|
-
const
|
|
495
|
-
(
|
|
496
|
-
|
|
497
|
-
if (!
|
|
498
|
-
|
|
583
|
+
const computeRubberStretch = (0, import_react4.useCallback)(
|
|
584
|
+
(clientX, sign) => {
|
|
585
|
+
const rect = wrapperRectRef.current;
|
|
586
|
+
if (!rect) return 0;
|
|
587
|
+
const distancePast = sign < 0 ? rect.left - clientX : clientX - rect.right;
|
|
588
|
+
const overflow = Math.max(0, distancePast - DEAD_ZONE);
|
|
589
|
+
return sign * MAX_STRETCH * Math.sqrt(Math.min(overflow / MAX_CURSOR_RANGE, 1));
|
|
499
590
|
},
|
|
500
|
-
[
|
|
591
|
+
[]
|
|
501
592
|
);
|
|
502
|
-
const
|
|
503
|
-
setIsInteracting(false);
|
|
504
|
-
setIsDragging(false);
|
|
505
|
-
}, []);
|
|
506
|
-
const handleTouchStart = (0, import_react4.useCallback)(
|
|
593
|
+
const handlePointerDown = (0, import_react4.useCallback)(
|
|
507
594
|
(e) => {
|
|
508
595
|
if (showInput) return;
|
|
509
596
|
e.preventDefault();
|
|
597
|
+
e.target.setPointerCapture(e.pointerId);
|
|
598
|
+
pointerDownPos.current = { x: e.clientX, y: e.clientY };
|
|
599
|
+
isClickRef.current = true;
|
|
510
600
|
setIsInteracting(true);
|
|
511
|
-
|
|
512
|
-
|
|
601
|
+
if (wrapperRef.current) {
|
|
602
|
+
wrapperRectRef.current = wrapperRef.current.getBoundingClientRect();
|
|
603
|
+
const nativeWidth = wrapperRef.current.offsetWidth;
|
|
604
|
+
scaleRef.current = wrapperRectRef.current.width / nativeWidth;
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
[showInput]
|
|
608
|
+
);
|
|
609
|
+
const handlePointerMove = (0, import_react4.useCallback)(
|
|
610
|
+
(e) => {
|
|
611
|
+
if (!isInteracting || !pointerDownPos.current) return;
|
|
612
|
+
const dx = e.clientX - pointerDownPos.current.x;
|
|
613
|
+
const dy = e.clientY - pointerDownPos.current.y;
|
|
614
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
615
|
+
if (isClickRef.current && distance > CLICK_THRESHOLD) {
|
|
616
|
+
isClickRef.current = false;
|
|
617
|
+
setIsDragging(true);
|
|
618
|
+
}
|
|
619
|
+
if (!isClickRef.current) {
|
|
620
|
+
const rect = wrapperRectRef.current;
|
|
621
|
+
if (rect) {
|
|
622
|
+
if (e.clientX < rect.left) {
|
|
623
|
+
rubberStretchPx.jump(computeRubberStretch(e.clientX, -1));
|
|
624
|
+
} else if (e.clientX > rect.right) {
|
|
625
|
+
rubberStretchPx.jump(computeRubberStretch(e.clientX, 1));
|
|
626
|
+
} else {
|
|
627
|
+
rubberStretchPx.jump(0);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const newValue = positionToValue(e.clientX);
|
|
631
|
+
const newPct = percentFromValue(newValue);
|
|
632
|
+
if (animRef.current) {
|
|
633
|
+
animRef.current.stop();
|
|
634
|
+
animRef.current = null;
|
|
635
|
+
}
|
|
636
|
+
fillPercent.jump(newPct);
|
|
637
|
+
onChange(roundValue(newValue, step));
|
|
638
|
+
}
|
|
513
639
|
},
|
|
514
|
-
[
|
|
640
|
+
[
|
|
641
|
+
isInteracting,
|
|
642
|
+
positionToValue,
|
|
643
|
+
percentFromValue,
|
|
644
|
+
onChange,
|
|
645
|
+
fillPercent,
|
|
646
|
+
rubberStretchPx,
|
|
647
|
+
computeRubberStretch
|
|
648
|
+
]
|
|
515
649
|
);
|
|
516
|
-
const
|
|
650
|
+
const handlePointerUp = (0, import_react4.useCallback)(
|
|
517
651
|
(e) => {
|
|
518
652
|
if (!isInteracting) return;
|
|
519
|
-
if (
|
|
520
|
-
|
|
521
|
-
|
|
653
|
+
if (isClickRef.current) {
|
|
654
|
+
const rawValue = positionToValue(e.clientX);
|
|
655
|
+
const snappedValue = snapToDecile(rawValue, min, max);
|
|
656
|
+
const newPct = percentFromValue(snappedValue);
|
|
657
|
+
if (animRef.current) {
|
|
658
|
+
animRef.current.stop();
|
|
659
|
+
}
|
|
660
|
+
animRef.current = (0, import_react5.animate)(fillPercent, newPct, {
|
|
661
|
+
type: "spring",
|
|
662
|
+
stiffness: 300,
|
|
663
|
+
damping: 25,
|
|
664
|
+
mass: 0.8,
|
|
665
|
+
onComplete: () => {
|
|
666
|
+
animRef.current = null;
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
onChange(roundValue(snappedValue, step));
|
|
670
|
+
}
|
|
671
|
+
if (rubberStretchPx.get() !== 0) {
|
|
672
|
+
(0, import_react5.animate)(rubberStretchPx, 0, {
|
|
673
|
+
type: "spring",
|
|
674
|
+
visualDuration: 0.35,
|
|
675
|
+
bounce: 0.15
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
setIsInteracting(false);
|
|
679
|
+
setIsDragging(false);
|
|
680
|
+
pointerDownPos.current = null;
|
|
522
681
|
},
|
|
523
|
-
[
|
|
682
|
+
[
|
|
683
|
+
isInteracting,
|
|
684
|
+
positionToValue,
|
|
685
|
+
percentFromValue,
|
|
686
|
+
onChange,
|
|
687
|
+
min,
|
|
688
|
+
max,
|
|
689
|
+
fillPercent,
|
|
690
|
+
rubberStretchPx
|
|
691
|
+
]
|
|
524
692
|
);
|
|
525
|
-
const handleTouchEnd = (0, import_react4.useCallback)(() => {
|
|
526
|
-
setIsInteracting(false);
|
|
527
|
-
setIsDragging(false);
|
|
528
|
-
}, []);
|
|
529
|
-
(0, import_react4.useEffect)(() => {
|
|
530
|
-
if (isInteracting) {
|
|
531
|
-
document.addEventListener("mousemove", handleMouseMove);
|
|
532
|
-
document.addEventListener("mouseup", handleMouseUp);
|
|
533
|
-
document.addEventListener("touchmove", handleTouchMove, { passive: false });
|
|
534
|
-
document.addEventListener("touchend", handleTouchEnd);
|
|
535
|
-
return () => {
|
|
536
|
-
document.removeEventListener("mousemove", handleMouseMove);
|
|
537
|
-
document.removeEventListener("mouseup", handleMouseUp);
|
|
538
|
-
document.removeEventListener("touchmove", handleTouchMove);
|
|
539
|
-
document.removeEventListener("touchend", handleTouchEnd);
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
}, [isInteracting, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
|
|
543
693
|
(0, import_react4.useEffect)(() => {
|
|
544
694
|
if (isValueHovered && !showInput && !isValueEditable) {
|
|
545
695
|
hoverTimeoutRef.current = setTimeout(() => {
|
|
@@ -571,7 +721,7 @@ function Slider({
|
|
|
571
721
|
const parsed = parseFloat(inputValue);
|
|
572
722
|
if (!isNaN(parsed)) {
|
|
573
723
|
const clamped = Math.max(min, Math.min(max, parsed));
|
|
574
|
-
onChange(clamped);
|
|
724
|
+
onChange(roundValue(clamped, step));
|
|
575
725
|
}
|
|
576
726
|
setShowInput(false);
|
|
577
727
|
setIsValueHovered(false);
|
|
@@ -597,29 +747,56 @@ function Slider({
|
|
|
597
747
|
handleInputSubmit();
|
|
598
748
|
};
|
|
599
749
|
const displayValue = step >= 1 ? value.toFixed(0) : value.toFixed(2);
|
|
600
|
-
const
|
|
601
|
-
const
|
|
602
|
-
const
|
|
750
|
+
const HANDLE_BUFFER = 8;
|
|
751
|
+
const LABEL_CSS_LEFT = 10;
|
|
752
|
+
const VALUE_CSS_RIGHT = 10;
|
|
753
|
+
let leftThreshold = 30;
|
|
754
|
+
let rightThreshold = 78;
|
|
755
|
+
const trackWidth = wrapperRef.current?.offsetWidth;
|
|
756
|
+
if (trackWidth && trackWidth > 0) {
|
|
757
|
+
if (labelRef.current) {
|
|
758
|
+
leftThreshold = (LABEL_CSS_LEFT + labelRef.current.offsetWidth + HANDLE_BUFFER) / trackWidth * 100;
|
|
759
|
+
}
|
|
760
|
+
if (valueSpanRef.current) {
|
|
761
|
+
rightThreshold = (trackWidth - VALUE_CSS_RIGHT - valueSpanRef.current.offsetWidth - HANDLE_BUFFER) / trackWidth * 100;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const valueDodge = percentage < leftThreshold || percentage > rightThreshold;
|
|
765
|
+
const handleOpacity = !isActive ? 0 : valueDodge ? 0.1 : isDragging ? 0.9 : 0.5;
|
|
603
766
|
const fillBackground = isActive ? "rgba(255, 255, 255, 0.15)" : "rgba(255, 255, 255, 0.11)";
|
|
604
|
-
const hashMarks = Array.from({ length:
|
|
605
|
-
|
|
606
|
-
|
|
767
|
+
const hashMarks = Array.from({ length: 9 }, (_, i) => {
|
|
768
|
+
const pct = (i + 1) * 10;
|
|
769
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
770
|
+
"div",
|
|
771
|
+
{
|
|
772
|
+
className: "dialkit-slider-hashmark",
|
|
773
|
+
style: { left: `${pct}%` }
|
|
774
|
+
},
|
|
775
|
+
i
|
|
776
|
+
);
|
|
777
|
+
});
|
|
778
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: wrapperRef, className: "dialkit-slider-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
779
|
+
import_react5.motion.div,
|
|
607
780
|
{
|
|
608
781
|
ref: trackRef,
|
|
609
782
|
className: `dialkit-slider ${isActive ? "dialkit-slider-active" : ""}`,
|
|
610
|
-
|
|
611
|
-
|
|
783
|
+
onPointerDown: handlePointerDown,
|
|
784
|
+
onPointerMove: handlePointerMove,
|
|
785
|
+
onPointerUp: handlePointerUp,
|
|
612
786
|
onMouseEnter: () => setIsHovered(true),
|
|
613
787
|
onMouseLeave: () => setIsHovered(false),
|
|
788
|
+
style: { width: rubberBandWidth, x: rubberBandX },
|
|
614
789
|
children: [
|
|
615
790
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dialkit-slider-hashmarks", children: hashMarks }),
|
|
616
791
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
617
792
|
import_react5.motion.div,
|
|
618
793
|
{
|
|
619
794
|
className: "dialkit-slider-fill",
|
|
620
|
-
style: {
|
|
621
|
-
|
|
622
|
-
|
|
795
|
+
style: {
|
|
796
|
+
background: fillBackground,
|
|
797
|
+
width: fillWidth,
|
|
798
|
+
transition: "background 0.15s"
|
|
799
|
+
}
|
|
623
800
|
}
|
|
624
801
|
),
|
|
625
802
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -627,15 +804,23 @@ function Slider({
|
|
|
627
804
|
{
|
|
628
805
|
className: "dialkit-slider-handle",
|
|
629
806
|
style: {
|
|
630
|
-
background: isInteracting ? "rgba(255, 255, 255, 1)" : "rgba(255, 255, 255, 0.5)",
|
|
631
807
|
left: handleLeft,
|
|
632
|
-
|
|
808
|
+
y: "-50%",
|
|
809
|
+
background: "rgba(255, 255, 255, 0.9)"
|
|
810
|
+
},
|
|
811
|
+
animate: {
|
|
812
|
+
opacity: handleOpacity,
|
|
813
|
+
scaleX: isActive ? 1 : 0.25,
|
|
814
|
+
scaleY: isActive && valueDodge ? 0.75 : 1
|
|
633
815
|
},
|
|
634
|
-
|
|
635
|
-
|
|
816
|
+
transition: {
|
|
817
|
+
scaleX: { type: "spring", visualDuration: 0.25, bounce: 0.15 },
|
|
818
|
+
scaleY: { type: "spring", visualDuration: 0.2, bounce: 0.1 },
|
|
819
|
+
opacity: { duration: 0.15 }
|
|
820
|
+
}
|
|
636
821
|
}
|
|
637
822
|
),
|
|
638
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dialkit-slider-label", children: label }),
|
|
823
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { ref: labelRef, className: "dialkit-slider-label", children: label }),
|
|
639
824
|
showInput ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
640
825
|
"input",
|
|
641
826
|
{
|
|
@@ -649,24 +834,22 @@ function Slider({
|
|
|
649
834
|
onClick: (e) => e.stopPropagation(),
|
|
650
835
|
onMouseDown: (e) => e.stopPropagation()
|
|
651
836
|
}
|
|
652
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
837
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
653
838
|
"span",
|
|
654
839
|
{
|
|
840
|
+
ref: valueSpanRef,
|
|
655
841
|
className: `dialkit-slider-value ${isValueEditable ? "dialkit-slider-value-editable" : ""}`,
|
|
656
842
|
onMouseEnter: () => setIsValueHovered(true),
|
|
657
843
|
onMouseLeave: () => setIsValueHovered(false),
|
|
658
844
|
onClick: handleValueClick,
|
|
659
845
|
onMouseDown: (e) => isValueEditable && e.stopPropagation(),
|
|
660
846
|
style: { cursor: isValueEditable ? "text" : "default" },
|
|
661
|
-
children:
|
|
662
|
-
displayValue,
|
|
663
|
-
unit
|
|
664
|
-
]
|
|
847
|
+
children: displayValue
|
|
665
848
|
}
|
|
666
849
|
)
|
|
667
850
|
]
|
|
668
851
|
}
|
|
669
|
-
);
|
|
852
|
+
) });
|
|
670
853
|
}
|
|
671
854
|
|
|
672
855
|
// src/components/SegmentedControl.tsx
|
|
@@ -951,20 +1134,352 @@ function SpringControl({ panelId, path, label, spring, onChange }) {
|
|
|
951
1134
|
] }) });
|
|
952
1135
|
}
|
|
953
1136
|
|
|
954
|
-
// src/components/
|
|
955
|
-
var import_react9 = require("react");
|
|
1137
|
+
// src/components/TextControl.tsx
|
|
956
1138
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1139
|
+
function TextControl({ label, value, onChange, placeholder }) {
|
|
1140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dialkit-text-control", children: [
|
|
1141
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "dialkit-text-label", children: label }),
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1143
|
+
"input",
|
|
1144
|
+
{
|
|
1145
|
+
type: "text",
|
|
1146
|
+
className: "dialkit-text-input",
|
|
1147
|
+
value,
|
|
1148
|
+
onChange: (e) => onChange(e.target.value),
|
|
1149
|
+
placeholder
|
|
1150
|
+
}
|
|
1151
|
+
)
|
|
1152
|
+
] });
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// src/components/SelectControl.tsx
|
|
1156
|
+
var import_react9 = require("react");
|
|
1157
|
+
var import_react10 = require("motion/react");
|
|
1158
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1159
|
+
function toTitleCase(s) {
|
|
1160
|
+
return s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1161
|
+
}
|
|
1162
|
+
function normalizeOptions(options) {
|
|
1163
|
+
return options.map(
|
|
1164
|
+
(opt) => typeof opt === "string" ? { value: opt, label: toTitleCase(opt) } : opt
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
function SelectControl({ label, value, options, onChange }) {
|
|
1168
|
+
const [isOpen, setIsOpen] = (0, import_react9.useState)(false);
|
|
1169
|
+
const containerRef = (0, import_react9.useRef)(null);
|
|
1170
|
+
const normalized = normalizeOptions(options);
|
|
1171
|
+
const selectedOption = normalized.find((o) => o.value === value);
|
|
1172
|
+
(0, import_react9.useEffect)(() => {
|
|
1173
|
+
if (!isOpen) return;
|
|
1174
|
+
const handleClick = (e) => {
|
|
1175
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
1176
|
+
setIsOpen(false);
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
document.addEventListener("mousedown", handleClick);
|
|
1180
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1181
|
+
}, [isOpen]);
|
|
1182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ref: containerRef, className: "dialkit-select-row", children: [
|
|
1183
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1184
|
+
"button",
|
|
1185
|
+
{
|
|
1186
|
+
className: "dialkit-select-trigger",
|
|
1187
|
+
onClick: () => setIsOpen(!isOpen),
|
|
1188
|
+
"data-open": String(isOpen),
|
|
1189
|
+
children: [
|
|
1190
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dialkit-select-label", children: label }),
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dialkit-select-right", children: [
|
|
1192
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dialkit-select-value", children: selectedOption?.label ?? value }),
|
|
1193
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1194
|
+
import_react10.motion.svg,
|
|
1195
|
+
{
|
|
1196
|
+
className: "dialkit-select-chevron",
|
|
1197
|
+
viewBox: "0 0 24 24",
|
|
1198
|
+
fill: "none",
|
|
1199
|
+
stroke: "currentColor",
|
|
1200
|
+
strokeWidth: "2.5",
|
|
1201
|
+
strokeLinecap: "round",
|
|
1202
|
+
strokeLinejoin: "round",
|
|
1203
|
+
animate: { rotate: isOpen ? 180 : 0 },
|
|
1204
|
+
transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
|
|
1205
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
1206
|
+
}
|
|
1207
|
+
)
|
|
1208
|
+
] })
|
|
1209
|
+
]
|
|
1210
|
+
}
|
|
1211
|
+
),
|
|
1212
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react10.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1213
|
+
import_react10.motion.div,
|
|
1214
|
+
{
|
|
1215
|
+
className: "dialkit-select-dropdown",
|
|
1216
|
+
initial: { opacity: 0, y: -8, scale: 0.95 },
|
|
1217
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1218
|
+
exit: { opacity: 0, y: -8, scale: 0.95 },
|
|
1219
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1220
|
+
children: normalized.map((option) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1221
|
+
"button",
|
|
1222
|
+
{
|
|
1223
|
+
className: "dialkit-select-option",
|
|
1224
|
+
"data-selected": String(option.value === value),
|
|
1225
|
+
onClick: () => {
|
|
1226
|
+
onChange(option.value);
|
|
1227
|
+
setIsOpen(false);
|
|
1228
|
+
},
|
|
1229
|
+
children: option.label
|
|
1230
|
+
},
|
|
1231
|
+
option.value
|
|
1232
|
+
))
|
|
1233
|
+
}
|
|
1234
|
+
) })
|
|
1235
|
+
] });
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// src/components/ColorControl.tsx
|
|
1239
|
+
var import_react11 = require("react");
|
|
1240
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1241
|
+
var HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
1242
|
+
function ColorControl({ label, value, onChange }) {
|
|
1243
|
+
const [isEditing, setIsEditing] = (0, import_react11.useState)(false);
|
|
1244
|
+
const [editValue, setEditValue] = (0, import_react11.useState)(value);
|
|
1245
|
+
const colorInputRef = (0, import_react11.useRef)(null);
|
|
1246
|
+
(0, import_react11.useEffect)(() => {
|
|
1247
|
+
if (!isEditing) {
|
|
1248
|
+
setEditValue(value);
|
|
1249
|
+
}
|
|
1250
|
+
}, [value, isEditing]);
|
|
1251
|
+
function handleTextSubmit() {
|
|
1252
|
+
setIsEditing(false);
|
|
1253
|
+
if (HEX_COLOR_REGEX.test(editValue)) {
|
|
1254
|
+
onChange(editValue);
|
|
1255
|
+
} else {
|
|
1256
|
+
setEditValue(value);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
function handleKeyDown(e) {
|
|
1260
|
+
if (e.key === "Enter") {
|
|
1261
|
+
handleTextSubmit();
|
|
1262
|
+
} else if (e.key === "Escape") {
|
|
1263
|
+
setIsEditing(false);
|
|
1264
|
+
setEditValue(value);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dialkit-color-control", children: [
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dialkit-color-label", children: label }),
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dialkit-color-inputs", children: [
|
|
1270
|
+
isEditing ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1271
|
+
"input",
|
|
1272
|
+
{
|
|
1273
|
+
type: "text",
|
|
1274
|
+
className: "dialkit-color-hex-input",
|
|
1275
|
+
value: editValue,
|
|
1276
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
1277
|
+
onBlur: handleTextSubmit,
|
|
1278
|
+
onKeyDown: handleKeyDown,
|
|
1279
|
+
autoFocus: true
|
|
1280
|
+
}
|
|
1281
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1282
|
+
"span",
|
|
1283
|
+
{
|
|
1284
|
+
className: "dialkit-color-hex",
|
|
1285
|
+
onClick: () => setIsEditing(true),
|
|
1286
|
+
children: (value ?? "").toUpperCase()
|
|
1287
|
+
}
|
|
1288
|
+
),
|
|
1289
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1290
|
+
"button",
|
|
1291
|
+
{
|
|
1292
|
+
className: "dialkit-color-swatch",
|
|
1293
|
+
style: { backgroundColor: value },
|
|
1294
|
+
onClick: () => colorInputRef.current?.click(),
|
|
1295
|
+
title: "Pick color"
|
|
1296
|
+
}
|
|
1297
|
+
),
|
|
1298
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1299
|
+
"input",
|
|
1300
|
+
{
|
|
1301
|
+
ref: colorInputRef,
|
|
1302
|
+
type: "color",
|
|
1303
|
+
className: "dialkit-color-picker-native",
|
|
1304
|
+
value: value.length === 4 ? expandShorthandHex(value) : value.slice(0, 7),
|
|
1305
|
+
onChange: (e) => onChange(e.target.value)
|
|
1306
|
+
}
|
|
1307
|
+
)
|
|
1308
|
+
] })
|
|
1309
|
+
] });
|
|
1310
|
+
}
|
|
1311
|
+
function expandShorthandHex(hex) {
|
|
1312
|
+
if (hex.length !== 4) return hex;
|
|
1313
|
+
return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// src/components/PresetManager.tsx
|
|
1317
|
+
var import_react12 = require("react");
|
|
1318
|
+
var import_react_dom = require("react-dom");
|
|
1319
|
+
var import_react13 = require("motion/react");
|
|
1320
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1321
|
+
function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
1322
|
+
const [isOpen, setIsOpen] = (0, import_react12.useState)(false);
|
|
1323
|
+
const triggerRef = (0, import_react12.useRef)(null);
|
|
1324
|
+
const dropdownRef = (0, import_react12.useRef)(null);
|
|
1325
|
+
const [pos, setPos] = (0, import_react12.useState)({ top: 0, left: 0, width: 0 });
|
|
1326
|
+
const hasPresets = presets.length > 0;
|
|
1327
|
+
const activePreset = presets.find((p) => p.id === activePresetId);
|
|
1328
|
+
const open = (0, import_react12.useCallback)(() => {
|
|
1329
|
+
if (!hasPresets) return;
|
|
1330
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1331
|
+
if (rect) {
|
|
1332
|
+
setPos({ top: rect.bottom + 4, left: rect.left, width: rect.width });
|
|
1333
|
+
}
|
|
1334
|
+
setIsOpen(true);
|
|
1335
|
+
}, [hasPresets]);
|
|
1336
|
+
const close = (0, import_react12.useCallback)(() => setIsOpen(false), []);
|
|
1337
|
+
const toggle = (0, import_react12.useCallback)(() => {
|
|
1338
|
+
if (isOpen) close();
|
|
1339
|
+
else open();
|
|
1340
|
+
}, [isOpen, open, close]);
|
|
1341
|
+
(0, import_react12.useEffect)(() => {
|
|
1342
|
+
if (!isOpen) return;
|
|
1343
|
+
const handler = (e) => {
|
|
1344
|
+
const target = e.target;
|
|
1345
|
+
if (triggerRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;
|
|
1346
|
+
close();
|
|
1347
|
+
};
|
|
1348
|
+
document.addEventListener("mousedown", handler);
|
|
1349
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
1350
|
+
}, [isOpen, close]);
|
|
1351
|
+
const handleSelect = (presetId) => {
|
|
1352
|
+
if (presetId) {
|
|
1353
|
+
DialStore.loadPreset(panelId, presetId);
|
|
1354
|
+
} else {
|
|
1355
|
+
DialStore.clearActivePreset(panelId);
|
|
1356
|
+
}
|
|
1357
|
+
close();
|
|
1358
|
+
};
|
|
1359
|
+
const handleDelete = (e, presetId) => {
|
|
1360
|
+
e.stopPropagation();
|
|
1361
|
+
DialStore.deletePreset(panelId, presetId);
|
|
1362
|
+
};
|
|
1363
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dialkit-preset-manager", children: [
|
|
1364
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1365
|
+
"button",
|
|
1366
|
+
{
|
|
1367
|
+
ref: triggerRef,
|
|
1368
|
+
className: "dialkit-preset-trigger",
|
|
1369
|
+
onClick: toggle,
|
|
1370
|
+
"data-open": String(isOpen),
|
|
1371
|
+
"data-has-preset": String(!!activePreset),
|
|
1372
|
+
"data-disabled": String(!hasPresets),
|
|
1373
|
+
children: [
|
|
1374
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-preset-label", children: activePreset ? activePreset.name : "Version 1" }),
|
|
1375
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1376
|
+
import_react13.motion.svg,
|
|
1377
|
+
{
|
|
1378
|
+
className: "dialkit-select-chevron",
|
|
1379
|
+
viewBox: "0 0 24 24",
|
|
1380
|
+
fill: "none",
|
|
1381
|
+
stroke: "currentColor",
|
|
1382
|
+
strokeWidth: "2.5",
|
|
1383
|
+
strokeLinecap: "round",
|
|
1384
|
+
strokeLinejoin: "round",
|
|
1385
|
+
animate: { rotate: isOpen ? 180 : 0, opacity: hasPresets ? 0.6 : 0.25 },
|
|
1386
|
+
transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
|
|
1387
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
1388
|
+
}
|
|
1389
|
+
)
|
|
1390
|
+
]
|
|
1391
|
+
}
|
|
1392
|
+
),
|
|
1393
|
+
(0, import_react_dom.createPortal)(
|
|
1394
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react13.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1395
|
+
import_react13.motion.div,
|
|
1396
|
+
{
|
|
1397
|
+
ref: dropdownRef,
|
|
1398
|
+
className: "dialkit-preset-dropdown",
|
|
1399
|
+
style: { position: "fixed", top: pos.top, left: pos.left, minWidth: pos.width },
|
|
1400
|
+
initial: { opacity: 0, y: 4, scale: 0.97 },
|
|
1401
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1402
|
+
exit: { opacity: 0, y: 4, scale: 0.97, pointerEvents: "none" },
|
|
1403
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1404
|
+
children: [
|
|
1405
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1406
|
+
"div",
|
|
1407
|
+
{
|
|
1408
|
+
className: "dialkit-preset-item",
|
|
1409
|
+
"data-active": String(!activePresetId),
|
|
1410
|
+
onClick: () => handleSelect(null),
|
|
1411
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-preset-name", children: "Version 1" })
|
|
1412
|
+
}
|
|
1413
|
+
),
|
|
1414
|
+
presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1415
|
+
"div",
|
|
1416
|
+
{
|
|
1417
|
+
className: "dialkit-preset-item",
|
|
1418
|
+
"data-active": String(preset.id === activePresetId),
|
|
1419
|
+
onClick: () => handleSelect(preset.id),
|
|
1420
|
+
children: [
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dialkit-preset-name", children: preset.name }),
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1423
|
+
"button",
|
|
1424
|
+
{
|
|
1425
|
+
className: "dialkit-preset-delete",
|
|
1426
|
+
onClick: (e) => handleDelete(e, preset.id),
|
|
1427
|
+
title: "Delete preset",
|
|
1428
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M5 6.5L5.80734 18.2064C5.91582 19.7794 7.22348 21 8.80023 21H15.1998C16.7765 21 18.0842 19.7794 18.1927 18.2064L19 6.5" }),
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M10 11V16" }),
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M14 11V16" }),
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M3.5 6H20.5" }),
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M8.07092 5.74621C8.42348 3.89745 10.0485 2.5 12 2.5C13.9515 2.5 15.5765 3.89745 15.9291 5.74621" })
|
|
1434
|
+
] })
|
|
1435
|
+
}
|
|
1436
|
+
)
|
|
1437
|
+
]
|
|
1438
|
+
},
|
|
1439
|
+
preset.id
|
|
1440
|
+
))
|
|
1441
|
+
]
|
|
1442
|
+
}
|
|
1443
|
+
) }),
|
|
1444
|
+
document.body
|
|
1445
|
+
)
|
|
1446
|
+
] });
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
// src/components/Panel.tsx
|
|
1450
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
957
1451
|
function Panel({ panel }) {
|
|
958
|
-
const
|
|
1452
|
+
const [copied, setCopied] = (0, import_react14.useState)(false);
|
|
1453
|
+
const [isPanelOpen, setIsPanelOpen] = (0, import_react14.useState)(true);
|
|
1454
|
+
const values = (0, import_react14.useSyncExternalStore)(
|
|
959
1455
|
(cb) => DialStore.subscribe(panel.id, cb),
|
|
960
1456
|
() => DialStore.getValues(panel.id),
|
|
961
1457
|
() => DialStore.getValues(panel.id)
|
|
962
1458
|
);
|
|
1459
|
+
const presets = DialStore.getPresets(panel.id);
|
|
1460
|
+
const activePresetId = DialStore.getActivePresetId(panel.id);
|
|
1461
|
+
const handleAddPreset = () => {
|
|
1462
|
+
const nextNum = presets.length + 2;
|
|
1463
|
+
DialStore.savePreset(panel.id, `Version ${nextNum}`);
|
|
1464
|
+
};
|
|
1465
|
+
const handleCopy = () => {
|
|
1466
|
+
const jsonStr = JSON.stringify(values, null, 2);
|
|
1467
|
+
const instruction = `Update the useDialKit configuration for "${panel.name}" with these values:
|
|
1468
|
+
|
|
1469
|
+
\`\`\`json
|
|
1470
|
+
${jsonStr}
|
|
1471
|
+
\`\`\`
|
|
1472
|
+
|
|
1473
|
+
Apply these values as the new defaults in the useDialKit call.`;
|
|
1474
|
+
navigator.clipboard.writeText(instruction);
|
|
1475
|
+
setCopied(true);
|
|
1476
|
+
setTimeout(() => setCopied(false), 1500);
|
|
1477
|
+
};
|
|
963
1478
|
const renderControl = (control) => {
|
|
964
1479
|
const value = values[control.path];
|
|
965
1480
|
switch (control.type) {
|
|
966
1481
|
case "slider":
|
|
967
|
-
return /* @__PURE__ */ (0,
|
|
1482
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
968
1483
|
Slider,
|
|
969
1484
|
{
|
|
970
1485
|
label: control.label,
|
|
@@ -977,7 +1492,7 @@ function Panel({ panel }) {
|
|
|
977
1492
|
control.path
|
|
978
1493
|
);
|
|
979
1494
|
case "toggle":
|
|
980
|
-
return /* @__PURE__ */ (0,
|
|
1495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
981
1496
|
Toggle,
|
|
982
1497
|
{
|
|
983
1498
|
label: control.label,
|
|
@@ -987,7 +1502,7 @@ function Panel({ panel }) {
|
|
|
987
1502
|
control.path
|
|
988
1503
|
);
|
|
989
1504
|
case "spring":
|
|
990
|
-
return /* @__PURE__ */ (0,
|
|
1505
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
991
1506
|
SpringControl,
|
|
992
1507
|
{
|
|
993
1508
|
panelId: panel.id,
|
|
@@ -999,7 +1514,39 @@ function Panel({ panel }) {
|
|
|
999
1514
|
control.path
|
|
1000
1515
|
);
|
|
1001
1516
|
case "folder":
|
|
1002
|
-
return /* @__PURE__ */ (0,
|
|
1517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Folder, { title: control.label, children: control.children?.map(renderControl) }, control.path);
|
|
1518
|
+
case "text":
|
|
1519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1520
|
+
TextControl,
|
|
1521
|
+
{
|
|
1522
|
+
label: control.label,
|
|
1523
|
+
value,
|
|
1524
|
+
onChange: (v) => DialStore.updateValue(panel.id, control.path, v),
|
|
1525
|
+
placeholder: control.placeholder
|
|
1526
|
+
},
|
|
1527
|
+
control.path
|
|
1528
|
+
);
|
|
1529
|
+
case "select":
|
|
1530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1531
|
+
SelectControl,
|
|
1532
|
+
{
|
|
1533
|
+
label: control.label,
|
|
1534
|
+
value,
|
|
1535
|
+
options: control.options ?? [],
|
|
1536
|
+
onChange: (v) => DialStore.updateValue(panel.id, control.path, v)
|
|
1537
|
+
},
|
|
1538
|
+
control.path
|
|
1539
|
+
);
|
|
1540
|
+
case "color":
|
|
1541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1542
|
+
ColorControl,
|
|
1543
|
+
{
|
|
1544
|
+
label: control.label,
|
|
1545
|
+
value,
|
|
1546
|
+
onChange: (v) => DialStore.updateValue(panel.id, control.path, v)
|
|
1547
|
+
},
|
|
1548
|
+
control.path
|
|
1549
|
+
);
|
|
1003
1550
|
default:
|
|
1004
1551
|
return null;
|
|
1005
1552
|
}
|
|
@@ -1010,24 +1557,16 @@ function Panel({ panel }) {
|
|
|
1010
1557
|
while (i < panel.controls.length) {
|
|
1011
1558
|
const control = panel.controls[i];
|
|
1012
1559
|
if (control.type === "action") {
|
|
1013
|
-
const actions = [control];
|
|
1014
|
-
while (i + 1 < panel.controls.length && panel.controls[i + 1].type === "action") {
|
|
1015
|
-
i++;
|
|
1016
|
-
actions.push(panel.controls[i]);
|
|
1017
|
-
}
|
|
1018
1560
|
result.push(
|
|
1019
|
-
/* @__PURE__ */ (0,
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
"button",
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
action.path
|
|
1029
|
-
)) })
|
|
1030
|
-
] }, `actions-${actions[0].path}`)
|
|
1561
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1562
|
+
"button",
|
|
1563
|
+
{
|
|
1564
|
+
className: "dialkit-button",
|
|
1565
|
+
onClick: () => DialStore.triggerAction(panel.id, control.path),
|
|
1566
|
+
children: control.label
|
|
1567
|
+
},
|
|
1568
|
+
control.path
|
|
1569
|
+
)
|
|
1031
1570
|
);
|
|
1032
1571
|
} else {
|
|
1033
1572
|
result.push(renderControl(control));
|
|
@@ -1036,15 +1575,92 @@ function Panel({ panel }) {
|
|
|
1036
1575
|
}
|
|
1037
1576
|
return result;
|
|
1038
1577
|
};
|
|
1039
|
-
|
|
1578
|
+
const iconTransition = { type: "spring", visualDuration: 0.4, bounce: 0.1 };
|
|
1579
|
+
const toolbar = /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1580
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1581
|
+
import_react15.motion.button,
|
|
1582
|
+
{
|
|
1583
|
+
className: "dialkit-toolbar-add",
|
|
1584
|
+
onClick: handleAddPreset,
|
|
1585
|
+
title: "Add preset",
|
|
1586
|
+
whileTap: { scale: 0.9 },
|
|
1587
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1588
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1589
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 6H20" }),
|
|
1590
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 12H10" }),
|
|
1591
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M15 15L21 15" }),
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M18 12V18" }),
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 18H10" })
|
|
1594
|
+
] })
|
|
1595
|
+
}
|
|
1596
|
+
),
|
|
1597
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1598
|
+
PresetManager,
|
|
1599
|
+
{
|
|
1600
|
+
panelId: panel.id,
|
|
1601
|
+
presets,
|
|
1602
|
+
activePresetId,
|
|
1603
|
+
onAdd: handleAddPreset
|
|
1604
|
+
}
|
|
1605
|
+
),
|
|
1606
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1607
|
+
import_react15.motion.button,
|
|
1608
|
+
{
|
|
1609
|
+
className: "dialkit-toolbar-copy",
|
|
1610
|
+
onClick: handleCopy,
|
|
1611
|
+
title: "Copy parameters",
|
|
1612
|
+
whileTap: { scale: 0.95 },
|
|
1613
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1614
|
+
children: [
|
|
1615
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react15.AnimatePresence, { initial: false, mode: "popLayout", children: copied ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1616
|
+
import_react15.motion.svg,
|
|
1617
|
+
{
|
|
1618
|
+
className: "dialkit-toolbar-copy-icon",
|
|
1619
|
+
viewBox: "0 0 24 24",
|
|
1620
|
+
fill: "none",
|
|
1621
|
+
stroke: "currentColor",
|
|
1622
|
+
strokeWidth: "2",
|
|
1623
|
+
strokeLinecap: "round",
|
|
1624
|
+
strokeLinejoin: "round",
|
|
1625
|
+
initial: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1626
|
+
animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
|
|
1627
|
+
exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1628
|
+
transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
1629
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M5 12.75L10 19L19 5" })
|
|
1630
|
+
},
|
|
1631
|
+
"check"
|
|
1632
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1633
|
+
import_react15.motion.svg,
|
|
1634
|
+
{
|
|
1635
|
+
className: "dialkit-toolbar-copy-icon",
|
|
1636
|
+
viewBox: "0 0 24 24",
|
|
1637
|
+
fill: "none",
|
|
1638
|
+
initial: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1639
|
+
animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
|
|
1640
|
+
exit: { scale: 0.5, opacity: 0, filter: "blur(4px)" },
|
|
1641
|
+
transition: { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
1642
|
+
children: [
|
|
1643
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }),
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M19.2405 16.1852L18.5436 14.3733C18.4571 14.1484 18.241 14 18 14C17.759 14 17.5429 14.1484 17.4564 14.3733L16.7595 16.1852C16.658 16.4493 16.4493 16.658 16.1852 16.7595L14.3733 17.4564C14.1484 17.5429 14 17.759 14 18C14 18.241 14.1484 18.4571 14.3733 18.5436L16.1852 19.2405C16.4493 19.342 16.658 19.5507 16.7595 19.8148L17.4564 21.6267C17.5429 21.8516 17.759 22 18 22C18.241 22 18.4571 21.8516 18.5436 21.6267L19.2405 19.8148C19.342 19.5507 19.5507 19.342 19.8148 19.2405L21.6267 18.5436C21.8516 18.4571 22 18.241 22 18C22 17.759 21.8516 17.5429 21.6267 17.4564L19.8148 16.7595C19.5507 16.658 19.342 16.4493 19.2405 16.1852Z", fill: "currentColor" }),
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M16 5H17C18.6569 5 20 6.34315 20 8V11M8 5H7C5.34315 5 4 6.34315 4 8V18C4 19.6569 5.34315 21 7 21H12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
1646
|
+
]
|
|
1647
|
+
},
|
|
1648
|
+
"clipboard"
|
|
1649
|
+
) }) }),
|
|
1650
|
+
"Copy"
|
|
1651
|
+
]
|
|
1652
|
+
}
|
|
1653
|
+
)
|
|
1654
|
+
] });
|
|
1655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Folder, { title: panel.name, defaultOpen: true, isRoot: true, onOpenChange: setIsPanelOpen, toolbar, children: renderControls() }) });
|
|
1040
1656
|
}
|
|
1041
1657
|
|
|
1042
1658
|
// src/components/DialRoot.tsx
|
|
1043
|
-
var
|
|
1659
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1044
1660
|
function DialRoot({ position = "top-right" }) {
|
|
1045
|
-
const [panels, setPanels] = (0,
|
|
1046
|
-
const [mounted, setMounted] = (0,
|
|
1047
|
-
(0,
|
|
1661
|
+
const [panels, setPanels] = (0, import_react16.useState)([]);
|
|
1662
|
+
const [mounted, setMounted] = (0, import_react16.useState)(false);
|
|
1663
|
+
(0, import_react16.useEffect)(() => {
|
|
1048
1664
|
setMounted(true);
|
|
1049
1665
|
setPanels(DialStore.getPanels());
|
|
1050
1666
|
const unsubscribe = DialStore.subscribeGlobal(() => {
|
|
@@ -1058,14 +1674,14 @@ function DialRoot({ position = "top-right" }) {
|
|
|
1058
1674
|
if (panels.length === 0) {
|
|
1059
1675
|
return null;
|
|
1060
1676
|
}
|
|
1061
|
-
const content = /* @__PURE__ */ (0,
|
|
1062
|
-
return (0,
|
|
1677
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dialkit-root", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dialkit-panel", "data-position": position, children: panels.map((panel) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Panel, { panel }, panel.id)) }) });
|
|
1678
|
+
return (0, import_react_dom2.createPortal)(content, document.body);
|
|
1063
1679
|
}
|
|
1064
1680
|
|
|
1065
1681
|
// src/components/ButtonGroup.tsx
|
|
1066
|
-
var
|
|
1682
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1067
1683
|
function ButtonGroup({ buttons }) {
|
|
1068
|
-
return /* @__PURE__ */ (0,
|
|
1684
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dialkit-button-group", children: buttons.map((button, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1069
1685
|
"button",
|
|
1070
1686
|
{
|
|
1071
1687
|
className: "dialkit-button",
|
|
@@ -1078,13 +1694,16 @@ function ButtonGroup({ buttons }) {
|
|
|
1078
1694
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1079
1695
|
0 && (module.exports = {
|
|
1080
1696
|
ButtonGroup,
|
|
1697
|
+
ColorControl,
|
|
1081
1698
|
DialRoot,
|
|
1082
1699
|
DialStore,
|
|
1083
1700
|
Folder,
|
|
1084
|
-
|
|
1701
|
+
PresetManager,
|
|
1702
|
+
SelectControl,
|
|
1085
1703
|
Slider,
|
|
1086
1704
|
SpringControl,
|
|
1087
1705
|
SpringVisualization,
|
|
1706
|
+
TextControl,
|
|
1088
1707
|
Toggle,
|
|
1089
1708
|
useDialKit
|
|
1090
1709
|
});
|