dialkit 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +293 -2
- package/dist/index.cjs +905 -363
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -9
- package/dist/index.d.ts +46 -9
- package/dist/index.js +910 -370
- package/dist/index.js.map +1 -1
- package/dist/solid/index.cjs +1042 -532
- package/dist/solid/index.cjs.map +1 -1
- package/dist/solid/index.d.cts +36 -3
- package/dist/solid/index.d.ts +36 -3
- package/dist/solid/index.js +911 -402
- package/dist/solid/index.js.map +1 -1
- package/dist/store/index.cjs +490 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.cts +146 -0
- package/dist/store/index.d.ts +146 -0
- package/dist/store/index.js +465 -0
- package/dist/store/index.js.map +1 -0
- package/dist/styles.css +287 -25
- package/dist/svelte/Portal.svelte +30 -0
- package/dist/svelte/Portal.svelte.d.ts +9 -0
- package/dist/svelte/Portal.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ButtonGroup.svelte +16 -0
- package/dist/svelte/components/ButtonGroup.svelte.d.ts +11 -0
- package/dist/svelte/components/ButtonGroup.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ColorControl.svelte +81 -0
- package/dist/svelte/components/ColorControl.svelte.d.ts +9 -0
- package/dist/svelte/components/ColorControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ControlRenderer.svelte +96 -0
- package/dist/svelte/components/ControlRenderer.svelte.d.ts +11 -0
- package/dist/svelte/components/ControlRenderer.svelte.d.ts.map +1 -0
- package/dist/svelte/components/DialRoot.svelte +79 -0
- package/dist/svelte/components/DialRoot.svelte.d.ts +14 -0
- package/dist/svelte/components/DialRoot.svelte.d.ts.map +1 -0
- package/dist/svelte/components/EasingVisualization.svelte +50 -0
- package/dist/svelte/components/EasingVisualization.svelte.d.ts +10 -0
- package/dist/svelte/components/EasingVisualization.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Folder.svelte +213 -0
- package/dist/svelte/components/Folder.svelte.d.ts +14 -0
- package/dist/svelte/components/Folder.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Panel.svelte +149 -0
- package/dist/svelte/components/Panel.svelte.d.ts +10 -0
- package/dist/svelte/components/Panel.svelte.d.ts.map +1 -0
- package/dist/svelte/components/PresetManager.svelte +157 -0
- package/dist/svelte/components/PresetManager.svelte.d.ts +10 -0
- package/dist/svelte/components/PresetManager.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SegmentedControl.svelte +62 -0
- package/dist/svelte/components/SegmentedControl.svelte.d.ts +13 -0
- package/dist/svelte/components/SegmentedControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SelectControl.svelte +152 -0
- package/dist/svelte/components/SelectControl.svelte.d.ts +14 -0
- package/dist/svelte/components/SelectControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ShortcutListener.svelte +265 -0
- package/dist/svelte/components/ShortcutListener.svelte.d.ts +13 -0
- package/dist/svelte/components/ShortcutListener.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ShortcutsMenu.svelte +128 -0
- package/dist/svelte/components/ShortcutsMenu.svelte.d.ts +7 -0
- package/dist/svelte/components/ShortcutsMenu.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Slider.svelte +332 -0
- package/dist/svelte/components/Slider.svelte.d.ts +16 -0
- package/dist/svelte/components/Slider.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SpringControl.svelte +126 -0
- package/dist/svelte/components/SpringControl.svelte.d.ts +12 -0
- package/dist/svelte/components/SpringControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SpringVisualization.svelte +115 -0
- package/dist/svelte/components/SpringVisualization.svelte.d.ts +9 -0
- package/dist/svelte/components/SpringVisualization.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TextControl.svelte +19 -0
- package/dist/svelte/components/TextControl.svelte.d.ts +10 -0
- package/dist/svelte/components/TextControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Toggle.svelte +32 -0
- package/dist/svelte/components/Toggle.svelte.d.ts +12 -0
- package/dist/svelte/components/Toggle.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TransitionControl.svelte +203 -0
- package/dist/svelte/components/TransitionControl.svelte.d.ts +12 -0
- package/dist/svelte/components/TransitionControl.svelte.d.ts.map +1 -0
- package/dist/svelte/components/transitions.d.ts +6 -0
- package/dist/svelte/components/transitions.d.ts.map +1 -0
- package/dist/svelte/components/transitions.js +14 -0
- package/dist/svelte/createDialKit.svelte.d.ts +8 -0
- package/dist/svelte/createDialKit.svelte.d.ts.map +1 -0
- package/dist/svelte/createDialKit.svelte.js +82 -0
- package/dist/svelte/index.d.ts +23 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +23 -0
- package/dist/svelte/shims.d.ts +9 -0
- package/dist/svelte/theme-css.d.ts +2 -0
- package/dist/svelte/theme-css.d.ts.map +1 -0
- package/dist/svelte/theme-css.js +1328 -0
- package/dist/vue/index.cjs +3056 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.cts +675 -0
- package/dist/vue/index.d.ts +675 -0
- package/dist/vue/index.js +3014 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +50 -6
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export const SHORTCUT_CTX = Symbol('dialkit-shortcut');
|
|
3
|
+
|
|
4
|
+
export interface ShortcutContextValue {
|
|
5
|
+
activePanelId: string | null;
|
|
6
|
+
activePath: string | null;
|
|
7
|
+
}
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import { setContext } from 'svelte';
|
|
12
|
+
import { DialStore } from 'dialkit/store';
|
|
13
|
+
import type { Snippet } from 'svelte';
|
|
14
|
+
import {
|
|
15
|
+
getEffectiveStep,
|
|
16
|
+
applySliderDelta,
|
|
17
|
+
findControl,
|
|
18
|
+
DRAG_SENSITIVITY,
|
|
19
|
+
isInputFocused,
|
|
20
|
+
getActiveModifier,
|
|
21
|
+
} from '../../shortcut-utils';
|
|
22
|
+
|
|
23
|
+
let { children } = $props<{ children?: Snippet }>();
|
|
24
|
+
|
|
25
|
+
let activePanelId = $state<string | null>(null);
|
|
26
|
+
let activePath = $state<string | null>(null);
|
|
27
|
+
|
|
28
|
+
const ctx: ShortcutContextValue = {
|
|
29
|
+
get activePanelId() { return activePanelId; },
|
|
30
|
+
get activePath() { return activePath; },
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
setContext(SHORTCUT_CTX, ctx);
|
|
34
|
+
|
|
35
|
+
// --- mutable refs ---
|
|
36
|
+
|
|
37
|
+
let activeKeys = new Set<string>();
|
|
38
|
+
let isDragging = false;
|
|
39
|
+
let lastMouseX: number | null = null;
|
|
40
|
+
let dragAccumulator = 0;
|
|
41
|
+
|
|
42
|
+
function resolveActiveTarget(interaction: string) {
|
|
43
|
+
for (const key of activeKeys) {
|
|
44
|
+
const panels = DialStore.getPanels();
|
|
45
|
+
for (const panel of panels) {
|
|
46
|
+
for (const [path, shortcut] of Object.entries(panel.shortcuts)) {
|
|
47
|
+
if (!shortcut.key) continue;
|
|
48
|
+
if (shortcut.key.toLowerCase() !== key) continue;
|
|
49
|
+
if ((shortcut.interaction ?? 'scroll') !== interaction) continue;
|
|
50
|
+
const control = DialStore.getPanel(panel.id)?.controls
|
|
51
|
+
? findControl(panel.controls, path)
|
|
52
|
+
: null;
|
|
53
|
+
if (control && control.type === 'slider') {
|
|
54
|
+
return { panelId: panel.id, path, control, shortcut };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- event handlers ---
|
|
63
|
+
|
|
64
|
+
function handleKeyDown(e: KeyboardEvent) {
|
|
65
|
+
if (isInputFocused()) return;
|
|
66
|
+
|
|
67
|
+
const key = e.key.toLowerCase();
|
|
68
|
+
|
|
69
|
+
// Arrow keys adjust the active shortcut's slider
|
|
70
|
+
if (key === 'arrowleft' || key === 'arrowright' || key === 'arrowup' || key === 'arrowdown') {
|
|
71
|
+
if (activeKeys.size > 0) {
|
|
72
|
+
const target = resolveActiveTarget('scroll') || resolveActiveTarget('drag') || resolveActiveTarget('move');
|
|
73
|
+
if (target && target.control.type === 'slider') {
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
const direction = (key === 'arrowright' || key === 'arrowup') ? 1 : -1;
|
|
76
|
+
const effectiveStep = getEffectiveStep(target.control, target.shortcut);
|
|
77
|
+
applySliderDelta(target.panelId, target.path, target.control, effectiveStep, direction);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const wasAlreadyHeld = activeKeys.has(key);
|
|
84
|
+
activeKeys.add(key);
|
|
85
|
+
|
|
86
|
+
const modifier = getActiveModifier(e);
|
|
87
|
+
const target = DialStore.resolveShortcutTarget(key, modifier);
|
|
88
|
+
if (target) {
|
|
89
|
+
activePanelId = target.panelId;
|
|
90
|
+
activePath = target.path;
|
|
91
|
+
|
|
92
|
+
// Toggle: flip on first keydown only (not on key repeat)
|
|
93
|
+
if (!wasAlreadyHeld && target.control.type === 'toggle') {
|
|
94
|
+
const currentValue = DialStore.getValue(target.panelId, target.path) as boolean;
|
|
95
|
+
DialStore.updateValue(target.panelId, target.path, !currentValue);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Reset mouse tracking when a new key is pressed (for move/drag)
|
|
100
|
+
if (!wasAlreadyHeld) {
|
|
101
|
+
lastMouseX = null;
|
|
102
|
+
dragAccumulator = 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function handleKeyUp(e: KeyboardEvent) {
|
|
107
|
+
const key = e.key.toLowerCase();
|
|
108
|
+
activeKeys.delete(key);
|
|
109
|
+
|
|
110
|
+
// Reset drag state when key is released
|
|
111
|
+
isDragging = false;
|
|
112
|
+
lastMouseX = null;
|
|
113
|
+
dragAccumulator = 0;
|
|
114
|
+
|
|
115
|
+
if (activeKeys.size === 0) {
|
|
116
|
+
activePanelId = null;
|
|
117
|
+
activePath = null;
|
|
118
|
+
} else {
|
|
119
|
+
let found = false;
|
|
120
|
+
for (const remainingKey of activeKeys) {
|
|
121
|
+
const modifier = getActiveModifier(e);
|
|
122
|
+
const target = DialStore.resolveShortcutTarget(remainingKey, modifier);
|
|
123
|
+
if (target) {
|
|
124
|
+
activePanelId = target.panelId;
|
|
125
|
+
activePath = target.path;
|
|
126
|
+
found = true;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (!found) {
|
|
131
|
+
activePanelId = null;
|
|
132
|
+
activePath = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function handleWheel(e: WheelEvent) {
|
|
138
|
+
if (isInputFocused()) return;
|
|
139
|
+
|
|
140
|
+
const modifier = getActiveModifier(e);
|
|
141
|
+
|
|
142
|
+
// Key+scroll shortcuts
|
|
143
|
+
if (activeKeys.size > 0) {
|
|
144
|
+
for (const key of activeKeys) {
|
|
145
|
+
const target = DialStore.resolveShortcutTarget(key, modifier);
|
|
146
|
+
if (!target) continue;
|
|
147
|
+
|
|
148
|
+
const { panelId, path, control } = target;
|
|
149
|
+
const interaction = control.shortcut?.interaction ?? 'scroll';
|
|
150
|
+
if (interaction !== 'scroll' || control.type !== 'slider') continue;
|
|
151
|
+
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
const effectiveStep = getEffectiveStep(control, control.shortcut!);
|
|
154
|
+
const direction = e.deltaY > 0 ? -1 : 1;
|
|
155
|
+
applySliderDelta(panelId, path, control, effectiveStep, direction);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Scroll-only shortcuts (no key needed)
|
|
161
|
+
const scrollOnlyTargets = DialStore.resolveScrollOnlyTargets();
|
|
162
|
+
for (const { panelId, path, control, shortcut } of scrollOnlyTargets) {
|
|
163
|
+
if (control.type !== 'slider') continue;
|
|
164
|
+
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
const effectiveStep = getEffectiveStep(control, shortcut);
|
|
167
|
+
const direction = e.deltaY > 0 ? -1 : 1;
|
|
168
|
+
applySliderDelta(panelId, path, control, effectiveStep, direction);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function handleMouseDown(e: MouseEvent) {
|
|
174
|
+
if (isInputFocused()) return;
|
|
175
|
+
if (activeKeys.size === 0) return;
|
|
176
|
+
|
|
177
|
+
const target = resolveActiveTarget('drag');
|
|
178
|
+
if (target) {
|
|
179
|
+
isDragging = true;
|
|
180
|
+
lastMouseX = e.clientX;
|
|
181
|
+
dragAccumulator = 0;
|
|
182
|
+
e.preventDefault();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function handleMouseUp() {
|
|
187
|
+
isDragging = false;
|
|
188
|
+
lastMouseX = null;
|
|
189
|
+
dragAccumulator = 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function handleMouseMove(e: MouseEvent) {
|
|
193
|
+
if (isInputFocused()) return;
|
|
194
|
+
if (activeKeys.size === 0) return;
|
|
195
|
+
|
|
196
|
+
// Drag interaction (requires mousedown)
|
|
197
|
+
if (isDragging) {
|
|
198
|
+
const target = resolveActiveTarget('drag');
|
|
199
|
+
if (target && lastMouseX !== null) {
|
|
200
|
+
const deltaX = e.clientX - lastMouseX;
|
|
201
|
+
lastMouseX = e.clientX;
|
|
202
|
+
dragAccumulator += deltaX;
|
|
203
|
+
|
|
204
|
+
const effectiveStep = getEffectiveStep(target.control, target.shortcut);
|
|
205
|
+
const steps = Math.trunc(dragAccumulator / DRAG_SENSITIVITY);
|
|
206
|
+
if (steps !== 0) {
|
|
207
|
+
dragAccumulator -= steps * DRAG_SENSITIVITY;
|
|
208
|
+
applySliderDelta(target.panelId, target.path, target.control, effectiveStep, steps);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Move interaction (no click needed, just key held + mouse movement)
|
|
215
|
+
const moveTarget = resolveActiveTarget('move');
|
|
216
|
+
if (moveTarget) {
|
|
217
|
+
if (lastMouseX === null) {
|
|
218
|
+
lastMouseX = e.clientX;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const deltaX = e.clientX - lastMouseX;
|
|
223
|
+
lastMouseX = e.clientX;
|
|
224
|
+
dragAccumulator += deltaX;
|
|
225
|
+
|
|
226
|
+
const effectiveStep = getEffectiveStep(moveTarget.control, moveTarget.shortcut);
|
|
227
|
+
const steps = Math.trunc(dragAccumulator / DRAG_SENSITIVITY);
|
|
228
|
+
if (steps !== 0) {
|
|
229
|
+
dragAccumulator -= steps * DRAG_SENSITIVITY;
|
|
230
|
+
applySliderDelta(moveTarget.panelId, moveTarget.path, moveTarget.control, effectiveStep, steps);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function handleWindowBlur() {
|
|
236
|
+
activeKeys.clear();
|
|
237
|
+
isDragging = false;
|
|
238
|
+
lastMouseX = null;
|
|
239
|
+
dragAccumulator = 0;
|
|
240
|
+
activePanelId = null;
|
|
241
|
+
activePath = null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
$effect(() => {
|
|
245
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
246
|
+
window.addEventListener('keyup', handleKeyUp);
|
|
247
|
+
window.addEventListener('wheel', handleWheel, { passive: false });
|
|
248
|
+
window.addEventListener('mousedown', handleMouseDown);
|
|
249
|
+
window.addEventListener('mouseup', handleMouseUp);
|
|
250
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
251
|
+
window.addEventListener('blur', handleWindowBlur);
|
|
252
|
+
|
|
253
|
+
return () => {
|
|
254
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
255
|
+
window.removeEventListener('keyup', handleKeyUp);
|
|
256
|
+
window.removeEventListener('wheel', handleWheel);
|
|
257
|
+
window.removeEventListener('mousedown', handleMouseDown);
|
|
258
|
+
window.removeEventListener('mouseup', handleMouseUp);
|
|
259
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
260
|
+
window.removeEventListener('blur', handleWindowBlur);
|
|
261
|
+
};
|
|
262
|
+
});
|
|
263
|
+
</script>
|
|
264
|
+
|
|
265
|
+
{#if children}{@render children()}{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const SHORTCUT_CTX: unique symbol;
|
|
2
|
+
export interface ShortcutContextValue {
|
|
3
|
+
activePanelId: string | null;
|
|
4
|
+
activePath: string | null;
|
|
5
|
+
}
|
|
6
|
+
import type { Snippet } from 'svelte';
|
|
7
|
+
type $$ComponentProps = {
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
};
|
|
10
|
+
declare const ShortcutListener: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type ShortcutListener = ReturnType<typeof ShortcutListener>;
|
|
12
|
+
export default ShortcutListener;
|
|
13
|
+
//# sourceMappingURL=ShortcutListener.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShortcutListener.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ShortcutListener.svelte.ts"],"names":[],"mappings":"AAGE,eAAO,MAAM,YAAY,eAA6B,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAUrC,KAAK,gBAAgB,GAAG;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA+PhD,QAAA,MAAM,gBAAgB,sDAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { DialStore } from 'dialkit/store';
|
|
3
|
+
import type { ShortcutConfig } from 'dialkit/store';
|
|
4
|
+
import Portal from '../Portal.svelte';
|
|
5
|
+
|
|
6
|
+
let { panelId } = $props<{ panelId: string }>();
|
|
7
|
+
|
|
8
|
+
let isOpen = $state(false);
|
|
9
|
+
let triggerEl: HTMLButtonElement | undefined;
|
|
10
|
+
let dropdownEl: HTMLDivElement | undefined;
|
|
11
|
+
let pos = $state({ top: 0, right: 0 });
|
|
12
|
+
|
|
13
|
+
function formatShortcutKey(sc: ShortcutConfig): string {
|
|
14
|
+
if (!sc.key) return '\u2014';
|
|
15
|
+
const mod = sc.modifier === 'alt' ? '\u2325'
|
|
16
|
+
: sc.modifier === 'shift' ? '\u21E7'
|
|
17
|
+
: sc.modifier === 'meta' ? '\u2318'
|
|
18
|
+
: '';
|
|
19
|
+
return `${mod}${sc.key.toUpperCase()}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatInteraction(sc: ShortcutConfig): string {
|
|
23
|
+
const interaction = sc.interaction ?? 'scroll';
|
|
24
|
+
switch (interaction) {
|
|
25
|
+
case 'scroll': return sc.key ? 'key+scroll' : 'scroll';
|
|
26
|
+
case 'drag': return 'key+drag';
|
|
27
|
+
case 'move': return 'key+move';
|
|
28
|
+
case 'scroll-only': return 'scroll';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function open() {
|
|
33
|
+
const rect = triggerEl?.getBoundingClientRect();
|
|
34
|
+
if (rect) {
|
|
35
|
+
pos = { top: rect.bottom + 4, right: window.innerWidth - rect.right };
|
|
36
|
+
}
|
|
37
|
+
isOpen = true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function close() {
|
|
41
|
+
isOpen = false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function toggle() {
|
|
45
|
+
if (isOpen) close();
|
|
46
|
+
else open();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Close on mousedown outside
|
|
50
|
+
$effect(() => {
|
|
51
|
+
if (!isOpen) return;
|
|
52
|
+
|
|
53
|
+
const handler = (e: MouseEvent) => {
|
|
54
|
+
const target = e.target as Node;
|
|
55
|
+
if (triggerEl?.contains(target) || dropdownEl?.contains(target)) return;
|
|
56
|
+
close();
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
document.addEventListener('mousedown', handler);
|
|
60
|
+
return () => document.removeEventListener('mousedown', handler);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const panel = $derived(DialStore.getPanel(panelId));
|
|
64
|
+
|
|
65
|
+
const rows = $derived.by(() => {
|
|
66
|
+
if (!panel) return [];
|
|
67
|
+
const shortcuts = Object.entries(panel.shortcuts);
|
|
68
|
+
if (shortcuts.length === 0) return [];
|
|
69
|
+
|
|
70
|
+
return shortcuts.map(([path, shortcut]) => {
|
|
71
|
+
const findLabel = (controls: typeof panel.controls): string => {
|
|
72
|
+
for (const c of controls) {
|
|
73
|
+
if (c.path === path) return c.label;
|
|
74
|
+
if (c.type === 'folder' && c.children) {
|
|
75
|
+
const found = findLabel(c.children);
|
|
76
|
+
if (found) return found;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return path;
|
|
80
|
+
};
|
|
81
|
+
return { path, shortcut, label: findLabel(panel.controls) };
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
{#if panel && rows.length > 0}
|
|
87
|
+
<button
|
|
88
|
+
bind:this={triggerEl}
|
|
89
|
+
class="dialkit-shortcuts-trigger"
|
|
90
|
+
onclick={toggle}
|
|
91
|
+
title="Keyboard shortcuts"
|
|
92
|
+
>
|
|
93
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
94
|
+
<rect x="2" y="6" width="20" height="12" rx="2" />
|
|
95
|
+
<path d="M6 10H6.01" />
|
|
96
|
+
<path d="M10 10H10.01" />
|
|
97
|
+
<path d="M14 10H14.01" />
|
|
98
|
+
<path d="M18 10H18.01" />
|
|
99
|
+
<path d="M8 14H16" />
|
|
100
|
+
</svg>
|
|
101
|
+
</button>
|
|
102
|
+
|
|
103
|
+
<Portal target="body">
|
|
104
|
+
{#if isOpen}
|
|
105
|
+
<div
|
|
106
|
+
bind:this={dropdownEl}
|
|
107
|
+
class="dialkit-root dialkit-shortcuts-dropdown"
|
|
108
|
+
style:position="fixed"
|
|
109
|
+
style:top="{pos.top}px"
|
|
110
|
+
style:right="{pos.right}px"
|
|
111
|
+
>
|
|
112
|
+
<div class="dialkit-shortcuts-title">Keyboard Shortcuts</div>
|
|
113
|
+
<div class="dialkit-shortcuts-list">
|
|
114
|
+
{#each rows as row (row.path)}
|
|
115
|
+
<div class="dialkit-shortcuts-row">
|
|
116
|
+
<span class="dialkit-shortcuts-row-key">
|
|
117
|
+
{formatShortcutKey(row.shortcut)}
|
|
118
|
+
</span>
|
|
119
|
+
<span class="dialkit-shortcuts-row-label">{row.label}</span>
|
|
120
|
+
<span class="dialkit-shortcuts-row-mode">{formatInteraction(row.shortcut)}</span>
|
|
121
|
+
</div>
|
|
122
|
+
{/each}
|
|
123
|
+
</div>
|
|
124
|
+
<div class="dialkit-shortcuts-hint">See pill badges on controls for keys</div>
|
|
125
|
+
</div>
|
|
126
|
+
{/if}
|
|
127
|
+
</Portal>
|
|
128
|
+
{/if}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
panelId: string;
|
|
3
|
+
};
|
|
4
|
+
declare const ShortcutsMenu: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
5
|
+
type ShortcutsMenu = ReturnType<typeof ShortcutsMenu>;
|
|
6
|
+
export default ShortcutsMenu;
|
|
7
|
+
//# sourceMappingURL=ShortcutsMenu.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShortcutsMenu.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ShortcutsMenu.svelte.ts"],"names":[],"mappings":"AAOC,KAAK,gBAAgB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAyH7C,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|