dialkit 1.3.0 → 1.4.1
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 +433 -3
- package/dist/icons.d.ts +5 -1
- package/dist/icons.js +18 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.cjs +3222 -479
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +274 -6
- package/dist/index.d.ts +274 -6
- package/dist/index.js +3154 -416
- package/dist/index.js.map +1 -1
- package/dist/solid/index.d.ts +225 -3
- package/dist/solid/index.js +5761 -2500
- package/dist/solid/index.js.map +1 -1
- package/dist/store/index.cjs +57 -16
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +14 -2
- package/dist/store/index.d.ts +14 -2
- package/dist/store/index.js +52 -16
- package/dist/store/index.js.map +1 -1
- package/dist/styles.css +788 -0
- package/dist/svelte/components/ControlRenderer.svelte +5 -2
- package/dist/svelte/components/ControlRenderer.svelte.d.ts +2 -0
- package/dist/svelte/components/ControlRenderer.svelte.d.ts.map +1 -1
- package/dist/svelte/components/DialRoot.svelte +43 -6
- package/dist/svelte/components/DialRoot.svelte.d.ts.map +1 -1
- package/dist/svelte/components/Panel.svelte +7 -1
- 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/Timeline/ClipPopover.svelte +206 -0
- package/dist/svelte/components/Timeline/ClipPopover.svelte.d.ts +26 -0
- package/dist/svelte/components/Timeline/ClipPopover.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Timeline/DialTimeline.svelte +125 -0
- package/dist/svelte/components/Timeline/DialTimeline.svelte.d.ts +13 -0
- package/dist/svelte/components/Timeline/DialTimeline.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Timeline/TimelineClip.svelte +233 -0
- package/dist/svelte/components/Timeline/TimelineClip.svelte.d.ts +24 -0
- package/dist/svelte/components/Timeline/TimelineClip.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Timeline/TimelineSection.svelte +803 -0
- package/dist/svelte/components/Timeline/TimelineSection.svelte.d.ts +12 -0
- package/dist/svelte/components/Timeline/TimelineSection.svelte.d.ts.map +1 -0
- package/dist/svelte/components/Timeline/TimelineToggleButton.svelte +25 -0
- package/dist/svelte/components/Timeline/TimelineToggleButton.svelte.d.ts +4 -0
- package/dist/svelte/components/Timeline/TimelineToggleButton.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TransitionControl.svelte +26 -11
- package/dist/svelte/components/TransitionControl.svelte.d.ts +9 -0
- package/dist/svelte/components/TransitionControl.svelte.d.ts.map +1 -1
- package/dist/svelte/createDialTimeline.svelte.d.ts +4 -0
- package/dist/svelte/createDialTimeline.svelte.d.ts.map +1 -0
- package/dist/svelte/createDialTimeline.svelte.js +73 -0
- package/dist/svelte/index.d.ts +4 -0
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +3 -0
- 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 +788 -0
- package/dist/timeline/index.cjs +1288 -0
- package/dist/timeline/index.cjs.map +1 -0
- package/dist/timeline/index.d.cts +443 -0
- package/dist/timeline/index.d.ts +443 -0
- package/dist/timeline/index.js +1233 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/vue/index.d.ts +273 -7
- package/dist/vue/index.js +4116 -1517
- package/dist/vue/index.js.map +1 -1
- package/package.json +23 -13
- package/dist/solid/index.cjs +0 -3536
- package/dist/solid/index.cjs.map +0 -1
- package/dist/solid/index.d.cts +0 -295
- package/dist/vue/index.cjs +0 -3497
- package/dist/vue/index.cjs.map +0 -1
- package/dist/vue/index.d.cts +0 -722
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
import ControlRenderer from './ControlRenderer.svelte';
|
|
14
14
|
import { SHORTCUT_CTX } from './ShortcutListener.svelte';
|
|
15
15
|
import type { ShortcutContextValue } from './ShortcutListener.svelte';
|
|
16
|
+
import type { TransitionDurationControl } from './TransitionControl.svelte';
|
|
16
17
|
|
|
17
|
-
let { panelId, control, values } = $props<{
|
|
18
|
+
let { panelId, control, values, transitionDuration } = $props<{
|
|
18
19
|
panelId: string;
|
|
19
20
|
control: ControlMeta;
|
|
20
21
|
values: Record<string, DialValue>;
|
|
22
|
+
transitionDuration?: TransitionDurationControl;
|
|
21
23
|
}>();
|
|
22
24
|
|
|
23
25
|
const shortcutCtx = getContext<ShortcutContextValue | undefined>(SHORTCUT_CTX);
|
|
@@ -62,11 +64,12 @@
|
|
|
62
64
|
label={control.label}
|
|
63
65
|
value={controlValue as TransitionConfig}
|
|
64
66
|
onChange={(v) => DialStore.updateValue(panelId, control.path, v)}
|
|
67
|
+
durationControl={transitionDuration}
|
|
65
68
|
/>
|
|
66
69
|
{:else if control.type === 'folder'}
|
|
67
70
|
<Folder title={control.label} defaultOpen={control.defaultOpen ?? true}>
|
|
68
71
|
{#each control.children ?? [] as child (child.path)}
|
|
69
|
-
<ControlRenderer {panelId} control={child} {values} />
|
|
72
|
+
<ControlRenderer {panelId} control={child} {values} {transitionDuration} />
|
|
70
73
|
{/each}
|
|
71
74
|
</Folder>
|
|
72
75
|
{:else if control.type === 'text'}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { ControlMeta, DialValue } from 'dialkit/store';
|
|
2
2
|
import ControlRenderer from './ControlRenderer.svelte';
|
|
3
|
+
import type { TransitionDurationControl } from './TransitionControl.svelte';
|
|
3
4
|
type $$ComponentProps = {
|
|
4
5
|
panelId: string;
|
|
5
6
|
control: ControlMeta;
|
|
6
7
|
values: Record<string, DialValue>;
|
|
8
|
+
transitionDuration?: TransitionDurationControl;
|
|
7
9
|
};
|
|
8
10
|
declare const ControlRenderer: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
11
|
type ControlRenderer = ReturnType<typeof ControlRenderer>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ControlRenderer.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ControlRenderer.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAkC,MAAM,eAAe,CAAC;AAS5F,OAAO,eAAe,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"ControlRenderer.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ControlRenderer.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAkC,MAAM,eAAe,CAAC;AAS5F,OAAO,eAAe,MAAM,0BAA0B,CAAC;AAGvD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAE3E,KAAK,gBAAgB,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,kBAAkB,CAAC,EAAE,yBAAyB,CAAC;CAChD,CAAC;AAwDJ,QAAA,MAAM,eAAe,sDAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { DialStore } from 'dialkit/store';
|
|
3
3
|
import type { PanelConfig } from 'dialkit/store';
|
|
4
|
+
import { TimelineStore } from 'dialkit/timeline';
|
|
5
|
+
import type { TimelineMeta } from 'dialkit/timeline';
|
|
4
6
|
import { themeCSS } from '../theme-css';
|
|
5
7
|
import Portal from '../Portal.svelte';
|
|
6
8
|
import Folder from './Folder.svelte';
|
|
7
9
|
import Panel from './Panel.svelte';
|
|
10
|
+
import TimelineToggleButton from './Timeline/TimelineToggleButton.svelte';
|
|
8
11
|
import ShortcutListener from './ShortcutListener.svelte';
|
|
9
12
|
import {
|
|
10
13
|
blockPanelDragClick,
|
|
@@ -41,6 +44,7 @@
|
|
|
41
44
|
const inline = $derived(mode === 'inline');
|
|
42
45
|
|
|
43
46
|
let panels = $state<PanelConfig[]>([]);
|
|
47
|
+
let timelines = $state<TimelineMeta[]>([]);
|
|
44
48
|
let mounted = $state(false);
|
|
45
49
|
let panelRef = $state<HTMLDivElement>();
|
|
46
50
|
let dragOffset = $state<PanelDragOffset | null>(null);
|
|
@@ -75,13 +79,20 @@
|
|
|
75
79
|
if (typeof window === 'undefined') return;
|
|
76
80
|
|
|
77
81
|
mounted = true;
|
|
78
|
-
panels = DialStore.getPanels();
|
|
82
|
+
panels = DialStore.getPanels('panel');
|
|
83
|
+
timelines = TimelineStore.getTimelines();
|
|
79
84
|
|
|
80
|
-
const
|
|
81
|
-
panels = DialStore.getPanels();
|
|
85
|
+
const unsubscribePanels = DialStore.subscribeGlobal(() => {
|
|
86
|
+
panels = DialStore.getPanels('panel');
|
|
87
|
+
});
|
|
88
|
+
const unsubscribeTimelines = TimelineStore.subscribeGlobal(() => {
|
|
89
|
+
timelines = TimelineStore.getTimelines();
|
|
82
90
|
});
|
|
83
91
|
|
|
84
|
-
return
|
|
92
|
+
return () => {
|
|
93
|
+
unsubscribePanels();
|
|
94
|
+
unsubscribeTimelines();
|
|
95
|
+
};
|
|
85
96
|
});
|
|
86
97
|
|
|
87
98
|
$effect(() => {
|
|
@@ -183,7 +194,13 @@
|
|
|
183
194
|
|
|
184
195
|
</script>
|
|
185
196
|
|
|
186
|
-
{#
|
|
197
|
+
{#snippet timelineToolbar()}
|
|
198
|
+
{#if timelines.length > 0}
|
|
199
|
+
<TimelineToggleButton />
|
|
200
|
+
{/if}
|
|
201
|
+
{/snippet}
|
|
202
|
+
|
|
203
|
+
{#if productionEnabled && mounted && (panels.length > 0 || timelines.length > 0)}
|
|
187
204
|
{#snippet content()}
|
|
188
205
|
<ShortcutListener>
|
|
189
206
|
<div class="dialkit-root" data-mode={mode} data-theme={theme}>
|
|
@@ -200,7 +217,23 @@
|
|
|
200
217
|
onpointerup={!inline ? handlePointerUp : undefined}
|
|
201
218
|
onpointercancel={!inline ? handlePointerUp : undefined}
|
|
202
219
|
>
|
|
203
|
-
{#if panels.length
|
|
220
|
+
{#if panels.length === 0}
|
|
221
|
+
<div class="dialkit-panel-wrapper">
|
|
222
|
+
<Folder
|
|
223
|
+
title="DialKit"
|
|
224
|
+
defaultOpen={inline || defaultOpen}
|
|
225
|
+
isRoot={true}
|
|
226
|
+
{inline}
|
|
227
|
+
onOpenChange={handleRootOpenChange}
|
|
228
|
+
panelHeightOffset={2}
|
|
229
|
+
>
|
|
230
|
+
{#snippet toolbar()}
|
|
231
|
+
{@render timelineToolbar()}
|
|
232
|
+
{/snippet}
|
|
233
|
+
<div class="dialkit-timeline-toolkit-only">Timeline</div>
|
|
234
|
+
</Folder>
|
|
235
|
+
</div>
|
|
236
|
+
{:else if panels.length > 1}
|
|
204
237
|
<div class="dialkit-panel-wrapper">
|
|
205
238
|
<Folder
|
|
206
239
|
title="DialKit"
|
|
@@ -210,6 +243,9 @@
|
|
|
210
243
|
onOpenChange={handleRootOpenChange}
|
|
211
244
|
panelHeightOffset={2}
|
|
212
245
|
>
|
|
246
|
+
{#snippet toolbar()}
|
|
247
|
+
{@render timelineToolbar()}
|
|
248
|
+
{/snippet}
|
|
213
249
|
{#each panels as panel (panel.id)}
|
|
214
250
|
<Panel
|
|
215
251
|
{panel}
|
|
@@ -225,6 +261,7 @@
|
|
|
225
261
|
{panel}
|
|
226
262
|
defaultOpen={inline || defaultOpen}
|
|
227
263
|
{inline}
|
|
264
|
+
toolbarExtra={timelineToolbar}
|
|
228
265
|
onOpenChange={(open) => handlePanelOpenChange(panel.id, open)}
|
|
229
266
|
/>
|
|
230
267
|
{/each}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialRoot.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/DialRoot.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DialRoot.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/DialRoot.svelte.ts"],"names":[],"mappings":"AAyBE,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAC;AACrF,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAC5C,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AACrD,KAAK,gBAAgB,GAAG;IACrB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,CAAC;AAwOJ,QAAA,MAAM,QAAQ,sDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Spring } from 'svelte/motion';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
3
4
|
import { DialStore } from 'dialkit/store';
|
|
4
5
|
import type { DialValue, PanelConfig, Preset } from 'dialkit/store';
|
|
5
6
|
import Folder from './Folder.svelte';
|
|
@@ -8,12 +9,13 @@
|
|
|
8
9
|
import ShortcutsMenu from './ShortcutsMenu.svelte';
|
|
9
10
|
import { ICON_CLIPBOARD, ICON_CHECK, ICON_ADD_PRESET } from '../../icons';
|
|
10
11
|
|
|
11
|
-
let { panel, defaultOpen = true, inline = false, onOpenChange, variant = 'root' } = $props<{
|
|
12
|
+
let { panel, defaultOpen = true, inline = false, onOpenChange, variant = 'root', toolbarExtra } = $props<{
|
|
12
13
|
panel: PanelConfig;
|
|
13
14
|
defaultOpen?: boolean;
|
|
14
15
|
inline?: boolean;
|
|
15
16
|
onOpenChange?: (open: boolean) => void;
|
|
16
17
|
variant?: 'root' | 'section';
|
|
18
|
+
toolbarExtra?: Snippet;
|
|
17
19
|
}>();
|
|
18
20
|
|
|
19
21
|
const hasShortcuts = $derived(Object.keys(panel.shortcuts).length > 0);
|
|
@@ -148,6 +150,10 @@
|
|
|
148
150
|
</span>
|
|
149
151
|
Copy
|
|
150
152
|
</button>
|
|
153
|
+
|
|
154
|
+
{#if toolbarExtra}
|
|
155
|
+
{@render toolbarExtra()}
|
|
156
|
+
{/if}
|
|
151
157
|
{/snippet}
|
|
152
158
|
|
|
153
159
|
{#snippet panelControls()}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import type { PanelConfig } from 'dialkit/store';
|
|
2
3
|
type $$ComponentProps = {
|
|
3
4
|
panel: PanelConfig;
|
|
@@ -5,6 +6,7 @@ type $$ComponentProps = {
|
|
|
5
6
|
inline?: boolean;
|
|
6
7
|
onOpenChange?: (open: boolean) => void;
|
|
7
8
|
variant?: 'root' | 'section';
|
|
9
|
+
toolbarExtra?: Snippet;
|
|
8
10
|
};
|
|
9
11
|
declare const Panel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
12
|
type Panel = ReturnType<typeof Panel>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Panel.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/Panel.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Panel.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/Panel.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAa,WAAW,EAAU,MAAM,eAAe,CAAC;AAOnE,KAAK,gBAAgB,GAAG;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AA+IJ,QAAA,MAAM,KAAK,sDAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { DialStore } from 'dialkit/store';
|
|
3
|
+
import type { ControlMeta, DialValue } from 'dialkit/store';
|
|
4
|
+
import {
|
|
5
|
+
TIMELINE_MIN_CLIP_DURATION,
|
|
6
|
+
clamp,
|
|
7
|
+
formatStepLabel,
|
|
8
|
+
timelinePopoverDisplayValues,
|
|
9
|
+
} from 'dialkit/timeline';
|
|
10
|
+
import type { TimelineClipMeta } from 'dialkit/timeline';
|
|
11
|
+
import { findControl } from '../../../shortcut-utils';
|
|
12
|
+
import Portal from '../../Portal.svelte';
|
|
13
|
+
import ControlRenderer from '../ControlRenderer.svelte';
|
|
14
|
+
import type { DialTheme } from '../DialRoot.svelte';
|
|
15
|
+
|
|
16
|
+
const POPOVER_WIDTH = 280;
|
|
17
|
+
|
|
18
|
+
export type PopoverState = {
|
|
19
|
+
clip: TimelineClipMeta;
|
|
20
|
+
stepKey?: string;
|
|
21
|
+
anchor: { left: number; top: number; right: number; bottom: number; width: number; height: number };
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
let { panelId, popover, values, theme, onClose } = $props<{
|
|
25
|
+
panelId: string;
|
|
26
|
+
popover: PopoverState;
|
|
27
|
+
values: Record<string, DialValue>;
|
|
28
|
+
theme: DialTheme;
|
|
29
|
+
onClose: () => void;
|
|
30
|
+
}>();
|
|
31
|
+
|
|
32
|
+
let element = $state<HTMLDivElement>();
|
|
33
|
+
let naturalHeight = $state(0);
|
|
34
|
+
let viewport = $state(readViewport());
|
|
35
|
+
|
|
36
|
+
const presentation = $derived.by(() => {
|
|
37
|
+
const { clip, stepKey } = popover;
|
|
38
|
+
let controls: ControlMeta[];
|
|
39
|
+
let title: string;
|
|
40
|
+
if (stepKey) {
|
|
41
|
+
controls = getClipControls(panelId, `${clip.key}.${stepKey}`);
|
|
42
|
+
if (stepKey === clip.stepKeys?.[0]) {
|
|
43
|
+
const from = getControlAt(panelId, `${clip.key}.from`);
|
|
44
|
+
if (from) {
|
|
45
|
+
const index = controls.findIndex((control) => control.path === `${clip.key}.${stepKey}.to`);
|
|
46
|
+
controls = index >= 0
|
|
47
|
+
? [...controls.slice(0, index), from, ...controls.slice(index)]
|
|
48
|
+
: [...controls, from];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
title = `${clip.label} · ${formatStepLabel(stepKey)}`;
|
|
52
|
+
} else {
|
|
53
|
+
controls = getClipControls(panelId, clip.key, clipPopoverExclusions(clip));
|
|
54
|
+
title = clip.label;
|
|
55
|
+
}
|
|
56
|
+
const target = stepKey ? `${clip.key}.${stepKey}` : clip.key;
|
|
57
|
+
const durationMeta = getControlAt(panelId, `${target}.duration`);
|
|
58
|
+
const durationValue = durationMeta ? values[durationMeta.path] : undefined;
|
|
59
|
+
const transitionDuration = durationMeta?.type === 'slider' && typeof durationValue === 'number'
|
|
60
|
+
? {
|
|
61
|
+
value: durationValue,
|
|
62
|
+
onChange: (next: number) => DialStore.updateValue(panelId, durationMeta.path, next),
|
|
63
|
+
min: Math.max(TIMELINE_MIN_CLIP_DURATION, durationMeta.min ?? 0),
|
|
64
|
+
max: durationMeta.max,
|
|
65
|
+
step: durationMeta.step,
|
|
66
|
+
}
|
|
67
|
+
: undefined;
|
|
68
|
+
return {
|
|
69
|
+
controls,
|
|
70
|
+
title,
|
|
71
|
+
transitionDuration,
|
|
72
|
+
displayValues: timelinePopoverDisplayValues(values, clip.key, clip.stepKeys, stepKey),
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const position = $derived.by(() => {
|
|
77
|
+
const right = viewport.offsetLeft + viewport.width;
|
|
78
|
+
const bottom = viewport.offsetTop + viewport.height;
|
|
79
|
+
const width = Math.min(POPOVER_WIDTH, Math.max(220, viewport.width - 24));
|
|
80
|
+
const left = clamp(
|
|
81
|
+
popover.anchor.left + popover.anchor.width / 2 - width / 2,
|
|
82
|
+
viewport.offsetLeft + 12,
|
|
83
|
+
Math.max(viewport.offsetLeft + 12, right - width - 12)
|
|
84
|
+
);
|
|
85
|
+
const above = Math.max(0, popover.anchor.top - viewport.offsetTop - 22);
|
|
86
|
+
const below = Math.max(0, bottom - popover.anchor.bottom - 22);
|
|
87
|
+
const placeAbove = naturalHeight === 0
|
|
88
|
+
? above >= below
|
|
89
|
+
: naturalHeight <= above || (naturalHeight > below && above >= below);
|
|
90
|
+
const availableHeight = placeAbove ? above : below;
|
|
91
|
+
const renderedHeight = Math.min(naturalHeight || availableHeight, availableHeight);
|
|
92
|
+
const rawTop = placeAbove ? popover.anchor.top - 10 - renderedHeight : popover.anchor.bottom + 10;
|
|
93
|
+
return {
|
|
94
|
+
left,
|
|
95
|
+
top: clamp(rawTop, viewport.offsetTop + 12, Math.max(viewport.offsetTop + 12, bottom - renderedHeight - 12)),
|
|
96
|
+
width,
|
|
97
|
+
availableHeight,
|
|
98
|
+
placeAbove,
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
$effect(() => {
|
|
103
|
+
if (!element) return;
|
|
104
|
+
popover.clip.key;
|
|
105
|
+
popover.stepKey;
|
|
106
|
+
const measure = () => {
|
|
107
|
+
if (element) naturalHeight = element.scrollHeight + 2;
|
|
108
|
+
};
|
|
109
|
+
measure();
|
|
110
|
+
const observer = new ResizeObserver(measure);
|
|
111
|
+
observer.observe(element.querySelector('.dialkit-timeline-popover-body') ?? element);
|
|
112
|
+
return () => observer.disconnect();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
$effect(() => {
|
|
116
|
+
if (typeof window === 'undefined') return;
|
|
117
|
+
const updateViewport = () => { viewport = readViewport(); };
|
|
118
|
+
const outside = (event: PointerEvent) => {
|
|
119
|
+
const target = event.target as HTMLElement;
|
|
120
|
+
if (element?.contains(target) || target.closest?.('.dialkit-timeline-clip') || target.closest?.('.dialkit-timeline-label')) return;
|
|
121
|
+
onClose();
|
|
122
|
+
};
|
|
123
|
+
const keydown = (event: KeyboardEvent) => {
|
|
124
|
+
if (event.key === 'Escape') onClose();
|
|
125
|
+
};
|
|
126
|
+
window.addEventListener('resize', updateViewport);
|
|
127
|
+
window.visualViewport?.addEventListener('resize', updateViewport);
|
|
128
|
+
window.visualViewport?.addEventListener('scroll', updateViewport);
|
|
129
|
+
document.addEventListener('pointerdown', outside, true);
|
|
130
|
+
document.addEventListener('keydown', keydown);
|
|
131
|
+
return () => {
|
|
132
|
+
window.removeEventListener('resize', updateViewport);
|
|
133
|
+
window.visualViewport?.removeEventListener('resize', updateViewport);
|
|
134
|
+
window.visualViewport?.removeEventListener('scroll', updateViewport);
|
|
135
|
+
document.removeEventListener('pointerdown', outside, true);
|
|
136
|
+
document.removeEventListener('keydown', keydown);
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
function readViewport() {
|
|
141
|
+
if (typeof window === 'undefined') return { width: 1024, height: 768, offsetLeft: 0, offsetTop: 0 };
|
|
142
|
+
return {
|
|
143
|
+
width: window.visualViewport?.width ?? window.innerWidth,
|
|
144
|
+
height: window.visualViewport?.height ?? window.innerHeight,
|
|
145
|
+
offsetLeft: window.visualViewport?.offsetLeft ?? 0,
|
|
146
|
+
offsetTop: window.visualViewport?.offsetTop ?? 0,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function clipPopoverExclusions(clip: TimelineClipMeta) {
|
|
151
|
+
return new Set([...(clip.stepKeys ?? []), ...(clip.tracks?.map((track) => track.prop) ?? [])]);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function getClipControls(panel: string, path: string, exclusions?: Set<string>): ControlMeta[] {
|
|
155
|
+
const currentPanel = DialStore.getPanel(panel);
|
|
156
|
+
const folder = currentPanel ? findControl(currentPanel.controls, path) : null;
|
|
157
|
+
if (!folder?.children) return [];
|
|
158
|
+
return folder.children.filter((control) => {
|
|
159
|
+
const key = control.path.slice(path.length + 1);
|
|
160
|
+
return key !== 'at' && key !== 'duration' && !exclusions?.has(key);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function getControlAt(panel: string, path: string): ControlMeta | null {
|
|
165
|
+
const currentPanel = DialStore.getPanel(panel);
|
|
166
|
+
return currentPanel ? findControl(currentPanel.controls, path) : null;
|
|
167
|
+
}
|
|
168
|
+
</script>
|
|
169
|
+
|
|
170
|
+
{#if presentation.controls.length > 0}
|
|
171
|
+
<Portal target="body">
|
|
172
|
+
<div class="dialkit-root" data-theme={theme}>
|
|
173
|
+
<div
|
|
174
|
+
bind:this={element}
|
|
175
|
+
class="dialkit-timeline-popover"
|
|
176
|
+
data-placement={position.placeAbove ? 'above' : 'below'}
|
|
177
|
+
style:left={`${position.left}px`}
|
|
178
|
+
style:top={`${position.top}px`}
|
|
179
|
+
style:width={`${position.width}px`}
|
|
180
|
+
style:max-height={`${position.availableHeight}px`}
|
|
181
|
+
style:visibility={naturalHeight > 0 ? 'visible' : 'hidden'}
|
|
182
|
+
role="dialog"
|
|
183
|
+
aria-label={`Edit ${presentation.title}`}
|
|
184
|
+
>
|
|
185
|
+
<div class="dialkit-timeline-popover-header">
|
|
186
|
+
<span class="dialkit-timeline-popover-title">{presentation.title}</span>
|
|
187
|
+
<button class="dialkit-timeline-popover-close" onclick={onClose} title="Close editor" aria-label="Close editor">
|
|
188
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
189
|
+
<path d="M6 6L18 18M18 6L6 18" />
|
|
190
|
+
</svg>
|
|
191
|
+
</button>
|
|
192
|
+
</div>
|
|
193
|
+
<div class="dialkit-timeline-popover-body">
|
|
194
|
+
{#each presentation.controls as control (control.path)}
|
|
195
|
+
<ControlRenderer
|
|
196
|
+
{panelId}
|
|
197
|
+
{control}
|
|
198
|
+
values={presentation.displayValues}
|
|
199
|
+
transitionDuration={presentation.transitionDuration}
|
|
200
|
+
/>
|
|
201
|
+
{/each}
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</Portal>
|
|
206
|
+
{/if}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DialValue } from 'dialkit/store';
|
|
2
|
+
import type { TimelineClipMeta } from 'dialkit/timeline';
|
|
3
|
+
import type { DialTheme } from '../DialRoot.svelte';
|
|
4
|
+
export type PopoverState = {
|
|
5
|
+
clip: TimelineClipMeta;
|
|
6
|
+
stepKey?: string;
|
|
7
|
+
anchor: {
|
|
8
|
+
left: number;
|
|
9
|
+
top: number;
|
|
10
|
+
right: number;
|
|
11
|
+
bottom: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
type $$ComponentProps = {
|
|
17
|
+
panelId: string;
|
|
18
|
+
popover: PopoverState;
|
|
19
|
+
values: Record<string, DialValue>;
|
|
20
|
+
theme: DialTheme;
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
};
|
|
23
|
+
declare const ClipPopover: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
24
|
+
type ClipPopover = ReturnType<typeof ClipPopover>;
|
|
25
|
+
export default ClipPopover;
|
|
26
|
+
//# sourceMappingURL=ClipPopover.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClipPopover.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/Timeline/ClipPopover.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,eAAe,CAAC;AAO5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACrG,CAAC;AACH,KAAK,gBAAgB,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAkLJ,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
TimelineStore,
|
|
4
|
+
TimelineUiStore,
|
|
5
|
+
isDevDefault,
|
|
6
|
+
} from 'dialkit/timeline';
|
|
7
|
+
import type { TimelineMeta } from 'dialkit/timeline';
|
|
8
|
+
import Portal from '../../Portal.svelte';
|
|
9
|
+
import type { DialTheme } from '../DialRoot.svelte';
|
|
10
|
+
import TimelineSection from './TimelineSection.svelte';
|
|
11
|
+
|
|
12
|
+
const DEFAULT_DOCK_MAX_HEIGHT = 400;
|
|
13
|
+
const MIN_DOCK_MAX_HEIGHT = 120;
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
theme = 'system',
|
|
17
|
+
defaultVisible = true,
|
|
18
|
+
visible,
|
|
19
|
+
onVisibilityChange,
|
|
20
|
+
defaultOpen = true,
|
|
21
|
+
productionEnabled = isDevDefault,
|
|
22
|
+
} = $props<{
|
|
23
|
+
theme?: DialTheme;
|
|
24
|
+
defaultVisible?: boolean;
|
|
25
|
+
visible?: boolean;
|
|
26
|
+
onVisibilityChange?: (visible: boolean) => void;
|
|
27
|
+
defaultOpen?: boolean;
|
|
28
|
+
productionEnabled?: boolean;
|
|
29
|
+
}>();
|
|
30
|
+
|
|
31
|
+
const controllerId = Symbol('dialkit-timeline-visibility');
|
|
32
|
+
let mounted = $state(false);
|
|
33
|
+
let timelines = $state<TimelineMeta[]>([]);
|
|
34
|
+
let dockVisible = $state(TimelineUiStore.getVisible());
|
|
35
|
+
let dockMaxHeight = $state(DEFAULT_DOCK_MAX_HEIGHT);
|
|
36
|
+
let dockElement = $state<HTMLDivElement>();
|
|
37
|
+
let resizeCleanup: (() => void) | null = null;
|
|
38
|
+
|
|
39
|
+
$effect(() => {
|
|
40
|
+
if (typeof window === 'undefined') return;
|
|
41
|
+
mounted = true;
|
|
42
|
+
timelines = TimelineStore.getTimelines();
|
|
43
|
+
dockVisible = TimelineUiStore.getVisible();
|
|
44
|
+
const unsubscribeVisibility = TimelineUiStore.subscribe(() => {
|
|
45
|
+
dockVisible = TimelineUiStore.getVisible();
|
|
46
|
+
});
|
|
47
|
+
const unregisterController = TimelineUiStore.registerController(controllerId, {
|
|
48
|
+
visible,
|
|
49
|
+
defaultVisible,
|
|
50
|
+
onVisibilityChange,
|
|
51
|
+
});
|
|
52
|
+
dockVisible = TimelineUiStore.getVisible();
|
|
53
|
+
const unsubscribeTimelines = TimelineStore.subscribeGlobal(() => {
|
|
54
|
+
timelines = TimelineStore.getTimelines();
|
|
55
|
+
});
|
|
56
|
+
return () => {
|
|
57
|
+
unregisterController();
|
|
58
|
+
unsubscribeTimelines();
|
|
59
|
+
unsubscribeVisibility();
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
$effect(() => {
|
|
64
|
+
TimelineUiStore.updateController(controllerId, {
|
|
65
|
+
visible,
|
|
66
|
+
defaultVisible,
|
|
67
|
+
onVisibilityChange,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
$effect(() => () => resizeCleanup?.());
|
|
72
|
+
|
|
73
|
+
function handleResizePointerDown(event: PointerEvent) {
|
|
74
|
+
if (!dockElement) return;
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
event.stopPropagation();
|
|
77
|
+
resizeCleanup?.();
|
|
78
|
+
|
|
79
|
+
const pointerY = event.clientY;
|
|
80
|
+
const startHeight = dockElement.getBoundingClientRect().height;
|
|
81
|
+
const move = (next: PointerEvent) => {
|
|
82
|
+
next.preventDefault();
|
|
83
|
+
const viewportMax = Math.max(MIN_DOCK_MAX_HEIGHT, window.innerHeight - 24);
|
|
84
|
+
dockMaxHeight = Math.min(
|
|
85
|
+
viewportMax,
|
|
86
|
+
Math.max(MIN_DOCK_MAX_HEIGHT, startHeight + pointerY - next.clientY)
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
const finish = () => {
|
|
90
|
+
window.removeEventListener('pointermove', move);
|
|
91
|
+
window.removeEventListener('pointerup', finish);
|
|
92
|
+
window.removeEventListener('pointercancel', finish);
|
|
93
|
+
resizeCleanup = null;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
window.addEventListener('pointermove', move, { passive: false });
|
|
97
|
+
window.addEventListener('pointerup', finish);
|
|
98
|
+
window.addEventListener('pointercancel', finish);
|
|
99
|
+
resizeCleanup = finish;
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
{#if productionEnabled && mounted && timelines.length > 0}
|
|
104
|
+
<Portal target="body">
|
|
105
|
+
<div class="dialkit-root dialkit-timeline" data-theme={theme} hidden={!dockVisible}>
|
|
106
|
+
<div
|
|
107
|
+
class="dialkit-timeline-resize-handle"
|
|
108
|
+
onpointerdown={handleResizePointerDown}
|
|
109
|
+
role="separator"
|
|
110
|
+
aria-label="Resize timeline height"
|
|
111
|
+
aria-orientation="horizontal"
|
|
112
|
+
title="Drag to resize timeline"
|
|
113
|
+
></div>
|
|
114
|
+
<div
|
|
115
|
+
bind:this={dockElement}
|
|
116
|
+
class="dialkit-timeline-dock"
|
|
117
|
+
style:max-height={`min(${dockMaxHeight}px, calc(100vh - 24px))`}
|
|
118
|
+
>
|
|
119
|
+
{#each timelines as timeline (timeline.id)}
|
|
120
|
+
<TimelineSection meta={timeline} {defaultOpen} {theme} {dockVisible} />
|
|
121
|
+
{/each}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</Portal>
|
|
125
|
+
{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DialTheme } from '../DialRoot.svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
theme?: DialTheme;
|
|
4
|
+
defaultVisible?: boolean;
|
|
5
|
+
visible?: boolean;
|
|
6
|
+
onVisibilityChange?: (visible: boolean) => void;
|
|
7
|
+
defaultOpen?: boolean;
|
|
8
|
+
productionEnabled?: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare const DialTimeline: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type DialTimeline = ReturnType<typeof DialTimeline>;
|
|
12
|
+
export default DialTimeline;
|
|
13
|
+
//# sourceMappingURL=DialTimeline.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DialTimeline.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/Timeline/DialTimeline.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGnD,KAAK,gBAAgB,GAAG;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AA2GJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|