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.js
CHANGED
|
@@ -1,10 +1,93 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/hooks/useDialKit.ts
|
|
4
|
-
import { useEffect, useId,
|
|
4
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useSyncExternalStore } from "react";
|
|
5
5
|
|
|
6
6
|
// src/store/DialStore.ts
|
|
7
7
|
var EMPTY_VALUES = Object.freeze({});
|
|
8
|
+
function resolveDialValues(config, flatValues) {
|
|
9
|
+
return resolveConfigValues(config, flatValues, "");
|
|
10
|
+
}
|
|
11
|
+
function flattenDialValueUpdates(config, updates) {
|
|
12
|
+
const values = {};
|
|
13
|
+
if (typeof updates === "object" && updates !== null) {
|
|
14
|
+
flattenConfigUpdates(config, updates, "", values);
|
|
15
|
+
}
|
|
16
|
+
return values;
|
|
17
|
+
}
|
|
18
|
+
function resolveConfigValues(config, flatValues, prefix) {
|
|
19
|
+
const result = {};
|
|
20
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
21
|
+
if (key === "_collapsed") continue;
|
|
22
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
23
|
+
if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
|
|
24
|
+
result[key] = flatValues[path] ?? configValue[0];
|
|
25
|
+
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
26
|
+
result[key] = flatValues[path] ?? configValue;
|
|
27
|
+
} else if (isSpringConfigValue(configValue) || isEasingConfigValue(configValue)) {
|
|
28
|
+
result[key] = flatValues[path] ?? configValue;
|
|
29
|
+
} else if (isActionConfigValue(configValue)) {
|
|
30
|
+
result[key] = flatValues[path] ?? configValue;
|
|
31
|
+
} else if (isSelectConfigValue(configValue)) {
|
|
32
|
+
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
33
|
+
result[key] = flatValues[path] ?? defaultValue;
|
|
34
|
+
} else if (isColorConfigValue(configValue)) {
|
|
35
|
+
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
36
|
+
} else if (isTextConfigValue(configValue)) {
|
|
37
|
+
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
38
|
+
} else if (typeof configValue === "object" && configValue !== null) {
|
|
39
|
+
result[key] = resolveConfigValues(configValue, flatValues, path);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function flattenConfigUpdates(config, updates, prefix, values) {
|
|
45
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
46
|
+
if (key === "_collapsed" || !(key in updates)) continue;
|
|
47
|
+
const nextValue = updates[key];
|
|
48
|
+
if (nextValue === void 0) continue;
|
|
49
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
50
|
+
if (isActionConfigValue(configValue)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (isLeafConfigValue(configValue)) {
|
|
54
|
+
values[path] = nextValue;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (typeof configValue === "object" && configValue !== null && typeof nextValue === "object" && nextValue !== null && !Array.isArray(nextValue)) {
|
|
58
|
+
flattenConfigUpdates(configValue, nextValue, path, values);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function isLeafConfigValue(value) {
|
|
63
|
+
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);
|
|
64
|
+
}
|
|
65
|
+
function hasType(value, type) {
|
|
66
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
67
|
+
}
|
|
68
|
+
function isSpringConfigValue(value) {
|
|
69
|
+
return hasType(value, "spring");
|
|
70
|
+
}
|
|
71
|
+
function isEasingConfigValue(value) {
|
|
72
|
+
return hasType(value, "easing");
|
|
73
|
+
}
|
|
74
|
+
function isActionConfigValue(value) {
|
|
75
|
+
return hasType(value, "action");
|
|
76
|
+
}
|
|
77
|
+
function isSelectConfigValue(value) {
|
|
78
|
+
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
79
|
+
}
|
|
80
|
+
function isColorConfigValue(value) {
|
|
81
|
+
return hasType(value, "color");
|
|
82
|
+
}
|
|
83
|
+
function isTextConfigValue(value) {
|
|
84
|
+
return hasType(value, "text");
|
|
85
|
+
}
|
|
86
|
+
function getFirstOptionValue(options) {
|
|
87
|
+
const first = options[0];
|
|
88
|
+
if (first === void 0) return "";
|
|
89
|
+
return typeof first === "string" ? first : first.value;
|
|
90
|
+
}
|
|
8
91
|
var DialStoreClass = class {
|
|
9
92
|
constructor() {
|
|
10
93
|
this.panels = /* @__PURE__ */ new Map();
|
|
@@ -15,87 +98,138 @@ var DialStoreClass = class {
|
|
|
15
98
|
this.presets = /* @__PURE__ */ new Map();
|
|
16
99
|
this.activePreset = /* @__PURE__ */ new Map();
|
|
17
100
|
this.baseValues = /* @__PURE__ */ new Map();
|
|
101
|
+
this.defaultValues = /* @__PURE__ */ new Map();
|
|
102
|
+
this.registrationCounts = /* @__PURE__ */ new Map();
|
|
103
|
+
this.retainedPanels = /* @__PURE__ */ new Set();
|
|
104
|
+
this.persistConfigs = /* @__PURE__ */ new Map();
|
|
18
105
|
}
|
|
19
|
-
registerPanel(id, name, config, shortcuts) {
|
|
106
|
+
registerPanel(id, name, config, shortcuts, options = {}) {
|
|
107
|
+
this.configurePanelRetention(id, options);
|
|
108
|
+
this.registrationCounts.set(id, (this.registrationCounts.get(id) ?? 0) + 1);
|
|
20
109
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
21
|
-
const
|
|
22
|
-
this.
|
|
110
|
+
const controlsByPath = this.mapControlsByPath(controls);
|
|
111
|
+
const defaultValues = this.flattenValues(config, "");
|
|
112
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
113
|
+
const persisted = this.loadPersistedPanel(id);
|
|
114
|
+
const previousValues = this.panels.get(id)?.values ?? this.snapshots.get(id) ?? persisted?.values ?? {};
|
|
115
|
+
const values = this.reconcileValues(defaultValues, previousValues, controlsByPath);
|
|
116
|
+
const previousBaseValues = this.baseValues.get(id) ?? persisted?.baseValues ?? persisted?.values ?? {};
|
|
117
|
+
const baseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
23
118
|
this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {} });
|
|
24
119
|
this.snapshots.set(id, { ...values });
|
|
25
|
-
this.baseValues.set(id,
|
|
120
|
+
this.baseValues.set(id, baseValues);
|
|
121
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
122
|
+
const existingPresets = this.presets.get(id) ?? persisted?.presets;
|
|
123
|
+
if (existingPresets) {
|
|
124
|
+
this.presets.set(id, this.reconcilePresets(existingPresets, defaultValues, controlsByPath));
|
|
125
|
+
}
|
|
126
|
+
if (!this.activePreset.has(id) && persisted?.activePresetId !== void 0) {
|
|
127
|
+
this.activePreset.set(id, persisted.activePresetId);
|
|
128
|
+
}
|
|
129
|
+
this.persistPanel(id);
|
|
130
|
+
this.notify(id);
|
|
26
131
|
this.notifyGlobal();
|
|
27
132
|
}
|
|
28
|
-
updatePanel(id, name, config, shortcuts) {
|
|
133
|
+
updatePanel(id, name, config, shortcuts, options = {}) {
|
|
134
|
+
this.configurePanelRetention(id, options);
|
|
29
135
|
const existing = this.panels.get(id);
|
|
30
136
|
if (!existing) {
|
|
31
|
-
this.registerPanel(id, name, config, shortcuts);
|
|
137
|
+
this.registerPanel(id, name, config, shortcuts, options);
|
|
32
138
|
return;
|
|
33
139
|
}
|
|
34
140
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
35
141
|
const controlsByPath = this.mapControlsByPath(controls);
|
|
36
142
|
const defaultValues = this.flattenValues(config, "");
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
nextValues[path] = this.normalizePreservedValue(
|
|
40
|
-
existing.values[path],
|
|
41
|
-
defaultValue,
|
|
42
|
-
controlsByPath.get(path)
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
this.initTransitionModes(config, "", nextValues);
|
|
46
|
-
for (const [path, mode] of Object.entries(existing.values)) {
|
|
47
|
-
if (!path.endsWith(".__mode")) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
const transitionPath = path.slice(0, -"__mode".length - 1);
|
|
51
|
-
const transitionControl = controlsByPath.get(transitionPath);
|
|
52
|
-
if (transitionControl?.type === "transition") {
|
|
53
|
-
nextValues[path] = mode;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
143
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
144
|
+
const nextValues = this.reconcileValues(defaultValues, existing.values, controlsByPath);
|
|
56
145
|
const nextPanel = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts };
|
|
57
146
|
this.panels.set(id, nextPanel);
|
|
58
147
|
this.snapshots.set(id, { ...nextValues });
|
|
59
148
|
const previousBaseValues = this.baseValues.get(id) ?? {};
|
|
60
|
-
const nextBaseValues =
|
|
61
|
-
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
62
|
-
nextBaseValues[path] = this.normalizePreservedValue(
|
|
63
|
-
previousBaseValues[path],
|
|
64
|
-
defaultValue,
|
|
65
|
-
controlsByPath.get(path)
|
|
66
|
-
);
|
|
67
|
-
}
|
|
149
|
+
const nextBaseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
68
150
|
for (const [path, value] of Object.entries(nextValues)) {
|
|
69
151
|
if (path.endsWith(".__mode")) {
|
|
70
152
|
nextBaseValues[path] = value;
|
|
71
153
|
}
|
|
72
154
|
}
|
|
73
155
|
this.baseValues.set(id, nextBaseValues);
|
|
156
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
157
|
+
this.presets.set(id, this.reconcilePresets(this.presets.get(id) ?? [], defaultValues, controlsByPath));
|
|
158
|
+
this.persistPanel(id);
|
|
74
159
|
this.notify(id);
|
|
75
160
|
this.notifyGlobal();
|
|
76
161
|
}
|
|
77
162
|
unregisterPanel(id) {
|
|
163
|
+
const nextCount = (this.registrationCounts.get(id) ?? 1) - 1;
|
|
164
|
+
if (nextCount > 0) {
|
|
165
|
+
this.registrationCounts.set(id, nextCount);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.registrationCounts.delete(id);
|
|
78
169
|
this.panels.delete(id);
|
|
79
170
|
this.listeners.delete(id);
|
|
80
|
-
this.snapshots.delete(id);
|
|
81
171
|
this.actionListeners.delete(id);
|
|
82
|
-
this.
|
|
172
|
+
if (!this.retainedPanels.has(id)) {
|
|
173
|
+
this.snapshots.delete(id);
|
|
174
|
+
this.baseValues.delete(id);
|
|
175
|
+
this.defaultValues.delete(id);
|
|
176
|
+
this.presets.delete(id);
|
|
177
|
+
this.activePreset.delete(id);
|
|
178
|
+
this.persistConfigs.delete(id);
|
|
179
|
+
}
|
|
83
180
|
this.notifyGlobal();
|
|
84
181
|
}
|
|
85
182
|
updateValue(panelId, path, value) {
|
|
183
|
+
this.updateValues(panelId, { [path]: value });
|
|
184
|
+
}
|
|
185
|
+
updateValues(panelId, updates) {
|
|
86
186
|
const panel = this.panels.get(panelId);
|
|
87
187
|
if (!panel) return;
|
|
88
|
-
|
|
188
|
+
const validUpdates = {};
|
|
189
|
+
for (const [path, value] of Object.entries(updates)) {
|
|
190
|
+
if (!Object.prototype.hasOwnProperty.call(panel.values, path)) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const control = this.findControlByPath(panel.controls, path);
|
|
194
|
+
if (control?.type === "action") {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
panel.values[path] = value;
|
|
198
|
+
validUpdates[path] = value;
|
|
199
|
+
}
|
|
200
|
+
if (Object.keys(validUpdates).length === 0) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
89
203
|
const activeId = this.activePreset.get(panelId);
|
|
90
204
|
if (activeId) {
|
|
91
205
|
const presets = this.presets.get(panelId) ?? [];
|
|
92
206
|
const preset = presets.find((p) => p.id === activeId);
|
|
93
|
-
if (preset)
|
|
207
|
+
if (preset) {
|
|
208
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
209
|
+
preset.values[path] = value;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
94
212
|
} else {
|
|
95
213
|
const base = this.baseValues.get(panelId);
|
|
96
|
-
if (base)
|
|
214
|
+
if (base) {
|
|
215
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
216
|
+
base[path] = value;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
97
219
|
}
|
|
98
220
|
this.snapshots.set(panelId, { ...panel.values });
|
|
221
|
+
this.persistPanel(panelId);
|
|
222
|
+
this.notify(panelId);
|
|
223
|
+
}
|
|
224
|
+
resetValues(panelId) {
|
|
225
|
+
const panel = this.panels.get(panelId);
|
|
226
|
+
const defaults = this.defaultValues.get(panelId);
|
|
227
|
+
if (!panel || !defaults) return;
|
|
228
|
+
panel.values = { ...defaults };
|
|
229
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
230
|
+
this.baseValues.set(panelId, { ...defaults });
|
|
231
|
+
this.activePreset.set(panelId, null);
|
|
232
|
+
this.persistPanel(panelId);
|
|
99
233
|
this.notify(panelId);
|
|
100
234
|
}
|
|
101
235
|
updateSpringMode(panelId, path, mode) {
|
|
@@ -111,6 +245,7 @@ var DialStoreClass = class {
|
|
|
111
245
|
if (!panel) return;
|
|
112
246
|
panel.values[`${path}.__mode`] = mode;
|
|
113
247
|
this.snapshots.set(panelId, { ...panel.values });
|
|
248
|
+
this.persistPanel(panelId);
|
|
114
249
|
this.notify(panelId);
|
|
115
250
|
}
|
|
116
251
|
getTransitionMode(panelId, path) {
|
|
@@ -169,6 +304,7 @@ var DialStoreClass = class {
|
|
|
169
304
|
this.presets.set(panelId, [...existing, preset]);
|
|
170
305
|
this.activePreset.set(panelId, id);
|
|
171
306
|
this.snapshots.set(panelId, { ...panel.values });
|
|
307
|
+
this.persistPanel(panelId);
|
|
172
308
|
this.notify(panelId);
|
|
173
309
|
return id;
|
|
174
310
|
}
|
|
@@ -181,6 +317,7 @@ var DialStoreClass = class {
|
|
|
181
317
|
panel.values = { ...preset.values };
|
|
182
318
|
this.snapshots.set(panelId, { ...panel.values });
|
|
183
319
|
this.activePreset.set(panelId, presetId);
|
|
320
|
+
this.persistPanel(panelId);
|
|
184
321
|
this.notify(panelId);
|
|
185
322
|
}
|
|
186
323
|
deletePreset(panelId, presetId) {
|
|
@@ -193,6 +330,7 @@ var DialStoreClass = class {
|
|
|
193
330
|
if (panel) {
|
|
194
331
|
this.snapshots.set(panelId, { ...panel.values });
|
|
195
332
|
}
|
|
333
|
+
this.persistPanel(panelId);
|
|
196
334
|
this.notify(panelId);
|
|
197
335
|
}
|
|
198
336
|
getPresets(panelId) {
|
|
@@ -209,6 +347,7 @@ var DialStoreClass = class {
|
|
|
209
347
|
this.snapshots.set(panelId, { ...panel.values });
|
|
210
348
|
}
|
|
211
349
|
this.activePreset.set(panelId, null);
|
|
350
|
+
this.persistPanel(panelId);
|
|
212
351
|
this.notify(panelId);
|
|
213
352
|
}
|
|
214
353
|
resolveShortcutTarget(key, modifier) {
|
|
@@ -239,6 +378,94 @@ var DialStoreClass = class {
|
|
|
239
378
|
}
|
|
240
379
|
return results;
|
|
241
380
|
}
|
|
381
|
+
configurePanelRetention(id, options) {
|
|
382
|
+
if (options.retainOnUnmount) {
|
|
383
|
+
this.retainedPanels.add(id);
|
|
384
|
+
}
|
|
385
|
+
const persistConfig = this.normalizePersistConfig(id, options.persist);
|
|
386
|
+
if (persistConfig) {
|
|
387
|
+
this.persistConfigs.set(id, persistConfig);
|
|
388
|
+
this.retainedPanels.add(id);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
reconcileValues(defaultValues, previousValues, controlsByPath) {
|
|
392
|
+
const nextValues = {};
|
|
393
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
394
|
+
if (path.endsWith(".__mode")) {
|
|
395
|
+
const transitionPath = path.slice(0, -".__mode".length);
|
|
396
|
+
const transitionControl = controlsByPath.get(transitionPath);
|
|
397
|
+
nextValues[path] = transitionControl?.type === "transition" && previousValues[path] !== void 0 ? previousValues[path] : defaultValue;
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
nextValues[path] = this.normalizePreservedValue(
|
|
401
|
+
previousValues[path],
|
|
402
|
+
defaultValue,
|
|
403
|
+
controlsByPath.get(path)
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
return nextValues;
|
|
407
|
+
}
|
|
408
|
+
reconcilePresets(presets, defaultValues, controlsByPath) {
|
|
409
|
+
return presets.map((preset) => ({
|
|
410
|
+
...preset,
|
|
411
|
+
values: this.reconcileValues(defaultValues, preset.values, controlsByPath)
|
|
412
|
+
}));
|
|
413
|
+
}
|
|
414
|
+
normalizePersistConfig(id, persist) {
|
|
415
|
+
if (!persist) return null;
|
|
416
|
+
const options = typeof persist === "object" ? persist : {};
|
|
417
|
+
return {
|
|
418
|
+
key: options.key ?? `dialkit:${id}`,
|
|
419
|
+
storage: options.storage ?? "localStorage",
|
|
420
|
+
presets: options.presets ?? true
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
loadPersistedPanel(id) {
|
|
424
|
+
const config = this.persistConfigs.get(id);
|
|
425
|
+
if (!config) return null;
|
|
426
|
+
const storage = this.getStorage(config.storage);
|
|
427
|
+
if (!storage) return null;
|
|
428
|
+
try {
|
|
429
|
+
const raw = storage.getItem(config.key);
|
|
430
|
+
if (!raw) return null;
|
|
431
|
+
const parsed = JSON.parse(raw);
|
|
432
|
+
if (parsed?.version !== 1 || typeof parsed !== "object") return null;
|
|
433
|
+
return parsed;
|
|
434
|
+
} catch {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
persistPanel(id) {
|
|
439
|
+
const config = this.persistConfigs.get(id);
|
|
440
|
+
if (!config) return;
|
|
441
|
+
const storage = this.getStorage(config.storage);
|
|
442
|
+
if (!storage) return;
|
|
443
|
+
const values = this.snapshots.get(id) ?? this.panels.get(id)?.values;
|
|
444
|
+
if (!values) return;
|
|
445
|
+
const state = {
|
|
446
|
+
version: 1,
|
|
447
|
+
values,
|
|
448
|
+
baseValues: this.baseValues.get(id) ?? values,
|
|
449
|
+
activePresetId: this.activePreset.get(id) ?? null
|
|
450
|
+
};
|
|
451
|
+
if (config.presets) {
|
|
452
|
+
state.presets = this.presets.get(id) ?? [];
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
storage.setItem(config.key, JSON.stringify(state));
|
|
456
|
+
} catch {
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
getStorage(kind) {
|
|
460
|
+
if (typeof globalThis === "undefined" || !("window" in globalThis)) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
try {
|
|
464
|
+
return kind === "sessionStorage" ? globalThis.window?.sessionStorage ?? null : globalThis.window?.localStorage ?? null;
|
|
465
|
+
} catch {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
242
469
|
findControlByPath(controls, path) {
|
|
243
470
|
for (const control of controls) {
|
|
244
471
|
if (control.path === path) return control;
|
|
@@ -467,8 +694,12 @@ var DialStore = new DialStoreClass();
|
|
|
467
694
|
|
|
468
695
|
// src/hooks/useDialKit.ts
|
|
469
696
|
function useDialKit(name, config, options) {
|
|
697
|
+
return useDialKitController(name, config, options).values;
|
|
698
|
+
}
|
|
699
|
+
function useDialKitController(name, config, options) {
|
|
470
700
|
const instanceId = useId();
|
|
471
|
-
const
|
|
701
|
+
const hasStableId = options?.id !== void 0;
|
|
702
|
+
const panelId = options?.id ?? `${name}-${instanceId}`;
|
|
472
703
|
const configRef = useRef(config);
|
|
473
704
|
const serializedConfig = JSON.stringify(config);
|
|
474
705
|
configRef.current = config;
|
|
@@ -476,93 +707,236 @@ function useDialKit(name, config, options) {
|
|
|
476
707
|
onActionRef.current = options?.onAction;
|
|
477
708
|
const shortcutsRef = useRef(options?.shortcuts);
|
|
478
709
|
shortcutsRef.current = options?.shortcuts;
|
|
710
|
+
const persistRef = useRef(options?.persist);
|
|
711
|
+
persistRef.current = options?.persist;
|
|
479
712
|
const serializedShortcuts = JSON.stringify(options?.shortcuts);
|
|
713
|
+
const serializedPersist = JSON.stringify(options?.persist);
|
|
480
714
|
useEffect(() => {
|
|
481
|
-
DialStore.registerPanel(panelId, name, configRef.current, shortcutsRef.current
|
|
715
|
+
DialStore.registerPanel(panelId, name, configRef.current, shortcutsRef.current, {
|
|
716
|
+
retainOnUnmount: hasStableId,
|
|
717
|
+
persist: persistRef.current
|
|
718
|
+
});
|
|
482
719
|
return () => DialStore.unregisterPanel(panelId);
|
|
483
|
-
}, [panelId, name]);
|
|
720
|
+
}, [hasStableId, panelId, name]);
|
|
484
721
|
const mountedRef = useRef(false);
|
|
485
722
|
useEffect(() => {
|
|
486
723
|
if (!mountedRef.current) {
|
|
487
724
|
mountedRef.current = true;
|
|
488
725
|
return;
|
|
489
726
|
}
|
|
490
|
-
DialStore.updatePanel(panelId, name, configRef.current, shortcutsRef.current
|
|
491
|
-
|
|
727
|
+
DialStore.updatePanel(panelId, name, configRef.current, shortcutsRef.current, {
|
|
728
|
+
retainOnUnmount: hasStableId,
|
|
729
|
+
persist: persistRef.current
|
|
730
|
+
});
|
|
731
|
+
}, [hasStableId, panelId, name, serializedConfig, serializedShortcuts, serializedPersist]);
|
|
492
732
|
useEffect(() => {
|
|
493
733
|
return DialStore.subscribeActions(panelId, (action) => {
|
|
494
734
|
onActionRef.current?.(action);
|
|
495
735
|
});
|
|
496
736
|
}, [panelId]);
|
|
497
|
-
const
|
|
737
|
+
const subscribe = useCallback(
|
|
498
738
|
(callback) => DialStore.subscribe(panelId, callback),
|
|
739
|
+
[panelId]
|
|
740
|
+
);
|
|
741
|
+
const getSnapshot = useCallback(
|
|
499
742
|
() => DialStore.getValues(panelId),
|
|
500
|
-
|
|
743
|
+
[panelId]
|
|
744
|
+
);
|
|
745
|
+
const flatValues = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
746
|
+
const values = useMemo(
|
|
747
|
+
() => resolveDialValues(configRef.current, flatValues),
|
|
748
|
+
[flatValues, serializedConfig]
|
|
749
|
+
);
|
|
750
|
+
const setValue = useCallback(
|
|
751
|
+
(path, value) => {
|
|
752
|
+
DialStore.updateValue(panelId, path, value);
|
|
753
|
+
},
|
|
754
|
+
[panelId]
|
|
755
|
+
);
|
|
756
|
+
const setValues = useCallback(
|
|
757
|
+
(nextValues) => {
|
|
758
|
+
DialStore.updateValues(panelId, flattenDialValueUpdates(configRef.current, nextValues));
|
|
759
|
+
},
|
|
760
|
+
[panelId]
|
|
761
|
+
);
|
|
762
|
+
const resetValues = useCallback(() => {
|
|
763
|
+
DialStore.resetValues(panelId);
|
|
764
|
+
}, [panelId]);
|
|
765
|
+
const getValues = useCallback(
|
|
766
|
+
() => resolveDialValues(configRef.current, DialStore.getValues(panelId)),
|
|
767
|
+
[panelId]
|
|
768
|
+
);
|
|
769
|
+
return useMemo(
|
|
770
|
+
() => ({
|
|
771
|
+
values,
|
|
772
|
+
setValue,
|
|
773
|
+
setValues,
|
|
774
|
+
resetValues,
|
|
775
|
+
getValues
|
|
776
|
+
}),
|
|
777
|
+
[getValues, resetValues, setValue, setValues, values]
|
|
501
778
|
);
|
|
502
|
-
return buildResolvedValues(config, values, "");
|
|
503
|
-
}
|
|
504
|
-
function buildResolvedValues(config, flatValues, prefix) {
|
|
505
|
-
const result = {};
|
|
506
|
-
for (const [key, configValue] of Object.entries(config)) {
|
|
507
|
-
if (key === "_collapsed") continue;
|
|
508
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
509
|
-
if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
|
|
510
|
-
result[key] = flatValues[path] ?? configValue[0];
|
|
511
|
-
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
512
|
-
result[key] = flatValues[path] ?? configValue;
|
|
513
|
-
} else if (isSpringConfig(configValue) || isEasingConfig(configValue)) {
|
|
514
|
-
result[key] = flatValues[path] ?? configValue;
|
|
515
|
-
} else if (isActionConfig(configValue)) {
|
|
516
|
-
result[key] = flatValues[path] ?? configValue;
|
|
517
|
-
} else if (isSelectConfig(configValue)) {
|
|
518
|
-
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
519
|
-
result[key] = flatValues[path] ?? defaultValue;
|
|
520
|
-
} else if (isColorConfig(configValue)) {
|
|
521
|
-
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
522
|
-
} else if (isTextConfig(configValue)) {
|
|
523
|
-
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
524
|
-
} else if (typeof configValue === "object" && configValue !== null) {
|
|
525
|
-
result[key] = buildResolvedValues(configValue, flatValues, path);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
return result;
|
|
529
|
-
}
|
|
530
|
-
function hasType(value, type) {
|
|
531
|
-
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
532
|
-
}
|
|
533
|
-
function isSpringConfig(value) {
|
|
534
|
-
return hasType(value, "spring");
|
|
535
|
-
}
|
|
536
|
-
function isEasingConfig(value) {
|
|
537
|
-
return hasType(value, "easing");
|
|
538
|
-
}
|
|
539
|
-
function isActionConfig(value) {
|
|
540
|
-
return hasType(value, "action");
|
|
541
|
-
}
|
|
542
|
-
function isSelectConfig(value) {
|
|
543
|
-
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
544
|
-
}
|
|
545
|
-
function isColorConfig(value) {
|
|
546
|
-
return hasType(value, "color");
|
|
547
|
-
}
|
|
548
|
-
function isTextConfig(value) {
|
|
549
|
-
return hasType(value, "text");
|
|
550
|
-
}
|
|
551
|
-
function getFirstOptionValue(options) {
|
|
552
|
-
const first = options[0];
|
|
553
|
-
return typeof first === "string" ? first : first.value;
|
|
554
779
|
}
|
|
555
780
|
|
|
556
781
|
// src/components/DialRoot.tsx
|
|
557
|
-
import { useEffect as useEffect8, useState as useState10, useRef as useRef11, useCallback as
|
|
782
|
+
import { useEffect as useEffect8, useState as useState10, useRef as useRef11, useCallback as useCallback10 } from "react";
|
|
558
783
|
import { createPortal as createPortal3 } from "react-dom";
|
|
559
784
|
|
|
785
|
+
// src/components/Folder.tsx
|
|
786
|
+
import { useState, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
787
|
+
import { motion, AnimatePresence } from "motion/react";
|
|
788
|
+
|
|
789
|
+
// src/icons.ts
|
|
790
|
+
var ICON_CHEVRON = "M6 9.5L12 15.5L18 9.5";
|
|
791
|
+
var ICON_CHECK = "M5 12.75L10 19L19 5";
|
|
792
|
+
var ICON_CLIPBOARD = {
|
|
793
|
+
board: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z",
|
|
794
|
+
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",
|
|
795
|
+
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"
|
|
796
|
+
};
|
|
797
|
+
var ICON_ADD_PRESET = [
|
|
798
|
+
"M4 6H20",
|
|
799
|
+
"M4 12H10",
|
|
800
|
+
"M15 15L21 15",
|
|
801
|
+
"M18 12V18",
|
|
802
|
+
"M4 18H10"
|
|
803
|
+
];
|
|
804
|
+
var ICON_TRASH = [
|
|
805
|
+
"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",
|
|
806
|
+
"M10 11V16",
|
|
807
|
+
"M14 11V16",
|
|
808
|
+
"M3.5 6H20.5",
|
|
809
|
+
"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"
|
|
810
|
+
];
|
|
811
|
+
var ICON_PANEL = {
|
|
812
|
+
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",
|
|
813
|
+
circles: [
|
|
814
|
+
{ cx: "6", cy: "8", r: "0.998596" },
|
|
815
|
+
{ cx: "10.4999", cy: "3.5", r: "0.998657" },
|
|
816
|
+
{ cx: "9.75015", cy: "12.5", r: "0.997986" }
|
|
817
|
+
]
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
// src/components/Folder.tsx
|
|
821
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
822
|
+
function Folder({ title, children, defaultOpen = true, isRoot = false, inline = false, onOpenChange, toolbar, panelHeightOffset = 10 }) {
|
|
823
|
+
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
824
|
+
const [isCollapsed, setIsCollapsed] = useState(!defaultOpen);
|
|
825
|
+
const contentRef = useRef2(null);
|
|
826
|
+
const [contentHeight, setContentHeight] = useState(void 0);
|
|
827
|
+
const [windowHeight, setWindowHeight] = useState(typeof window !== "undefined" ? window.innerHeight : 800);
|
|
828
|
+
useEffect2(() => {
|
|
829
|
+
if (!isRoot) return;
|
|
830
|
+
const onResize = () => setWindowHeight(window.innerHeight);
|
|
831
|
+
window.addEventListener("resize", onResize);
|
|
832
|
+
return () => window.removeEventListener("resize", onResize);
|
|
833
|
+
}, [isRoot]);
|
|
834
|
+
useEffect2(() => {
|
|
835
|
+
const el = contentRef.current;
|
|
836
|
+
if (!el) return;
|
|
837
|
+
const ro = new ResizeObserver(() => {
|
|
838
|
+
if (isOpen) {
|
|
839
|
+
const h = el.offsetHeight;
|
|
840
|
+
setContentHeight((prev) => prev === h ? prev : h);
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
ro.observe(el);
|
|
844
|
+
return () => ro.disconnect();
|
|
845
|
+
}, [isOpen]);
|
|
846
|
+
const handleToggle = () => {
|
|
847
|
+
if (inline && isRoot) return;
|
|
848
|
+
const next = !isOpen;
|
|
849
|
+
setIsOpen(next);
|
|
850
|
+
if (next) {
|
|
851
|
+
setIsCollapsed(false);
|
|
852
|
+
} else {
|
|
853
|
+
setIsCollapsed(true);
|
|
854
|
+
}
|
|
855
|
+
onOpenChange?.(next);
|
|
856
|
+
};
|
|
857
|
+
const folderContent = /* @__PURE__ */ jsxs(
|
|
858
|
+
"div",
|
|
859
|
+
{
|
|
860
|
+
ref: isRoot ? contentRef : void 0,
|
|
861
|
+
className: `dialkit-folder ${isRoot ? "dialkit-folder-root" : ""}`,
|
|
862
|
+
"data-open": String(isOpen),
|
|
863
|
+
children: [
|
|
864
|
+
/* @__PURE__ */ jsxs("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
|
|
865
|
+
/* @__PURE__ */ jsxs("div", { className: "dialkit-folder-header-top", children: [
|
|
866
|
+
isRoot ? isOpen && /* @__PURE__ */ jsx("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ jsx("span", { className: "dialkit-folder-title dialkit-folder-title-root", children: title }) }) : /* @__PURE__ */ jsx("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ jsx("span", { className: "dialkit-folder-title", children: title }) }),
|
|
867
|
+
isRoot && !inline && /* @__PURE__ */ jsxs(
|
|
868
|
+
"svg",
|
|
869
|
+
{
|
|
870
|
+
className: "dialkit-panel-icon",
|
|
871
|
+
viewBox: "0 0 16 16",
|
|
872
|
+
fill: "none",
|
|
873
|
+
children: [
|
|
874
|
+
/* @__PURE__ */ jsx("path", { opacity: "0.5", d: ICON_PANEL.path, fill: "currentColor" }),
|
|
875
|
+
ICON_PANEL.circles.map((c, i) => /* @__PURE__ */ jsx("circle", { cx: c.cx, cy: c.cy, r: c.r, fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }, i))
|
|
876
|
+
]
|
|
877
|
+
}
|
|
878
|
+
),
|
|
879
|
+
!isRoot && /* @__PURE__ */ jsx(
|
|
880
|
+
motion.svg,
|
|
881
|
+
{
|
|
882
|
+
className: "dialkit-folder-icon",
|
|
883
|
+
viewBox: "0 0 24 24",
|
|
884
|
+
fill: "none",
|
|
885
|
+
stroke: "currentColor",
|
|
886
|
+
strokeWidth: "2.5",
|
|
887
|
+
strokeLinecap: "round",
|
|
888
|
+
strokeLinejoin: "round",
|
|
889
|
+
initial: false,
|
|
890
|
+
animate: { rotate: isOpen ? 0 : 180 },
|
|
891
|
+
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
892
|
+
children: /* @__PURE__ */ jsx("path", { d: ICON_CHEVRON })
|
|
893
|
+
}
|
|
894
|
+
)
|
|
895
|
+
] }),
|
|
896
|
+
isRoot && toolbar && isOpen && /* @__PURE__ */ jsx("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
897
|
+
] }),
|
|
898
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ jsx(
|
|
899
|
+
motion.div,
|
|
900
|
+
{
|
|
901
|
+
className: "dialkit-folder-content",
|
|
902
|
+
initial: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
903
|
+
animate: isRoot ? void 0 : { height: "auto", opacity: 1 },
|
|
904
|
+
exit: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
905
|
+
transition: isRoot ? void 0 : { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
906
|
+
style: isRoot ? void 0 : { clipPath: "inset(0 -20px)" },
|
|
907
|
+
children: /* @__PURE__ */ jsx("div", { className: "dialkit-folder-inner", children })
|
|
908
|
+
}
|
|
909
|
+
) })
|
|
910
|
+
]
|
|
911
|
+
}
|
|
912
|
+
);
|
|
913
|
+
if (isRoot) {
|
|
914
|
+
if (inline) {
|
|
915
|
+
return /* @__PURE__ */ jsx("div", { className: "dialkit-panel-inner dialkit-panel-inline", children: folderContent });
|
|
916
|
+
}
|
|
917
|
+
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" };
|
|
918
|
+
return /* @__PURE__ */ jsx(
|
|
919
|
+
motion.div,
|
|
920
|
+
{
|
|
921
|
+
className: "dialkit-panel-inner",
|
|
922
|
+
style: panelStyle,
|
|
923
|
+
onClick: !isOpen ? handleToggle : void 0,
|
|
924
|
+
"data-collapsed": isCollapsed,
|
|
925
|
+
whileTap: !isOpen ? { scale: 0.9 } : void 0,
|
|
926
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
927
|
+
children: folderContent
|
|
928
|
+
}
|
|
929
|
+
);
|
|
930
|
+
}
|
|
931
|
+
return folderContent;
|
|
932
|
+
}
|
|
933
|
+
|
|
560
934
|
// src/components/Panel.tsx
|
|
561
|
-
import {
|
|
935
|
+
import { useCallback as useCallback9, useContext, useState as useState9, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
562
936
|
import { motion as motion5, AnimatePresence as AnimatePresence4 } from "motion/react";
|
|
563
937
|
|
|
564
938
|
// src/components/ShortcutListener.tsx
|
|
565
|
-
import { createContext, useEffect as
|
|
939
|
+
import { createContext, useEffect as useEffect3, useRef as useRef3, useState as useState2, useCallback as useCallback2 } from "react";
|
|
566
940
|
|
|
567
941
|
// src/shortcut-utils.ts
|
|
568
942
|
function decimalsForStep(step) {
|
|
@@ -650,15 +1024,15 @@ function formatModifier(modifier) {
|
|
|
650
1024
|
}
|
|
651
1025
|
|
|
652
1026
|
// src/components/ShortcutListener.tsx
|
|
653
|
-
import { jsx } from "react/jsx-runtime";
|
|
1027
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
654
1028
|
var ShortcutContext = createContext({ activePanelId: null, activePath: null });
|
|
655
1029
|
function ShortcutListener({ children }) {
|
|
656
|
-
const [activeShortcut, setActiveShortcut] =
|
|
657
|
-
const activeKeysRef =
|
|
658
|
-
const isDraggingRef =
|
|
659
|
-
const lastMouseXRef =
|
|
660
|
-
const dragAccumulatorRef =
|
|
661
|
-
const resolveActiveTarget =
|
|
1030
|
+
const [activeShortcut, setActiveShortcut] = useState2({ activePanelId: null, activePath: null });
|
|
1031
|
+
const activeKeysRef = useRef3(/* @__PURE__ */ new Set());
|
|
1032
|
+
const isDraggingRef = useRef3(false);
|
|
1033
|
+
const lastMouseXRef = useRef3(null);
|
|
1034
|
+
const dragAccumulatorRef = useRef3(0);
|
|
1035
|
+
const resolveActiveTarget = useCallback2((interaction) => {
|
|
662
1036
|
for (const key of activeKeysRef.current) {
|
|
663
1037
|
const panels = DialStore.getPanels();
|
|
664
1038
|
for (const panel of panels) {
|
|
@@ -675,7 +1049,7 @@ function ShortcutListener({ children }) {
|
|
|
675
1049
|
}
|
|
676
1050
|
return null;
|
|
677
1051
|
}, []);
|
|
678
|
-
|
|
1052
|
+
useEffect3(() => {
|
|
679
1053
|
const handleKeyDown = (e) => {
|
|
680
1054
|
if (isInputFocused()) return;
|
|
681
1055
|
const key = e.key.toLowerCase();
|
|
@@ -833,150 +1207,11 @@ function ShortcutListener({ children }) {
|
|
|
833
1207
|
window.removeEventListener("blur", handleWindowBlur);
|
|
834
1208
|
};
|
|
835
1209
|
}, [resolveActiveTarget]);
|
|
836
|
-
return /* @__PURE__ */
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// src/icons.ts
|
|
840
|
-
var ICON_CHEVRON = "M6 9.5L12 15.5L18 9.5";
|
|
841
|
-
var ICON_CHECK = "M5 12.75L10 19L19 5";
|
|
842
|
-
var ICON_CLIPBOARD = {
|
|
843
|
-
board: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z",
|
|
844
|
-
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",
|
|
845
|
-
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"
|
|
846
|
-
};
|
|
847
|
-
var ICON_ADD_PRESET = [
|
|
848
|
-
"M4 6H20",
|
|
849
|
-
"M4 12H10",
|
|
850
|
-
"M15 15L21 15",
|
|
851
|
-
"M18 12V18",
|
|
852
|
-
"M4 18H10"
|
|
853
|
-
];
|
|
854
|
-
var ICON_TRASH = [
|
|
855
|
-
"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",
|
|
856
|
-
"M10 11V16",
|
|
857
|
-
"M14 11V16",
|
|
858
|
-
"M3.5 6H20.5",
|
|
859
|
-
"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"
|
|
860
|
-
];
|
|
861
|
-
var ICON_PANEL = {
|
|
862
|
-
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",
|
|
863
|
-
circles: [
|
|
864
|
-
{ cx: "6", cy: "8", r: "0.998596" },
|
|
865
|
-
{ cx: "10.4999", cy: "3.5", r: "0.998657" },
|
|
866
|
-
{ cx: "9.75015", cy: "12.5", r: "0.997986" }
|
|
867
|
-
]
|
|
868
|
-
};
|
|
869
|
-
|
|
870
|
-
// src/components/Folder.tsx
|
|
871
|
-
import { useState as useState2, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
872
|
-
import { motion, AnimatePresence } from "motion/react";
|
|
873
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
874
|
-
function Folder({ title, children, defaultOpen = true, isRoot = false, inline = false, onOpenChange, toolbar }) {
|
|
875
|
-
const [isOpen, setIsOpen] = useState2(defaultOpen);
|
|
876
|
-
const [isCollapsed, setIsCollapsed] = useState2(!defaultOpen);
|
|
877
|
-
const contentRef = useRef3(null);
|
|
878
|
-
const [contentHeight, setContentHeight] = useState2(void 0);
|
|
879
|
-
const [windowHeight, setWindowHeight] = useState2(typeof window !== "undefined" ? window.innerHeight : 800);
|
|
880
|
-
useEffect3(() => {
|
|
881
|
-
if (!isRoot) return;
|
|
882
|
-
const onResize = () => setWindowHeight(window.innerHeight);
|
|
883
|
-
window.addEventListener("resize", onResize);
|
|
884
|
-
return () => window.removeEventListener("resize", onResize);
|
|
885
|
-
}, [isRoot]);
|
|
886
|
-
useEffect3(() => {
|
|
887
|
-
const el = contentRef.current;
|
|
888
|
-
if (!el) return;
|
|
889
|
-
const ro = new ResizeObserver(() => {
|
|
890
|
-
if (isOpen) {
|
|
891
|
-
const h = el.offsetHeight;
|
|
892
|
-
setContentHeight((prev) => prev === h ? prev : h);
|
|
893
|
-
}
|
|
894
|
-
});
|
|
895
|
-
ro.observe(el);
|
|
896
|
-
return () => ro.disconnect();
|
|
897
|
-
}, [isOpen]);
|
|
898
|
-
const handleToggle = () => {
|
|
899
|
-
if (inline && isRoot) return;
|
|
900
|
-
const next = !isOpen;
|
|
901
|
-
setIsOpen(next);
|
|
902
|
-
if (next) {
|
|
903
|
-
setIsCollapsed(false);
|
|
904
|
-
} else {
|
|
905
|
-
setIsCollapsed(true);
|
|
906
|
-
}
|
|
907
|
-
onOpenChange?.(next);
|
|
908
|
-
};
|
|
909
|
-
const folderContent = /* @__PURE__ */ jsxs("div", { ref: isRoot ? contentRef : void 0, className: `dialkit-folder ${isRoot ? "dialkit-folder-root" : ""}`, children: [
|
|
910
|
-
/* @__PURE__ */ jsxs("div", { className: `dialkit-folder-header ${isRoot ? "dialkit-panel-header" : ""}`, onClick: handleToggle, children: [
|
|
911
|
-
/* @__PURE__ */ jsxs("div", { className: "dialkit-folder-header-top", children: [
|
|
912
|
-
isRoot ? isOpen && /* @__PURE__ */ jsx2("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ jsx2("span", { className: "dialkit-folder-title dialkit-folder-title-root", children: title }) }) : /* @__PURE__ */ jsx2("div", { className: "dialkit-folder-title-row", children: /* @__PURE__ */ jsx2("span", { className: "dialkit-folder-title", children: title }) }),
|
|
913
|
-
isRoot && !inline && /* @__PURE__ */ jsxs(
|
|
914
|
-
"svg",
|
|
915
|
-
{
|
|
916
|
-
className: "dialkit-panel-icon",
|
|
917
|
-
viewBox: "0 0 16 16",
|
|
918
|
-
fill: "none",
|
|
919
|
-
children: [
|
|
920
|
-
/* @__PURE__ */ jsx2("path", { opacity: "0.5", d: ICON_PANEL.path, fill: "currentColor" }),
|
|
921
|
-
ICON_PANEL.circles.map((c, i) => /* @__PURE__ */ jsx2("circle", { cx: c.cx, cy: c.cy, r: c.r, fill: "currentColor", stroke: "currentColor", strokeWidth: "1.25" }, i))
|
|
922
|
-
]
|
|
923
|
-
}
|
|
924
|
-
),
|
|
925
|
-
!isRoot && /* @__PURE__ */ jsx2(
|
|
926
|
-
motion.svg,
|
|
927
|
-
{
|
|
928
|
-
className: "dialkit-folder-icon",
|
|
929
|
-
viewBox: "0 0 24 24",
|
|
930
|
-
fill: "none",
|
|
931
|
-
stroke: "currentColor",
|
|
932
|
-
strokeWidth: "2.5",
|
|
933
|
-
strokeLinecap: "round",
|
|
934
|
-
strokeLinejoin: "round",
|
|
935
|
-
initial: false,
|
|
936
|
-
animate: { rotate: isOpen ? 0 : 180 },
|
|
937
|
-
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 },
|
|
938
|
-
children: /* @__PURE__ */ jsx2("path", { d: ICON_CHEVRON })
|
|
939
|
-
}
|
|
940
|
-
)
|
|
941
|
-
] }),
|
|
942
|
-
isRoot && toolbar && isOpen && /* @__PURE__ */ jsx2("div", { className: "dialkit-panel-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar })
|
|
943
|
-
] }),
|
|
944
|
-
/* @__PURE__ */ jsx2(AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ jsx2(
|
|
945
|
-
motion.div,
|
|
946
|
-
{
|
|
947
|
-
className: "dialkit-folder-content",
|
|
948
|
-
initial: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
949
|
-
animate: isRoot ? void 0 : { height: "auto", opacity: 1 },
|
|
950
|
-
exit: isRoot ? void 0 : { height: 0, opacity: 0 },
|
|
951
|
-
transition: isRoot ? void 0 : { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
952
|
-
style: isRoot ? void 0 : { clipPath: "inset(0 -20px)" },
|
|
953
|
-
children: /* @__PURE__ */ jsx2("div", { className: "dialkit-folder-inner", children })
|
|
954
|
-
}
|
|
955
|
-
) })
|
|
956
|
-
] });
|
|
957
|
-
if (isRoot) {
|
|
958
|
-
if (inline) {
|
|
959
|
-
return /* @__PURE__ */ jsx2("div", { className: "dialkit-panel-inner dialkit-panel-inline", children: folderContent });
|
|
960
|
-
}
|
|
961
|
-
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" };
|
|
962
|
-
return /* @__PURE__ */ jsx2(
|
|
963
|
-
motion.div,
|
|
964
|
-
{
|
|
965
|
-
className: "dialkit-panel-inner",
|
|
966
|
-
style: panelStyle,
|
|
967
|
-
onClick: !isOpen ? handleToggle : void 0,
|
|
968
|
-
"data-collapsed": isCollapsed,
|
|
969
|
-
whileTap: !isOpen ? { scale: 0.9 } : void 0,
|
|
970
|
-
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 },
|
|
971
|
-
children: folderContent
|
|
972
|
-
}
|
|
973
|
-
);
|
|
974
|
-
}
|
|
975
|
-
return folderContent;
|
|
1210
|
+
return /* @__PURE__ */ jsx2(ShortcutContext.Provider, { value: activeShortcut, children });
|
|
976
1211
|
}
|
|
977
1212
|
|
|
978
1213
|
// src/components/Slider.tsx
|
|
979
|
-
import { useRef as useRef4, useState as useState3, useCallback as
|
|
1214
|
+
import { useRef as useRef4, useState as useState3, useCallback as useCallback3, useEffect as useEffect4 } from "react";
|
|
980
1215
|
import { motion as motion2, useMotionValue, useTransform, animate } from "motion/react";
|
|
981
1216
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
982
1217
|
var CLICK_THRESHOLD = 3;
|
|
@@ -1034,7 +1269,7 @@ function Slider({
|
|
|
1034
1269
|
fillPercent.jump(percentage);
|
|
1035
1270
|
}
|
|
1036
1271
|
}, [percentage, isInteracting, fillPercent]);
|
|
1037
|
-
const positionToValue =
|
|
1272
|
+
const positionToValue = useCallback3(
|
|
1038
1273
|
(clientX) => {
|
|
1039
1274
|
const rect = wrapperRectRef.current;
|
|
1040
1275
|
if (!rect) return value;
|
|
@@ -1047,11 +1282,11 @@ function Slider({
|
|
|
1047
1282
|
},
|
|
1048
1283
|
[min, max, value]
|
|
1049
1284
|
);
|
|
1050
|
-
const percentFromValue =
|
|
1285
|
+
const percentFromValue = useCallback3(
|
|
1051
1286
|
(v) => (v - min) / (max - min) * 100,
|
|
1052
1287
|
[min, max]
|
|
1053
1288
|
);
|
|
1054
|
-
const computeRubberStretch =
|
|
1289
|
+
const computeRubberStretch = useCallback3(
|
|
1055
1290
|
(clientX, sign) => {
|
|
1056
1291
|
const rect = wrapperRectRef.current;
|
|
1057
1292
|
if (!rect) return 0;
|
|
@@ -1061,7 +1296,7 @@ function Slider({
|
|
|
1061
1296
|
},
|
|
1062
1297
|
[]
|
|
1063
1298
|
);
|
|
1064
|
-
const handlePointerDown =
|
|
1299
|
+
const handlePointerDown = useCallback3(
|
|
1065
1300
|
(e) => {
|
|
1066
1301
|
if (showInput) return;
|
|
1067
1302
|
e.preventDefault();
|
|
@@ -1077,7 +1312,7 @@ function Slider({
|
|
|
1077
1312
|
},
|
|
1078
1313
|
[showInput]
|
|
1079
1314
|
);
|
|
1080
|
-
const handlePointerMove =
|
|
1315
|
+
const handlePointerMove = useCallback3(
|
|
1081
1316
|
(e) => {
|
|
1082
1317
|
if (!isInteracting || !pointerDownPos.current) return;
|
|
1083
1318
|
const dx = e.clientX - pointerDownPos.current.x;
|
|
@@ -1118,7 +1353,7 @@ function Slider({
|
|
|
1118
1353
|
computeRubberStretch
|
|
1119
1354
|
]
|
|
1120
1355
|
);
|
|
1121
|
-
const handlePointerUp =
|
|
1356
|
+
const handlePointerUp = useCallback3(
|
|
1122
1357
|
(e) => {
|
|
1123
1358
|
if (!isInteracting) return;
|
|
1124
1359
|
if (isClickRef.current) {
|
|
@@ -1335,7 +1570,7 @@ function Slider({
|
|
|
1335
1570
|
}
|
|
1336
1571
|
|
|
1337
1572
|
// src/components/SegmentedControl.tsx
|
|
1338
|
-
import { useRef as useRef5, useState as useState4, useLayoutEffect, useCallback as
|
|
1573
|
+
import { useRef as useRef5, useState as useState4, useLayoutEffect, useCallback as useCallback4 } from "react";
|
|
1339
1574
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1340
1575
|
function SegmentedControl({
|
|
1341
1576
|
options,
|
|
@@ -1345,7 +1580,7 @@ function SegmentedControl({
|
|
|
1345
1580
|
const containerRef = useRef5(null);
|
|
1346
1581
|
const hasAnimated = useRef5(false);
|
|
1347
1582
|
const [pillStyle, setPillStyle] = useState4(null);
|
|
1348
|
-
const measure =
|
|
1583
|
+
const measure = useCallback4(() => {
|
|
1349
1584
|
const container = containerRef.current;
|
|
1350
1585
|
if (!container) return;
|
|
1351
1586
|
const activeButton = container.querySelector('[data-active="true"]');
|
|
@@ -1499,14 +1734,18 @@ function SpringVisualization({ spring, isSimpleMode }) {
|
|
|
1499
1734
|
}
|
|
1500
1735
|
|
|
1501
1736
|
// src/components/SpringControl.tsx
|
|
1502
|
-
import {
|
|
1737
|
+
import { useCallback as useCallback5, useRef as useRef6, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
1503
1738
|
import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1504
1739
|
function SpringControl({ panelId, path, label, spring, onChange }) {
|
|
1505
|
-
const
|
|
1506
|
-
(
|
|
1740
|
+
const subscribe = useCallback5(
|
|
1741
|
+
(callback) => DialStore.subscribe(panelId, callback),
|
|
1742
|
+
[panelId]
|
|
1743
|
+
);
|
|
1744
|
+
const getSnapshot = useCallback5(
|
|
1507
1745
|
() => DialStore.getSpringMode(panelId, path),
|
|
1508
|
-
|
|
1746
|
+
[panelId, path]
|
|
1509
1747
|
);
|
|
1748
|
+
const mode = useSyncExternalStore2(subscribe, getSnapshot, getSnapshot);
|
|
1510
1749
|
const isSimpleMode = mode === "simple";
|
|
1511
1750
|
const cache = useRef6({
|
|
1512
1751
|
simple: spring.visualDuration !== void 0 ? spring : { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
@@ -1655,14 +1894,18 @@ function EasingVisualization({ easing }) {
|
|
|
1655
1894
|
}
|
|
1656
1895
|
|
|
1657
1896
|
// src/components/TransitionControl.tsx
|
|
1658
|
-
import {
|
|
1897
|
+
import { useCallback as useCallback6, useRef as useRef7, useState as useState5, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1659
1898
|
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1660
1899
|
function TransitionControl({ panelId, path, label, value, onChange }) {
|
|
1661
|
-
const
|
|
1662
|
-
(
|
|
1900
|
+
const subscribe = useCallback6(
|
|
1901
|
+
(callback) => DialStore.subscribe(panelId, callback),
|
|
1902
|
+
[panelId]
|
|
1903
|
+
);
|
|
1904
|
+
const getSnapshot = useCallback6(
|
|
1663
1905
|
() => DialStore.getTransitionMode(panelId, path),
|
|
1664
|
-
|
|
1906
|
+
[panelId, path]
|
|
1665
1907
|
);
|
|
1908
|
+
const mode = useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
|
|
1666
1909
|
const isEasing = mode === "easing";
|
|
1667
1910
|
const isSimpleSpring = mode === "simple";
|
|
1668
1911
|
const cache = useRef7({
|
|
@@ -1801,9 +2044,29 @@ function TextControl({ label, value, onChange, placeholder }) {
|
|
|
1801
2044
|
}
|
|
1802
2045
|
|
|
1803
2046
|
// src/components/SelectControl.tsx
|
|
1804
|
-
import { useState as useState6, useRef as useRef8, useEffect as useEffect5, useCallback as
|
|
2047
|
+
import { useState as useState6, useRef as useRef8, useEffect as useEffect5, useCallback as useCallback7 } from "react";
|
|
1805
2048
|
import { createPortal } from "react-dom";
|
|
1806
2049
|
import { motion as motion3, AnimatePresence as AnimatePresence2 } from "motion/react";
|
|
2050
|
+
|
|
2051
|
+
// src/dropdown-position.ts
|
|
2052
|
+
function getDropdownPosition(trigger, portalRoot, options = {}) {
|
|
2053
|
+
const { dropdownHeight = 0, gap = 4, allowAbove = true } = options;
|
|
2054
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2055
|
+
const rootRect = portalRoot.getBoundingClientRect();
|
|
2056
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom - gap;
|
|
2057
|
+
const above = allowAbove && spaceBelow < dropdownHeight && triggerRect.top > spaceBelow;
|
|
2058
|
+
return {
|
|
2059
|
+
top: above ? triggerRect.top - rootRect.top - dropdownHeight - gap : triggerRect.bottom - rootRect.top + gap,
|
|
2060
|
+
left: triggerRect.left - rootRect.left,
|
|
2061
|
+
width: triggerRect.width,
|
|
2062
|
+
above
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
2065
|
+
function getDialKitPortalRoot(trigger) {
|
|
2066
|
+
return trigger?.closest(".dialkit-root") ?? null;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// src/components/SelectControl.tsx
|
|
1807
2070
|
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1808
2071
|
function toTitleCase(s) {
|
|
1809
2072
|
return s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
@@ -1821,23 +2084,14 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1821
2084
|
const [pos, setPos] = useState6(null);
|
|
1822
2085
|
const normalized = normalizeOptions(options);
|
|
1823
2086
|
const selectedOption = normalized.find((o) => o.value === value);
|
|
1824
|
-
const updatePos =
|
|
2087
|
+
const updatePos = useCallback7(() => {
|
|
1825
2088
|
const el = triggerRef.current;
|
|
1826
|
-
if (!el) return;
|
|
1827
|
-
const rect = el.getBoundingClientRect();
|
|
2089
|
+
if (!el || !portalTarget) return;
|
|
1828
2090
|
const dropdownHeight = 8 + normalized.length * 36;
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
setPos({
|
|
1832
|
-
top: above ? rect.top - 4 : rect.bottom + 4,
|
|
1833
|
-
left: rect.left,
|
|
1834
|
-
width: rect.width,
|
|
1835
|
-
above
|
|
1836
|
-
});
|
|
1837
|
-
}, [normalized.length]);
|
|
2091
|
+
setPos(getDropdownPosition(el, portalTarget, { dropdownHeight }));
|
|
2092
|
+
}, [normalized.length, portalTarget]);
|
|
1838
2093
|
useEffect5(() => {
|
|
1839
|
-
|
|
1840
|
-
setPortalTarget(root ?? document.body);
|
|
2094
|
+
setPortalTarget(getDialKitPortalRoot(triggerRef.current) ?? document.body);
|
|
1841
2095
|
}, []);
|
|
1842
2096
|
useEffect5(() => {
|
|
1843
2097
|
if (!isOpen) return;
|
|
@@ -1896,10 +2150,11 @@ function SelectControl({ label, value, options, onChange }) {
|
|
|
1896
2150
|
exit: { opacity: 0, y: pos.above ? 8 : -8, scale: 0.95 },
|
|
1897
2151
|
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
1898
2152
|
style: {
|
|
1899
|
-
position: "
|
|
2153
|
+
position: "absolute",
|
|
1900
2154
|
left: pos.left,
|
|
2155
|
+
top: pos.top,
|
|
1901
2156
|
width: pos.width,
|
|
1902
|
-
|
|
2157
|
+
transformOrigin: pos.above ? "bottom" : "top"
|
|
1903
2158
|
},
|
|
1904
2159
|
children: normalized.map((option) => /* @__PURE__ */ jsx11(
|
|
1905
2160
|
"button",
|
|
@@ -2000,7 +2255,7 @@ function expandShorthandHex(hex) {
|
|
|
2000
2255
|
}
|
|
2001
2256
|
|
|
2002
2257
|
// src/components/PresetManager.tsx
|
|
2003
|
-
import { useState as useState8, useRef as useRef10, useEffect as useEffect7, useCallback as
|
|
2258
|
+
import { useState as useState8, useRef as useRef10, useEffect as useEffect7, useCallback as useCallback8 } from "react";
|
|
2004
2259
|
import { createPortal as createPortal2 } from "react-dom";
|
|
2005
2260
|
import { motion as motion4, AnimatePresence as AnimatePresence3 } from "motion/react";
|
|
2006
2261
|
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
@@ -2011,7 +2266,7 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
2011
2266
|
const [pos, setPos] = useState8({ top: 0, left: 0, width: 0 });
|
|
2012
2267
|
const hasPresets = presets.length > 0;
|
|
2013
2268
|
const activePreset = presets.find((p) => p.id === activePresetId);
|
|
2014
|
-
const open =
|
|
2269
|
+
const open = useCallback8(() => {
|
|
2015
2270
|
if (!hasPresets) return;
|
|
2016
2271
|
const rect = triggerRef.current?.getBoundingClientRect();
|
|
2017
2272
|
if (rect) {
|
|
@@ -2019,8 +2274,8 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
2019
2274
|
}
|
|
2020
2275
|
setIsOpen(true);
|
|
2021
2276
|
}, [hasPresets]);
|
|
2022
|
-
const close =
|
|
2023
|
-
const toggle =
|
|
2277
|
+
const close = useCallback8(() => setIsOpen(false), []);
|
|
2278
|
+
const toggle = useCallback8(() => {
|
|
2024
2279
|
if (isOpen) close();
|
|
2025
2280
|
else open();
|
|
2026
2281
|
}, [isOpen, open, close]);
|
|
@@ -2128,16 +2383,20 @@ function PresetManager({ panelId, presets, activePresetId, onAdd }) {
|
|
|
2128
2383
|
|
|
2129
2384
|
// src/components/Panel.tsx
|
|
2130
2385
|
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2131
|
-
function Panel({ panel, defaultOpen = true, inline = false }) {
|
|
2386
|
+
function Panel({ panel, defaultOpen = true, inline = false, onOpenChange, variant = "root" }) {
|
|
2132
2387
|
const [copied, setCopied] = useState9(false);
|
|
2133
2388
|
const [isPanelOpen, setIsPanelOpen] = useState9(defaultOpen);
|
|
2134
2389
|
const shortcutCtx = useContext(ShortcutContext);
|
|
2135
2390
|
const hasShortcuts = Object.keys(panel.shortcuts).length > 0;
|
|
2136
|
-
const
|
|
2137
|
-
(
|
|
2391
|
+
const subscribe = useCallback9(
|
|
2392
|
+
(callback) => DialStore.subscribe(panel.id, callback),
|
|
2393
|
+
[panel.id]
|
|
2394
|
+
);
|
|
2395
|
+
const getSnapshot = useCallback9(
|
|
2138
2396
|
() => DialStore.getValues(panel.id),
|
|
2139
|
-
|
|
2397
|
+
[panel.id]
|
|
2140
2398
|
);
|
|
2399
|
+
const values = useSyncExternalStore4(subscribe, getSnapshot, getSnapshot);
|
|
2141
2400
|
const presets = DialStore.getPresets(panel.id);
|
|
2142
2401
|
const activePresetId = DialStore.getActivePresetId(panel.id);
|
|
2143
2402
|
const handleAddPreset = () => {
|
|
@@ -2157,6 +2416,10 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2157
2416
|
setCopied(true);
|
|
2158
2417
|
setTimeout(() => setCopied(false), 1500);
|
|
2159
2418
|
};
|
|
2419
|
+
const handleOpenChange = useCallback9((open) => {
|
|
2420
|
+
setIsPanelOpen(open);
|
|
2421
|
+
onOpenChange?.(open);
|
|
2422
|
+
}, [onOpenChange]);
|
|
2160
2423
|
const renderControl = (control) => {
|
|
2161
2424
|
const value = values[control.path];
|
|
2162
2425
|
switch (control.type) {
|
|
@@ -2330,13 +2593,83 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2330
2593
|
}
|
|
2331
2594
|
)
|
|
2332
2595
|
] });
|
|
2333
|
-
|
|
2596
|
+
if (variant === "section") {
|
|
2597
|
+
return /* @__PURE__ */ jsxs13(Folder, { title: panel.name, defaultOpen, onOpenChange: handleOpenChange, children: [
|
|
2598
|
+
/* @__PURE__ */ jsx14("div", { className: "dialkit-panel-section-toolbar", onClick: (e) => e.stopPropagation(), children: toolbar }),
|
|
2599
|
+
renderControls()
|
|
2600
|
+
] });
|
|
2601
|
+
}
|
|
2602
|
+
return /* @__PURE__ */ jsx14("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ jsx14(Folder, { title: panel.name, defaultOpen, isRoot: true, inline, onOpenChange: handleOpenChange, toolbar, children: renderControls() }) });
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
// src/panel-drag.ts
|
|
2606
|
+
var PANEL_DRAG_THRESHOLD = 8;
|
|
2607
|
+
var COLLAPSED_PANEL_SIZE = 42;
|
|
2608
|
+
var DRAG_EXCLUSION_SELECTOR = [
|
|
2609
|
+
".dialkit-panel-icon",
|
|
2610
|
+
".dialkit-panel-toolbar",
|
|
2611
|
+
"button",
|
|
2612
|
+
"input",
|
|
2613
|
+
"select",
|
|
2614
|
+
"textarea",
|
|
2615
|
+
"a",
|
|
2616
|
+
'[role="button"]',
|
|
2617
|
+
'[contenteditable="true"]'
|
|
2618
|
+
].join(",");
|
|
2619
|
+
function getPanelDragHandle(target, panel) {
|
|
2620
|
+
if (!(target instanceof Element) || !panel) return null;
|
|
2621
|
+
const inner = target.closest(".dialkit-panel-inner");
|
|
2622
|
+
if (!inner || !panel.contains(inner)) return null;
|
|
2623
|
+
if (inner.getAttribute("data-collapsed") === "true") {
|
|
2624
|
+
return inner;
|
|
2625
|
+
}
|
|
2626
|
+
const header = target.closest(".dialkit-panel-header");
|
|
2627
|
+
if (!header || !inner.contains(header)) return null;
|
|
2628
|
+
if (target.closest(DRAG_EXCLUSION_SELECTOR)) return null;
|
|
2629
|
+
return header;
|
|
2630
|
+
}
|
|
2631
|
+
function getPanelDragStart(pointerX, pointerY, panel) {
|
|
2632
|
+
const rect = panel.getBoundingClientRect();
|
|
2633
|
+
return {
|
|
2634
|
+
pointerX,
|
|
2635
|
+
pointerY,
|
|
2636
|
+
elX: rect.left,
|
|
2637
|
+
elY: rect.top
|
|
2638
|
+
};
|
|
2639
|
+
}
|
|
2640
|
+
function getPanelDragOffset(start, pointerX, pointerY) {
|
|
2641
|
+
return {
|
|
2642
|
+
x: start.elX + pointerX - start.pointerX,
|
|
2643
|
+
y: start.elY + pointerY - start.pointerY
|
|
2644
|
+
};
|
|
2645
|
+
}
|
|
2646
|
+
function hasPanelDragMoved(start, pointerX, pointerY) {
|
|
2647
|
+
const dx = pointerX - start.pointerX;
|
|
2648
|
+
const dy = pointerY - start.pointerY;
|
|
2649
|
+
return Math.hypot(dx, dy) >= PANEL_DRAG_THRESHOLD;
|
|
2650
|
+
}
|
|
2651
|
+
function getPanelOriginX(position, offset, viewportWidth = typeof window !== "undefined" ? window.innerWidth : void 0) {
|
|
2652
|
+
if (offset && viewportWidth) {
|
|
2653
|
+
return offset.x + COLLAPSED_PANEL_SIZE / 2 < viewportWidth / 2 ? "left" : "right";
|
|
2654
|
+
}
|
|
2655
|
+
return position.endsWith("left") ? "left" : "right";
|
|
2656
|
+
}
|
|
2657
|
+
function blockPanelDragClick(handle) {
|
|
2658
|
+
const blocker = (event) => {
|
|
2659
|
+
event.preventDefault();
|
|
2660
|
+
event.stopImmediatePropagation();
|
|
2661
|
+
event.stopPropagation();
|
|
2662
|
+
};
|
|
2663
|
+
handle.addEventListener("click", blocker, { capture: true, once: true });
|
|
2664
|
+
window.setTimeout(() => {
|
|
2665
|
+
handle.removeEventListener("click", blocker, true);
|
|
2666
|
+
}, 0);
|
|
2334
2667
|
}
|
|
2335
2668
|
|
|
2336
2669
|
// src/components/DialRoot.tsx
|
|
2337
2670
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
2338
2671
|
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;
|
|
2339
|
-
function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover", theme = "system", productionEnabled = isDevDefault }) {
|
|
2672
|
+
function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover", theme = "system", productionEnabled = isDevDefault, onOpenChange }) {
|
|
2340
2673
|
if (!productionEnabled) return null;
|
|
2341
2674
|
const [panels, setPanels] = useState10([]);
|
|
2342
2675
|
const [mounted, setMounted] = useState10(false);
|
|
@@ -2348,6 +2681,9 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2348
2681
|
const draggingRef = useRef11(false);
|
|
2349
2682
|
const dragStartRef = useRef11(null);
|
|
2350
2683
|
const didDragRef = useRef11(false);
|
|
2684
|
+
const dragTargetRef = useRef11(null);
|
|
2685
|
+
const panelOpenStatesRef = useRef11(/* @__PURE__ */ new Map());
|
|
2686
|
+
const rootOpenRef = useRef11(null);
|
|
2351
2687
|
useEffect8(() => {
|
|
2352
2688
|
setMounted(true);
|
|
2353
2689
|
setPanels(DialStore.getPanels());
|
|
@@ -2356,22 +2692,36 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2356
2692
|
});
|
|
2357
2693
|
return unsubscribe;
|
|
2358
2694
|
}, []);
|
|
2695
|
+
useEffect8(() => {
|
|
2696
|
+
const fallbackOpen = inline || defaultOpen;
|
|
2697
|
+
const nextStates = /* @__PURE__ */ new Map();
|
|
2698
|
+
for (const panel of panels) {
|
|
2699
|
+
nextStates.set(panel.id, panelOpenStatesRef.current.get(panel.id) ?? fallbackOpen);
|
|
2700
|
+
}
|
|
2701
|
+
panelOpenStatesRef.current = nextStates;
|
|
2702
|
+
rootOpenRef.current = Array.from(nextStates.values()).some(Boolean);
|
|
2703
|
+
}, [defaultOpen, inline, panels]);
|
|
2359
2704
|
useEffect8(() => {
|
|
2360
2705
|
if (!panelRef.current || inline) return;
|
|
2361
2706
|
const observer = new MutationObserver(() => {
|
|
2362
|
-
const
|
|
2363
|
-
if (!
|
|
2364
|
-
const collapsed =
|
|
2707
|
+
const inners = panelRef.current?.querySelectorAll(".dialkit-panel-inner");
|
|
2708
|
+
if (!inners || inners.length === 0) return;
|
|
2709
|
+
const collapsed = Array.from(inners).every(
|
|
2710
|
+
(el) => el.getAttribute("data-collapsed") === "true"
|
|
2711
|
+
);
|
|
2712
|
+
const currentDragOffset = dragOffset;
|
|
2365
2713
|
if (!collapsed) {
|
|
2366
|
-
if (
|
|
2367
|
-
lastDragOffset.current =
|
|
2368
|
-
const bubbleCenterX =
|
|
2714
|
+
if (currentDragOffset) {
|
|
2715
|
+
lastDragOffset.current = currentDragOffset;
|
|
2716
|
+
const bubbleCenterX = currentDragOffset.x + 21;
|
|
2369
2717
|
const midX = window.innerWidth / 2;
|
|
2370
2718
|
setActivePosition(bubbleCenterX < midX ? "top-left" : "top-right");
|
|
2371
2719
|
} else {
|
|
2372
2720
|
setActivePosition(position);
|
|
2373
2721
|
}
|
|
2374
2722
|
setDragOffset(null);
|
|
2723
|
+
} else if (currentDragOffset) {
|
|
2724
|
+
lastDragOffset.current = currentDragOffset;
|
|
2375
2725
|
} else if (lastDragOffset.current) {
|
|
2376
2726
|
setDragOffset(lastDragOffset.current);
|
|
2377
2727
|
}
|
|
@@ -2379,46 +2729,51 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2379
2729
|
observer.observe(panelRef.current, { subtree: true, attributes: true, attributeFilter: ["data-collapsed"] });
|
|
2380
2730
|
return () => observer.disconnect();
|
|
2381
2731
|
}, [inline, dragOffset, position]);
|
|
2382
|
-
const handlePointerDown =
|
|
2383
|
-
const
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
pointerY: e.clientY,
|
|
2389
|
-
elX: rect.left,
|
|
2390
|
-
elY: rect.top
|
|
2391
|
-
};
|
|
2732
|
+
const handlePointerDown = useCallback10((e) => {
|
|
2733
|
+
const panel = panelRef.current;
|
|
2734
|
+
const handle = getPanelDragHandle(e.target, panel);
|
|
2735
|
+
if (!panel || !handle) return;
|
|
2736
|
+
dragTargetRef.current = handle;
|
|
2737
|
+
dragStartRef.current = getPanelDragStart(e.clientX, e.clientY, panel);
|
|
2392
2738
|
didDragRef.current = false;
|
|
2393
2739
|
draggingRef.current = true;
|
|
2394
|
-
|
|
2740
|
+
handle.setPointerCapture(e.pointerId);
|
|
2395
2741
|
}, []);
|
|
2396
|
-
const handlePointerMove =
|
|
2742
|
+
const handlePointerMove = useCallback10((e) => {
|
|
2397
2743
|
if (!draggingRef.current || !dragStartRef.current) return;
|
|
2398
|
-
|
|
2399
|
-
const dy = e.clientY - dragStartRef.current.pointerY;
|
|
2400
|
-
if (!didDragRef.current && Math.abs(dx) + Math.abs(dy) < 4) return;
|
|
2744
|
+
if (!didDragRef.current && !hasPanelDragMoved(dragStartRef.current, e.clientX, e.clientY)) return;
|
|
2401
2745
|
didDragRef.current = true;
|
|
2402
|
-
setDragOffset(
|
|
2403
|
-
x: dragStartRef.current.elX + dx,
|
|
2404
|
-
y: dragStartRef.current.elY + dy
|
|
2405
|
-
});
|
|
2746
|
+
setDragOffset(getPanelDragOffset(dragStartRef.current, e.clientX, e.clientY));
|
|
2406
2747
|
}, []);
|
|
2407
|
-
const handlePointerUp =
|
|
2748
|
+
const handlePointerUp = useCallback10((e) => {
|
|
2408
2749
|
if (!draggingRef.current) return;
|
|
2409
2750
|
draggingRef.current = false;
|
|
2410
2751
|
dragStartRef.current = null;
|
|
2752
|
+
const dragTarget = dragTargetRef.current;
|
|
2753
|
+
if (dragTarget?.hasPointerCapture(e.pointerId)) {
|
|
2754
|
+
dragTarget.releasePointerCapture(e.pointerId);
|
|
2755
|
+
}
|
|
2411
2756
|
if (didDragRef.current) {
|
|
2412
2757
|
e.stopPropagation();
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
const blocker = (ev) => {
|
|
2416
|
-
ev.stopPropagation();
|
|
2417
|
-
};
|
|
2418
|
-
inner.addEventListener("click", blocker, { capture: true, once: true });
|
|
2758
|
+
if (dragTarget) {
|
|
2759
|
+
blockPanelDragClick(dragTarget);
|
|
2419
2760
|
}
|
|
2420
2761
|
}
|
|
2762
|
+
dragTargetRef.current = null;
|
|
2421
2763
|
}, []);
|
|
2764
|
+
const handlePanelOpenChange = useCallback10((panelId, open) => {
|
|
2765
|
+
panelOpenStatesRef.current.set(panelId, open);
|
|
2766
|
+
const fallbackOpen = inline || defaultOpen;
|
|
2767
|
+
const nextRootOpen = panels.some((panel) => panelOpenStatesRef.current.get(panel.id) ?? fallbackOpen);
|
|
2768
|
+
if (rootOpenRef.current === nextRootOpen) return;
|
|
2769
|
+
rootOpenRef.current = nextRootOpen;
|
|
2770
|
+
onOpenChange?.(nextRootOpen);
|
|
2771
|
+
}, [defaultOpen, inline, onOpenChange, panels]);
|
|
2772
|
+
const handleRootOpenChange = useCallback10((open) => {
|
|
2773
|
+
if (rootOpenRef.current === open) return;
|
|
2774
|
+
rootOpenRef.current = open;
|
|
2775
|
+
onOpenChange?.(open);
|
|
2776
|
+
}, [onOpenChange]);
|
|
2422
2777
|
if (!mounted || typeof window === "undefined") {
|
|
2423
2778
|
return null;
|
|
2424
2779
|
}
|
|
@@ -2431,18 +2786,51 @@ function DialRoot({ position = "top-right", defaultOpen = true, mode = "popover"
|
|
|
2431
2786
|
right: "auto",
|
|
2432
2787
|
bottom: "auto"
|
|
2433
2788
|
} : void 0;
|
|
2789
|
+
const originX = getPanelOriginX(activePosition, dragOffset);
|
|
2790
|
+
const hasMultiplePanels = panels.length > 1;
|
|
2434
2791
|
const content = /* @__PURE__ */ jsx15(ShortcutListener, { children: /* @__PURE__ */ jsx15("div", { className: "dialkit-root", "data-mode": mode, "data-theme": theme, children: /* @__PURE__ */ jsx15(
|
|
2435
2792
|
"div",
|
|
2436
2793
|
{
|
|
2437
2794
|
ref: panelRef,
|
|
2438
2795
|
className: "dialkit-panel",
|
|
2439
2796
|
"data-position": inline ? void 0 : dragOffset ? void 0 : activePosition,
|
|
2797
|
+
"data-origin-x": inline ? void 0 : originX,
|
|
2440
2798
|
"data-mode": mode,
|
|
2799
|
+
"data-multiple": hasMultiplePanels ? "true" : void 0,
|
|
2441
2800
|
style: dragStyle,
|
|
2442
2801
|
onPointerDown: !inline ? handlePointerDown : void 0,
|
|
2443
2802
|
onPointerMove: !inline ? handlePointerMove : void 0,
|
|
2444
2803
|
onPointerUp: !inline ? handlePointerUp : void 0,
|
|
2445
|
-
|
|
2804
|
+
onPointerCancel: !inline ? handlePointerUp : void 0,
|
|
2805
|
+
children: hasMultiplePanels ? /* @__PURE__ */ jsx15("div", { className: "dialkit-panel-wrapper", children: /* @__PURE__ */ jsx15(
|
|
2806
|
+
Folder,
|
|
2807
|
+
{
|
|
2808
|
+
title: "DialKit",
|
|
2809
|
+
defaultOpen: inline || defaultOpen,
|
|
2810
|
+
isRoot: true,
|
|
2811
|
+
inline,
|
|
2812
|
+
onOpenChange: handleRootOpenChange,
|
|
2813
|
+
panelHeightOffset: 2,
|
|
2814
|
+
children: panels.map((panel) => /* @__PURE__ */ jsx15(
|
|
2815
|
+
Panel,
|
|
2816
|
+
{
|
|
2817
|
+
panel,
|
|
2818
|
+
defaultOpen: true,
|
|
2819
|
+
variant: "section"
|
|
2820
|
+
},
|
|
2821
|
+
panel.id
|
|
2822
|
+
))
|
|
2823
|
+
}
|
|
2824
|
+
) }) : panels.map((panel) => /* @__PURE__ */ jsx15(
|
|
2825
|
+
Panel,
|
|
2826
|
+
{
|
|
2827
|
+
panel,
|
|
2828
|
+
defaultOpen: inline || defaultOpen,
|
|
2829
|
+
inline,
|
|
2830
|
+
onOpenChange: (open) => handlePanelOpenChange(panel.id, open)
|
|
2831
|
+
},
|
|
2832
|
+
panel.id
|
|
2833
|
+
))
|
|
2446
2834
|
}
|
|
2447
2835
|
) }) });
|
|
2448
2836
|
if (inline) {
|
|
@@ -2466,7 +2854,7 @@ function ButtonGroup({ buttons }) {
|
|
|
2466
2854
|
}
|
|
2467
2855
|
|
|
2468
2856
|
// src/components/ShortcutsMenu.tsx
|
|
2469
|
-
import { useState as useState11, useRef as useRef12, useEffect as useEffect9, useCallback as
|
|
2857
|
+
import { useState as useState11, useRef as useRef12, useEffect as useEffect9, useCallback as useCallback11 } from "react";
|
|
2470
2858
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2471
2859
|
import { motion as motion6, AnimatePresence as AnimatePresence5 } from "motion/react";
|
|
2472
2860
|
import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
@@ -2493,15 +2881,15 @@ function ShortcutsMenu({ panelId }) {
|
|
|
2493
2881
|
const triggerRef = useRef12(null);
|
|
2494
2882
|
const dropdownRef = useRef12(null);
|
|
2495
2883
|
const [pos, setPos] = useState11({ top: 0, right: 0 });
|
|
2496
|
-
const open =
|
|
2884
|
+
const open = useCallback11(() => {
|
|
2497
2885
|
const rect = triggerRef.current?.getBoundingClientRect();
|
|
2498
2886
|
if (rect) {
|
|
2499
2887
|
setPos({ top: rect.bottom + 4, right: window.innerWidth - rect.right });
|
|
2500
2888
|
}
|
|
2501
2889
|
setIsOpen(true);
|
|
2502
2890
|
}, []);
|
|
2503
|
-
const close =
|
|
2504
|
-
const toggle =
|
|
2891
|
+
const close = useCallback11(() => setIsOpen(false), []);
|
|
2892
|
+
const toggle = useCallback11(() => {
|
|
2505
2893
|
if (isOpen) close();
|
|
2506
2894
|
else open();
|
|
2507
2895
|
}, [isOpen, open, close]);
|
|
@@ -2598,6 +2986,7 @@ export {
|
|
|
2598
2986
|
TextControl,
|
|
2599
2987
|
Toggle,
|
|
2600
2988
|
TransitionControl,
|
|
2601
|
-
useDialKit
|
|
2989
|
+
useDialKit,
|
|
2990
|
+
useDialKitController
|
|
2602
2991
|
};
|
|
2603
2992
|
//# sourceMappingURL=index.js.map
|