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.cjs
CHANGED
|
@@ -38,6 +38,7 @@ __export(vue_exports, {
|
|
|
38
38
|
Toggle: () => Toggle,
|
|
39
39
|
TransitionControl: () => TransitionControl,
|
|
40
40
|
useDialKit: () => useDialKit,
|
|
41
|
+
useDialKitController: () => useDialKitController,
|
|
41
42
|
useShortcutContext: () => useShortcutContext,
|
|
42
43
|
vDialKit: () => vDialKit
|
|
43
44
|
});
|
|
@@ -48,6 +49,89 @@ var import_vue = require("vue");
|
|
|
48
49
|
|
|
49
50
|
// src/store/DialStore.ts
|
|
50
51
|
var EMPTY_VALUES = Object.freeze({});
|
|
52
|
+
function resolveDialValues(config, flatValues) {
|
|
53
|
+
return resolveConfigValues(config, flatValues, "");
|
|
54
|
+
}
|
|
55
|
+
function flattenDialValueUpdates(config, updates) {
|
|
56
|
+
const values = {};
|
|
57
|
+
if (typeof updates === "object" && updates !== null) {
|
|
58
|
+
flattenConfigUpdates(config, updates, "", values);
|
|
59
|
+
}
|
|
60
|
+
return values;
|
|
61
|
+
}
|
|
62
|
+
function resolveConfigValues(config, flatValues, prefix) {
|
|
63
|
+
const result = {};
|
|
64
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
65
|
+
if (key === "_collapsed") continue;
|
|
66
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
67
|
+
if (Array.isArray(configValue) && configValue.length <= 4 && typeof configValue[0] === "number") {
|
|
68
|
+
result[key] = flatValues[path] ?? configValue[0];
|
|
69
|
+
} else if (typeof configValue === "number" || typeof configValue === "boolean" || typeof configValue === "string") {
|
|
70
|
+
result[key] = flatValues[path] ?? configValue;
|
|
71
|
+
} else if (isSpringConfigValue(configValue) || isEasingConfigValue(configValue)) {
|
|
72
|
+
result[key] = flatValues[path] ?? configValue;
|
|
73
|
+
} else if (isActionConfigValue(configValue)) {
|
|
74
|
+
result[key] = flatValues[path] ?? configValue;
|
|
75
|
+
} else if (isSelectConfigValue(configValue)) {
|
|
76
|
+
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
77
|
+
result[key] = flatValues[path] ?? defaultValue;
|
|
78
|
+
} else if (isColorConfigValue(configValue)) {
|
|
79
|
+
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
80
|
+
} else if (isTextConfigValue(configValue)) {
|
|
81
|
+
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
82
|
+
} else if (typeof configValue === "object" && configValue !== null) {
|
|
83
|
+
result[key] = resolveConfigValues(configValue, flatValues, path);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function flattenConfigUpdates(config, updates, prefix, values) {
|
|
89
|
+
for (const [key, configValue] of Object.entries(config)) {
|
|
90
|
+
if (key === "_collapsed" || !(key in updates)) continue;
|
|
91
|
+
const nextValue = updates[key];
|
|
92
|
+
if (nextValue === void 0) continue;
|
|
93
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
94
|
+
if (isActionConfigValue(configValue)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (isLeafConfigValue(configValue)) {
|
|
98
|
+
values[path] = nextValue;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (typeof configValue === "object" && configValue !== null && typeof nextValue === "object" && nextValue !== null && !Array.isArray(nextValue)) {
|
|
102
|
+
flattenConfigUpdates(configValue, nextValue, path, values);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function isLeafConfigValue(value) {
|
|
107
|
+
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);
|
|
108
|
+
}
|
|
109
|
+
function hasType(value, type) {
|
|
110
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
111
|
+
}
|
|
112
|
+
function isSpringConfigValue(value) {
|
|
113
|
+
return hasType(value, "spring");
|
|
114
|
+
}
|
|
115
|
+
function isEasingConfigValue(value) {
|
|
116
|
+
return hasType(value, "easing");
|
|
117
|
+
}
|
|
118
|
+
function isActionConfigValue(value) {
|
|
119
|
+
return hasType(value, "action");
|
|
120
|
+
}
|
|
121
|
+
function isSelectConfigValue(value) {
|
|
122
|
+
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
123
|
+
}
|
|
124
|
+
function isColorConfigValue(value) {
|
|
125
|
+
return hasType(value, "color");
|
|
126
|
+
}
|
|
127
|
+
function isTextConfigValue(value) {
|
|
128
|
+
return hasType(value, "text");
|
|
129
|
+
}
|
|
130
|
+
function getFirstOptionValue(options) {
|
|
131
|
+
const first = options[0];
|
|
132
|
+
if (first === void 0) return "";
|
|
133
|
+
return typeof first === "string" ? first : first.value;
|
|
134
|
+
}
|
|
51
135
|
var DialStoreClass = class {
|
|
52
136
|
constructor() {
|
|
53
137
|
this.panels = /* @__PURE__ */ new Map();
|
|
@@ -58,87 +142,138 @@ var DialStoreClass = class {
|
|
|
58
142
|
this.presets = /* @__PURE__ */ new Map();
|
|
59
143
|
this.activePreset = /* @__PURE__ */ new Map();
|
|
60
144
|
this.baseValues = /* @__PURE__ */ new Map();
|
|
61
|
-
|
|
62
|
-
|
|
145
|
+
this.defaultValues = /* @__PURE__ */ new Map();
|
|
146
|
+
this.registrationCounts = /* @__PURE__ */ new Map();
|
|
147
|
+
this.retainedPanels = /* @__PURE__ */ new Set();
|
|
148
|
+
this.persistConfigs = /* @__PURE__ */ new Map();
|
|
149
|
+
}
|
|
150
|
+
registerPanel(id, name, config, shortcuts, options = {}) {
|
|
151
|
+
this.configurePanelRetention(id, options);
|
|
152
|
+
this.registrationCounts.set(id, (this.registrationCounts.get(id) ?? 0) + 1);
|
|
63
153
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
64
|
-
const
|
|
65
|
-
this.
|
|
154
|
+
const controlsByPath = this.mapControlsByPath(controls);
|
|
155
|
+
const defaultValues = this.flattenValues(config, "");
|
|
156
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
157
|
+
const persisted = this.loadPersistedPanel(id);
|
|
158
|
+
const previousValues = this.panels.get(id)?.values ?? this.snapshots.get(id) ?? persisted?.values ?? {};
|
|
159
|
+
const values = this.reconcileValues(defaultValues, previousValues, controlsByPath);
|
|
160
|
+
const previousBaseValues = this.baseValues.get(id) ?? persisted?.baseValues ?? persisted?.values ?? {};
|
|
161
|
+
const baseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
66
162
|
this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {} });
|
|
67
163
|
this.snapshots.set(id, { ...values });
|
|
68
|
-
this.baseValues.set(id,
|
|
164
|
+
this.baseValues.set(id, baseValues);
|
|
165
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
166
|
+
const existingPresets = this.presets.get(id) ?? persisted?.presets;
|
|
167
|
+
if (existingPresets) {
|
|
168
|
+
this.presets.set(id, this.reconcilePresets(existingPresets, defaultValues, controlsByPath));
|
|
169
|
+
}
|
|
170
|
+
if (!this.activePreset.has(id) && persisted?.activePresetId !== void 0) {
|
|
171
|
+
this.activePreset.set(id, persisted.activePresetId);
|
|
172
|
+
}
|
|
173
|
+
this.persistPanel(id);
|
|
174
|
+
this.notify(id);
|
|
69
175
|
this.notifyGlobal();
|
|
70
176
|
}
|
|
71
|
-
updatePanel(id, name, config, shortcuts) {
|
|
177
|
+
updatePanel(id, name, config, shortcuts, options = {}) {
|
|
178
|
+
this.configurePanelRetention(id, options);
|
|
72
179
|
const existing = this.panels.get(id);
|
|
73
180
|
if (!existing) {
|
|
74
|
-
this.registerPanel(id, name, config, shortcuts);
|
|
181
|
+
this.registerPanel(id, name, config, shortcuts, options);
|
|
75
182
|
return;
|
|
76
183
|
}
|
|
77
184
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
78
185
|
const controlsByPath = this.mapControlsByPath(controls);
|
|
79
186
|
const defaultValues = this.flattenValues(config, "");
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
nextValues[path] = this.normalizePreservedValue(
|
|
83
|
-
existing.values[path],
|
|
84
|
-
defaultValue,
|
|
85
|
-
controlsByPath.get(path)
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
this.initTransitionModes(config, "", nextValues);
|
|
89
|
-
for (const [path, mode] of Object.entries(existing.values)) {
|
|
90
|
-
if (!path.endsWith(".__mode")) {
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
const transitionPath = path.slice(0, -"__mode".length - 1);
|
|
94
|
-
const transitionControl = controlsByPath.get(transitionPath);
|
|
95
|
-
if (transitionControl?.type === "transition") {
|
|
96
|
-
nextValues[path] = mode;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
187
|
+
this.initTransitionModes(config, "", defaultValues);
|
|
188
|
+
const nextValues = this.reconcileValues(defaultValues, existing.values, controlsByPath);
|
|
99
189
|
const nextPanel = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts };
|
|
100
190
|
this.panels.set(id, nextPanel);
|
|
101
191
|
this.snapshots.set(id, { ...nextValues });
|
|
102
192
|
const previousBaseValues = this.baseValues.get(id) ?? {};
|
|
103
|
-
const nextBaseValues =
|
|
104
|
-
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
105
|
-
nextBaseValues[path] = this.normalizePreservedValue(
|
|
106
|
-
previousBaseValues[path],
|
|
107
|
-
defaultValue,
|
|
108
|
-
controlsByPath.get(path)
|
|
109
|
-
);
|
|
110
|
-
}
|
|
193
|
+
const nextBaseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
111
194
|
for (const [path, value] of Object.entries(nextValues)) {
|
|
112
195
|
if (path.endsWith(".__mode")) {
|
|
113
196
|
nextBaseValues[path] = value;
|
|
114
197
|
}
|
|
115
198
|
}
|
|
116
199
|
this.baseValues.set(id, nextBaseValues);
|
|
200
|
+
this.defaultValues.set(id, { ...defaultValues });
|
|
201
|
+
this.presets.set(id, this.reconcilePresets(this.presets.get(id) ?? [], defaultValues, controlsByPath));
|
|
202
|
+
this.persistPanel(id);
|
|
117
203
|
this.notify(id);
|
|
118
204
|
this.notifyGlobal();
|
|
119
205
|
}
|
|
120
206
|
unregisterPanel(id) {
|
|
207
|
+
const nextCount = (this.registrationCounts.get(id) ?? 1) - 1;
|
|
208
|
+
if (nextCount > 0) {
|
|
209
|
+
this.registrationCounts.set(id, nextCount);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this.registrationCounts.delete(id);
|
|
121
213
|
this.panels.delete(id);
|
|
122
214
|
this.listeners.delete(id);
|
|
123
|
-
this.snapshots.delete(id);
|
|
124
215
|
this.actionListeners.delete(id);
|
|
125
|
-
this.
|
|
216
|
+
if (!this.retainedPanels.has(id)) {
|
|
217
|
+
this.snapshots.delete(id);
|
|
218
|
+
this.baseValues.delete(id);
|
|
219
|
+
this.defaultValues.delete(id);
|
|
220
|
+
this.presets.delete(id);
|
|
221
|
+
this.activePreset.delete(id);
|
|
222
|
+
this.persistConfigs.delete(id);
|
|
223
|
+
}
|
|
126
224
|
this.notifyGlobal();
|
|
127
225
|
}
|
|
128
226
|
updateValue(panelId, path, value) {
|
|
227
|
+
this.updateValues(panelId, { [path]: value });
|
|
228
|
+
}
|
|
229
|
+
updateValues(panelId, updates) {
|
|
129
230
|
const panel = this.panels.get(panelId);
|
|
130
231
|
if (!panel) return;
|
|
131
|
-
|
|
232
|
+
const validUpdates = {};
|
|
233
|
+
for (const [path, value] of Object.entries(updates)) {
|
|
234
|
+
if (!Object.prototype.hasOwnProperty.call(panel.values, path)) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const control = this.findControlByPath(panel.controls, path);
|
|
238
|
+
if (control?.type === "action") {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
panel.values[path] = value;
|
|
242
|
+
validUpdates[path] = value;
|
|
243
|
+
}
|
|
244
|
+
if (Object.keys(validUpdates).length === 0) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
132
247
|
const activeId = this.activePreset.get(panelId);
|
|
133
248
|
if (activeId) {
|
|
134
249
|
const presets = this.presets.get(panelId) ?? [];
|
|
135
250
|
const preset = presets.find((p) => p.id === activeId);
|
|
136
|
-
if (preset)
|
|
251
|
+
if (preset) {
|
|
252
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
253
|
+
preset.values[path] = value;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
137
256
|
} else {
|
|
138
257
|
const base = this.baseValues.get(panelId);
|
|
139
|
-
if (base)
|
|
258
|
+
if (base) {
|
|
259
|
+
for (const [path, value] of Object.entries(validUpdates)) {
|
|
260
|
+
base[path] = value;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
140
263
|
}
|
|
141
264
|
this.snapshots.set(panelId, { ...panel.values });
|
|
265
|
+
this.persistPanel(panelId);
|
|
266
|
+
this.notify(panelId);
|
|
267
|
+
}
|
|
268
|
+
resetValues(panelId) {
|
|
269
|
+
const panel = this.panels.get(panelId);
|
|
270
|
+
const defaults = this.defaultValues.get(panelId);
|
|
271
|
+
if (!panel || !defaults) return;
|
|
272
|
+
panel.values = { ...defaults };
|
|
273
|
+
this.snapshots.set(panelId, { ...panel.values });
|
|
274
|
+
this.baseValues.set(panelId, { ...defaults });
|
|
275
|
+
this.activePreset.set(panelId, null);
|
|
276
|
+
this.persistPanel(panelId);
|
|
142
277
|
this.notify(panelId);
|
|
143
278
|
}
|
|
144
279
|
updateSpringMode(panelId, path, mode) {
|
|
@@ -154,6 +289,7 @@ var DialStoreClass = class {
|
|
|
154
289
|
if (!panel) return;
|
|
155
290
|
panel.values[`${path}.__mode`] = mode;
|
|
156
291
|
this.snapshots.set(panelId, { ...panel.values });
|
|
292
|
+
this.persistPanel(panelId);
|
|
157
293
|
this.notify(panelId);
|
|
158
294
|
}
|
|
159
295
|
getTransitionMode(panelId, path) {
|
|
@@ -212,6 +348,7 @@ var DialStoreClass = class {
|
|
|
212
348
|
this.presets.set(panelId, [...existing, preset]);
|
|
213
349
|
this.activePreset.set(panelId, id);
|
|
214
350
|
this.snapshots.set(panelId, { ...panel.values });
|
|
351
|
+
this.persistPanel(panelId);
|
|
215
352
|
this.notify(panelId);
|
|
216
353
|
return id;
|
|
217
354
|
}
|
|
@@ -224,6 +361,7 @@ var DialStoreClass = class {
|
|
|
224
361
|
panel.values = { ...preset.values };
|
|
225
362
|
this.snapshots.set(panelId, { ...panel.values });
|
|
226
363
|
this.activePreset.set(panelId, presetId);
|
|
364
|
+
this.persistPanel(panelId);
|
|
227
365
|
this.notify(panelId);
|
|
228
366
|
}
|
|
229
367
|
deletePreset(panelId, presetId) {
|
|
@@ -236,6 +374,7 @@ var DialStoreClass = class {
|
|
|
236
374
|
if (panel) {
|
|
237
375
|
this.snapshots.set(panelId, { ...panel.values });
|
|
238
376
|
}
|
|
377
|
+
this.persistPanel(panelId);
|
|
239
378
|
this.notify(panelId);
|
|
240
379
|
}
|
|
241
380
|
getPresets(panelId) {
|
|
@@ -252,6 +391,7 @@ var DialStoreClass = class {
|
|
|
252
391
|
this.snapshots.set(panelId, { ...panel.values });
|
|
253
392
|
}
|
|
254
393
|
this.activePreset.set(panelId, null);
|
|
394
|
+
this.persistPanel(panelId);
|
|
255
395
|
this.notify(panelId);
|
|
256
396
|
}
|
|
257
397
|
resolveShortcutTarget(key, modifier) {
|
|
@@ -282,6 +422,94 @@ var DialStoreClass = class {
|
|
|
282
422
|
}
|
|
283
423
|
return results;
|
|
284
424
|
}
|
|
425
|
+
configurePanelRetention(id, options) {
|
|
426
|
+
if (options.retainOnUnmount) {
|
|
427
|
+
this.retainedPanels.add(id);
|
|
428
|
+
}
|
|
429
|
+
const persistConfig = this.normalizePersistConfig(id, options.persist);
|
|
430
|
+
if (persistConfig) {
|
|
431
|
+
this.persistConfigs.set(id, persistConfig);
|
|
432
|
+
this.retainedPanels.add(id);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
reconcileValues(defaultValues, previousValues, controlsByPath) {
|
|
436
|
+
const nextValues = {};
|
|
437
|
+
for (const [path, defaultValue] of Object.entries(defaultValues)) {
|
|
438
|
+
if (path.endsWith(".__mode")) {
|
|
439
|
+
const transitionPath = path.slice(0, -".__mode".length);
|
|
440
|
+
const transitionControl = controlsByPath.get(transitionPath);
|
|
441
|
+
nextValues[path] = transitionControl?.type === "transition" && previousValues[path] !== void 0 ? previousValues[path] : defaultValue;
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
nextValues[path] = this.normalizePreservedValue(
|
|
445
|
+
previousValues[path],
|
|
446
|
+
defaultValue,
|
|
447
|
+
controlsByPath.get(path)
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
return nextValues;
|
|
451
|
+
}
|
|
452
|
+
reconcilePresets(presets, defaultValues, controlsByPath) {
|
|
453
|
+
return presets.map((preset) => ({
|
|
454
|
+
...preset,
|
|
455
|
+
values: this.reconcileValues(defaultValues, preset.values, controlsByPath)
|
|
456
|
+
}));
|
|
457
|
+
}
|
|
458
|
+
normalizePersistConfig(id, persist) {
|
|
459
|
+
if (!persist) return null;
|
|
460
|
+
const options = typeof persist === "object" ? persist : {};
|
|
461
|
+
return {
|
|
462
|
+
key: options.key ?? `dialkit:${id}`,
|
|
463
|
+
storage: options.storage ?? "localStorage",
|
|
464
|
+
presets: options.presets ?? true
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
loadPersistedPanel(id) {
|
|
468
|
+
const config = this.persistConfigs.get(id);
|
|
469
|
+
if (!config) return null;
|
|
470
|
+
const storage = this.getStorage(config.storage);
|
|
471
|
+
if (!storage) return null;
|
|
472
|
+
try {
|
|
473
|
+
const raw = storage.getItem(config.key);
|
|
474
|
+
if (!raw) return null;
|
|
475
|
+
const parsed = JSON.parse(raw);
|
|
476
|
+
if (parsed?.version !== 1 || typeof parsed !== "object") return null;
|
|
477
|
+
return parsed;
|
|
478
|
+
} catch {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
persistPanel(id) {
|
|
483
|
+
const config = this.persistConfigs.get(id);
|
|
484
|
+
if (!config) return;
|
|
485
|
+
const storage = this.getStorage(config.storage);
|
|
486
|
+
if (!storage) return;
|
|
487
|
+
const values = this.snapshots.get(id) ?? this.panels.get(id)?.values;
|
|
488
|
+
if (!values) return;
|
|
489
|
+
const state = {
|
|
490
|
+
version: 1,
|
|
491
|
+
values,
|
|
492
|
+
baseValues: this.baseValues.get(id) ?? values,
|
|
493
|
+
activePresetId: this.activePreset.get(id) ?? null
|
|
494
|
+
};
|
|
495
|
+
if (config.presets) {
|
|
496
|
+
state.presets = this.presets.get(id) ?? [];
|
|
497
|
+
}
|
|
498
|
+
try {
|
|
499
|
+
storage.setItem(config.key, JSON.stringify(state));
|
|
500
|
+
} catch {
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
getStorage(kind) {
|
|
504
|
+
if (typeof globalThis === "undefined" || !("window" in globalThis)) {
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
try {
|
|
508
|
+
return kind === "sessionStorage" ? globalThis.window?.sessionStorage ?? null : globalThis.window?.localStorage ?? null;
|
|
509
|
+
} catch {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
285
513
|
findControlByPath(controls, path) {
|
|
286
514
|
for (const control of controls) {
|
|
287
515
|
if (control.path === path) return control;
|
|
@@ -511,21 +739,30 @@ var DialStore = new DialStoreClass();
|
|
|
511
739
|
// src/vue/useDialKit.ts
|
|
512
740
|
var dialKitInstance = 0;
|
|
513
741
|
function useDialKit(name, config, options) {
|
|
514
|
-
|
|
742
|
+
return useDialKitController(name, config, options).values;
|
|
743
|
+
}
|
|
744
|
+
function useDialKitController(name, config, options) {
|
|
745
|
+
const hasStableId = options?.id !== void 0;
|
|
746
|
+
const panelId = options?.id ?? `${name}-${++dialKitInstance}`;
|
|
515
747
|
const configRef = (0, import_vue.shallowRef)(config);
|
|
516
748
|
const onActionRef = (0, import_vue.ref)(options?.onAction);
|
|
517
749
|
const shortcutsRef = (0, import_vue.shallowRef)(options?.shortcuts);
|
|
518
|
-
const
|
|
750
|
+
const persistRef = (0, import_vue.shallowRef)(options?.persist);
|
|
751
|
+
const flatValues = (0, import_vue.ref)(DialStore.getValues(panelId));
|
|
519
752
|
const mounted = (0, import_vue.ref)(false);
|
|
520
753
|
const serializedConfig = (0, import_vue.computed)(() => JSON.stringify(config));
|
|
521
754
|
const serializedShortcuts = (0, import_vue.computed)(() => JSON.stringify(options?.shortcuts));
|
|
755
|
+
const serializedPersist = (0, import_vue.computed)(() => JSON.stringify(options?.persist));
|
|
522
756
|
let unsubscribeValues;
|
|
523
757
|
let unsubscribeActions;
|
|
524
758
|
const register = () => {
|
|
525
|
-
DialStore.registerPanel(panelId, name, configRef.value, shortcutsRef.value
|
|
526
|
-
|
|
759
|
+
DialStore.registerPanel(panelId, name, configRef.value, shortcutsRef.value, {
|
|
760
|
+
retainOnUnmount: hasStableId,
|
|
761
|
+
persist: persistRef.value
|
|
762
|
+
});
|
|
763
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
527
764
|
unsubscribeValues = DialStore.subscribe(panelId, () => {
|
|
528
|
-
|
|
765
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
529
766
|
});
|
|
530
767
|
unsubscribeActions = DialStore.subscribeActions(panelId, (action) => {
|
|
531
768
|
onActionRef.value?.(action);
|
|
@@ -537,12 +774,19 @@ function useDialKit(name, config, options) {
|
|
|
537
774
|
(0, import_vue.watch)(() => options?.shortcuts, (next) => {
|
|
538
775
|
shortcutsRef.value = next;
|
|
539
776
|
});
|
|
540
|
-
(0, import_vue.watch)(
|
|
777
|
+
(0, import_vue.watch)(() => options?.persist, (next) => {
|
|
778
|
+
persistRef.value = next;
|
|
779
|
+
});
|
|
780
|
+
(0, import_vue.watch)([serializedConfig, serializedShortcuts, serializedPersist], () => {
|
|
541
781
|
configRef.value = config;
|
|
542
782
|
shortcutsRef.value = options?.shortcuts;
|
|
783
|
+
persistRef.value = options?.persist;
|
|
543
784
|
if (mounted.value) {
|
|
544
|
-
DialStore.updatePanel(panelId, name, configRef.value, shortcutsRef.value
|
|
545
|
-
|
|
785
|
+
DialStore.updatePanel(panelId, name, configRef.value, shortcutsRef.value, {
|
|
786
|
+
retainOnUnmount: hasStableId,
|
|
787
|
+
persist: persistRef.value
|
|
788
|
+
});
|
|
789
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
546
790
|
}
|
|
547
791
|
});
|
|
548
792
|
(0, import_vue.onMounted)(register);
|
|
@@ -554,58 +798,22 @@ function useDialKit(name, config, options) {
|
|
|
554
798
|
unsubscribeActions?.();
|
|
555
799
|
DialStore.unregisterPanel(panelId);
|
|
556
800
|
});
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
result[key] = flatValues[path] ?? configValue;
|
|
572
|
-
} else if (isSelectConfig(configValue)) {
|
|
573
|
-
const defaultValue = configValue.default ?? getFirstOptionValue(configValue.options);
|
|
574
|
-
result[key] = flatValues[path] ?? defaultValue;
|
|
575
|
-
} else if (isColorConfig(configValue)) {
|
|
576
|
-
result[key] = flatValues[path] ?? configValue.default ?? "#000000";
|
|
577
|
-
} else if (isTextConfig(configValue)) {
|
|
578
|
-
result[key] = flatValues[path] ?? configValue.default ?? "";
|
|
579
|
-
} else if (typeof configValue === "object" && configValue !== null) {
|
|
580
|
-
result[key] = buildResolvedValues(configValue, flatValues, path);
|
|
801
|
+
const values = (0, import_vue.computed)(() => resolveDialValues(configRef.value, flatValues.value));
|
|
802
|
+
return {
|
|
803
|
+
values,
|
|
804
|
+
setValue(path, value) {
|
|
805
|
+
DialStore.updateValue(panelId, path, value);
|
|
806
|
+
},
|
|
807
|
+
setValues(nextValues) {
|
|
808
|
+
DialStore.updateValues(panelId, flattenDialValueUpdates(configRef.value, nextValues));
|
|
809
|
+
},
|
|
810
|
+
resetValues() {
|
|
811
|
+
DialStore.resetValues(panelId);
|
|
812
|
+
},
|
|
813
|
+
getValues() {
|
|
814
|
+
return resolveDialValues(configRef.value, DialStore.getValues(panelId));
|
|
581
815
|
}
|
|
582
|
-
}
|
|
583
|
-
return result;
|
|
584
|
-
}
|
|
585
|
-
function hasType(value, type) {
|
|
586
|
-
return typeof value === "object" && value !== null && "type" in value && value.type === type;
|
|
587
|
-
}
|
|
588
|
-
function isSpringConfig(value) {
|
|
589
|
-
return hasType(value, "spring");
|
|
590
|
-
}
|
|
591
|
-
function isEasingConfig(value) {
|
|
592
|
-
return hasType(value, "easing");
|
|
593
|
-
}
|
|
594
|
-
function isActionConfig(value) {
|
|
595
|
-
return hasType(value, "action");
|
|
596
|
-
}
|
|
597
|
-
function isSelectConfig(value) {
|
|
598
|
-
return hasType(value, "select") && "options" in value && Array.isArray(value.options);
|
|
599
|
-
}
|
|
600
|
-
function isColorConfig(value) {
|
|
601
|
-
return hasType(value, "color");
|
|
602
|
-
}
|
|
603
|
-
function isTextConfig(value) {
|
|
604
|
-
return hasType(value, "text");
|
|
605
|
-
}
|
|
606
|
-
function getFirstOptionValue(options) {
|
|
607
|
-
const first = options[0];
|
|
608
|
-
return typeof first === "string" ? first : first.value;
|
|
816
|
+
};
|
|
609
817
|
}
|
|
610
818
|
|
|
611
819
|
// src/vue/directives/dialkit.ts
|
|
@@ -614,9 +822,9 @@ var import_vue17 = require("vue");
|
|
|
614
822
|
// src/vue/components/DialRoot.ts
|
|
615
823
|
var import_vue16 = require("vue");
|
|
616
824
|
|
|
617
|
-
// src/vue/components/
|
|
618
|
-
var
|
|
619
|
-
var
|
|
825
|
+
// src/vue/components/Folder.ts
|
|
826
|
+
var import_vue2 = require("vue");
|
|
827
|
+
var import_motion_v = require("motion-v");
|
|
620
828
|
|
|
621
829
|
// src/icons.ts
|
|
622
830
|
var ICON_CHEVRON = "M6 9.5L12 15.5L18 9.5";
|
|
@@ -650,8 +858,6 @@ var ICON_PANEL = {
|
|
|
650
858
|
};
|
|
651
859
|
|
|
652
860
|
// src/vue/components/Folder.ts
|
|
653
|
-
var import_vue2 = require("vue");
|
|
654
|
-
var import_motion_v = require("motion-v");
|
|
655
861
|
var Folder = (0, import_vue2.defineComponent)({
|
|
656
862
|
name: "DialKitFolder",
|
|
657
863
|
props: {
|
|
@@ -663,6 +869,10 @@ var Folder = (0, import_vue2.defineComponent)({
|
|
|
663
869
|
type: null,
|
|
664
870
|
required: false,
|
|
665
871
|
default: null
|
|
872
|
+
},
|
|
873
|
+
panelHeightOffset: {
|
|
874
|
+
type: Number,
|
|
875
|
+
default: 10
|
|
666
876
|
}
|
|
667
877
|
},
|
|
668
878
|
emits: ["openChange"],
|
|
@@ -762,7 +972,8 @@ var Folder = (0, import_vue2.defineComponent)({
|
|
|
762
972
|
};
|
|
763
973
|
const folderContent = () => (0, import_vue2.h)("div", {
|
|
764
974
|
ref: props.isRoot ? contentRef : void 0,
|
|
765
|
-
class: `dialkit-folder ${props.isRoot ? "dialkit-folder-root" : ""}
|
|
975
|
+
class: `dialkit-folder ${props.isRoot ? "dialkit-folder-root" : ""}`,
|
|
976
|
+
"data-open": String(isOpen.value)
|
|
766
977
|
}, [
|
|
767
978
|
renderHeader(),
|
|
768
979
|
renderContent()
|
|
@@ -774,7 +985,7 @@ var Folder = (0, import_vue2.defineComponent)({
|
|
|
774
985
|
}
|
|
775
986
|
const panelStyle = isOpen.value ? {
|
|
776
987
|
width: 280,
|
|
777
|
-
height: contentHeight.value !== void 0 ? Math.min(contentHeight.value +
|
|
988
|
+
height: contentHeight.value !== void 0 ? Math.min(contentHeight.value + props.panelHeightOffset, windowHeight.value - 32) : "auto",
|
|
778
989
|
borderRadius: 14,
|
|
779
990
|
boxShadow: "var(--dial-shadow)",
|
|
780
991
|
cursor: void 0,
|
|
@@ -801,6 +1012,10 @@ var Folder = (0, import_vue2.defineComponent)({
|
|
|
801
1012
|
}
|
|
802
1013
|
});
|
|
803
1014
|
|
|
1015
|
+
// src/vue/components/Panel.ts
|
|
1016
|
+
var import_vue15 = require("vue");
|
|
1017
|
+
var import_motion_v5 = require("motion-v");
|
|
1018
|
+
|
|
804
1019
|
// src/vue/components/Slider.ts
|
|
805
1020
|
var import_vue3 = require("vue");
|
|
806
1021
|
var import_motion_v2 = require("motion-v");
|
|
@@ -1933,6 +2148,26 @@ var TextControl = (0, import_vue10.defineComponent)({
|
|
|
1933
2148
|
// src/vue/components/SelectControl.ts
|
|
1934
2149
|
var import_vue11 = require("vue");
|
|
1935
2150
|
var import_motion_v3 = require("motion-v");
|
|
2151
|
+
|
|
2152
|
+
// src/dropdown-position.ts
|
|
2153
|
+
function getDropdownPosition(trigger, portalRoot, options = {}) {
|
|
2154
|
+
const { dropdownHeight = 0, gap = 4, allowAbove = true } = options;
|
|
2155
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2156
|
+
const rootRect = portalRoot.getBoundingClientRect();
|
|
2157
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom - gap;
|
|
2158
|
+
const above = allowAbove && spaceBelow < dropdownHeight && triggerRect.top > spaceBelow;
|
|
2159
|
+
return {
|
|
2160
|
+
top: above ? triggerRect.top - rootRect.top - dropdownHeight - gap : triggerRect.bottom - rootRect.top + gap,
|
|
2161
|
+
left: triggerRect.left - rootRect.left,
|
|
2162
|
+
width: triggerRect.width,
|
|
2163
|
+
above
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
function getDialKitPortalRoot(trigger) {
|
|
2167
|
+
return trigger?.closest(".dialkit-root") ?? null;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
// src/vue/components/SelectControl.ts
|
|
1936
2171
|
function toTitleCase(value) {
|
|
1937
2172
|
return value.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
1938
2173
|
}
|
|
@@ -1961,17 +2196,9 @@ var SelectControl = (0, import_vue11.defineComponent)({
|
|
|
1961
2196
|
const normalizedOptions = () => normalizeOptions(props.options);
|
|
1962
2197
|
const selectedLabel = () => normalizedOptions().find((option) => option.value === props.value)?.label ?? props.value;
|
|
1963
2198
|
const updatePos = () => {
|
|
1964
|
-
if (!triggerRef.value) return;
|
|
1965
|
-
const rect = triggerRef.value.getBoundingClientRect();
|
|
2199
|
+
if (!triggerRef.value || !portalTarget.value) return;
|
|
1966
2200
|
const dropdownHeight = 8 + normalizedOptions().length * 36;
|
|
1967
|
-
|
|
1968
|
-
const above = spaceBelow < dropdownHeight && rect.top > spaceBelow;
|
|
1969
|
-
pos.value = {
|
|
1970
|
-
top: above ? rect.top - 4 : rect.bottom + 4,
|
|
1971
|
-
left: rect.left,
|
|
1972
|
-
width: rect.width,
|
|
1973
|
-
above
|
|
1974
|
-
};
|
|
2201
|
+
pos.value = getDropdownPosition(triggerRef.value, portalTarget.value, { dropdownHeight });
|
|
1975
2202
|
};
|
|
1976
2203
|
const openDropdown = () => {
|
|
1977
2204
|
updatePos();
|
|
@@ -2015,8 +2242,7 @@ var SelectControl = (0, import_vue11.defineComponent)({
|
|
|
2015
2242
|
});
|
|
2016
2243
|
});
|
|
2017
2244
|
(0, import_vue11.onMounted)(() => {
|
|
2018
|
-
|
|
2019
|
-
portalTarget.value = root ?? document.body;
|
|
2245
|
+
portalTarget.value = getDialKitPortalRoot(triggerRef.value) ?? document.body;
|
|
2020
2246
|
});
|
|
2021
2247
|
return () => (0, import_vue11.h)("div", { class: "dialkit-select-row" }, [
|
|
2022
2248
|
(0, import_vue11.h)("button", {
|
|
@@ -2052,16 +2278,11 @@ var SelectControl = (0, import_vue11.defineComponent)({
|
|
|
2052
2278
|
exit: { opacity: 0, y: pos.value.above ? 8 : -8, scale: 0.95 },
|
|
2053
2279
|
transition: { type: "spring", visualDuration: 0.15, bounce: 0 },
|
|
2054
2280
|
style: {
|
|
2055
|
-
position: "
|
|
2281
|
+
position: "absolute",
|
|
2056
2282
|
left: `${pos.value.left}px`,
|
|
2283
|
+
top: `${pos.value.top}px`,
|
|
2057
2284
|
width: `${pos.value.width}px`,
|
|
2058
|
-
|
|
2059
|
-
bottom: `${window.innerHeight - pos.value.top}px`,
|
|
2060
|
-
transformOrigin: "bottom"
|
|
2061
|
-
} : {
|
|
2062
|
-
top: `${pos.value.top}px`,
|
|
2063
|
-
transformOrigin: "top"
|
|
2064
|
-
}
|
|
2285
|
+
transformOrigin: pos.value.above ? "bottom" : "top"
|
|
2065
2286
|
}
|
|
2066
2287
|
}, normalizedOptions().map((option) => (0, import_vue11.h)("button", {
|
|
2067
2288
|
key: option.value,
|
|
@@ -2518,9 +2739,14 @@ var Panel = (0, import_vue15.defineComponent)({
|
|
|
2518
2739
|
inline: {
|
|
2519
2740
|
type: Boolean,
|
|
2520
2741
|
default: false
|
|
2742
|
+
},
|
|
2743
|
+
variant: {
|
|
2744
|
+
type: String,
|
|
2745
|
+
default: "root"
|
|
2521
2746
|
}
|
|
2522
2747
|
},
|
|
2523
|
-
|
|
2748
|
+
emits: ["openChange"],
|
|
2749
|
+
setup(props, { emit }) {
|
|
2524
2750
|
const shortcutCtx = useShortcutContext();
|
|
2525
2751
|
const values = (0, import_vue15.ref)(DialStore.getValues(props.panel.id));
|
|
2526
2752
|
const presets = (0, import_vue15.ref)(DialStore.getPresets(props.panel.id));
|
|
@@ -2569,6 +2795,9 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2569
2795
|
copied.value = false;
|
|
2570
2796
|
}, 1500);
|
|
2571
2797
|
};
|
|
2798
|
+
const handleOpenChange = (open) => {
|
|
2799
|
+
emit("openChange", open);
|
|
2800
|
+
};
|
|
2572
2801
|
const renderControl = (control) => {
|
|
2573
2802
|
const value = values.value[control.path];
|
|
2574
2803
|
switch (control.type) {
|
|
@@ -2737,13 +2966,29 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2737
2966
|
"Copy"
|
|
2738
2967
|
])
|
|
2739
2968
|
]);
|
|
2969
|
+
if (props.variant === "section") {
|
|
2970
|
+
return (0, import_vue15.h)(Folder, {
|
|
2971
|
+
title: props.panel.name,
|
|
2972
|
+
defaultOpen: props.defaultOpen,
|
|
2973
|
+
onOpenChange: handleOpenChange
|
|
2974
|
+
}, {
|
|
2975
|
+
default: () => [
|
|
2976
|
+
(0, import_vue15.h)("div", {
|
|
2977
|
+
class: "dialkit-panel-section-toolbar",
|
|
2978
|
+
onClick: (event) => event.stopPropagation()
|
|
2979
|
+
}, [toolbarNode]),
|
|
2980
|
+
...props.panel.controls.map(renderControl)
|
|
2981
|
+
]
|
|
2982
|
+
});
|
|
2983
|
+
}
|
|
2740
2984
|
return (0, import_vue15.h)("div", { class: "dialkit-panel-wrapper" }, [
|
|
2741
2985
|
(0, import_vue15.h)(Folder, {
|
|
2742
2986
|
title: props.panel.name,
|
|
2743
2987
|
defaultOpen: props.defaultOpen,
|
|
2744
2988
|
isRoot: true,
|
|
2745
2989
|
inline: props.inline,
|
|
2746
|
-
toolbar: () => toolbarNode
|
|
2990
|
+
toolbar: () => toolbarNode,
|
|
2991
|
+
onOpenChange: handleOpenChange
|
|
2747
2992
|
}, {
|
|
2748
2993
|
default: () => props.panel.controls.map(renderControl)
|
|
2749
2994
|
})
|
|
@@ -2752,6 +2997,70 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2752
2997
|
}
|
|
2753
2998
|
});
|
|
2754
2999
|
|
|
3000
|
+
// src/panel-drag.ts
|
|
3001
|
+
var PANEL_DRAG_THRESHOLD = 8;
|
|
3002
|
+
var COLLAPSED_PANEL_SIZE = 42;
|
|
3003
|
+
var DRAG_EXCLUSION_SELECTOR = [
|
|
3004
|
+
".dialkit-panel-icon",
|
|
3005
|
+
".dialkit-panel-toolbar",
|
|
3006
|
+
"button",
|
|
3007
|
+
"input",
|
|
3008
|
+
"select",
|
|
3009
|
+
"textarea",
|
|
3010
|
+
"a",
|
|
3011
|
+
'[role="button"]',
|
|
3012
|
+
'[contenteditable="true"]'
|
|
3013
|
+
].join(",");
|
|
3014
|
+
function getPanelDragHandle(target, panel) {
|
|
3015
|
+
if (!(target instanceof Element) || !panel) return null;
|
|
3016
|
+
const inner = target.closest(".dialkit-panel-inner");
|
|
3017
|
+
if (!inner || !panel.contains(inner)) return null;
|
|
3018
|
+
if (inner.getAttribute("data-collapsed") === "true") {
|
|
3019
|
+
return inner;
|
|
3020
|
+
}
|
|
3021
|
+
const header = target.closest(".dialkit-panel-header");
|
|
3022
|
+
if (!header || !inner.contains(header)) return null;
|
|
3023
|
+
if (target.closest(DRAG_EXCLUSION_SELECTOR)) return null;
|
|
3024
|
+
return header;
|
|
3025
|
+
}
|
|
3026
|
+
function getPanelDragStart(pointerX, pointerY, panel) {
|
|
3027
|
+
const rect = panel.getBoundingClientRect();
|
|
3028
|
+
return {
|
|
3029
|
+
pointerX,
|
|
3030
|
+
pointerY,
|
|
3031
|
+
elX: rect.left,
|
|
3032
|
+
elY: rect.top
|
|
3033
|
+
};
|
|
3034
|
+
}
|
|
3035
|
+
function getPanelDragOffset(start, pointerX, pointerY) {
|
|
3036
|
+
return {
|
|
3037
|
+
x: start.elX + pointerX - start.pointerX,
|
|
3038
|
+
y: start.elY + pointerY - start.pointerY
|
|
3039
|
+
};
|
|
3040
|
+
}
|
|
3041
|
+
function hasPanelDragMoved(start, pointerX, pointerY) {
|
|
3042
|
+
const dx = pointerX - start.pointerX;
|
|
3043
|
+
const dy = pointerY - start.pointerY;
|
|
3044
|
+
return Math.hypot(dx, dy) >= PANEL_DRAG_THRESHOLD;
|
|
3045
|
+
}
|
|
3046
|
+
function getPanelOriginX(position, offset, viewportWidth = typeof window !== "undefined" ? window.innerWidth : void 0) {
|
|
3047
|
+
if (offset && viewportWidth) {
|
|
3048
|
+
return offset.x + COLLAPSED_PANEL_SIZE / 2 < viewportWidth / 2 ? "left" : "right";
|
|
3049
|
+
}
|
|
3050
|
+
return position.endsWith("left") ? "left" : "right";
|
|
3051
|
+
}
|
|
3052
|
+
function blockPanelDragClick(handle) {
|
|
3053
|
+
const blocker = (event) => {
|
|
3054
|
+
event.preventDefault();
|
|
3055
|
+
event.stopImmediatePropagation();
|
|
3056
|
+
event.stopPropagation();
|
|
3057
|
+
};
|
|
3058
|
+
handle.addEventListener("click", blocker, { capture: true, once: true });
|
|
3059
|
+
window.setTimeout(() => {
|
|
3060
|
+
handle.removeEventListener("click", blocker, true);
|
|
3061
|
+
}, 0);
|
|
3062
|
+
}
|
|
3063
|
+
|
|
2755
3064
|
// src/vue/components/DialRoot.ts
|
|
2756
3065
|
var import_meta = {};
|
|
2757
3066
|
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;
|
|
@@ -2779,31 +3088,162 @@ var DialRoot = (0, import_vue16.defineComponent)({
|
|
|
2779
3088
|
default: isDevDefault
|
|
2780
3089
|
}
|
|
2781
3090
|
},
|
|
2782
|
-
|
|
3091
|
+
emits: ["openChange"],
|
|
3092
|
+
setup(props, { emit }) {
|
|
2783
3093
|
const panels = (0, import_vue16.ref)([]);
|
|
2784
3094
|
const mounted = (0, import_vue16.ref)(false);
|
|
3095
|
+
const panelRef = (0, import_vue16.ref)(null);
|
|
3096
|
+
const dragOffset = (0, import_vue16.ref)(null);
|
|
3097
|
+
const activePosition = (0, import_vue16.ref)(props.position);
|
|
2785
3098
|
let unsubscribe;
|
|
3099
|
+
let observer;
|
|
3100
|
+
let lastDragOffset = null;
|
|
3101
|
+
let dragging = false;
|
|
3102
|
+
let dragStart = null;
|
|
3103
|
+
let didDrag = false;
|
|
3104
|
+
let dragTarget = null;
|
|
3105
|
+
let panelOpenStates = /* @__PURE__ */ new Map();
|
|
3106
|
+
let rootOpen;
|
|
3107
|
+
const syncPanelOpenStates = () => {
|
|
3108
|
+
const fallbackOpen = props.mode === "inline" || props.defaultOpen;
|
|
3109
|
+
const nextStates = /* @__PURE__ */ new Map();
|
|
3110
|
+
for (const panel of panels.value) {
|
|
3111
|
+
nextStates.set(panel.id, panelOpenStates.get(panel.id) ?? fallbackOpen);
|
|
3112
|
+
}
|
|
3113
|
+
panelOpenStates = nextStates;
|
|
3114
|
+
rootOpen = Array.from(nextStates.values()).some(Boolean);
|
|
3115
|
+
};
|
|
3116
|
+
const connectObserver = () => {
|
|
3117
|
+
if (observer || props.mode === "inline" || !panelRef.value) return;
|
|
3118
|
+
observer = new MutationObserver(() => {
|
|
3119
|
+
const inners = panelRef.value?.querySelectorAll(".dialkit-panel-inner");
|
|
3120
|
+
if (!inners || inners.length === 0) return;
|
|
3121
|
+
const collapsed = Array.from(inners).every((el) => el.getAttribute("data-collapsed") === "true");
|
|
3122
|
+
const currentDragOffset = dragOffset.value;
|
|
3123
|
+
if (!collapsed) {
|
|
3124
|
+
if (currentDragOffset) {
|
|
3125
|
+
lastDragOffset = currentDragOffset;
|
|
3126
|
+
const bubbleCenterX = currentDragOffset.x + 21;
|
|
3127
|
+
activePosition.value = bubbleCenterX < window.innerWidth / 2 ? "top-left" : "top-right";
|
|
3128
|
+
} else {
|
|
3129
|
+
activePosition.value = props.position;
|
|
3130
|
+
}
|
|
3131
|
+
dragOffset.value = null;
|
|
3132
|
+
} else if (currentDragOffset) {
|
|
3133
|
+
lastDragOffset = currentDragOffset;
|
|
3134
|
+
} else if (lastDragOffset) {
|
|
3135
|
+
dragOffset.value = lastDragOffset;
|
|
3136
|
+
}
|
|
3137
|
+
});
|
|
3138
|
+
observer.observe(panelRef.value, { subtree: true, attributes: true, attributeFilter: ["data-collapsed"] });
|
|
3139
|
+
};
|
|
3140
|
+
const handlePointerDown = (event) => {
|
|
3141
|
+
const panel = panelRef.value;
|
|
3142
|
+
const handle = getPanelDragHandle(event.target, panel);
|
|
3143
|
+
if (!panel || !handle) return;
|
|
3144
|
+
dragTarget = handle;
|
|
3145
|
+
dragStart = getPanelDragStart(event.clientX, event.clientY, panel);
|
|
3146
|
+
didDrag = false;
|
|
3147
|
+
dragging = true;
|
|
3148
|
+
handle.setPointerCapture(event.pointerId);
|
|
3149
|
+
};
|
|
3150
|
+
const handlePointerMove = (event) => {
|
|
3151
|
+
if (!dragging || !dragStart) return;
|
|
3152
|
+
if (!didDrag && !hasPanelDragMoved(dragStart, event.clientX, event.clientY)) return;
|
|
3153
|
+
didDrag = true;
|
|
3154
|
+
dragOffset.value = getPanelDragOffset(dragStart, event.clientX, event.clientY);
|
|
3155
|
+
};
|
|
3156
|
+
const handlePointerUp = (event) => {
|
|
3157
|
+
if (!dragging) return;
|
|
3158
|
+
dragging = false;
|
|
3159
|
+
dragStart = null;
|
|
3160
|
+
const handle = dragTarget;
|
|
3161
|
+
if (handle?.hasPointerCapture(event.pointerId)) {
|
|
3162
|
+
handle.releasePointerCapture(event.pointerId);
|
|
3163
|
+
}
|
|
3164
|
+
if (didDrag) {
|
|
3165
|
+
event.stopPropagation();
|
|
3166
|
+
if (handle) {
|
|
3167
|
+
blockPanelDragClick(handle);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
dragTarget = null;
|
|
3171
|
+
};
|
|
3172
|
+
const handlePanelOpenChange = (panelId, open) => {
|
|
3173
|
+
panelOpenStates.set(panelId, open);
|
|
3174
|
+
const fallbackOpen = props.mode === "inline" || props.defaultOpen;
|
|
3175
|
+
const nextRootOpen = panels.value.some((panel) => panelOpenStates.get(panel.id) ?? fallbackOpen);
|
|
3176
|
+
if (rootOpen === nextRootOpen) return;
|
|
3177
|
+
rootOpen = nextRootOpen;
|
|
3178
|
+
emit("openChange", nextRootOpen);
|
|
3179
|
+
};
|
|
3180
|
+
const handleRootOpenChange = (open) => {
|
|
3181
|
+
if (rootOpen === open) return;
|
|
3182
|
+
rootOpen = open;
|
|
3183
|
+
emit("openChange", open);
|
|
3184
|
+
};
|
|
3185
|
+
const getDragStyle = () => dragOffset.value ? {
|
|
3186
|
+
top: `${dragOffset.value.y}px`,
|
|
3187
|
+
left: `${dragOffset.value.x}px`,
|
|
3188
|
+
right: "auto",
|
|
3189
|
+
bottom: "auto"
|
|
3190
|
+
} : void 0;
|
|
3191
|
+
const originX = (0, import_vue16.computed)(() => props.mode === "inline" ? void 0 : getPanelOriginX(activePosition.value, dragOffset.value));
|
|
2786
3192
|
(0, import_vue16.onMounted)(() => {
|
|
2787
3193
|
mounted.value = true;
|
|
2788
3194
|
panels.value = DialStore.getPanels();
|
|
3195
|
+
syncPanelOpenStates();
|
|
2789
3196
|
unsubscribe = DialStore.subscribeGlobal(() => {
|
|
2790
3197
|
panels.value = DialStore.getPanels();
|
|
3198
|
+
syncPanelOpenStates();
|
|
2791
3199
|
});
|
|
3200
|
+
(0, import_vue16.nextTick)(connectObserver);
|
|
2792
3201
|
});
|
|
2793
3202
|
(0, import_vue16.onUnmounted)(() => {
|
|
2794
3203
|
unsubscribe?.();
|
|
3204
|
+
observer?.disconnect();
|
|
2795
3205
|
});
|
|
2796
3206
|
const renderContent = () => (0, import_vue16.h)(ShortcutListener, null, {
|
|
2797
3207
|
default: () => (0, import_vue16.h)("div", { class: "dialkit-root", "data-mode": props.mode, "data-theme": props.theme }, [
|
|
2798
3208
|
(0, import_vue16.h)("div", {
|
|
3209
|
+
ref: (el) => {
|
|
3210
|
+
panelRef.value = el;
|
|
3211
|
+
connectObserver();
|
|
3212
|
+
},
|
|
2799
3213
|
class: "dialkit-panel",
|
|
2800
|
-
"data-position": props.mode === "inline" ? void 0 :
|
|
2801
|
-
"data-
|
|
2802
|
-
|
|
3214
|
+
"data-position": props.mode === "inline" ? void 0 : dragOffset.value ? void 0 : activePosition.value,
|
|
3215
|
+
"data-origin-x": originX.value,
|
|
3216
|
+
"data-mode": props.mode,
|
|
3217
|
+
"data-multiple": panels.value.length > 1 ? "true" : void 0,
|
|
3218
|
+
style: getDragStyle(),
|
|
3219
|
+
onPointerdown: props.mode === "inline" ? void 0 : handlePointerDown,
|
|
3220
|
+
onPointermove: props.mode === "inline" ? void 0 : handlePointerMove,
|
|
3221
|
+
onPointerup: props.mode === "inline" ? void 0 : handlePointerUp,
|
|
3222
|
+
onPointercancel: props.mode === "inline" ? void 0 : handlePointerUp
|
|
3223
|
+
}, panels.value.length > 1 ? [
|
|
3224
|
+
(0, import_vue16.h)("div", { class: "dialkit-panel-wrapper" }, [
|
|
3225
|
+
(0, import_vue16.h)(Folder, {
|
|
3226
|
+
title: "DialKit",
|
|
3227
|
+
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
3228
|
+
isRoot: true,
|
|
3229
|
+
inline: props.mode === "inline",
|
|
3230
|
+
onOpenChange: handleRootOpenChange,
|
|
3231
|
+
panelHeightOffset: 2
|
|
3232
|
+
}, {
|
|
3233
|
+
default: () => panels.value.map((panel) => (0, import_vue16.h)(Panel, {
|
|
3234
|
+
key: panel.id,
|
|
3235
|
+
panel,
|
|
3236
|
+
defaultOpen: true,
|
|
3237
|
+
variant: "section"
|
|
3238
|
+
}))
|
|
3239
|
+
})
|
|
3240
|
+
])
|
|
3241
|
+
] : panels.value.map((panel) => (0, import_vue16.h)(Panel, {
|
|
2803
3242
|
key: panel.id,
|
|
2804
3243
|
panel,
|
|
2805
3244
|
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
2806
|
-
inline: props.mode === "inline"
|
|
3245
|
+
inline: props.mode === "inline",
|
|
3246
|
+
onOpenChange: (open) => handlePanelOpenChange(panel.id, open)
|
|
2807
3247
|
})))
|
|
2808
3248
|
])
|
|
2809
3249
|
});
|
|
@@ -3050,6 +3490,7 @@ var ButtonGroup = (0, import_vue19.defineComponent)({
|
|
|
3050
3490
|
Toggle,
|
|
3051
3491
|
TransitionControl,
|
|
3052
3492
|
useDialKit,
|
|
3493
|
+
useDialKitController,
|
|
3053
3494
|
useShortcutContext,
|
|
3054
3495
|
vDialKit
|
|
3055
3496
|
});
|