dialkit 1.2.1 → 1.3.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 +220 -3
- package/dist/dropdown-position.d.ts +15 -0
- package/dist/dropdown-position.js +22 -0
- package/dist/dropdown-position.js.map +1 -0
- package/dist/index.cjs +697 -307
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -5
- package/dist/index.d.ts +42 -5
- package/dist/index.js +720 -331
- package/dist/index.js.map +1 -1
- package/dist/panel-drag.d.ts +19 -0
- package/dist/panel-drag.js +72 -0
- package/dist/panel-drag.js.map +1 -0
- package/dist/solid/index.cjs +661 -204
- package/dist/solid/index.cjs.map +1 -1
- package/dist/solid/index.d.cts +40 -3
- package/dist/solid/index.d.ts +40 -3
- package/dist/solid/index.js +646 -190
- package/dist/solid/index.js.map +1 -1
- package/dist/store/index.cjs +272 -41
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +30 -3
- package/dist/store/index.d.ts +30 -3
- package/dist/store/index.js +269 -40
- package/dist/store/index.js.map +1 -1
- package/dist/styles.css +105 -7
- package/dist/svelte/components/DialRoot.svelte +176 -11
- package/dist/svelte/components/DialRoot.svelte.d.ts +1 -0
- package/dist/svelte/components/DialRoot.svelte.d.ts.map +1 -1
- package/dist/svelte/components/Folder.svelte +24 -13
- package/dist/svelte/components/Folder.svelte.d.ts +1 -0
- package/dist/svelte/components/Folder.svelte.d.ts.map +1 -1
- package/dist/svelte/components/Panel.svelte +98 -71
- package/dist/svelte/components/Panel.svelte.d.ts +2 -0
- package/dist/svelte/components/Panel.svelte.d.ts.map +1 -1
- package/dist/svelte/components/PresetManager.svelte +5 -5
- package/dist/svelte/components/PresetManager.svelte.d.ts.map +1 -1
- package/dist/svelte/components/SelectControl.svelte +6 -14
- package/dist/svelte/components/SelectControl.svelte.d.ts.map +1 -1
- package/dist/svelte/createDialKit.svelte.d.ts +11 -1
- package/dist/svelte/createDialKit.svelte.d.ts.map +1 -1
- package/dist/svelte/createDialKit.svelte.js +61 -34
- package/dist/svelte/index.d.ts +3 -3
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +1 -1
- package/dist/svelte/theme-css.d.ts +1 -1
- package/dist/svelte/theme-css.d.ts.map +1 -1
- package/dist/svelte/theme-css.js +105 -7
- package/dist/vue/index.cjs +573 -132
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.d.cts +53 -6
- package/dist/vue/index.d.ts +53 -6
- package/dist/vue/index.js +573 -133
- package/dist/vue/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,8 @@ __export(index_exports, {
|
|
|
36
36
|
TextControl: () => TextControl,
|
|
37
37
|
Toggle: () => Toggle,
|
|
38
38
|
TransitionControl: () => TransitionControl,
|
|
39
|
-
useDialKit: () => useDialKit
|
|
39
|
+
useDialKit: () => useDialKit,
|
|
40
|
+
useDialKitController: () => useDialKitController
|
|
40
41
|
});
|
|
41
42
|
module.exports = __toCommonJS(index_exports);
|
|
42
43
|
|
|
@@ -45,6 +46,89 @@ var import_react = require("react");
|
|
|
45
46
|
|
|
46
47
|
// src/store/DialStore.ts
|
|
47
48
|
var EMPTY_VALUES = Object.freeze({});
|
|
49
|
+
function resolveDialValues(config, flatValues) {
|
|
50
|
+
return resolveConfigValues(config, flatValues, "");
|
|
51
|
+
}
|
|
52
|
+
function flattenDialValueUpdates(config, updates) {
|
|
53
|
+
const values = {};
|
|
54
|
+
if (typeof updates === "object" && updates !== null) {
|
|
55
|
+
flattenConfigUpdates(config, updates, "", values);
|
|
56
|
+
}
|
|
57
|
+
return values;
|
|
58
|
+
}
|
|
59
|
+
function resolveConfigValues(config, flatValues, prefix) {
|
|
60
|
+
const result = {};
|
|
61
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
62
|
+
if (key === "_collapsed") continue;
|
|
63
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
64
|
+
if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
|
|
65
|
+
result[key] = flatValues[path] ?? configValue[0];
|
|
66
|
+
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
67
|
+
result[key] = flatValues[path] ?? configValue;
|
|
68
|
+
} else if (isSpringConfigValue(configValue) || isEasingConfigValue(configValue)) {
|
|
69
|
+
result[key] = flatValues[path] ?? configValue;
|
|
70
|
+
} else if (isActionConfigValue(configValue)) {
|
|
71
|
+
result[key] = flatValues[path] ?? configValue;
|
|
72
|
+
} else if (isSelectConfigValue(configValue)) {
|
|
73
|
+
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
74
|
+
result[key] = flatValues[path] ?? defaultValue;
|
|
75
|
+
} else if (isColorConfigValue(configValue)) {
|
|
76
|
+
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
77
|
+
} else if (isTextConfigValue(configValue)) {
|
|
78
|
+
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
79
|
+
} else if (typeof configValue === "object" && configValue !== null) {
|
|
80
|
+
result[key] = resolveConfigValues(configValue, flatValues, path);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
function flattenConfigUpdates(config, updates, prefix, values) {
|
|
86
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
87
|
+
if (key === "_collapsed" || !(key in updates)) continue;
|
|
88
|
+
const nextValue = updates[key];
|
|
89
|
+
if (nextValue === void 0) continue;
|
|
90
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
91
|
+
if (isActionConfigValue(configValue)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (isLeafConfigValue(configValue)) {
|
|
95
|
+
values[path] = nextValue;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (typeof configValue === "object" && configValue !== null && typeof nextValue === "object" && nextValue !== null && !Array.isArray(nextValue)) {
|
|
99
|
+
flattenConfigUpdates(configValue, nextValue, path, values);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function isLeafConfigValue(value) {
|
|
104
|
+
return Array.isArray(value) && value.length <= 4 && typeof value[0] === "number" || typeof value === "number" || typeof value === "boolean" || typeof value === "string" || isSpringConfigValue(value) || isEasingConfigValue(value) || isActionConfigValue(value) || isSelectConfigValue(value) || isColorConfigValue(value) || isTextConfigValue(value);
|
|
105
|
+
}
|
|
106
|
+
function hasType(value, type) {
|
|
107
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
108
|
+
}
|
|
109
|
+
function isSpringConfigValue(value) {
|
|
110
|
+
return hasType(value, "spring");
|
|
111
|
+
}
|
|
112
|
+
function isEasingConfigValue(value) {
|
|
113
|
+
return hasType(value, "easing");
|
|
114
|
+
}
|
|
115
|
+
function isActionConfigValue(value) {
|
|
116
|
+
return hasType(value, "action");
|
|
117
|
+
}
|
|
118
|
+
function isSelectConfigValue(value) {
|
|
119
|
+
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
120
|
+
}
|
|
121
|
+
function isColorConfigValue(value) {
|
|
122
|
+
return hasType(value, "color");
|
|
123
|
+
}
|
|
124
|
+
function isTextConfigValue(value) {
|
|
125
|
+
return hasType(value, "text");
|
|
126
|
+
}
|
|
127
|
+
function getFirstOptionValue(options) {
|
|
128
|
+
const first = options[0];
|
|
129
|
+
if (first === void 0) return "";
|
|
130
|
+
return typeof first === "string" ? first : first.value;
|
|
131
|
+
}
|
|
48
132
|
var DialStoreClass = class {
|
|
49
133
|
constructor() {
|
|
50
134
|
this.panels = /* @__PURE__ */ new Map();
|
|
@@ -55,87 +139,138 @@ var DialStoreClass = class {
|
|
|
55
139
|
this.presets = /* @__PURE__ */ new Map();
|
|
56
140
|
this.activePreset = /* @__PURE__ */ new Map();
|
|
57
141
|
this.baseValues = /* @__PURE__ */ new Map();
|
|
58
|
-
|
|
59
|
-
|
|
142
|
+
this.defaultValues = /* @__PURE__ */ new Map();
|
|
143
|
+
this.registrationCounts = /* @__PURE__ */ new Map();
|
|
144
|
+
this.retainedPanels = /* @__PURE__ */ new Set();
|
|
145
|
+
this.persistConfigs = /* @__PURE__ */ new Map();
|
|
146
|
+
}
|
|
147
|
+
registerPanel(id, name, config, shortcuts, options = {}) {
|
|
148
|
+
this.configurePanelRetention(id, options);
|
|
149
|
+
this.registrationCounts.set(id, (this.registrationCounts.get(id) ?? 0) + 1);
|
|
60
150
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
61
|
-
const
|
|
62
|
-
this.
|
|
151
|
+
const controlsByPath = this.mapControlsByPath(controls);
|
|
152
|
+
const defaultValues = this.flattenValues(config, "");
|
|
153
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
154
|
+
const persisted = this.loadPersistedPanel(id);
|
|
155
|
+
const previousValues = this.panels.get(id)?.values ?? this.snapshots.get(id) ?? persisted?.values ?? {};
|
|
156
|
+
const values = this.reconcileValues(defaultValues, previousValues, controlsByPath);
|
|
157
|
+
const previousBaseValues = this.baseValues.get(id) ?? persisted?.baseValues ?? persisted?.values ?? {};
|
|
158
|
+
const baseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
63
159
|
this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {} });
|
|
64
160
|
this.snapshots.set(id, { ...values });
|
|
65
|
-
this.baseValues.set(id,
|
|
161
|
+
this.baseValues.set(id, baseValues);
|
|
162
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
163
|
+
const existingPresets = this.presets.get(id) ?? persisted?.presets;
|
|
164
|
+
if (existingPresets) {
|
|
165
|
+
this.presets.set(id, this.reconcilePresets(existingPresets, defaultValues, controlsByPath));
|
|
166
|
+
}
|
|
167
|
+
if (!this.activePreset.has(id) && persisted?.activePresetId !== void 0) {
|
|
168
|
+
this.activePreset.set(id, persisted.activePresetId);
|
|
169
|
+
}
|
|
170
|
+
this.persistPanel(id);
|
|
171
|
+
this.notify(id);
|
|
66
172
|
this.notifyGlobal();
|
|
67
173
|
}
|
|
68
|
-
updatePanel(id, name, config, shortcuts) {
|
|
174
|
+
updatePanel(id, name, config, shortcuts, options = {}) {
|
|
175
|
+
this.configurePanelRetention(id, options);
|
|
69
176
|
const existing = this.panels.get(id);
|
|
70
177
|
if (!existing) {
|
|
71
|
-
this.registerPanel(id, name, config, shortcuts);
|
|
178
|
+
this.registerPanel(id, name, config, shortcuts, options);
|
|
72
179
|
return;
|
|
73
180
|
}
|
|
74
181
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
75
182
|
const controlsByPath = this.mapControlsByPath(controls);
|
|
76
183
|
const defaultValues = this.flattenValues(config, "");
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
nextValues[path] = this.normalizePreservedValue(
|
|
80
|
-
existing.values[path],
|
|
81
|
-
defaultValue,
|
|
82
|
-
controlsByPath.get(path)
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
this.initTransitionModes(config, "", nextValues);
|
|
86
|
-
for (const [path, mode] of Object.entries(existing.values)) {
|
|
87
|
-
if (!path.endsWith(".__mode")) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
const transitionPath = path.slice(0, -"__mode".length - 1);
|
|
91
|
-
const transitionControl = controlsByPath.get(transitionPath);
|
|
92
|
-
if (transitionControl?.type === "transition") {
|
|
93
|
-
nextValues[path] = mode;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
184
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
185
|
+
const nextValues = this.reconcileValues(defaultValues, existing.values, controlsByPath);
|
|
96
186
|
const nextPanel = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts };
|
|
97
187
|
this.panels.set(id, nextPanel);
|
|
98
188
|
this.snapshots.set(id, { ...nextValues });
|
|
99
189
|
const previousBaseValues = this.baseValues.get(id) ?? {};
|
|
100
|
-
const nextBaseValues =
|
|
101
|
-
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
102
|
-
nextBaseValues[path] = this.normalizePreservedValue(
|
|
103
|
-
previousBaseValues[path],
|
|
104
|
-
defaultValue,
|
|
105
|
-
controlsByPath.get(path)
|
|
106
|
-
);
|
|
107
|
-
}
|
|
190
|
+
const nextBaseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
108
191
|
for (const [path, value] of Object.entries(nextValues)) {
|
|
109
192
|
if (path.endsWith(".__mode")) {
|
|
110
193
|
nextBaseValues[path] = value;
|
|
111
194
|
}
|
|
112
195
|
}
|
|
113
196
|
this.baseValues.set(id, nextBaseValues);
|
|
197
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
198
|
+
this.presets.set(id, this.reconcilePresets(this.presets.get(id) ?? [], defaultValues, controlsByPath));
|
|
199
|
+
this.persistPanel(id);
|
|
114
200
|
this.notify(id);
|
|
115
201
|
this.notifyGlobal();
|
|
116
202
|
}
|
|
117
203
|
unregisterPanel(id) {
|
|
204
|
+
const nextCount = (this.registrationCounts.get(id) ?? 1) - 1;
|
|
205
|
+
if (nextCount > 0) {
|
|
206
|
+
this.registrationCounts.set(id, nextCount);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
this.registrationCounts.delete(id);
|
|
118
210
|
this.panels.delete(id);
|
|
119
211
|
this.listeners.delete(id);
|
|
120
|
-
this.snapshots.delete(id);
|
|
121
212
|
this.actionListeners.delete(id);
|
|
122
|
-
this.
|
|
213
|
+
if (!this.retainedPanels.has(id)) {
|
|
214
|
+
this.snapshots.delete(id);
|
|
215
|
+
this.baseValues.delete(id);
|
|
216
|
+
this.defaultValues.delete(id);
|
|
217
|
+
this.presets.delete(id);
|
|
218
|
+
this.activePreset.delete(id);
|
|
219
|
+
this.persistConfigs.delete(id);
|
|
220
|
+
}
|
|
123
221
|
this.notifyGlobal();
|
|
124
222
|
}
|
|
125
223
|
updateValue(panelId, path, value) {
|
|
224
|
+
this.updateValues(panelId, { [path]: value });
|
|
225
|
+
}
|
|
226
|
+
updateValues(panelId, updates) {
|
|
126
227
|
const panel = this.panels.get(panelId);
|
|
127
228
|
if (!panel) return;
|
|
128
|
-
|
|
229
|
+
const validUpdates = {};
|
|
230
|
+
for (const [path, value] of Object.entries(updates)) {
|
|
231
|
+
if (!Object.prototype.hasOwnProperty.call(panel.values, path)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const control = this.findControlByPath(panel.controls, path);
|
|
235
|
+
if (control?.type === "action") {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
panel.values[path] = value;
|
|
239
|
+
validUpdates[path] = value;
|
|
240
|
+
}
|
|
241
|
+
if (Object.keys(validUpdates).length === 0) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
129
244
|
const activeId = this.activePreset.get(panelId);
|
|
130
245
|
if (activeId) {
|
|
131
246
|
const presets = this.presets.get(panelId) ?? [];
|
|
132
247
|
const preset = presets.find((p) => p.id === activeId);
|
|
133
|
-
if (preset)
|
|
248
|
+
if (preset) {
|
|
249
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
250
|
+
preset.values[path] = value;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
134
253
|
} else {
|
|
135
254
|
const base = this.baseValues.get(panelId);
|
|
136
|
-
if (base)
|
|
255
|
+
if (base) {
|
|
256
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
257
|
+
base[path] = value;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
137
260
|
}
|
|
138
261
|
this.snapshots.set(panelId, { ...panel.values });
|
|
262
|
+
this.persistPanel(panelId);
|
|
263
|
+
this.notify(panelId);
|
|
264
|
+
}
|
|
265
|
+
resetValues(panelId) {
|
|
266
|
+
const panel = this.panels.get(panelId);
|
|
267
|
+
const defaults = this.defaultValues.get(panelId);
|
|
268
|
+
if (!panel || !defaults) return;
|
|
269
|
+
panel.values = { ...defaults };
|
|
270
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
271
|
+
this.baseValues.set(panelId, { ...defaults });
|
|
272
|
+
this.activePreset.set(panelId, null);
|
|
273
|
+
this.persistPanel(panelId);
|
|
139
274
|
this.notify(panelId);
|
|
140
275
|
}
|
|
141
276
|
updateSpringMode(panelId, path, mode) {
|
|
@@ -151,6 +286,7 @@ var DialStoreClass = class {
|
|
|
151
286
|
if (!panel) return;
|
|
152
287
|
panel.values[`${path}.__mode`] = mode;
|
|
153
288
|
this.snapshots.set(panelId, { ...panel.values });
|
|
289
|
+
this.persistPanel(panelId);
|
|
154
290
|
this.notify(panelId);
|
|
155
291
|
}
|
|
156
292
|
getTransitionMode(panelId, path) {
|
|
@@ -209,6 +345,7 @@ var DialStoreClass = class {
|
|
|
209
345
|
this.presets.set(panelId, [...existing, preset]);
|
|
210
346
|
this.activePreset.set(panelId, id);
|
|
211
347
|
this.snapshots.set(panelId, { ...panel.values });
|
|
348
|
+
this.persistPanel(panelId);
|
|
212
349
|
this.notify(panelId);
|
|
213
350
|
return id;
|
|
214
351
|
}
|
|
@@ -221,6 +358,7 @@ var DialStoreClass = class {
|
|
|
221
358
|
panel.values = { ...preset.values };
|
|
222
359
|
this.snapshots.set(panelId, { ...panel.values });
|
|
223
360
|
this.activePreset.set(panelId, presetId);
|
|
361
|
+
this.persistPanel(panelId);
|
|
224
362
|
this.notify(panelId);
|
|
225
363
|
}
|
|
226
364
|
deletePreset(panelId, presetId) {
|
|
@@ -233,6 +371,7 @@ var DialStoreClass = class {
|
|
|
233
371
|
if (panel) {
|
|
234
372
|
this.snapshots.set(panelId, { ...panel.values });
|
|
235
373
|
}
|
|
374
|
+
this.persistPanel(panelId);
|
|
236
375
|
this.notify(panelId);
|
|
237
376
|
}
|
|
238
377
|
getPresets(panelId) {
|
|
@@ -249,6 +388,7 @@ var DialStoreClass = class {
|
|
|
249
388
|
this.snapshots.set(panelId, { ...panel.values });
|
|
250
389
|
}
|
|
251
390
|
this.activePreset.set(panelId, null);
|
|
391
|
+
this.persistPanel(panelId);
|
|
252
392
|
this.notify(panelId);
|
|
253
393
|
}
|
|
254
394
|
resolveShortcutTarget(key, modifier) {
|
|
@@ -279,6 +419,94 @@ var DialStoreClass = class {
|
|
|
279
419
|
}
|
|
280
420
|
return results;
|
|
281
421
|
}
|
|
422
|
+
configurePanelRetention(id, options) {
|
|
423
|
+
if (options.retainOnUnmount) {
|
|
424
|
+
this.retainedPanels.add(id);
|
|
425
|
+
}
|
|
426
|
+
const persistConfig = this.normalizePersistConfig(id, options.persist);
|
|
427
|
+
if (persistConfig) {
|
|
428
|
+
this.persistConfigs.set(id, persistConfig);
|
|
429
|
+
this.retainedPanels.add(id);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
reconcileValues(defaultValues, previousValues, controlsByPath) {
|
|
433
|
+
const nextValues = {};
|
|
434
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
435
|
+
if (path.endsWith(".__mode")) {
|
|
436
|
+
const transitionPath = path.slice(0, -".__mode".length);
|
|
437
|
+
const transitionControl = controlsByPath.get(transitionPath);
|
|
438
|
+
nextValues[path] = transitionControl?.type === "transition" && previousValues[path] !== void 0 ? previousValues[path] : defaultValue;
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
nextValues[path] = this.normalizePreservedValue(
|
|
442
|
+
previousValues[path],
|
|
443
|
+
defaultValue,
|
|
444
|
+
controlsByPath.get(path)
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
return nextValues;
|
|
448
|
+
}
|
|
449
|
+
reconcilePresets(presets, defaultValues, controlsByPath) {
|
|
450
|
+
return presets.map((preset) => ({
|
|
451
|
+
...preset,
|
|
452
|
+
values: this.reconcileValues(defaultValues, preset.values, controlsByPath)
|
|
453
|
+
}));
|
|
454
|
+
}
|
|
455
|
+
normalizePersistConfig(id, persist) {
|
|
456
|
+
if (!persist) return null;
|
|
457
|
+
const options = typeof persist === "object" ? persist : {};
|
|
458
|
+
return {
|
|
459
|
+
key: options.key ?? `dialkit:${id}`,
|
|
460
|
+
storage: options.storage ?? "localStorage",
|
|
461
|
+
presets: options.presets ?? true
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
loadPersistedPanel(id) {
|
|
465
|
+
const config = this.persistConfigs.get(id);
|
|
466
|
+
if (!config) return null;
|
|
467
|
+
const storage = this.getStorage(config.storage);
|
|
468
|
+
if (!storage) return null;
|
|
469
|
+
try {
|
|
470
|
+
const raw = storage.getItem(config.key);
|
|
471
|
+
if (!raw) return null;
|
|
472
|
+
const parsed = JSON.parse(raw);
|
|
473
|
+
if (parsed?.version !== 1 || typeof parsed !== "object") return null;
|
|
474
|
+
return parsed;
|
|
475
|
+
} catch {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
persistPanel(id) {
|
|
480
|
+
const config = this.persistConfigs.get(id);
|
|
481
|
+
if (!config) return;
|
|
482
|
+
const storage = this.getStorage(config.storage);
|
|
483
|
+
if (!storage) return;
|
|
484
|
+
const values = this.snapshots.get(id) ?? this.panels.get(id)?.values;
|
|
485
|
+
if (!values) return;
|
|
486
|
+
const state = {
|
|
487
|
+
version: 1,
|
|
488
|
+
values,
|
|
489
|
+
baseValues: this.baseValues.get(id) ?? values,
|
|
490
|
+
activePresetId: this.activePreset.get(id) ?? null
|
|
491
|
+
};
|
|
492
|
+
if (config.presets) {
|
|
493
|
+
state.presets = this.presets.get(id) ?? [];
|
|
494
|
+
}
|
|
495
|
+
try {
|
|
496
|
+
storage.setItem(config.key, JSON.stringify(state));
|
|
497
|
+
} catch {
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
getStorage(kind) {
|
|
501
|
+
if (typeof globalThis === "undefined" || !("window" in globalThis)) {
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
return kind === "sessionStorage" ? globalThis.window?.sessionStorage ?? null : globalThis.window?.localStorage ?? null;
|
|
506
|
+
} catch {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
282
510
|
findControlByPath(controls, path) {
|
|
283
511
|
for (const control of controls) {
|
|
284
512
|
if (control.path === path) return control;
|
|
@@ -507,8 +735,12 @@ var DialStore = new DialStoreClass();
|
|
|
507
735
|
|
|
508
736
|
// src/hooks/useDialKit.ts
|
|
509
737
|
function useDialKit(name, config, options) {
|
|
738
|
+
return useDialKitController(name, config, options).values;
|
|
739
|
+
}
|
|
740
|
+
function useDialKitController(name, config, options) {
|
|
510
741
|
const instanceId = (0, import_react.useId)();
|
|
511
|
-
const
|
|
742
|
+
const hasStableId = options?.id !== void 0;
|
|
743
|
+
const panelId = options?.id ?? `${name}-${instanceId}`;
|
|
512
744
|
const configRef = (0, import_react.useRef)(config);
|
|
513
745
|
const serializedConfig = JSON.stringify(config);
|
|
514
746
|
configRef.current = config;
|
|
@@ -516,93 +748,236 @@ function useDialKit(name, config, options) {
|
|
|
516
748
|
onActionRef.current = options?.onAction;
|
|
517
749
|
const shortcutsRef = (0, import_react.useRef)(options?.shortcuts);
|
|
518
750
|
shortcutsRef.current = options?.shortcuts;
|
|
751
|
+
const persistRef = (0, import_react.useRef)(options?.persist);
|
|
752
|
+
persistRef.current = options?.persist;
|
|
519
753
|
const serializedShortcuts = JSON.stringify(options?.shortcuts);
|
|
754
|
+
const serializedPersist = JSON.stringify(options?.persist);
|
|
520
755
|
(0, import_react.useEffect)(() => {
|
|
521
|
-
DialStore.registerPanel(panelId, name, configRef.current, shortcutsRef.current
|
|
756
|
+
DialStore.registerPanel(panelId, name, configRef.current, shortcutsRef.current, {
|
|
757
|
+
retainOnUnmount: hasStableId,
|
|
758
|
+
persist: persistRef.current
|
|
759
|
+
});
|
|
522
760
|
return () => DialStore.unregisterPanel(panelId);
|
|
523
|
-
}, [panelId, name]);
|
|
761
|
+
}, [hasStableId, panelId, name]);
|
|
524
762
|
const mountedRef = (0, import_react.useRef)(false);
|
|
525
763
|
(0, import_react.useEffect)(() => {
|
|
526
764
|
if (!mountedRef.current) {
|
|
527
765
|
mountedRef.current = true;
|
|
528
766
|
return;
|
|
529
767
|
}
|
|
530
|
-
DialStore.updatePanel(panelId, name, configRef.current, shortcutsRef.current
|
|
531
|
-
|
|
768
|
+
DialStore.updatePanel(panelId, name, configRef.current, shortcutsRef.current, {
|
|
769
|
+
retainOnUnmount: hasStableId,
|
|
770
|
+
persist: persistRef.current
|
|
771
|
+
});
|
|
772
|
+
}, [hasStableId, panelId, name, serializedConfig, serializedShortcuts, serializedPersist]);
|
|
532
773
|
(0, import_react.useEffect)(() => {
|
|
533
774
|
return DialStore.subscribeActions(panelId, (action) => {
|
|
534
775
|
onActionRef.current?.(action);
|
|
535
776
|
});
|
|
536
777
|
}, [panelId]);
|
|
537
|
-
const
|
|
778
|
+
const subscribe = (0, import_react.useCallback)(
|
|
538
779
|
(callback) => DialStore.subscribe(panelId, callback),
|
|
780
|
+
[panelId]
|
|
781
|
+
);
|
|
782
|
+
const getSnapshot = (0, import_react.useCallback)(
|
|
539
783
|
() => DialStore.getValues(panelId),
|
|
540
|
-
|
|
784
|
+
[panelId]
|
|
785
|
+
);
|
|
786
|
+
const flatValues = (0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
787
|
+
const values = (0, import_react.useMemo)(
|
|
788
|
+
() => resolveDialValues(configRef.current, flatValues),
|
|
789
|
+
[flatValues, serializedConfig]
|
|
790
|
+
);
|
|
791
|
+
const setValue = (0, import_react.useCallback)(
|
|
792
|
+
(path, value) => {
|
|
793
|
+
DialStore.updateValue(panelId, path, value);
|
|
794
|
+
},
|
|
795
|
+
[panelId]
|
|
796
|
+
);
|
|
797
|
+
const setValues = (0, import_react.useCallback)(
|
|
798
|
+
(nextValues) => {
|
|
799
|
+
DialStore.updateValues(panelId, flattenDialValueUpdates(configRef.current, nextValues));
|
|
800
|
+
},
|
|
801
|
+
[panelId]
|
|
802
|
+
);
|
|
803
|
+
const resetValues = (0, import_react.useCallback)(() => {
|
|
804
|
+
DialStore.resetValues(panelId);
|
|
805
|
+
}, [panelId]);
|
|
806
|
+
const getValues = (0, import_react.useCallback)(
|
|
807
|
+
() => resolveDialValues(configRef.current, DialStore.getValues(panelId)),
|
|
808
|
+
[panelId]
|
|
809
|
+
);
|
|
810
|
+
return (0, import_react.useMemo)(
|
|
811
|
+
() => ({
|
|
812
|
+
values,
|
|
813
|
+
setValue,
|
|
814
|
+
setValues,
|
|
815
|
+
resetValues,
|
|
816
|
+
getValues
|
|
817
|
+
}),
|
|
818
|
+
[getValues, resetValues, setValue, setValues, values]
|
|
541
819
|
);
|
|
542
|
-
return buildResolvedValues(config, values, "");
|
|
543
|
-
}
|
|
544
|
-
function buildResolvedValues(config, flatValues, prefix) {
|
|
545
|
-
const result = {};
|
|
546
|
-
for (const [key, configValue] of Object.entries(config)) {
|
|
547
|
-
if (key === "_collapsed") continue;
|
|
548
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
549
|
-
if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
|
|
550
|
-
result[key] = flatValues[path] ?? configValue[0];
|
|
551
|
-
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
552
|
-
result[key] = flatValues[path] ?? configValue;
|
|
553
|
-
} else if (isSpringConfig(configValue) || isEasingConfig(configValue)) {
|
|
554
|
-
result[key] = flatValues[path] ?? configValue;
|
|
555
|
-
} else if (isActionConfig(configValue)) {
|
|
556
|
-
result[key] = flatValues[path] ?? configValue;
|
|
557
|
-
} else if (isSelectConfig(configValue)) {
|
|
558
|
-
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
559
|
-
result[key] = flatValues[path] ?? defaultValue;
|
|
560
|
-
} else if (isColorConfig(configValue)) {
|
|
561
|
-
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
562
|
-
} else if (isTextConfig(configValue)) {
|
|
563
|
-
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
564
|
-
} else if (typeof configValue === "object" && configValue !== null) {
|
|
565
|
-
result[key] = buildResolvedValues(configValue, flatValues, path);
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
return result;
|
|
569
|
-
}
|
|
570
|
-
function hasType(value, type) {
|
|
571
|
-
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
572
|
-
}
|
|
573
|
-
function isSpringConfig(value) {
|
|
574
|
-
return hasType(value, "spring");
|
|
575
|
-
}
|
|
576
|
-
function isEasingConfig(value) {
|
|
577
|
-
return hasType(value, "easing");
|
|
578
|
-
}
|
|
579
|
-
function isActionConfig(value) {
|
|
580
|
-
return hasType(value, "action");
|
|
581
|
-
}
|
|
582
|
-
function isSelectConfig(value) {
|
|
583
|
-
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
584
|
-
}
|
|
585
|
-
function isColorConfig(value) {
|
|
586
|
-
return hasType(value, "color");
|
|
587
|
-
}
|
|
588
|
-
function isTextConfig(value) {
|
|
589
|
-
return hasType(value, "text");
|
|
590
|
-
}
|
|
591
|
-
function getFirstOptionValue(options) {
|
|
592
|
-
const first = options[0];
|
|
593
|
-
return typeof first === "string" ? first : first.value;
|
|
594
820
|
}
|
|
595
821
|
|
|
596
822
|
// src/components/DialRoot.tsx
|
|
597
823
|
var import_react17 = require("react");
|
|
598
824
|
var import_react_dom3 = require("react-dom");
|
|
599
825
|
|
|
826
|
+
// src/components/Folder.tsx
|
|
827
|
+
var import_react2 = require("react");
|
|
828
|
+
var import_react3 = require("motion/react");
|
|
829
|
+
|
|
830
|
+
// src/icons.ts
|
|
831
|
+
var ICON_CHEVRON = "M6 9.5L12 15.5L18 9.5";
|
|
832
|
+
var ICON_CHECK = "M5 12.75L10 19L19 5";
|
|
833
|
+
var ICON_CLIPBOARD = {
|
|
834
|
+
board: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z",
|
|
835
|
+
sparkle: "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",
|
|
836
|
+
body: "M16 5H17C18.6569 5 20 6.34315 20 8V11M8 5H7C5.34315 5 4 6.34315 4 8V18C4 19.6569 5.34315 21 7 21H12"
|
|
837
|
+
};
|
|
838
|
+
var ICON_ADD_PRESET = [
|
|
839
|
+
"M4 6H20",
|
|
840
|
+
"M4 12H10",
|
|
841
|
+
"M15 15L21 15",
|
|
842
|
+
"M18 12V18",
|
|
843
|
+
"M4 18H10"
|
|
844
|
+
];
|
|
845
|
+
var ICON_TRASH = [
|
|
846
|
+
"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",
|
|
847
|
+
"M10 11V16",
|
|
848
|
+
"M14 11V16",
|
|
849
|
+
"M3.5 6H20.5",
|
|
850
|
+
"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"
|
|
851
|
+
];
|
|
852
|
+
var ICON_PANEL = {
|
|
853
|
+
path: "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",
|
|
854
|
+
circles: [
|
|
855
|
+
{ cx: "6", cy: "8", r: "0.998596" },
|
|
856
|
+
{ cx: "10.4999", cy: "3.5", r: "0.998657" },
|
|
857
|
+
{ cx: "9.75015", cy: "12.5", r: "0.997986" }
|
|
858
|
+
]
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
// src/components/Folder.tsx
|
|
862
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
863
|
+
function Folder({ title, children, defaultOpen = true, isRoot = false, inline = false, onOpenChange, toolbar, panelHeightOffset = 10 }) {
|
|
864
|
+
const [isOpen, setIsOpen] = (0, import_react2.useState)(defaultOpen);
|
|
865
|
+
const [isCollapsed, setIsCollapsed] = (0, import_react2.useState)(!defaultOpen);
|
|
866
|
+
const contentRef = (0, import_react2.useRef)(null);
|
|
867
|
+
const [contentHeight, setContentHeight] = (0, import_react2.useState)(void 0);
|
|
868
|
+
const [windowHeight, setWindowHeight] = (0, import_react2.useState)(typeof window !== "undefined" ? window.innerHeight : 800);
|
|
869
|
+
(0, import_react2.useEffect)(() => {
|
|
870
|
+
if (!isRoot) return;
|
|
871
|
+
const onResize = () => setWindowHeight(window.innerHeight);
|
|
872
|
+
window.addEventListener("resize", onResize);
|
|
873
|
+
return () => window.removeEventListener("resize", onResize);
|
|
874
|
+
}, [isRoot]);
|
|
875
|
+
(0, import_react2.useEffect)(() => {
|
|
876
|
+
const el = contentRef.current;
|
|
877
|
+
if (!el) return;
|
|
878
|
+
const ro = new ResizeObserver(() => {
|
|
879
|
+
if (isOpen) {
|
|
880
|
+
const h = el.offsetHeight;
|
|
881
|
+
setContentHeight((prev) => prev === h ? prev : h);
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
ro.observe(el);
|
|
885
|
+
return () => ro.disconnect();
|
|
886
|
+
}, [isOpen]);
|
|
887
|
+
const handleToggle = () => {
|
|
888
|
+
if (inline && isRoot) return;
|
|
889
|
+
const next = !isOpen;
|
|
890
|
+
setIsOpen(next);
|
|
891
|
+
if (next) {
|
|
892
|
+
setIsCollapsed(false);
|
|
893
|
+
} else {
|
|
894
|
+
setIsCollapsed(true);
|
|
895
|
+
}
|
|
896
|
+
onOpenChange?.(next);
|
|
897
|
+
};
|
|
898
|
+
const folderContent = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
899
|
+
"div",
|
|
900
|
+
{
|
|
901
|
+
ref: isRoot ? contentRef : void 0,
|
|
902
|
+
className: `dialkit-folder ${isRoot ? "dialkit-folder-root" : ""}`,
|
|
903
|
+
"data-open": String(isOpen),
|
|
904
|
+
children: [
|
|
905
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dialkit-folder-header-top", children: [
|
|
907
|
+
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 }) }),
|
|
908
|
+
isRoot && !inline && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
909
|
+
"svg",
|
|
910
|
+
{
|
|
911
|
+
className: "dialkit-panel-icon",
|
|
912
|
+
viewBox: "0 0 16 16",
|
|
913
|
+
fill: "none",
|
|
914
|
+
children: [
|
|
915
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { opacity: "0.5", d: ICON_PANEL.path, fill: "currentColor" }),
|
|
916
|
+
ICON_PANEL.circles.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: c.cx, cy: c.cy, r: c.r, fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }, i))
|
|
917
|
+
]
|
|
918
|
+
}
|
|
919
|
+
),
|
|
920
|
+
!isRoot && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
921
|
+
import_react3.motion.svg,
|
|
922
|
+
{
|
|
923
|
+
className: "dialkit-folder-icon",
|
|
924
|
+
viewBox: "0 0 24 24",
|
|
925
|
+
fill: "none",
|
|
926
|
+
stroke: "currentColor",
|
|
927
|
+
strokeWidth: "2.5",
|
|
928
|
+
strokeLinecap: "round",
|
|
929
|
+
strokeLinejoin: "round",
|
|
930
|
+
initial: false,
|
|
931
|
+
animate: { rotate: isOpen ? 0 : 180 },
|
|
932
|
+
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
933
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: ICON_CHEVRON })
|
|
934
|
+
}
|
|
935
|
+
)
|
|
936
|
+
] }),
|
|
937
|
+
isRoot && toolbar && isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
938
|
+
] }),
|
|
939
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react3.AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
940
|
+
import_react3.motion.div,
|
|
941
|
+
{
|
|
942
|
+
className: "dialkit-folder-content",
|
|
943
|
+
initial: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
944
|
+
animate: isRoot ? void 0 : { height: "auto", opacity: 1 },
|
|
945
|
+
exit: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
946
|
+
transition: isRoot ? void 0 : { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
947
|
+
style: isRoot ? void 0 : { clipPath: "inset(0 -20px)" },
|
|
948
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dialkit-folder-inner", children })
|
|
949
|
+
}
|
|
950
|
+
) })
|
|
951
|
+
]
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
if (isRoot) {
|
|
955
|
+
if (inline) {
|
|
956
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dialkit-panel-inner dialkit-panel-inline", children: folderContent });
|
|
957
|
+
}
|
|
958
|
+
const panelStyle = isOpen ? { width: 280, height: contentHeight !== void 0 ? Math.min(contentHeight + panelHeightOffset, windowHeight - 32) : "auto", borderRadius: 14, boxShadow: "var(--dial-shadow)", cursor: void 0, overflowY: "auto" } : { width: 42, height: 42, borderRadius: "50%", boxSizing: "border-box", boxShadow: "var(--dial-shadow-collapsed)", overflow: "hidden", cursor: "pointer" };
|
|
959
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
960
|
+
import_react3.motion.div,
|
|
961
|
+
{
|
|
962
|
+
className: "dialkit-panel-inner",
|
|
963
|
+
style: panelStyle,
|
|
964
|
+
onClick: !isOpen ? handleToggle : void 0,
|
|
965
|
+
"data-collapsed": isCollapsed,
|
|
966
|
+
whileTap: !isOpen ? { scale: 0.9 } : void 0,
|
|
967
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
968
|
+
children: folderContent
|
|
969
|
+
}
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
return folderContent;
|
|
973
|
+
}
|
|
974
|
+
|
|
600
975
|
// src/components/Panel.tsx
|
|
601
976
|
var import_react15 = require("react");
|
|
602
977
|
var import_react16 = require("motion/react");
|
|
603
978
|
|
|
604
979
|
// src/components/ShortcutListener.tsx
|
|
605
|
-
var
|
|
980
|
+
var import_react4 = require("react");
|
|
606
981
|
|
|
607
982
|
// src/shortcut-utils.ts
|
|
608
983
|
function decimalsForStep(step) {
|
|
@@ -690,15 +1065,15 @@ function formatModifier(modifier) {
|
|
|
690
1065
|
}
|
|
691
1066
|
|
|
692
1067
|
// src/components/ShortcutListener.tsx
|
|
693
|
-
var
|
|
694
|
-
var ShortcutContext = (0,
|
|
1068
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1069
|
+
var ShortcutContext = (0, import_react4.createContext)({ activePanelId: null, activePath: null });
|
|
695
1070
|
function ShortcutListener({ children }) {
|
|
696
|
-
const [activeShortcut, setActiveShortcut] = (0,
|
|
697
|
-
const activeKeysRef = (0,
|
|
698
|
-
const isDraggingRef = (0,
|
|
699
|
-
const lastMouseXRef = (0,
|
|
700
|
-
const dragAccumulatorRef = (0,
|
|
701
|
-
const resolveActiveTarget = (0,
|
|
1071
|
+
const [activeShortcut, setActiveShortcut] = (0, import_react4.useState)({ activePanelId: null, activePath: null });
|
|
1072
|
+
const activeKeysRef = (0, import_react4.useRef)(/* @__PURE__ */ new Set());
|
|
1073
|
+
const isDraggingRef = (0, import_react4.useRef)(false);
|
|
1074
|
+
const lastMouseXRef = (0, import_react4.useRef)(null);
|
|
1075
|
+
const dragAccumulatorRef = (0, import_react4.useRef)(0);
|
|
1076
|
+
const resolveActiveTarget = (0, import_react4.useCallback)((interaction) => {
|
|
702
1077
|
for (const key of activeKeysRef.current) {
|
|
703
1078
|
const panels = DialStore.getPanels();
|
|
704
1079
|
for (const panel of panels) {
|
|
@@ -715,7 +1090,7 @@ function ShortcutListener({ children }) {
|
|
|
715
1090
|
}
|
|
716
1091
|
return null;
|
|
717
1092
|
}, []);
|
|
718
|
-
(0,
|
|
1093
|
+
(0, import_react4.useEffect)(() => {
|
|
719
1094
|
const handleKeyDown = (e) => {
|
|
720
1095
|
if (isInputFocused()) return;
|
|
721
1096
|
const key = e.key.toLowerCase();
|
|
@@ -873,146 +1248,7 @@ function ShortcutListener({ children }) {
|
|
|
873
1248
|
window.removeEventListener("blur", handleWindowBlur);
|
|
874
1249
|
};
|
|
875
1250
|
}, [resolveActiveTarget]);
|
|
876
|
-
return /* @__PURE__ */ (0,
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// src/icons.ts
|
|
880
|
-
var ICON_CHEVRON = "M6 9.5L12 15.5L18 9.5";
|
|
881
|
-
var ICON_CHECK = "M5 12.75L10 19L19 5";
|
|
882
|
-
var ICON_CLIPBOARD = {
|
|
883
|
-
board: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z",
|
|
884
|
-
sparkle: "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",
|
|
885
|
-
body: "M16 5H17C18.6569 5 20 6.34315 20 8V11M8 5H7C5.34315 5 4 6.34315 4 8V18C4 19.6569 5.34315 21 7 21H12"
|
|
886
|
-
};
|
|
887
|
-
var ICON_ADD_PRESET = [
|
|
888
|
-
"M4 6H20",
|
|
889
|
-
"M4 12H10",
|
|
890
|
-
"M15 15L21 15",
|
|
891
|
-
"M18 12V18",
|
|
892
|
-
"M4 18H10"
|
|
893
|
-
];
|
|
894
|
-
var ICON_TRASH = [
|
|
895
|
-
"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",
|
|
896
|
-
"M10 11V16",
|
|
897
|
-
"M14 11V16",
|
|
898
|
-
"M3.5 6H20.5",
|
|
899
|
-
"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"
|
|
900
|
-
];
|
|
901
|
-
var ICON_PANEL = {
|
|
902
|
-
path: "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",
|
|
903
|
-
circles: [
|
|
904
|
-
{ cx: "6", cy: "8", r: "0.998596" },
|
|
905
|
-
{ cx: "10.4999", cy: "3.5", r: "0.998657" },
|
|
906
|
-
{ cx: "9.75015", cy: "12.5", r: "0.997986" }
|
|
907
|
-
]
|
|
908
|
-
};
|
|
909
|
-
|
|
910
|
-
// src/components/Folder.tsx
|
|
911
|
-
var import_react3 = require("react");
|
|
912
|
-
var import_react4 = require("motion/react");
|
|
913
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
914
|
-
function Folder({ title, children, defaultOpen = true, isRoot = false, inline = false, onOpenChange, toolbar }) {
|
|
915
|
-
const [isOpen, setIsOpen] = (0, import_react3.useState)(defaultOpen);
|
|
916
|
-
const [isCollapsed, setIsCollapsed] = (0, import_react3.useState)(!defaultOpen);
|
|
917
|
-
const contentRef = (0, import_react3.useRef)(null);
|
|
918
|
-
const [contentHeight, setContentHeight] = (0, import_react3.useState)(void 0);
|
|
919
|
-
const [windowHeight, setWindowHeight] = (0, import_react3.useState)(typeof window !== "undefined" ? window.innerHeight : 800);
|
|
920
|
-
(0, import_react3.useEffect)(() => {
|
|
921
|
-
if (!isRoot) return;
|
|
922
|
-
const onResize = () => setWindowHeight(window.innerHeight);
|
|
923
|
-
window.addEventListener("resize", onResize);
|
|
924
|
-
return () => window.removeEventListener("resize", onResize);
|
|
925
|
-
}, [isRoot]);
|
|
926
|
-
(0, import_react3.useEffect)(() => {
|
|
927
|
-
const el = contentRef.current;
|
|
928
|
-
if (!el) return;
|
|
929
|
-
const ro = new ResizeObserver(() => {
|
|
930
|
-
if (isOpen) {
|
|
931
|
-
const h = el.offsetHeight;
|
|
932
|
-
setContentHeight((prev) => prev === h ? prev : h);
|
|
933
|
-
}
|
|
934
|
-
});
|
|
935
|
-
ro.observe(el);
|
|
936
|
-
return () => ro.disconnect();
|
|
937
|
-
}, [isOpen]);
|
|
938
|
-
const handleToggle = () => {
|
|
939
|
-
if (inline && isRoot) return;
|
|
940
|
-
const next = !isOpen;
|
|
941
|
-
setIsOpen(next);
|
|
942
|
-
if (next) {
|
|
943
|
-
setIsCollapsed(false);
|
|
944
|
-
} else {
|
|
945
|
-
setIsCollapsed(true);
|
|
946
|
-
}
|
|
947
|
-
onOpenChange?.(next);
|
|
948
|
-
};
|
|
949
|
-
const folderContent = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref: isRoot ? contentRef : void 0, className: `dialkit-folder ${isRoot ? "dialkit-folder-root" : ""}`, children: [
|
|
950
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
|
|
951
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dialkit-folder-header-top", children: [
|
|
952
|
-
isRoot ? isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dialkit-folder-title dialkit-folder-title-root", children: title }) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dialkit-folder-title", children: title }) }),
|
|
953
|
-
isRoot && !inline && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
954
|
-
"svg",
|
|
955
|
-
{
|
|
956
|
-
className: "dialkit-panel-icon",
|
|
957
|
-
viewBox: "0 0 16 16",
|
|
958
|
-
fill: "none",
|
|
959
|
-
children: [
|
|
960
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { opacity: "0.5", d: ICON_PANEL.path, fill: "currentColor" }),
|
|
961
|
-
ICON_PANEL.circles.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: c.cx, cy: c.cy, r: c.r, fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }, i))
|
|
962
|
-
]
|
|
963
|
-
}
|
|
964
|
-
),
|
|
965
|
-
!isRoot && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
966
|
-
import_react4.motion.svg,
|
|
967
|
-
{
|
|
968
|
-
className: "dialkit-folder-icon",
|
|
969
|
-
viewBox: "0 0 24 24",
|
|
970
|
-
fill: "none",
|
|
971
|
-
stroke: "currentColor",
|
|
972
|
-
strokeWidth: "2.5",
|
|
973
|
-
strokeLinecap: "round",
|
|
974
|
-
strokeLinejoin: "round",
|
|
975
|
-
initial: false,
|
|
976
|
-
animate: { rotate: isOpen ? 0 : 180 },
|
|
977
|
-
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
978
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: ICON_CHEVRON })
|
|
979
|
-
}
|
|
980
|
-
)
|
|
981
|
-
] }),
|
|
982
|
-
isRoot && toolbar && isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
983
|
-
] }),
|
|
984
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
985
|
-
import_react4.motion.div,
|
|
986
|
-
{
|
|
987
|
-
className: "dialkit-folder-content",
|
|
988
|
-
initial: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
989
|
-
animate: isRoot ? void 0 : { height: "auto", opacity: 1 },
|
|
990
|
-
exit: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
991
|
-
transition: isRoot ? void 0 : { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
992
|
-
style: isRoot ? void 0 : { clipPath: "inset(0 -20px)" },
|
|
993
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dialkit-folder-inner", children })
|
|
994
|
-
}
|
|
995
|
-
) })
|
|
996
|
-
] });
|
|
997
|
-
if (isRoot) {
|
|
998
|
-
if (inline) {
|
|
999
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dialkit-panel-inner dialkit-panel-inline", children: folderContent });
|
|
1000
|
-
}
|
|
1001
|
-
const panelStyle = isOpen ? { width: 280, height: contentHeight !== void 0 ? Math.min(contentHeight + 10, windowHeight - 32) : "auto", borderRadius: 14, boxShadow: "var(--dial-shadow)", cursor: void 0, overflowY: "auto" } : { width: 42, height: 42, borderRadius: "50%", boxSizing: "border-box", boxShadow: "var(--dial-shadow-collapsed)", overflow: "hidden", cursor: "pointer" };
|
|
1002
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1003
|
-
import_react4.motion.div,
|
|
1004
|
-
{
|
|
1005
|
-
className: "dialkit-panel-inner",
|
|
1006
|
-
style: panelStyle,
|
|
1007
|
-
onClick: !isOpen ? handleToggle : void 0,
|
|
1008
|
-
"data-collapsed": isCollapsed,
|
|
1009
|
-
whileTap: !isOpen ? { scale: 0.9 } : void 0,
|
|
1010
|
-
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
1011
|
-
children: folderContent
|
|
1012
|
-
}
|
|
1013
|
-
);
|
|
1014
|
-
}
|
|
1015
|
-
return folderContent;
|
|
1251
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ShortcutContext.Provider, { value: activeShortcut, children });
|
|
1016
1252
|
}
|
|
1017
1253
|
|
|
1018
1254
|
// src/components/Slider.tsx
|
|
@@ -1542,11 +1778,15 @@ function SpringVisualization({ spring, isSimpleMode }) {
|
|
|
1542
1778
|
var import_react8 = require("react");
|
|
1543
1779
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1544
1780
|
function SpringControl({ panelId, path, label, spring, onChange }) {
|
|
1545
|
-
const
|
|
1546
|
-
(
|
|
1781
|
+
const subscribe = (0, import_react8.useCallback)(
|
|
1782
|
+
(callback) => DialStore.subscribe(panelId, callback),
|
|
1783
|
+
[panelId]
|
|
1784
|
+
);
|
|
1785
|
+
const getSnapshot = (0, import_react8.useCallback)(
|
|
1547
1786
|
() => DialStore.getSpringMode(panelId, path),
|
|
1548
|
-
|
|
1787
|
+
[panelId, path]
|
|
1549
1788
|
);
|
|
1789
|
+
const mode = (0, import_react8.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1550
1790
|
const isSimpleMode = mode === "simple";
|
|
1551
1791
|
const cache = (0, import_react8.useRef)({
|
|
1552
1792
|
simple: spring.visualDuration !== void 0 ? spring : { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
@@ -1698,11 +1938,15 @@ function EasingVisualization({ easing }) {
|
|
|
1698
1938
|
var import_react9 = require("react");
|
|
1699
1939
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1700
1940
|
function TransitionControl({ panelId, path, label, value, onChange }) {
|
|
1701
|
-
const
|
|
1702
|
-
(
|
|
1941
|
+
const subscribe = (0, import_react9.useCallback)(
|
|
1942
|
+
(callback) => DialStore.subscribe(panelId, callback),
|
|
1943
|
+
[panelId]
|
|
1944
|
+
);
|
|
1945
|
+
const getSnapshot = (0, import_react9.useCallback)(
|
|
1703
1946
|
() => DialStore.getTransitionMode(panelId, path),
|
|
1704
|
-
|
|
1947
|
+
[panelId, path]
|
|
1705
1948
|
);
|
|
1949
|
+
const mode = (0, import_react9.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1706
1950
|
const isEasing = mode === "easing";
|
|
1707
1951
|
const isSimpleSpring = mode === "simple";
|
|
1708
1952
|
const cache = (0, import_react9.useRef)({
|
|
@@ -1844,6 +2088,26 @@ function TextControl({ label, value, onChange, placeholder }) {
|
|
|
1844
2088
|
var import_react10 = require("react");
|
|
1845
2089
|
var import_react_dom = require("react-dom");
|
|
1846
2090
|
var import_react11 = require("motion/react");
|
|
2091
|
+
|
|
2092
|
+
// src/dropdown-position.ts
|
|
2093
|
+
function getDropdownPosition(trigger, portalRoot, options = {}) {
|
|
2094
|
+
const { dropdownHeight = 0, gap = 4, allowAbove = true } = options;
|
|
2095
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2096
|
+
const rootRect = portalRoot.getBoundingClientRect();
|
|
2097
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom - gap;
|
|
2098
|
+
const above = allowAbove && spaceBelow < dropdownHeight && triggerRect.top > spaceBelow;
|
|
2099
|
+
return {
|
|
2100
|
+
top: above ? triggerRect.top - rootRect.top - dropdownHeight - gap : triggerRect.bottom - rootRect.top + gap,
|
|
2101
|
+
left: triggerRect.left - rootRect.left,
|
|
2102
|
+
width: triggerRect.width,
|
|
2103
|
+
above
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
function getDialKitPortalRoot(trigger) {
|
|
2107
|
+
return trigger?.closest(".dialkit-root") ?? null;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// src/components/SelectControl.tsx
|
|
1847
2111
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1848
2112
|
function toTitleCase(s) {
|
|
1849
2113
|
return s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
@@ -1863,21 +2127,12 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1863
2127
|
const selectedOption = normalized.find((o) => o.value === value);
|
|
1864
2128
|
const updatePos = (0, import_react10.useCallback)(() => {
|
|
1865
2129
|
const el = triggerRef.current;
|
|
1866
|
-
if (!el) return;
|
|
1867
|
-
const rect = el.getBoundingClientRect();
|
|
2130
|
+
if (!el || !portalTarget) return;
|
|
1868
2131
|
const dropdownHeight = 8 + normalized.length * 36;
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
setPos({
|
|
1872
|
-
top: above ? rect.top - 4 : rect.bottom + 4,
|
|
1873
|
-
left: rect.left,
|
|
1874
|
-
width: rect.width,
|
|
1875
|
-
above
|
|
1876
|
-
});
|
|
1877
|
-
}, [normalized.length]);
|
|
2132
|
+
setPos(getDropdownPosition(el, portalTarget, { dropdownHeight }));
|
|
2133
|
+
}, [normalized.length, portalTarget]);
|
|
1878
2134
|
(0, import_react10.useEffect)(() => {
|
|
1879
|
-
|
|
1880
|
-
setPortalTarget(root ?? document.body);
|
|
2135
|
+
setPortalTarget(getDialKitPortalRoot(triggerRef.current) ?? document.body);
|
|
1881
2136
|
}, []);
|
|
1882
2137
|
(0, import_react10.useEffect)(() => {
|
|
1883
2138
|
if (!isOpen) return;
|
|
@@ -1936,10 +2191,11 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1936
2191
|
exit: { opacity: 0, y: pos.above ? 8 : -8, scale: 0.95 },
|
|
1937
2192
|
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1938
2193
|
style: {
|
|
1939
|
-
position: "
|
|
2194
|
+
position: "absolute",
|
|
1940
2195
|
left: pos.left,
|
|
2196
|
+
top: pos.top,
|
|
1941
2197
|
width: pos.width,
|
|
1942
|
-
|
|
2198
|
+
transformOrigin: pos.above ? "bottom" : "top"
|
|
1943
2199
|
},
|
|
1944
2200
|
children: normalized.map((option) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1945
2201
|
"button",
|
|
@@ -2168,16 +2424,20 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
2168
2424
|
|
|
2169
2425
|
// src/components/Panel.tsx
|
|
2170
2426
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2171
|
-
function Panel({ panel, defaultOpen = true, inline = false }) {
|
|
2427
|
+
function Panel({ panel, defaultOpen = true, inline = false, onOpenChange, variant = "root" }) {
|
|
2172
2428
|
const [copied, setCopied] = (0, import_react15.useState)(false);
|
|
2173
2429
|
const [isPanelOpen, setIsPanelOpen] = (0, import_react15.useState)(defaultOpen);
|
|
2174
2430
|
const shortcutCtx = (0, import_react15.useContext)(ShortcutContext);
|
|
2175
2431
|
const hasShortcuts = Object.keys(panel.shortcuts).length > 0;
|
|
2176
|
-
const
|
|
2177
|
-
(
|
|
2432
|
+
const subscribe = (0, import_react15.useCallback)(
|
|
2433
|
+
(callback) => DialStore.subscribe(panel.id, callback),
|
|
2434
|
+
[panel.id]
|
|
2435
|
+
);
|
|
2436
|
+
const getSnapshot = (0, import_react15.useCallback)(
|
|
2178
2437
|
() => DialStore.getValues(panel.id),
|
|
2179
|
-
|
|
2438
|
+
[panel.id]
|
|
2180
2439
|
);
|
|
2440
|
+
const values = (0, import_react15.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
2181
2441
|
const presets = DialStore.getPresets(panel.id);
|
|
2182
2442
|
const activePresetId = DialStore.getActivePresetId(panel.id);
|
|
2183
2443
|
const handleAddPreset = () => {
|
|
@@ -2197,6 +2457,10 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2197
2457
|
setCopied(true);
|
|
2198
2458
|
setTimeout(() => setCopied(false), 1500);
|
|
2199
2459
|
};
|
|
2460
|
+
const handleOpenChange = (0, import_react15.useCallback)((open) => {
|
|
2461
|
+
setIsPanelOpen(open);
|
|
2462
|
+
onOpenChange?.(open);
|
|
2463
|
+
}, [onOpenChange]);
|
|
2200
2464
|
const renderControl = (control) => {
|
|
2201
2465
|
const value = values[control.path];
|
|
2202
2466
|
switch (control.type) {
|
|
@@ -2370,14 +2634,84 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2370
2634
|
}
|
|
2371
2635
|
)
|
|
2372
2636
|
] });
|
|
2373
|
-
|
|
2637
|
+
if (variant === "section") {
|
|
2638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Folder, { title: panel.name, defaultOpen, onOpenChange: handleOpenChange, children: [
|
|
2639
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dialkit-panel-section-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar }),
|
|
2640
|
+
renderControls()
|
|
2641
|
+
] });
|
|
2642
|
+
}
|
|
2643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Folder, { title: panel.name, defaultOpen, isRoot: true, inline, onOpenChange: handleOpenChange, toolbar, children: renderControls() }) });
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
// src/panel-drag.ts
|
|
2647
|
+
var PANEL_DRAG_THRESHOLD = 8;
|
|
2648
|
+
var COLLAPSED_PANEL_SIZE = 42;
|
|
2649
|
+
var DRAG_EXCLUSION_SELECTOR = [
|
|
2650
|
+
".dialkit-panel-icon",
|
|
2651
|
+
".dialkit-panel-toolbar",
|
|
2652
|
+
"button",
|
|
2653
|
+
"input",
|
|
2654
|
+
"select",
|
|
2655
|
+
"textarea",
|
|
2656
|
+
"a",
|
|
2657
|
+
'[role="button"]',
|
|
2658
|
+
'[contenteditable="true"]'
|
|
2659
|
+
].join(",");
|
|
2660
|
+
function getPanelDragHandle(target, panel) {
|
|
2661
|
+
if (!(target instanceof Element) || !panel) return null;
|
|
2662
|
+
const inner = target.closest(".dialkit-panel-inner");
|
|
2663
|
+
if (!inner || !panel.contains(inner)) return null;
|
|
2664
|
+
if (inner.getAttribute("data-collapsed") === "true") {
|
|
2665
|
+
return inner;
|
|
2666
|
+
}
|
|
2667
|
+
const header = target.closest(".dialkit-panel-header");
|
|
2668
|
+
if (!header || !inner.contains(header)) return null;
|
|
2669
|
+
if (target.closest(DRAG_EXCLUSION_SELECTOR)) return null;
|
|
2670
|
+
return header;
|
|
2671
|
+
}
|
|
2672
|
+
function getPanelDragStart(pointerX, pointerY, panel) {
|
|
2673
|
+
const rect = panel.getBoundingClientRect();
|
|
2674
|
+
return {
|
|
2675
|
+
pointerX,
|
|
2676
|
+
pointerY,
|
|
2677
|
+
elX: rect.left,
|
|
2678
|
+
elY: rect.top
|
|
2679
|
+
};
|
|
2680
|
+
}
|
|
2681
|
+
function getPanelDragOffset(start, pointerX, pointerY) {
|
|
2682
|
+
return {
|
|
2683
|
+
x: start.elX + pointerX - start.pointerX,
|
|
2684
|
+
y: start.elY + pointerY - start.pointerY
|
|
2685
|
+
};
|
|
2686
|
+
}
|
|
2687
|
+
function hasPanelDragMoved(start, pointerX, pointerY) {
|
|
2688
|
+
const dx = pointerX - start.pointerX;
|
|
2689
|
+
const dy = pointerY - start.pointerY;
|
|
2690
|
+
return Math.hypot(dx, dy) >= PANEL_DRAG_THRESHOLD;
|
|
2691
|
+
}
|
|
2692
|
+
function getPanelOriginX(position, offset, viewportWidth = typeof window !== "undefined" ? window.innerWidth : void 0) {
|
|
2693
|
+
if (offset && viewportWidth) {
|
|
2694
|
+
return offset.x + COLLAPSED_PANEL_SIZE / 2 < viewportWidth / 2 ? "left" : "right";
|
|
2695
|
+
}
|
|
2696
|
+
return position.endsWith("left") ? "left" : "right";
|
|
2697
|
+
}
|
|
2698
|
+
function blockPanelDragClick(handle) {
|
|
2699
|
+
const blocker = (event) => {
|
|
2700
|
+
event.preventDefault();
|
|
2701
|
+
event.stopImmediatePropagation();
|
|
2702
|
+
event.stopPropagation();
|
|
2703
|
+
};
|
|
2704
|
+
handle.addEventListener("click", blocker, { capture: true, once: true });
|
|
2705
|
+
window.setTimeout(() => {
|
|
2706
|
+
handle.removeEventListener("click", blocker, true);
|
|
2707
|
+
}, 0);
|
|
2374
2708
|
}
|
|
2375
2709
|
|
|
2376
2710
|
// src/components/DialRoot.tsx
|
|
2377
2711
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2378
2712
|
var import_meta = {};
|
|
2379
2713
|
var isDevDefault = typeof process !== "undefined" && process?.env?.NODE_ENV ? process.env.NODE_ENV !== "production" : typeof import_meta !== "undefined" && import_meta.env?.MODE ? import_meta.env.MODE !== "production" : true;
|
|
2380
|
-
function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover", theme = "system", productionEnabled = isDevDefault }) {
|
|
2714
|
+
function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover", theme = "system", productionEnabled = isDevDefault, onOpenChange }) {
|
|
2381
2715
|
if (!productionEnabled) return null;
|
|
2382
2716
|
const [panels, setPanels] = (0, import_react17.useState)([]);
|
|
2383
2717
|
const [mounted, setMounted] = (0, import_react17.useState)(false);
|
|
@@ -2389,6 +2723,9 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2389
2723
|
const draggingRef = (0, import_react17.useRef)(false);
|
|
2390
2724
|
const dragStartRef = (0, import_react17.useRef)(null);
|
|
2391
2725
|
const didDragRef = (0, import_react17.useRef)(false);
|
|
2726
|
+
const dragTargetRef = (0, import_react17.useRef)(null);
|
|
2727
|
+
const panelOpenStatesRef = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
|
|
2728
|
+
const rootOpenRef = (0, import_react17.useRef)(null);
|
|
2392
2729
|
(0, import_react17.useEffect)(() => {
|
|
2393
2730
|
setMounted(true);
|
|
2394
2731
|
setPanels(DialStore.getPanels());
|
|
@@ -2397,22 +2734,36 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2397
2734
|
});
|
|
2398
2735
|
return unsubscribe;
|
|
2399
2736
|
}, []);
|
|
2737
|
+
(0, import_react17.useEffect)(() => {
|
|
2738
|
+
const fallbackOpen = inline || defaultOpen;
|
|
2739
|
+
const nextStates = /* @__PURE__ */ new Map();
|
|
2740
|
+
for (const panel of panels) {
|
|
2741
|
+
nextStates.set(panel.id, panelOpenStatesRef.current.get(panel.id) ?? fallbackOpen);
|
|
2742
|
+
}
|
|
2743
|
+
panelOpenStatesRef.current = nextStates;
|
|
2744
|
+
rootOpenRef.current = Array.from(nextStates.values()).some(Boolean);
|
|
2745
|
+
}, [defaultOpen, inline, panels]);
|
|
2400
2746
|
(0, import_react17.useEffect)(() => {
|
|
2401
2747
|
if (!panelRef.current || inline) return;
|
|
2402
2748
|
const observer = new MutationObserver(() => {
|
|
2403
|
-
const
|
|
2404
|
-
if (!
|
|
2405
|
-
const collapsed =
|
|
2749
|
+
const inners = panelRef.current?.querySelectorAll(".dialkit-panel-inner");
|
|
2750
|
+
if (!inners || inners.length === 0) return;
|
|
2751
|
+
const collapsed = Array.from(inners).every(
|
|
2752
|
+
(el) => el.getAttribute("data-collapsed") === "true"
|
|
2753
|
+
);
|
|
2754
|
+
const currentDragOffset = dragOffset;
|
|
2406
2755
|
if (!collapsed) {
|
|
2407
|
-
if (
|
|
2408
|
-
lastDragOffset.current =
|
|
2409
|
-
const bubbleCenterX =
|
|
2756
|
+
if (currentDragOffset) {
|
|
2757
|
+
lastDragOffset.current = currentDragOffset;
|
|
2758
|
+
const bubbleCenterX = currentDragOffset.x + 21;
|
|
2410
2759
|
const midX = window.innerWidth / 2;
|
|
2411
2760
|
setActivePosition(bubbleCenterX < midX ? "top-left" : "top-right");
|
|
2412
2761
|
} else {
|
|
2413
2762
|
setActivePosition(position);
|
|
2414
2763
|
}
|
|
2415
2764
|
setDragOffset(null);
|
|
2765
|
+
} else if (currentDragOffset) {
|
|
2766
|
+
lastDragOffset.current = currentDragOffset;
|
|
2416
2767
|
} else if (lastDragOffset.current) {
|
|
2417
2768
|
setDragOffset(lastDragOffset.current);
|
|
2418
2769
|
}
|
|
@@ -2421,45 +2772,50 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2421
2772
|
return () => observer.disconnect();
|
|
2422
2773
|
}, [inline, dragOffset, position]);
|
|
2423
2774
|
const handlePointerDown = (0, import_react17.useCallback)((e) => {
|
|
2424
|
-
const
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
pointerY: e.clientY,
|
|
2430
|
-
elX: rect.left,
|
|
2431
|
-
elY: rect.top
|
|
2432
|
-
};
|
|
2775
|
+
const panel = panelRef.current;
|
|
2776
|
+
const handle = getPanelDragHandle(e.target, panel);
|
|
2777
|
+
if (!panel || !handle) return;
|
|
2778
|
+
dragTargetRef.current = handle;
|
|
2779
|
+
dragStartRef.current = getPanelDragStart(e.clientX, e.clientY, panel);
|
|
2433
2780
|
didDragRef.current = false;
|
|
2434
2781
|
draggingRef.current = true;
|
|
2435
|
-
|
|
2782
|
+
handle.setPointerCapture(e.pointerId);
|
|
2436
2783
|
}, []);
|
|
2437
2784
|
const handlePointerMove = (0, import_react17.useCallback)((e) => {
|
|
2438
2785
|
if (!draggingRef.current || !dragStartRef.current) return;
|
|
2439
|
-
|
|
2440
|
-
const dy = e.clientY - dragStartRef.current.pointerY;
|
|
2441
|
-
if (!didDragRef.current && Math.abs(dx) + Math.abs(dy) < 4) return;
|
|
2786
|
+
if (!didDragRef.current && !hasPanelDragMoved(dragStartRef.current, e.clientX, e.clientY)) return;
|
|
2442
2787
|
didDragRef.current = true;
|
|
2443
|
-
setDragOffset(
|
|
2444
|
-
x: dragStartRef.current.elX + dx,
|
|
2445
|
-
y: dragStartRef.current.elY + dy
|
|
2446
|
-
});
|
|
2788
|
+
setDragOffset(getPanelDragOffset(dragStartRef.current, e.clientX, e.clientY));
|
|
2447
2789
|
}, []);
|
|
2448
2790
|
const handlePointerUp = (0, import_react17.useCallback)((e) => {
|
|
2449
2791
|
if (!draggingRef.current) return;
|
|
2450
2792
|
draggingRef.current = false;
|
|
2451
2793
|
dragStartRef.current = null;
|
|
2794
|
+
const dragTarget = dragTargetRef.current;
|
|
2795
|
+
if (dragTarget?.hasPointerCapture(e.pointerId)) {
|
|
2796
|
+
dragTarget.releasePointerCapture(e.pointerId);
|
|
2797
|
+
}
|
|
2452
2798
|
if (didDragRef.current) {
|
|
2453
2799
|
e.stopPropagation();
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
const blocker = (ev) => {
|
|
2457
|
-
ev.stopPropagation();
|
|
2458
|
-
};
|
|
2459
|
-
inner.addEventListener("click", blocker, { capture: true, once: true });
|
|
2800
|
+
if (dragTarget) {
|
|
2801
|
+
blockPanelDragClick(dragTarget);
|
|
2460
2802
|
}
|
|
2461
2803
|
}
|
|
2804
|
+
dragTargetRef.current = null;
|
|
2462
2805
|
}, []);
|
|
2806
|
+
const handlePanelOpenChange = (0, import_react17.useCallback)((panelId, open) => {
|
|
2807
|
+
panelOpenStatesRef.current.set(panelId, open);
|
|
2808
|
+
const fallbackOpen = inline || defaultOpen;
|
|
2809
|
+
const nextRootOpen = panels.some((panel) => panelOpenStatesRef.current.get(panel.id) ?? fallbackOpen);
|
|
2810
|
+
if (rootOpenRef.current === nextRootOpen) return;
|
|
2811
|
+
rootOpenRef.current = nextRootOpen;
|
|
2812
|
+
onOpenChange?.(nextRootOpen);
|
|
2813
|
+
}, [defaultOpen, inline, onOpenChange, panels]);
|
|
2814
|
+
const handleRootOpenChange = (0, import_react17.useCallback)((open) => {
|
|
2815
|
+
if (rootOpenRef.current === open) return;
|
|
2816
|
+
rootOpenRef.current = open;
|
|
2817
|
+
onOpenChange?.(open);
|
|
2818
|
+
}, [onOpenChange]);
|
|
2463
2819
|
if (!mounted || typeof window === "undefined") {
|
|
2464
2820
|
return null;
|
|
2465
2821
|
}
|
|
@@ -2472,18 +2828,51 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2472
2828
|
right: "auto",
|
|
2473
2829
|
bottom: "auto"
|
|
2474
2830
|
} : void 0;
|
|
2831
|
+
const originX = getPanelOriginX(activePosition, dragOffset);
|
|
2832
|
+
const hasMultiplePanels = panels.length > 1;
|
|
2475
2833
|
const content = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ShortcutListener, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dialkit-root", "data-mode": mode, "data-theme": theme, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2476
2834
|
"div",
|
|
2477
2835
|
{
|
|
2478
2836
|
ref: panelRef,
|
|
2479
2837
|
className: "dialkit-panel",
|
|
2480
2838
|
"data-position": inline ? void 0 : dragOffset ? void 0 : activePosition,
|
|
2839
|
+
"data-origin-x": inline ? void 0 : originX,
|
|
2481
2840
|
"data-mode": mode,
|
|
2841
|
+
"data-multiple": hasMultiplePanels ? "true" : void 0,
|
|
2482
2842
|
style: dragStyle,
|
|
2483
2843
|
onPointerDown: !inline ? handlePointerDown : void 0,
|
|
2484
2844
|
onPointerMove: !inline ? handlePointerMove : void 0,
|
|
2485
2845
|
onPointerUp: !inline ? handlePointerUp : void 0,
|
|
2486
|
-
|
|
2846
|
+
onPointerCancel: !inline ? handlePointerUp : void 0,
|
|
2847
|
+
children: hasMultiplePanels ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2848
|
+
Folder,
|
|
2849
|
+
{
|
|
2850
|
+
title: "DialKit",
|
|
2851
|
+
defaultOpen: inline || defaultOpen,
|
|
2852
|
+
isRoot: true,
|
|
2853
|
+
inline,
|
|
2854
|
+
onOpenChange: handleRootOpenChange,
|
|
2855
|
+
panelHeightOffset: 2,
|
|
2856
|
+
children: panels.map((panel) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2857
|
+
Panel,
|
|
2858
|
+
{
|
|
2859
|
+
panel,
|
|
2860
|
+
defaultOpen: true,
|
|
2861
|
+
variant: "section"
|
|
2862
|
+
},
|
|
2863
|
+
panel.id
|
|
2864
|
+
))
|
|
2865
|
+
}
|
|
2866
|
+
) }) : panels.map((panel) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2867
|
+
Panel,
|
|
2868
|
+
{
|
|
2869
|
+
panel,
|
|
2870
|
+
defaultOpen: inline || defaultOpen,
|
|
2871
|
+
inline,
|
|
2872
|
+
onOpenChange: (open) => handlePanelOpenChange(panel.id, open)
|
|
2873
|
+
},
|
|
2874
|
+
panel.id
|
|
2875
|
+
))
|
|
2487
2876
|
}
|
|
2488
2877
|
) }) });
|
|
2489
2878
|
if (inline) {
|
|
@@ -2640,6 +3029,7 @@ function ShortcutsMenu({ panelId }) {
|
|
|
2640
3029
|
TextControl,
|
|
2641
3030
|
Toggle,
|
|
2642
3031
|
TransitionControl,
|
|
2643
|
-
useDialKit
|
|
3032
|
+
useDialKit,
|
|
3033
|
+
useDialKitController
|
|
2644
3034
|
});
|
|
2645
3035
|
//# sourceMappingURL=index.cjs.map
|