dialkit 0.2.0 → 0.2.2
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 +27 -6
- package/dist/index.cjs +138 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +143 -104
- package/dist/index.js.map +1 -1
- package/dist/styles.css +3 -9
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -33,10 +33,10 @@ type TextConfig = {
|
|
|
33
33
|
};
|
|
34
34
|
type DialValue = number | boolean | string | SpringConfig | ActionConfig | SelectConfig | ColorConfig | TextConfig;
|
|
35
35
|
type DialConfig = {
|
|
36
|
-
[key: string]: DialValue | [number, number, number] | DialConfig;
|
|
36
|
+
[key: string]: DialValue | [number, number, number, number?] | DialConfig;
|
|
37
37
|
};
|
|
38
38
|
type ResolvedValues<T extends DialConfig> = {
|
|
39
|
-
[K in keyof T]: T[K] extends [number, number, number] ? number : T[K] extends SpringConfig ? SpringConfig : T[K] extends SelectConfig ? string : T[K] extends ColorConfig ? string : T[K] extends TextConfig ? string : T[K] extends DialConfig ? ResolvedValues<T[K]> : T[K];
|
|
39
|
+
[K in keyof T]: T[K] extends [number, number, number, number?] ? number : T[K] extends SpringConfig ? SpringConfig : T[K] extends SelectConfig ? string : T[K] extends ColorConfig ? string : T[K] extends TextConfig ? string : T[K] extends DialConfig ? ResolvedValues<T[K]> : T[K];
|
|
40
40
|
};
|
|
41
41
|
type ControlMeta = {
|
|
42
42
|
type: 'slider' | 'toggle' | 'spring' | 'folder' | 'action' | 'select' | 'color' | 'text';
|
|
@@ -46,6 +46,7 @@ type ControlMeta = {
|
|
|
46
46
|
max?: number;
|
|
47
47
|
step?: number;
|
|
48
48
|
children?: ControlMeta[];
|
|
49
|
+
defaultOpen?: boolean;
|
|
49
50
|
options?: (string | {
|
|
50
51
|
value: string;
|
|
51
52
|
label: string;
|
package/dist/index.js
CHANGED
|
@@ -160,16 +160,17 @@ var DialStoreClass = class {
|
|
|
160
160
|
parseConfig(config, prefix) {
|
|
161
161
|
const controls = [];
|
|
162
162
|
for (const [key, value] of Object.entries(config)) {
|
|
163
|
+
if (key === "_collapsed") continue;
|
|
163
164
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
164
165
|
const label = this.formatLabel(key);
|
|
165
|
-
if (Array.isArray(value) && value.length
|
|
166
|
+
if (Array.isArray(value) && value.length <= 4 && typeof value[0] === "number") {
|
|
166
167
|
controls.push({
|
|
167
168
|
type: "slider",
|
|
168
169
|
path,
|
|
169
170
|
label,
|
|
170
171
|
min: value[1],
|
|
171
172
|
max: value[2],
|
|
172
|
-
step: this.inferStep(value[1], value[2])
|
|
173
|
+
step: value[3] ?? this.inferStep(value[1], value[2])
|
|
173
174
|
});
|
|
174
175
|
} else if (typeof value === "number") {
|
|
175
176
|
const { min, max, step } = this.inferRange(value);
|
|
@@ -193,11 +194,14 @@ var DialStoreClass = class {
|
|
|
193
194
|
controls.push({ type: "text", path, label });
|
|
194
195
|
}
|
|
195
196
|
} else if (typeof value === "object" && value !== null) {
|
|
197
|
+
const folderConfig = value;
|
|
198
|
+
const defaultOpen = "_collapsed" in folderConfig ? !folderConfig._collapsed : true;
|
|
196
199
|
controls.push({
|
|
197
200
|
type: "folder",
|
|
198
201
|
path,
|
|
199
202
|
label,
|
|
200
|
-
|
|
203
|
+
defaultOpen,
|
|
204
|
+
children: this.parseConfig(folderConfig, path)
|
|
201
205
|
});
|
|
202
206
|
}
|
|
203
207
|
}
|
|
@@ -206,8 +210,9 @@ var DialStoreClass = class {
|
|
|
206
210
|
flattenValues(config, prefix) {
|
|
207
211
|
const values = {};
|
|
208
212
|
for (const [key, value] of Object.entries(config)) {
|
|
213
|
+
if (key === "_collapsed") continue;
|
|
209
214
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
210
|
-
if (Array.isArray(value) && value.length
|
|
215
|
+
if (Array.isArray(value) && value.length <= 4 && typeof value[0] === "number") {
|
|
211
216
|
values[path] = value[0];
|
|
212
217
|
} else if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
|
|
213
218
|
values[path] = value;
|
|
@@ -299,8 +304,9 @@ function useDialKit(name, config, options) {
|
|
|
299
304
|
function buildResolvedValues(config, flatValues, prefix) {
|
|
300
305
|
const result = {};
|
|
301
306
|
for (const [key, configValue] of Object.entries(config)) {
|
|
307
|
+
if (key === "_collapsed") continue;
|
|
302
308
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
303
|
-
if (Array.isArray(configValue) && configValue.length
|
|
309
|
+
if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
|
|
304
310
|
result[key] = flatValues[path] ?? configValue[0];
|
|
305
311
|
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
306
312
|
result[key] = flatValues[path] ?? configValue;
|
|
@@ -346,7 +352,7 @@ function getFirstOptionValue(options) {
|
|
|
346
352
|
|
|
347
353
|
// src/components/DialRoot.tsx
|
|
348
354
|
import { useEffect as useEffect7, useState as useState8 } from "react";
|
|
349
|
-
import { createPortal as
|
|
355
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
350
356
|
|
|
351
357
|
// src/components/Panel.tsx
|
|
352
358
|
import { useState as useState7, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
@@ -361,8 +367,6 @@ function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenCha
|
|
|
361
367
|
const [isCollapsed, setIsCollapsed] = useState(!defaultOpen);
|
|
362
368
|
const contentRef = useRef2(null);
|
|
363
369
|
const [contentHeight, setContentHeight] = useState(void 0);
|
|
364
|
-
const iconTransition = { type: "spring", visualDuration: 0.4, bounce: 0.1 };
|
|
365
|
-
const panelTransition = { type: "spring", visualDuration: 0.4, bounce: 0.2 };
|
|
366
370
|
useEffect2(() => {
|
|
367
371
|
const el = contentRef.current;
|
|
368
372
|
if (!el) return;
|
|
@@ -375,25 +379,20 @@ function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenCha
|
|
|
375
379
|
ro.observe(el);
|
|
376
380
|
return () => ro.disconnect();
|
|
377
381
|
}, [isOpen]);
|
|
382
|
+
const handleToggle = () => {
|
|
383
|
+
const next = !isOpen;
|
|
384
|
+
setIsOpen(next);
|
|
385
|
+
if (next) {
|
|
386
|
+
setIsCollapsed(false);
|
|
387
|
+
} else {
|
|
388
|
+
setIsCollapsed(true);
|
|
389
|
+
}
|
|
390
|
+
onOpenChange?.(next);
|
|
391
|
+
};
|
|
378
392
|
const folderContent = /* @__PURE__ */ jsxs("div", { ref: isRoot ? contentRef : void 0, className: `dialkit-folder ${isRoot ? "dialkit-folder-root" : ""}`, children: [
|
|
379
|
-
/* @__PURE__ */ jsxs("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick:
|
|
380
|
-
const next = !isOpen;
|
|
381
|
-
setIsOpen(next);
|
|
382
|
-
if (next) setIsCollapsed(false);
|
|
383
|
-
onOpenChange?.(next);
|
|
384
|
-
}, children: [
|
|
393
|
+
/* @__PURE__ */ jsxs("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
|
|
385
394
|
/* @__PURE__ */ jsxs("div", { className: "dialkit-folder-header-top", children: [
|
|
386
|
-
isRoot ? /* @__PURE__ */ jsx(
|
|
387
|
-
motion.div,
|
|
388
|
-
{
|
|
389
|
-
className: "dialkit-folder-title-row",
|
|
390
|
-
initial: { opacity: 1 },
|
|
391
|
-
animate: { opacity: 1 },
|
|
392
|
-
exit: { opacity: 0 },
|
|
393
|
-
transition: { duration: 0.15 },
|
|
394
|
-
children: /* @__PURE__ */ jsx("span", { className: "dialkit-folder-title dialkit-folder-title-root", children: title })
|
|
395
|
-
}
|
|
396
|
-
) }) : /* @__PURE__ */ jsx("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ jsx("span", { className: "dialkit-folder-title", children: title }) }),
|
|
395
|
+
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 }) }),
|
|
397
396
|
isRoot ? (
|
|
398
397
|
// Root panel icon — fixed position, container morphs around it
|
|
399
398
|
/* @__PURE__ */ jsxs(
|
|
@@ -430,53 +429,32 @@ function Folder({ title, children, defaultOpen = true, isRoot = false, onOpenCha
|
|
|
430
429
|
)
|
|
431
430
|
)
|
|
432
431
|
] }),
|
|
433
|
-
isRoot && toolbar && /* @__PURE__ */ jsx(
|
|
434
|
-
motion.div,
|
|
435
|
-
{
|
|
436
|
-
initial: { opacity: 1 },
|
|
437
|
-
animate: { opacity: 1 },
|
|
438
|
-
exit: { opacity: 0 },
|
|
439
|
-
transition: { duration: 0.15 },
|
|
440
|
-
children: /* @__PURE__ */ jsx("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
441
|
-
}
|
|
442
|
-
) })
|
|
432
|
+
isRoot && toolbar && isOpen && /* @__PURE__ */ jsx("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
443
433
|
] }),
|
|
444
434
|
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ jsx(
|
|
445
435
|
motion.div,
|
|
446
436
|
{
|
|
447
437
|
className: "dialkit-folder-content",
|
|
448
|
-
initial: isRoot ?
|
|
449
|
-
animate: isRoot ?
|
|
450
|
-
exit: isRoot ?
|
|
451
|
-
transition: isRoot ?
|
|
452
|
-
style: isRoot ? void 0 : {
|
|
438
|
+
initial: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
439
|
+
animate: isRoot ? void 0 : { height: "auto", opacity: 1 },
|
|
440
|
+
exit: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
441
|
+
transition: isRoot ? void 0 : { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
442
|
+
style: isRoot ? void 0 : { clipPath: "inset(0 -20px)" },
|
|
453
443
|
children: /* @__PURE__ */ jsx("div", { className: "dialkit-folder-inner", children })
|
|
454
444
|
}
|
|
455
445
|
) })
|
|
456
446
|
] });
|
|
457
447
|
if (isRoot) {
|
|
448
|
+
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" };
|
|
458
449
|
return /* @__PURE__ */ jsx(
|
|
459
450
|
motion.div,
|
|
460
451
|
{
|
|
461
452
|
className: "dialkit-panel-inner",
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
width: isOpen ? 280 : 42,
|
|
465
|
-
height: isOpen ? contentHeight !== void 0 ? contentHeight + 24 : "auto" : 42,
|
|
466
|
-
borderRadius: isOpen ? 14 : 21,
|
|
467
|
-
boxShadow: isOpen ? "0 8px 32px rgba(0, 0, 0, 0.5)" : "0 4px 16px rgba(0, 0, 0, 0.25)"
|
|
468
|
-
},
|
|
469
|
-
transition: panelTransition,
|
|
470
|
-
style: { overflow: isOpen ? void 0 : "hidden", cursor: isOpen ? void 0 : "pointer" },
|
|
471
|
-
onClick: !isOpen ? () => {
|
|
472
|
-
setIsOpen(true);
|
|
473
|
-
setIsCollapsed(false);
|
|
474
|
-
onOpenChange?.(true);
|
|
475
|
-
} : void 0,
|
|
476
|
-
onAnimationComplete: () => {
|
|
477
|
-
if (!isOpen) setIsCollapsed(true);
|
|
478
|
-
},
|
|
453
|
+
style: panelStyle,
|
|
454
|
+
onClick: !isOpen ? handleToggle : void 0,
|
|
479
455
|
"data-collapsed": isCollapsed,
|
|
456
|
+
whileTap: !isOpen ? { scale: 0.9 } : void 0,
|
|
457
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
480
458
|
children: folderContent
|
|
481
459
|
}
|
|
482
460
|
);
|
|
@@ -492,10 +470,14 @@ var CLICK_THRESHOLD = 3;
|
|
|
492
470
|
var DEAD_ZONE = 32;
|
|
493
471
|
var MAX_CURSOR_RANGE = 200;
|
|
494
472
|
var MAX_STRETCH = 8;
|
|
473
|
+
function decimalsForStep(step) {
|
|
474
|
+
const s = step.toString();
|
|
475
|
+
const dot = s.indexOf(".");
|
|
476
|
+
return dot === -1 ? 0 : s.length - dot - 1;
|
|
477
|
+
}
|
|
495
478
|
function roundValue(val, step) {
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
return Math.round(val * factor) / factor;
|
|
479
|
+
const raw = Math.round(val / step) * step;
|
|
480
|
+
return parseFloat(raw.toFixed(decimalsForStep(step)));
|
|
499
481
|
}
|
|
500
482
|
function snapToDecile(rawValue, min, max) {
|
|
501
483
|
const normalized = (rawValue - min) / (max - min);
|
|
@@ -643,7 +625,8 @@ function Slider({
|
|
|
643
625
|
if (!isInteracting) return;
|
|
644
626
|
if (isClickRef.current) {
|
|
645
627
|
const rawValue = positionToValue(e.clientX);
|
|
646
|
-
const
|
|
628
|
+
const discreteSteps2 = (max - min) / step;
|
|
629
|
+
const snappedValue = discreteSteps2 <= 10 ? Math.max(min, Math.min(max, min + Math.round((rawValue - min) / step) * step)) : snapToDecile(rawValue, min, max);
|
|
647
630
|
const newPct = percentFromValue(snappedValue);
|
|
648
631
|
if (animRef.current) {
|
|
649
632
|
animRef.current.stop();
|
|
@@ -723,7 +706,7 @@ function Slider({
|
|
|
723
706
|
e.stopPropagation();
|
|
724
707
|
e.preventDefault();
|
|
725
708
|
setShowInput(true);
|
|
726
|
-
setInputValue(
|
|
709
|
+
setInputValue(value.toFixed(decimalsForStep(step)));
|
|
727
710
|
}
|
|
728
711
|
};
|
|
729
712
|
const handleInputKeyDown = (e) => {
|
|
@@ -737,7 +720,7 @@ function Slider({
|
|
|
737
720
|
const handleInputBlur = () => {
|
|
738
721
|
handleInputSubmit();
|
|
739
722
|
};
|
|
740
|
-
const displayValue =
|
|
723
|
+
const displayValue = value.toFixed(decimalsForStep(step));
|
|
741
724
|
const HANDLE_BUFFER = 8;
|
|
742
725
|
const LABEL_CSS_LEFT = 10;
|
|
743
726
|
const VALUE_CSS_RIGHT = 10;
|
|
@@ -755,7 +738,18 @@ function Slider({
|
|
|
755
738
|
const valueDodge = percentage < leftThreshold || percentage > rightThreshold;
|
|
756
739
|
const handleOpacity = !isActive ? 0 : valueDodge ? 0.1 : isDragging ? 0.9 : 0.5;
|
|
757
740
|
const fillBackground = isActive ? "rgba(255, 255, 255, 0.15)" : "rgba(255, 255, 255, 0.11)";
|
|
758
|
-
const
|
|
741
|
+
const discreteSteps = (max - min) / step;
|
|
742
|
+
const hashMarks = discreteSteps <= 10 ? Array.from({ length: discreteSteps - 1 }, (_, i) => {
|
|
743
|
+
const pct = (i + 1) * step / (max - min) * 100;
|
|
744
|
+
return /* @__PURE__ */ jsx2(
|
|
745
|
+
"div",
|
|
746
|
+
{
|
|
747
|
+
className: "dialkit-slider-hashmark",
|
|
748
|
+
style: { left: `${pct}%` }
|
|
749
|
+
},
|
|
750
|
+
i
|
|
751
|
+
);
|
|
752
|
+
}) : Array.from({ length: 9 }, (_, i) => {
|
|
759
753
|
const pct = (i + 1) * 10;
|
|
760
754
|
return /* @__PURE__ */ jsx2(
|
|
761
755
|
"div",
|
|
@@ -1144,33 +1138,64 @@ function TextControl({ label, value, onChange, placeholder }) {
|
|
|
1144
1138
|
}
|
|
1145
1139
|
|
|
1146
1140
|
// src/components/SelectControl.tsx
|
|
1147
|
-
import { useState as useState4, useRef as useRef5, useEffect as useEffect4 } from "react";
|
|
1141
|
+
import { useState as useState4, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback2 } from "react";
|
|
1142
|
+
import { createPortal } from "react-dom";
|
|
1148
1143
|
import { motion as motion4, AnimatePresence as AnimatePresence2 } from "motion/react";
|
|
1149
1144
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1145
|
+
function toTitleCase(s) {
|
|
1146
|
+
return s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1147
|
+
}
|
|
1150
1148
|
function normalizeOptions(options) {
|
|
1151
1149
|
return options.map(
|
|
1152
|
-
(opt) => typeof opt === "string" ? { value: opt, label: opt } : opt
|
|
1150
|
+
(opt) => typeof opt === "string" ? { value: opt, label: toTitleCase(opt) } : opt
|
|
1153
1151
|
);
|
|
1154
1152
|
}
|
|
1155
1153
|
function SelectControl({ label, value, options, onChange }) {
|
|
1156
1154
|
const [isOpen, setIsOpen] = useState4(false);
|
|
1157
|
-
const
|
|
1155
|
+
const triggerRef = useRef5(null);
|
|
1156
|
+
const dropdownRef = useRef5(null);
|
|
1157
|
+
const [portalTarget, setPortalTarget] = useState4(null);
|
|
1158
|
+
const [pos, setPos] = useState4(null);
|
|
1158
1159
|
const normalized = normalizeOptions(options);
|
|
1159
1160
|
const selectedOption = normalized.find((o) => o.value === value);
|
|
1161
|
+
const updatePos = useCallback2(() => {
|
|
1162
|
+
const el = triggerRef.current;
|
|
1163
|
+
if (!el) return;
|
|
1164
|
+
const rect = el.getBoundingClientRect();
|
|
1165
|
+
const dropdownHeight = 8 + normalized.length * 36;
|
|
1166
|
+
const spaceBelow = window.innerHeight - rect.bottom - 4;
|
|
1167
|
+
const above = spaceBelow < dropdownHeight && rect.top > spaceBelow;
|
|
1168
|
+
setPos({
|
|
1169
|
+
top: above ? rect.top - 4 : rect.bottom + 4,
|
|
1170
|
+
left: rect.left,
|
|
1171
|
+
width: rect.width,
|
|
1172
|
+
above
|
|
1173
|
+
});
|
|
1174
|
+
}, [normalized.length]);
|
|
1175
|
+
useEffect4(() => {
|
|
1176
|
+
const root = triggerRef.current?.closest(".dialkit-root");
|
|
1177
|
+
setPortalTarget(root ?? document.body);
|
|
1178
|
+
}, []);
|
|
1179
|
+
useEffect4(() => {
|
|
1180
|
+
if (!isOpen) return;
|
|
1181
|
+
updatePos();
|
|
1182
|
+
}, [isOpen, updatePos]);
|
|
1160
1183
|
useEffect4(() => {
|
|
1161
1184
|
if (!isOpen) return;
|
|
1162
1185
|
const handleClick = (e) => {
|
|
1163
|
-
|
|
1186
|
+
const target = e.target;
|
|
1187
|
+
if (triggerRef.current && !triggerRef.current.contains(target) && dropdownRef.current && !dropdownRef.current.contains(target)) {
|
|
1164
1188
|
setIsOpen(false);
|
|
1165
1189
|
}
|
|
1166
1190
|
};
|
|
1167
1191
|
document.addEventListener("mousedown", handleClick);
|
|
1168
1192
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
1169
1193
|
}, [isOpen]);
|
|
1170
|
-
return /* @__PURE__ */ jsxs8("div", {
|
|
1194
|
+
return /* @__PURE__ */ jsxs8("div", { className: "dialkit-select-row", children: [
|
|
1171
1195
|
/* @__PURE__ */ jsxs8(
|
|
1172
1196
|
"button",
|
|
1173
1197
|
{
|
|
1198
|
+
ref: triggerRef,
|
|
1174
1199
|
className: "dialkit-select-trigger",
|
|
1175
1200
|
onClick: () => setIsOpen(!isOpen),
|
|
1176
1201
|
"data-open": String(isOpen),
|
|
@@ -1197,29 +1222,39 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1197
1222
|
]
|
|
1198
1223
|
}
|
|
1199
1224
|
),
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
"
|
|
1210
|
-
{
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
setIsOpen(false);
|
|
1216
|
-
},
|
|
1217
|
-
children: option.label
|
|
1225
|
+
portalTarget && createPortal(
|
|
1226
|
+
/* @__PURE__ */ jsx8(AnimatePresence2, { children: isOpen && pos && /* @__PURE__ */ jsx8(
|
|
1227
|
+
motion4.div,
|
|
1228
|
+
{
|
|
1229
|
+
ref: dropdownRef,
|
|
1230
|
+
className: "dialkit-select-dropdown",
|
|
1231
|
+
initial: { opacity: 0, y: pos.above ? 8 : -8, scale: 0.95 },
|
|
1232
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1233
|
+
exit: { opacity: 0, y: pos.above ? 8 : -8, scale: 0.95 },
|
|
1234
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1235
|
+
style: {
|
|
1236
|
+
position: "fixed",
|
|
1237
|
+
left: pos.left,
|
|
1238
|
+
width: pos.width,
|
|
1239
|
+
...pos.above ? { bottom: window.innerHeight - pos.top, transformOrigin: "bottom" } : { top: pos.top, transformOrigin: "top" }
|
|
1218
1240
|
},
|
|
1219
|
-
option
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1241
|
+
children: normalized.map((option) => /* @__PURE__ */ jsx8(
|
|
1242
|
+
"button",
|
|
1243
|
+
{
|
|
1244
|
+
className: "dialkit-select-option",
|
|
1245
|
+
"data-selected": String(option.value === value),
|
|
1246
|
+
onClick: () => {
|
|
1247
|
+
onChange(option.value);
|
|
1248
|
+
setIsOpen(false);
|
|
1249
|
+
},
|
|
1250
|
+
children: option.label
|
|
1251
|
+
},
|
|
1252
|
+
option.value
|
|
1253
|
+
))
|
|
1254
|
+
}
|
|
1255
|
+
) }),
|
|
1256
|
+
portalTarget
|
|
1257
|
+
)
|
|
1223
1258
|
] });
|
|
1224
1259
|
}
|
|
1225
1260
|
|
|
@@ -1302,8 +1337,8 @@ function expandShorthandHex(hex) {
|
|
|
1302
1337
|
}
|
|
1303
1338
|
|
|
1304
1339
|
// src/components/PresetManager.tsx
|
|
1305
|
-
import { useState as useState6, useRef as useRef7, useEffect as useEffect6, useCallback as
|
|
1306
|
-
import { createPortal } from "react-dom";
|
|
1340
|
+
import { useState as useState6, useRef as useRef7, useEffect as useEffect6, useCallback as useCallback3 } from "react";
|
|
1341
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
1307
1342
|
import { motion as motion5, AnimatePresence as AnimatePresence3 } from "motion/react";
|
|
1308
1343
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1309
1344
|
function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
@@ -1313,7 +1348,7 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1313
1348
|
const [pos, setPos] = useState6({ top: 0, left: 0, width: 0 });
|
|
1314
1349
|
const hasPresets = presets.length > 0;
|
|
1315
1350
|
const activePreset = presets.find((p) => p.id === activePresetId);
|
|
1316
|
-
const open =
|
|
1351
|
+
const open = useCallback3(() => {
|
|
1317
1352
|
if (!hasPresets) return;
|
|
1318
1353
|
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1319
1354
|
if (rect) {
|
|
@@ -1321,8 +1356,8 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1321
1356
|
}
|
|
1322
1357
|
setIsOpen(true);
|
|
1323
1358
|
}, [hasPresets]);
|
|
1324
|
-
const close =
|
|
1325
|
-
const toggle =
|
|
1359
|
+
const close = useCallback3(() => setIsOpen(false), []);
|
|
1360
|
+
const toggle = useCallback3(() => {
|
|
1326
1361
|
if (isOpen) close();
|
|
1327
1362
|
else open();
|
|
1328
1363
|
}, [isOpen, open, close]);
|
|
@@ -1370,7 +1405,7 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1370
1405
|
strokeWidth: "2.5",
|
|
1371
1406
|
strokeLinecap: "round",
|
|
1372
1407
|
strokeLinejoin: "round",
|
|
1373
|
-
animate: { rotate: isOpen ? 180 : 0 },
|
|
1408
|
+
animate: { rotate: isOpen ? 180 : 0, opacity: hasPresets ? 0.6 : 0.25 },
|
|
1374
1409
|
transition: { type: "spring", visualDuration: 0.2, bounce: 0.15 },
|
|
1375
1410
|
children: /* @__PURE__ */ jsx10("path", { d: "M6 9.5L12 15.5L18 9.5" })
|
|
1376
1411
|
}
|
|
@@ -1378,12 +1413,12 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
1378
1413
|
]
|
|
1379
1414
|
}
|
|
1380
1415
|
),
|
|
1381
|
-
|
|
1416
|
+
createPortal2(
|
|
1382
1417
|
/* @__PURE__ */ jsx10(AnimatePresence3, { children: isOpen && /* @__PURE__ */ jsxs10(
|
|
1383
1418
|
motion5.div,
|
|
1384
1419
|
{
|
|
1385
1420
|
ref: dropdownRef,
|
|
1386
|
-
className: "dialkit-preset-dropdown",
|
|
1421
|
+
className: "dialkit-root dialkit-preset-dropdown",
|
|
1387
1422
|
style: { position: "fixed", top: pos.top, left: pos.left, minWidth: pos.width },
|
|
1388
1423
|
initial: { opacity: 0, y: 4, scale: 0.97 },
|
|
1389
1424
|
animate: { opacity: 1, y: 0, scale: 1 },
|
|
@@ -1502,7 +1537,7 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1502
1537
|
control.path
|
|
1503
1538
|
);
|
|
1504
1539
|
case "folder":
|
|
1505
|
-
return /* @__PURE__ */ jsx11(Folder, { title: control.label, children: control.children?.map(renderControl) }, control.path);
|
|
1540
|
+
return /* @__PURE__ */ jsx11(Folder, { title: control.label, defaultOpen: control.defaultOpen ?? true, children: control.children?.map(renderControl) }, control.path);
|
|
1506
1541
|
case "text":
|
|
1507
1542
|
return /* @__PURE__ */ jsx11(
|
|
1508
1543
|
TextControl,
|
|
@@ -1566,11 +1601,13 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1566
1601
|
const iconTransition = { type: "spring", visualDuration: 0.4, bounce: 0.1 };
|
|
1567
1602
|
const toolbar = /* @__PURE__ */ jsxs11(Fragment2, { children: [
|
|
1568
1603
|
/* @__PURE__ */ jsx11(
|
|
1569
|
-
|
|
1604
|
+
motion6.button,
|
|
1570
1605
|
{
|
|
1571
1606
|
className: "dialkit-toolbar-add",
|
|
1572
1607
|
onClick: handleAddPreset,
|
|
1573
1608
|
title: "Add preset",
|
|
1609
|
+
whileTap: { scale: 0.9 },
|
|
1610
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1574
1611
|
children: /* @__PURE__ */ jsxs11("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1575
1612
|
/* @__PURE__ */ jsx11("path", { d: "M4 6H20" }),
|
|
1576
1613
|
/* @__PURE__ */ jsx11("path", { d: "M4 12H10" }),
|
|
@@ -1590,13 +1627,15 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
1590
1627
|
}
|
|
1591
1628
|
),
|
|
1592
1629
|
/* @__PURE__ */ jsxs11(
|
|
1593
|
-
|
|
1630
|
+
motion6.button,
|
|
1594
1631
|
{
|
|
1595
1632
|
className: "dialkit-toolbar-copy",
|
|
1596
1633
|
onClick: handleCopy,
|
|
1597
1634
|
title: "Copy parameters",
|
|
1635
|
+
whileTap: { scale: 0.95 },
|
|
1636
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1598
1637
|
children: [
|
|
1599
|
-
/* @__PURE__ */ jsx11("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ jsx11(AnimatePresence4, { mode: "popLayout", children: copied ? /* @__PURE__ */ jsx11(
|
|
1638
|
+
/* @__PURE__ */ jsx11("span", { className: "dialkit-toolbar-copy-icon-wrap", children: /* @__PURE__ */ jsx11(AnimatePresence4, { initial: false, mode: "popLayout", children: copied ? /* @__PURE__ */ jsx11(
|
|
1600
1639
|
motion6.svg,
|
|
1601
1640
|
{
|
|
1602
1641
|
className: "dialkit-toolbar-copy-icon",
|
|
@@ -1659,7 +1698,7 @@ function DialRoot({ position = "top-right" }) {
|
|
|
1659
1698
|
return null;
|
|
1660
1699
|
}
|
|
1661
1700
|
const content = /* @__PURE__ */ jsx12("div", { className: "dialkit-root", children: /* @__PURE__ */ jsx12("div", { className: "dialkit-panel", "data-position": position, children: panels.map((panel) => /* @__PURE__ */ jsx12(Panel, { panel }, panel.id)) }) });
|
|
1662
|
-
return
|
|
1701
|
+
return createPortal3(content, document.body);
|
|
1663
1702
|
}
|
|
1664
1703
|
|
|
1665
1704
|
// src/components/ButtonGroup.tsx
|