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/vue/index.js
CHANGED
|
@@ -3,6 +3,89 @@ import { computed, onMounted, onUnmounted, ref, shallowRef, watch } from "vue";
|
|
|
3
3
|
|
|
4
4
|
// src/store/DialStore.ts
|
|
5
5
|
var EMPTY_VALUES = Object.freeze({});
|
|
6
|
+
function resolveDialValues(config, flatValues) {
|
|
7
|
+
return resolveConfigValues(config, flatValues, "");
|
|
8
|
+
}
|
|
9
|
+
function flattenDialValueUpdates(config, updates) {
|
|
10
|
+
const values = {};
|
|
11
|
+
if (typeof updates === "object" && updates !== null) {
|
|
12
|
+
flattenConfigUpdates(config, updates, "", values);
|
|
13
|
+
}
|
|
14
|
+
return values;
|
|
15
|
+
}
|
|
16
|
+
function resolveConfigValues(config, flatValues, prefix) {
|
|
17
|
+
const result = {};
|
|
18
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
19
|
+
if (key === "_collapsed") continue;
|
|
20
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
21
|
+
if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
|
|
22
|
+
result[key] = flatValues[path] ?? configValue[0];
|
|
23
|
+
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
24
|
+
result[key] = flatValues[path] ?? configValue;
|
|
25
|
+
} else if (isSpringConfigValue(configValue) || isEasingConfigValue(configValue)) {
|
|
26
|
+
result[key] = flatValues[path] ?? configValue;
|
|
27
|
+
} else if (isActionConfigValue(configValue)) {
|
|
28
|
+
result[key] = flatValues[path] ?? configValue;
|
|
29
|
+
} else if (isSelectConfigValue(configValue)) {
|
|
30
|
+
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
31
|
+
result[key] = flatValues[path] ?? defaultValue;
|
|
32
|
+
} else if (isColorConfigValue(configValue)) {
|
|
33
|
+
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
34
|
+
} else if (isTextConfigValue(configValue)) {
|
|
35
|
+
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
36
|
+
} else if (typeof configValue === "object" && configValue !== null) {
|
|
37
|
+
result[key] = resolveConfigValues(configValue, flatValues, path);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
function flattenConfigUpdates(config, updates, prefix, values) {
|
|
43
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
44
|
+
if (key === "_collapsed" || !(key in updates)) continue;
|
|
45
|
+
const nextValue = updates[key];
|
|
46
|
+
if (nextValue === void 0) continue;
|
|
47
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
48
|
+
if (isActionConfigValue(configValue)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (isLeafConfigValue(configValue)) {
|
|
52
|
+
values[path] = nextValue;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (typeof configValue === "object" && configValue !== null && typeof nextValue === "object" && nextValue !== null && !Array.isArray(nextValue)) {
|
|
56
|
+
flattenConfigUpdates(configValue, nextValue, path, values);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function isLeafConfigValue(value) {
|
|
61
|
+
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);
|
|
62
|
+
}
|
|
63
|
+
function hasType(value, type) {
|
|
64
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
65
|
+
}
|
|
66
|
+
function isSpringConfigValue(value) {
|
|
67
|
+
return hasType(value, "spring");
|
|
68
|
+
}
|
|
69
|
+
function isEasingConfigValue(value) {
|
|
70
|
+
return hasType(value, "easing");
|
|
71
|
+
}
|
|
72
|
+
function isActionConfigValue(value) {
|
|
73
|
+
return hasType(value, "action");
|
|
74
|
+
}
|
|
75
|
+
function isSelectConfigValue(value) {
|
|
76
|
+
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
77
|
+
}
|
|
78
|
+
function isColorConfigValue(value) {
|
|
79
|
+
return hasType(value, "color");
|
|
80
|
+
}
|
|
81
|
+
function isTextConfigValue(value) {
|
|
82
|
+
return hasType(value, "text");
|
|
83
|
+
}
|
|
84
|
+
function getFirstOptionValue(options) {
|
|
85
|
+
const first = options[0];
|
|
86
|
+
if (first === void 0) return "";
|
|
87
|
+
return typeof first === "string" ? first : first.value;
|
|
88
|
+
}
|
|
6
89
|
var DialStoreClass = class {
|
|
7
90
|
constructor() {
|
|
8
91
|
this.panels = /* @__PURE__ */ new Map();
|
|
@@ -13,87 +96,138 @@ var DialStoreClass = class {
|
|
|
13
96
|
this.presets = /* @__PURE__ */ new Map();
|
|
14
97
|
this.activePreset = /* @__PURE__ */ new Map();
|
|
15
98
|
this.baseValues = /* @__PURE__ */ new Map();
|
|
16
|
-
|
|
17
|
-
|
|
99
|
+
this.defaultValues = /* @__PURE__ */ new Map();
|
|
100
|
+
this.registrationCounts = /* @__PURE__ */ new Map();
|
|
101
|
+
this.retainedPanels = /* @__PURE__ */ new Set();
|
|
102
|
+
this.persistConfigs = /* @__PURE__ */ new Map();
|
|
103
|
+
}
|
|
104
|
+
registerPanel(id, name, config, shortcuts, options = {}) {
|
|
105
|
+
this.configurePanelRetention(id, options);
|
|
106
|
+
this.registrationCounts.set(id, (this.registrationCounts.get(id) ?? 0) + 1);
|
|
18
107
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
19
|
-
const
|
|
20
|
-
this.
|
|
108
|
+
const controlsByPath = this.mapControlsByPath(controls);
|
|
109
|
+
const defaultValues = this.flattenValues(config, "");
|
|
110
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
111
|
+
const persisted = this.loadPersistedPanel(id);
|
|
112
|
+
const previousValues = this.panels.get(id)?.values ?? this.snapshots.get(id) ?? persisted?.values ?? {};
|
|
113
|
+
const values = this.reconcileValues(defaultValues, previousValues, controlsByPath);
|
|
114
|
+
const previousBaseValues = this.baseValues.get(id) ?? persisted?.baseValues ?? persisted?.values ?? {};
|
|
115
|
+
const baseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
21
116
|
this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {} });
|
|
22
117
|
this.snapshots.set(id, { ...values });
|
|
23
|
-
this.baseValues.set(id,
|
|
118
|
+
this.baseValues.set(id, baseValues);
|
|
119
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
120
|
+
const existingPresets = this.presets.get(id) ?? persisted?.presets;
|
|
121
|
+
if (existingPresets) {
|
|
122
|
+
this.presets.set(id, this.reconcilePresets(existingPresets, defaultValues, controlsByPath));
|
|
123
|
+
}
|
|
124
|
+
if (!this.activePreset.has(id) && persisted?.activePresetId !== void 0) {
|
|
125
|
+
this.activePreset.set(id, persisted.activePresetId);
|
|
126
|
+
}
|
|
127
|
+
this.persistPanel(id);
|
|
128
|
+
this.notify(id);
|
|
24
129
|
this.notifyGlobal();
|
|
25
130
|
}
|
|
26
|
-
updatePanel(id, name, config, shortcuts) {
|
|
131
|
+
updatePanel(id, name, config, shortcuts, options = {}) {
|
|
132
|
+
this.configurePanelRetention(id, options);
|
|
27
133
|
const existing = this.panels.get(id);
|
|
28
134
|
if (!existing) {
|
|
29
|
-
this.registerPanel(id, name, config, shortcuts);
|
|
135
|
+
this.registerPanel(id, name, config, shortcuts, options);
|
|
30
136
|
return;
|
|
31
137
|
}
|
|
32
138
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
33
139
|
const controlsByPath = this.mapControlsByPath(controls);
|
|
34
140
|
const defaultValues = this.flattenValues(config, "");
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
nextValues[path] = this.normalizePreservedValue(
|
|
38
|
-
existing.values[path],
|
|
39
|
-
defaultValue,
|
|
40
|
-
controlsByPath.get(path)
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
this.initTransitionModes(config, "", nextValues);
|
|
44
|
-
for (const [path, mode] of Object.entries(existing.values)) {
|
|
45
|
-
if (!path.endsWith(".__mode")) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const transitionPath = path.slice(0, -"__mode".length - 1);
|
|
49
|
-
const transitionControl = controlsByPath.get(transitionPath);
|
|
50
|
-
if (transitionControl?.type === "transition") {
|
|
51
|
-
nextValues[path] = mode;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
141
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
142
|
+
const nextValues = this.reconcileValues(defaultValues, existing.values, controlsByPath);
|
|
54
143
|
const nextPanel = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts };
|
|
55
144
|
this.panels.set(id, nextPanel);
|
|
56
145
|
this.snapshots.set(id, { ...nextValues });
|
|
57
146
|
const previousBaseValues = this.baseValues.get(id) ?? {};
|
|
58
|
-
const nextBaseValues =
|
|
59
|
-
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
60
|
-
nextBaseValues[path] = this.normalizePreservedValue(
|
|
61
|
-
previousBaseValues[path],
|
|
62
|
-
defaultValue,
|
|
63
|
-
controlsByPath.get(path)
|
|
64
|
-
);
|
|
65
|
-
}
|
|
147
|
+
const nextBaseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
66
148
|
for (const [path, value] of Object.entries(nextValues)) {
|
|
67
149
|
if (path.endsWith(".__mode")) {
|
|
68
150
|
nextBaseValues[path] = value;
|
|
69
151
|
}
|
|
70
152
|
}
|
|
71
153
|
this.baseValues.set(id, nextBaseValues);
|
|
154
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
155
|
+
this.presets.set(id, this.reconcilePresets(this.presets.get(id) ?? [], defaultValues, controlsByPath));
|
|
156
|
+
this.persistPanel(id);
|
|
72
157
|
this.notify(id);
|
|
73
158
|
this.notifyGlobal();
|
|
74
159
|
}
|
|
75
160
|
unregisterPanel(id) {
|
|
161
|
+
const nextCount = (this.registrationCounts.get(id) ?? 1) - 1;
|
|
162
|
+
if (nextCount > 0) {
|
|
163
|
+
this.registrationCounts.set(id, nextCount);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.registrationCounts.delete(id);
|
|
76
167
|
this.panels.delete(id);
|
|
77
168
|
this.listeners.delete(id);
|
|
78
|
-
this.snapshots.delete(id);
|
|
79
169
|
this.actionListeners.delete(id);
|
|
80
|
-
this.
|
|
170
|
+
if (!this.retainedPanels.has(id)) {
|
|
171
|
+
this.snapshots.delete(id);
|
|
172
|
+
this.baseValues.delete(id);
|
|
173
|
+
this.defaultValues.delete(id);
|
|
174
|
+
this.presets.delete(id);
|
|
175
|
+
this.activePreset.delete(id);
|
|
176
|
+
this.persistConfigs.delete(id);
|
|
177
|
+
}
|
|
81
178
|
this.notifyGlobal();
|
|
82
179
|
}
|
|
83
180
|
updateValue(panelId, path, value) {
|
|
181
|
+
this.updateValues(panelId, { [path]: value });
|
|
182
|
+
}
|
|
183
|
+
updateValues(panelId, updates) {
|
|
84
184
|
const panel = this.panels.get(panelId);
|
|
85
185
|
if (!panel) return;
|
|
86
|
-
|
|
186
|
+
const validUpdates = {};
|
|
187
|
+
for (const [path, value] of Object.entries(updates)) {
|
|
188
|
+
if (!Object.prototype.hasOwnProperty.call(panel.values, path)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const control = this.findControlByPath(panel.controls, path);
|
|
192
|
+
if (control?.type === "action") {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
panel.values[path] = value;
|
|
196
|
+
validUpdates[path] = value;
|
|
197
|
+
}
|
|
198
|
+
if (Object.keys(validUpdates).length === 0) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
87
201
|
const activeId = this.activePreset.get(panelId);
|
|
88
202
|
if (activeId) {
|
|
89
203
|
const presets = this.presets.get(panelId) ?? [];
|
|
90
204
|
const preset = presets.find((p) => p.id === activeId);
|
|
91
|
-
if (preset)
|
|
205
|
+
if (preset) {
|
|
206
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
207
|
+
preset.values[path] = value;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
92
210
|
} else {
|
|
93
211
|
const base = this.baseValues.get(panelId);
|
|
94
|
-
if (base)
|
|
212
|
+
if (base) {
|
|
213
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
214
|
+
base[path] = value;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
95
217
|
}
|
|
96
218
|
this.snapshots.set(panelId, { ...panel.values });
|
|
219
|
+
this.persistPanel(panelId);
|
|
220
|
+
this.notify(panelId);
|
|
221
|
+
}
|
|
222
|
+
resetValues(panelId) {
|
|
223
|
+
const panel = this.panels.get(panelId);
|
|
224
|
+
const defaults = this.defaultValues.get(panelId);
|
|
225
|
+
if (!panel || !defaults) return;
|
|
226
|
+
panel.values = { ...defaults };
|
|
227
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
228
|
+
this.baseValues.set(panelId, { ...defaults });
|
|
229
|
+
this.activePreset.set(panelId, null);
|
|
230
|
+
this.persistPanel(panelId);
|
|
97
231
|
this.notify(panelId);
|
|
98
232
|
}
|
|
99
233
|
updateSpringMode(panelId, path, mode) {
|
|
@@ -109,6 +243,7 @@ var DialStoreClass = class {
|
|
|
109
243
|
if (!panel) return;
|
|
110
244
|
panel.values[`${path}.__mode`] = mode;
|
|
111
245
|
this.snapshots.set(panelId, { ...panel.values });
|
|
246
|
+
this.persistPanel(panelId);
|
|
112
247
|
this.notify(panelId);
|
|
113
248
|
}
|
|
114
249
|
getTransitionMode(panelId, path) {
|
|
@@ -167,6 +302,7 @@ var DialStoreClass = class {
|
|
|
167
302
|
this.presets.set(panelId, [...existing, preset]);
|
|
168
303
|
this.activePreset.set(panelId, id);
|
|
169
304
|
this.snapshots.set(panelId, { ...panel.values });
|
|
305
|
+
this.persistPanel(panelId);
|
|
170
306
|
this.notify(panelId);
|
|
171
307
|
return id;
|
|
172
308
|
}
|
|
@@ -179,6 +315,7 @@ var DialStoreClass = class {
|
|
|
179
315
|
panel.values = { ...preset.values };
|
|
180
316
|
this.snapshots.set(panelId, { ...panel.values });
|
|
181
317
|
this.activePreset.set(panelId, presetId);
|
|
318
|
+
this.persistPanel(panelId);
|
|
182
319
|
this.notify(panelId);
|
|
183
320
|
}
|
|
184
321
|
deletePreset(panelId, presetId) {
|
|
@@ -191,6 +328,7 @@ var DialStoreClass = class {
|
|
|
191
328
|
if (panel) {
|
|
192
329
|
this.snapshots.set(panelId, { ...panel.values });
|
|
193
330
|
}
|
|
331
|
+
this.persistPanel(panelId);
|
|
194
332
|
this.notify(panelId);
|
|
195
333
|
}
|
|
196
334
|
getPresets(panelId) {
|
|
@@ -207,6 +345,7 @@ var DialStoreClass = class {
|
|
|
207
345
|
this.snapshots.set(panelId, { ...panel.values });
|
|
208
346
|
}
|
|
209
347
|
this.activePreset.set(panelId, null);
|
|
348
|
+
this.persistPanel(panelId);
|
|
210
349
|
this.notify(panelId);
|
|
211
350
|
}
|
|
212
351
|
resolveShortcutTarget(key, modifier) {
|
|
@@ -237,6 +376,94 @@ var DialStoreClass = class {
|
|
|
237
376
|
}
|
|
238
377
|
return results;
|
|
239
378
|
}
|
|
379
|
+
configurePanelRetention(id, options) {
|
|
380
|
+
if (options.retainOnUnmount) {
|
|
381
|
+
this.retainedPanels.add(id);
|
|
382
|
+
}
|
|
383
|
+
const persistConfig = this.normalizePersistConfig(id, options.persist);
|
|
384
|
+
if (persistConfig) {
|
|
385
|
+
this.persistConfigs.set(id, persistConfig);
|
|
386
|
+
this.retainedPanels.add(id);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
reconcileValues(defaultValues, previousValues, controlsByPath) {
|
|
390
|
+
const nextValues = {};
|
|
391
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
392
|
+
if (path.endsWith(".__mode")) {
|
|
393
|
+
const transitionPath = path.slice(0, -".__mode".length);
|
|
394
|
+
const transitionControl = controlsByPath.get(transitionPath);
|
|
395
|
+
nextValues[path] = transitionControl?.type === "transition" && previousValues[path] !== void 0 ? previousValues[path] : defaultValue;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
nextValues[path] = this.normalizePreservedValue(
|
|
399
|
+
previousValues[path],
|
|
400
|
+
defaultValue,
|
|
401
|
+
controlsByPath.get(path)
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
return nextValues;
|
|
405
|
+
}
|
|
406
|
+
reconcilePresets(presets, defaultValues, controlsByPath) {
|
|
407
|
+
return presets.map((preset) => ({
|
|
408
|
+
...preset,
|
|
409
|
+
values: this.reconcileValues(defaultValues, preset.values, controlsByPath)
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
412
|
+
normalizePersistConfig(id, persist) {
|
|
413
|
+
if (!persist) return null;
|
|
414
|
+
const options = typeof persist === "object" ? persist : {};
|
|
415
|
+
return {
|
|
416
|
+
key: options.key ?? `dialkit:${id}`,
|
|
417
|
+
storage: options.storage ?? "localStorage",
|
|
418
|
+
presets: options.presets ?? true
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
loadPersistedPanel(id) {
|
|
422
|
+
const config = this.persistConfigs.get(id);
|
|
423
|
+
if (!config) return null;
|
|
424
|
+
const storage = this.getStorage(config.storage);
|
|
425
|
+
if (!storage) return null;
|
|
426
|
+
try {
|
|
427
|
+
const raw = storage.getItem(config.key);
|
|
428
|
+
if (!raw) return null;
|
|
429
|
+
const parsed = JSON.parse(raw);
|
|
430
|
+
if (parsed?.version !== 1 || typeof parsed !== "object") return null;
|
|
431
|
+
return parsed;
|
|
432
|
+
} catch {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
persistPanel(id) {
|
|
437
|
+
const config = this.persistConfigs.get(id);
|
|
438
|
+
if (!config) return;
|
|
439
|
+
const storage = this.getStorage(config.storage);
|
|
440
|
+
if (!storage) return;
|
|
441
|
+
const values = this.snapshots.get(id) ?? this.panels.get(id)?.values;
|
|
442
|
+
if (!values) return;
|
|
443
|
+
const state = {
|
|
444
|
+
version: 1,
|
|
445
|
+
values,
|
|
446
|
+
baseValues: this.baseValues.get(id) ?? values,
|
|
447
|
+
activePresetId: this.activePreset.get(id) ?? null
|
|
448
|
+
};
|
|
449
|
+
if (config.presets) {
|
|
450
|
+
state.presets = this.presets.get(id) ?? [];
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
storage.setItem(config.key, JSON.stringify(state));
|
|
454
|
+
} catch {
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
getStorage(kind) {
|
|
458
|
+
if (typeof globalThis === "undefined" || !("window" in globalThis)) {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
return kind === "sessionStorage" ? globalThis.window?.sessionStorage ?? null : globalThis.window?.localStorage ?? null;
|
|
463
|
+
} catch {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
240
467
|
findControlByPath(controls, path) {
|
|
241
468
|
for (const control of controls) {
|
|
242
469
|
if (control.path === path) return control;
|
|
@@ -466,21 +693,30 @@ var DialStore = new DialStoreClass();
|
|
|
466
693
|
// src/vue/useDialKit.ts
|
|
467
694
|
var dialKitInstance = 0;
|
|
468
695
|
function useDialKit(name, config, options) {
|
|
469
|
-
|
|
696
|
+
return useDialKitController(name, config, options).values;
|
|
697
|
+
}
|
|
698
|
+
function useDialKitController(name, config, options) {
|
|
699
|
+
const hasStableId = options?.id !== void 0;
|
|
700
|
+
const panelId = options?.id ?? `${name}-${++dialKitInstance}`;
|
|
470
701
|
const configRef = shallowRef(config);
|
|
471
702
|
const onActionRef = ref(options?.onAction);
|
|
472
703
|
const shortcutsRef = shallowRef(options?.shortcuts);
|
|
473
|
-
const
|
|
704
|
+
const persistRef = shallowRef(options?.persist);
|
|
705
|
+
const flatValues = ref(DialStore.getValues(panelId));
|
|
474
706
|
const mounted = ref(false);
|
|
475
707
|
const serializedConfig = computed(() => JSON.stringify(config));
|
|
476
708
|
const serializedShortcuts = computed(() => JSON.stringify(options?.shortcuts));
|
|
709
|
+
const serializedPersist = computed(() => JSON.stringify(options?.persist));
|
|
477
710
|
let unsubscribeValues;
|
|
478
711
|
let unsubscribeActions;
|
|
479
712
|
const register = () => {
|
|
480
|
-
DialStore.registerPanel(panelId, name, configRef.value, shortcutsRef.value
|
|
481
|
-
|
|
713
|
+
DialStore.registerPanel(panelId, name, configRef.value, shortcutsRef.value, {
|
|
714
|
+
retainOnUnmount: hasStableId,
|
|
715
|
+
persist: persistRef.value
|
|
716
|
+
});
|
|
717
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
482
718
|
unsubscribeValues = DialStore.subscribe(panelId, () => {
|
|
483
|
-
|
|
719
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
484
720
|
});
|
|
485
721
|
unsubscribeActions = DialStore.subscribeActions(panelId, (action) => {
|
|
486
722
|
onActionRef.value?.(action);
|
|
@@ -492,12 +728,19 @@ function useDialKit(name, config, options) {
|
|
|
492
728
|
watch(() => options?.shortcuts, (next) => {
|
|
493
729
|
shortcutsRef.value = next;
|
|
494
730
|
});
|
|
495
|
-
watch(
|
|
731
|
+
watch(() => options?.persist, (next) => {
|
|
732
|
+
persistRef.value = next;
|
|
733
|
+
});
|
|
734
|
+
watch([serializedConfig, serializedShortcuts, serializedPersist], () => {
|
|
496
735
|
configRef.value = config;
|
|
497
736
|
shortcutsRef.value = options?.shortcuts;
|
|
737
|
+
persistRef.value = options?.persist;
|
|
498
738
|
if (mounted.value) {
|
|
499
|
-
DialStore.updatePanel(panelId, name, configRef.value, shortcutsRef.value
|
|
500
|
-
|
|
739
|
+
DialStore.updatePanel(panelId, name, configRef.value, shortcutsRef.value, {
|
|
740
|
+
retainOnUnmount: hasStableId,
|
|
741
|
+
persist: persistRef.value
|
|
742
|
+
});
|
|
743
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
501
744
|
}
|
|
502
745
|
});
|
|
503
746
|
onMounted(register);
|
|
@@ -509,58 +752,22 @@ function useDialKit(name, config, options) {
|
|
|
509
752
|
unsubscribeActions?.();
|
|
510
753
|
DialStore.unregisterPanel(panelId);
|
|
511
754
|
});
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
result[key] = flatValues[path] ?? configValue;
|
|
527
|
-
} else if (isSelectConfig(configValue)) {
|
|
528
|
-
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
529
|
-
result[key] = flatValues[path] ?? defaultValue;
|
|
530
|
-
} else if (isColorConfig(configValue)) {
|
|
531
|
-
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
532
|
-
} else if (isTextConfig(configValue)) {
|
|
533
|
-
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
534
|
-
} else if (typeof configValue === "object" && configValue !== null) {
|
|
535
|
-
result[key] = buildResolvedValues(configValue, flatValues, path);
|
|
755
|
+
const values = computed(() => resolveDialValues(configRef.value, flatValues.value));
|
|
756
|
+
return {
|
|
757
|
+
values,
|
|
758
|
+
setValue(path, value) {
|
|
759
|
+
DialStore.updateValue(panelId, path, value);
|
|
760
|
+
},
|
|
761
|
+
setValues(nextValues) {
|
|
762
|
+
DialStore.updateValues(panelId, flattenDialValueUpdates(configRef.value, nextValues));
|
|
763
|
+
},
|
|
764
|
+
resetValues() {
|
|
765
|
+
DialStore.resetValues(panelId);
|
|
766
|
+
},
|
|
767
|
+
getValues() {
|
|
768
|
+
return resolveDialValues(configRef.value, DialStore.getValues(panelId));
|
|
536
769
|
}
|
|
537
|
-
}
|
|
538
|
-
return result;
|
|
539
|
-
}
|
|
540
|
-
function hasType(value, type) {
|
|
541
|
-
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
542
|
-
}
|
|
543
|
-
function isSpringConfig(value) {
|
|
544
|
-
return hasType(value, "spring");
|
|
545
|
-
}
|
|
546
|
-
function isEasingConfig(value) {
|
|
547
|
-
return hasType(value, "easing");
|
|
548
|
-
}
|
|
549
|
-
function isActionConfig(value) {
|
|
550
|
-
return hasType(value, "action");
|
|
551
|
-
}
|
|
552
|
-
function isSelectConfig(value) {
|
|
553
|
-
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
554
|
-
}
|
|
555
|
-
function isColorConfig(value) {
|
|
556
|
-
return hasType(value, "color");
|
|
557
|
-
}
|
|
558
|
-
function isTextConfig(value) {
|
|
559
|
-
return hasType(value, "text");
|
|
560
|
-
}
|
|
561
|
-
function getFirstOptionValue(options) {
|
|
562
|
-
const first = options[0];
|
|
563
|
-
return typeof first === "string" ? first : first.value;
|
|
770
|
+
};
|
|
564
771
|
}
|
|
565
772
|
|
|
566
773
|
// src/vue/directives/dialkit.ts
|
|
@@ -572,11 +779,11 @@ import {
|
|
|
572
779
|
} from "vue";
|
|
573
780
|
|
|
574
781
|
// src/vue/components/DialRoot.ts
|
|
575
|
-
import { defineComponent as defineComponent15, h as h15, onMounted as onMounted10, onUnmounted as onUnmounted9, ref as ref13, Teleport as Teleport3 } from "vue";
|
|
782
|
+
import { computed as computed5, defineComponent as defineComponent15, h as h15, nextTick as nextTick3, onMounted as onMounted10, onUnmounted as onUnmounted9, ref as ref13, Teleport as Teleport3 } from "vue";
|
|
576
783
|
|
|
577
|
-
// src/vue/components/
|
|
578
|
-
import {
|
|
579
|
-
import { AnimatePresence
|
|
784
|
+
// src/vue/components/Folder.ts
|
|
785
|
+
import { defineComponent, h, onMounted as onMounted2, onUnmounted as onUnmounted2, ref as ref2 } from "vue";
|
|
786
|
+
import { AnimatePresence, motion } from "motion-v";
|
|
580
787
|
|
|
581
788
|
// src/icons.ts
|
|
582
789
|
var ICON_CHEVRON = "M6 9.5L12 15.5L18 9.5";
|
|
@@ -610,8 +817,6 @@ var ICON_PANEL = {
|
|
|
610
817
|
};
|
|
611
818
|
|
|
612
819
|
// src/vue/components/Folder.ts
|
|
613
|
-
import { defineComponent, h, onMounted as onMounted2, onUnmounted as onUnmounted2, ref as ref2 } from "vue";
|
|
614
|
-
import { AnimatePresence, motion } from "motion-v";
|
|
615
820
|
var Folder = defineComponent({
|
|
616
821
|
name: "DialKitFolder",
|
|
617
822
|
props: {
|
|
@@ -623,6 +828,10 @@ var Folder = defineComponent({
|
|
|
623
828
|
type: null,
|
|
624
829
|
required: false,
|
|
625
830
|
default: null
|
|
831
|
+
},
|
|
832
|
+
panelHeightOffset: {
|
|
833
|
+
type: Number,
|
|
834
|
+
default: 10
|
|
626
835
|
}
|
|
627
836
|
},
|
|
628
837
|
emits: ["openChange"],
|
|
@@ -722,7 +931,8 @@ var Folder = defineComponent({
|
|
|
722
931
|
};
|
|
723
932
|
const folderContent = () => h("div", {
|
|
724
933
|
ref: props.isRoot ? contentRef : void 0,
|
|
725
|
-
class: `dialkit-folder ${props.isRoot ? "dialkit-folder-root" : ""}
|
|
934
|
+
class: `dialkit-folder ${props.isRoot ? "dialkit-folder-root" : ""}`,
|
|
935
|
+
"data-open": String(isOpen.value)
|
|
726
936
|
}, [
|
|
727
937
|
renderHeader(),
|
|
728
938
|
renderContent()
|
|
@@ -734,7 +944,7 @@ var Folder = defineComponent({
|
|
|
734
944
|
}
|
|
735
945
|
const panelStyle = isOpen.value ? {
|
|
736
946
|
width: 280,
|
|
737
|
-
height: contentHeight.value !== void 0 ? Math.min(contentHeight.value +
|
|
947
|
+
height: contentHeight.value !== void 0 ? Math.min(contentHeight.value + props.panelHeightOffset, windowHeight.value - 32) : "auto",
|
|
738
948
|
borderRadius: 14,
|
|
739
949
|
boxShadow: "var(--dial-shadow)",
|
|
740
950
|
cursor: void 0,
|
|
@@ -761,6 +971,10 @@ var Folder = defineComponent({
|
|
|
761
971
|
}
|
|
762
972
|
});
|
|
763
973
|
|
|
974
|
+
// src/vue/components/Panel.ts
|
|
975
|
+
import { Fragment, defineComponent as defineComponent14, h as h14, onMounted as onMounted9, onUnmounted as onUnmounted8, ref as ref12 } from "vue";
|
|
976
|
+
import { AnimatePresence as AnimatePresence4, motion as motion4 } from "motion-v";
|
|
977
|
+
|
|
764
978
|
// src/vue/components/Slider.ts
|
|
765
979
|
import { defineComponent as defineComponent2, h as h2, computed as computed2, nextTick, onMounted as onMounted3, onUnmounted as onUnmounted3, ref as ref3, watch as watch2 } from "vue";
|
|
766
980
|
import { animate, motionValue } from "motion-v";
|
|
@@ -1893,6 +2107,26 @@ var TextControl = defineComponent9({
|
|
|
1893
2107
|
// src/vue/components/SelectControl.ts
|
|
1894
2108
|
import { Teleport, defineComponent as defineComponent10, h as h10, onMounted as onMounted7, ref as ref8, watch as watch4 } from "vue";
|
|
1895
2109
|
import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion-v";
|
|
2110
|
+
|
|
2111
|
+
// src/dropdown-position.ts
|
|
2112
|
+
function getDropdownPosition(trigger, portalRoot, options = {}) {
|
|
2113
|
+
const { dropdownHeight = 0, gap = 4, allowAbove = true } = options;
|
|
2114
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2115
|
+
const rootRect = portalRoot.getBoundingClientRect();
|
|
2116
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom - gap;
|
|
2117
|
+
const above = allowAbove && spaceBelow < dropdownHeight && triggerRect.top > spaceBelow;
|
|
2118
|
+
return {
|
|
2119
|
+
top: above ? triggerRect.top - rootRect.top - dropdownHeight - gap : triggerRect.bottom - rootRect.top + gap,
|
|
2120
|
+
left: triggerRect.left - rootRect.left,
|
|
2121
|
+
width: triggerRect.width,
|
|
2122
|
+
above
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
function getDialKitPortalRoot(trigger) {
|
|
2126
|
+
return trigger?.closest(".dialkit-root") ?? null;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
// src/vue/components/SelectControl.ts
|
|
1896
2130
|
function toTitleCase(value) {
|
|
1897
2131
|
return value.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
1898
2132
|
}
|
|
@@ -1921,17 +2155,9 @@ var SelectControl = defineComponent10({
|
|
|
1921
2155
|
const normalizedOptions = () => normalizeOptions(props.options);
|
|
1922
2156
|
const selectedLabel = () => normalizedOptions().find((option) => option.value === props.value)?.label ?? props.value;
|
|
1923
2157
|
const updatePos = () => {
|
|
1924
|
-
if (!triggerRef.value) return;
|
|
1925
|
-
const rect = triggerRef.value.getBoundingClientRect();
|
|
2158
|
+
if (!triggerRef.value || !portalTarget.value) return;
|
|
1926
2159
|
const dropdownHeight = 8 + normalizedOptions().length * 36;
|
|
1927
|
-
|
|
1928
|
-
const above = spaceBelow < dropdownHeight && rect.top > spaceBelow;
|
|
1929
|
-
pos.value = {
|
|
1930
|
-
top: above ? rect.top - 4 : rect.bottom + 4,
|
|
1931
|
-
left: rect.left,
|
|
1932
|
-
width: rect.width,
|
|
1933
|
-
above
|
|
1934
|
-
};
|
|
2160
|
+
pos.value = getDropdownPosition(triggerRef.value, portalTarget.value, { dropdownHeight });
|
|
1935
2161
|
};
|
|
1936
2162
|
const openDropdown = () => {
|
|
1937
2163
|
updatePos();
|
|
@@ -1975,8 +2201,7 @@ var SelectControl = defineComponent10({
|
|
|
1975
2201
|
});
|
|
1976
2202
|
});
|
|
1977
2203
|
onMounted7(() => {
|
|
1978
|
-
|
|
1979
|
-
portalTarget.value = root ?? document.body;
|
|
2204
|
+
portalTarget.value = getDialKitPortalRoot(triggerRef.value) ?? document.body;
|
|
1980
2205
|
});
|
|
1981
2206
|
return () => h10("div", { class: "dialkit-select-row" }, [
|
|
1982
2207
|
h10("button", {
|
|
@@ -2012,16 +2237,11 @@ var SelectControl = defineComponent10({
|
|
|
2012
2237
|
exit: { opacity: 0, y: pos.value.above ? 8 : -8, scale: 0.95 },
|
|
2013
2238
|
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
2014
2239
|
style: {
|
|
2015
|
-
position: "
|
|
2240
|
+
position: "absolute",
|
|
2016
2241
|
left: `${pos.value.left}px`,
|
|
2242
|
+
top: `${pos.value.top}px`,
|
|
2017
2243
|
width: `${pos.value.width}px`,
|
|
2018
|
-
|
|
2019
|
-
bottom: `${window.innerHeight - pos.value.top}px`,
|
|
2020
|
-
transformOrigin: "bottom"
|
|
2021
|
-
} : {
|
|
2022
|
-
top: `${pos.value.top}px`,
|
|
2023
|
-
transformOrigin: "top"
|
|
2024
|
-
}
|
|
2244
|
+
transformOrigin: pos.value.above ? "bottom" : "top"
|
|
2025
2245
|
}
|
|
2026
2246
|
}, normalizedOptions().map((option) => h10("button", {
|
|
2027
2247
|
key: option.value,
|
|
@@ -2478,9 +2698,14 @@ var Panel = defineComponent14({
|
|
|
2478
2698
|
inline: {
|
|
2479
2699
|
type: Boolean,
|
|
2480
2700
|
default: false
|
|
2701
|
+
},
|
|
2702
|
+
variant: {
|
|
2703
|
+
type: String,
|
|
2704
|
+
default: "root"
|
|
2481
2705
|
}
|
|
2482
2706
|
},
|
|
2483
|
-
|
|
2707
|
+
emits: ["openChange"],
|
|
2708
|
+
setup(props, { emit }) {
|
|
2484
2709
|
const shortcutCtx = useShortcutContext();
|
|
2485
2710
|
const values = ref12(DialStore.getValues(props.panel.id));
|
|
2486
2711
|
const presets = ref12(DialStore.getPresets(props.panel.id));
|
|
@@ -2529,6 +2754,9 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2529
2754
|
copied.value = false;
|
|
2530
2755
|
}, 1500);
|
|
2531
2756
|
};
|
|
2757
|
+
const handleOpenChange = (open) => {
|
|
2758
|
+
emit("openChange", open);
|
|
2759
|
+
};
|
|
2532
2760
|
const renderControl = (control) => {
|
|
2533
2761
|
const value = values.value[control.path];
|
|
2534
2762
|
switch (control.type) {
|
|
@@ -2697,13 +2925,29 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2697
2925
|
"Copy"
|
|
2698
2926
|
])
|
|
2699
2927
|
]);
|
|
2928
|
+
if (props.variant === "section") {
|
|
2929
|
+
return h14(Folder, {
|
|
2930
|
+
title: props.panel.name,
|
|
2931
|
+
defaultOpen: props.defaultOpen,
|
|
2932
|
+
onOpenChange: handleOpenChange
|
|
2933
|
+
}, {
|
|
2934
|
+
default: () => [
|
|
2935
|
+
h14("div", {
|
|
2936
|
+
class: "dialkit-panel-section-toolbar",
|
|
2937
|
+
onClick: (event) => event.stopPropagation()
|
|
2938
|
+
}, [toolbarNode]),
|
|
2939
|
+
...props.panel.controls.map(renderControl)
|
|
2940
|
+
]
|
|
2941
|
+
});
|
|
2942
|
+
}
|
|
2700
2943
|
return h14("div", { class: "dialkit-panel-wrapper" }, [
|
|
2701
2944
|
h14(Folder, {
|
|
2702
2945
|
title: props.panel.name,
|
|
2703
2946
|
defaultOpen: props.defaultOpen,
|
|
2704
2947
|
isRoot: true,
|
|
2705
2948
|
inline: props.inline,
|
|
2706
|
-
toolbar: () => toolbarNode
|
|
2949
|
+
toolbar: () => toolbarNode,
|
|
2950
|
+
onOpenChange: handleOpenChange
|
|
2707
2951
|
}, {
|
|
2708
2952
|
default: () => props.panel.controls.map(renderControl)
|
|
2709
2953
|
})
|
|
@@ -2712,6 +2956,70 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2712
2956
|
}
|
|
2713
2957
|
});
|
|
2714
2958
|
|
|
2959
|
+
// src/panel-drag.ts
|
|
2960
|
+
var PANEL_DRAG_THRESHOLD = 8;
|
|
2961
|
+
var COLLAPSED_PANEL_SIZE = 42;
|
|
2962
|
+
var DRAG_EXCLUSION_SELECTOR = [
|
|
2963
|
+
".dialkit-panel-icon",
|
|
2964
|
+
".dialkit-panel-toolbar",
|
|
2965
|
+
"button",
|
|
2966
|
+
"input",
|
|
2967
|
+
"select",
|
|
2968
|
+
"textarea",
|
|
2969
|
+
"a",
|
|
2970
|
+
'[role="button"]',
|
|
2971
|
+
'[contenteditable="true"]'
|
|
2972
|
+
].join(",");
|
|
2973
|
+
function getPanelDragHandle(target, panel) {
|
|
2974
|
+
if (!(target instanceof Element) || !panel) return null;
|
|
2975
|
+
const inner = target.closest(".dialkit-panel-inner");
|
|
2976
|
+
if (!inner || !panel.contains(inner)) return null;
|
|
2977
|
+
if (inner.getAttribute("data-collapsed") === "true") {
|
|
2978
|
+
return inner;
|
|
2979
|
+
}
|
|
2980
|
+
const header = target.closest(".dialkit-panel-header");
|
|
2981
|
+
if (!header || !inner.contains(header)) return null;
|
|
2982
|
+
if (target.closest(DRAG_EXCLUSION_SELECTOR)) return null;
|
|
2983
|
+
return header;
|
|
2984
|
+
}
|
|
2985
|
+
function getPanelDragStart(pointerX, pointerY, panel) {
|
|
2986
|
+
const rect = panel.getBoundingClientRect();
|
|
2987
|
+
return {
|
|
2988
|
+
pointerX,
|
|
2989
|
+
pointerY,
|
|
2990
|
+
elX: rect.left,
|
|
2991
|
+
elY: rect.top
|
|
2992
|
+
};
|
|
2993
|
+
}
|
|
2994
|
+
function getPanelDragOffset(start, pointerX, pointerY) {
|
|
2995
|
+
return {
|
|
2996
|
+
x: start.elX + pointerX - start.pointerX,
|
|
2997
|
+
y: start.elY + pointerY - start.pointerY
|
|
2998
|
+
};
|
|
2999
|
+
}
|
|
3000
|
+
function hasPanelDragMoved(start, pointerX, pointerY) {
|
|
3001
|
+
const dx = pointerX - start.pointerX;
|
|
3002
|
+
const dy = pointerY - start.pointerY;
|
|
3003
|
+
return Math.hypot(dx, dy) >= PANEL_DRAG_THRESHOLD;
|
|
3004
|
+
}
|
|
3005
|
+
function getPanelOriginX(position, offset, viewportWidth = typeof window !== "undefined" ? window.innerWidth : void 0) {
|
|
3006
|
+
if (offset && viewportWidth) {
|
|
3007
|
+
return offset.x + COLLAPSED_PANEL_SIZE / 2 < viewportWidth / 2 ? "left" : "right";
|
|
3008
|
+
}
|
|
3009
|
+
return position.endsWith("left") ? "left" : "right";
|
|
3010
|
+
}
|
|
3011
|
+
function blockPanelDragClick(handle) {
|
|
3012
|
+
const blocker = (event) => {
|
|
3013
|
+
event.preventDefault();
|
|
3014
|
+
event.stopImmediatePropagation();
|
|
3015
|
+
event.stopPropagation();
|
|
3016
|
+
};
|
|
3017
|
+
handle.addEventListener("click", blocker, { capture: true, once: true });
|
|
3018
|
+
window.setTimeout(() => {
|
|
3019
|
+
handle.removeEventListener("click", blocker, true);
|
|
3020
|
+
}, 0);
|
|
3021
|
+
}
|
|
3022
|
+
|
|
2715
3023
|
// src/vue/components/DialRoot.ts
|
|
2716
3024
|
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;
|
|
2717
3025
|
var DialRoot = defineComponent15({
|
|
@@ -2738,31 +3046,162 @@ var DialRoot = defineComponent15({
|
|
|
2738
3046
|
default: isDevDefault
|
|
2739
3047
|
}
|
|
2740
3048
|
},
|
|
2741
|
-
|
|
3049
|
+
emits: ["openChange"],
|
|
3050
|
+
setup(props, { emit }) {
|
|
2742
3051
|
const panels = ref13([]);
|
|
2743
3052
|
const mounted = ref13(false);
|
|
3053
|
+
const panelRef = ref13(null);
|
|
3054
|
+
const dragOffset = ref13(null);
|
|
3055
|
+
const activePosition = ref13(props.position);
|
|
2744
3056
|
let unsubscribe;
|
|
3057
|
+
let observer;
|
|
3058
|
+
let lastDragOffset = null;
|
|
3059
|
+
let dragging = false;
|
|
3060
|
+
let dragStart = null;
|
|
3061
|
+
let didDrag = false;
|
|
3062
|
+
let dragTarget = null;
|
|
3063
|
+
let panelOpenStates = /* @__PURE__ */ new Map();
|
|
3064
|
+
let rootOpen;
|
|
3065
|
+
const syncPanelOpenStates = () => {
|
|
3066
|
+
const fallbackOpen = props.mode === "inline" || props.defaultOpen;
|
|
3067
|
+
const nextStates = /* @__PURE__ */ new Map();
|
|
3068
|
+
for (const panel of panels.value) {
|
|
3069
|
+
nextStates.set(panel.id, panelOpenStates.get(panel.id) ?? fallbackOpen);
|
|
3070
|
+
}
|
|
3071
|
+
panelOpenStates = nextStates;
|
|
3072
|
+
rootOpen = Array.from(nextStates.values()).some(Boolean);
|
|
3073
|
+
};
|
|
3074
|
+
const connectObserver = () => {
|
|
3075
|
+
if (observer || props.mode === "inline" || !panelRef.value) return;
|
|
3076
|
+
observer = new MutationObserver(() => {
|
|
3077
|
+
const inners = panelRef.value?.querySelectorAll(".dialkit-panel-inner");
|
|
3078
|
+
if (!inners || inners.length === 0) return;
|
|
3079
|
+
const collapsed = Array.from(inners).every((el) => el.getAttribute("data-collapsed") === "true");
|
|
3080
|
+
const currentDragOffset = dragOffset.value;
|
|
3081
|
+
if (!collapsed) {
|
|
3082
|
+
if (currentDragOffset) {
|
|
3083
|
+
lastDragOffset = currentDragOffset;
|
|
3084
|
+
const bubbleCenterX = currentDragOffset.x + 21;
|
|
3085
|
+
activePosition.value = bubbleCenterX < window.innerWidth / 2 ? "top-left" : "top-right";
|
|
3086
|
+
} else {
|
|
3087
|
+
activePosition.value = props.position;
|
|
3088
|
+
}
|
|
3089
|
+
dragOffset.value = null;
|
|
3090
|
+
} else if (currentDragOffset) {
|
|
3091
|
+
lastDragOffset = currentDragOffset;
|
|
3092
|
+
} else if (lastDragOffset) {
|
|
3093
|
+
dragOffset.value = lastDragOffset;
|
|
3094
|
+
}
|
|
3095
|
+
});
|
|
3096
|
+
observer.observe(panelRef.value, { subtree: true, attributes: true, attributeFilter: ["data-collapsed"] });
|
|
3097
|
+
};
|
|
3098
|
+
const handlePointerDown = (event) => {
|
|
3099
|
+
const panel = panelRef.value;
|
|
3100
|
+
const handle = getPanelDragHandle(event.target, panel);
|
|
3101
|
+
if (!panel || !handle) return;
|
|
3102
|
+
dragTarget = handle;
|
|
3103
|
+
dragStart = getPanelDragStart(event.clientX, event.clientY, panel);
|
|
3104
|
+
didDrag = false;
|
|
3105
|
+
dragging = true;
|
|
3106
|
+
handle.setPointerCapture(event.pointerId);
|
|
3107
|
+
};
|
|
3108
|
+
const handlePointerMove = (event) => {
|
|
3109
|
+
if (!dragging || !dragStart) return;
|
|
3110
|
+
if (!didDrag && !hasPanelDragMoved(dragStart, event.clientX, event.clientY)) return;
|
|
3111
|
+
didDrag = true;
|
|
3112
|
+
dragOffset.value = getPanelDragOffset(dragStart, event.clientX, event.clientY);
|
|
3113
|
+
};
|
|
3114
|
+
const handlePointerUp = (event) => {
|
|
3115
|
+
if (!dragging) return;
|
|
3116
|
+
dragging = false;
|
|
3117
|
+
dragStart = null;
|
|
3118
|
+
const handle = dragTarget;
|
|
3119
|
+
if (handle?.hasPointerCapture(event.pointerId)) {
|
|
3120
|
+
handle.releasePointerCapture(event.pointerId);
|
|
3121
|
+
}
|
|
3122
|
+
if (didDrag) {
|
|
3123
|
+
event.stopPropagation();
|
|
3124
|
+
if (handle) {
|
|
3125
|
+
blockPanelDragClick(handle);
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
dragTarget = null;
|
|
3129
|
+
};
|
|
3130
|
+
const handlePanelOpenChange = (panelId, open) => {
|
|
3131
|
+
panelOpenStates.set(panelId, open);
|
|
3132
|
+
const fallbackOpen = props.mode === "inline" || props.defaultOpen;
|
|
3133
|
+
const nextRootOpen = panels.value.some((panel) => panelOpenStates.get(panel.id) ?? fallbackOpen);
|
|
3134
|
+
if (rootOpen === nextRootOpen) return;
|
|
3135
|
+
rootOpen = nextRootOpen;
|
|
3136
|
+
emit("openChange", nextRootOpen);
|
|
3137
|
+
};
|
|
3138
|
+
const handleRootOpenChange = (open) => {
|
|
3139
|
+
if (rootOpen === open) return;
|
|
3140
|
+
rootOpen = open;
|
|
3141
|
+
emit("openChange", open);
|
|
3142
|
+
};
|
|
3143
|
+
const getDragStyle = () => dragOffset.value ? {
|
|
3144
|
+
top: `${dragOffset.value.y}px`,
|
|
3145
|
+
left: `${dragOffset.value.x}px`,
|
|
3146
|
+
right: "auto",
|
|
3147
|
+
bottom: "auto"
|
|
3148
|
+
} : void 0;
|
|
3149
|
+
const originX = computed5(() => props.mode === "inline" ? void 0 : getPanelOriginX(activePosition.value, dragOffset.value));
|
|
2745
3150
|
onMounted10(() => {
|
|
2746
3151
|
mounted.value = true;
|
|
2747
3152
|
panels.value = DialStore.getPanels();
|
|
3153
|
+
syncPanelOpenStates();
|
|
2748
3154
|
unsubscribe = DialStore.subscribeGlobal(() => {
|
|
2749
3155
|
panels.value = DialStore.getPanels();
|
|
3156
|
+
syncPanelOpenStates();
|
|
2750
3157
|
});
|
|
3158
|
+
nextTick3(connectObserver);
|
|
2751
3159
|
});
|
|
2752
3160
|
onUnmounted9(() => {
|
|
2753
3161
|
unsubscribe?.();
|
|
3162
|
+
observer?.disconnect();
|
|
2754
3163
|
});
|
|
2755
3164
|
const renderContent = () => h15(ShortcutListener, null, {
|
|
2756
3165
|
default: () => h15("div", { class: "dialkit-root", "data-mode": props.mode, "data-theme": props.theme }, [
|
|
2757
3166
|
h15("div", {
|
|
3167
|
+
ref: (el) => {
|
|
3168
|
+
panelRef.value = el;
|
|
3169
|
+
connectObserver();
|
|
3170
|
+
},
|
|
2758
3171
|
class: "dialkit-panel",
|
|
2759
|
-
"data-position": props.mode === "inline" ? void 0 :
|
|
2760
|
-
"data-
|
|
2761
|
-
|
|
3172
|
+
"data-position": props.mode === "inline" ? void 0 : dragOffset.value ? void 0 : activePosition.value,
|
|
3173
|
+
"data-origin-x": originX.value,
|
|
3174
|
+
"data-mode": props.mode,
|
|
3175
|
+
"data-multiple": panels.value.length > 1 ? "true" : void 0,
|
|
3176
|
+
style: getDragStyle(),
|
|
3177
|
+
onPointerdown: props.mode === "inline" ? void 0 : handlePointerDown,
|
|
3178
|
+
onPointermove: props.mode === "inline" ? void 0 : handlePointerMove,
|
|
3179
|
+
onPointerup: props.mode === "inline" ? void 0 : handlePointerUp,
|
|
3180
|
+
onPointercancel: props.mode === "inline" ? void 0 : handlePointerUp
|
|
3181
|
+
}, panels.value.length > 1 ? [
|
|
3182
|
+
h15("div", { class: "dialkit-panel-wrapper" }, [
|
|
3183
|
+
h15(Folder, {
|
|
3184
|
+
title: "DialKit",
|
|
3185
|
+
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
3186
|
+
isRoot: true,
|
|
3187
|
+
inline: props.mode === "inline",
|
|
3188
|
+
onOpenChange: handleRootOpenChange,
|
|
3189
|
+
panelHeightOffset: 2
|
|
3190
|
+
}, {
|
|
3191
|
+
default: () => panels.value.map((panel) => h15(Panel, {
|
|
3192
|
+
key: panel.id,
|
|
3193
|
+
panel,
|
|
3194
|
+
defaultOpen: true,
|
|
3195
|
+
variant: "section"
|
|
3196
|
+
}))
|
|
3197
|
+
})
|
|
3198
|
+
])
|
|
3199
|
+
] : panels.value.map((panel) => h15(Panel, {
|
|
2762
3200
|
key: panel.id,
|
|
2763
3201
|
panel,
|
|
2764
3202
|
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
2765
|
-
inline: props.mode === "inline"
|
|
3203
|
+
inline: props.mode === "inline",
|
|
3204
|
+
onOpenChange: (open) => handlePanelOpenChange(panel.id, open)
|
|
2766
3205
|
})))
|
|
2767
3206
|
])
|
|
2768
3207
|
});
|
|
@@ -3008,6 +3447,7 @@ export {
|
|
|
3008
3447
|
Toggle,
|
|
3009
3448
|
TransitionControl,
|
|
3010
3449
|
useDialKit,
|
|
3450
|
+
useDialKitController,
|
|
3011
3451
|
useShortcutContext,
|
|
3012
3452
|
vDialKit
|
|
3013
3453
|
};
|