dialkit 1.0.0 → 1.1.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 +123 -2
- package/dist/index.cjs +42 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +42 -39
- package/dist/index.js.map +1 -1
- package/dist/solid/index.cjs +97 -54
- package/dist/solid/index.cjs.map +1 -1
- package/dist/solid/index.d.cts +4 -1
- package/dist/solid/index.d.ts +4 -1
- package/dist/solid/index.js +96 -53
- package/dist/solid/index.js.map +1 -1
- package/dist/store/index.cjs +450 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.cts +124 -0
- package/dist/store/index.d.ts +124 -0
- package/dist/store/index.js +425 -0
- package/dist/store/index.js.map +1 -0
- package/dist/styles.css +31 -0
- 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 +84 -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 +65 -0
- package/dist/svelte/components/DialRoot.svelte.d.ts +11 -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 +204 -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 +144 -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 +156 -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 +106 -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 +151 -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/Slider.svelte +345 -0
- package/dist/svelte/components/Slider.svelte.d.ts +13 -0
- package/dist/svelte/components/Slider.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SpringControl.svelte +124 -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 +21 -0
- package/dist/svelte/components/Toggle.svelte.d.ts +9 -0
- package/dist/svelte/components/Toggle.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TransitionControl.svelte +200 -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 +7 -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 +19 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +19 -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 +1097 -0
- package/package.json +29 -5
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Spring } from 'svelte/motion';
|
|
3
|
+
import { DialStore } from 'dialkit/store';
|
|
4
|
+
import type { DialValue, PanelConfig, Preset } from 'dialkit/store';
|
|
5
|
+
import Folder from './Folder.svelte';
|
|
6
|
+
import PresetManager from './PresetManager.svelte';
|
|
7
|
+
import ControlRenderer from './ControlRenderer.svelte';
|
|
8
|
+
|
|
9
|
+
let { panel, defaultOpen = true, inline = false } = $props<{ panel: PanelConfig; defaultOpen?: boolean; inline?: boolean }>();
|
|
10
|
+
|
|
11
|
+
let copied = $state(false);
|
|
12
|
+
let isPanelOpen = $state(defaultOpen);
|
|
13
|
+
let values = $state<Record<string, DialValue>>(DialStore.getValues(panel.id));
|
|
14
|
+
let presets = $state<Preset[]>(DialStore.getPresets(panel.id));
|
|
15
|
+
let activePresetId = $state<string | null>(DialStore.getActivePresetId(panel.id));
|
|
16
|
+
|
|
17
|
+
const addScale = new Spring(1, { stiffness: 0.25, damping: 0.7 });
|
|
18
|
+
const copyScale = new Spring(1, { stiffness: 0.25, damping: 0.7 });
|
|
19
|
+
const clipboardOpacity = new Spring(1, { stiffness: 0.25, damping: 0.7 });
|
|
20
|
+
const clipboardScale = new Spring(1, { stiffness: 0.2, damping: 0.6 });
|
|
21
|
+
const checkOpacity = new Spring(0, { stiffness: 0.25, damping: 0.7 });
|
|
22
|
+
const checkScale = new Spring(0.5, { stiffness: 0.2, damping: 0.6 });
|
|
23
|
+
|
|
24
|
+
let copyTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
25
|
+
|
|
26
|
+
$effect(() => {
|
|
27
|
+
const unsub = DialStore.subscribe(panel.id, () => {
|
|
28
|
+
values = DialStore.getValues(panel.id);
|
|
29
|
+
presets = DialStore.getPresets(panel.id);
|
|
30
|
+
activePresetId = DialStore.getActivePresetId(panel.id);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return () => {
|
|
34
|
+
unsub();
|
|
35
|
+
if (copyTimeout) clearTimeout(copyTimeout);
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
$effect(() => {
|
|
40
|
+
if (copied) {
|
|
41
|
+
clipboardOpacity.set(0);
|
|
42
|
+
clipboardScale.set(0.5);
|
|
43
|
+
checkOpacity.set(1);
|
|
44
|
+
checkScale.set(1);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
clipboardOpacity.set(1);
|
|
49
|
+
clipboardScale.set(1);
|
|
50
|
+
checkOpacity.set(0);
|
|
51
|
+
checkScale.set(0.5);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const handleAddPreset = () => {
|
|
55
|
+
const nextNum = presets.length + 2;
|
|
56
|
+
DialStore.savePreset(panel.id, `Version ${nextNum}`);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleCopy = async () => {
|
|
60
|
+
const jsonStr = JSON.stringify(values, null, 2);
|
|
61
|
+
const instruction = `Update the createDialKit configuration for "${panel.name}" with these values:\n\n\`\`\`json\n${jsonStr}\n\`\`\`\n\nApply these values as the new defaults in the createDialKit call.`;
|
|
62
|
+
|
|
63
|
+
await navigator.clipboard.writeText(instruction);
|
|
64
|
+
copied = true;
|
|
65
|
+
|
|
66
|
+
if (copyTimeout) clearTimeout(copyTimeout);
|
|
67
|
+
copyTimeout = setTimeout(() => {
|
|
68
|
+
copied = false;
|
|
69
|
+
}, 1500);
|
|
70
|
+
};
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<div class="dialkit-panel-wrapper">
|
|
74
|
+
<Folder title={panel.name} {defaultOpen} isRoot={true} {inline} onOpenChange={(open) => (isPanelOpen = open)}>
|
|
75
|
+
{#snippet toolbar()}
|
|
76
|
+
<button
|
|
77
|
+
class="dialkit-toolbar-add"
|
|
78
|
+
onclick={handleAddPreset}
|
|
79
|
+
onpointerdown={() => addScale.set(0.9)}
|
|
80
|
+
onpointerup={() => addScale.set(1)}
|
|
81
|
+
onpointercancel={() => addScale.set(1)}
|
|
82
|
+
onpointerleave={() => addScale.set(1)}
|
|
83
|
+
title="Add preset"
|
|
84
|
+
style:transform={`scale(${addScale.current})`}
|
|
85
|
+
>
|
|
86
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
87
|
+
<path d="M4 6H20" />
|
|
88
|
+
<path d="M4 12H10" />
|
|
89
|
+
<path d="M15 15L21 15" />
|
|
90
|
+
<path d="M18 12V18" />
|
|
91
|
+
<path d="M4 18H10" />
|
|
92
|
+
</svg>
|
|
93
|
+
</button>
|
|
94
|
+
|
|
95
|
+
<PresetManager panelId={panel.id} {presets} {activePresetId} />
|
|
96
|
+
|
|
97
|
+
<button
|
|
98
|
+
class="dialkit-toolbar-copy"
|
|
99
|
+
onclick={handleCopy}
|
|
100
|
+
onpointerdown={() => copyScale.set(0.95)}
|
|
101
|
+
onpointerup={() => copyScale.set(1)}
|
|
102
|
+
onpointercancel={() => copyScale.set(1)}
|
|
103
|
+
onpointerleave={() => copyScale.set(1)}
|
|
104
|
+
title="Copy parameters"
|
|
105
|
+
style:transform={`scale(${copyScale.current})`}
|
|
106
|
+
>
|
|
107
|
+
<span class="dialkit-toolbar-copy-icon-wrap">
|
|
108
|
+
<svg
|
|
109
|
+
class="dialkit-toolbar-copy-icon"
|
|
110
|
+
viewBox="0 0 24 24"
|
|
111
|
+
fill="none"
|
|
112
|
+
style:opacity={clipboardOpacity.current}
|
|
113
|
+
style:transform={`scale(${clipboardScale.current})`}
|
|
114
|
+
style:filter={`blur(${(1 - clipboardOpacity.current) * 4}px)`}
|
|
115
|
+
>
|
|
116
|
+
<path d="M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
|
117
|
+
<path d="M19.2405 16.1852L18.5436 14.3733C18.4571 14.1484 18.241 14 18 14C17.759 14 17.5429 14.1484 17.4564 14.3733L16.7595 16.1852C16.658 16.4493 16.4493 16.658 16.1852 16.7595L14.3733 17.4564C14.1484 17.5429 14 17.759 14 18C14 18.241 14.1484 18.4571 14.3733 18.5436L16.1852 19.2405C16.4493 19.342 16.658 19.5507 16.7595 19.8148L17.4564 21.6267C17.5429 21.8516 17.759 22 18 22C18.241 22 18.4571 21.8516 18.5436 21.6267L19.2405 19.8148C19.342 19.5507 19.5507 19.342 19.8148 19.2405L21.6267 18.5436C21.8516 18.4571 22 18.241 22 18C22 17.759 21.8516 17.5429 21.6267 17.4564L19.8148 16.7595C19.5507 16.658 19.342 16.4493 19.2405 16.1852Z" fill="currentColor"/>
|
|
118
|
+
<path d="M16 5H17C18.6569 5 20 6.34315 20 8V11M8 5H7C5.34315 5 4 6.34315 4 8V18C4 19.6569 5.34315 21 7 21H12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
119
|
+
</svg>
|
|
120
|
+
|
|
121
|
+
<svg
|
|
122
|
+
class="dialkit-toolbar-copy-icon"
|
|
123
|
+
viewBox="0 0 24 24"
|
|
124
|
+
fill="none"
|
|
125
|
+
stroke="currentColor"
|
|
126
|
+
stroke-width="2"
|
|
127
|
+
stroke-linecap="round"
|
|
128
|
+
stroke-linejoin="round"
|
|
129
|
+
style:opacity={checkOpacity.current}
|
|
130
|
+
style:transform={`scale(${checkScale.current})`}
|
|
131
|
+
style:filter={`blur(${(1 - checkOpacity.current) * 4}px)`}
|
|
132
|
+
>
|
|
133
|
+
<path d="M5 12.75L10 19L19 5" />
|
|
134
|
+
</svg>
|
|
135
|
+
</span>
|
|
136
|
+
Copy
|
|
137
|
+
</button>
|
|
138
|
+
{/snippet}
|
|
139
|
+
|
|
140
|
+
{#each panel.controls as control (control.path)}
|
|
141
|
+
<ControlRenderer panelId={panel.id} {control} {values} />
|
|
142
|
+
{/each}
|
|
143
|
+
</Folder>
|
|
144
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PanelConfig } from 'dialkit/store';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
panel: PanelConfig;
|
|
4
|
+
defaultOpen?: boolean;
|
|
5
|
+
inline?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const Panel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type Panel = ReturnType<typeof Panel>;
|
|
9
|
+
export default Panel;
|
|
10
|
+
//# sourceMappingURL=Panel.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Panel.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/Panel.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAa,WAAW,EAAU,MAAM,eAAe,CAAC;AAKnE,KAAK,gBAAgB,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAgHzF,QAAA,MAAM,KAAK,sDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Spring } from 'svelte/motion';
|
|
3
|
+
import Portal from '../Portal.svelte';
|
|
4
|
+
import { DialStore } from 'dialkit/store';
|
|
5
|
+
import type { Preset } from 'dialkit/store';
|
|
6
|
+
import { dropdownTransition } from './transitions';
|
|
7
|
+
|
|
8
|
+
let { panelId, presets, activePresetId } = $props<{
|
|
9
|
+
panelId: string;
|
|
10
|
+
presets: Preset[];
|
|
11
|
+
activePresetId: string | null;
|
|
12
|
+
}>();
|
|
13
|
+
|
|
14
|
+
let isOpen = $state(false);
|
|
15
|
+
let pos = $state({ top: 0, left: 0, width: 0 });
|
|
16
|
+
let portalTarget = $state<HTMLElement | null>(null);
|
|
17
|
+
let triggerRef: HTMLButtonElement | undefined;
|
|
18
|
+
let dropdownRef: HTMLDivElement | undefined;
|
|
19
|
+
|
|
20
|
+
const chevronRotation = new Spring(0, { stiffness: 0.2, damping: 0.6 });
|
|
21
|
+
const chevronOpacity = new Spring(0.25, { stiffness: 0.2, damping: 0.6 });
|
|
22
|
+
|
|
23
|
+
const hasPresets = $derived(presets.length > 0);
|
|
24
|
+
const activePreset = $derived(presets.find((p: Preset) => p.id === activePresetId));
|
|
25
|
+
|
|
26
|
+
const updatePos = () => {
|
|
27
|
+
const rect = triggerRef?.getBoundingClientRect();
|
|
28
|
+
if (!rect) return;
|
|
29
|
+
pos = { top: rect.bottom + 4, left: rect.left, width: rect.width };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const openDropdown = () => {
|
|
33
|
+
if (!hasPresets) return;
|
|
34
|
+
updatePos();
|
|
35
|
+
isOpen = true;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const closeDropdown = () => {
|
|
39
|
+
isOpen = false;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
$effect(() => {
|
|
43
|
+
if (typeof document === 'undefined' || !triggerRef) return;
|
|
44
|
+
portalTarget = (triggerRef.closest('.dialkit-root') as HTMLElement | null) ?? document.body;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
$effect(() => {
|
|
48
|
+
chevronRotation.set(isOpen ? 180 : 0);
|
|
49
|
+
chevronOpacity.set(hasPresets ? 0.6 : 0.25);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
$effect(() => {
|
|
53
|
+
if (!isOpen || typeof window === 'undefined') return;
|
|
54
|
+
|
|
55
|
+
const handleViewportChange = () => updatePos();
|
|
56
|
+
const handler = (e: MouseEvent) => {
|
|
57
|
+
const target = e.target as Node;
|
|
58
|
+
if (triggerRef?.contains(target) || dropdownRef?.contains(target)) return;
|
|
59
|
+
closeDropdown();
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
updatePos();
|
|
63
|
+
document.addEventListener('mousedown', handler);
|
|
64
|
+
window.addEventListener('resize', handleViewportChange);
|
|
65
|
+
window.addEventListener('scroll', handleViewportChange, true);
|
|
66
|
+
|
|
67
|
+
return () => {
|
|
68
|
+
document.removeEventListener('mousedown', handler);
|
|
69
|
+
window.removeEventListener('resize', handleViewportChange);
|
|
70
|
+
window.removeEventListener('scroll', handleViewportChange, true);
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const handleSelect = (presetId: string | null) => {
|
|
75
|
+
if (presetId) DialStore.loadPreset(panelId, presetId);
|
|
76
|
+
else DialStore.clearActivePreset(panelId);
|
|
77
|
+
closeDropdown();
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const handleDelete = (e: MouseEvent, presetId: string) => {
|
|
81
|
+
e.stopPropagation();
|
|
82
|
+
DialStore.deletePreset(panelId, presetId);
|
|
83
|
+
};
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<div class="dialkit-preset-manager">
|
|
87
|
+
<button
|
|
88
|
+
bind:this={triggerRef}
|
|
89
|
+
class="dialkit-preset-trigger"
|
|
90
|
+
onclick={() => (isOpen ? closeDropdown() : openDropdown())}
|
|
91
|
+
data-open={String(isOpen)}
|
|
92
|
+
data-has-preset={String(!!activePreset)}
|
|
93
|
+
data-disabled={String(!hasPresets)}
|
|
94
|
+
>
|
|
95
|
+
<span class="dialkit-preset-label">
|
|
96
|
+
{activePreset ? activePreset.name : 'Version 1'}
|
|
97
|
+
</span>
|
|
98
|
+
<svg
|
|
99
|
+
class="dialkit-select-chevron"
|
|
100
|
+
viewBox="0 0 24 24"
|
|
101
|
+
fill="none"
|
|
102
|
+
stroke="currentColor"
|
|
103
|
+
stroke-width="2.5"
|
|
104
|
+
stroke-linecap="round"
|
|
105
|
+
stroke-linejoin="round"
|
|
106
|
+
style:transform={`rotate(${chevronRotation.current}deg)`}
|
|
107
|
+
style:opacity={chevronOpacity.current}
|
|
108
|
+
>
|
|
109
|
+
<path d="M6 9.5L12 15.5L18 9.5" />
|
|
110
|
+
</svg>
|
|
111
|
+
</button>
|
|
112
|
+
|
|
113
|
+
{#if portalTarget}
|
|
114
|
+
<Portal target={portalTarget}>
|
|
115
|
+
{#if isOpen}
|
|
116
|
+
<div
|
|
117
|
+
bind:this={dropdownRef}
|
|
118
|
+
class="dialkit-root dialkit-preset-dropdown"
|
|
119
|
+
style={`position:fixed;top:${pos.top}px;left:${pos.left}px;min-width:${pos.width}px;`}
|
|
120
|
+
transition:dropdownTransition={{ above: false }}
|
|
121
|
+
>
|
|
122
|
+
<div
|
|
123
|
+
class="dialkit-preset-item"
|
|
124
|
+
data-active={String(!activePresetId)}
|
|
125
|
+
onclick={() => handleSelect(null)}
|
|
126
|
+
>
|
|
127
|
+
<span class="dialkit-preset-name">Version 1</span>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{#each presets as preset (preset.id)}
|
|
131
|
+
<div
|
|
132
|
+
class="dialkit-preset-item"
|
|
133
|
+
data-active={String(preset.id === activePresetId)}
|
|
134
|
+
onclick={() => handleSelect(preset.id)}
|
|
135
|
+
>
|
|
136
|
+
<span class="dialkit-preset-name">{preset.name}</span>
|
|
137
|
+
<button
|
|
138
|
+
class="dialkit-preset-delete"
|
|
139
|
+
onclick={(e) => handleDelete(e, preset.id)}
|
|
140
|
+
title="Delete preset"
|
|
141
|
+
>
|
|
142
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
143
|
+
<path d="M5 6.5L5.80734 18.2064C5.91582 19.7794 7.22348 21 8.80023 21H15.1998C16.7765 21 18.0842 19.7794 18.1927 18.2064L19 6.5" />
|
|
144
|
+
<path d="M10 11V16" />
|
|
145
|
+
<path d="M14 11V16" />
|
|
146
|
+
<path d="M3.5 6H20.5" />
|
|
147
|
+
<path d="M8.07092 5.74621C8.42348 3.89745 10.0485 2.5 12 2.5C13.9515 2.5 15.5765 3.89745 15.9291 5.74621" />
|
|
148
|
+
</svg>
|
|
149
|
+
</button>
|
|
150
|
+
</div>
|
|
151
|
+
{/each}
|
|
152
|
+
</div>
|
|
153
|
+
{/if}
|
|
154
|
+
</Portal>
|
|
155
|
+
{/if}
|
|
156
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Preset } from 'dialkit/store';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
panelId: string;
|
|
4
|
+
presets: Preset[];
|
|
5
|
+
activePresetId: string | null;
|
|
6
|
+
};
|
|
7
|
+
declare const PresetManager: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type PresetManager = ReturnType<typeof PresetManager>;
|
|
9
|
+
export default PresetManager;
|
|
10
|
+
//# sourceMappingURL=PresetManager.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PresetManager.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/PresetManager.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG3C,KAAK,gBAAgB,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AA0HJ,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Spring } from 'svelte/motion';
|
|
3
|
+
|
|
4
|
+
export interface SegmentedControlOption<T extends string = string> {
|
|
5
|
+
value: T;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let { options, value, onChange } = $props<{
|
|
10
|
+
options: SegmentedControlOption[];
|
|
11
|
+
value: string;
|
|
12
|
+
onChange: (value: string) => void;
|
|
13
|
+
}>();
|
|
14
|
+
|
|
15
|
+
let containerRef: HTMLDivElement | undefined;
|
|
16
|
+
const buttonRefs = new Map<string, HTMLButtonElement>();
|
|
17
|
+
let pillReady = $state(false);
|
|
18
|
+
let hasAnimated = false;
|
|
19
|
+
|
|
20
|
+
const pillLeft = new Spring(0, { stiffness: 0.2, damping: 0.6 });
|
|
21
|
+
const pillWidth = new Spring(0, { stiffness: 0.2, damping: 0.6 });
|
|
22
|
+
|
|
23
|
+
const buttonRef = (node: HTMLButtonElement, key: string) => {
|
|
24
|
+
buttonRefs.set(key, node);
|
|
25
|
+
return {
|
|
26
|
+
destroy() {
|
|
27
|
+
buttonRefs.delete(key);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const measurePill = () => {
|
|
33
|
+
const button = buttonRefs.get(value);
|
|
34
|
+
if (!button || !containerRef) return null;
|
|
35
|
+
const containerRect = containerRef.getBoundingClientRect();
|
|
36
|
+
const buttonRect = button.getBoundingClientRect();
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
left: buttonRect.left - containerRect.left,
|
|
40
|
+
width: buttonRect.width,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const updatePill = (shouldAnimate: boolean) => {
|
|
45
|
+
const next = measurePill();
|
|
46
|
+
if (!next) return;
|
|
47
|
+
|
|
48
|
+
if (!pillReady) {
|
|
49
|
+
pillLeft.set(next.left, { instant: true });
|
|
50
|
+
pillWidth.set(next.width, { instant: true });
|
|
51
|
+
pillReady = true;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!shouldAnimate || !hasAnimated) {
|
|
56
|
+
pillLeft.set(next.left, { instant: true });
|
|
57
|
+
pillWidth.set(next.width, { instant: true });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pillLeft.set(next.left);
|
|
62
|
+
pillWidth.set(next.width);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
$effect(() => {
|
|
66
|
+
value;
|
|
67
|
+
if (!pillReady) return;
|
|
68
|
+
updatePill(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
$effect(() => {
|
|
72
|
+
if (!containerRef || typeof ResizeObserver === 'undefined') return;
|
|
73
|
+
|
|
74
|
+
requestAnimationFrame(() => {
|
|
75
|
+
updatePill(false);
|
|
76
|
+
hasAnimated = true;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const ro = new ResizeObserver(() => updatePill(false));
|
|
80
|
+
ro.observe(containerRef);
|
|
81
|
+
|
|
82
|
+
return () => {
|
|
83
|
+
ro.disconnect();
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
</script>
|
|
87
|
+
|
|
88
|
+
<div bind:this={containerRef} class="dialkit-segmented">
|
|
89
|
+
<div
|
|
90
|
+
class="dialkit-segmented-pill"
|
|
91
|
+
style:left={`${pillLeft.current}px`}
|
|
92
|
+
style:width={`${pillWidth.current}px`}
|
|
93
|
+
style:visibility={pillReady ? 'visible' : 'hidden'}
|
|
94
|
+
/>
|
|
95
|
+
|
|
96
|
+
{#each options as option (option.value)}
|
|
97
|
+
<button
|
|
98
|
+
use:buttonRef={option.value}
|
|
99
|
+
onclick={() => onChange(option.value)}
|
|
100
|
+
class="dialkit-segmented-button"
|
|
101
|
+
data-active={String(value === option.value)}
|
|
102
|
+
>
|
|
103
|
+
{option.label}
|
|
104
|
+
</button>
|
|
105
|
+
{/each}
|
|
106
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface SegmentedControlOption<T extends string = string> {
|
|
2
|
+
value: T;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
type $$ComponentProps = {
|
|
6
|
+
options: SegmentedControlOption[];
|
|
7
|
+
value: string;
|
|
8
|
+
onChange: (value: string) => void;
|
|
9
|
+
};
|
|
10
|
+
declare const SegmentedControl: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type SegmentedControl = ReturnType<typeof SegmentedControl>;
|
|
12
|
+
export default SegmentedControl;
|
|
13
|
+
//# sourceMappingURL=SegmentedControl.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SegmentedControl.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/SegmentedControl.svelte.ts"],"names":[],"mappings":"AAME,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC/D,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACf;AACF,KAAK,gBAAgB,GAAG;IACrB,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AA4FJ,QAAA,MAAM,gBAAgB,sDAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Spring } from 'svelte/motion';
|
|
3
|
+
import Portal from '../Portal.svelte';
|
|
4
|
+
import { dropdownTransition } from './transitions';
|
|
5
|
+
|
|
6
|
+
type SelectOption = string | { value: string; label: string };
|
|
7
|
+
|
|
8
|
+
let { label, value, options, onChange } = $props<{
|
|
9
|
+
label: string;
|
|
10
|
+
value: string;
|
|
11
|
+
options: SelectOption[];
|
|
12
|
+
onChange: (value: string) => void;
|
|
13
|
+
}>();
|
|
14
|
+
|
|
15
|
+
let isOpen = $state(false);
|
|
16
|
+
let pos = $state<{ top: number; left: number; width: number; above: boolean } | null>(null);
|
|
17
|
+
let portalTarget = $state<HTMLElement | null>(null);
|
|
18
|
+
let triggerRef: HTMLButtonElement | undefined;
|
|
19
|
+
let dropdownRef: HTMLDivElement | undefined;
|
|
20
|
+
|
|
21
|
+
const chevronRotation = new Spring(0, { stiffness: 0.2, damping: 0.6 });
|
|
22
|
+
|
|
23
|
+
const toTitleCase = (s: string) => s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
24
|
+
|
|
25
|
+
const normalized = $derived(
|
|
26
|
+
options.map((opt: SelectOption) =>
|
|
27
|
+
typeof opt === 'string' ? { value: opt, label: toTitleCase(opt) } : opt
|
|
28
|
+
)
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const selectedOption = $derived(normalized.find((o: { value: string; label: string }) => o.value === value));
|
|
32
|
+
|
|
33
|
+
const updatePos = () => {
|
|
34
|
+
if (!triggerRef || typeof window === 'undefined') return;
|
|
35
|
+
const rect = triggerRef.getBoundingClientRect();
|
|
36
|
+
const dropdownHeight = 8 + normalized.length * 36;
|
|
37
|
+
const spaceBelow = window.innerHeight - rect.bottom - 4;
|
|
38
|
+
const above = spaceBelow < dropdownHeight && rect.top > spaceBelow;
|
|
39
|
+
|
|
40
|
+
pos = {
|
|
41
|
+
top: above ? rect.top - 4 : rect.bottom + 4,
|
|
42
|
+
left: rect.left,
|
|
43
|
+
width: rect.width,
|
|
44
|
+
above,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const openDropdown = () => {
|
|
49
|
+
updatePos();
|
|
50
|
+
isOpen = true;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const closeDropdown = () => {
|
|
54
|
+
isOpen = false;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const dropdownStyle = $derived.by(() => {
|
|
58
|
+
if (!pos || typeof window === 'undefined') return '';
|
|
59
|
+
|
|
60
|
+
if (pos.above) {
|
|
61
|
+
return `position:fixed;left:${pos.left}px;width:${pos.width}px;bottom:${window.innerHeight - pos.top}px;transform-origin:bottom;`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return `position:fixed;left:${pos.left}px;width:${pos.width}px;top:${pos.top}px;transform-origin:top;`;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
$effect(() => {
|
|
68
|
+
if (typeof document === 'undefined' || !triggerRef) return;
|
|
69
|
+
|
|
70
|
+
portalTarget = (triggerRef.closest('.dialkit-root') as HTMLElement | null) ?? document.body;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
$effect(() => {
|
|
74
|
+
chevronRotation.set(isOpen ? 180 : 0);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
$effect(() => {
|
|
78
|
+
if (!isOpen || typeof window === 'undefined') return;
|
|
79
|
+
|
|
80
|
+
const handleViewportChange = () => updatePos();
|
|
81
|
+
|
|
82
|
+
const handleClick = (e: MouseEvent) => {
|
|
83
|
+
const target = e.target as Node;
|
|
84
|
+
if (triggerRef?.contains(target) || dropdownRef?.contains(target)) return;
|
|
85
|
+
closeDropdown();
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
updatePos();
|
|
89
|
+
document.addEventListener('mousedown', handleClick);
|
|
90
|
+
window.addEventListener('resize', handleViewportChange);
|
|
91
|
+
window.addEventListener('scroll', handleViewportChange, true);
|
|
92
|
+
|
|
93
|
+
return () => {
|
|
94
|
+
document.removeEventListener('mousedown', handleClick);
|
|
95
|
+
window.removeEventListener('resize', handleViewportChange);
|
|
96
|
+
window.removeEventListener('scroll', handleViewportChange, true);
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<div class="dialkit-select-row">
|
|
102
|
+
<button
|
|
103
|
+
bind:this={triggerRef}
|
|
104
|
+
class="dialkit-select-trigger"
|
|
105
|
+
onclick={() => (isOpen ? closeDropdown() : openDropdown())}
|
|
106
|
+
data-open={String(isOpen)}
|
|
107
|
+
>
|
|
108
|
+
<span class="dialkit-select-label">{label}</span>
|
|
109
|
+
<div class="dialkit-select-right">
|
|
110
|
+
<span class="dialkit-select-value">{selectedOption?.label ?? value}</span>
|
|
111
|
+
<svg
|
|
112
|
+
class="dialkit-select-chevron"
|
|
113
|
+
viewBox="0 0 24 24"
|
|
114
|
+
fill="none"
|
|
115
|
+
stroke="currentColor"
|
|
116
|
+
stroke-width="2.5"
|
|
117
|
+
stroke-linecap="round"
|
|
118
|
+
stroke-linejoin="round"
|
|
119
|
+
style:transform={`rotate(${chevronRotation.current}deg)`}
|
|
120
|
+
>
|
|
121
|
+
<path d="M6 9.5L12 15.5L18 9.5" />
|
|
122
|
+
</svg>
|
|
123
|
+
</div>
|
|
124
|
+
</button>
|
|
125
|
+
|
|
126
|
+
{#if portalTarget}
|
|
127
|
+
<Portal target={portalTarget}>
|
|
128
|
+
{#if isOpen && pos}
|
|
129
|
+
<div
|
|
130
|
+
bind:this={dropdownRef}
|
|
131
|
+
class="dialkit-select-dropdown"
|
|
132
|
+
style={dropdownStyle}
|
|
133
|
+
transition:dropdownTransition={{ above: pos.above }}
|
|
134
|
+
>
|
|
135
|
+
{#each normalized as option (option.value)}
|
|
136
|
+
<button
|
|
137
|
+
class="dialkit-select-option"
|
|
138
|
+
data-selected={String(option.value === value)}
|
|
139
|
+
onclick={() => {
|
|
140
|
+
onChange(option.value);
|
|
141
|
+
closeDropdown();
|
|
142
|
+
}}
|
|
143
|
+
>
|
|
144
|
+
{option.label}
|
|
145
|
+
</button>
|
|
146
|
+
{/each}
|
|
147
|
+
</div>
|
|
148
|
+
{/if}
|
|
149
|
+
</Portal>
|
|
150
|
+
{/if}
|
|
151
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type SelectOption = string | {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
};
|
|
5
|
+
type $$ComponentProps = {
|
|
6
|
+
label: string;
|
|
7
|
+
value: string;
|
|
8
|
+
options: SelectOption[];
|
|
9
|
+
onChange: (value: string) => void;
|
|
10
|
+
};
|
|
11
|
+
declare const SelectControl: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type SelectControl = ReturnType<typeof SelectControl>;
|
|
13
|
+
export default SelectControl;
|
|
14
|
+
//# sourceMappingURL=SelectControl.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectControl.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/SelectControl.svelte.ts"],"names":[],"mappings":"AAQE,KAAK,YAAY,GAAG,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAC/D,KAAK,gBAAgB,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AA8HJ,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|