dialkit 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +293 -2
- package/dist/index.cjs +905 -363
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -9
- package/dist/index.d.ts +46 -9
- package/dist/index.js +910 -370
- package/dist/index.js.map +1 -1
- package/dist/solid/index.cjs +1042 -532
- package/dist/solid/index.cjs.map +1 -1
- package/dist/solid/index.d.cts +36 -3
- package/dist/solid/index.d.ts +36 -3
- package/dist/solid/index.js +911 -402
- package/dist/solid/index.js.map +1 -1
- package/dist/store/index.cjs +490 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.cts +146 -0
- package/dist/store/index.d.ts +146 -0
- package/dist/store/index.js +465 -0
- package/dist/store/index.js.map +1 -0
- package/dist/styles.css +287 -25
- package/dist/svelte/Portal.svelte +30 -0
- package/dist/svelte/Portal.svelte.d.ts +9 -0
- package/dist/svelte/Portal.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ButtonGroup.svelte +16 -0
- package/dist/svelte/components/ButtonGroup.svelte.d.ts +11 -0
- package/dist/svelte/components/ButtonGroup.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ColorControl.svelte +81 -0
- package/dist/svelte/components/ColorControl.svelte.d.ts +9 -0
- package/dist/svelte/components/ColorControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ControlRenderer.svelte +96 -0
- package/dist/svelte/components/ControlRenderer.svelte.d.ts +11 -0
- package/dist/svelte/components/ControlRenderer.svelte.d.ts.map +1 -0
- package/dist/svelte/components/DialRoot.svelte +79 -0
- package/dist/svelte/components/DialRoot.svelte.d.ts +14 -0
- package/dist/svelte/components/DialRoot.svelte.d.ts.map +1 -0
- package/dist/svelte/components/EasingVisualization.svelte +50 -0
- package/dist/svelte/components/EasingVisualization.svelte.d.ts +10 -0
- package/dist/svelte/components/EasingVisualization.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Folder.svelte +213 -0
- package/dist/svelte/components/Folder.svelte.d.ts +14 -0
- package/dist/svelte/components/Folder.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Panel.svelte +149 -0
- package/dist/svelte/components/Panel.svelte.d.ts +10 -0
- package/dist/svelte/components/Panel.svelte.d.ts.map +1 -0
- package/dist/svelte/components/PresetManager.svelte +157 -0
- package/dist/svelte/components/PresetManager.svelte.d.ts +10 -0
- package/dist/svelte/components/PresetManager.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SegmentedControl.svelte +62 -0
- package/dist/svelte/components/SegmentedControl.svelte.d.ts +13 -0
- package/dist/svelte/components/SegmentedControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SelectControl.svelte +152 -0
- package/dist/svelte/components/SelectControl.svelte.d.ts +14 -0
- package/dist/svelte/components/SelectControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ShortcutListener.svelte +265 -0
- package/dist/svelte/components/ShortcutListener.svelte.d.ts +13 -0
- package/dist/svelte/components/ShortcutListener.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ShortcutsMenu.svelte +128 -0
- package/dist/svelte/components/ShortcutsMenu.svelte.d.ts +7 -0
- package/dist/svelte/components/ShortcutsMenu.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Slider.svelte +332 -0
- package/dist/svelte/components/Slider.svelte.d.ts +16 -0
- package/dist/svelte/components/Slider.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SpringControl.svelte +126 -0
- package/dist/svelte/components/SpringControl.svelte.d.ts +12 -0
- package/dist/svelte/components/SpringControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SpringVisualization.svelte +115 -0
- package/dist/svelte/components/SpringVisualization.svelte.d.ts +9 -0
- package/dist/svelte/components/SpringVisualization.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TextControl.svelte +19 -0
- package/dist/svelte/components/TextControl.svelte.d.ts +10 -0
- package/dist/svelte/components/TextControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Toggle.svelte +32 -0
- package/dist/svelte/components/Toggle.svelte.d.ts +12 -0
- package/dist/svelte/components/Toggle.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TransitionControl.svelte +203 -0
- package/dist/svelte/components/TransitionControl.svelte.d.ts +12 -0
- package/dist/svelte/components/TransitionControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/transitions.d.ts +6 -0
- package/dist/svelte/components/transitions.d.ts.map +1 -0
- package/dist/svelte/components/transitions.js +14 -0
- package/dist/svelte/createDialKit.svelte.d.ts +8 -0
- package/dist/svelte/createDialKit.svelte.d.ts.map +1 -0
- package/dist/svelte/createDialKit.svelte.js +82 -0
- package/dist/svelte/index.d.ts +23 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +23 -0
- package/dist/svelte/shims.d.ts +9 -0
- package/dist/svelte/theme-css.d.ts +2 -0
- package/dist/svelte/theme-css.d.ts.map +1 -0
- package/dist/svelte/theme-css.js +1328 -0
- package/dist/vue/index.cjs +3056 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.cts +675 -0
- package/dist/vue/index.d.ts +675 -0
- package/dist/vue/index.js +3014 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +50 -6
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/store/DialStore.ts
|
|
21
|
+
var DialStore_exports = {};
|
|
22
|
+
__export(DialStore_exports, {
|
|
23
|
+
DialStore: () => DialStore
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(DialStore_exports);
|
|
26
|
+
var EMPTY_VALUES = Object.freeze({});
|
|
27
|
+
var DialStoreClass = class {
|
|
28
|
+
constructor() {
|
|
29
|
+
this.panels = /* @__PURE__ */ new Map();
|
|
30
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
31
|
+
this.globalListeners = /* @__PURE__ */ new Set();
|
|
32
|
+
this.snapshots = /* @__PURE__ */ new Map();
|
|
33
|
+
this.actionListeners = /* @__PURE__ */ new Map();
|
|
34
|
+
this.presets = /* @__PURE__ */ new Map();
|
|
35
|
+
this.activePreset = /* @__PURE__ */ new Map();
|
|
36
|
+
this.baseValues = /* @__PURE__ */ new Map();
|
|
37
|
+
}
|
|
38
|
+
registerPanel(id, name, config, shortcuts) {
|
|
39
|
+
const controls = this.parseConfig(config, "", shortcuts);
|
|
40
|
+
const values = this.flattenValues(config, "");
|
|
41
|
+
this.initTransitionModes(config, "", values);
|
|
42
|
+
this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {} });
|
|
43
|
+
this.snapshots.set(id, { ...values });
|
|
44
|
+
this.baseValues.set(id, { ...values });
|
|
45
|
+
this.notifyGlobal();
|
|
46
|
+
}
|
|
47
|
+
updatePanel(id, name, config, shortcuts) {
|
|
48
|
+
const existing = this.panels.get(id);
|
|
49
|
+
if (!existing) {
|
|
50
|
+
this.registerPanel(id, name, config, shortcuts);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const controls = this.parseConfig(config, "", shortcuts);
|
|
54
|
+
const controlsByPath = this.mapControlsByPath(controls);
|
|
55
|
+
const defaultValues = this.flattenValues(config, "");
|
|
56
|
+
const nextValues = {};
|
|
57
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
58
|
+
nextValues[path] = this.normalizePreservedValue(
|
|
59
|
+
existing.values[path],
|
|
60
|
+
defaultValue,
|
|
61
|
+
controlsByPath.get(path)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
this.initTransitionModes(config, "", nextValues);
|
|
65
|
+
for (const [path, mode] of Object.entries(existing.values)) {
|
|
66
|
+
if (!path.endsWith(".__mode")) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const transitionPath = path.slice(0, -"__mode".length - 1);
|
|
70
|
+
const transitionControl = controlsByPath.get(transitionPath);
|
|
71
|
+
if (transitionControl?.type === "transition") {
|
|
72
|
+
nextValues[path] = mode;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const nextPanel = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts };
|
|
76
|
+
this.panels.set(id, nextPanel);
|
|
77
|
+
this.snapshots.set(id, { ...nextValues });
|
|
78
|
+
const previousBaseValues = this.baseValues.get(id) ?? {};
|
|
79
|
+
const nextBaseValues = {};
|
|
80
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
81
|
+
nextBaseValues[path] = this.normalizePreservedValue(
|
|
82
|
+
previousBaseValues[path],
|
|
83
|
+
defaultValue,
|
|
84
|
+
controlsByPath.get(path)
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
for (const [path, value] of Object.entries(nextValues)) {
|
|
88
|
+
if (path.endsWith(".__mode")) {
|
|
89
|
+
nextBaseValues[path] = value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
this.baseValues.set(id, nextBaseValues);
|
|
93
|
+
this.notify(id);
|
|
94
|
+
this.notifyGlobal();
|
|
95
|
+
}
|
|
96
|
+
unregisterPanel(id) {
|
|
97
|
+
this.panels.delete(id);
|
|
98
|
+
this.listeners.delete(id);
|
|
99
|
+
this.snapshots.delete(id);
|
|
100
|
+
this.actionListeners.delete(id);
|
|
101
|
+
this.baseValues.delete(id);
|
|
102
|
+
this.notifyGlobal();
|
|
103
|
+
}
|
|
104
|
+
updateValue(panelId, path, value) {
|
|
105
|
+
const panel = this.panels.get(panelId);
|
|
106
|
+
if (!panel) return;
|
|
107
|
+
panel.values[path] = value;
|
|
108
|
+
const activeId = this.activePreset.get(panelId);
|
|
109
|
+
if (activeId) {
|
|
110
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
111
|
+
const preset = presets.find((p) => p.id === activeId);
|
|
112
|
+
if (preset) preset.values[path] = value;
|
|
113
|
+
} else {
|
|
114
|
+
const base = this.baseValues.get(panelId);
|
|
115
|
+
if (base) base[path] = value;
|
|
116
|
+
}
|
|
117
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
118
|
+
this.notify(panelId);
|
|
119
|
+
}
|
|
120
|
+
updateSpringMode(panelId, path, mode) {
|
|
121
|
+
this.updateTransitionMode(panelId, path, mode);
|
|
122
|
+
}
|
|
123
|
+
getSpringMode(panelId, path) {
|
|
124
|
+
const mode = this.getTransitionMode(panelId, path);
|
|
125
|
+
if (mode === "easing") return "simple";
|
|
126
|
+
return mode;
|
|
127
|
+
}
|
|
128
|
+
updateTransitionMode(panelId, path, mode) {
|
|
129
|
+
const panel = this.panels.get(panelId);
|
|
130
|
+
if (!panel) return;
|
|
131
|
+
panel.values[`${path}.__mode`] = mode;
|
|
132
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
133
|
+
this.notify(panelId);
|
|
134
|
+
}
|
|
135
|
+
getTransitionMode(panelId, path) {
|
|
136
|
+
const panel = this.panels.get(panelId);
|
|
137
|
+
if (!panel) return "simple";
|
|
138
|
+
return panel.values[`${path}.__mode`] || "simple";
|
|
139
|
+
}
|
|
140
|
+
getValue(panelId, path) {
|
|
141
|
+
const panel = this.panels.get(panelId);
|
|
142
|
+
return panel?.values[path];
|
|
143
|
+
}
|
|
144
|
+
getValues(panelId) {
|
|
145
|
+
return this.snapshots.get(panelId) ?? EMPTY_VALUES;
|
|
146
|
+
}
|
|
147
|
+
getPanels() {
|
|
148
|
+
return Array.from(this.panels.values());
|
|
149
|
+
}
|
|
150
|
+
getPanel(id) {
|
|
151
|
+
return this.panels.get(id);
|
|
152
|
+
}
|
|
153
|
+
subscribe(panelId, listener) {
|
|
154
|
+
if (!this.listeners.has(panelId)) {
|
|
155
|
+
this.listeners.set(panelId, /* @__PURE__ */ new Set());
|
|
156
|
+
}
|
|
157
|
+
this.listeners.get(panelId).add(listener);
|
|
158
|
+
return () => {
|
|
159
|
+
this.listeners.get(panelId)?.delete(listener);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
subscribeGlobal(listener) {
|
|
163
|
+
this.globalListeners.add(listener);
|
|
164
|
+
return () => this.globalListeners.delete(listener);
|
|
165
|
+
}
|
|
166
|
+
subscribeActions(panelId, listener) {
|
|
167
|
+
if (!this.actionListeners.has(panelId)) {
|
|
168
|
+
this.actionListeners.set(panelId, /* @__PURE__ */ new Set());
|
|
169
|
+
}
|
|
170
|
+
this.actionListeners.get(panelId).add(listener);
|
|
171
|
+
return () => {
|
|
172
|
+
this.actionListeners.get(panelId)?.delete(listener);
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
triggerAction(panelId, path) {
|
|
176
|
+
this.actionListeners.get(panelId)?.forEach((fn) => fn(path));
|
|
177
|
+
}
|
|
178
|
+
savePreset(panelId, name) {
|
|
179
|
+
const panel = this.panels.get(panelId);
|
|
180
|
+
if (!panel) throw new Error(`Panel ${panelId} not found`);
|
|
181
|
+
const id = `preset-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
182
|
+
const preset = {
|
|
183
|
+
id,
|
|
184
|
+
name,
|
|
185
|
+
values: { ...panel.values }
|
|
186
|
+
};
|
|
187
|
+
const existing = this.presets.get(panelId) ?? [];
|
|
188
|
+
this.presets.set(panelId, [...existing, preset]);
|
|
189
|
+
this.activePreset.set(panelId, id);
|
|
190
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
191
|
+
this.notify(panelId);
|
|
192
|
+
return id;
|
|
193
|
+
}
|
|
194
|
+
loadPreset(panelId, presetId) {
|
|
195
|
+
const panel = this.panels.get(panelId);
|
|
196
|
+
if (!panel) return;
|
|
197
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
198
|
+
const preset = presets.find((p) => p.id === presetId);
|
|
199
|
+
if (!preset) return;
|
|
200
|
+
panel.values = { ...preset.values };
|
|
201
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
202
|
+
this.activePreset.set(panelId, presetId);
|
|
203
|
+
this.notify(panelId);
|
|
204
|
+
}
|
|
205
|
+
deletePreset(panelId, presetId) {
|
|
206
|
+
const presets = this.presets.get(panelId) ?? [];
|
|
207
|
+
this.presets.set(panelId, presets.filter((p) => p.id !== presetId));
|
|
208
|
+
if (this.activePreset.get(panelId) === presetId) {
|
|
209
|
+
this.activePreset.set(panelId, null);
|
|
210
|
+
}
|
|
211
|
+
const panel = this.panels.get(panelId);
|
|
212
|
+
if (panel) {
|
|
213
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
214
|
+
}
|
|
215
|
+
this.notify(panelId);
|
|
216
|
+
}
|
|
217
|
+
getPresets(panelId) {
|
|
218
|
+
return this.presets.get(panelId) ?? [];
|
|
219
|
+
}
|
|
220
|
+
getActivePresetId(panelId) {
|
|
221
|
+
return this.activePreset.get(panelId) ?? null;
|
|
222
|
+
}
|
|
223
|
+
clearActivePreset(panelId) {
|
|
224
|
+
const panel = this.panels.get(panelId);
|
|
225
|
+
const base = this.baseValues.get(panelId);
|
|
226
|
+
if (panel && base) {
|
|
227
|
+
panel.values = { ...base };
|
|
228
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
229
|
+
}
|
|
230
|
+
this.activePreset.set(panelId, null);
|
|
231
|
+
this.notify(panelId);
|
|
232
|
+
}
|
|
233
|
+
resolveShortcutTarget(key, modifier) {
|
|
234
|
+
for (const panel of this.panels.values()) {
|
|
235
|
+
for (const [path, shortcut] of Object.entries(panel.shortcuts)) {
|
|
236
|
+
if (!shortcut.key) continue;
|
|
237
|
+
if (shortcut.key.toLowerCase() !== key.toLowerCase()) continue;
|
|
238
|
+
const scMod = shortcut.modifier ?? void 0;
|
|
239
|
+
if (scMod !== modifier) continue;
|
|
240
|
+
const control = this.findControlByPath(panel.controls, path);
|
|
241
|
+
if (control) {
|
|
242
|
+
return { panelId: panel.id, path, control };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
resolveScrollOnlyTargets() {
|
|
249
|
+
const results = [];
|
|
250
|
+
for (const panel of this.panels.values()) {
|
|
251
|
+
for (const [path, shortcut] of Object.entries(panel.shortcuts)) {
|
|
252
|
+
if ((shortcut.interaction ?? "scroll") !== "scroll-only") continue;
|
|
253
|
+
const control = this.findControlByPath(panel.controls, path);
|
|
254
|
+
if (control) {
|
|
255
|
+
results.push({ panelId: panel.id, path, control, shortcut });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return results;
|
|
260
|
+
}
|
|
261
|
+
findControlByPath(controls, path) {
|
|
262
|
+
for (const control of controls) {
|
|
263
|
+
if (control.path === path) return control;
|
|
264
|
+
if (control.type === "folder" && control.children) {
|
|
265
|
+
const found = this.findControlByPath(control.children, path);
|
|
266
|
+
if (found) return found;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
notify(panelId) {
|
|
272
|
+
this.listeners.get(panelId)?.forEach((fn) => fn());
|
|
273
|
+
}
|
|
274
|
+
notifyGlobal() {
|
|
275
|
+
this.globalListeners.forEach((fn) => fn());
|
|
276
|
+
}
|
|
277
|
+
initTransitionModes(config, prefix, values) {
|
|
278
|
+
for (const [key, value] of Object.entries(config)) {
|
|
279
|
+
if (key === "_collapsed") continue;
|
|
280
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
281
|
+
if (this.isEasingConfig(value)) {
|
|
282
|
+
values[`${path}.__mode`] = "easing";
|
|
283
|
+
} else if (this.isSpringConfig(value)) {
|
|
284
|
+
const hasPhysics = value.stiffness !== void 0 || value.damping !== void 0 || value.mass !== void 0;
|
|
285
|
+
const hasTime = value.visualDuration !== void 0 || value.bounce !== void 0;
|
|
286
|
+
values[`${path}.__mode`] = hasPhysics && !hasTime ? "advanced" : "simple";
|
|
287
|
+
} else if (typeof value === "object" && value !== null && !Array.isArray(value) && !this.isActionConfig(value) && !this.isSelectConfig(value) && !this.isColorConfig(value) && !this.isTextConfig(value)) {
|
|
288
|
+
this.initTransitionModes(value, path, values);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
parseConfig(config, prefix, shortcuts) {
|
|
293
|
+
const controls = [];
|
|
294
|
+
for (const [key, value] of Object.entries(config)) {
|
|
295
|
+
if (key === "_collapsed") continue;
|
|
296
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
297
|
+
const label = this.formatLabel(key);
|
|
298
|
+
const shortcut = shortcuts?.[path];
|
|
299
|
+
if (Array.isArray(value) && value.length <= 4 && typeof value[0] === "number") {
|
|
300
|
+
controls.push({
|
|
301
|
+
type: "slider",
|
|
302
|
+
path,
|
|
303
|
+
label,
|
|
304
|
+
min: value[1],
|
|
305
|
+
max: value[2],
|
|
306
|
+
step: value[3] ?? this.inferStep(value[1], value[2]),
|
|
307
|
+
shortcut
|
|
308
|
+
});
|
|
309
|
+
} else if (typeof value === "number") {
|
|
310
|
+
const { min, max, step } = this.inferRange(value);
|
|
311
|
+
controls.push({ type: "slider", path, label, min, max, step, shortcut });
|
|
312
|
+
} else if (typeof value === "boolean") {
|
|
313
|
+
controls.push({ type: "toggle", path, label, shortcut });
|
|
314
|
+
} else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
|
|
315
|
+
controls.push({ type: "transition", path, label });
|
|
316
|
+
} else if (this.isActionConfig(value)) {
|
|
317
|
+
controls.push({ type: "action", path, label: value.label || label });
|
|
318
|
+
} else if (this.isSelectConfig(value)) {
|
|
319
|
+
controls.push({ type: "select", path, label, options: value.options });
|
|
320
|
+
} else if (this.isColorConfig(value)) {
|
|
321
|
+
controls.push({ type: "color", path, label });
|
|
322
|
+
} else if (this.isTextConfig(value)) {
|
|
323
|
+
controls.push({ type: "text", path, label, placeholder: value.placeholder });
|
|
324
|
+
} else if (typeof value === "string") {
|
|
325
|
+
if (this.isHexColor(value)) {
|
|
326
|
+
controls.push({ type: "color", path, label });
|
|
327
|
+
} else {
|
|
328
|
+
controls.push({ type: "text", path, label });
|
|
329
|
+
}
|
|
330
|
+
} else if (typeof value === "object" && value !== null) {
|
|
331
|
+
const folderConfig = value;
|
|
332
|
+
const defaultOpen = "_collapsed" in folderConfig ? !folderConfig._collapsed : true;
|
|
333
|
+
controls.push({
|
|
334
|
+
type: "folder",
|
|
335
|
+
path,
|
|
336
|
+
label,
|
|
337
|
+
defaultOpen,
|
|
338
|
+
children: this.parseConfig(folderConfig, path, shortcuts)
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return controls;
|
|
343
|
+
}
|
|
344
|
+
flattenValues(config, prefix) {
|
|
345
|
+
const values = {};
|
|
346
|
+
for (const [key, value] of Object.entries(config)) {
|
|
347
|
+
if (key === "_collapsed") continue;
|
|
348
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
349
|
+
if (Array.isArray(value) && value.length <= 4 && typeof value[0] === "number") {
|
|
350
|
+
values[path] = value[0];
|
|
351
|
+
} else if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
|
|
352
|
+
values[path] = value;
|
|
353
|
+
} else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {
|
|
354
|
+
values[path] = value;
|
|
355
|
+
} else if (this.isActionConfig(value)) {
|
|
356
|
+
values[path] = value;
|
|
357
|
+
} else if (this.isSelectConfig(value)) {
|
|
358
|
+
const firstOption = value.options[0];
|
|
359
|
+
const firstValue = typeof firstOption === "string" ? firstOption : firstOption.value;
|
|
360
|
+
values[path] = value.default ?? firstValue;
|
|
361
|
+
} else if (this.isColorConfig(value)) {
|
|
362
|
+
values[path] = value.default ?? "#000000";
|
|
363
|
+
} else if (this.isTextConfig(value)) {
|
|
364
|
+
values[path] = value.default ?? "";
|
|
365
|
+
} else if (typeof value === "object" && value !== null) {
|
|
366
|
+
Object.assign(values, this.flattenValues(value, path));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return values;
|
|
370
|
+
}
|
|
371
|
+
isSpringConfig(value) {
|
|
372
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "spring";
|
|
373
|
+
}
|
|
374
|
+
isEasingConfig(value) {
|
|
375
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "easing";
|
|
376
|
+
}
|
|
377
|
+
isActionConfig(value) {
|
|
378
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "action";
|
|
379
|
+
}
|
|
380
|
+
isSelectConfig(value) {
|
|
381
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "select" && "options" in value && Array.isArray(value.options);
|
|
382
|
+
}
|
|
383
|
+
isColorConfig(value) {
|
|
384
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "color";
|
|
385
|
+
}
|
|
386
|
+
isTextConfig(value) {
|
|
387
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "text";
|
|
388
|
+
}
|
|
389
|
+
isHexColor(value) {
|
|
390
|
+
return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(value);
|
|
391
|
+
}
|
|
392
|
+
formatLabel(key) {
|
|
393
|
+
return key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
|
|
394
|
+
}
|
|
395
|
+
inferRange(value) {
|
|
396
|
+
if (value >= 0 && value <= 1) {
|
|
397
|
+
return { min: 0, max: 1, step: 0.01 };
|
|
398
|
+
} else if (value >= 0 && value <= 10) {
|
|
399
|
+
return { min: 0, max: value * 3 || 10, step: 0.1 };
|
|
400
|
+
} else if (value >= 0 && value <= 100) {
|
|
401
|
+
return { min: 0, max: value * 3 || 100, step: 1 };
|
|
402
|
+
} else if (value >= 0) {
|
|
403
|
+
return { min: 0, max: value * 3 || 1e3, step: 10 };
|
|
404
|
+
} else {
|
|
405
|
+
return { min: value * 3, max: -value * 3, step: 1 };
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
inferStep(min, max) {
|
|
409
|
+
const range = max - min;
|
|
410
|
+
if (range <= 1) return 0.01;
|
|
411
|
+
if (range <= 10) return 0.1;
|
|
412
|
+
if (range <= 100) return 1;
|
|
413
|
+
return 10;
|
|
414
|
+
}
|
|
415
|
+
normalizePreservedValue(existingValue, defaultValue, control) {
|
|
416
|
+
if (existingValue === void 0 || !control) {
|
|
417
|
+
return defaultValue;
|
|
418
|
+
}
|
|
419
|
+
switch (control.type) {
|
|
420
|
+
case "slider": {
|
|
421
|
+
if (typeof existingValue !== "number" || typeof defaultValue !== "number") {
|
|
422
|
+
return defaultValue;
|
|
423
|
+
}
|
|
424
|
+
const min = control.min ?? Number.NEGATIVE_INFINITY;
|
|
425
|
+
const max = control.max ?? Number.POSITIVE_INFINITY;
|
|
426
|
+
const clamped = Math.min(max, Math.max(min, existingValue));
|
|
427
|
+
if (typeof control.step !== "number" || control.step <= 0) {
|
|
428
|
+
return clamped;
|
|
429
|
+
}
|
|
430
|
+
return this.roundToStep(clamped, min, max, control.step);
|
|
431
|
+
}
|
|
432
|
+
case "toggle":
|
|
433
|
+
return typeof existingValue === "boolean" ? existingValue : defaultValue;
|
|
434
|
+
case "select": {
|
|
435
|
+
if (typeof existingValue !== "string") {
|
|
436
|
+
return defaultValue;
|
|
437
|
+
}
|
|
438
|
+
const options = control.options ?? [];
|
|
439
|
+
const validValues = new Set(options.map((option) => typeof option === "string" ? option : option.value));
|
|
440
|
+
return validValues.has(existingValue) ? existingValue : defaultValue;
|
|
441
|
+
}
|
|
442
|
+
case "color":
|
|
443
|
+
case "text":
|
|
444
|
+
return typeof existingValue === "string" ? existingValue : defaultValue;
|
|
445
|
+
case "transition":
|
|
446
|
+
if (this.isSpringConfig(defaultValue)) {
|
|
447
|
+
return this.isSpringConfig(existingValue) ? existingValue : defaultValue;
|
|
448
|
+
}
|
|
449
|
+
if (this.isEasingConfig(defaultValue)) {
|
|
450
|
+
return this.isEasingConfig(existingValue) ? existingValue : defaultValue;
|
|
451
|
+
}
|
|
452
|
+
return defaultValue;
|
|
453
|
+
case "action":
|
|
454
|
+
return defaultValue;
|
|
455
|
+
default:
|
|
456
|
+
return defaultValue;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
roundToStep(value, min, max, step) {
|
|
460
|
+
const snapped = min + Math.round((value - min) / step) * step;
|
|
461
|
+
const clamped = Math.min(max, Math.max(min, snapped));
|
|
462
|
+
const precision = this.stepPrecision(step);
|
|
463
|
+
return Number(clamped.toFixed(precision));
|
|
464
|
+
}
|
|
465
|
+
stepPrecision(step) {
|
|
466
|
+
const text = String(step);
|
|
467
|
+
const decimalIndex = text.indexOf(".");
|
|
468
|
+
return decimalIndex === -1 ? 0 : text.length - decimalIndex - 1;
|
|
469
|
+
}
|
|
470
|
+
mapControlsByPath(controls) {
|
|
471
|
+
const map = /* @__PURE__ */ new Map();
|
|
472
|
+
const visit = (nodes) => {
|
|
473
|
+
for (const node of nodes) {
|
|
474
|
+
if (node.type === "folder" && node.children) {
|
|
475
|
+
visit(node.children);
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
map.set(node.path, node);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
visit(controls);
|
|
482
|
+
return map;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
var DialStore = new DialStoreClass();
|
|
486
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
487
|
+
0 && (module.exports = {
|
|
488
|
+
DialStore
|
|
489
|
+
});
|
|
490
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/store/DialStore.ts"],"sourcesContent":["// Lightweight state store with subscriptions for dialkit\n\nexport type SpringConfig = {\n type: 'spring';\n stiffness?: number;\n damping?: number;\n mass?: number;\n visualDuration?: number;\n bounce?: number;\n};\n\nexport type EasingConfig = {\n type: 'easing';\n duration: number;\n ease: [number, number, number, number];\n};\n\nexport type TransitionConfig = SpringConfig | EasingConfig;\n\nexport type ActionConfig = {\n type: 'action';\n label?: string;\n};\n\nexport type SelectConfig = {\n type: 'select';\n options: (string | { value: string; label: string })[];\n default?: string;\n};\n\nexport type ColorConfig = {\n type: 'color';\n default?: string;\n};\n\nexport type TextConfig = {\n type: 'text';\n default?: string;\n placeholder?: string;\n};\n\nexport type DialValue = number | boolean | string | SpringConfig | EasingConfig | ActionConfig | SelectConfig | ColorConfig | TextConfig;\n\nexport type DialConfig = {\n [key: string]: DialValue | [number, number, number, number?] | DialConfig;\n};\n\nexport type ResolvedValues<T extends DialConfig> = {\n [K in keyof T]: T[K] extends [number, number, number, number?]\n ? number\n : T[K] extends SpringConfig\n ? TransitionConfig\n : T[K] extends EasingConfig\n ? TransitionConfig\n : T[K] extends SelectConfig\n ? string\n : T[K] extends ColorConfig\n ? string\n : T[K] extends TextConfig\n ? string\n : T[K] extends DialConfig\n ? ResolvedValues<T[K]>\n : T[K];\n};\n\nexport type ShortcutMode = 'fine' | 'normal' | 'coarse';\nexport type ShortcutInteraction = 'scroll' | 'drag' | 'move' | 'scroll-only';\n\nexport type ShortcutConfig = {\n key?: string;\n modifier?: 'alt' | 'shift' | 'meta';\n mode?: ShortcutMode;\n interaction?: ShortcutInteraction;\n};\n\nexport type ControlMeta = {\n type: 'slider' | 'toggle' | 'spring' | 'transition' | 'folder' | 'action' | 'select' | 'color' | 'text';\n path: string;\n label: string;\n min?: number;\n max?: number;\n step?: number;\n children?: ControlMeta[];\n defaultOpen?: boolean;\n options?: (string | { value: string; label: string })[];\n placeholder?: string;\n shortcut?: ShortcutConfig;\n};\n\nexport type PanelConfig = {\n id: string;\n name: string;\n controls: ControlMeta[];\n values: Record<string, DialValue>;\n shortcuts: Record<string, ShortcutConfig>;\n};\n\ntype Listener = () => void;\ntype ActionListener = (action: string) => void;\n\nexport type Preset = {\n id: string;\n name: string;\n values: Record<string, DialValue>;\n};\n\n// Stable empty object for unregistered panels (React 19 useSyncExternalStore requirement)\nconst EMPTY_VALUES: Record<string, DialValue> = Object.freeze({});\n\nclass DialStoreClass {\n private panels: Map<string, PanelConfig> = new Map();\n private listeners: Map<string, Set<Listener>> = new Map();\n private globalListeners: Set<Listener> = new Set();\n private snapshots: Map<string, Record<string, DialValue>> = new Map();\n private actionListeners: Map<string, Set<ActionListener>> = new Map();\n private presets: Map<string, Preset[]> = new Map();\n private activePreset: Map<string, string | null> = new Map();\n private baseValues: Map<string, Record<string, DialValue>> = new Map();\n\n registerPanel(id: string, name: string, config: DialConfig, shortcuts?: Record<string, ShortcutConfig>): void {\n const controls = this.parseConfig(config, '', shortcuts);\n const values = this.flattenValues(config, '');\n\n // Set initial transition modes based on config types\n this.initTransitionModes(config, '', values);\n\n this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {} });\n this.snapshots.set(id, { ...values });\n this.baseValues.set(id, { ...values });\n this.notifyGlobal();\n }\n\n updatePanel(id: string, name: string, config: DialConfig, shortcuts?: Record<string, ShortcutConfig>): void {\n const existing = this.panels.get(id);\n if (!existing) {\n this.registerPanel(id, name, config, shortcuts);\n return;\n }\n\n const controls = this.parseConfig(config, '', shortcuts);\n const controlsByPath = this.mapControlsByPath(controls);\n const defaultValues = this.flattenValues(config, '');\n const nextValues: Record<string, DialValue> = {};\n\n for (const [path, defaultValue] of Object.entries(defaultValues)) {\n nextValues[path] = this.normalizePreservedValue(\n existing.values[path],\n defaultValue,\n controlsByPath.get(path)\n );\n }\n\n // Set mode defaults for new transition controls first.\n this.initTransitionModes(config, '', nextValues);\n\n for (const [path, mode] of Object.entries(existing.values)) {\n if (!path.endsWith('.__mode')) {\n continue;\n }\n\n const transitionPath = path.slice(0, -'__mode'.length - 1);\n const transitionControl = controlsByPath.get(transitionPath);\n if (transitionControl?.type === 'transition') {\n nextValues[path] = mode;\n }\n }\n\n const nextPanel: PanelConfig = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts };\n this.panels.set(id, nextPanel);\n this.snapshots.set(id, { ...nextValues });\n\n const previousBaseValues = this.baseValues.get(id) ?? {};\n const nextBaseValues: Record<string, DialValue> = {};\n for (const [path, defaultValue] of Object.entries(defaultValues)) {\n nextBaseValues[path] = this.normalizePreservedValue(\n previousBaseValues[path],\n defaultValue,\n controlsByPath.get(path)\n );\n }\n\n for (const [path, value] of Object.entries(nextValues)) {\n if (path.endsWith('.__mode')) {\n nextBaseValues[path] = value;\n }\n }\n\n this.baseValues.set(id, nextBaseValues);\n\n this.notify(id);\n this.notifyGlobal();\n }\n\n unregisterPanel(id: string): void {\n this.panels.delete(id);\n this.listeners.delete(id);\n this.snapshots.delete(id);\n this.actionListeners.delete(id);\n this.baseValues.delete(id);\n this.notifyGlobal();\n }\n\n updateValue(panelId: string, path: string, value: DialValue): void {\n const panel = this.panels.get(panelId);\n if (!panel) return;\n\n panel.values[path] = value;\n\n // Auto-save to active preset or base values\n const activeId = this.activePreset.get(panelId);\n if (activeId) {\n const presets = this.presets.get(panelId) ?? [];\n const preset = presets.find(p => p.id === activeId);\n if (preset) preset.values[path] = value;\n } else {\n const base = this.baseValues.get(panelId);\n if (base) base[path] = value;\n }\n\n // Create a new snapshot reference so useSyncExternalStore detects the change\n this.snapshots.set(panelId, { ...panel.values });\n this.notify(panelId);\n }\n\n updateSpringMode(panelId: string, path: string, mode: 'simple' | 'advanced'): void {\n this.updateTransitionMode(panelId, path, mode);\n }\n\n getSpringMode(panelId: string, path: string): 'simple' | 'advanced' {\n const mode = this.getTransitionMode(panelId, path);\n if (mode === 'easing') return 'simple';\n return mode;\n }\n\n updateTransitionMode(panelId: string, path: string, mode: 'easing' | 'simple' | 'advanced'): void {\n const panel = this.panels.get(panelId);\n if (!panel) return;\n\n panel.values[`${path}.__mode`] = mode;\n this.snapshots.set(panelId, { ...panel.values });\n this.notify(panelId);\n }\n\n getTransitionMode(panelId: string, path: string): 'easing' | 'simple' | 'advanced' {\n const panel = this.panels.get(panelId);\n if (!panel) return 'simple';\n return (panel.values[`${path}.__mode`] as 'easing' | 'simple' | 'advanced') || 'simple';\n }\n\n getValue(panelId: string, path: string): DialValue | undefined {\n const panel = this.panels.get(panelId);\n return panel?.values[path];\n }\n\n getValues(panelId: string): Record<string, DialValue> {\n // Return the snapshot for useSyncExternalStore compatibility\n // Use stable EMPTY_VALUES to avoid infinite loop in React 19\n return this.snapshots.get(panelId) ?? EMPTY_VALUES;\n }\n\n getPanels(): PanelConfig[] {\n return Array.from(this.panels.values());\n }\n\n getPanel(id: string): PanelConfig | undefined {\n return this.panels.get(id);\n }\n\n subscribe(panelId: string, listener: Listener): () => void {\n if (!this.listeners.has(panelId)) {\n this.listeners.set(panelId, new Set());\n }\n this.listeners.get(panelId)!.add(listener);\n\n return () => {\n this.listeners.get(panelId)?.delete(listener);\n };\n }\n\n subscribeGlobal(listener: Listener): () => void {\n this.globalListeners.add(listener);\n return () => this.globalListeners.delete(listener);\n }\n\n subscribeActions(panelId: string, listener: ActionListener): () => void {\n if (!this.actionListeners.has(panelId)) {\n this.actionListeners.set(panelId, new Set());\n }\n this.actionListeners.get(panelId)!.add(listener);\n\n return () => {\n this.actionListeners.get(panelId)?.delete(listener);\n };\n }\n\n triggerAction(panelId: string, path: string): void {\n this.actionListeners.get(panelId)?.forEach(fn => fn(path));\n }\n\n savePreset(panelId: string, name: string): string {\n const panel = this.panels.get(panelId);\n if (!panel) throw new Error(`Panel ${panelId} not found`);\n\n const id = `preset-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n const preset: Preset = {\n id,\n name,\n values: { ...panel.values },\n };\n\n const existing = this.presets.get(panelId) ?? [];\n this.presets.set(panelId, [...existing, preset]);\n this.activePreset.set(panelId, id);\n\n // Force re-render by creating new snapshot reference\n this.snapshots.set(panelId, { ...panel.values });\n this.notify(panelId);\n\n return id;\n }\n\n loadPreset(panelId: string, presetId: string): void {\n const panel = this.panels.get(panelId);\n if (!panel) return;\n\n const presets = this.presets.get(panelId) ?? [];\n const preset = presets.find(p => p.id === presetId);\n if (!preset) return;\n\n // Apply preset values\n panel.values = { ...preset.values };\n this.snapshots.set(panelId, { ...panel.values });\n this.activePreset.set(panelId, presetId);\n this.notify(panelId);\n }\n\n deletePreset(panelId: string, presetId: string): void {\n const presets = this.presets.get(panelId) ?? [];\n this.presets.set(panelId, presets.filter(p => p.id !== presetId));\n\n // Clear active if deleted\n if (this.activePreset.get(panelId) === presetId) {\n this.activePreset.set(panelId, null);\n }\n\n // Force re-render by creating new snapshot reference\n const panel = this.panels.get(panelId);\n if (panel) {\n this.snapshots.set(panelId, { ...panel.values });\n }\n this.notify(panelId);\n }\n\n getPresets(panelId: string): Preset[] {\n return this.presets.get(panelId) ?? [];\n }\n\n getActivePresetId(panelId: string): string | null {\n return this.activePreset.get(panelId) ?? null;\n }\n\n clearActivePreset(panelId: string): void {\n const panel = this.panels.get(panelId);\n const base = this.baseValues.get(panelId);\n if (panel && base) {\n panel.values = { ...base };\n this.snapshots.set(panelId, { ...panel.values });\n }\n this.activePreset.set(panelId, null);\n this.notify(panelId);\n }\n\n resolveShortcutTarget(key: string, modifier?: 'alt' | 'shift' | 'meta'): {\n panelId: string;\n path: string;\n control: ControlMeta;\n } | null {\n for (const panel of this.panels.values()) {\n for (const [path, shortcut] of Object.entries(panel.shortcuts)) {\n if (!shortcut.key) continue; // skip keyless shortcuts\n if (shortcut.key.toLowerCase() !== key.toLowerCase()) continue;\n const scMod = shortcut.modifier ?? undefined;\n if (scMod !== modifier) continue;\n\n const control = this.findControlByPath(panel.controls, path);\n if (control) {\n return { panelId: panel.id, path, control };\n }\n }\n }\n return null;\n }\n\n resolveScrollOnlyTargets(): Array<{\n panelId: string;\n path: string;\n control: ControlMeta;\n shortcut: ShortcutConfig;\n }> {\n const results: Array<{ panelId: string; path: string; control: ControlMeta; shortcut: ShortcutConfig }> = [];\n for (const panel of this.panels.values()) {\n for (const [path, shortcut] of Object.entries(panel.shortcuts)) {\n if ((shortcut.interaction ?? 'scroll') !== 'scroll-only') continue;\n const control = this.findControlByPath(panel.controls, path);\n if (control) {\n results.push({ panelId: panel.id, path, control, shortcut });\n }\n }\n }\n return results;\n }\n\n private findControlByPath(controls: ControlMeta[], path: string): ControlMeta | null {\n for (const control of controls) {\n if (control.path === path) return control;\n if (control.type === 'folder' && control.children) {\n const found = this.findControlByPath(control.children, path);\n if (found) return found;\n }\n }\n return null;\n }\n\n private notify(panelId: string): void {\n this.listeners.get(panelId)?.forEach(fn => fn());\n }\n\n private notifyGlobal(): void {\n this.globalListeners.forEach(fn => fn());\n }\n\n private initTransitionModes(config: DialConfig, prefix: string, values: Record<string, DialValue>): void {\n for (const [key, value] of Object.entries(config)) {\n if (key === '_collapsed') continue;\n const path = prefix ? `${prefix}.${key}` : key;\n\n if (this.isEasingConfig(value)) {\n values[`${path}.__mode`] = 'easing';\n } else if (this.isSpringConfig(value)) {\n // Detect physics mode from config\n const hasPhysics = value.stiffness !== undefined || value.damping !== undefined || value.mass !== undefined;\n const hasTime = value.visualDuration !== undefined || value.bounce !== undefined;\n values[`${path}.__mode`] = hasPhysics && !hasTime ? 'advanced' : 'simple';\n } else if (typeof value === 'object' && value !== null && !Array.isArray(value) && !this.isActionConfig(value) && !this.isSelectConfig(value) && !this.isColorConfig(value) && !this.isTextConfig(value)) {\n this.initTransitionModes(value as DialConfig, path, values);\n }\n }\n }\n\n private parseConfig(config: DialConfig, prefix: string, shortcuts?: Record<string, ShortcutConfig>): ControlMeta[] {\n const controls: ControlMeta[] = [];\n\n for (const [key, value] of Object.entries(config)) {\n if (key === '_collapsed') continue;\n const path = prefix ? `${prefix}.${key}` : key;\n const label = this.formatLabel(key);\n const shortcut = shortcuts?.[path];\n\n if (Array.isArray(value) && value.length <= 4 && typeof value[0] === 'number') {\n // Range tuple: [default, min, max]\n controls.push({\n type: 'slider',\n path,\n label,\n min: value[1],\n max: value[2],\n step: value[3] ?? this.inferStep(value[1], value[2]),\n shortcut,\n });\n } else if (typeof value === 'number') {\n // Single number - auto-infer range\n const { min, max, step } = this.inferRange(value);\n controls.push({ type: 'slider', path, label, min, max, step, shortcut });\n } else if (typeof value === 'boolean') {\n controls.push({ type: 'toggle', path, label, shortcut });\n } else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {\n controls.push({ type: 'transition', path, label });\n } else if (this.isActionConfig(value)) {\n controls.push({ type: 'action', path, label: (value as ActionConfig).label || label });\n } else if (this.isSelectConfig(value)) {\n controls.push({ type: 'select', path, label, options: value.options });\n } else if (this.isColorConfig(value)) {\n controls.push({ type: 'color', path, label });\n } else if (this.isTextConfig(value)) {\n controls.push({ type: 'text', path, label, placeholder: value.placeholder });\n } else if (typeof value === 'string') {\n // Auto-detect: hex color vs text\n if (this.isHexColor(value)) {\n controls.push({ type: 'color', path, label });\n } else {\n controls.push({ type: 'text', path, label });\n }\n } else if (typeof value === 'object' && value !== null) {\n // Nested object becomes a folder\n const folderConfig = value as DialConfig;\n const defaultOpen = '_collapsed' in folderConfig ? !(folderConfig._collapsed as boolean) : true;\n controls.push({\n type: 'folder',\n path,\n label,\n defaultOpen,\n children: this.parseConfig(folderConfig, path, shortcuts),\n });\n }\n }\n\n return controls;\n }\n\n private flattenValues(config: DialConfig, prefix: string): Record<string, DialValue> {\n const values: Record<string, DialValue> = {};\n\n for (const [key, value] of Object.entries(config)) {\n if (key === '_collapsed') continue;\n const path = prefix ? `${prefix}.${key}` : key;\n\n if (Array.isArray(value) && value.length <= 4 && typeof value[0] === 'number') {\n values[path] = value[0]; // Default value\n } else if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'string') {\n values[path] = value;\n } else if (this.isSpringConfig(value) || this.isEasingConfig(value)) {\n values[path] = value;\n } else if (this.isActionConfig(value)) {\n // Actions don't need stored values - they're just triggers\n values[path] = value;\n } else if (this.isSelectConfig(value)) {\n // Use default or first option's value\n const firstOption = value.options[0];\n const firstValue = typeof firstOption === 'string' ? firstOption : firstOption.value;\n values[path] = value.default ?? firstValue;\n } else if (this.isColorConfig(value)) {\n values[path] = value.default ?? '#000000';\n } else if (this.isTextConfig(value)) {\n values[path] = value.default ?? '';\n } else if (typeof value === 'object' && value !== null) {\n Object.assign(values, this.flattenValues(value as DialConfig, path));\n }\n }\n\n return values;\n }\n\n private isSpringConfig(value: unknown): value is SpringConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as SpringConfig).type === 'spring'\n );\n }\n\n private isEasingConfig(value: unknown): value is EasingConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as EasingConfig).type === 'easing'\n );\n }\n\n private isActionConfig(value: unknown): value is ActionConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as ActionConfig).type === 'action'\n );\n }\n\n private isSelectConfig(value: unknown): value is SelectConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as SelectConfig).type === 'select' &&\n 'options' in value &&\n Array.isArray((value as SelectConfig).options)\n );\n }\n\n private isColorConfig(value: unknown): value is ColorConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as ColorConfig).type === 'color'\n );\n }\n\n private isTextConfig(value: unknown): value is TextConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as TextConfig).type === 'text'\n );\n }\n\n private isHexColor(value: string): boolean {\n return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(value);\n }\n\n private formatLabel(key: string): string {\n // Convert camelCase to Title Case\n return key\n .replace(/([A-Z])/g, ' $1')\n .replace(/^./, str => str.toUpperCase())\n .trim();\n }\n\n private inferRange(value: number): { min: number; max: number; step: number } {\n // Infer reasonable range based on value\n if (value >= 0 && value <= 1) {\n return { min: 0, max: 1, step: 0.01 };\n } else if (value >= 0 && value <= 10) {\n return { min: 0, max: value * 3 || 10, step: 0.1 };\n } else if (value >= 0 && value <= 100) {\n return { min: 0, max: value * 3 || 100, step: 1 };\n } else if (value >= 0) {\n return { min: 0, max: value * 3 || 1000, step: 10 };\n } else {\n return { min: value * 3, max: -value * 3, step: 1 };\n }\n }\n\n private inferStep(min: number, max: number): number {\n const range = max - min;\n if (range <= 1) return 0.01;\n if (range <= 10) return 0.1;\n if (range <= 100) return 1;\n return 10;\n }\n\n private normalizePreservedValue(\n existingValue: DialValue | undefined,\n defaultValue: DialValue,\n control: ControlMeta | undefined\n ): DialValue {\n if (existingValue === undefined || !control) {\n return defaultValue;\n }\n\n switch (control.type) {\n case 'slider': {\n if (typeof existingValue !== 'number' || typeof defaultValue !== 'number') {\n return defaultValue;\n }\n\n const min = control.min ?? Number.NEGATIVE_INFINITY;\n const max = control.max ?? Number.POSITIVE_INFINITY;\n const clamped = Math.min(max, Math.max(min, existingValue));\n\n if (typeof control.step !== 'number' || control.step <= 0) {\n return clamped;\n }\n\n return this.roundToStep(clamped, min, max, control.step);\n }\n case 'toggle':\n return typeof existingValue === 'boolean' ? existingValue : defaultValue;\n case 'select': {\n if (typeof existingValue !== 'string') {\n return defaultValue;\n }\n\n const options = control.options ?? [];\n const validValues = new Set(options.map((option) => (typeof option === 'string' ? option : option.value)));\n return validValues.has(existingValue) ? existingValue : defaultValue;\n }\n case 'color':\n case 'text':\n return typeof existingValue === 'string' ? existingValue : defaultValue;\n case 'transition':\n if (this.isSpringConfig(defaultValue)) {\n return this.isSpringConfig(existingValue) ? existingValue : defaultValue;\n }\n if (this.isEasingConfig(defaultValue)) {\n return this.isEasingConfig(existingValue) ? existingValue : defaultValue;\n }\n return defaultValue;\n case 'action':\n return defaultValue;\n default:\n return defaultValue;\n }\n }\n\n private roundToStep(value: number, min: number, max: number, step: number): number {\n const snapped = min + Math.round((value - min) / step) * step;\n const clamped = Math.min(max, Math.max(min, snapped));\n const precision = this.stepPrecision(step);\n return Number(clamped.toFixed(precision));\n }\n\n private stepPrecision(step: number): number {\n const text = String(step);\n const decimalIndex = text.indexOf('.');\n return decimalIndex === -1 ? 0 : text.length - decimalIndex - 1;\n }\n\n private mapControlsByPath(controls: ControlMeta[]): Map<string, ControlMeta> {\n const map = new Map<string, ControlMeta>();\n\n const visit = (nodes: ControlMeta[]) => {\n for (const node of nodes) {\n if (node.type === 'folder' && node.children) {\n visit(node.children);\n continue;\n }\n\n map.set(node.path, node);\n }\n };\n\n visit(controls);\n return map;\n }\n\n}\n\n// Singleton instance\nexport const DialStore = new DialStoreClass();\n"],"mappings":"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","names":[]}
|