dialkit 1.3.0 → 1.4.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 +433 -3
- package/dist/icons.d.ts +4 -1
- package/dist/icons.js +13 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.cjs +3118 -480
- 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 +3050 -417
- package/dist/index.js.map +1 -1
- package/dist/solid/index.d.ts +225 -3
- package/dist/solid/index.js +5697 -2508
- 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 +704 -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 +76 -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 +756 -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 +704 -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 +2867 -361
- 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
package/dist/vue/index.js
CHANGED
|
@@ -69,6 +69,19 @@ function isSpringConfigValue(value) {
|
|
|
69
69
|
function isEasingConfigValue(value) {
|
|
70
70
|
return hasType(value, "easing");
|
|
71
71
|
}
|
|
72
|
+
function isHexColor(value) {
|
|
73
|
+
return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(value);
|
|
74
|
+
}
|
|
75
|
+
function formatLabel(key) {
|
|
76
|
+
return key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
|
|
77
|
+
}
|
|
78
|
+
function inferStep(min, max) {
|
|
79
|
+
const range = max - min;
|
|
80
|
+
if (range <= 1) return 0.01;
|
|
81
|
+
if (range <= 10) return 0.1;
|
|
82
|
+
if (range <= 100) return 1;
|
|
83
|
+
return 10;
|
|
84
|
+
}
|
|
72
85
|
function isActionConfigValue(value) {
|
|
73
86
|
return hasType(value, "action");
|
|
74
87
|
}
|
|
@@ -89,6 +102,9 @@ function getFirstOptionValue(options) {
|
|
|
89
102
|
var DialStoreClass = class {
|
|
90
103
|
constructor() {
|
|
91
104
|
this.panels = /* @__PURE__ */ new Map();
|
|
105
|
+
this.panelsSnapshot = [];
|
|
106
|
+
this.standardPanelsSnapshot = [];
|
|
107
|
+
this.timelinePanelsSnapshot = [];
|
|
92
108
|
this.listeners = /* @__PURE__ */ new Map();
|
|
93
109
|
this.globalListeners = /* @__PURE__ */ new Set();
|
|
94
110
|
this.snapshots = /* @__PURE__ */ new Map();
|
|
@@ -102,6 +118,12 @@ var DialStoreClass = class {
|
|
|
102
118
|
this.persistConfigs = /* @__PURE__ */ new Map();
|
|
103
119
|
}
|
|
104
120
|
registerPanel(id, name, config, shortcuts, options = {}) {
|
|
121
|
+
const existingPanel = this.panels.get(id);
|
|
122
|
+
if (existingPanel && existingPanel.kind !== options.kind) {
|
|
123
|
+
console.warn(
|
|
124
|
+
`[dialkit] Panel id "${id}" cannot be shared by a timeline and a standard panel; the most recent registration controls where it renders.`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
105
127
|
this.configurePanelRetention(id, options);
|
|
106
128
|
this.registrationCounts.set(id, (this.registrationCounts.get(id) ?? 0) + 1);
|
|
107
129
|
const controls = this.parseConfig(config, "", shortcuts);
|
|
@@ -113,7 +135,7 @@ var DialStoreClass = class {
|
|
|
113
135
|
const values = this.reconcileValues(defaultValues, previousValues, controlsByPath);
|
|
114
136
|
const previousBaseValues = this.baseValues.get(id) ?? persisted?.baseValues ?? persisted?.values ?? {};
|
|
115
137
|
const baseValues = this.reconcileValues(defaultValues, previousBaseValues, controlsByPath);
|
|
116
|
-
this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {} });
|
|
138
|
+
this.panels.set(id, { id, name, controls, values, shortcuts: shortcuts ?? {}, kind: options.kind });
|
|
117
139
|
this.snapshots.set(id, { ...values });
|
|
118
140
|
this.baseValues.set(id, baseValues);
|
|
119
141
|
this.defaultValues.set(id, { ...defaultValues });
|
|
@@ -140,7 +162,7 @@ var DialStoreClass = class {
|
|
|
140
162
|
const defaultValues = this.flattenValues(config, "");
|
|
141
163
|
this.initTransitionModes(config, "", defaultValues);
|
|
142
164
|
const nextValues = this.reconcileValues(defaultValues, existing.values, controlsByPath);
|
|
143
|
-
const nextPanel = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts };
|
|
165
|
+
const nextPanel = { id, name, controls, values: nextValues, shortcuts: shortcuts ?? existing.shortcuts, kind: options.kind ?? existing.kind };
|
|
144
166
|
this.panels.set(id, nextPanel);
|
|
145
167
|
this.snapshots.set(id, { ...nextValues });
|
|
146
168
|
const previousBaseValues = this.baseValues.get(id) ?? {};
|
|
@@ -165,8 +187,8 @@ var DialStoreClass = class {
|
|
|
165
187
|
}
|
|
166
188
|
this.registrationCounts.delete(id);
|
|
167
189
|
this.panels.delete(id);
|
|
168
|
-
this.listeners.delete(id);
|
|
169
|
-
this.actionListeners.delete(id);
|
|
190
|
+
if (this.listeners.get(id)?.size === 0) this.listeners.delete(id);
|
|
191
|
+
if (this.actionListeners.get(id)?.size === 0) this.actionListeners.delete(id);
|
|
170
192
|
if (!this.retainedPanels.has(id)) {
|
|
171
193
|
this.snapshots.delete(id);
|
|
172
194
|
this.baseValues.delete(id);
|
|
@@ -258,8 +280,10 @@ var DialStoreClass = class {
|
|
|
258
280
|
getValues(panelId) {
|
|
259
281
|
return this.snapshots.get(panelId) ?? EMPTY_VALUES;
|
|
260
282
|
}
|
|
261
|
-
getPanels() {
|
|
262
|
-
return
|
|
283
|
+
getPanels(kind) {
|
|
284
|
+
if (kind === "panel") return this.standardPanelsSnapshot;
|
|
285
|
+
if (kind === "timeline") return this.timelinePanelsSnapshot;
|
|
286
|
+
return this.panelsSnapshot;
|
|
263
287
|
}
|
|
264
288
|
getPanel(id) {
|
|
265
289
|
return this.panels.get(id);
|
|
@@ -270,7 +294,11 @@ var DialStoreClass = class {
|
|
|
270
294
|
}
|
|
271
295
|
this.listeners.get(panelId).add(listener);
|
|
272
296
|
return () => {
|
|
273
|
-
this.listeners.get(panelId)
|
|
297
|
+
const listeners = this.listeners.get(panelId);
|
|
298
|
+
listeners?.delete(listener);
|
|
299
|
+
if (listeners?.size === 0 && !this.panels.has(panelId)) {
|
|
300
|
+
this.listeners.delete(panelId);
|
|
301
|
+
}
|
|
274
302
|
};
|
|
275
303
|
}
|
|
276
304
|
subscribeGlobal(listener) {
|
|
@@ -283,7 +311,11 @@ var DialStoreClass = class {
|
|
|
283
311
|
}
|
|
284
312
|
this.actionListeners.get(panelId).add(listener);
|
|
285
313
|
return () => {
|
|
286
|
-
this.actionListeners.get(panelId)
|
|
314
|
+
const listeners = this.actionListeners.get(panelId);
|
|
315
|
+
listeners?.delete(listener);
|
|
316
|
+
if (listeners?.size === 0 && !this.panels.has(panelId)) {
|
|
317
|
+
this.actionListeners.delete(panelId);
|
|
318
|
+
}
|
|
287
319
|
};
|
|
288
320
|
}
|
|
289
321
|
triggerAction(panelId, path) {
|
|
@@ -478,6 +510,9 @@ var DialStoreClass = class {
|
|
|
478
510
|
this.listeners.get(panelId)?.forEach((fn) => fn());
|
|
479
511
|
}
|
|
480
512
|
notifyGlobal() {
|
|
513
|
+
this.panelsSnapshot = Array.from(this.panels.values());
|
|
514
|
+
this.standardPanelsSnapshot = this.panelsSnapshot.filter((panel) => panel.kind !== "timeline");
|
|
515
|
+
this.timelinePanelsSnapshot = this.panelsSnapshot.filter((panel) => panel.kind === "timeline");
|
|
481
516
|
this.globalListeners.forEach((fn) => fn());
|
|
482
517
|
}
|
|
483
518
|
initTransitionModes(config, prefix, values) {
|
|
@@ -593,10 +628,10 @@ var DialStoreClass = class {
|
|
|
593
628
|
return typeof value === "object" && value !== null && "type" in value && value.type === "text";
|
|
594
629
|
}
|
|
595
630
|
isHexColor(value) {
|
|
596
|
-
return
|
|
631
|
+
return isHexColor(value);
|
|
597
632
|
}
|
|
598
633
|
formatLabel(key) {
|
|
599
|
-
return key
|
|
634
|
+
return formatLabel(key);
|
|
600
635
|
}
|
|
601
636
|
inferRange(value) {
|
|
602
637
|
if (value >= 0 && value <= 1) {
|
|
@@ -612,11 +647,7 @@ var DialStoreClass = class {
|
|
|
612
647
|
}
|
|
613
648
|
}
|
|
614
649
|
inferStep(min, max) {
|
|
615
|
-
|
|
616
|
-
if (range <= 1) return 0.01;
|
|
617
|
-
if (range <= 10) return 0.1;
|
|
618
|
-
if (range <= 100) return 1;
|
|
619
|
-
return 10;
|
|
650
|
+
return inferStep(min, max);
|
|
620
651
|
}
|
|
621
652
|
normalizePreservedValue(existingValue, defaultValue, control) {
|
|
622
653
|
if (existingValue === void 0 || !control) {
|
|
@@ -688,7 +719,7 @@ var DialStoreClass = class {
|
|
|
688
719
|
return map;
|
|
689
720
|
}
|
|
690
721
|
};
|
|
691
|
-
var DialStore = new DialStoreClass();
|
|
722
|
+
var DialStore = /* @__PURE__ */ new DialStoreClass();
|
|
692
723
|
|
|
693
724
|
// src/vue/useDialKit.ts
|
|
694
725
|
var dialKitInstance = 0;
|
|
@@ -770,226 +801,1518 @@ function useDialKitController(name, config, options) {
|
|
|
770
801
|
};
|
|
771
802
|
}
|
|
772
803
|
|
|
773
|
-
// src/vue/
|
|
774
|
-
import {
|
|
775
|
-
createApp,
|
|
776
|
-
defineComponent as defineComponent16,
|
|
777
|
-
h as h16,
|
|
778
|
-
shallowRef as shallowRef2
|
|
779
|
-
} from "vue";
|
|
780
|
-
|
|
781
|
-
// src/vue/components/DialRoot.ts
|
|
782
|
-
import { computed as computed5, defineComponent as defineComponent15, h as h15, nextTick as nextTick3, onMounted as onMounted10, onUnmounted as onUnmounted9, ref as ref13, Teleport as Teleport3 } from "vue";
|
|
783
|
-
|
|
784
|
-
// src/vue/components/Folder.ts
|
|
785
|
-
import { defineComponent, h, onMounted as onMounted2, onUnmounted as onUnmounted2, ref as ref2 } from "vue";
|
|
786
|
-
import { AnimatePresence, motion } from "motion-v";
|
|
804
|
+
// src/vue/useDialTimeline.ts
|
|
805
|
+
import { computed as computed2, onMounted as onMounted2, onUnmounted as onUnmounted2, shallowRef as shallowRef2, watch as watch2 } from "vue";
|
|
787
806
|
|
|
788
|
-
// src/
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
"
|
|
807
|
-
|
|
808
|
-
"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"
|
|
807
|
+
// src/store/TimelineStore.ts
|
|
808
|
+
function loopSpan(duration, loopStart) {
|
|
809
|
+
if (!Number.isFinite(duration) || duration <= 0) return 0;
|
|
810
|
+
if (!Number.isFinite(loopStart)) loopStart = 0;
|
|
811
|
+
const start = Math.min(Math.max(0, loopStart), duration);
|
|
812
|
+
return duration - start > 0 ? duration - start : duration;
|
|
813
|
+
}
|
|
814
|
+
function foldLoopTime(time, duration, loopStart = 0) {
|
|
815
|
+
if (!Number.isFinite(time) || !Number.isFinite(duration) || duration <= 0) {
|
|
816
|
+
return { time: 0, wraps: 0 };
|
|
817
|
+
}
|
|
818
|
+
if (time < duration) return { time, wraps: 0 };
|
|
819
|
+
const span = loopSpan(duration, loopStart);
|
|
820
|
+
const base = duration - span;
|
|
821
|
+
const over = time - base;
|
|
822
|
+
return { time: base + over % span, wraps: Math.floor(over / span) };
|
|
823
|
+
}
|
|
824
|
+
var TIMELINE_CLIP_COLORS = [
|
|
825
|
+
"#E8E8E8"
|
|
826
|
+
// neutral white — slightly off-white so the pure-white selection ring still reads
|
|
809
827
|
];
|
|
810
|
-
var
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
if (props.isRoot) {
|
|
846
|
-
resizeHandler = () => {
|
|
847
|
-
windowHeight.value = window.innerHeight;
|
|
848
|
-
};
|
|
849
|
-
window.addEventListener("resize", resizeHandler);
|
|
850
|
-
}
|
|
851
|
-
onUnmounted2(() => {
|
|
852
|
-
if (resizeHandler) window.removeEventListener("resize", resizeHandler);
|
|
853
|
-
});
|
|
854
|
-
const handleToggle = () => {
|
|
855
|
-
if (props.inline && props.isRoot) return;
|
|
856
|
-
const next = !isOpen.value;
|
|
857
|
-
isOpen.value = next;
|
|
858
|
-
isCollapsed.value = !next;
|
|
859
|
-
emit("openChange", next);
|
|
860
|
-
};
|
|
861
|
-
let ro = null;
|
|
862
|
-
onMounted2(() => {
|
|
863
|
-
if (!props.isRoot || typeof ResizeObserver === "undefined") return;
|
|
864
|
-
const el = contentRef.value;
|
|
865
|
-
if (!el) return;
|
|
866
|
-
ro = new ResizeObserver(() => {
|
|
867
|
-
if (isOpen.value) {
|
|
868
|
-
const next = el.offsetHeight;
|
|
869
|
-
if (contentHeight.value !== next) {
|
|
870
|
-
contentHeight.value = next;
|
|
828
|
+
var EMPTY_TRANSPORT = Object.freeze({ time: 0, playing: false, duration: 0, wraps: 0 });
|
|
829
|
+
var TimelineStoreClass = class {
|
|
830
|
+
constructor() {
|
|
831
|
+
this.timelines = /* @__PURE__ */ new Map();
|
|
832
|
+
this.transports = /* @__PURE__ */ new Map();
|
|
833
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
834
|
+
this.globalListeners = /* @__PURE__ */ new Set();
|
|
835
|
+
this.registrationCounts = /* @__PURE__ */ new Map();
|
|
836
|
+
this.listCache = null;
|
|
837
|
+
this.rafId = null;
|
|
838
|
+
this.lastTick = 0;
|
|
839
|
+
this.tick = (now) => {
|
|
840
|
+
const dt = Math.max(0, (now - this.lastTick) / 1e3);
|
|
841
|
+
this.lastTick = now;
|
|
842
|
+
let anyPlaying = false;
|
|
843
|
+
for (const [id, transport] of this.transports) {
|
|
844
|
+
if (!transport.playing) continue;
|
|
845
|
+
const meta = this.timelines.get(id);
|
|
846
|
+
const duration = meta?.duration ?? transport.duration;
|
|
847
|
+
if (!Number.isFinite(duration) || duration <= 0) {
|
|
848
|
+
this.transports.set(id, { time: 0, playing: false, duration: 0, wraps: 0 });
|
|
849
|
+
this.notify(id);
|
|
850
|
+
continue;
|
|
851
|
+
}
|
|
852
|
+
let time = transport.time + dt;
|
|
853
|
+
let playing = true;
|
|
854
|
+
let wraps = transport.wraps;
|
|
855
|
+
if (time >= duration) {
|
|
856
|
+
if (meta?.loop) {
|
|
857
|
+
const folded = foldLoopTime(time, duration, meta.loopStart);
|
|
858
|
+
time = folded.time;
|
|
859
|
+
wraps += folded.wraps;
|
|
860
|
+
} else {
|
|
861
|
+
time = duration;
|
|
862
|
+
playing = false;
|
|
871
863
|
}
|
|
872
864
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
contentHeight.value = el.offsetHeight;
|
|
865
|
+
this.transports.set(id, { time, playing, duration, wraps });
|
|
866
|
+
if (playing) anyPlaying = true;
|
|
867
|
+
this.notify(id);
|
|
877
868
|
}
|
|
869
|
+
this.rafId = anyPlaying ? window.requestAnimationFrame(this.tick) : null;
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
register(meta, options) {
|
|
873
|
+
const existing = this.timelines.get(meta.id);
|
|
874
|
+
if (existing && existing.name !== meta.name) {
|
|
875
|
+
console.warn(
|
|
876
|
+
`[dialkit] Timeline id "${meta.id}" is already registered by "${existing.name}"; "${meta.name}" will share and overwrite that transport.`
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
this.registrationCounts.set(meta.id, (this.registrationCounts.get(meta.id) ?? 0) + 1);
|
|
880
|
+
this.applyMeta(meta, options.autoplay);
|
|
881
|
+
}
|
|
882
|
+
update(meta) {
|
|
883
|
+
if (!this.timelines.has(meta.id)) return;
|
|
884
|
+
this.applyMeta(meta, false);
|
|
885
|
+
}
|
|
886
|
+
unregister(id) {
|
|
887
|
+
const nextCount = (this.registrationCounts.get(id) ?? 1) - 1;
|
|
888
|
+
if (nextCount > 0) {
|
|
889
|
+
this.registrationCounts.set(id, nextCount);
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
this.registrationCounts.delete(id);
|
|
893
|
+
this.timelines.delete(id);
|
|
894
|
+
this.transports.delete(id);
|
|
895
|
+
if (this.listeners.get(id)?.size === 0) this.listeners.delete(id);
|
|
896
|
+
this.listCache = null;
|
|
897
|
+
this.notifyGlobal();
|
|
898
|
+
}
|
|
899
|
+
play(id) {
|
|
900
|
+
const transport = this.transports.get(id);
|
|
901
|
+
if (!transport || transport.duration <= 0 || transport.playing) return;
|
|
902
|
+
const restart = transport.time >= transport.duration;
|
|
903
|
+
this.transports.set(id, {
|
|
904
|
+
...transport,
|
|
905
|
+
time: restart ? 0 : transport.time,
|
|
906
|
+
wraps: restart ? 0 : transport.wraps,
|
|
907
|
+
playing: true
|
|
878
908
|
});
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
909
|
+
this.notify(id);
|
|
910
|
+
this.ensureLoop();
|
|
911
|
+
}
|
|
912
|
+
pause(id) {
|
|
913
|
+
const transport = this.transports.get(id);
|
|
914
|
+
if (!transport || !transport.playing) return;
|
|
915
|
+
this.transports.set(id, { ...transport, playing: false });
|
|
916
|
+
this.notify(id);
|
|
917
|
+
}
|
|
918
|
+
replay(id) {
|
|
919
|
+
const transport = this.transports.get(id);
|
|
920
|
+
if (!transport || transport.duration <= 0) return;
|
|
921
|
+
this.transports.set(id, { ...transport, time: 0, wraps: 0, playing: true });
|
|
922
|
+
this.notify(id);
|
|
923
|
+
this.ensureLoop();
|
|
924
|
+
}
|
|
925
|
+
seek(id, time) {
|
|
926
|
+
const transport = this.transports.get(id);
|
|
927
|
+
if (!transport || !Number.isFinite(time)) return;
|
|
928
|
+
const clamped = Math.min(transport.duration, Math.max(0, time));
|
|
929
|
+
this.transports.set(id, { ...transport, time: clamped, wraps: 0 });
|
|
930
|
+
this.notify(id);
|
|
931
|
+
}
|
|
932
|
+
getTransport(id) {
|
|
933
|
+
return this.transports.get(id) ?? EMPTY_TRANSPORT;
|
|
934
|
+
}
|
|
935
|
+
getTimeline(id) {
|
|
936
|
+
return this.timelines.get(id);
|
|
937
|
+
}
|
|
938
|
+
getTimelines() {
|
|
939
|
+
if (!this.listCache) {
|
|
940
|
+
this.listCache = Array.from(this.timelines.values());
|
|
941
|
+
}
|
|
942
|
+
return this.listCache;
|
|
943
|
+
}
|
|
944
|
+
subscribe(id, listener) {
|
|
945
|
+
if (!this.listeners.has(id)) {
|
|
946
|
+
this.listeners.set(id, /* @__PURE__ */ new Set());
|
|
947
|
+
}
|
|
948
|
+
this.listeners.get(id).add(listener);
|
|
949
|
+
return () => {
|
|
950
|
+
const listeners = this.listeners.get(id);
|
|
951
|
+
listeners?.delete(listener);
|
|
952
|
+
if (listeners?.size === 0 && !this.timelines.has(id)) {
|
|
953
|
+
this.listeners.delete(id);
|
|
919
954
|
}
|
|
920
|
-
return h(AnimatePresence, { initial: false }, {
|
|
921
|
-
default: () => isOpen.value ? [h(motion.div, {
|
|
922
|
-
key: "dialkit-folder-content",
|
|
923
|
-
class: "dialkit-folder-content",
|
|
924
|
-
initial: { height: 0, opacity: 0 },
|
|
925
|
-
animate: { height: "auto", opacity: 1 },
|
|
926
|
-
exit: { height: 0, opacity: 0 },
|
|
927
|
-
transition: { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
928
|
-
style: { clipPath: "inset(0 -20px)" }
|
|
929
|
-
}, [renderChildren()])] : []
|
|
930
|
-
});
|
|
931
955
|
};
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
"data-open": String(isOpen.value)
|
|
936
|
-
}, [
|
|
937
|
-
renderHeader(),
|
|
938
|
-
renderContent()
|
|
939
|
-
]);
|
|
956
|
+
}
|
|
957
|
+
subscribeGlobal(listener) {
|
|
958
|
+
this.globalListeners.add(listener);
|
|
940
959
|
return () => {
|
|
941
|
-
|
|
942
|
-
if (props.inline) {
|
|
943
|
-
return h("div", { class: "dialkit-panel-inner dialkit-panel-inline" }, [folderContent()]);
|
|
944
|
-
}
|
|
945
|
-
const panelStyle = isOpen.value ? {
|
|
946
|
-
width: 280,
|
|
947
|
-
height: contentHeight.value !== void 0 ? Math.min(contentHeight.value + props.panelHeightOffset, windowHeight.value - 32) : "auto",
|
|
948
|
-
borderRadius: 14,
|
|
949
|
-
boxShadow: "var(--dial-shadow)",
|
|
950
|
-
cursor: void 0,
|
|
951
|
-
overflowY: "auto"
|
|
952
|
-
} : {
|
|
953
|
-
width: 42,
|
|
954
|
-
height: 42,
|
|
955
|
-
borderRadius: 21,
|
|
956
|
-
boxShadow: "var(--dial-shadow-collapsed)",
|
|
957
|
-
overflow: "hidden",
|
|
958
|
-
cursor: "pointer"
|
|
959
|
-
};
|
|
960
|
-
return h(motion.div, {
|
|
961
|
-
class: "dialkit-panel-inner",
|
|
962
|
-
style: panelStyle,
|
|
963
|
-
onClick: !isOpen.value ? handleToggle : void 0,
|
|
964
|
-
"data-collapsed": String(isCollapsed.value),
|
|
965
|
-
whilePress: !isOpen.value ? { scale: 0.9 } : void 0,
|
|
966
|
-
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 }
|
|
967
|
-
}, [folderContent()]);
|
|
968
|
-
}
|
|
969
|
-
return folderContent();
|
|
960
|
+
this.globalListeners.delete(listener);
|
|
970
961
|
};
|
|
971
962
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
963
|
+
applyMeta(meta, autoplay) {
|
|
964
|
+
const duration = Number.isFinite(meta.duration) ? Math.max(0, meta.duration) : 0;
|
|
965
|
+
const loopStart = Number.isFinite(meta.loopStart) ? Math.min(duration, Math.max(0, meta.loopStart)) : 0;
|
|
966
|
+
const safeMeta = { ...meta, duration, loopStart };
|
|
967
|
+
this.timelines.set(meta.id, safeMeta);
|
|
968
|
+
const existing = this.transports.get(meta.id);
|
|
969
|
+
if (existing) {
|
|
970
|
+
this.transports.set(meta.id, {
|
|
971
|
+
time: Math.min(existing.time, duration),
|
|
972
|
+
playing: duration > 0 && existing.playing,
|
|
973
|
+
duration,
|
|
974
|
+
wraps: existing.wraps
|
|
975
|
+
});
|
|
976
|
+
} else {
|
|
977
|
+
const playing = duration > 0 && autoplay;
|
|
978
|
+
this.transports.set(meta.id, { time: 0, playing, duration, wraps: 0 });
|
|
979
|
+
if (playing) this.ensureLoop();
|
|
980
|
+
}
|
|
981
|
+
this.listCache = null;
|
|
982
|
+
this.notify(meta.id);
|
|
983
|
+
this.notifyGlobal();
|
|
984
|
+
}
|
|
985
|
+
ensureLoop() {
|
|
986
|
+
if (this.rafId !== null || typeof window === "undefined") return;
|
|
987
|
+
this.lastTick = performance.now();
|
|
988
|
+
this.rafId = window.requestAnimationFrame(this.tick);
|
|
989
|
+
}
|
|
990
|
+
notify(id) {
|
|
991
|
+
this.listeners.get(id)?.forEach((fn) => fn());
|
|
992
|
+
}
|
|
993
|
+
notifyGlobal() {
|
|
994
|
+
this.globalListeners.forEach((fn) => fn());
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
var TimelineStore = /* @__PURE__ */ new TimelineStoreClass();
|
|
981
998
|
|
|
982
|
-
// src/
|
|
983
|
-
function
|
|
984
|
-
|
|
985
|
-
const dot = s.indexOf(".");
|
|
986
|
-
return dot === -1 ? 0 : s.length - dot - 1;
|
|
999
|
+
// src/transition-math.ts
|
|
1000
|
+
function round2(value) {
|
|
1001
|
+
return Math.round(value * 100) / 100;
|
|
987
1002
|
}
|
|
988
|
-
function
|
|
989
|
-
|
|
990
|
-
return parseFloat(raw.toFixed(decimalsForStep(step)));
|
|
1003
|
+
function clamp(value, min, max) {
|
|
1004
|
+
return Math.min(max, Math.max(min, value));
|
|
991
1005
|
}
|
|
992
|
-
function
|
|
1006
|
+
function isTransitionConfig(value) {
|
|
1007
|
+
return isSpringConfigValue(value) || isEasingConfigValue(value);
|
|
1008
|
+
}
|
|
1009
|
+
function isPhysicsSpring(transition) {
|
|
1010
|
+
return transition.type === "spring" && (transition.stiffness !== void 0 || transition.damping !== void 0 || transition.mass !== void 0);
|
|
1011
|
+
}
|
|
1012
|
+
function springParams(spring) {
|
|
1013
|
+
if (isPhysicsSpring(spring)) {
|
|
1014
|
+
return { stiffness: spring.stiffness ?? 200, damping: spring.damping ?? 25, mass: spring.mass ?? 1 };
|
|
1015
|
+
}
|
|
1016
|
+
const visualDuration = Math.max(0.05, spring.visualDuration ?? 0.3);
|
|
1017
|
+
const bounce = spring.bounce ?? 0.3;
|
|
1018
|
+
const root = 2 * Math.PI / (visualDuration * 1.2);
|
|
1019
|
+
const stiffness = root * root;
|
|
1020
|
+
const damping = 2 * Math.min(1, Math.max(0.05, 1 - bounce)) * Math.sqrt(stiffness);
|
|
1021
|
+
return { stiffness, damping, mass: 1 };
|
|
1022
|
+
}
|
|
1023
|
+
function springProgress(t, { stiffness, damping, mass }) {
|
|
1024
|
+
if (t <= 0) return 0;
|
|
1025
|
+
const w0 = Math.sqrt(stiffness / mass);
|
|
1026
|
+
const zeta = damping / (2 * Math.sqrt(stiffness * mass));
|
|
1027
|
+
if (zeta < 0.9999) {
|
|
1028
|
+
const wd2 = w0 * Math.sqrt(1 - zeta * zeta);
|
|
1029
|
+
return 1 - Math.exp(-zeta * w0 * t) * (Math.cos(wd2 * t) + zeta * w0 / wd2 * Math.sin(wd2 * t));
|
|
1030
|
+
}
|
|
1031
|
+
if (zeta < 1.0001) {
|
|
1032
|
+
return 1 - Math.exp(-w0 * t) * (1 + w0 * t);
|
|
1033
|
+
}
|
|
1034
|
+
const wd = w0 * Math.sqrt(zeta * zeta - 1);
|
|
1035
|
+
const r1 = -zeta * w0 + wd;
|
|
1036
|
+
const r2 = -zeta * w0 - wd;
|
|
1037
|
+
return 1 + (r2 * Math.exp(r1 * t) - r1 * Math.exp(r2 * t)) / (r1 - r2);
|
|
1038
|
+
}
|
|
1039
|
+
function springSettleDuration(params) {
|
|
1040
|
+
const w0 = Math.sqrt(params.stiffness / params.mass);
|
|
1041
|
+
const zeta = params.damping / (2 * Math.sqrt(params.stiffness * params.mass));
|
|
1042
|
+
const decay = zeta >= 1 ? zeta * w0 - w0 * Math.sqrt(Math.max(0, zeta * zeta - 1)) : zeta * w0;
|
|
1043
|
+
const duration = Math.log(200) / Math.max(decay, 1e-6);
|
|
1044
|
+
return round2(clamp(duration, 0.05, 10));
|
|
1045
|
+
}
|
|
1046
|
+
function cubicBezierProgress(p, [x1, y1, x2, y2]) {
|
|
1047
|
+
if (p <= 0) return 0;
|
|
1048
|
+
if (p >= 1) return 1;
|
|
1049
|
+
const sampleX = (t2) => bezierAxis(t2, x1, x2);
|
|
1050
|
+
const sampleY = (t2) => bezierAxis(t2, y1, y2);
|
|
1051
|
+
let t = p;
|
|
1052
|
+
for (let i = 0; i < 8; i++) {
|
|
1053
|
+
const x = sampleX(t) - p;
|
|
1054
|
+
if (Math.abs(x) < 1e-5) return sampleY(t);
|
|
1055
|
+
const dx = bezierAxisDerivative(t, x1, x2);
|
|
1056
|
+
if (Math.abs(dx) < 1e-6) break;
|
|
1057
|
+
t -= x / dx;
|
|
1058
|
+
}
|
|
1059
|
+
let lo = 0;
|
|
1060
|
+
let hi = 1;
|
|
1061
|
+
t = p;
|
|
1062
|
+
while (hi - lo > 1e-5) {
|
|
1063
|
+
if (sampleX(t) < p) lo = t;
|
|
1064
|
+
else hi = t;
|
|
1065
|
+
t = (lo + hi) / 2;
|
|
1066
|
+
}
|
|
1067
|
+
return sampleY(t);
|
|
1068
|
+
}
|
|
1069
|
+
function bezierAxis(t, a1, a2) {
|
|
1070
|
+
return (1 - 3 * a2 + 3 * a1) * t * t * t + (3 * a2 - 6 * a1) * t * t + 3 * a1 * t;
|
|
1071
|
+
}
|
|
1072
|
+
function bezierAxisDerivative(t, a1, a2) {
|
|
1073
|
+
return 3 * (1 - 3 * a2 + 3 * a1) * t * t + 2 * (3 * a2 - 6 * a1) * t + 3 * a1;
|
|
1074
|
+
}
|
|
1075
|
+
function resolveClipTransition(raw, clipDuration) {
|
|
1076
|
+
const safeDuration = Math.max(0.05, clipDuration);
|
|
1077
|
+
if (raw.type === "easing") {
|
|
1078
|
+
return {
|
|
1079
|
+
transition: { ...raw, duration: safeDuration },
|
|
1080
|
+
duration: safeDuration,
|
|
1081
|
+
isPhysics: false
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
if (isPhysicsSpring(raw)) {
|
|
1085
|
+
return {
|
|
1086
|
+
transition: raw,
|
|
1087
|
+
duration: springSettleDuration(springParams(raw)),
|
|
1088
|
+
isPhysics: true
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
return {
|
|
1092
|
+
transition: { type: "spring", bounce: raw.bounce ?? 0.2, visualDuration: safeDuration },
|
|
1093
|
+
duration: safeDuration,
|
|
1094
|
+
isPhysics: false
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// src/timeline-core.ts
|
|
1099
|
+
var CLIP_VALUE_STEP = 0.01;
|
|
1100
|
+
var TIMELINE_MIN_CLIP_DURATION = 0.05;
|
|
1101
|
+
var DEFAULT_STEP_DURATION = 0.3;
|
|
1102
|
+
var DEFAULT_CLIP_TRANSITION = { type: "spring", bounce: 0.2 };
|
|
1103
|
+
var RESERVED_KEYS = /* @__PURE__ */ new Set(["time", "playing", "duration", "play", "pause", "replay", "seek"]);
|
|
1104
|
+
function isClipConfig(value) {
|
|
1105
|
+
return isPlainObject(value) && Number.isFinite(value.at);
|
|
1106
|
+
}
|
|
1107
|
+
function isGroupConfig(value) {
|
|
1108
|
+
if (!isPlainObject(value) || "at" in value) return false;
|
|
1109
|
+
const entries = Object.values(value);
|
|
1110
|
+
return entries.length > 0 && entries.some(isClipConfig);
|
|
1111
|
+
}
|
|
1112
|
+
function isPlainObject(value) {
|
|
1113
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1114
|
+
}
|
|
1115
|
+
function nonNegativeFinite(value, fallback = 0) {
|
|
1116
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : fallback;
|
|
1117
|
+
}
|
|
1118
|
+
function animatedDuration(value, fallback = DEFAULT_STEP_DURATION) {
|
|
1119
|
+
return Math.max(TIMELINE_MIN_CLIP_DURATION, nonNegativeFinite(value, fallback));
|
|
1120
|
+
}
|
|
1121
|
+
function transitionDefaultDuration(transition) {
|
|
1122
|
+
if (transition.type === "easing") return animatedDuration(transition.duration);
|
|
1123
|
+
if (isPhysicsSpring(transition)) {
|
|
1124
|
+
return animatedDuration(springSettleDuration(springParams(transition)));
|
|
1125
|
+
}
|
|
1126
|
+
if (transition.visualDuration !== void 0) return animatedDuration(transition.visualDuration);
|
|
1127
|
+
return animatedDuration(springSettleDuration(springParams(transition)));
|
|
1128
|
+
}
|
|
1129
|
+
function defaultStepDuration(step, inheritedTransition) {
|
|
1130
|
+
const curve = step.transition ?? inheritedTransition;
|
|
1131
|
+
if (curve && isPhysicsSpring(curve)) return transitionDefaultDuration(curve);
|
|
1132
|
+
if (step.duration !== void 0) return animatedDuration(step.duration);
|
|
1133
|
+
if (step.transition) return transitionDefaultDuration(step.transition);
|
|
1134
|
+
return DEFAULT_STEP_DURATION;
|
|
1135
|
+
}
|
|
1136
|
+
function defaultTrackDuration(track, inheritedTransition) {
|
|
1137
|
+
const curve = track.transition ?? inheritedTransition;
|
|
1138
|
+
if (track.steps?.length) {
|
|
1139
|
+
return track.steps.reduce((sum, step) => sum + defaultStepDuration(step, curve), 0);
|
|
1140
|
+
}
|
|
1141
|
+
if (curve && isPhysicsSpring(curve)) return transitionDefaultDuration(curve);
|
|
1142
|
+
if (track.duration !== void 0) return animatedDuration(track.duration);
|
|
1143
|
+
if (track.transition) return transitionDefaultDuration(track.transition);
|
|
1144
|
+
return DEFAULT_STEP_DURATION;
|
|
1145
|
+
}
|
|
1146
|
+
function defaultClipDuration(clip) {
|
|
1147
|
+
const defaultCurve = isTransitionConfig(clip.transition) ? clip.transition : DEFAULT_CLIP_TRANSITION;
|
|
1148
|
+
if (clip.props) {
|
|
1149
|
+
return Object.values(clip.props).reduce(
|
|
1150
|
+
(max, track) => Math.max(
|
|
1151
|
+
max,
|
|
1152
|
+
nonNegativeFinite(track.delay) + defaultTrackDuration(track, defaultCurve)
|
|
1153
|
+
),
|
|
1154
|
+
0
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
if (clip.steps?.length) {
|
|
1158
|
+
return clip.steps.reduce((sum, step) => sum + defaultStepDuration(step, defaultCurve), 0);
|
|
1159
|
+
}
|
|
1160
|
+
const animating = Boolean(clip.transition || clip.from || clip.to);
|
|
1161
|
+
if (!animating) return nonNegativeFinite(clip.duration);
|
|
1162
|
+
if (isPhysicsSpring(defaultCurve)) return transitionDefaultDuration(defaultCurve);
|
|
1163
|
+
if (clip.duration !== void 0) return animatedDuration(clip.duration);
|
|
1164
|
+
if (isTransitionConfig(clip.transition)) return transitionDefaultDuration(clip.transition);
|
|
1165
|
+
return clip.from || clip.to ? transitionDefaultDuration(DEFAULT_CLIP_TRANSITION) : 0;
|
|
1166
|
+
}
|
|
1167
|
+
function normalizeLoopMode(value) {
|
|
1168
|
+
if (value === true || value === "mirror" || value === "repeat") return "repeat";
|
|
1169
|
+
return "off";
|
|
1170
|
+
}
|
|
1171
|
+
function normalizeStoredTransition(transition, clipDuration) {
|
|
1172
|
+
if (transition.type === "easing") {
|
|
1173
|
+
return { ...transition, duration: clipDuration };
|
|
1174
|
+
}
|
|
1175
|
+
if (isPhysicsSpring(transition)) {
|
|
1176
|
+
return transition;
|
|
1177
|
+
}
|
|
1178
|
+
return { type: "spring", bounce: transition.bounce ?? 0.2 };
|
|
1179
|
+
}
|
|
1180
|
+
function collectClipEntries(config) {
|
|
1181
|
+
const entries = [];
|
|
1182
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1183
|
+
if (key === "duration") continue;
|
|
1184
|
+
if (RESERVED_KEYS.has(key)) {
|
|
1185
|
+
console.warn(`[dialkit] Timeline key "${key}" collides with a reserved key and was skipped.`);
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
if (isClipConfig(value)) {
|
|
1189
|
+
entries.push({ path: key, childKey: key, clip: value });
|
|
1190
|
+
} else if (isGroupConfig(value)) {
|
|
1191
|
+
for (const [childKey, childClip] of Object.entries(value)) {
|
|
1192
|
+
if (isClipConfig(childClip)) {
|
|
1193
|
+
entries.push({ path: `${key}.${childKey}`, childKey, group: key, clip: childClip });
|
|
1194
|
+
} else {
|
|
1195
|
+
console.warn(
|
|
1196
|
+
`[dialkit] Timeline clip "${key}.${childKey}" is missing a numeric "at" and was skipped.`
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
} else {
|
|
1201
|
+
console.warn(
|
|
1202
|
+
`[dialkit] Timeline entry "${key}" is neither a clip (needs a numeric "at") nor a group of clips and was skipped.`
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return entries;
|
|
1207
|
+
}
|
|
1208
|
+
function definedValues(values) {
|
|
1209
|
+
if (!values) return void 0;
|
|
1210
|
+
const result = {};
|
|
1211
|
+
for (const [key, value] of Object.entries(values)) {
|
|
1212
|
+
if (value !== void 0) result[key] = value;
|
|
1213
|
+
}
|
|
1214
|
+
return result;
|
|
1215
|
+
}
|
|
1216
|
+
function setDialPath(dialConfig, path, value) {
|
|
1217
|
+
const segments = path.split(".");
|
|
1218
|
+
let node = dialConfig;
|
|
1219
|
+
for (const segment of segments.slice(0, -1)) {
|
|
1220
|
+
node = node[segment] ?? (node[segment] = {});
|
|
1221
|
+
}
|
|
1222
|
+
node[segments[segments.length - 1]] = value;
|
|
1223
|
+
}
|
|
1224
|
+
function parseTimelineConfig(config) {
|
|
1225
|
+
const entries = collectClipEntries(config);
|
|
1226
|
+
let maxEnd = 0;
|
|
1227
|
+
for (const { clip } of entries) {
|
|
1228
|
+
maxEnd = Math.max(maxEnd, nonNegativeFinite(clip.at) + defaultClipDuration(clip));
|
|
1229
|
+
}
|
|
1230
|
+
const duration = typeof config.duration === "number" && Number.isFinite(config.duration) && config.duration > 0 ? config.duration : maxEnd > 0 ? Math.ceil(maxEnd * 100 - 1e-4) / 100 : 1;
|
|
1231
|
+
const dialConfig = {};
|
|
1232
|
+
const clips = [];
|
|
1233
|
+
entries.forEach(({ path, childKey, group, clip }, index) => {
|
|
1234
|
+
const raw = clip;
|
|
1235
|
+
if (raw.props && (raw.steps?.length || raw.from || raw.to)) {
|
|
1236
|
+
console.warn(
|
|
1237
|
+
`[dialkit] Timeline clip "${path}": "props" is mutually exclusive with from/to/steps \u2014 using "props".`
|
|
1238
|
+
);
|
|
1239
|
+
} else if (raw.steps?.length && raw.to) {
|
|
1240
|
+
console.warn(
|
|
1241
|
+
`[dialkit] Timeline clip "${path}": "to" is ignored when "steps" is present \u2014 each leg's "to" defines its targets.`
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
const hasSteps = Boolean(clip.steps?.length) && !clip.props;
|
|
1245
|
+
const hasProps = Boolean(clip.props);
|
|
1246
|
+
const single = isTransitionConfig(clip.transition) ? clip.transition : void 0;
|
|
1247
|
+
const total = defaultClipDuration(clip);
|
|
1248
|
+
const defaultCurve = single ?? DEFAULT_CLIP_TRANSITION;
|
|
1249
|
+
const clipAt = nonNegativeFinite(clip.at);
|
|
1250
|
+
const clipDial = {
|
|
1251
|
+
at: [clipAt, 0, duration, CLIP_VALUE_STEP]
|
|
1252
|
+
};
|
|
1253
|
+
if (!hasSteps && !hasProps) {
|
|
1254
|
+
clipDial.duration = [total, 0, duration, CLIP_VALUE_STEP];
|
|
1255
|
+
}
|
|
1256
|
+
if (!hasSteps && !hasProps && (clip.transition || clip.from || clip.to)) {
|
|
1257
|
+
clipDial.transition = normalizeStoredTransition(defaultCurve, total);
|
|
1258
|
+
}
|
|
1259
|
+
let tracks;
|
|
1260
|
+
if (clip.props) {
|
|
1261
|
+
tracks = [];
|
|
1262
|
+
for (const [prop, track] of Object.entries(clip.props)) {
|
|
1263
|
+
if (TRACK_RESERVED.has(prop) || /^step\d+$/.test(prop)) {
|
|
1264
|
+
console.warn(`[dialkit] Timeline property "${prop}" collides with a clip field and was skipped.`);
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
const trackDuration = defaultTrackDuration(track, defaultCurve);
|
|
1268
|
+
const trackCurve = track.transition ?? defaultCurve;
|
|
1269
|
+
const hasTrackSteps = Boolean(track.steps?.length);
|
|
1270
|
+
const trackDial = {
|
|
1271
|
+
delay: [nonNegativeFinite(track.delay), 0, duration, CLIP_VALUE_STEP]
|
|
1272
|
+
};
|
|
1273
|
+
if (!hasTrackSteps) {
|
|
1274
|
+
trackDial.duration = [trackDuration, 0, duration, CLIP_VALUE_STEP];
|
|
1275
|
+
trackDial.transition = normalizeStoredTransition(trackCurve, trackDuration);
|
|
1276
|
+
}
|
|
1277
|
+
const fromValue = track.from ?? (hasTrackSteps ? void 0 : track.to);
|
|
1278
|
+
if (hasTrackSteps && fromValue === void 0) {
|
|
1279
|
+
console.warn(
|
|
1280
|
+
`[dialkit] Timeline clip "${path}": track "${prop}" has steps but no "from" \u2014 declare its starting value.`
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
if (fromValue !== void 0) {
|
|
1284
|
+
trackDial.from = scalarDial(prop, fromValue, hasTrackSteps ? track.steps[0]?.to : track.to);
|
|
1285
|
+
}
|
|
1286
|
+
if (!hasTrackSteps && track.to !== void 0) {
|
|
1287
|
+
trackDial.to = scalarDial(prop, track.to, fromValue);
|
|
1288
|
+
}
|
|
1289
|
+
let trackStepKeys;
|
|
1290
|
+
if (hasTrackSteps) {
|
|
1291
|
+
trackStepKeys = [];
|
|
1292
|
+
let previous = fromValue;
|
|
1293
|
+
track.steps.forEach((step, stepIndex) => {
|
|
1294
|
+
const stepKey = `step${stepIndex + 1}`;
|
|
1295
|
+
trackStepKeys.push(stepKey);
|
|
1296
|
+
const stepDuration = defaultStepDuration(step, trackCurve);
|
|
1297
|
+
const stepDial = {
|
|
1298
|
+
duration: [stepDuration, 0, duration, CLIP_VALUE_STEP],
|
|
1299
|
+
transition: normalizeStoredTransition(step.transition ?? trackCurve, stepDuration)
|
|
1300
|
+
};
|
|
1301
|
+
if (step.to !== void 0) {
|
|
1302
|
+
stepDial.to = scalarDial(prop, step.to, previous);
|
|
1303
|
+
previous = step.to;
|
|
1304
|
+
}
|
|
1305
|
+
trackDial[stepKey] = stepDial;
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
clipDial[prop] = trackDial;
|
|
1309
|
+
tracks.push({ prop, stepKeys: trackStepKeys });
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
if (clip.from && !hasProps) {
|
|
1313
|
+
clipDial.from = withFromToRanges(
|
|
1314
|
+
clip.from,
|
|
1315
|
+
hasSteps ? definedValues(clip.steps[0]?.to) : clip.to
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
if (!hasSteps && !hasProps && clip.to) {
|
|
1319
|
+
clipDial.to = withFromToRanges(clip.to, clip.from);
|
|
1320
|
+
}
|
|
1321
|
+
let stepKeys;
|
|
1322
|
+
if (hasSteps) {
|
|
1323
|
+
stepKeys = [];
|
|
1324
|
+
let running = clip.from;
|
|
1325
|
+
clip.steps.forEach((step, stepIndex) => {
|
|
1326
|
+
const stepKey = `step${stepIndex + 1}`;
|
|
1327
|
+
stepKeys.push(stepKey);
|
|
1328
|
+
const stepDuration = defaultStepDuration(step, defaultCurve);
|
|
1329
|
+
const stepDial = {
|
|
1330
|
+
duration: [stepDuration, 0, duration, CLIP_VALUE_STEP],
|
|
1331
|
+
transition: normalizeStoredTransition(step.transition ?? defaultCurve, stepDuration)
|
|
1332
|
+
};
|
|
1333
|
+
const stepTo = definedValues(step.to);
|
|
1334
|
+
if (stepTo) {
|
|
1335
|
+
for (const prop of Object.keys(stepTo)) {
|
|
1336
|
+
if (!running || !(prop in running)) {
|
|
1337
|
+
console.warn(
|
|
1338
|
+
`[dialkit] Timeline clip "${path}": property "${prop}" first animates in step ${stepIndex + 1} with no starting value \u2014 declare it in "from".`
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
stepDial.to = withFromToRanges(stepTo, running);
|
|
1343
|
+
}
|
|
1344
|
+
clipDial[stepKey] = stepDial;
|
|
1345
|
+
running = { ...running ?? {}, ...stepTo ?? {} };
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
setDialPath(dialConfig, path, clipDial);
|
|
1349
|
+
clips.push({
|
|
1350
|
+
key: path,
|
|
1351
|
+
label: formatLabel(childKey),
|
|
1352
|
+
color: TIMELINE_CLIP_COLORS[index % TIMELINE_CLIP_COLORS.length],
|
|
1353
|
+
loop: normalizeLoopMode(clip.loop),
|
|
1354
|
+
group,
|
|
1355
|
+
stepKeys,
|
|
1356
|
+
tracks
|
|
1357
|
+
});
|
|
1358
|
+
});
|
|
1359
|
+
return { duration, dialConfig, clips };
|
|
1360
|
+
}
|
|
1361
|
+
var TRACK_RESERVED = /* @__PURE__ */ new Set(["at", "duration", "loop", "from", "to", "transition", "delay"]);
|
|
1362
|
+
function scalarDial(prop, value, counterpart) {
|
|
1363
|
+
const record = withFromToRanges(
|
|
1364
|
+
{ [prop]: value },
|
|
1365
|
+
counterpart === void 0 ? void 0 : { [prop]: counterpart }
|
|
1366
|
+
);
|
|
1367
|
+
return record[prop];
|
|
1368
|
+
}
|
|
1369
|
+
var FROM_TO_RANGE_PRESETS = [
|
|
1370
|
+
[/^(x|y|z|tx|ty|offsetx|offsety|translatex|translatey)$/i, { min: -100, max: 100, step: 1 }],
|
|
1371
|
+
[/rotat|angle|skew/i, { min: -180, max: 180, step: 1 }],
|
|
1372
|
+
[/^scale/i, { min: 0, max: 2, step: 0.01 }],
|
|
1373
|
+
[/opacity|alpha/i, { min: 0, max: 1, step: 0.01 }],
|
|
1374
|
+
[/blur|radius|spread/i, { min: 0, max: 100, step: 1 }]
|
|
1375
|
+
];
|
|
1376
|
+
function inferFromToRange(key, value, counterpart) {
|
|
1377
|
+
const lo = Math.min(value, counterpart ?? value);
|
|
1378
|
+
const hi = Math.max(value, counterpart ?? value);
|
|
1379
|
+
const preset = FROM_TO_RANGE_PRESETS.find(([pattern]) => pattern.test(key))?.[1];
|
|
1380
|
+
if (preset) {
|
|
1381
|
+
return [value, Math.min(preset.min, lo), Math.max(preset.max, hi), preset.step];
|
|
1382
|
+
}
|
|
1383
|
+
if (lo >= 0 && hi <= 1) {
|
|
1384
|
+
return [value, 0, 1, 0.01];
|
|
1385
|
+
}
|
|
1386
|
+
const extent = Math.max(Math.abs(lo), Math.abs(hi), 1);
|
|
1387
|
+
const min = lo < 0 ? -extent * 2 : 0;
|
|
1388
|
+
const max = Math.max(extent * 2, hi);
|
|
1389
|
+
return [value, min, max, inferStep(min, max)];
|
|
1390
|
+
}
|
|
1391
|
+
function withFromToRanges(config, counterpart) {
|
|
1392
|
+
const result = {};
|
|
1393
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1394
|
+
const other = counterpart?.[key];
|
|
1395
|
+
if (typeof value === "number") {
|
|
1396
|
+
result[key] = inferFromToRange(key, value, typeof other === "number" ? other : void 0);
|
|
1397
|
+
} else if (isPlainObject(value) && !("type" in value)) {
|
|
1398
|
+
result[key] = withFromToRanges(
|
|
1399
|
+
value,
|
|
1400
|
+
isPlainObject(other) && !("type" in other) ? other : void 0
|
|
1401
|
+
);
|
|
1402
|
+
} else {
|
|
1403
|
+
result[key] = value;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
return result;
|
|
1407
|
+
}
|
|
1408
|
+
function curveStatic(transition, duration) {
|
|
1409
|
+
if (!transition) return { duration };
|
|
1410
|
+
if (transition.type === "easing") return { duration, ease: transition.ease };
|
|
1411
|
+
const spring = springParams(transition);
|
|
1412
|
+
return { duration, spring, settle: springSettleDuration(spring) };
|
|
1413
|
+
}
|
|
1414
|
+
function sampleCurve(curve, elapsed) {
|
|
1415
|
+
if (elapsed <= 0) return 0;
|
|
1416
|
+
if (curve.spring) {
|
|
1417
|
+
if (curve.settle !== void 0 && elapsed >= curve.settle) return 1;
|
|
1418
|
+
return springProgress(elapsed, curve.spring);
|
|
1419
|
+
}
|
|
1420
|
+
if (curve.ease) {
|
|
1421
|
+
return cubicBezierProgress(clamp(curve.duration > 0 ? elapsed / curve.duration : 1, 0, 1), curve.ease);
|
|
1422
|
+
}
|
|
1423
|
+
return curve.duration > 0 ? Math.min(1, elapsed / curve.duration) : 1;
|
|
1424
|
+
}
|
|
1425
|
+
function resolvedAtPath(resolved, path) {
|
|
1426
|
+
let node = resolved;
|
|
1427
|
+
for (const segment of path.split(".")) {
|
|
1428
|
+
node = isPlainObject(node) ? node[segment] : void 0;
|
|
1429
|
+
}
|
|
1430
|
+
return isPlainObject(node) ? node : {};
|
|
1431
|
+
}
|
|
1432
|
+
function computeStaticClips(parsed, flatValues) {
|
|
1433
|
+
const resolved = resolveDialValues(parsed.dialConfig, flatValues);
|
|
1434
|
+
return parsed.clips.map(
|
|
1435
|
+
(clip) => buildClipStatic(resolvedAtPath(resolved, clip.key), clip, parsed.duration)
|
|
1436
|
+
);
|
|
1437
|
+
}
|
|
1438
|
+
function computeStaticTimeline(parsed, flatValues) {
|
|
1439
|
+
let clips = computeStaticClips(parsed, flatValues);
|
|
1440
|
+
const maxEnd = clips.reduce(
|
|
1441
|
+
(end, clip) => Math.max(end, clip.at + clip.duration),
|
|
1442
|
+
parsed.duration
|
|
1443
|
+
);
|
|
1444
|
+
const duration = maxEnd > parsed.duration ? Math.ceil(maxEnd * 100 - 1e-4) / 100 : parsed.duration;
|
|
1445
|
+
if (duration !== parsed.duration) {
|
|
1446
|
+
clips = clips.map(
|
|
1447
|
+
(clip) => clip.loop === "repeat" ? { ...clip, end: duration } : clip
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
return { duration, clips };
|
|
1451
|
+
}
|
|
1452
|
+
function computeClipStaticFromValues(values, clip, timelineDuration) {
|
|
1453
|
+
return buildClipStatic(unflattenClipValues(values, clip.key), clip, timelineDuration);
|
|
1454
|
+
}
|
|
1455
|
+
function buildClipStatic(clipResolved, clip, timelineDuration) {
|
|
1456
|
+
{
|
|
1457
|
+
const at = typeof clipResolved.at === "number" ? clipResolved.at : 0;
|
|
1458
|
+
const from = isPlainObject(clipResolved.from) ? clipResolved.from : void 0;
|
|
1459
|
+
const single = isTransitionConfig(clipResolved.transition) ? clipResolved.transition : void 0;
|
|
1460
|
+
const staticClip = {
|
|
1461
|
+
key: clip.key,
|
|
1462
|
+
childKey: clip.group ? clip.key.slice(clip.group.length + 1) : clip.key,
|
|
1463
|
+
group: clip.group,
|
|
1464
|
+
at,
|
|
1465
|
+
duration: 0,
|
|
1466
|
+
loop: "off",
|
|
1467
|
+
end: 0,
|
|
1468
|
+
isPhysics: false,
|
|
1469
|
+
from,
|
|
1470
|
+
tracks: [],
|
|
1471
|
+
explicitSteps: Boolean(clip.stepKeys?.length)
|
|
1472
|
+
};
|
|
1473
|
+
if (clip.tracks?.length) {
|
|
1474
|
+
const tracks = clip.tracks.map(({ prop, stepKeys }) => {
|
|
1475
|
+
const trackResolved = isPlainObject(clipResolved[prop]) ? clipResolved[prop] : {};
|
|
1476
|
+
const delay = typeof trackResolved.delay === "number" ? trackResolved.delay : 0;
|
|
1477
|
+
const fromValue = trackResolved.from;
|
|
1478
|
+
let steps;
|
|
1479
|
+
let trackDuration = 0;
|
|
1480
|
+
if (stepKeys?.length) {
|
|
1481
|
+
let running = fromValue;
|
|
1482
|
+
steps = stepKeys.map((stepKey) => {
|
|
1483
|
+
const stepResolved = isPlainObject(trackResolved[stepKey]) ? trackResolved[stepKey] : {};
|
|
1484
|
+
const storedDuration = typeof stepResolved.duration === "number" ? stepResolved.duration : 0;
|
|
1485
|
+
const raw = isTransitionConfig(stepResolved.transition) ? stepResolved.transition : void 0;
|
|
1486
|
+
const effective = raw ? resolveClipTransition(raw, storedDuration) : { transition: void 0, duration: storedDuration, isPhysics: false };
|
|
1487
|
+
const toValue = stepResolved.to;
|
|
1488
|
+
const step = {
|
|
1489
|
+
key: stepKey,
|
|
1490
|
+
offset: trackDuration,
|
|
1491
|
+
duration: effective.duration,
|
|
1492
|
+
isPhysics: effective.isPhysics,
|
|
1493
|
+
start: running === void 0 ? {} : { [prop]: running },
|
|
1494
|
+
to: toValue === void 0 ? {} : { [prop]: toValue },
|
|
1495
|
+
curve: curveStatic(effective.transition, effective.duration)
|
|
1496
|
+
};
|
|
1497
|
+
if (toValue !== void 0) running = toValue;
|
|
1498
|
+
trackDuration += effective.duration;
|
|
1499
|
+
return step;
|
|
1500
|
+
});
|
|
1501
|
+
} else {
|
|
1502
|
+
const storedDuration = typeof trackResolved.duration === "number" ? trackResolved.duration : 0;
|
|
1503
|
+
const raw = isTransitionConfig(trackResolved.transition) ? trackResolved.transition : void 0;
|
|
1504
|
+
const effective = raw ? resolveClipTransition(raw, storedDuration) : { transition: void 0, duration: storedDuration, isPhysics: false };
|
|
1505
|
+
const toValue = trackResolved.to;
|
|
1506
|
+
trackDuration = effective.duration;
|
|
1507
|
+
steps = [
|
|
1508
|
+
{
|
|
1509
|
+
key: null,
|
|
1510
|
+
offset: 0,
|
|
1511
|
+
duration: effective.duration,
|
|
1512
|
+
isPhysics: effective.isPhysics,
|
|
1513
|
+
start: fromValue === void 0 ? {} : { [prop]: fromValue },
|
|
1514
|
+
to: toValue === void 0 ? {} : { [prop]: toValue },
|
|
1515
|
+
curve: curveStatic(effective.transition, effective.duration)
|
|
1516
|
+
}
|
|
1517
|
+
];
|
|
1518
|
+
}
|
|
1519
|
+
return { prop, delay, duration: trackDuration, steps };
|
|
1520
|
+
});
|
|
1521
|
+
staticClip.tracks = tracks;
|
|
1522
|
+
staticClip.props = tracks.map((track) => track.prop);
|
|
1523
|
+
staticClip.duration = tracks.reduce((max, track) => Math.max(max, track.delay + track.duration), 0);
|
|
1524
|
+
staticClip.from = Object.fromEntries(
|
|
1525
|
+
tracks.map((track) => [track.prop, track.steps[0].start[track.prop]])
|
|
1526
|
+
);
|
|
1527
|
+
staticClip.to = Object.fromEntries(
|
|
1528
|
+
tracks.map((track) => {
|
|
1529
|
+
const last = track.steps[track.steps.length - 1];
|
|
1530
|
+
return [track.prop, last.to[track.prop] ?? last.start[track.prop]];
|
|
1531
|
+
})
|
|
1532
|
+
);
|
|
1533
|
+
staticClip.loop = staticClip.duration > 0 ? clip.loop : "off";
|
|
1534
|
+
staticClip.end = staticClip.loop === "off" ? staticClip.at + staticClip.duration : timelineDuration;
|
|
1535
|
+
return staticClip;
|
|
1536
|
+
}
|
|
1537
|
+
if (clip.stepKeys?.length) {
|
|
1538
|
+
let running = { ...from ?? {} };
|
|
1539
|
+
let offset = 0;
|
|
1540
|
+
const steps = clip.stepKeys.map((stepKey) => {
|
|
1541
|
+
const stepResolved = isPlainObject(clipResolved[stepKey]) ? clipResolved[stepKey] : {};
|
|
1542
|
+
const storedDuration = typeof stepResolved.duration === "number" ? stepResolved.duration : 0;
|
|
1543
|
+
const raw = isTransitionConfig(stepResolved.transition) ? stepResolved.transition : void 0;
|
|
1544
|
+
const effective = raw ? resolveClipTransition(raw, storedDuration) : { transition: void 0, duration: storedDuration, isPhysics: false };
|
|
1545
|
+
const to = isPlainObject(stepResolved.to) ? stepResolved.to : {};
|
|
1546
|
+
const step = {
|
|
1547
|
+
key: stepKey,
|
|
1548
|
+
offset,
|
|
1549
|
+
duration: effective.duration,
|
|
1550
|
+
isPhysics: effective.isPhysics,
|
|
1551
|
+
start: running,
|
|
1552
|
+
to,
|
|
1553
|
+
curve: curveStatic(effective.transition, effective.duration)
|
|
1554
|
+
};
|
|
1555
|
+
running = { ...running, ...to };
|
|
1556
|
+
offset += effective.duration;
|
|
1557
|
+
return step;
|
|
1558
|
+
});
|
|
1559
|
+
staticClip.tracks = [{ delay: 0, duration: offset, steps }];
|
|
1560
|
+
staticClip.duration = offset;
|
|
1561
|
+
staticClip.to = running;
|
|
1562
|
+
} else {
|
|
1563
|
+
const storedDuration = typeof clipResolved.duration === "number" ? clipResolved.duration : 0;
|
|
1564
|
+
const to = isPlainObject(clipResolved.to) ? clipResolved.to : void 0;
|
|
1565
|
+
if (single) {
|
|
1566
|
+
const effective = resolveClipTransition(single, storedDuration);
|
|
1567
|
+
staticClip.duration = effective.duration;
|
|
1568
|
+
staticClip.isPhysics = effective.isPhysics;
|
|
1569
|
+
staticClip.transition = effective.transition;
|
|
1570
|
+
staticClip.css = transitionToCss(effective.transition);
|
|
1571
|
+
staticClip.to = to;
|
|
1572
|
+
if (from && to) {
|
|
1573
|
+
staticClip.tracks = [
|
|
1574
|
+
{
|
|
1575
|
+
delay: 0,
|
|
1576
|
+
duration: effective.duration,
|
|
1577
|
+
steps: [
|
|
1578
|
+
{
|
|
1579
|
+
key: null,
|
|
1580
|
+
offset: 0,
|
|
1581
|
+
duration: effective.duration,
|
|
1582
|
+
isPhysics: effective.isPhysics,
|
|
1583
|
+
start: from,
|
|
1584
|
+
to,
|
|
1585
|
+
curve: curveStatic(effective.transition, effective.duration)
|
|
1586
|
+
}
|
|
1587
|
+
]
|
|
1588
|
+
}
|
|
1589
|
+
];
|
|
1590
|
+
}
|
|
1591
|
+
} else {
|
|
1592
|
+
staticClip.duration = storedDuration;
|
|
1593
|
+
staticClip.to = to;
|
|
1594
|
+
if (from && to) {
|
|
1595
|
+
const base = resolveClipTransition(DEFAULT_CLIP_TRANSITION, storedDuration);
|
|
1596
|
+
staticClip.duration = base.duration;
|
|
1597
|
+
staticClip.tracks = [
|
|
1598
|
+
{
|
|
1599
|
+
delay: 0,
|
|
1600
|
+
duration: base.duration,
|
|
1601
|
+
steps: [
|
|
1602
|
+
{
|
|
1603
|
+
key: null,
|
|
1604
|
+
offset: 0,
|
|
1605
|
+
duration: base.duration,
|
|
1606
|
+
isPhysics: false,
|
|
1607
|
+
start: from,
|
|
1608
|
+
to,
|
|
1609
|
+
curve: curveStatic(base.transition, base.duration)
|
|
1610
|
+
}
|
|
1611
|
+
]
|
|
1612
|
+
}
|
|
1613
|
+
];
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
if (staticClip.tracks.length) {
|
|
1618
|
+
const props = new Set(Object.keys(from ?? {}));
|
|
1619
|
+
for (const track of staticClip.tracks) {
|
|
1620
|
+
for (const step of track.steps) {
|
|
1621
|
+
for (const prop of Object.keys(step.to)) props.add(prop);
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
staticClip.props = Array.from(props);
|
|
1625
|
+
}
|
|
1626
|
+
staticClip.loop = staticClip.duration > 0 ? clip.loop : "off";
|
|
1627
|
+
staticClip.end = staticClip.loop === "off" ? staticClip.at + staticClip.duration : timelineDuration;
|
|
1628
|
+
return staticClip;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
function stepAtPosition(steps, pos) {
|
|
1632
|
+
for (const step of steps) {
|
|
1633
|
+
if (pos < step.offset + step.duration) return step;
|
|
1634
|
+
}
|
|
1635
|
+
return steps[steps.length - 1];
|
|
1636
|
+
}
|
|
1637
|
+
function evalPropAtPos(steps, prop, pos) {
|
|
1638
|
+
const step = stepAtPosition(steps, pos);
|
|
1639
|
+
const within = Math.max(0, pos - step.offset);
|
|
1640
|
+
if (prop in step.to) {
|
|
1641
|
+
const eased = sampleCurve(step.curve, within);
|
|
1642
|
+
return interpolateResolved(step.start[prop], step.to[prop], eased);
|
|
1643
|
+
}
|
|
1644
|
+
return step.start[prop];
|
|
1645
|
+
}
|
|
1646
|
+
function computeClipState(clip, time, cycleTime = time) {
|
|
1647
|
+
const total = clip.duration;
|
|
1648
|
+
const looping = clip.loop === "repeat" && total > 0;
|
|
1649
|
+
const started = time >= clip.at || looping && cycleTime > time;
|
|
1650
|
+
const done = time >= clip.end;
|
|
1651
|
+
const elapsed = time - clip.at;
|
|
1652
|
+
const phaseElapsed = looping ? cycleTime - clip.at : elapsed;
|
|
1653
|
+
const fold = (e) => looping ? e % total : e;
|
|
1654
|
+
const basePos = started ? fold(Math.max(0, phaseElapsed)) : 0;
|
|
1655
|
+
const progress = total > 0 ? clamp(basePos / total, 0, 1) : started ? 1 : 0;
|
|
1656
|
+
let current;
|
|
1657
|
+
let stepIndex = 0;
|
|
1658
|
+
if (clip.tracks.length && clip.props?.length) {
|
|
1659
|
+
current = {};
|
|
1660
|
+
for (const track of clip.tracks) {
|
|
1661
|
+
const props = track.prop !== void 0 ? [track.prop] : clip.props;
|
|
1662
|
+
for (const prop of props) {
|
|
1663
|
+
const startValue = track.steps[0]?.start[prop];
|
|
1664
|
+
if (!started) {
|
|
1665
|
+
if (startValue !== void 0) current[prop] = startValue;
|
|
1666
|
+
continue;
|
|
1667
|
+
}
|
|
1668
|
+
const phase = phaseElapsed - track.delay;
|
|
1669
|
+
if (phase <= 0) {
|
|
1670
|
+
if (startValue !== void 0) current[prop] = startValue;
|
|
1671
|
+
continue;
|
|
1672
|
+
}
|
|
1673
|
+
const pos = looping && track.duration > 0 ? phase % track.duration : phase;
|
|
1674
|
+
const value = evalPropAtPos(track.steps, prop, pos);
|
|
1675
|
+
if (value !== void 0) current[prop] = value;
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
const shared = clip.tracks[0];
|
|
1679
|
+
if (started && clip.explicitSteps && shared.prop === void 0) {
|
|
1680
|
+
stepIndex = shared.steps.indexOf(stepAtPosition(shared.steps, basePos));
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
return {
|
|
1684
|
+
at: clip.at,
|
|
1685
|
+
duration: clip.duration,
|
|
1686
|
+
loop: clip.loop,
|
|
1687
|
+
started,
|
|
1688
|
+
active: started && !done,
|
|
1689
|
+
done,
|
|
1690
|
+
progress,
|
|
1691
|
+
step: clip.explicitSteps ? stepIndex : void 0,
|
|
1692
|
+
from: clip.from,
|
|
1693
|
+
to: clip.to,
|
|
1694
|
+
animate: started ? clip.to : clip.from,
|
|
1695
|
+
transition: clip.transition,
|
|
1696
|
+
css: clip.css,
|
|
1697
|
+
current
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
function interpolateResolved(from, to, p) {
|
|
1701
|
+
if (typeof from === "number" && typeof to === "number") {
|
|
1702
|
+
return from + (to - from) * p;
|
|
1703
|
+
}
|
|
1704
|
+
if (typeof from === "string" && typeof to === "string") {
|
|
1705
|
+
const mixed = mixHexColors(from, to, p);
|
|
1706
|
+
if (mixed) return mixed;
|
|
1707
|
+
}
|
|
1708
|
+
if (isPlainObject(from) && isPlainObject(to)) {
|
|
1709
|
+
const result = {};
|
|
1710
|
+
for (const key of Object.keys(from)) {
|
|
1711
|
+
result[key] = key in to ? interpolateResolved(from[key], to[key], p) : from[key];
|
|
1712
|
+
}
|
|
1713
|
+
for (const key of Object.keys(to)) {
|
|
1714
|
+
if (!(key in from)) result[key] = to[key];
|
|
1715
|
+
}
|
|
1716
|
+
return result;
|
|
1717
|
+
}
|
|
1718
|
+
return p < 0.5 ? from : to;
|
|
1719
|
+
}
|
|
1720
|
+
function parseHex(hex) {
|
|
1721
|
+
if (!isHexColor(hex)) return null;
|
|
1722
|
+
let h22 = hex.slice(1);
|
|
1723
|
+
if (h22.length === 3) h22 = h22.split("").map((c) => c + c).join("");
|
|
1724
|
+
return [
|
|
1725
|
+
parseInt(h22.slice(0, 2), 16),
|
|
1726
|
+
parseInt(h22.slice(2, 4), 16),
|
|
1727
|
+
parseInt(h22.slice(4, 6), 16),
|
|
1728
|
+
h22.length === 8 ? parseInt(h22.slice(6, 8), 16) : 255
|
|
1729
|
+
];
|
|
1730
|
+
}
|
|
1731
|
+
function mixHexColors(a, b, p) {
|
|
1732
|
+
const ca = parseHex(a);
|
|
1733
|
+
const cb = parseHex(b);
|
|
1734
|
+
if (!ca || !cb) return null;
|
|
1735
|
+
const t = clamp(p, 0, 1);
|
|
1736
|
+
const mixed = ca.map((v, i) => Math.round(v + (cb[i] - v) * t));
|
|
1737
|
+
const hex = (n) => n.toString(16).padStart(2, "0");
|
|
1738
|
+
const rgb = `#${hex(mixed[0])}${hex(mixed[1])}${hex(mixed[2])}`;
|
|
1739
|
+
return mixed[3] === 255 ? rgb : `${rgb}${hex(mixed[3])}`;
|
|
1740
|
+
}
|
|
1741
|
+
function transitionToCss(transition) {
|
|
1742
|
+
if (!transition) return void 0;
|
|
1743
|
+
if (transition.type === "easing") {
|
|
1744
|
+
return {
|
|
1745
|
+
transitionDuration: `${round2(transition.duration)}s`,
|
|
1746
|
+
transitionTimingFunction: `cubic-bezier(${transition.ease.map((v) => round2(v)).join(", ")})`
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
const params = springParams(transition);
|
|
1750
|
+
const dampingRatio = params.damping / (2 * Math.sqrt(params.stiffness * params.mass));
|
|
1751
|
+
const duration = transition.visualDuration ?? springSettleDuration(params);
|
|
1752
|
+
const bounce = transition.bounce ?? Math.max(0, round2(1 - dampingRatio));
|
|
1753
|
+
return {
|
|
1754
|
+
transitionDuration: `${round2(duration)}s`,
|
|
1755
|
+
transitionTimingFunction: bounce > 0.05 ? `cubic-bezier(0.34, ${round2(1.2 + bounce)}, 0.64, 1)` : "cubic-bezier(0.25, 0.6, 0.35, 1)"
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
function timelinePopoverDisplayValues(values, clipKey, stepKeys, stepKey) {
|
|
1759
|
+
const display = { ...values };
|
|
1760
|
+
const swap = (path, duration) => {
|
|
1761
|
+
const raw = display[path];
|
|
1762
|
+
if (isTransitionConfig(raw)) display[path] = resolveClipTransition(raw, duration).transition;
|
|
1763
|
+
};
|
|
1764
|
+
if (stepKey) {
|
|
1765
|
+
swap(`${clipKey}.${stepKey}.transition`, numberValue(values[`${clipKey}.${stepKey}.duration`]));
|
|
1766
|
+
return display;
|
|
1767
|
+
}
|
|
1768
|
+
const cycle = stepKeys?.length ? stepKeys.reduce((sum, sk) => sum + numberValue(values[`${clipKey}.${sk}.duration`]), 0) : numberValue(values[`${clipKey}.duration`]);
|
|
1769
|
+
swap(`${clipKey}.transition`, cycle);
|
|
1770
|
+
return display;
|
|
1771
|
+
}
|
|
1772
|
+
function numberValue(value) {
|
|
1773
|
+
return typeof value === "number" ? value : 0;
|
|
1774
|
+
}
|
|
1775
|
+
function unflattenClipValues(values, clipKey) {
|
|
1776
|
+
const prefix = `${clipKey}.`;
|
|
1777
|
+
const result = {};
|
|
1778
|
+
const entries = Object.entries(values).filter(([path]) => path.startsWith(prefix)).map(([path, value]) => ({ segments: path.slice(prefix.length).split("."), value })).sort((a, b) => a.segments.length - b.segments.length);
|
|
1779
|
+
for (const { segments, value } of entries) {
|
|
1780
|
+
let node = result;
|
|
1781
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1782
|
+
const existing = node[segments[i]];
|
|
1783
|
+
node = isPlainObject(existing) ? existing : node[segments[i]] = {};
|
|
1784
|
+
}
|
|
1785
|
+
node[segments[segments.length - 1]] = cloneTimelineValue(value);
|
|
1786
|
+
}
|
|
1787
|
+
return result;
|
|
1788
|
+
}
|
|
1789
|
+
function cloneTimelineValue(value) {
|
|
1790
|
+
if (Array.isArray(value)) return value.map(cloneTimelineValue);
|
|
1791
|
+
if (!isPlainObject(value)) return value;
|
|
1792
|
+
return Object.fromEntries(
|
|
1793
|
+
Object.entries(value).map(([key, nested]) => [key, cloneTimelineValue(nested)])
|
|
1794
|
+
);
|
|
1795
|
+
}
|
|
1796
|
+
function clampTrackDelay(delay, at, trackDuration, timelineDuration) {
|
|
1797
|
+
return clamp(round2(delay), 0, Math.max(0, round2(timelineDuration - at - trackDuration)));
|
|
1798
|
+
}
|
|
1799
|
+
function clampClipMove(at, duration, timelineDuration) {
|
|
1800
|
+
return clamp(round2(at), 0, Math.max(0, timelineDuration - duration));
|
|
1801
|
+
}
|
|
1802
|
+
function clampClipResizeEnd(duration, at, timelineDuration) {
|
|
1803
|
+
return clamp(round2(duration), TIMELINE_MIN_CLIP_DURATION, timelineDuration - at);
|
|
1804
|
+
}
|
|
1805
|
+
function clampClipResizeStart(newAt, at, duration) {
|
|
1806
|
+
const clampedAt = clamp(round2(newAt), 0, at + duration - TIMELINE_MIN_CLIP_DURATION);
|
|
1807
|
+
return { at: clampedAt, duration: round2(at + duration - clampedAt) };
|
|
1808
|
+
}
|
|
1809
|
+
function clampStepResize(duration, at, otherStepsTotal, timelineDuration) {
|
|
1810
|
+
const max = Math.max(TIMELINE_MIN_CLIP_DURATION, timelineDuration - at - otherStepsTotal);
|
|
1811
|
+
return clamp(round2(duration), TIMELINE_MIN_CLIP_DURATION, max);
|
|
1812
|
+
}
|
|
1813
|
+
function normalizeTimelineValuesForCopy(values, clips) {
|
|
1814
|
+
const normalized = { ...values };
|
|
1815
|
+
for (const path of Object.keys(normalized)) {
|
|
1816
|
+
if (path.endsWith(".__mode")) delete normalized[path];
|
|
1817
|
+
}
|
|
1818
|
+
const normalizeTransitionAt = (transitionPath, durationPath) => {
|
|
1819
|
+
const raw = normalized[transitionPath];
|
|
1820
|
+
if (!isTransitionConfig(raw)) return;
|
|
1821
|
+
if (isPhysicsSpring(raw)) {
|
|
1822
|
+
normalized[durationPath] = transitionDefaultDuration(raw);
|
|
1823
|
+
}
|
|
1824
|
+
normalized[transitionPath] = normalizeStoredTransition(
|
|
1825
|
+
raw,
|
|
1826
|
+
numberValue(normalized[durationPath])
|
|
1827
|
+
);
|
|
1828
|
+
};
|
|
1829
|
+
for (const clip of clips) {
|
|
1830
|
+
for (const stepKey of clip.stepKeys ?? []) {
|
|
1831
|
+
normalizeTransitionAt(
|
|
1832
|
+
`${clip.key}.${stepKey}.transition`,
|
|
1833
|
+
`${clip.key}.${stepKey}.duration`
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
normalizeTransitionAt(`${clip.key}.transition`, `${clip.key}.duration`);
|
|
1837
|
+
for (const track of clip.tracks ?? []) {
|
|
1838
|
+
const trackKey = `${clip.key}.${track.prop}`;
|
|
1839
|
+
for (const stepKey of track.stepKeys ?? []) {
|
|
1840
|
+
normalizeTransitionAt(
|
|
1841
|
+
`${trackKey}.${stepKey}.transition`,
|
|
1842
|
+
`${trackKey}.${stepKey}.duration`
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
normalizeTransitionAt(`${trackKey}.transition`, `${trackKey}.duration`);
|
|
1846
|
+
if (normalized[`${trackKey}.delay`] === 0) {
|
|
1847
|
+
delete normalized[`${trackKey}.delay`];
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
delete normalized[`${clip.key}.loop`];
|
|
1851
|
+
}
|
|
1852
|
+
return normalized;
|
|
1853
|
+
}
|
|
1854
|
+
function formatClock(time, tenths = false) {
|
|
1855
|
+
const safe = Math.max(0, time);
|
|
1856
|
+
const minutes = Math.floor(safe / 60);
|
|
1857
|
+
const seconds = safe - minutes * 60;
|
|
1858
|
+
const secondsText = tenths ? seconds.toFixed(1).padStart(4, "0") : String(Math.floor(seconds)).padStart(2, "0");
|
|
1859
|
+
return `${String(minutes).padStart(2, "0")}:${secondsText}`;
|
|
1860
|
+
}
|
|
1861
|
+
function formatSeconds(value) {
|
|
1862
|
+
return `${round2(value)}s`;
|
|
1863
|
+
}
|
|
1864
|
+
function formatStepLabel(stepKey) {
|
|
1865
|
+
const match = /^step(\d+)$/.exec(stepKey);
|
|
1866
|
+
return match ? `Step ${match[1]}` : formatLabel(stepKey);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// src/timeline/adapter.ts
|
|
1870
|
+
function resolveTimelineLoop(loop) {
|
|
1871
|
+
if (typeof loop === "object" && loop !== null) {
|
|
1872
|
+
return {
|
|
1873
|
+
enabled: true,
|
|
1874
|
+
start: Number.isFinite(loop.from) ? Math.max(0, loop.from) : 0
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
return { enabled: Boolean(loop), start: 0 };
|
|
1878
|
+
}
|
|
1879
|
+
function buildTimelineMeta(id, name, duration, parsed, loop) {
|
|
1880
|
+
const resolvedLoop = resolveTimelineLoop(loop);
|
|
1881
|
+
return {
|
|
1882
|
+
id,
|
|
1883
|
+
name,
|
|
1884
|
+
duration,
|
|
1885
|
+
loop: resolvedLoop.enabled,
|
|
1886
|
+
loopStart: resolvedLoop.start,
|
|
1887
|
+
clips: parsed.clips
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
function buildTimelineValues(staticClips, transport, timelineDuration, loopStart, actions) {
|
|
1891
|
+
var _a;
|
|
1892
|
+
const result = {
|
|
1893
|
+
time: transport.time,
|
|
1894
|
+
playing: transport.playing,
|
|
1895
|
+
duration: timelineDuration,
|
|
1896
|
+
...actions
|
|
1897
|
+
};
|
|
1898
|
+
const span = loopSpan(transport.duration, loopStart);
|
|
1899
|
+
const cycleTime = (span > 0 ? transport.wraps * span : 0) + transport.time;
|
|
1900
|
+
for (const clip of staticClips) {
|
|
1901
|
+
const state = computeClipState(clip, transport.time, cycleTime);
|
|
1902
|
+
if (clip.group) {
|
|
1903
|
+
const bucket = result[_a = clip.group] ?? (result[_a] = {});
|
|
1904
|
+
bucket[clip.childKey] = state;
|
|
1905
|
+
} else {
|
|
1906
|
+
result[clip.key] = state;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
return result;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
// src/store/TimelineUiStore.ts
|
|
1913
|
+
var TimelineUiStoreClass = class {
|
|
1914
|
+
constructor() {
|
|
1915
|
+
this.visible = true;
|
|
1916
|
+
this.initialized = false;
|
|
1917
|
+
this.controllers = /* @__PURE__ */ new Map();
|
|
1918
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
1919
|
+
}
|
|
1920
|
+
getVisible() {
|
|
1921
|
+
for (const controller of this.controllers.values()) {
|
|
1922
|
+
if (controller.visible !== void 0) return controller.visible;
|
|
1923
|
+
}
|
|
1924
|
+
return this.visible;
|
|
1925
|
+
}
|
|
1926
|
+
registerController(id, controller) {
|
|
1927
|
+
const previous = this.getVisible();
|
|
1928
|
+
if (!this.initialized) {
|
|
1929
|
+
this.visible = controller.defaultVisible;
|
|
1930
|
+
this.initialized = true;
|
|
1931
|
+
}
|
|
1932
|
+
this.controllers.set(id, controller);
|
|
1933
|
+
if (previous !== this.getVisible()) this.notify();
|
|
1934
|
+
return () => {
|
|
1935
|
+
const before = this.getVisible();
|
|
1936
|
+
this.controllers.delete(id);
|
|
1937
|
+
if (this.controllers.size === 0) this.initialized = false;
|
|
1938
|
+
if (before !== this.getVisible()) this.notify();
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
updateController(id, controller) {
|
|
1942
|
+
if (!this.controllers.has(id)) return;
|
|
1943
|
+
const previous = this.getVisible();
|
|
1944
|
+
this.controllers.set(id, controller);
|
|
1945
|
+
if (previous !== this.getVisible()) this.notify();
|
|
1946
|
+
}
|
|
1947
|
+
requestVisible(visible) {
|
|
1948
|
+
const current = this.getVisible();
|
|
1949
|
+
if (current === visible) return;
|
|
1950
|
+
const controlled = Array.from(this.controllers.values()).filter(
|
|
1951
|
+
(controller) => controller.visible !== void 0
|
|
1952
|
+
);
|
|
1953
|
+
if (controlled.length > 0) {
|
|
1954
|
+
controlled.forEach((controller) => controller.onVisibilityChange?.(visible));
|
|
1955
|
+
return;
|
|
1956
|
+
}
|
|
1957
|
+
this.visible = visible;
|
|
1958
|
+
this.controllers.forEach((controller) => controller.onVisibilityChange?.(visible));
|
|
1959
|
+
this.notify();
|
|
1960
|
+
}
|
|
1961
|
+
toggle() {
|
|
1962
|
+
this.requestVisible(!this.getVisible());
|
|
1963
|
+
}
|
|
1964
|
+
subscribe(listener) {
|
|
1965
|
+
this.listeners.add(listener);
|
|
1966
|
+
return () => this.listeners.delete(listener);
|
|
1967
|
+
}
|
|
1968
|
+
notify() {
|
|
1969
|
+
this.listeners.forEach((listener) => listener());
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
var TimelineUiStore = /* @__PURE__ */ new TimelineUiStoreClass();
|
|
1973
|
+
|
|
1974
|
+
// src/copy-instruction.ts
|
|
1975
|
+
function buildCopyInstruction(hookName, panelName, values) {
|
|
1976
|
+
const jsonStr = JSON.stringify(values, null, 2);
|
|
1977
|
+
if (hookName === "useDialTimeline" || hookName === "createDialTimeline") {
|
|
1978
|
+
return `Update the ${hookName} configuration for "${panelName}" with these values:
|
|
1979
|
+
|
|
1980
|
+
\`\`\`json
|
|
1981
|
+
${jsonStr}
|
|
1982
|
+
\`\`\`
|
|
1983
|
+
|
|
1984
|
+
Apply these values as the new defaults in the ${hookName} call. Keep the existing \`clip.current\` bindings while this timeline is being authored; do not convert the animation or remove DialKit yet.
|
|
1985
|
+
|
|
1986
|
+
Add this comment immediately above the ${hookName} call as a production handoff note:
|
|
1987
|
+
|
|
1988
|
+
\`\`\`tsx
|
|
1989
|
+
// TODO(production): DialKit's clip.current values are the scrubbable authoring preview.
|
|
1990
|
+
// Replace them with equivalent real Motion animations using the tuned timeline
|
|
1991
|
+
// timings and transitions, then remove ${hookName} and <DialTimeline />.
|
|
1992
|
+
\`\`\``;
|
|
1993
|
+
}
|
|
1994
|
+
return `Update the ${hookName} configuration for "${panelName}" with these values:
|
|
1995
|
+
|
|
1996
|
+
\`\`\`json
|
|
1997
|
+
${jsonStr}
|
|
1998
|
+
\`\`\`
|
|
1999
|
+
|
|
2000
|
+
Apply these values as the new defaults in the ${hookName} call.`;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
// src/env.ts
|
|
2004
|
+
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;
|
|
2005
|
+
|
|
2006
|
+
// src/vue/useDialTimeline.ts
|
|
2007
|
+
var timelineInstance = 0;
|
|
2008
|
+
function useDialTimeline(name, config, options) {
|
|
2009
|
+
const hasStableId = options?.id !== void 0;
|
|
2010
|
+
const panelId = options?.id ?? `${name}-${++timelineInstance}`;
|
|
2011
|
+
const serializedConfig = computed2(() => JSON.stringify(config));
|
|
2012
|
+
const serializedPersist = computed2(() => JSON.stringify(options?.persist));
|
|
2013
|
+
const serializedLoop = computed2(() => JSON.stringify(options?.loop));
|
|
2014
|
+
const parsed = computed2(() => {
|
|
2015
|
+
serializedConfig.value;
|
|
2016
|
+
return parseTimelineConfig(config);
|
|
2017
|
+
});
|
|
2018
|
+
const flatValues = shallowRef2(DialStore.getValues(panelId));
|
|
2019
|
+
const transport = shallowRef2(TimelineStore.getTransport(panelId));
|
|
2020
|
+
const staticTimeline = computed2(() => computeStaticTimeline(parsed.value, flatValues.value));
|
|
2021
|
+
const meta = computed2(() => {
|
|
2022
|
+
serializedLoop.value;
|
|
2023
|
+
return buildTimelineMeta(
|
|
2024
|
+
panelId,
|
|
2025
|
+
name,
|
|
2026
|
+
staticTimeline.value.duration,
|
|
2027
|
+
parsed.value,
|
|
2028
|
+
options?.loop
|
|
2029
|
+
);
|
|
2030
|
+
});
|
|
2031
|
+
let mounted = false;
|
|
2032
|
+
let unsubscribeValues;
|
|
2033
|
+
let unsubscribeTransport;
|
|
2034
|
+
const play = () => TimelineStore.play(panelId);
|
|
2035
|
+
const pause = () => TimelineStore.pause(panelId);
|
|
2036
|
+
const replay = () => TimelineStore.replay(panelId);
|
|
2037
|
+
const seek = (time) => TimelineStore.seek(panelId, time);
|
|
2038
|
+
watch2([serializedConfig, serializedPersist], () => {
|
|
2039
|
+
if (!mounted) return;
|
|
2040
|
+
DialStore.updatePanel(panelId, name, parsed.value.dialConfig, void 0, {
|
|
2041
|
+
retainOnUnmount: hasStableId,
|
|
2042
|
+
persist: options?.persist,
|
|
2043
|
+
kind: "timeline"
|
|
2044
|
+
});
|
|
2045
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
2046
|
+
});
|
|
2047
|
+
watch2(meta, (nextMeta) => {
|
|
2048
|
+
if (mounted) TimelineStore.update(nextMeta);
|
|
2049
|
+
});
|
|
2050
|
+
onMounted2(() => {
|
|
2051
|
+
unsubscribeValues = DialStore.subscribe(panelId, () => {
|
|
2052
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
2053
|
+
});
|
|
2054
|
+
unsubscribeTransport = TimelineStore.subscribe(panelId, () => {
|
|
2055
|
+
transport.value = TimelineStore.getTransport(panelId);
|
|
2056
|
+
});
|
|
2057
|
+
DialStore.registerPanel(panelId, name, parsed.value.dialConfig, void 0, {
|
|
2058
|
+
retainOnUnmount: hasStableId,
|
|
2059
|
+
persist: options?.persist,
|
|
2060
|
+
kind: "timeline"
|
|
2061
|
+
});
|
|
2062
|
+
flatValues.value = DialStore.getValues(panelId);
|
|
2063
|
+
TimelineStore.register(meta.value, { autoplay: options?.autoplay ?? true });
|
|
2064
|
+
transport.value = TimelineStore.getTransport(panelId);
|
|
2065
|
+
mounted = true;
|
|
2066
|
+
});
|
|
2067
|
+
onUnmounted2(() => {
|
|
2068
|
+
mounted = false;
|
|
2069
|
+
unsubscribeValues?.();
|
|
2070
|
+
unsubscribeTransport?.();
|
|
2071
|
+
TimelineStore.unregister(panelId);
|
|
2072
|
+
DialStore.unregisterPanel(panelId);
|
|
2073
|
+
});
|
|
2074
|
+
return computed2(() => {
|
|
2075
|
+
const currentStatic = staticTimeline.value;
|
|
2076
|
+
return buildTimelineValues(
|
|
2077
|
+
currentStatic.clips,
|
|
2078
|
+
transport.value,
|
|
2079
|
+
currentStatic.duration,
|
|
2080
|
+
resolveTimelineLoop(options?.loop).start,
|
|
2081
|
+
{ play, pause, replay, seek }
|
|
2082
|
+
);
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
// src/vue/directives/dialkit.ts
|
|
2087
|
+
import {
|
|
2088
|
+
createApp,
|
|
2089
|
+
defineComponent as defineComponent17,
|
|
2090
|
+
h as h17,
|
|
2091
|
+
shallowRef as shallowRef3
|
|
2092
|
+
} from "vue";
|
|
2093
|
+
|
|
2094
|
+
// src/vue/components/DialRoot.ts
|
|
2095
|
+
import { computed as computed6, defineComponent as defineComponent16, h as h16, nextTick as nextTick3, onMounted as onMounted12, onUnmounted as onUnmounted11, ref as ref14, Teleport as Teleport3 } from "vue";
|
|
2096
|
+
|
|
2097
|
+
// src/vue/components/Folder.ts
|
|
2098
|
+
import { defineComponent, h, onMounted as onMounted3, onUnmounted as onUnmounted3, ref as ref2 } from "vue";
|
|
2099
|
+
import { AnimatePresence, motion } from "motion-v";
|
|
2100
|
+
|
|
2101
|
+
// src/icons.ts
|
|
2102
|
+
var ICON_CHEVRON = "M6 9.5L12 15.5L18 9.5";
|
|
2103
|
+
var ICON_CHECK = "M5 12.75L10 19L19 5";
|
|
2104
|
+
var ICON_PAUSE = [
|
|
2105
|
+
"M6.75 3C5.23122 3 4 4.23122 4 5.75V18.25C4 19.7688 5.23122 21 6.75 21H7.25C8.76878 21 10 19.7688 10 18.25V5.75C10 4.23122 8.76878 3 7.25 3H6.75Z",
|
|
2106
|
+
"M16.75 3C15.2312 3 14 4.23122 14 5.75V18.25C14 19.7688 15.2312 21 16.75 21H17.25C18.7688 21 20 19.7688 20 18.25V5.75C20 4.23122 18.7688 3 17.25 3H16.75Z"
|
|
2107
|
+
];
|
|
2108
|
+
var ICON_PLAY = "M9.24394 2.36758C7.41419 1.18362 5 2.49701 5 4.67639V19.3238C5 21.5032 7.41419 22.8166 9.24394 21.6326L20.5624 14.3089C22.2371 13.2253 22.2372 10.775 20.5624 9.69129L9.24394 2.36758Z";
|
|
2109
|
+
var ICON_TIMELINE = [
|
|
2110
|
+
"M18.868 10C20.8517 10.0003 22.2886 11.8914 21.7577 13.8027L20.369 18.8027C20.0083 20.1012 18.826 20.9999 17.4784 21H6.51941C5.17179 21 3.98948 20.1012 3.62878 18.8027L2.24011 13.8027C1.7092 11.8913 3.14603 10.0003 5.12976 10H18.868Z",
|
|
2111
|
+
"M18.9989 6.5C19.5511 6.50007 19.9989 6.94776 19.9989 7.5C19.9989 8.05224 19.5511 8.49993 18.9989 8.5H4.9989C4.44661 8.5 3.9989 8.05228 3.9989 7.5C3.9989 6.94772 4.44661 6.5 4.9989 6.5H18.9989Z",
|
|
2112
|
+
"M16.9989 3C17.5511 3.00007 17.9989 3.44776 17.9989 4C17.9989 4.55224 17.5511 4.99993 16.9989 5H6.9989C6.44661 5 5.9989 4.55228 5.9989 4C5.9989 3.44772 6.44661 3 6.9989 3H16.9989Z"
|
|
2113
|
+
];
|
|
2114
|
+
var ICON_CLIPBOARD = {
|
|
2115
|
+
board: "M8 6C8 4.34315 9.34315 3 11 3H13C14.6569 3 16 4.34315 16 6V7H8V6Z",
|
|
2116
|
+
sparkle: "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",
|
|
2117
|
+
body: "M16 5H17C18.6569 5 20 6.34315 20 8V11M8 5H7C5.34315 5 4 6.34315 4 8V18C4 19.6569 5.34315 21 7 21H12"
|
|
2118
|
+
};
|
|
2119
|
+
var ICON_ADD_PRESET = [
|
|
2120
|
+
"M4 6H20",
|
|
2121
|
+
"M4 12H10",
|
|
2122
|
+
"M15 15L21 15",
|
|
2123
|
+
"M18 12V18",
|
|
2124
|
+
"M4 18H10"
|
|
2125
|
+
];
|
|
2126
|
+
var ICON_TRASH = [
|
|
2127
|
+
"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",
|
|
2128
|
+
"M10 11V16",
|
|
2129
|
+
"M14 11V16",
|
|
2130
|
+
"M3.5 6H20.5",
|
|
2131
|
+
"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"
|
|
2132
|
+
];
|
|
2133
|
+
var ICON_PANEL = {
|
|
2134
|
+
path: "M6.84766 11.75C6.78583 11.9899 6.75 12.2408 6.75 12.5C6.75 12.7592 6.78583 13.0101 6.84766 13.25H2C1.58579 13.25 1.25 12.9142 1.25 12.5C1.25 12.0858 1.58579 11.75 2 11.75H6.84766ZM14 11.75C14.4142 11.75 14.75 12.0858 14.75 12.5C14.75 12.9142 14.4142 13.25 14 13.25H12.6523C12.7142 13.0101 12.75 12.7592 12.75 12.5C12.75 12.2408 12.7142 11.9899 12.6523 11.75H14ZM3.09766 7.25C3.03583 7.48994 3 7.74075 3 8C3 8.25925 3.03583 8.51006 3.09766 8.75H2C1.58579 8.75 1.25 8.41421 1.25 8C1.25 7.58579 1.58579 7.25 2 7.25H3.09766ZM14 7.25C14.4142 7.25 14.75 7.58579 14.75 8C14.75 8.41421 14.4142 8.75 14 8.75H8.90234C8.96417 8.51006 9 8.25925 9 8C9 7.74075 8.96417 7.48994 8.90234 7.25H14ZM7.59766 2.75C7.53583 2.98994 7.5 3.24075 7.5 3.5C7.5 3.75925 7.53583 4.01006 7.59766 4.25H2C1.58579 4.25 1.25 3.91421 1.25 3.5C1.25 3.08579 1.58579 2.75 2 2.75H7.59766ZM14 2.75C14.4142 2.75 14.75 3.08579 14.75 3.5C14.75 3.91421 14.4142 4.25 14 4.25H13.4023C13.4642 4.01006 13.5 3.75925 13.5 3.5C13.5 3.24075 13.4642 2.98994 13.4023 2.75H14Z",
|
|
2135
|
+
circles: [
|
|
2136
|
+
{ cx: "6", cy: "8", r: "0.998596" },
|
|
2137
|
+
{ cx: "10.4999", cy: "3.5", r: "0.998657" },
|
|
2138
|
+
{ cx: "9.75015", cy: "12.5", r: "0.997986" }
|
|
2139
|
+
]
|
|
2140
|
+
};
|
|
2141
|
+
|
|
2142
|
+
// src/vue/components/Folder.ts
|
|
2143
|
+
var Folder = defineComponent({
|
|
2144
|
+
name: "DialKitFolder",
|
|
2145
|
+
props: {
|
|
2146
|
+
title: { type: String, required: true },
|
|
2147
|
+
defaultOpen: { type: Boolean, default: true },
|
|
2148
|
+
isRoot: { type: Boolean, default: false },
|
|
2149
|
+
inline: { type: Boolean, default: false },
|
|
2150
|
+
toolbar: {
|
|
2151
|
+
type: null,
|
|
2152
|
+
required: false,
|
|
2153
|
+
default: null
|
|
2154
|
+
},
|
|
2155
|
+
panelHeightOffset: {
|
|
2156
|
+
type: Number,
|
|
2157
|
+
default: 10
|
|
2158
|
+
}
|
|
2159
|
+
},
|
|
2160
|
+
emits: ["openChange"],
|
|
2161
|
+
setup(props, { emit, slots }) {
|
|
2162
|
+
const isOpen = ref2(props.defaultOpen);
|
|
2163
|
+
const isCollapsed = ref2(!props.defaultOpen);
|
|
2164
|
+
const contentRef = ref2(null);
|
|
2165
|
+
const contentHeight = ref2(void 0);
|
|
2166
|
+
const windowHeight = ref2(typeof window !== "undefined" ? window.innerHeight : 800);
|
|
2167
|
+
let resizeHandler = null;
|
|
2168
|
+
if (props.isRoot) {
|
|
2169
|
+
resizeHandler = () => {
|
|
2170
|
+
windowHeight.value = window.innerHeight;
|
|
2171
|
+
};
|
|
2172
|
+
window.addEventListener("resize", resizeHandler);
|
|
2173
|
+
}
|
|
2174
|
+
onUnmounted3(() => {
|
|
2175
|
+
if (resizeHandler) window.removeEventListener("resize", resizeHandler);
|
|
2176
|
+
});
|
|
2177
|
+
const handleToggle = () => {
|
|
2178
|
+
if (props.inline && props.isRoot) return;
|
|
2179
|
+
const next = !isOpen.value;
|
|
2180
|
+
isOpen.value = next;
|
|
2181
|
+
isCollapsed.value = !next;
|
|
2182
|
+
emit("openChange", next);
|
|
2183
|
+
};
|
|
2184
|
+
let ro = null;
|
|
2185
|
+
onMounted3(() => {
|
|
2186
|
+
if (!props.isRoot || typeof ResizeObserver === "undefined") return;
|
|
2187
|
+
const el = contentRef.value;
|
|
2188
|
+
if (!el) return;
|
|
2189
|
+
ro = new ResizeObserver(() => {
|
|
2190
|
+
if (isOpen.value) {
|
|
2191
|
+
const next = el.offsetHeight;
|
|
2192
|
+
if (contentHeight.value !== next) {
|
|
2193
|
+
contentHeight.value = next;
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
ro.observe(el);
|
|
2198
|
+
if (isOpen.value) {
|
|
2199
|
+
contentHeight.value = el.offsetHeight;
|
|
2200
|
+
}
|
|
2201
|
+
});
|
|
2202
|
+
onUnmounted3(() => {
|
|
2203
|
+
ro?.disconnect();
|
|
2204
|
+
});
|
|
2205
|
+
const renderHeader = () => h("div", {
|
|
2206
|
+
class: `dialkit-folder-header ${props.isRoot ? "dialkit-panel-header" : ""}`,
|
|
2207
|
+
onClick: handleToggle
|
|
2208
|
+
}, [
|
|
2209
|
+
h("div", { class: "dialkit-folder-header-top" }, [
|
|
2210
|
+
props.isRoot ? isOpen.value ? h("div", { class: "dialkit-folder-title-row" }, [
|
|
2211
|
+
h("span", { class: "dialkit-folder-title dialkit-folder-title-root" }, props.title)
|
|
2212
|
+
]) : null : h("div", { class: "dialkit-folder-title-row" }, [
|
|
2213
|
+
h("span", { class: "dialkit-folder-title" }, props.title)
|
|
2214
|
+
]),
|
|
2215
|
+
props.isRoot && !props.inline ? h("svg", { class: "dialkit-panel-icon", viewBox: "0 0 16 16", fill: "none" }, [
|
|
2216
|
+
h("path", {
|
|
2217
|
+
opacity: "0.5",
|
|
2218
|
+
d: ICON_PANEL.path,
|
|
2219
|
+
fill: "currentColor"
|
|
2220
|
+
}),
|
|
2221
|
+
...ICON_PANEL.circles.map((c) => h("circle", { cx: c.cx, cy: c.cy, r: c.r, fill: "currentColor", stroke: "currentColor", "stroke-width": "1.25" }))
|
|
2222
|
+
]) : null,
|
|
2223
|
+
!props.isRoot ? h(motion.svg, {
|
|
2224
|
+
class: "dialkit-folder-icon",
|
|
2225
|
+
viewBox: "0 0 24 24",
|
|
2226
|
+
fill: "none",
|
|
2227
|
+
stroke: "currentColor",
|
|
2228
|
+
"stroke-width": "2.5",
|
|
2229
|
+
"stroke-linecap": "round",
|
|
2230
|
+
"stroke-linejoin": "round",
|
|
2231
|
+
initial: false,
|
|
2232
|
+
animate: { rotate: isOpen.value ? 0 : 180 },
|
|
2233
|
+
transition: { type: "spring", visualDuration: 0.35, bounce: 0.15 }
|
|
2234
|
+
}, [h("path", { d: ICON_CHEVRON })]) : null
|
|
2235
|
+
]),
|
|
2236
|
+
props.isRoot && props.toolbar && isOpen.value ? h("div", { class: "dialkit-panel-toolbar", onClick: (event) => event.stopPropagation() }, [props.toolbar()]) : null
|
|
2237
|
+
]);
|
|
2238
|
+
const renderChildren = () => h("div", { class: "dialkit-folder-inner" }, slots.default ? slots.default() : []);
|
|
2239
|
+
const renderContent = () => {
|
|
2240
|
+
if (props.isRoot) {
|
|
2241
|
+
return isOpen.value ? h("div", { class: "dialkit-folder-content" }, [renderChildren()]) : null;
|
|
2242
|
+
}
|
|
2243
|
+
return h(AnimatePresence, { initial: false }, {
|
|
2244
|
+
default: () => isOpen.value ? [h(motion.div, {
|
|
2245
|
+
key: "dialkit-folder-content",
|
|
2246
|
+
class: "dialkit-folder-content",
|
|
2247
|
+
initial: { height: 0, opacity: 0 },
|
|
2248
|
+
animate: { height: "auto", opacity: 1 },
|
|
2249
|
+
exit: { height: 0, opacity: 0 },
|
|
2250
|
+
transition: { type: "spring", visualDuration: 0.35, bounce: 0.1 },
|
|
2251
|
+
style: { clipPath: "inset(0 -20px)" }
|
|
2252
|
+
}, [renderChildren()])] : []
|
|
2253
|
+
});
|
|
2254
|
+
};
|
|
2255
|
+
const folderContent = () => h("div", {
|
|
2256
|
+
ref: props.isRoot ? contentRef : void 0,
|
|
2257
|
+
class: `dialkit-folder ${props.isRoot ? "dialkit-folder-root" : ""}`,
|
|
2258
|
+
"data-open": String(isOpen.value)
|
|
2259
|
+
}, [
|
|
2260
|
+
renderHeader(),
|
|
2261
|
+
renderContent()
|
|
2262
|
+
]);
|
|
2263
|
+
return () => {
|
|
2264
|
+
if (props.isRoot) {
|
|
2265
|
+
if (props.inline) {
|
|
2266
|
+
return h("div", { class: "dialkit-panel-inner dialkit-panel-inline" }, [folderContent()]);
|
|
2267
|
+
}
|
|
2268
|
+
const panelStyle = isOpen.value ? {
|
|
2269
|
+
width: 280,
|
|
2270
|
+
height: contentHeight.value !== void 0 ? Math.min(contentHeight.value + props.panelHeightOffset, windowHeight.value - 32) : "auto",
|
|
2271
|
+
borderRadius: 14,
|
|
2272
|
+
boxShadow: "var(--dial-shadow)",
|
|
2273
|
+
cursor: void 0,
|
|
2274
|
+
overflowY: "auto"
|
|
2275
|
+
} : {
|
|
2276
|
+
width: 42,
|
|
2277
|
+
height: 42,
|
|
2278
|
+
borderRadius: 21,
|
|
2279
|
+
boxShadow: "var(--dial-shadow-collapsed)",
|
|
2280
|
+
overflow: "hidden",
|
|
2281
|
+
cursor: "pointer"
|
|
2282
|
+
};
|
|
2283
|
+
return h(motion.div, {
|
|
2284
|
+
class: "dialkit-panel-inner",
|
|
2285
|
+
style: panelStyle,
|
|
2286
|
+
onClick: !isOpen.value ? handleToggle : void 0,
|
|
2287
|
+
"data-collapsed": String(isCollapsed.value),
|
|
2288
|
+
whilePress: !isOpen.value ? { scale: 0.9 } : void 0,
|
|
2289
|
+
transition: { type: "spring", visualDuration: 0.15, bounce: 0.3 }
|
|
2290
|
+
}, [folderContent()]);
|
|
2291
|
+
}
|
|
2292
|
+
return folderContent();
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
});
|
|
2296
|
+
|
|
2297
|
+
// src/vue/components/Panel.ts
|
|
2298
|
+
import { Fragment, defineComponent as defineComponent14, h as h14, onMounted as onMounted10, onUnmounted as onUnmounted9, ref as ref12 } from "vue";
|
|
2299
|
+
import { AnimatePresence as AnimatePresence4, motion as motion4 } from "motion-v";
|
|
2300
|
+
|
|
2301
|
+
// src/vue/components/Slider.ts
|
|
2302
|
+
import { defineComponent as defineComponent2, h as h2, computed as computed3, nextTick, onMounted as onMounted4, onUnmounted as onUnmounted4, ref as ref3, watch as watch3 } from "vue";
|
|
2303
|
+
import { animate, motionValue } from "motion-v";
|
|
2304
|
+
|
|
2305
|
+
// src/shortcut-utils.ts
|
|
2306
|
+
function decimalsForStep(step) {
|
|
2307
|
+
const s = step.toString();
|
|
2308
|
+
const dot = s.indexOf(".");
|
|
2309
|
+
return dot === -1 ? 0 : s.length - dot - 1;
|
|
2310
|
+
}
|
|
2311
|
+
function roundValue(val, step) {
|
|
2312
|
+
const raw = Math.round(val / step) * step;
|
|
2313
|
+
return parseFloat(raw.toFixed(decimalsForStep(step)));
|
|
2314
|
+
}
|
|
2315
|
+
function getEffectiveStep(control, shortcut) {
|
|
993
2316
|
const min = control.min ?? 0;
|
|
994
2317
|
const max = control.max ?? 1;
|
|
995
2318
|
const range = max - min;
|
|
@@ -1083,9 +2406,9 @@ var Slider = defineComponent2({
|
|
|
1083
2406
|
},
|
|
1084
2407
|
emits: ["change"],
|
|
1085
2408
|
setup(props, { emit }) {
|
|
1086
|
-
const min =
|
|
1087
|
-
const max =
|
|
1088
|
-
const step =
|
|
2409
|
+
const min = computed3(() => props.min ?? 0);
|
|
2410
|
+
const max = computed3(() => props.max ?? 1);
|
|
2411
|
+
const step = computed3(() => props.step ?? 0.01);
|
|
1089
2412
|
const wrapperRef = ref3(null);
|
|
1090
2413
|
const trackRef = ref3(null);
|
|
1091
2414
|
const fillRef = ref3(null);
|
|
@@ -1105,9 +2428,9 @@ var Slider = defineComponent2({
|
|
|
1105
2428
|
const handleOpacityMv = motionValue(0);
|
|
1106
2429
|
const handleScaleXMv = motionValue(0.25);
|
|
1107
2430
|
const handleScaleYMv = motionValue(1);
|
|
1108
|
-
const percentage =
|
|
1109
|
-
const isActive =
|
|
1110
|
-
const displayValue =
|
|
2431
|
+
const percentage = computed3(() => (props.value - min.value) / (max.value - min.value) * 100);
|
|
2432
|
+
const isActive = computed3(() => isInteracting.value || isHovered.value);
|
|
2433
|
+
const displayValue = computed3(() => props.value.toFixed(decimalsForStep(step.value)));
|
|
1111
2434
|
let pointerDownPos = null;
|
|
1112
2435
|
let isClickFlag = true;
|
|
1113
2436
|
let wrapperRect = null;
|
|
@@ -1296,15 +2619,15 @@ var Slider = defineComponent2({
|
|
|
1296
2619
|
isValueHovered.value = false;
|
|
1297
2620
|
}
|
|
1298
2621
|
};
|
|
1299
|
-
|
|
2622
|
+
watch3(() => props.value, () => {
|
|
1300
2623
|
if (!isInteracting.value && !snapAnim) {
|
|
1301
2624
|
fillPercent.jump(percentage.value);
|
|
1302
2625
|
}
|
|
1303
2626
|
});
|
|
1304
|
-
|
|
2627
|
+
watch3([isInteracting, isHovered, isDragging, () => props.value], () => {
|
|
1305
2628
|
animateHandleState();
|
|
1306
2629
|
});
|
|
1307
|
-
|
|
2630
|
+
watch3([isValueHovered, showInput, isValueEditable], () => {
|
|
1308
2631
|
if (hoverTimeout) {
|
|
1309
2632
|
clearTimeout(hoverTimeout);
|
|
1310
2633
|
hoverTimeout = null;
|
|
@@ -1318,14 +2641,14 @@ var Slider = defineComponent2({
|
|
|
1318
2641
|
isValueEditable.value = false;
|
|
1319
2642
|
}
|
|
1320
2643
|
});
|
|
1321
|
-
|
|
2644
|
+
watch3(showInput, async (visible) => {
|
|
1322
2645
|
if (!visible) return;
|
|
1323
2646
|
await nextTick();
|
|
1324
2647
|
inputRef.value?.focus();
|
|
1325
2648
|
inputRef.value?.select();
|
|
1326
2649
|
});
|
|
1327
|
-
const discreteSteps =
|
|
1328
|
-
const hashMarks =
|
|
2650
|
+
const discreteSteps = computed3(() => (max.value - min.value) / step.value);
|
|
2651
|
+
const hashMarks = computed3(() => {
|
|
1329
2652
|
const marks = [];
|
|
1330
2653
|
if (discreteSteps.value <= 10) {
|
|
1331
2654
|
const count = Math.max(0, Math.floor(discreteSteps.value) - 1);
|
|
@@ -1346,7 +2669,7 @@ var Slider = defineComponent2({
|
|
|
1346
2669
|
let unsubHandleOpacity = null;
|
|
1347
2670
|
let unsubHandleScaleX = null;
|
|
1348
2671
|
let unsubHandleScaleY = null;
|
|
1349
|
-
|
|
2672
|
+
onMounted4(() => {
|
|
1350
2673
|
unsubFill = fillPercent.on("change", applyFillStyles);
|
|
1351
2674
|
unsubRubber = rubberStretchPx.on("change", applyRubberStyles);
|
|
1352
2675
|
unsubHandleOpacity = handleOpacityMv.on("change", applyHandleVisualStyles);
|
|
@@ -1357,7 +2680,7 @@ var Slider = defineComponent2({
|
|
|
1357
2680
|
applyHandleVisualStyles();
|
|
1358
2681
|
animateHandleState();
|
|
1359
2682
|
});
|
|
1360
|
-
|
|
2683
|
+
onUnmounted4(() => {
|
|
1361
2684
|
if (hoverTimeout) clearTimeout(hoverTimeout);
|
|
1362
2685
|
snapAnim?.stop();
|
|
1363
2686
|
rubberAnim?.stop();
|
|
@@ -1446,7 +2769,7 @@ var Slider = defineComponent2({
|
|
|
1446
2769
|
import { defineComponent as defineComponent4, h as h4 } from "vue";
|
|
1447
2770
|
|
|
1448
2771
|
// src/vue/components/SegmentedControl.ts
|
|
1449
|
-
import { defineComponent as defineComponent3, h as h3, nextTick as nextTick2, onMounted as
|
|
2772
|
+
import { defineComponent as defineComponent3, h as h3, nextTick as nextTick2, onMounted as onMounted5, onUnmounted as onUnmounted5, ref as ref4, watch as watch4 } from "vue";
|
|
1450
2773
|
import { animate as animate2 } from "motion";
|
|
1451
2774
|
var SegmentedControl = defineComponent3({
|
|
1452
2775
|
name: "DialKitSegmentedControl",
|
|
@@ -1517,7 +2840,7 @@ var SegmentedControl = defineComponent3({
|
|
|
1517
2840
|
);
|
|
1518
2841
|
};
|
|
1519
2842
|
let ro;
|
|
1520
|
-
|
|
2843
|
+
onMounted5(() => {
|
|
1521
2844
|
nextTick2(() => {
|
|
1522
2845
|
updatePill(false);
|
|
1523
2846
|
hasAnimated = true;
|
|
@@ -1527,11 +2850,11 @@ var SegmentedControl = defineComponent3({
|
|
|
1527
2850
|
ro.observe(containerRef.value);
|
|
1528
2851
|
}
|
|
1529
2852
|
});
|
|
1530
|
-
|
|
2853
|
+
onUnmounted5(() => {
|
|
1531
2854
|
pillAnim?.stop();
|
|
1532
2855
|
ro?.disconnect();
|
|
1533
2856
|
});
|
|
1534
|
-
|
|
2857
|
+
watch4(
|
|
1535
2858
|
() => props.value,
|
|
1536
2859
|
() => {
|
|
1537
2860
|
updatePill(true);
|
|
@@ -1595,10 +2918,10 @@ var Toggle = defineComponent4({
|
|
|
1595
2918
|
});
|
|
1596
2919
|
|
|
1597
2920
|
// src/vue/components/SpringControl.ts
|
|
1598
|
-
import { defineComponent as defineComponent6, h as h6, onMounted as
|
|
2921
|
+
import { defineComponent as defineComponent6, h as h6, onMounted as onMounted6, onUnmounted as onUnmounted6, ref as ref5 } from "vue";
|
|
1599
2922
|
|
|
1600
2923
|
// src/vue/components/SpringVisualization.ts
|
|
1601
|
-
import { defineComponent as defineComponent5, h as h5, computed as
|
|
2924
|
+
import { defineComponent as defineComponent5, h as h5, computed as computed4 } from "vue";
|
|
1602
2925
|
function generateSpringCurve(stiffness, damping, mass, duration) {
|
|
1603
2926
|
const points = [];
|
|
1604
2927
|
const steps = 100;
|
|
@@ -1632,7 +2955,7 @@ var SpringVisualization = defineComponent5({
|
|
|
1632
2955
|
setup(props) {
|
|
1633
2956
|
const width = 256;
|
|
1634
2957
|
const height = 140;
|
|
1635
|
-
const pathData =
|
|
2958
|
+
const pathData = computed4(() => {
|
|
1636
2959
|
let stiffness;
|
|
1637
2960
|
let damping;
|
|
1638
2961
|
let mass;
|
|
@@ -1708,12 +3031,12 @@ var SpringControl = defineComponent6({
|
|
|
1708
3031
|
setup(props, { emit }) {
|
|
1709
3032
|
const mode = ref5(DialStore.getSpringMode(props.panelId, props.path));
|
|
1710
3033
|
let unsub;
|
|
1711
|
-
|
|
3034
|
+
onMounted6(() => {
|
|
1712
3035
|
unsub = DialStore.subscribe(props.panelId, () => {
|
|
1713
3036
|
mode.value = DialStore.getSpringMode(props.panelId, props.path);
|
|
1714
3037
|
});
|
|
1715
3038
|
});
|
|
1716
|
-
|
|
3039
|
+
onUnmounted6(() => {
|
|
1717
3040
|
unsub?.();
|
|
1718
3041
|
});
|
|
1719
3042
|
const isSimpleMode = () => mode.value === "simple";
|
|
@@ -1809,10 +3132,10 @@ var SpringControl = defineComponent6({
|
|
|
1809
3132
|
});
|
|
1810
3133
|
|
|
1811
3134
|
// src/vue/components/TransitionControl.ts
|
|
1812
|
-
import { defineComponent as defineComponent8, h as h8, onMounted as
|
|
3135
|
+
import { defineComponent as defineComponent8, h as h8, onMounted as onMounted7, onUnmounted as onUnmounted7, ref as ref6 } from "vue";
|
|
1813
3136
|
|
|
1814
3137
|
// src/vue/components/EasingVisualization.ts
|
|
1815
|
-
import { defineComponent as defineComponent7, h as h7, computed as
|
|
3138
|
+
import { defineComponent as defineComponent7, h as h7, computed as computed5 } from "vue";
|
|
1816
3139
|
var EasingVisualization = defineComponent7({
|
|
1817
3140
|
name: "DialKitEasingVisualization",
|
|
1818
3141
|
props: {
|
|
@@ -1826,7 +3149,7 @@ var EasingVisualization = defineComponent7({
|
|
|
1826
3149
|
const pad = 10;
|
|
1827
3150
|
const inner = size - pad * 2;
|
|
1828
3151
|
const unit = inner / 2;
|
|
1829
|
-
const curve =
|
|
3152
|
+
const curve = computed5(() => {
|
|
1830
3153
|
const [x1, y1, x2, y2] = props.easing.ease;
|
|
1831
3154
|
const toSvg = (nx, ny) => ({
|
|
1832
3155
|
x: pad + (nx + 0.5) * unit,
|
|
@@ -1929,18 +3252,20 @@ var TransitionControl = defineComponent8({
|
|
|
1929
3252
|
value: {
|
|
1930
3253
|
type: Object,
|
|
1931
3254
|
required: true
|
|
1932
|
-
}
|
|
3255
|
+
},
|
|
3256
|
+
hideDuration: { type: Boolean, default: false },
|
|
3257
|
+
durationControl: Object
|
|
1933
3258
|
},
|
|
1934
3259
|
emits: ["change"],
|
|
1935
3260
|
setup(props, { emit }) {
|
|
1936
3261
|
const mode = ref6(DialStore.getTransitionMode(props.panelId, props.path));
|
|
1937
3262
|
let unsub;
|
|
1938
|
-
|
|
3263
|
+
onMounted7(() => {
|
|
1939
3264
|
unsub = DialStore.subscribe(props.panelId, () => {
|
|
1940
3265
|
mode.value = DialStore.getTransitionMode(props.panelId, props.path);
|
|
1941
3266
|
});
|
|
1942
3267
|
});
|
|
1943
|
-
|
|
3268
|
+
onUnmounted7(() => unsub?.());
|
|
1944
3269
|
const cache = {
|
|
1945
3270
|
easing: props.value.type === "easing" ? { ...props.value } : { type: "easing", duration: 0.3, ease: [1, -0.4, 0.5, 1] },
|
|
1946
3271
|
simple: props.value.type === "spring" && props.value.visualDuration !== void 0 ? { ...props.value } : { type: "spring", visualDuration: 0.3, bounce: 0.2 },
|
|
@@ -1992,6 +3317,18 @@ var TransitionControl = defineComponent8({
|
|
|
1992
3317
|
const isSimpleSpring = mode.value === "simple";
|
|
1993
3318
|
const currentSpring = spring();
|
|
1994
3319
|
const currentEasing = easing();
|
|
3320
|
+
const durationSlider = !props.hideDuration && (isEasing || isSimpleSpring) ? h8(Slider, {
|
|
3321
|
+
label: "Duration",
|
|
3322
|
+
value: props.durationControl?.value ?? (isEasing ? currentEasing.duration : currentSpring.visualDuration ?? 0.3),
|
|
3323
|
+
min: props.durationControl?.min ?? 0.1,
|
|
3324
|
+
max: props.durationControl?.max ?? (isEasing ? 2 : 1),
|
|
3325
|
+
step: props.durationControl?.step ?? 0.05,
|
|
3326
|
+
unit: "s",
|
|
3327
|
+
onChange: props.durationControl?.onChange ?? ((next) => {
|
|
3328
|
+
if (isEasing) emit("change", { ...currentEasing, duration: next });
|
|
3329
|
+
else handleSpringUpdate("visualDuration", next);
|
|
3330
|
+
})
|
|
3331
|
+
}) : null;
|
|
1995
3332
|
return h8(Folder, { title: props.label, defaultOpen: true }, {
|
|
1996
3333
|
default: () => [
|
|
1997
3334
|
h8("div", { style: { display: "flex", flexDirection: "column", gap: "6px" } }, [
|
|
@@ -2013,29 +3350,11 @@ var TransitionControl = defineComponent8({
|
|
|
2013
3350
|
h8(Slider, { label: "y1", value: currentEasing.ease[1], min: -1, max: 2, step: 0.01, onChange: (next) => updateEase(1, next) }),
|
|
2014
3351
|
h8(Slider, { label: "x2", value: currentEasing.ease[2], min: 0, max: 1, step: 0.01, onChange: (next) => updateEase(2, next) }),
|
|
2015
3352
|
h8(Slider, { label: "y2", value: currentEasing.ease[3], min: -1, max: 2, step: 0.01, onChange: (next) => updateEase(3, next) }),
|
|
2016
|
-
h8(Slider, {
|
|
2017
|
-
label: "Duration",
|
|
2018
|
-
value: currentEasing.duration,
|
|
2019
|
-
min: 0.1,
|
|
2020
|
-
max: 2,
|
|
2021
|
-
step: 0.05,
|
|
2022
|
-
unit: "s",
|
|
2023
|
-
onChange: (next) => emit("change", { ...currentEasing, duration: next })
|
|
2024
|
-
}),
|
|
2025
3353
|
h8(EaseTextInput, {
|
|
2026
3354
|
ease: currentEasing.ease,
|
|
2027
3355
|
onChange: (next) => emit("change", { ...currentEasing, ease: next })
|
|
2028
3356
|
})
|
|
2029
3357
|
] : isSimpleSpring ? [
|
|
2030
|
-
h8(Slider, {
|
|
2031
|
-
label: "Duration",
|
|
2032
|
-
value: currentSpring.visualDuration ?? 0.3,
|
|
2033
|
-
min: 0.1,
|
|
2034
|
-
max: 1,
|
|
2035
|
-
step: 0.05,
|
|
2036
|
-
unit: "s",
|
|
2037
|
-
onChange: (next) => handleSpringUpdate("visualDuration", next)
|
|
2038
|
-
}),
|
|
2039
3358
|
h8(Slider, {
|
|
2040
3359
|
label: "Bounce",
|
|
2041
3360
|
value: currentSpring.bounce ?? 0.2,
|
|
@@ -2069,7 +3388,8 @@ var TransitionControl = defineComponent8({
|
|
|
2069
3388
|
step: 0.1,
|
|
2070
3389
|
onChange: (next) => handleSpringUpdate("mass", next)
|
|
2071
3390
|
})
|
|
2072
|
-
]
|
|
3391
|
+
],
|
|
3392
|
+
durationSlider
|
|
2073
3393
|
])
|
|
2074
3394
|
]
|
|
2075
3395
|
});
|
|
@@ -2105,7 +3425,7 @@ var TextControl = defineComponent9({
|
|
|
2105
3425
|
});
|
|
2106
3426
|
|
|
2107
3427
|
// src/vue/components/SelectControl.ts
|
|
2108
|
-
import { Teleport, defineComponent as defineComponent10, h as h10, onMounted as
|
|
3428
|
+
import { Teleport, defineComponent as defineComponent10, h as h10, onMounted as onMounted8, ref as ref8, watch as watch5 } from "vue";
|
|
2109
3429
|
import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion-v";
|
|
2110
3430
|
|
|
2111
3431
|
// src/dropdown-position.ts
|
|
@@ -2182,7 +3502,7 @@ var SelectControl = defineComponent10({
|
|
|
2182
3502
|
if (isOpen.value) closeDropdown();
|
|
2183
3503
|
else openDropdown();
|
|
2184
3504
|
};
|
|
2185
|
-
|
|
3505
|
+
watch5(isOpen, (open, _, onCleanup) => {
|
|
2186
3506
|
if (!open) return;
|
|
2187
3507
|
const handleViewportChange = () => updatePos();
|
|
2188
3508
|
const handleDocumentClick = (event) => {
|
|
@@ -2200,7 +3520,7 @@ var SelectControl = defineComponent10({
|
|
|
2200
3520
|
window.removeEventListener("scroll", handleViewportChange, true);
|
|
2201
3521
|
});
|
|
2202
3522
|
});
|
|
2203
|
-
|
|
3523
|
+
onMounted8(() => {
|
|
2204
3524
|
portalTarget.value = getDialKitPortalRoot(triggerRef.value) ?? document.body;
|
|
2205
3525
|
});
|
|
2206
3526
|
return () => h10("div", { class: "dialkit-select-row" }, [
|
|
@@ -2259,7 +3579,7 @@ var SelectControl = defineComponent10({
|
|
|
2259
3579
|
});
|
|
2260
3580
|
|
|
2261
3581
|
// src/vue/components/ColorControl.ts
|
|
2262
|
-
import { defineComponent as defineComponent11, h as h11, ref as ref9, watch as
|
|
3582
|
+
import { defineComponent as defineComponent11, h as h11, ref as ref9, watch as watch6 } from "vue";
|
|
2263
3583
|
var HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
2264
3584
|
function expandShorthandHex(hex) {
|
|
2265
3585
|
if (hex.length !== 4) return hex;
|
|
@@ -2278,7 +3598,7 @@ var ColorControl = defineComponent11({
|
|
|
2278
3598
|
const isEditing = ref9(false);
|
|
2279
3599
|
const editValue = ref9(props.value);
|
|
2280
3600
|
const colorInputRef = ref9(null);
|
|
2281
|
-
|
|
3601
|
+
watch6(() => props.value, (value) => {
|
|
2282
3602
|
if (!isEditing.value) editValue.value = value;
|
|
2283
3603
|
});
|
|
2284
3604
|
const submit = () => {
|
|
@@ -2333,7 +3653,7 @@ var ColorControl = defineComponent11({
|
|
|
2333
3653
|
});
|
|
2334
3654
|
|
|
2335
3655
|
// src/vue/components/PresetManager.ts
|
|
2336
|
-
import { Teleport as Teleport2, defineComponent as defineComponent12, h as h12, ref as ref10, watch as
|
|
3656
|
+
import { Teleport as Teleport2, defineComponent as defineComponent12, h as h12, ref as ref10, watch as watch7 } from "vue";
|
|
2337
3657
|
import { AnimatePresence as AnimatePresence3, motion as motion3 } from "motion-v";
|
|
2338
3658
|
var PresetManager = defineComponent12({
|
|
2339
3659
|
name: "DialKitPresetManager",
|
|
@@ -2383,7 +3703,7 @@ var PresetManager = defineComponent12({
|
|
|
2383
3703
|
if (isOpen.value) close();
|
|
2384
3704
|
else open();
|
|
2385
3705
|
};
|
|
2386
|
-
|
|
3706
|
+
watch7(isOpen, (open2, _, onCleanup) => {
|
|
2387
3707
|
if (!open2) return;
|
|
2388
3708
|
const handler = (event) => {
|
|
2389
3709
|
const target = event.target;
|
|
@@ -2481,7 +3801,7 @@ var PresetManager = defineComponent12({
|
|
|
2481
3801
|
});
|
|
2482
3802
|
|
|
2483
3803
|
// src/vue/components/ShortcutListener.ts
|
|
2484
|
-
import { defineComponent as defineComponent13, inject, onMounted as
|
|
3804
|
+
import { defineComponent as defineComponent13, inject, onMounted as onMounted9, onUnmounted as onUnmounted8, provide, ref as ref11 } from "vue";
|
|
2485
3805
|
var ShortcutKey = /* @__PURE__ */ Symbol("DialKitShortcut");
|
|
2486
3806
|
function useShortcutContext() {
|
|
2487
3807
|
return inject(ShortcutKey, {
|
|
@@ -2661,7 +3981,7 @@ var ShortcutListener = defineComponent13({
|
|
|
2661
3981
|
activePanelId.value = null;
|
|
2662
3982
|
activePath.value = null;
|
|
2663
3983
|
};
|
|
2664
|
-
|
|
3984
|
+
onMounted9(() => {
|
|
2665
3985
|
window.addEventListener("keydown", handleKeyDown);
|
|
2666
3986
|
window.addEventListener("keyup", handleKeyUp);
|
|
2667
3987
|
window.addEventListener("wheel", handleWheel, { passive: false });
|
|
@@ -2670,7 +3990,7 @@ var ShortcutListener = defineComponent13({
|
|
|
2670
3990
|
window.addEventListener("mousemove", handleMouseMove);
|
|
2671
3991
|
window.addEventListener("blur", handleWindowBlur);
|
|
2672
3992
|
});
|
|
2673
|
-
|
|
3993
|
+
onUnmounted8(() => {
|
|
2674
3994
|
window.removeEventListener("keydown", handleKeyDown);
|
|
2675
3995
|
window.removeEventListener("keyup", handleKeyUp);
|
|
2676
3996
|
window.removeEventListener("wheel", handleWheel);
|
|
@@ -2702,7 +4022,8 @@ var Panel = defineComponent14({
|
|
|
2702
4022
|
variant: {
|
|
2703
4023
|
type: String,
|
|
2704
4024
|
default: "root"
|
|
2705
|
-
}
|
|
4025
|
+
},
|
|
4026
|
+
toolbarExtra: Function
|
|
2706
4027
|
},
|
|
2707
4028
|
emits: ["openChange"],
|
|
2708
4029
|
setup(props, { emit }) {
|
|
@@ -2714,14 +4035,14 @@ var Panel = defineComponent14({
|
|
|
2714
4035
|
const hasShortcuts = () => Object.keys(DialStore.getPanel(props.panel.id)?.shortcuts ?? {}).length > 0;
|
|
2715
4036
|
let unsubscribe;
|
|
2716
4037
|
let copiedTimeout = null;
|
|
2717
|
-
|
|
4038
|
+
onMounted10(() => {
|
|
2718
4039
|
unsubscribe = DialStore.subscribe(props.panel.id, () => {
|
|
2719
4040
|
values.value = DialStore.getValues(props.panel.id);
|
|
2720
4041
|
presets.value = DialStore.getPresets(props.panel.id);
|
|
2721
4042
|
activePresetId.value = DialStore.getActivePresetId(props.panel.id);
|
|
2722
4043
|
});
|
|
2723
4044
|
});
|
|
2724
|
-
|
|
4045
|
+
onUnmounted9(() => {
|
|
2725
4046
|
unsubscribe?.();
|
|
2726
4047
|
if (copiedTimeout) {
|
|
2727
4048
|
window.clearTimeout(copiedTimeout);
|
|
@@ -2923,7 +4244,8 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2923
4244
|
})
|
|
2924
4245
|
]),
|
|
2925
4246
|
"Copy"
|
|
2926
|
-
])
|
|
4247
|
+
]),
|
|
4248
|
+
props.toolbarExtra?.()
|
|
2927
4249
|
]);
|
|
2928
4250
|
if (props.variant === "section") {
|
|
2929
4251
|
return h14(Folder, {
|
|
@@ -2956,6 +4278,39 @@ Apply these values as the new defaults in the useDialKit call.`;
|
|
|
2956
4278
|
}
|
|
2957
4279
|
});
|
|
2958
4280
|
|
|
4281
|
+
// src/vue/components/Timeline/TimelineToggleButton.ts
|
|
4282
|
+
import { defineComponent as defineComponent15, h as h15, onMounted as onMounted11, onUnmounted as onUnmounted10, ref as ref13 } from "vue";
|
|
4283
|
+
var TimelineToggleButton = defineComponent15({
|
|
4284
|
+
name: "DialKitTimelineToggleButton",
|
|
4285
|
+
setup() {
|
|
4286
|
+
const visible = ref13(TimelineUiStore.getVisible());
|
|
4287
|
+
let unsubscribe;
|
|
4288
|
+
onMounted11(() => {
|
|
4289
|
+
unsubscribe = TimelineUiStore.subscribe(() => {
|
|
4290
|
+
visible.value = TimelineUiStore.getVisible();
|
|
4291
|
+
});
|
|
4292
|
+
});
|
|
4293
|
+
onUnmounted10(() => unsubscribe?.());
|
|
4294
|
+
return () => {
|
|
4295
|
+
const label = visible.value ? "Hide timeline" : "Show timeline";
|
|
4296
|
+
return h15("button", {
|
|
4297
|
+
class: "dialkit-toolbar-add dialkit-timeline-toolbar-toggle",
|
|
4298
|
+
"data-active": visible.value || void 0,
|
|
4299
|
+
"aria-pressed": visible.value,
|
|
4300
|
+
"aria-label": label,
|
|
4301
|
+
title: label,
|
|
4302
|
+
onClick: () => TimelineUiStore.toggle()
|
|
4303
|
+
}, [
|
|
4304
|
+
h15(
|
|
4305
|
+
"svg",
|
|
4306
|
+
{ viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" },
|
|
4307
|
+
ICON_TIMELINE.map((path) => h15("path", { d: path, fill: "currentColor" }))
|
|
4308
|
+
)
|
|
4309
|
+
]);
|
|
4310
|
+
};
|
|
4311
|
+
}
|
|
4312
|
+
});
|
|
4313
|
+
|
|
2959
4314
|
// src/panel-drag.ts
|
|
2960
4315
|
var PANEL_DRAG_THRESHOLD = 8;
|
|
2961
4316
|
var COLLAPSED_PANEL_SIZE = 42;
|
|
@@ -3021,8 +4376,8 @@ function blockPanelDragClick(handle) {
|
|
|
3021
4376
|
}
|
|
3022
4377
|
|
|
3023
4378
|
// src/vue/components/DialRoot.ts
|
|
3024
|
-
var
|
|
3025
|
-
var DialRoot =
|
|
4379
|
+
var isDevDefault2 = 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;
|
|
4380
|
+
var DialRoot = defineComponent16({
|
|
3026
4381
|
name: "DialKitDialRoot",
|
|
3027
4382
|
props: {
|
|
3028
4383
|
position: {
|
|
@@ -3043,17 +4398,19 @@ var DialRoot = defineComponent15({
|
|
|
3043
4398
|
},
|
|
3044
4399
|
productionEnabled: {
|
|
3045
4400
|
type: Boolean,
|
|
3046
|
-
default:
|
|
4401
|
+
default: isDevDefault2
|
|
3047
4402
|
}
|
|
3048
4403
|
},
|
|
3049
4404
|
emits: ["openChange"],
|
|
3050
4405
|
setup(props, { emit }) {
|
|
3051
|
-
const panels =
|
|
3052
|
-
const
|
|
3053
|
-
const
|
|
3054
|
-
const
|
|
3055
|
-
const
|
|
3056
|
-
|
|
4406
|
+
const panels = ref14([]);
|
|
4407
|
+
const timelines = ref14([]);
|
|
4408
|
+
const mounted = ref14(false);
|
|
4409
|
+
const panelRef = ref14(null);
|
|
4410
|
+
const dragOffset = ref14(null);
|
|
4411
|
+
const activePosition = ref14(props.position);
|
|
4412
|
+
let unsubscribePanels;
|
|
4413
|
+
let unsubscribeTimelines;
|
|
3057
4414
|
let observer;
|
|
3058
4415
|
let lastDragOffset = null;
|
|
3059
4416
|
let dragging = false;
|
|
@@ -3146,24 +4503,73 @@ var DialRoot = defineComponent15({
|
|
|
3146
4503
|
right: "auto",
|
|
3147
4504
|
bottom: "auto"
|
|
3148
4505
|
} : void 0;
|
|
3149
|
-
const originX =
|
|
3150
|
-
|
|
4506
|
+
const originX = computed6(() => props.mode === "inline" ? void 0 : getPanelOriginX(activePosition.value, dragOffset.value));
|
|
4507
|
+
onMounted12(() => {
|
|
3151
4508
|
mounted.value = true;
|
|
3152
|
-
panels.value = DialStore.getPanels();
|
|
4509
|
+
panels.value = DialStore.getPanels("panel");
|
|
4510
|
+
timelines.value = TimelineStore.getTimelines();
|
|
3153
4511
|
syncPanelOpenStates();
|
|
3154
|
-
|
|
3155
|
-
panels.value = DialStore.getPanels();
|
|
4512
|
+
unsubscribePanels = DialStore.subscribeGlobal(() => {
|
|
4513
|
+
panels.value = DialStore.getPanels("panel");
|
|
3156
4514
|
syncPanelOpenStates();
|
|
3157
4515
|
});
|
|
4516
|
+
unsubscribeTimelines = TimelineStore.subscribeGlobal(() => {
|
|
4517
|
+
timelines.value = TimelineStore.getTimelines();
|
|
4518
|
+
});
|
|
3158
4519
|
nextTick3(connectObserver);
|
|
3159
4520
|
});
|
|
3160
|
-
|
|
3161
|
-
|
|
4521
|
+
onUnmounted11(() => {
|
|
4522
|
+
unsubscribePanels?.();
|
|
4523
|
+
unsubscribeTimelines?.();
|
|
3162
4524
|
observer?.disconnect();
|
|
3163
4525
|
});
|
|
3164
|
-
const
|
|
3165
|
-
|
|
3166
|
-
|
|
4526
|
+
const timelineToggle = () => timelines.value.length > 0 ? h16(TimelineToggleButton) : null;
|
|
4527
|
+
const renderPanels = () => {
|
|
4528
|
+
if (panels.value.length === 0) {
|
|
4529
|
+
return [h16("div", { class: "dialkit-panel-wrapper" }, [
|
|
4530
|
+
h16(Folder, {
|
|
4531
|
+
title: "DialKit",
|
|
4532
|
+
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
4533
|
+
isRoot: true,
|
|
4534
|
+
inline: props.mode === "inline",
|
|
4535
|
+
toolbar: timelineToggle,
|
|
4536
|
+
onOpenChange: handleRootOpenChange,
|
|
4537
|
+
panelHeightOffset: 2
|
|
4538
|
+
}, { default: () => [h16("div", { class: "dialkit-timeline-toolkit-only" }, "Timeline")] })
|
|
4539
|
+
])];
|
|
4540
|
+
}
|
|
4541
|
+
if (panels.value.length > 1) {
|
|
4542
|
+
return [h16("div", { class: "dialkit-panel-wrapper" }, [
|
|
4543
|
+
h16(Folder, {
|
|
4544
|
+
title: "DialKit",
|
|
4545
|
+
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
4546
|
+
isRoot: true,
|
|
4547
|
+
inline: props.mode === "inline",
|
|
4548
|
+
toolbar: timelineToggle,
|
|
4549
|
+
onOpenChange: handleRootOpenChange,
|
|
4550
|
+
panelHeightOffset: 2
|
|
4551
|
+
}, {
|
|
4552
|
+
default: () => panels.value.map((panel) => h16(Panel, {
|
|
4553
|
+
key: panel.id,
|
|
4554
|
+
panel,
|
|
4555
|
+
defaultOpen: true,
|
|
4556
|
+
variant: "section"
|
|
4557
|
+
}))
|
|
4558
|
+
})
|
|
4559
|
+
])];
|
|
4560
|
+
}
|
|
4561
|
+
return panels.value.map((panel) => h16(Panel, {
|
|
4562
|
+
key: panel.id,
|
|
4563
|
+
panel,
|
|
4564
|
+
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
4565
|
+
inline: props.mode === "inline",
|
|
4566
|
+
toolbarExtra: timelineToggle,
|
|
4567
|
+
onOpenChange: (open) => handlePanelOpenChange(panel.id, open)
|
|
4568
|
+
}));
|
|
4569
|
+
};
|
|
4570
|
+
const renderContent = () => h16(ShortcutListener, null, {
|
|
4571
|
+
default: () => h16("div", { class: "dialkit-root", "data-mode": props.mode, "data-theme": props.theme }, [
|
|
4572
|
+
h16("div", {
|
|
3167
4573
|
ref: (el) => {
|
|
3168
4574
|
panelRef.value = el;
|
|
3169
4575
|
connectObserver();
|
|
@@ -3178,41 +4584,17 @@ var DialRoot = defineComponent15({
|
|
|
3178
4584
|
onPointermove: props.mode === "inline" ? void 0 : handlePointerMove,
|
|
3179
4585
|
onPointerup: props.mode === "inline" ? void 0 : handlePointerUp,
|
|
3180
4586
|
onPointercancel: props.mode === "inline" ? void 0 : handlePointerUp
|
|
3181
|
-
},
|
|
3182
|
-
h15("div", { class: "dialkit-panel-wrapper" }, [
|
|
3183
|
-
h15(Folder, {
|
|
3184
|
-
title: "DialKit",
|
|
3185
|
-
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
3186
|
-
isRoot: true,
|
|
3187
|
-
inline: props.mode === "inline",
|
|
3188
|
-
onOpenChange: handleRootOpenChange,
|
|
3189
|
-
panelHeightOffset: 2
|
|
3190
|
-
}, {
|
|
3191
|
-
default: () => panels.value.map((panel) => h15(Panel, {
|
|
3192
|
-
key: panel.id,
|
|
3193
|
-
panel,
|
|
3194
|
-
defaultOpen: true,
|
|
3195
|
-
variant: "section"
|
|
3196
|
-
}))
|
|
3197
|
-
})
|
|
3198
|
-
])
|
|
3199
|
-
] : panels.value.map((panel) => h15(Panel, {
|
|
3200
|
-
key: panel.id,
|
|
3201
|
-
panel,
|
|
3202
|
-
defaultOpen: props.mode === "inline" || props.defaultOpen,
|
|
3203
|
-
inline: props.mode === "inline",
|
|
3204
|
-
onOpenChange: (open) => handlePanelOpenChange(panel.id, open)
|
|
3205
|
-
})))
|
|
4587
|
+
}, renderPanels())
|
|
3206
4588
|
])
|
|
3207
4589
|
});
|
|
3208
4590
|
return () => {
|
|
3209
|
-
if (!props.productionEnabled || !mounted.value || typeof window === "undefined" || panels.value.length === 0) {
|
|
4591
|
+
if (!props.productionEnabled || !mounted.value || typeof window === "undefined" || panels.value.length === 0 && timelines.value.length === 0) {
|
|
3210
4592
|
return null;
|
|
3211
4593
|
}
|
|
3212
4594
|
if (props.mode === "inline") {
|
|
3213
4595
|
return renderContent();
|
|
3214
4596
|
}
|
|
3215
|
-
return
|
|
4597
|
+
return h16(Teleport3, { to: "body" }, renderContent());
|
|
3216
4598
|
};
|
|
3217
4599
|
}
|
|
3218
4600
|
});
|
|
@@ -3230,11 +4612,11 @@ function mountDialRoot(el, value) {
|
|
|
3230
4612
|
if (typeof window === "undefined") return;
|
|
3231
4613
|
const host = document.createElement("div");
|
|
3232
4614
|
el.appendChild(host);
|
|
3233
|
-
const props =
|
|
3234
|
-
const RootHost =
|
|
4615
|
+
const props = shallowRef3(normalizeDirectiveValue(value));
|
|
4616
|
+
const RootHost = defineComponent17({
|
|
3235
4617
|
name: "DialKitDirectiveHost",
|
|
3236
4618
|
setup() {
|
|
3237
|
-
return () =>
|
|
4619
|
+
return () => h17(DialRoot, props.value);
|
|
3238
4620
|
}
|
|
3239
4621
|
});
|
|
3240
4622
|
const app = createApp(RootHost);
|
|
@@ -3265,8 +4647,1129 @@ var vDialKit = {
|
|
|
3265
4647
|
}
|
|
3266
4648
|
};
|
|
3267
4649
|
|
|
4650
|
+
// src/vue/components/Timeline/DialTimeline.ts
|
|
4651
|
+
import {
|
|
4652
|
+
Teleport as Teleport4,
|
|
4653
|
+
computed as computed7,
|
|
4654
|
+
defineComponent as defineComponent19,
|
|
4655
|
+
h as h19,
|
|
4656
|
+
nextTick as nextTick4,
|
|
4657
|
+
onMounted as onMounted13,
|
|
4658
|
+
onUnmounted as onUnmounted12,
|
|
4659
|
+
ref as ref15,
|
|
4660
|
+
watch as watch8
|
|
4661
|
+
} from "vue";
|
|
4662
|
+
|
|
4663
|
+
// src/vue/components/ControlRenderer.ts
|
|
4664
|
+
import { Fragment as Fragment2, defineComponent as defineComponent18, h as h18 } from "vue";
|
|
4665
|
+
import { inject as inject2 } from "vue";
|
|
4666
|
+
var ControlRenderer = defineComponent18({
|
|
4667
|
+
name: "DialKitControlRenderer",
|
|
4668
|
+
props: {
|
|
4669
|
+
panelId: { type: String, required: true },
|
|
4670
|
+
controls: { type: Array, required: true },
|
|
4671
|
+
values: { type: Object, required: true },
|
|
4672
|
+
transitionDuration: Object
|
|
4673
|
+
},
|
|
4674
|
+
setup(props) {
|
|
4675
|
+
const shortcut = inject2(ShortcutKey, void 0);
|
|
4676
|
+
const renderControl = (control) => {
|
|
4677
|
+
const value = props.values[control.path];
|
|
4678
|
+
switch (control.type) {
|
|
4679
|
+
case "slider":
|
|
4680
|
+
return h18(Slider, {
|
|
4681
|
+
key: control.path,
|
|
4682
|
+
label: control.label,
|
|
4683
|
+
value,
|
|
4684
|
+
min: control.min,
|
|
4685
|
+
max: control.max,
|
|
4686
|
+
step: control.step,
|
|
4687
|
+
shortcut: control.shortcut,
|
|
4688
|
+
shortcutActive: shortcut?.activePanelId.value === props.panelId && shortcut.activePath.value === control.path,
|
|
4689
|
+
onChange: (next) => DialStore.updateValue(props.panelId, control.path, next)
|
|
4690
|
+
});
|
|
4691
|
+
case "toggle":
|
|
4692
|
+
return h18(Toggle, {
|
|
4693
|
+
key: control.path,
|
|
4694
|
+
label: control.label,
|
|
4695
|
+
checked: value,
|
|
4696
|
+
shortcut: control.shortcut,
|
|
4697
|
+
shortcutActive: shortcut?.activePanelId.value === props.panelId && shortcut.activePath.value === control.path,
|
|
4698
|
+
onChange: (next) => DialStore.updateValue(props.panelId, control.path, next)
|
|
4699
|
+
});
|
|
4700
|
+
case "spring":
|
|
4701
|
+
return h18(SpringControl, {
|
|
4702
|
+
key: control.path,
|
|
4703
|
+
panelId: props.panelId,
|
|
4704
|
+
path: control.path,
|
|
4705
|
+
label: control.label,
|
|
4706
|
+
spring: value,
|
|
4707
|
+
onChange: (next) => DialStore.updateValue(props.panelId, control.path, next)
|
|
4708
|
+
});
|
|
4709
|
+
case "transition":
|
|
4710
|
+
return h18(TransitionControl, {
|
|
4711
|
+
key: control.path,
|
|
4712
|
+
panelId: props.panelId,
|
|
4713
|
+
path: control.path,
|
|
4714
|
+
label: control.label,
|
|
4715
|
+
value,
|
|
4716
|
+
durationControl: props.transitionDuration,
|
|
4717
|
+
onChange: (next) => DialStore.updateValue(props.panelId, control.path, next)
|
|
4718
|
+
});
|
|
4719
|
+
case "folder":
|
|
4720
|
+
return h18(Folder, {
|
|
4721
|
+
key: control.path,
|
|
4722
|
+
title: control.label,
|
|
4723
|
+
defaultOpen: control.defaultOpen ?? true
|
|
4724
|
+
}, { default: () => (control.children ?? []).map(renderControl) });
|
|
4725
|
+
case "text":
|
|
4726
|
+
return h18(TextControl, {
|
|
4727
|
+
key: control.path,
|
|
4728
|
+
label: control.label,
|
|
4729
|
+
value,
|
|
4730
|
+
placeholder: control.placeholder,
|
|
4731
|
+
onChange: (next) => DialStore.updateValue(props.panelId, control.path, next)
|
|
4732
|
+
});
|
|
4733
|
+
case "select":
|
|
4734
|
+
return h18(SelectControl, {
|
|
4735
|
+
key: control.path,
|
|
4736
|
+
label: control.label,
|
|
4737
|
+
value,
|
|
4738
|
+
options: control.options ?? [],
|
|
4739
|
+
onChange: (next) => DialStore.updateValue(props.panelId, control.path, next)
|
|
4740
|
+
});
|
|
4741
|
+
case "color":
|
|
4742
|
+
return h18(ColorControl, {
|
|
4743
|
+
key: control.path,
|
|
4744
|
+
label: control.label,
|
|
4745
|
+
value,
|
|
4746
|
+
onChange: (next) => DialStore.updateValue(props.panelId, control.path, next)
|
|
4747
|
+
});
|
|
4748
|
+
case "action":
|
|
4749
|
+
return h18("button", {
|
|
4750
|
+
key: control.path,
|
|
4751
|
+
class: "dialkit-button",
|
|
4752
|
+
onClick: () => DialStore.triggerAction(props.panelId, control.path)
|
|
4753
|
+
}, control.label);
|
|
4754
|
+
default:
|
|
4755
|
+
return null;
|
|
4756
|
+
}
|
|
4757
|
+
};
|
|
4758
|
+
return () => h18(Fragment2, null, props.controls.map(renderControl));
|
|
4759
|
+
}
|
|
4760
|
+
});
|
|
4761
|
+
|
|
4762
|
+
// src/vue/components/Timeline/DialTimeline.ts
|
|
4763
|
+
var DRAG_THRESHOLD_PX = 3;
|
|
4764
|
+
var MAJOR_TICK_TARGET_PX = 140;
|
|
4765
|
+
var MILLISECOND_STEP = 1e-3;
|
|
4766
|
+
var SECOND_TICK_STEPS = [
|
|
4767
|
+
1e-3,
|
|
4768
|
+
2e-3,
|
|
4769
|
+
5e-3,
|
|
4770
|
+
0.01,
|
|
4771
|
+
0.02,
|
|
4772
|
+
0.05,
|
|
4773
|
+
0.1,
|
|
4774
|
+
0.2,
|
|
4775
|
+
0.5,
|
|
4776
|
+
1,
|
|
4777
|
+
2,
|
|
4778
|
+
5,
|
|
4779
|
+
10,
|
|
4780
|
+
15,
|
|
4781
|
+
30,
|
|
4782
|
+
60,
|
|
4783
|
+
120,
|
|
4784
|
+
300,
|
|
4785
|
+
600
|
|
4786
|
+
];
|
|
4787
|
+
var MIN_TIMELINE_MAX_ZOOM = 8;
|
|
4788
|
+
var PLAYHEAD_FLAG_WIDTH = 52;
|
|
4789
|
+
var POPOVER_WIDTH = 280;
|
|
4790
|
+
var ZOOM_DRAG_DISTANCE = 180;
|
|
4791
|
+
var DialTimeline = defineComponent19({
|
|
4792
|
+
name: "DialKitTimeline",
|
|
4793
|
+
props: {
|
|
4794
|
+
theme: { type: String, default: "system" },
|
|
4795
|
+
defaultVisible: { type: Boolean, default: true },
|
|
4796
|
+
visible: {
|
|
4797
|
+
type: Boolean,
|
|
4798
|
+
default: void 0
|
|
4799
|
+
},
|
|
4800
|
+
onVisibilityChange: Function,
|
|
4801
|
+
defaultOpen: { type: Boolean, default: true },
|
|
4802
|
+
productionEnabled: { type: Boolean, default: isDevDefault }
|
|
4803
|
+
},
|
|
4804
|
+
setup(props) {
|
|
4805
|
+
const timelines = ref15(TimelineStore.getTimelines());
|
|
4806
|
+
const dockVisible = ref15(TimelineUiStore.getVisible());
|
|
4807
|
+
const mounted = ref15(false);
|
|
4808
|
+
const controllerId = /* @__PURE__ */ Symbol("dialkit-timeline-visibility");
|
|
4809
|
+
let unsubscribeTimelines;
|
|
4810
|
+
let unsubscribeVisibility;
|
|
4811
|
+
let unregisterController;
|
|
4812
|
+
onMounted13(() => {
|
|
4813
|
+
mounted.value = true;
|
|
4814
|
+
unsubscribeVisibility = TimelineUiStore.subscribe(() => {
|
|
4815
|
+
dockVisible.value = TimelineUiStore.getVisible();
|
|
4816
|
+
});
|
|
4817
|
+
unregisterController = TimelineUiStore.registerController(controllerId, {
|
|
4818
|
+
visible: props.visible,
|
|
4819
|
+
defaultVisible: props.defaultVisible,
|
|
4820
|
+
onVisibilityChange: props.onVisibilityChange
|
|
4821
|
+
});
|
|
4822
|
+
dockVisible.value = TimelineUiStore.getVisible();
|
|
4823
|
+
unsubscribeTimelines = TimelineStore.subscribeGlobal(() => {
|
|
4824
|
+
timelines.value = TimelineStore.getTimelines();
|
|
4825
|
+
});
|
|
4826
|
+
});
|
|
4827
|
+
watch8(() => [props.visible, props.defaultVisible, props.onVisibilityChange], () => {
|
|
4828
|
+
TimelineUiStore.updateController(controllerId, {
|
|
4829
|
+
visible: props.visible,
|
|
4830
|
+
defaultVisible: props.defaultVisible,
|
|
4831
|
+
onVisibilityChange: props.onVisibilityChange
|
|
4832
|
+
});
|
|
4833
|
+
});
|
|
4834
|
+
onUnmounted12(() => {
|
|
4835
|
+
unregisterController?.();
|
|
4836
|
+
unsubscribeTimelines?.();
|
|
4837
|
+
unsubscribeVisibility?.();
|
|
4838
|
+
});
|
|
4839
|
+
return () => {
|
|
4840
|
+
if (!props.productionEnabled || !mounted.value || timelines.value.length === 0) return null;
|
|
4841
|
+
return h19(Teleport4, { to: "body" }, [
|
|
4842
|
+
h19("div", {
|
|
4843
|
+
class: "dialkit-root dialkit-timeline",
|
|
4844
|
+
"data-theme": props.theme,
|
|
4845
|
+
hidden: !dockVisible.value
|
|
4846
|
+
}, [
|
|
4847
|
+
h19("div", { class: "dialkit-timeline-dock" }, timelines.value.map((meta) => h19(TimelineSection, {
|
|
4848
|
+
key: meta.id,
|
|
4849
|
+
meta,
|
|
4850
|
+
defaultOpen: props.defaultOpen,
|
|
4851
|
+
theme: props.theme,
|
|
4852
|
+
dockVisible: dockVisible.value
|
|
4853
|
+
})))
|
|
4854
|
+
])
|
|
4855
|
+
]);
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
});
|
|
4859
|
+
var PlayPauseButton = defineComponent19({
|
|
4860
|
+
props: { id: { type: String, required: true } },
|
|
4861
|
+
setup(props) {
|
|
4862
|
+
const playing = ref15(TimelineStore.getTransport(props.id).playing);
|
|
4863
|
+
let unsubscribe;
|
|
4864
|
+
onMounted13(() => {
|
|
4865
|
+
unsubscribe = TimelineStore.subscribe(props.id, () => {
|
|
4866
|
+
playing.value = TimelineStore.getTransport(props.id).playing;
|
|
4867
|
+
});
|
|
4868
|
+
});
|
|
4869
|
+
onUnmounted12(() => unsubscribe?.());
|
|
4870
|
+
return () => {
|
|
4871
|
+
const label = playing.value ? "Pause" : "Play";
|
|
4872
|
+
const icon = playing.value ? h19(
|
|
4873
|
+
"svg",
|
|
4874
|
+
{ viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", style: iconStyle },
|
|
4875
|
+
ICON_PAUSE.map((path) => h19("path", { d: path, fill: "currentColor" }))
|
|
4876
|
+
) : h19("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", style: iconStyle }, [
|
|
4877
|
+
h19("path", { d: ICON_PLAY, fill: "currentColor" })
|
|
4878
|
+
]);
|
|
4879
|
+
return h19("button", {
|
|
4880
|
+
class: "dialkit-toolbar-add",
|
|
4881
|
+
title: label,
|
|
4882
|
+
"aria-label": label,
|
|
4883
|
+
onClick: () => playing.value ? TimelineStore.pause(props.id) : TimelineStore.play(props.id)
|
|
4884
|
+
}, [h19("span", { style: { position: "relative", width: "16px", height: "16px" } }, [icon])]);
|
|
4885
|
+
};
|
|
4886
|
+
}
|
|
4887
|
+
});
|
|
4888
|
+
var iconStyle = {
|
|
4889
|
+
position: "absolute",
|
|
4890
|
+
inset: 0,
|
|
4891
|
+
width: "16px",
|
|
4892
|
+
height: "16px",
|
|
4893
|
+
color: "var(--dial-text-label)"
|
|
4894
|
+
};
|
|
4895
|
+
var TimelineOverview = defineComponent19({
|
|
4896
|
+
props: {
|
|
4897
|
+
id: { type: String, required: true },
|
|
4898
|
+
duration: { type: Number, required: true },
|
|
4899
|
+
viewStart: { type: Number, required: true },
|
|
4900
|
+
viewEnd: { type: Number, required: true },
|
|
4901
|
+
onNavigate: { type: Function, required: true }
|
|
4902
|
+
},
|
|
4903
|
+
setup(props) {
|
|
4904
|
+
const time = ref15(TimelineStore.getTransport(props.id).time);
|
|
4905
|
+
let scrub = null;
|
|
4906
|
+
let unsubscribe;
|
|
4907
|
+
onMounted13(() => {
|
|
4908
|
+
unsubscribe = TimelineStore.subscribe(props.id, () => {
|
|
4909
|
+
time.value = TimelineStore.getTransport(props.id).time;
|
|
4910
|
+
});
|
|
4911
|
+
});
|
|
4912
|
+
onUnmounted12(() => unsubscribe?.());
|
|
4913
|
+
const seek = (clientX) => {
|
|
4914
|
+
if (!scrub || scrub.rect.width <= 0 || props.duration <= 0) return;
|
|
4915
|
+
const next = clamp((clientX - scrub.rect.left) / scrub.rect.width * props.duration, 0, props.duration);
|
|
4916
|
+
TimelineStore.seek(props.id, next);
|
|
4917
|
+
props.onNavigate(next);
|
|
4918
|
+
};
|
|
4919
|
+
const finish = () => {
|
|
4920
|
+
if (scrub?.wasPlaying) TimelineStore.play(props.id);
|
|
4921
|
+
scrub = null;
|
|
4922
|
+
};
|
|
4923
|
+
return () => {
|
|
4924
|
+
const viewportWidth = props.duration > 0 ? (props.viewEnd - props.viewStart) / props.duration * 100 : 100;
|
|
4925
|
+
const playhead = props.duration > 0 ? time.value / props.duration * 100 : 0;
|
|
4926
|
+
return h19("div", {
|
|
4927
|
+
class: "dialkit-timeline-overview",
|
|
4928
|
+
title: "Drag to scrub the full timeline",
|
|
4929
|
+
onPointerdown: (event) => {
|
|
4930
|
+
event.preventDefault();
|
|
4931
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
4932
|
+
scrub = {
|
|
4933
|
+
wasPlaying: TimelineStore.getTransport(props.id).playing,
|
|
4934
|
+
rect: event.currentTarget.getBoundingClientRect()
|
|
4935
|
+
};
|
|
4936
|
+
TimelineStore.pause(props.id);
|
|
4937
|
+
seek(event.clientX);
|
|
4938
|
+
},
|
|
4939
|
+
onPointermove: (event) => scrub && seek(event.clientX),
|
|
4940
|
+
onPointerup: finish,
|
|
4941
|
+
onPointercancel: finish,
|
|
4942
|
+
onLostpointercapture: finish
|
|
4943
|
+
}, [
|
|
4944
|
+
h19("div", {
|
|
4945
|
+
class: "dialkit-timeline-overview-viewport",
|
|
4946
|
+
"data-zoomed": viewportWidth < 99.999 || void 0,
|
|
4947
|
+
style: { left: `${props.duration > 0 ? props.viewStart / props.duration * 100 : 0}%`, width: `${viewportWidth}%` }
|
|
4948
|
+
}),
|
|
4949
|
+
h19("div", { class: "dialkit-timeline-overview-progress", style: { width: `${playhead}%` } }),
|
|
4950
|
+
h19("div", { class: "dialkit-timeline-overview-playhead", style: { left: `${playhead}%` } })
|
|
4951
|
+
]);
|
|
4952
|
+
};
|
|
4953
|
+
}
|
|
4954
|
+
});
|
|
4955
|
+
var TimelinePlayheadFlag = defineComponent19({
|
|
4956
|
+
props: {
|
|
4957
|
+
id: { type: String, required: true },
|
|
4958
|
+
duration: { type: Number, required: true },
|
|
4959
|
+
pxPerSecond: { type: Number, required: true },
|
|
4960
|
+
viewStart: { type: Number, required: true },
|
|
4961
|
+
viewEnd: { type: Number, required: true },
|
|
4962
|
+
laneWidth: { type: Number, required: true },
|
|
4963
|
+
ruler: Object,
|
|
4964
|
+
headerClearStart: { type: Number, required: true },
|
|
4965
|
+
headerClearEnd: { type: Number, required: true },
|
|
4966
|
+
onResetView: { type: Function, required: true }
|
|
4967
|
+
},
|
|
4968
|
+
setup(props) {
|
|
4969
|
+
const time = ref15(TimelineStore.getTransport(props.id).time);
|
|
4970
|
+
let unsubscribe;
|
|
4971
|
+
let scrub = null;
|
|
4972
|
+
let cleanup = null;
|
|
4973
|
+
onMounted13(() => {
|
|
4974
|
+
unsubscribe = TimelineStore.subscribe(props.id, () => {
|
|
4975
|
+
time.value = TimelineStore.getTransport(props.id).time;
|
|
4976
|
+
});
|
|
4977
|
+
});
|
|
4978
|
+
onUnmounted12(() => {
|
|
4979
|
+
unsubscribe?.();
|
|
4980
|
+
cleanup?.();
|
|
4981
|
+
});
|
|
4982
|
+
const seek = (clientX) => {
|
|
4983
|
+
if (!scrub || scrub.rect.width <= 0) return;
|
|
4984
|
+
TimelineStore.seek(props.id, clamp(
|
|
4985
|
+
scrub.viewStart + (clientX - scrub.rect.left) / scrub.rect.width * (scrub.viewEnd - scrub.viewStart),
|
|
4986
|
+
scrub.viewStart,
|
|
4987
|
+
scrub.viewEnd
|
|
4988
|
+
));
|
|
4989
|
+
};
|
|
4990
|
+
return () => {
|
|
4991
|
+
if (time.value < props.viewStart || time.value > props.viewEnd || props.laneWidth <= 0) return null;
|
|
4992
|
+
const x = clamp((time.value - props.viewStart) * props.pxPerSecond, 0, props.laneWidth);
|
|
4993
|
+
const left = x - PLAYHEAD_FLAG_WIDTH / 2;
|
|
4994
|
+
const placement = left >= props.headerClearStart && left + PLAYHEAD_FLAG_WIDTH <= props.headerClearEnd ? "raised" : "lowered";
|
|
4995
|
+
return h19("div", {
|
|
4996
|
+
class: "dialkit-timeline-playhead-control",
|
|
4997
|
+
"data-edge": "center",
|
|
4998
|
+
"data-placement": placement,
|
|
4999
|
+
style: { left: `calc(var(--dial-timeline-label-w) + ${x}px)` },
|
|
5000
|
+
role: "slider",
|
|
5001
|
+
"aria-label": "Timeline current time",
|
|
5002
|
+
"aria-valuemin": 0,
|
|
5003
|
+
"aria-valuemax": props.duration,
|
|
5004
|
+
"aria-valuenow": time.value,
|
|
5005
|
+
title: "Drag to scrub the timeline",
|
|
5006
|
+
onPointerdown: (event) => {
|
|
5007
|
+
const rect = props.ruler?.getBoundingClientRect();
|
|
5008
|
+
if (!rect) return;
|
|
5009
|
+
event.preventDefault();
|
|
5010
|
+
event.stopPropagation();
|
|
5011
|
+
cleanup?.();
|
|
5012
|
+
const reset = event.shiftKey;
|
|
5013
|
+
scrub = {
|
|
5014
|
+
wasPlaying: TimelineStore.getTransport(props.id).playing,
|
|
5015
|
+
rect,
|
|
5016
|
+
viewStart: reset ? 0 : props.viewStart,
|
|
5017
|
+
viewEnd: reset ? props.duration : props.viewEnd
|
|
5018
|
+
};
|
|
5019
|
+
if (reset) props.onResetView();
|
|
5020
|
+
TimelineStore.pause(props.id);
|
|
5021
|
+
seek(event.clientX);
|
|
5022
|
+
const move = (next) => {
|
|
5023
|
+
next.preventDefault();
|
|
5024
|
+
seek(next.clientX);
|
|
5025
|
+
};
|
|
5026
|
+
const finish = () => {
|
|
5027
|
+
window.removeEventListener("pointermove", move);
|
|
5028
|
+
window.removeEventListener("pointerup", finish);
|
|
5029
|
+
window.removeEventListener("pointercancel", finish);
|
|
5030
|
+
if (scrub?.wasPlaying) TimelineStore.play(props.id);
|
|
5031
|
+
scrub = null;
|
|
5032
|
+
cleanup = null;
|
|
5033
|
+
};
|
|
5034
|
+
window.addEventListener("pointermove", move, { passive: false });
|
|
5035
|
+
window.addEventListener("pointerup", finish);
|
|
5036
|
+
window.addEventListener("pointercancel", finish);
|
|
5037
|
+
cleanup = finish;
|
|
5038
|
+
}
|
|
5039
|
+
}, [
|
|
5040
|
+
h19("div", { class: "dialkit-timeline-playhead-flag" }, time.value.toFixed(2)),
|
|
5041
|
+
h19("div", { class: "dialkit-timeline-playhead-stem" })
|
|
5042
|
+
]);
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5045
|
+
});
|
|
5046
|
+
function clampViewStart(start, duration, visibleDuration) {
|
|
5047
|
+
return clamp(start, 0, Math.max(0, duration - visibleDuration));
|
|
5048
|
+
}
|
|
5049
|
+
function formatRulerSeconds(time, step) {
|
|
5050
|
+
if (step >= 1 && Number.isInteger(time)) return formatClock(time);
|
|
5051
|
+
const decimals = Math.min(3, Math.max(1, Math.ceil(-Math.log10(step))));
|
|
5052
|
+
return `${time.toFixed(decimals)}s`;
|
|
5053
|
+
}
|
|
5054
|
+
var TimelineSection = defineComponent19({
|
|
5055
|
+
props: {
|
|
5056
|
+
meta: { type: Object, required: true },
|
|
5057
|
+
defaultOpen: { type: Boolean, required: true },
|
|
5058
|
+
theme: { type: String, required: true },
|
|
5059
|
+
dockVisible: { type: Boolean, required: true }
|
|
5060
|
+
},
|
|
5061
|
+
setup(props) {
|
|
5062
|
+
const open = ref15(props.defaultOpen);
|
|
5063
|
+
const copied = ref15(false);
|
|
5064
|
+
const popover = ref15(null);
|
|
5065
|
+
const collapsedGroups = ref15(/* @__PURE__ */ new Set());
|
|
5066
|
+
const expandedTracks = ref15(/* @__PURE__ */ new Set());
|
|
5067
|
+
const zoom = ref15(1);
|
|
5068
|
+
const viewStart = ref15(0);
|
|
5069
|
+
const values = ref15(DialStore.getValues(props.meta.id));
|
|
5070
|
+
const presets = ref15(DialStore.getPresets(props.meta.id));
|
|
5071
|
+
const activePresetId = ref15(DialStore.getActivePresetId(props.meta.id));
|
|
5072
|
+
const laneAreaRef = ref15(null);
|
|
5073
|
+
const titleRef = ref15(null);
|
|
5074
|
+
const actionsRef = ref15(null);
|
|
5075
|
+
const laneWidth = ref15(0);
|
|
5076
|
+
const flagClearRange = ref15({ start: 0, end: 0 });
|
|
5077
|
+
let unsubscribeValues;
|
|
5078
|
+
let resizeObserver;
|
|
5079
|
+
const measure = () => {
|
|
5080
|
+
if (!laneAreaRef.value || !titleRef.value || !actionsRef.value) return;
|
|
5081
|
+
const ruler = laneAreaRef.value.getBoundingClientRect();
|
|
5082
|
+
const title = titleRef.value.getBoundingClientRect();
|
|
5083
|
+
const actions = actionsRef.value.getBoundingClientRect();
|
|
5084
|
+
laneWidth.value = ruler.width;
|
|
5085
|
+
flagClearRange.value = {
|
|
5086
|
+
start: Math.round(title.right + 10 - ruler.left),
|
|
5087
|
+
end: Math.round(actions.left - 10 - ruler.left)
|
|
5088
|
+
};
|
|
5089
|
+
};
|
|
5090
|
+
const connectMeasure = async () => {
|
|
5091
|
+
resizeObserver?.disconnect();
|
|
5092
|
+
if (!open.value) return;
|
|
5093
|
+
await nextTick4();
|
|
5094
|
+
if (!laneAreaRef.value || !titleRef.value || !actionsRef.value) return;
|
|
5095
|
+
measure();
|
|
5096
|
+
resizeObserver = new ResizeObserver(measure);
|
|
5097
|
+
resizeObserver.observe(laneAreaRef.value);
|
|
5098
|
+
resizeObserver.observe(titleRef.value);
|
|
5099
|
+
resizeObserver.observe(actionsRef.value);
|
|
5100
|
+
};
|
|
5101
|
+
onMounted13(() => {
|
|
5102
|
+
unsubscribeValues = DialStore.subscribe(props.meta.id, () => {
|
|
5103
|
+
values.value = DialStore.getValues(props.meta.id);
|
|
5104
|
+
presets.value = DialStore.getPresets(props.meta.id);
|
|
5105
|
+
activePresetId.value = DialStore.getActivePresetId(props.meta.id);
|
|
5106
|
+
});
|
|
5107
|
+
void connectMeasure();
|
|
5108
|
+
});
|
|
5109
|
+
onUnmounted12(() => {
|
|
5110
|
+
unsubscribeValues?.();
|
|
5111
|
+
resizeObserver?.disconnect();
|
|
5112
|
+
});
|
|
5113
|
+
watch8(open, connectMeasure);
|
|
5114
|
+
watch8(() => props.dockVisible, (visible) => {
|
|
5115
|
+
if (!visible) popover.value = null;
|
|
5116
|
+
});
|
|
5117
|
+
const visibleDuration = computed7(() => props.meta.duration > 0 ? props.meta.duration / zoom.value : props.meta.duration);
|
|
5118
|
+
const safeViewStart = computed7(() => clampViewStart(viewStart.value, props.meta.duration, visibleDuration.value));
|
|
5119
|
+
const viewEnd = computed7(() => safeViewStart.value + visibleDuration.value);
|
|
5120
|
+
const pxPerSecond = computed7(() => visibleDuration.value > 0 && laneWidth.value > 0 ? laneWidth.value / visibleDuration.value : 0);
|
|
5121
|
+
const maxZoom = computed7(() => Math.max(
|
|
5122
|
+
MIN_TIMELINE_MAX_ZOOM,
|
|
5123
|
+
laneWidth.value > 0 && props.meta.duration > 0 ? MAJOR_TICK_TARGET_PX * props.meta.duration / (MILLISECOND_STEP * 10 * laneWidth.value) : MIN_TIMELINE_MAX_ZOOM
|
|
5124
|
+
));
|
|
5125
|
+
watch8(maxZoom, (next) => {
|
|
5126
|
+
zoom.value = clamp(zoom.value, 1, next);
|
|
5127
|
+
}, { immediate: true });
|
|
5128
|
+
watch8([() => props.meta.duration, zoom], () => {
|
|
5129
|
+
viewStart.value = clampViewStart(viewStart.value, props.meta.duration, props.meta.duration / zoom.value);
|
|
5130
|
+
});
|
|
5131
|
+
const centerViewAt = (time) => {
|
|
5132
|
+
if (zoom.value <= 1 || props.meta.duration <= 0) return;
|
|
5133
|
+
const duration = props.meta.duration / zoom.value;
|
|
5134
|
+
viewStart.value = clampViewStart(time - duration / 2, props.meta.duration, duration);
|
|
5135
|
+
};
|
|
5136
|
+
const resetView = () => {
|
|
5137
|
+
zoom.value = 1;
|
|
5138
|
+
viewStart.value = 0;
|
|
5139
|
+
};
|
|
5140
|
+
let zoomDrag = null;
|
|
5141
|
+
let rulerScrub = null;
|
|
5142
|
+
let trackScrub = null;
|
|
5143
|
+
const seekRuler = (clientX) => {
|
|
5144
|
+
if (!rulerScrub || rulerScrub.rect.width <= 0) return;
|
|
5145
|
+
TimelineStore.seek(props.meta.id, clamp(
|
|
5146
|
+
rulerScrub.viewStart + (clientX - rulerScrub.rect.left) / rulerScrub.rect.width * rulerScrub.visibleDuration,
|
|
5147
|
+
rulerScrub.viewStart,
|
|
5148
|
+
rulerScrub.viewStart + rulerScrub.visibleDuration
|
|
5149
|
+
));
|
|
5150
|
+
};
|
|
5151
|
+
const seekTrack = (clientX) => {
|
|
5152
|
+
if (!trackScrub || trackScrub.rect.width <= 0) return;
|
|
5153
|
+
TimelineStore.seek(props.meta.id, clamp(
|
|
5154
|
+
trackScrub.viewStart + (clientX - trackScrub.rect.left) / trackScrub.rect.width * trackScrub.visibleDuration,
|
|
5155
|
+
trackScrub.viewStart,
|
|
5156
|
+
trackScrub.viewStart + trackScrub.visibleDuration
|
|
5157
|
+
));
|
|
5158
|
+
};
|
|
5159
|
+
const finishRuler = () => {
|
|
5160
|
+
if (rulerScrub?.wasPlaying) TimelineStore.play(props.meta.id);
|
|
5161
|
+
rulerScrub = null;
|
|
5162
|
+
zoomDrag = null;
|
|
5163
|
+
};
|
|
5164
|
+
const finishTrack = () => {
|
|
5165
|
+
if (trackScrub?.wasPlaying) TimelineStore.play(props.meta.id);
|
|
5166
|
+
trackScrub = null;
|
|
5167
|
+
};
|
|
5168
|
+
const handleCopy = () => {
|
|
5169
|
+
const normalized = normalizeTimelineValuesForCopy(DialStore.getValues(props.meta.id), props.meta.clips);
|
|
5170
|
+
void navigator.clipboard.writeText(buildCopyInstruction("useDialTimeline", props.meta.name, normalized));
|
|
5171
|
+
copied.value = true;
|
|
5172
|
+
window.setTimeout(() => {
|
|
5173
|
+
copied.value = false;
|
|
5174
|
+
}, 1500);
|
|
5175
|
+
};
|
|
5176
|
+
const handleAddPreset = () => DialStore.savePreset(props.meta.id, `Version ${presets.value.length + 2}`);
|
|
5177
|
+
const closePopover = () => {
|
|
5178
|
+
popover.value = null;
|
|
5179
|
+
};
|
|
5180
|
+
const openClipPopover = (clip, rect, stepKey) => {
|
|
5181
|
+
const target = stepKey ? `${clip.key}.${stepKey}` : clip.key;
|
|
5182
|
+
if (getClipControls(props.meta.id, target, stepKey ? void 0 : clipPopoverExclusions(clip)).length === 0) return;
|
|
5183
|
+
popover.value = popover.value?.clip.key === clip.key && popover.value.stepKey === stepKey ? null : {
|
|
5184
|
+
clip,
|
|
5185
|
+
stepKey,
|
|
5186
|
+
anchor: { left: rect.left, top: rect.top, right: rect.right, bottom: rect.bottom, width: rect.width, height: rect.height }
|
|
5187
|
+
};
|
|
5188
|
+
};
|
|
5189
|
+
const toggleSet = (state, key) => {
|
|
5190
|
+
const next = new Set(state.value);
|
|
5191
|
+
if (next.has(key)) next.delete(key);
|
|
5192
|
+
else next.add(key);
|
|
5193
|
+
state.value = next;
|
|
5194
|
+
};
|
|
5195
|
+
const toggleTracks = (key) => toggleSet(expandedTracks, key);
|
|
5196
|
+
const toggleGroup = (key) => toggleSet(collapsedGroups, key);
|
|
5197
|
+
const handleBarClick = (clip, rect, stepKey) => {
|
|
5198
|
+
if (!stepKey && clip.tracks?.length) toggleTracks(clip.key);
|
|
5199
|
+
else openClipPopover(clip, rect, stepKey);
|
|
5200
|
+
};
|
|
5201
|
+
const ticks = computed7(() => {
|
|
5202
|
+
const raw = pxPerSecond.value > 0 ? MAJOR_TICK_TARGET_PX / pxPerSecond.value : 1;
|
|
5203
|
+
const adaptive = SECOND_TICK_STEPS.find((step) => step >= raw) ?? SECOND_TICK_STEPS[SECOND_TICK_STEPS.length - 1];
|
|
5204
|
+
const majorStep = zoom.value < 1.5 && props.meta.duration >= 1 ? Math.max(1, adaptive) : adaptive;
|
|
5205
|
+
const fineStep = majorStep / 10;
|
|
5206
|
+
const major = [];
|
|
5207
|
+
const medium = [];
|
|
5208
|
+
const fine = [];
|
|
5209
|
+
for (let time = Math.ceil((safeViewStart.value - 1e-6) / majorStep) * majorStep; time <= viewEnd.value + 1e-6; time += majorStep) {
|
|
5210
|
+
major.push(Number(time.toFixed(4)));
|
|
5211
|
+
}
|
|
5212
|
+
const first = Math.ceil((safeViewStart.value - 1e-6) / fineStep);
|
|
5213
|
+
const last = Math.floor((viewEnd.value + 1e-6) / fineStep);
|
|
5214
|
+
for (let index = first; index <= last; index++) {
|
|
5215
|
+
if (index % 10 === 0) continue;
|
|
5216
|
+
const tick = Number((index * fineStep).toFixed(6));
|
|
5217
|
+
if (index % 5 === 0) medium.push(tick);
|
|
5218
|
+
else fine.push(tick);
|
|
5219
|
+
}
|
|
5220
|
+
return { major, medium, fine, majorStep };
|
|
5221
|
+
});
|
|
5222
|
+
const renderRows = () => {
|
|
5223
|
+
const rows = [];
|
|
5224
|
+
let lastGroup;
|
|
5225
|
+
for (const clip of props.meta.clips) {
|
|
5226
|
+
if (clip.group !== lastGroup) {
|
|
5227
|
+
lastGroup = clip.group;
|
|
5228
|
+
if (clip.group) {
|
|
5229
|
+
const group = clip.group;
|
|
5230
|
+
const collapsed = collapsedGroups.value.has(group);
|
|
5231
|
+
rows.push(h19("div", { key: `group:${group}`, class: "dialkit-timeline-row dialkit-timeline-group-row" }, [
|
|
5232
|
+
h19("div", { class: "dialkit-timeline-label" }, [
|
|
5233
|
+
h19("button", {
|
|
5234
|
+
class: "dialkit-timeline-group-toggle",
|
|
5235
|
+
"data-open": !collapsed,
|
|
5236
|
+
title: collapsed ? "Expand layer" : "Collapse layer",
|
|
5237
|
+
onClick: () => toggleGroup(group)
|
|
5238
|
+
}, [chevronIcon()]),
|
|
5239
|
+
h19("span", formatLabel(group))
|
|
5240
|
+
]),
|
|
5241
|
+
h19("div", { class: "dialkit-timeline-lane" })
|
|
5242
|
+
]));
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
if (clip.group && collapsedGroups.value.has(clip.group)) continue;
|
|
5246
|
+
const isProps = Boolean(clip.tracks?.length);
|
|
5247
|
+
const tracksOpen = isProps && expandedTracks.value.has(clip.key);
|
|
5248
|
+
const stat = computeClipStaticFromValues(values.value, clip, props.meta.duration);
|
|
5249
|
+
const selected = popover.value?.clip.key === clip.key;
|
|
5250
|
+
rows.push(h19("div", { key: clip.key, class: "dialkit-timeline-row", "data-grouped": clip.group ? "" : void 0 }, [
|
|
5251
|
+
h19("div", { class: "dialkit-timeline-label" }, [
|
|
5252
|
+
isProps ? h19("button", {
|
|
5253
|
+
class: "dialkit-timeline-group-toggle",
|
|
5254
|
+
"data-open": tracksOpen,
|
|
5255
|
+
title: tracksOpen ? "Collapse properties" : "Expand properties",
|
|
5256
|
+
onClick: (event) => {
|
|
5257
|
+
event.stopPropagation();
|
|
5258
|
+
toggleTracks(clip.key);
|
|
5259
|
+
}
|
|
5260
|
+
}, [chevronIcon()]) : null,
|
|
5261
|
+
clip.label
|
|
5262
|
+
]),
|
|
5263
|
+
h19("div", { class: "dialkit-timeline-lane" }, [h19(TimelineClip, {
|
|
5264
|
+
timelineId: props.meta.id,
|
|
5265
|
+
clip,
|
|
5266
|
+
at: stat.at,
|
|
5267
|
+
duration: stat.duration,
|
|
5268
|
+
loop: stat.loop,
|
|
5269
|
+
steps: clip.stepKeys?.length ? stat.tracks[0]?.steps : void 0,
|
|
5270
|
+
fixedDuration: isProps ? true : stat.isPhysics,
|
|
5271
|
+
composite: isProps,
|
|
5272
|
+
pxPerSecond: pxPerSecond.value,
|
|
5273
|
+
viewStart: safeViewStart.value,
|
|
5274
|
+
timelineDuration: props.meta.duration,
|
|
5275
|
+
selected,
|
|
5276
|
+
selectedStepKey: selected ? popover.value?.stepKey : void 0,
|
|
5277
|
+
onClick: handleBarClick,
|
|
5278
|
+
onDrag: closePopover
|
|
5279
|
+
})])
|
|
5280
|
+
]));
|
|
5281
|
+
if (!tracksOpen) continue;
|
|
5282
|
+
for (const trackRef of clip.tracks ?? []) {
|
|
5283
|
+
const track = stat.tracks.find((candidate) => candidate.prop === trackRef.prop);
|
|
5284
|
+
if (!track) continue;
|
|
5285
|
+
const trackKey = `${clip.key}.${trackRef.prop}`;
|
|
5286
|
+
const trackMeta = {
|
|
5287
|
+
key: trackKey,
|
|
5288
|
+
label: `${clip.label} \xB7 ${formatLabel(trackRef.prop)}`,
|
|
5289
|
+
color: clip.color,
|
|
5290
|
+
loop: clip.loop,
|
|
5291
|
+
group: clip.group,
|
|
5292
|
+
stepKeys: trackRef.stepKeys
|
|
5293
|
+
};
|
|
5294
|
+
const trackSelected = popover.value?.clip.key === trackKey;
|
|
5295
|
+
rows.push(h19("div", { key: trackKey, class: "dialkit-timeline-row dialkit-timeline-track-row", "data-grouped": clip.group ? "" : void 0 }, [
|
|
5296
|
+
h19("div", { class: "dialkit-timeline-label" }, formatLabel(trackRef.prop)),
|
|
5297
|
+
h19("div", { class: "dialkit-timeline-lane" }, [h19(TimelineClip, {
|
|
5298
|
+
timelineId: props.meta.id,
|
|
5299
|
+
clip: trackMeta,
|
|
5300
|
+
at: stat.at + track.delay,
|
|
5301
|
+
duration: track.duration,
|
|
5302
|
+
loop: stat.loop,
|
|
5303
|
+
steps: trackRef.stepKeys?.length ? track.steps : void 0,
|
|
5304
|
+
fixedDuration: !trackRef.stepKeys?.length && track.steps[0]?.isPhysics === true,
|
|
5305
|
+
baseAt: stat.at,
|
|
5306
|
+
delayMode: true,
|
|
5307
|
+
pxPerSecond: pxPerSecond.value,
|
|
5308
|
+
viewStart: safeViewStart.value,
|
|
5309
|
+
timelineDuration: props.meta.duration,
|
|
5310
|
+
selected: trackSelected,
|
|
5311
|
+
selectedStepKey: trackSelected ? popover.value?.stepKey : void 0,
|
|
5312
|
+
onClick: openClipPopover,
|
|
5313
|
+
onDrag: closePopover
|
|
5314
|
+
})])
|
|
5315
|
+
]));
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
return rows;
|
|
5319
|
+
};
|
|
5320
|
+
return () => h19("div", { class: "dialkit-timeline-section" }, [
|
|
5321
|
+
h19("div", { class: "dialkit-timeline-header", "data-open": open.value || void 0 }, [
|
|
5322
|
+
h19("div", { class: "dialkit-timeline-identity" }, [
|
|
5323
|
+
h19("span", { ref: titleRef, class: "dialkit-timeline-title" }, props.meta.name)
|
|
5324
|
+
]),
|
|
5325
|
+
!open.value ? h19(TimelineOverview, {
|
|
5326
|
+
id: props.meta.id,
|
|
5327
|
+
duration: props.meta.duration,
|
|
5328
|
+
viewStart: safeViewStart.value,
|
|
5329
|
+
viewEnd: viewEnd.value,
|
|
5330
|
+
onNavigate: centerViewAt
|
|
5331
|
+
}) : null,
|
|
5332
|
+
h19("div", { ref: actionsRef, class: "dialkit-timeline-actions" }, [
|
|
5333
|
+
h19(PlayPauseButton, { id: props.meta.id }),
|
|
5334
|
+
h19("button", { class: "dialkit-toolbar-add", title: "Add timeline version", "aria-label": "Add timeline version", onClick: handleAddPreset }, [
|
|
5335
|
+
h19(
|
|
5336
|
+
"svg",
|
|
5337
|
+
{ viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2.5", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" },
|
|
5338
|
+
ICON_ADD_PRESET.map((path) => h19("path", { d: path }))
|
|
5339
|
+
)
|
|
5340
|
+
]),
|
|
5341
|
+
h19(PresetManager, { panelId: props.meta.id, presets: presets.value, activePresetId: activePresetId.value }),
|
|
5342
|
+
h19("button", {
|
|
5343
|
+
class: "dialkit-toolbar-add",
|
|
5344
|
+
title: "Copy parameters",
|
|
5345
|
+
"aria-label": copied.value ? "Copied parameters" : "Copy parameters",
|
|
5346
|
+
onClick: handleCopy
|
|
5347
|
+
}, [h19("span", { style: { position: "relative", width: "16px", height: "16px" } }, [
|
|
5348
|
+
copied.value ? h19("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", style: iconStyle }, [h19("path", { d: ICON_CHECK })]) : h19("svg", { viewBox: "0 0 24 24", fill: "none", style: iconStyle }, [
|
|
5349
|
+
h19("path", { d: ICON_CLIPBOARD.board, stroke: "currentColor", "stroke-width": "2", "stroke-linejoin": "round" }),
|
|
5350
|
+
h19("path", { d: ICON_CLIPBOARD.sparkle, fill: "currentColor" }),
|
|
5351
|
+
h19("path", { d: ICON_CLIPBOARD.body, stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" })
|
|
5352
|
+
])
|
|
5353
|
+
])]),
|
|
5354
|
+
h19("button", {
|
|
5355
|
+
class: "dialkit-timeline-chevron",
|
|
5356
|
+
"data-open": open.value,
|
|
5357
|
+
"aria-expanded": open.value,
|
|
5358
|
+
title: open.value ? "Collapse timeline" : "Expand timeline",
|
|
5359
|
+
onClick: () => {
|
|
5360
|
+
open.value = !open.value;
|
|
5361
|
+
}
|
|
5362
|
+
}, [chevronIcon()])
|
|
5363
|
+
])
|
|
5364
|
+
]),
|
|
5365
|
+
open.value ? h19("div", {
|
|
5366
|
+
class: "dialkit-timeline-body",
|
|
5367
|
+
onPointerdown: (event) => {
|
|
5368
|
+
const target = event.target;
|
|
5369
|
+
if (target.closest(".dialkit-timeline-label, button")) return;
|
|
5370
|
+
if (!event.shiftKey && target.closest(".dialkit-timeline-clip")) return;
|
|
5371
|
+
const rect = laneAreaRef.value?.getBoundingClientRect();
|
|
5372
|
+
if (!rect) return;
|
|
5373
|
+
event.preventDefault();
|
|
5374
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
5375
|
+
const reset = event.shiftKey;
|
|
5376
|
+
trackScrub = {
|
|
5377
|
+
wasPlaying: TimelineStore.getTransport(props.meta.id).playing,
|
|
5378
|
+
rect,
|
|
5379
|
+
viewStart: reset ? 0 : safeViewStart.value,
|
|
5380
|
+
visibleDuration: reset ? props.meta.duration : visibleDuration.value
|
|
5381
|
+
};
|
|
5382
|
+
if (reset) resetView();
|
|
5383
|
+
popover.value = null;
|
|
5384
|
+
TimelineStore.pause(props.meta.id);
|
|
5385
|
+
seekTrack(event.clientX);
|
|
5386
|
+
},
|
|
5387
|
+
onPointermove: (event) => trackScrub && seekTrack(event.clientX),
|
|
5388
|
+
onPointerup: finishTrack,
|
|
5389
|
+
onPointercancel: finishTrack,
|
|
5390
|
+
onLostpointercapture: finishTrack
|
|
5391
|
+
}, [h19("div", { class: "dialkit-timeline-grid" }, [
|
|
5392
|
+
h19("div", { class: "dialkit-timeline-row dialkit-timeline-ruler-row" }, [
|
|
5393
|
+
h19("div", { class: "dialkit-timeline-label" }),
|
|
5394
|
+
h19("div", {
|
|
5395
|
+
ref: laneAreaRef,
|
|
5396
|
+
class: "dialkit-timeline-ruler",
|
|
5397
|
+
title: "Drag to seek \xB7 Option-drag to zoom \xB7 Shift-drag to reset zoom",
|
|
5398
|
+
onPointerdown: (event) => {
|
|
5399
|
+
event.preventDefault();
|
|
5400
|
+
event.stopPropagation();
|
|
5401
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
5402
|
+
if (rect.width <= 0) return;
|
|
5403
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
5404
|
+
if (!event.altKey) {
|
|
5405
|
+
const reset = event.shiftKey;
|
|
5406
|
+
rulerScrub = {
|
|
5407
|
+
wasPlaying: TimelineStore.getTransport(props.meta.id).playing,
|
|
5408
|
+
rect,
|
|
5409
|
+
viewStart: reset ? 0 : safeViewStart.value,
|
|
5410
|
+
visibleDuration: reset ? props.meta.duration : visibleDuration.value
|
|
5411
|
+
};
|
|
5412
|
+
if (reset) resetView();
|
|
5413
|
+
TimelineStore.pause(props.meta.id);
|
|
5414
|
+
seekRuler(event.clientX);
|
|
5415
|
+
return;
|
|
5416
|
+
}
|
|
5417
|
+
const ratio = clamp((event.clientX - rect.left) / rect.width, 0, 1);
|
|
5418
|
+
zoomDrag = {
|
|
5419
|
+
pointerX: event.clientX,
|
|
5420
|
+
zoom: zoom.value,
|
|
5421
|
+
anchorRatio: ratio,
|
|
5422
|
+
anchorTime: safeViewStart.value + ratio * visibleDuration.value,
|
|
5423
|
+
moved: false
|
|
5424
|
+
};
|
|
5425
|
+
},
|
|
5426
|
+
onPointermove: (event) => {
|
|
5427
|
+
if (rulerScrub) {
|
|
5428
|
+
seekRuler(event.clientX);
|
|
5429
|
+
return;
|
|
5430
|
+
}
|
|
5431
|
+
if (!zoomDrag || props.meta.duration <= 0) return;
|
|
5432
|
+
const dx = event.clientX - zoomDrag.pointerX;
|
|
5433
|
+
if (!zoomDrag.moved && Math.abs(dx) <= DRAG_THRESHOLD_PX) return;
|
|
5434
|
+
zoomDrag.moved = true;
|
|
5435
|
+
const nextZoom = clamp(zoomDrag.zoom * Math.exp(dx / ZOOM_DRAG_DISTANCE), 1, maxZoom.value);
|
|
5436
|
+
const duration = props.meta.duration / nextZoom;
|
|
5437
|
+
zoom.value = nextZoom;
|
|
5438
|
+
viewStart.value = clampViewStart(zoomDrag.anchorTime - zoomDrag.anchorRatio * duration, props.meta.duration, duration);
|
|
5439
|
+
},
|
|
5440
|
+
onPointerup: finishRuler,
|
|
5441
|
+
onPointercancel: finishRuler,
|
|
5442
|
+
onLostpointercapture: finishRuler
|
|
5443
|
+
}, [
|
|
5444
|
+
...ticks.value.fine.map((time) => h19("div", { key: `fine:${time}`, class: "dialkit-timeline-tick dialkit-timeline-tick-fine", style: { left: `${(time - safeViewStart.value) * pxPerSecond.value}px` } })),
|
|
5445
|
+
...ticks.value.medium.map((time) => h19("div", { key: `medium:${time}`, class: "dialkit-timeline-tick dialkit-timeline-tick-medium", style: { left: `${(time - safeViewStart.value) * pxPerSecond.value}px` } })),
|
|
5446
|
+
...ticks.value.major.map((time) => h19("div", { key: time, class: "dialkit-timeline-tick", style: { left: `${(time - safeViewStart.value) * pxPerSecond.value}px` } }, [
|
|
5447
|
+
h19("span", { class: "dialkit-timeline-tick-label" }, formatRulerSeconds(time, ticks.value.majorStep))
|
|
5448
|
+
]))
|
|
5449
|
+
])
|
|
5450
|
+
]),
|
|
5451
|
+
...renderRows(),
|
|
5452
|
+
pxPerSecond.value > 0 ? h19(TimelinePlayheadFlag, {
|
|
5453
|
+
id: props.meta.id,
|
|
5454
|
+
duration: props.meta.duration,
|
|
5455
|
+
pxPerSecond: pxPerSecond.value,
|
|
5456
|
+
viewStart: safeViewStart.value,
|
|
5457
|
+
viewEnd: viewEnd.value,
|
|
5458
|
+
laneWidth: laneWidth.value,
|
|
5459
|
+
ruler: laneAreaRef.value ?? void 0,
|
|
5460
|
+
headerClearStart: flagClearRange.value.start,
|
|
5461
|
+
headerClearEnd: flagClearRange.value.end,
|
|
5462
|
+
onResetView: resetView
|
|
5463
|
+
}) : null
|
|
5464
|
+
])]) : null,
|
|
5465
|
+
popover.value ? h19(ClipPopover, {
|
|
5466
|
+
panelId: props.meta.id,
|
|
5467
|
+
popover: popover.value,
|
|
5468
|
+
values: values.value,
|
|
5469
|
+
theme: props.theme,
|
|
5470
|
+
onClose: closePopover
|
|
5471
|
+
}) : null
|
|
5472
|
+
]);
|
|
5473
|
+
}
|
|
5474
|
+
});
|
|
5475
|
+
function chevronIcon() {
|
|
5476
|
+
return h19("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2.5", "stroke-linecap": "round", "stroke-linejoin": "round" }, [
|
|
5477
|
+
h19("path", { d: ICON_CHEVRON })
|
|
5478
|
+
]);
|
|
5479
|
+
}
|
|
5480
|
+
var ClipPopover = defineComponent19({
|
|
5481
|
+
props: {
|
|
5482
|
+
panelId: { type: String, required: true },
|
|
5483
|
+
popover: { type: Object, required: true },
|
|
5484
|
+
values: { type: Object, required: true },
|
|
5485
|
+
theme: { type: String, required: true },
|
|
5486
|
+
onClose: { type: Function, required: true }
|
|
5487
|
+
},
|
|
5488
|
+
setup(props) {
|
|
5489
|
+
const element = ref15(null);
|
|
5490
|
+
const naturalHeight = ref15(0);
|
|
5491
|
+
const viewport = ref15(readViewport());
|
|
5492
|
+
let observer;
|
|
5493
|
+
const measure = () => {
|
|
5494
|
+
if (element.value) naturalHeight.value = element.value.scrollHeight + 2;
|
|
5495
|
+
};
|
|
5496
|
+
const updateViewport = () => {
|
|
5497
|
+
viewport.value = readViewport();
|
|
5498
|
+
};
|
|
5499
|
+
const outside = (event) => {
|
|
5500
|
+
const target = event.target;
|
|
5501
|
+
if (element.value?.contains(target) || target.closest?.(".dialkit-timeline-clip") || target.closest?.(".dialkit-timeline-label")) return;
|
|
5502
|
+
props.onClose();
|
|
5503
|
+
};
|
|
5504
|
+
const keydown = (event) => {
|
|
5505
|
+
if (event.key === "Escape") props.onClose();
|
|
5506
|
+
};
|
|
5507
|
+
onMounted13(() => {
|
|
5508
|
+
measure();
|
|
5509
|
+
observer = new ResizeObserver(measure);
|
|
5510
|
+
if (element.value) observer.observe(element.value.querySelector(".dialkit-timeline-popover-body") ?? element.value);
|
|
5511
|
+
window.addEventListener("resize", updateViewport);
|
|
5512
|
+
window.visualViewport?.addEventListener("resize", updateViewport);
|
|
5513
|
+
window.visualViewport?.addEventListener("scroll", updateViewport);
|
|
5514
|
+
document.addEventListener("pointerdown", outside, true);
|
|
5515
|
+
document.addEventListener("keydown", keydown);
|
|
5516
|
+
});
|
|
5517
|
+
onUnmounted12(() => {
|
|
5518
|
+
observer?.disconnect();
|
|
5519
|
+
window.removeEventListener("resize", updateViewport);
|
|
5520
|
+
window.visualViewport?.removeEventListener("resize", updateViewport);
|
|
5521
|
+
window.visualViewport?.removeEventListener("scroll", updateViewport);
|
|
5522
|
+
document.removeEventListener("pointerdown", outside, true);
|
|
5523
|
+
document.removeEventListener("keydown", keydown);
|
|
5524
|
+
});
|
|
5525
|
+
return () => {
|
|
5526
|
+
const { clip, stepKey } = props.popover;
|
|
5527
|
+
let controls;
|
|
5528
|
+
let title;
|
|
5529
|
+
if (stepKey) {
|
|
5530
|
+
controls = getClipControls(props.panelId, `${clip.key}.${stepKey}`);
|
|
5531
|
+
if (stepKey === clip.stepKeys?.[0]) {
|
|
5532
|
+
const from = getControlAt(props.panelId, `${clip.key}.from`);
|
|
5533
|
+
if (from) {
|
|
5534
|
+
const index = controls.findIndex((control) => control.path === `${clip.key}.${stepKey}.to`);
|
|
5535
|
+
controls = index >= 0 ? [...controls.slice(0, index), from, ...controls.slice(index)] : [...controls, from];
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
title = `${clip.label} \xB7 ${formatStepLabel(stepKey)}`;
|
|
5539
|
+
} else {
|
|
5540
|
+
controls = getClipControls(props.panelId, clip.key, clipPopoverExclusions(clip));
|
|
5541
|
+
title = clip.label;
|
|
5542
|
+
}
|
|
5543
|
+
if (controls.length === 0) return null;
|
|
5544
|
+
const target = stepKey ? `${clip.key}.${stepKey}` : clip.key;
|
|
5545
|
+
const durationMeta = getControlAt(props.panelId, `${target}.duration`);
|
|
5546
|
+
const durationValue = durationMeta ? props.values[durationMeta.path] : void 0;
|
|
5547
|
+
const transitionDuration = durationMeta?.type === "slider" && typeof durationValue === "number" ? {
|
|
5548
|
+
value: durationValue,
|
|
5549
|
+
onChange: (next) => DialStore.updateValue(props.panelId, durationMeta.path, next),
|
|
5550
|
+
min: Math.max(TIMELINE_MIN_CLIP_DURATION, durationMeta.min ?? 0),
|
|
5551
|
+
max: durationMeta.max,
|
|
5552
|
+
step: durationMeta.step
|
|
5553
|
+
} : void 0;
|
|
5554
|
+
const current = viewport.value;
|
|
5555
|
+
const right = current.offsetLeft + current.width;
|
|
5556
|
+
const bottom = current.offsetTop + current.height;
|
|
5557
|
+
const width = Math.min(POPOVER_WIDTH, Math.max(220, current.width - 24));
|
|
5558
|
+
const left = clamp(props.popover.anchor.left + props.popover.anchor.width / 2 - width / 2, current.offsetLeft + 12, Math.max(current.offsetLeft + 12, right - width - 12));
|
|
5559
|
+
const above = Math.max(0, props.popover.anchor.top - current.offsetTop - 22);
|
|
5560
|
+
const below = Math.max(0, bottom - props.popover.anchor.bottom - 22);
|
|
5561
|
+
const placeAbove = naturalHeight.value === 0 ? above >= below : naturalHeight.value <= above || naturalHeight.value > below && above >= below;
|
|
5562
|
+
const availableHeight = placeAbove ? above : below;
|
|
5563
|
+
const renderedHeight = Math.min(naturalHeight.value || availableHeight, availableHeight);
|
|
5564
|
+
const rawTop = placeAbove ? props.popover.anchor.top - 10 - renderedHeight : props.popover.anchor.bottom + 10;
|
|
5565
|
+
const top = clamp(rawTop, current.offsetTop + 12, Math.max(current.offsetTop + 12, bottom - renderedHeight - 12));
|
|
5566
|
+
return h19(Teleport4, { to: "body" }, [h19("div", { class: "dialkit-root", "data-theme": props.theme }, [
|
|
5567
|
+
h19("div", {
|
|
5568
|
+
ref: element,
|
|
5569
|
+
class: "dialkit-timeline-popover",
|
|
5570
|
+
"data-placement": placeAbove ? "above" : "below",
|
|
5571
|
+
style: { left: `${left}px`, top: `${top}px`, width: `${width}px`, maxHeight: `${availableHeight}px`, visibility: naturalHeight.value > 0 ? "visible" : "hidden" },
|
|
5572
|
+
role: "dialog",
|
|
5573
|
+
"aria-label": `Edit ${title}`
|
|
5574
|
+
}, [
|
|
5575
|
+
h19("div", { class: "dialkit-timeline-popover-header" }, [
|
|
5576
|
+
h19("span", { class: "dialkit-timeline-popover-title" }, title),
|
|
5577
|
+
h19("button", { class: "dialkit-timeline-popover-close", title: "Close editor", "aria-label": "Close editor", onClick: props.onClose }, [
|
|
5578
|
+
h19("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }, [h19("path", { d: "M6 6L18 18M18 6L6 18" })])
|
|
5579
|
+
])
|
|
5580
|
+
]),
|
|
5581
|
+
h19("div", { class: "dialkit-timeline-popover-body" }, [h19(ControlRenderer, {
|
|
5582
|
+
panelId: props.panelId,
|
|
5583
|
+
controls,
|
|
5584
|
+
values: timelinePopoverDisplayValues(props.values, clip.key, clip.stepKeys, stepKey),
|
|
5585
|
+
transitionDuration
|
|
5586
|
+
})])
|
|
5587
|
+
])
|
|
5588
|
+
])]);
|
|
5589
|
+
};
|
|
5590
|
+
}
|
|
5591
|
+
});
|
|
5592
|
+
function readViewport() {
|
|
5593
|
+
return {
|
|
5594
|
+
width: window.visualViewport?.width ?? window.innerWidth,
|
|
5595
|
+
height: window.visualViewport?.height ?? window.innerHeight,
|
|
5596
|
+
offsetLeft: window.visualViewport?.offsetLeft ?? 0,
|
|
5597
|
+
offsetTop: window.visualViewport?.offsetTop ?? 0
|
|
5598
|
+
};
|
|
5599
|
+
}
|
|
5600
|
+
function clipPopoverExclusions(clip) {
|
|
5601
|
+
return /* @__PURE__ */ new Set([...clip.stepKeys ?? [], ...clip.tracks?.map((track) => track.prop) ?? []]);
|
|
5602
|
+
}
|
|
5603
|
+
function getClipControls(panelId, path, exclusions) {
|
|
5604
|
+
const panel = DialStore.getPanel(panelId);
|
|
5605
|
+
const folder = panel ? findControl(panel.controls, path) : null;
|
|
5606
|
+
if (!folder?.children) return [];
|
|
5607
|
+
return folder.children.filter((control) => {
|
|
5608
|
+
const key = control.path.slice(path.length + 1);
|
|
5609
|
+
return key !== "at" && key !== "duration" && !exclusions?.has(key);
|
|
5610
|
+
});
|
|
5611
|
+
}
|
|
5612
|
+
function getControlAt(panelId, path) {
|
|
5613
|
+
const panel = DialStore.getPanel(panelId);
|
|
5614
|
+
return panel ? findControl(panel.controls, path) : null;
|
|
5615
|
+
}
|
|
5616
|
+
var TimelineClip = defineComponent19({
|
|
5617
|
+
props: {
|
|
5618
|
+
timelineId: { type: String, required: true },
|
|
5619
|
+
clip: { type: Object, required: true },
|
|
5620
|
+
at: { type: Number, required: true },
|
|
5621
|
+
duration: { type: Number, required: true },
|
|
5622
|
+
loop: { type: String, required: true },
|
|
5623
|
+
steps: Array,
|
|
5624
|
+
fixedDuration: { type: Boolean, required: true },
|
|
5625
|
+
composite: Boolean,
|
|
5626
|
+
baseAt: { type: Number, default: 0 },
|
|
5627
|
+
delayMode: Boolean,
|
|
5628
|
+
pxPerSecond: { type: Number, required: true },
|
|
5629
|
+
viewStart: { type: Number, required: true },
|
|
5630
|
+
timelineDuration: { type: Number, required: true },
|
|
5631
|
+
selected: { type: Boolean, required: true },
|
|
5632
|
+
selectedStepKey: String,
|
|
5633
|
+
onClick: { type: Function, required: true },
|
|
5634
|
+
onDrag: { type: Function, required: true }
|
|
5635
|
+
},
|
|
5636
|
+
setup(props) {
|
|
5637
|
+
const dragging = ref15(false);
|
|
5638
|
+
let drag = null;
|
|
5639
|
+
const finish = (event) => {
|
|
5640
|
+
const previous = drag;
|
|
5641
|
+
drag = null;
|
|
5642
|
+
dragging.value = false;
|
|
5643
|
+
if (previous && !previous.moved && event) {
|
|
5644
|
+
const anchor = previous.clickEl ?? event.currentTarget;
|
|
5645
|
+
props.onClick(props.clip, anchor.getBoundingClientRect(), previous.clickEl?.dataset.step);
|
|
5646
|
+
}
|
|
5647
|
+
};
|
|
5648
|
+
return () => {
|
|
5649
|
+
const width = Math.max(props.duration * props.pxPerSecond, 14);
|
|
5650
|
+
const isSteps = Boolean(props.steps?.length);
|
|
5651
|
+
const looping = props.loop === "repeat" && props.duration > 0;
|
|
5652
|
+
const resizable = props.duration > 0 && !props.fixedDuration && !props.composite;
|
|
5653
|
+
const durationText = `${props.fixedDuration && !props.composite ? "~" : ""}${formatSeconds(props.duration)}`;
|
|
5654
|
+
const ghosts = [];
|
|
5655
|
+
if (looping) {
|
|
5656
|
+
const first = Math.max(1, Math.floor((props.viewStart - props.at) / props.duration));
|
|
5657
|
+
for (let offset = 0; offset < 256; offset++) {
|
|
5658
|
+
const index = first + offset;
|
|
5659
|
+
const start = props.at + props.duration * index;
|
|
5660
|
+
if (start >= props.timelineDuration - 1e-6) break;
|
|
5661
|
+
const duration = Math.min(props.duration, props.timelineDuration - start);
|
|
5662
|
+
ghosts.push(h19("div", {
|
|
5663
|
+
key: `ghost:${index}`,
|
|
5664
|
+
class: "dialkit-timeline-clip-ghost",
|
|
5665
|
+
"data-steps": isSteps || void 0,
|
|
5666
|
+
"aria-hidden": "true",
|
|
5667
|
+
style: { left: `${(start - props.viewStart) * props.pxPerSecond + 1}px`, width: `${Math.max(1, duration * props.pxPerSecond - 2)}px`, background: props.clip.color }
|
|
5668
|
+
}, props.steps?.map((step) => h19("span", { class: "dialkit-timeline-clip-ghost-segment", style: { width: `${step.duration * props.pxPerSecond}px` } }))));
|
|
5669
|
+
}
|
|
5670
|
+
}
|
|
5671
|
+
let cumulative = 0;
|
|
5672
|
+
const boundaries = props.steps?.map((step) => cumulative += step.duration) ?? [];
|
|
5673
|
+
const children = [];
|
|
5674
|
+
if (props.composite) {
|
|
5675
|
+
if (width > 56) children.push(h19("span", { class: "dialkit-timeline-clip-duration" }, durationText));
|
|
5676
|
+
} else if (isSteps) {
|
|
5677
|
+
for (const step of props.steps ?? []) {
|
|
5678
|
+
const segmentWidth = step.duration * props.pxPerSecond;
|
|
5679
|
+
children.push(h19("div", {
|
|
5680
|
+
key: step.key ?? "step",
|
|
5681
|
+
class: "dialkit-timeline-clip-segment",
|
|
5682
|
+
"data-step": step.key,
|
|
5683
|
+
"data-selected": props.selectedStepKey === step.key || void 0,
|
|
5684
|
+
style: { width: `${segmentWidth}px` }
|
|
5685
|
+
}, segmentWidth > 52 ? [h19("span", { class: "dialkit-timeline-clip-duration" }, formatSeconds(step.duration))] : []));
|
|
5686
|
+
}
|
|
5687
|
+
(props.steps ?? []).forEach((step, index) => {
|
|
5688
|
+
if (!step.isPhysics) children.push(h19("div", { key: `boundary:${step.key}`, class: "dialkit-timeline-clip-handle", "data-boundary": index, style: { left: `${boundaries[index] * props.pxPerSecond - 4}px` } }));
|
|
5689
|
+
});
|
|
5690
|
+
if (!props.steps?.[0]?.isPhysics) children.push(h19("div", { class: "dialkit-timeline-clip-handle", "data-edge": "start" }));
|
|
5691
|
+
} else {
|
|
5692
|
+
if (resizable) children.push(h19("div", { class: "dialkit-timeline-clip-handle", "data-edge": "start" }));
|
|
5693
|
+
if (width > 56) children.push(h19("span", { class: "dialkit-timeline-clip-duration" }, durationText));
|
|
5694
|
+
if (resizable) children.push(h19("div", { class: "dialkit-timeline-clip-handle", "data-edge": "end" }));
|
|
5695
|
+
}
|
|
5696
|
+
const title = props.composite ? `${props.clip.label} \u2014 composite of its property tracks${looping ? " \xB7 repeats through timeline" : ""} \xB7 click to expand` : `${props.clip.label} \u2014 ${formatSeconds(props.at)} for ${durationText}${props.fixedDuration ? " (duration set by spring physics)" : ""}${looping ? " \xB7 repeats through timeline" : ""}${props.delayMode ? " \xB7 drag to phase-shift" : ""}`;
|
|
5697
|
+
return [...ghosts, h19("div", {
|
|
5698
|
+
class: "dialkit-timeline-clip",
|
|
5699
|
+
"data-steps": isSteps || void 0,
|
|
5700
|
+
"data-composite": props.composite || void 0,
|
|
5701
|
+
"data-selected": props.selected || void 0,
|
|
5702
|
+
"data-dragging": dragging.value || void 0,
|
|
5703
|
+
style: { left: `${(props.at - props.viewStart) * props.pxPerSecond}px`, width: `${width}px`, background: props.composite ? `${props.clip.color}80` : props.clip.color },
|
|
5704
|
+
title,
|
|
5705
|
+
onPointerdown: (event) => {
|
|
5706
|
+
if (event.shiftKey) return;
|
|
5707
|
+
event.stopPropagation();
|
|
5708
|
+
const target = event.target;
|
|
5709
|
+
let mode = "move";
|
|
5710
|
+
let boundaryIndex;
|
|
5711
|
+
if (target.dataset.boundary !== void 0) {
|
|
5712
|
+
mode = "boundary";
|
|
5713
|
+
boundaryIndex = Number(target.dataset.boundary);
|
|
5714
|
+
} else if (!props.fixedDuration) {
|
|
5715
|
+
const edge = target.dataset.edge;
|
|
5716
|
+
if (edge) mode = edge;
|
|
5717
|
+
}
|
|
5718
|
+
drag = {
|
|
5719
|
+
mode,
|
|
5720
|
+
boundaryIndex,
|
|
5721
|
+
pointerX: event.clientX,
|
|
5722
|
+
at: props.at,
|
|
5723
|
+
duration: props.duration,
|
|
5724
|
+
stepDurations: props.steps?.map((step) => step.duration),
|
|
5725
|
+
clickEl: target.closest?.("[data-step]"),
|
|
5726
|
+
moved: false
|
|
5727
|
+
};
|
|
5728
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
5729
|
+
},
|
|
5730
|
+
onPointermove: (event) => {
|
|
5731
|
+
if (!drag || props.pxPerSecond <= 0) return;
|
|
5732
|
+
const dx = event.clientX - drag.pointerX;
|
|
5733
|
+
if (!drag.moved) {
|
|
5734
|
+
if (Math.abs(dx) <= DRAG_THRESHOLD_PX) return;
|
|
5735
|
+
drag.moved = true;
|
|
5736
|
+
dragging.value = true;
|
|
5737
|
+
props.onDrag();
|
|
5738
|
+
}
|
|
5739
|
+
const dt = dx / props.pxPerSecond;
|
|
5740
|
+
if (drag.mode === "boundary" && props.steps && drag.stepDurations) {
|
|
5741
|
+
const index = drag.boundaryIndex ?? 0;
|
|
5742
|
+
const others = drag.stepDurations.reduce((sum, duration, stepIndex) => stepIndex === index ? sum : sum + duration, 0);
|
|
5743
|
+
DialStore.updateValue(props.timelineId, `${props.clip.key}.${props.steps[index].key ?? ""}.duration`, clampStepResize(drag.stepDurations[index] + dt, drag.at, others, props.timelineDuration));
|
|
5744
|
+
} else if (drag.mode === "move") {
|
|
5745
|
+
if (props.delayMode) DialStore.updateValue(props.timelineId, `${props.clip.key}.delay`, clampTrackDelay(drag.at + dt - props.baseAt, props.baseAt, drag.duration, props.timelineDuration));
|
|
5746
|
+
else DialStore.updateValue(props.timelineId, `${props.clip.key}.at`, clampClipMove(drag.at + dt, drag.duration, props.timelineDuration));
|
|
5747
|
+
} else if (drag.mode === "end") {
|
|
5748
|
+
DialStore.updateValue(props.timelineId, `${props.clip.key}.duration`, clampClipResizeEnd(drag.duration + dt, drag.at, props.timelineDuration));
|
|
5749
|
+
} else if (props.steps && drag.stepDurations) {
|
|
5750
|
+
const next = clampClipResizeStart(Math.max(drag.at + dt, Math.max(props.baseAt, 0)), drag.at, drag.stepDurations[0]);
|
|
5751
|
+
DialStore.updateValues(props.timelineId, {
|
|
5752
|
+
[props.delayMode ? `${props.clip.key}.delay` : `${props.clip.key}.at`]: props.delayMode ? Math.max(0, next.at - props.baseAt) : next.at,
|
|
5753
|
+
[`${props.clip.key}.${props.steps[0].key ?? ""}.duration`]: next.duration
|
|
5754
|
+
});
|
|
5755
|
+
} else {
|
|
5756
|
+
const next = clampClipResizeStart(Math.max(drag.at + dt, Math.max(props.baseAt, 0)), drag.at, drag.duration);
|
|
5757
|
+
DialStore.updateValues(props.timelineId, {
|
|
5758
|
+
[props.delayMode ? `${props.clip.key}.delay` : `${props.clip.key}.at`]: props.delayMode ? Math.max(0, next.at - props.baseAt) : next.at,
|
|
5759
|
+
[`${props.clip.key}.duration`]: next.duration
|
|
5760
|
+
});
|
|
5761
|
+
}
|
|
5762
|
+
},
|
|
5763
|
+
onPointerup: finish,
|
|
5764
|
+
onPointercancel: () => finish(),
|
|
5765
|
+
onLostpointercapture: () => finish()
|
|
5766
|
+
}, children), looping ? h19("span", { class: "dialkit-timeline-loop-infinity", "aria-hidden": "true", title: "Repeats indefinitely" }, "\u221E") : null];
|
|
5767
|
+
};
|
|
5768
|
+
}
|
|
5769
|
+
});
|
|
5770
|
+
|
|
3268
5771
|
// src/vue/components/ShortcutsMenu.ts
|
|
3269
|
-
import { defineComponent as
|
|
5772
|
+
import { defineComponent as defineComponent20, h as h20, onUnmounted as onUnmounted13, ref as ref16, Teleport as Teleport5 } from "vue";
|
|
3270
5773
|
function formatShortcutKey(sc) {
|
|
3271
5774
|
if (!sc.key) return "\u2014";
|
|
3272
5775
|
const mod = sc.modifier === "alt" ? "\u2325" : sc.modifier === "shift" ? "\u21E7" : sc.modifier === "meta" ? "\u2318" : "";
|
|
@@ -3285,7 +5788,7 @@ function formatInteraction(sc) {
|
|
|
3285
5788
|
return "scroll";
|
|
3286
5789
|
}
|
|
3287
5790
|
}
|
|
3288
|
-
var ShortcutsMenu =
|
|
5791
|
+
var ShortcutsMenu = defineComponent20({
|
|
3289
5792
|
name: "DialKitShortcutsMenu",
|
|
3290
5793
|
props: {
|
|
3291
5794
|
panelId: {
|
|
@@ -3294,10 +5797,10 @@ var ShortcutsMenu = defineComponent17({
|
|
|
3294
5797
|
}
|
|
3295
5798
|
},
|
|
3296
5799
|
setup(props) {
|
|
3297
|
-
const isOpen =
|
|
3298
|
-
const triggerRef =
|
|
3299
|
-
const dropdownRef =
|
|
3300
|
-
const pos =
|
|
5800
|
+
const isOpen = ref16(false);
|
|
5801
|
+
const triggerRef = ref16(null);
|
|
5802
|
+
const dropdownRef = ref16(null);
|
|
5803
|
+
const pos = ref16({ top: 0, right: 0 });
|
|
3301
5804
|
const open = () => {
|
|
3302
5805
|
const rect = triggerRef.value?.getBoundingClientRect();
|
|
3303
5806
|
if (rect) {
|
|
@@ -3327,7 +5830,7 @@ var ShortcutsMenu = defineComponent17({
|
|
|
3327
5830
|
mousedownHandler = null;
|
|
3328
5831
|
}
|
|
3329
5832
|
};
|
|
3330
|
-
|
|
5833
|
+
onUnmounted13(() => {
|
|
3331
5834
|
removeOutsideClickListener();
|
|
3332
5835
|
});
|
|
3333
5836
|
return () => {
|
|
@@ -3356,13 +5859,13 @@ var ShortcutsMenu = defineComponent17({
|
|
|
3356
5859
|
removeOutsideClickListener();
|
|
3357
5860
|
}
|
|
3358
5861
|
return [
|
|
3359
|
-
|
|
5862
|
+
h20("button", {
|
|
3360
5863
|
ref: triggerRef,
|
|
3361
5864
|
class: "dialkit-shortcuts-trigger",
|
|
3362
5865
|
onClick: toggle,
|
|
3363
5866
|
title: "Keyboard shortcuts"
|
|
3364
5867
|
}, [
|
|
3365
|
-
|
|
5868
|
+
h20("svg", {
|
|
3366
5869
|
viewBox: "0 0 24 24",
|
|
3367
5870
|
fill: "none",
|
|
3368
5871
|
stroke: "currentColor",
|
|
@@ -3370,16 +5873,16 @@ var ShortcutsMenu = defineComponent17({
|
|
|
3370
5873
|
"stroke-linecap": "round",
|
|
3371
5874
|
"stroke-linejoin": "round"
|
|
3372
5875
|
}, [
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
5876
|
+
h20("rect", { x: "2", y: "6", width: "20", height: "12", rx: "2" }),
|
|
5877
|
+
h20("path", { d: "M6 10H6.01" }),
|
|
5878
|
+
h20("path", { d: "M10 10H10.01" }),
|
|
5879
|
+
h20("path", { d: "M14 10H14.01" }),
|
|
5880
|
+
h20("path", { d: "M18 10H18.01" }),
|
|
5881
|
+
h20("path", { d: "M8 14H16" })
|
|
3379
5882
|
])
|
|
3380
5883
|
]),
|
|
3381
|
-
isOpen.value ?
|
|
3382
|
-
|
|
5884
|
+
isOpen.value ? h20(Teleport5, { to: "body" }, [
|
|
5885
|
+
h20("div", {
|
|
3383
5886
|
ref: dropdownRef,
|
|
3384
5887
|
class: "dialkit-root dialkit-shortcuts-dropdown",
|
|
3385
5888
|
style: {
|
|
@@ -3388,19 +5891,19 @@ var ShortcutsMenu = defineComponent17({
|
|
|
3388
5891
|
right: `${pos.value.right}px`
|
|
3389
5892
|
}
|
|
3390
5893
|
}, [
|
|
3391
|
-
|
|
3392
|
-
|
|
5894
|
+
h20("div", { class: "dialkit-shortcuts-title" }, "Keyboard Shortcuts"),
|
|
5895
|
+
h20(
|
|
3393
5896
|
"div",
|
|
3394
5897
|
{ class: "dialkit-shortcuts-list" },
|
|
3395
5898
|
rows.map(
|
|
3396
|
-
(row) =>
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
5899
|
+
(row) => h20("div", { key: row.path, class: "dialkit-shortcuts-row" }, [
|
|
5900
|
+
h20("span", { class: "dialkit-shortcuts-row-key" }, formatShortcutKey(row.shortcut)),
|
|
5901
|
+
h20("span", { class: "dialkit-shortcuts-row-label" }, row.label),
|
|
5902
|
+
h20("span", { class: "dialkit-shortcuts-row-mode" }, formatInteraction(row.shortcut))
|
|
3400
5903
|
])
|
|
3401
5904
|
)
|
|
3402
5905
|
),
|
|
3403
|
-
|
|
5906
|
+
h20("div", { class: "dialkit-shortcuts-hint" }, "See pill badges on controls for keys")
|
|
3404
5907
|
])
|
|
3405
5908
|
]) : null
|
|
3406
5909
|
];
|
|
@@ -3409,8 +5912,8 @@ var ShortcutsMenu = defineComponent17({
|
|
|
3409
5912
|
});
|
|
3410
5913
|
|
|
3411
5914
|
// src/vue/components/ButtonGroup.ts
|
|
3412
|
-
import { defineComponent as
|
|
3413
|
-
var ButtonGroup =
|
|
5915
|
+
import { defineComponent as defineComponent21, h as h21 } from "vue";
|
|
5916
|
+
var ButtonGroup = defineComponent21({
|
|
3414
5917
|
name: "DialKitButtonGroup",
|
|
3415
5918
|
props: {
|
|
3416
5919
|
buttons: {
|
|
@@ -3419,11 +5922,11 @@ var ButtonGroup = defineComponent18({
|
|
|
3419
5922
|
}
|
|
3420
5923
|
},
|
|
3421
5924
|
setup(props) {
|
|
3422
|
-
return () =>
|
|
5925
|
+
return () => h21(
|
|
3423
5926
|
"div",
|
|
3424
5927
|
{ class: "dialkit-button-group" },
|
|
3425
5928
|
props.buttons.map(
|
|
3426
|
-
(button) =>
|
|
5929
|
+
(button) => h21("button", { class: "dialkit-button", onClick: button.onClick }, button.label)
|
|
3427
5930
|
)
|
|
3428
5931
|
);
|
|
3429
5932
|
}
|
|
@@ -3431,8 +5934,10 @@ var ButtonGroup = defineComponent18({
|
|
|
3431
5934
|
export {
|
|
3432
5935
|
ButtonGroup,
|
|
3433
5936
|
ColorControl,
|
|
5937
|
+
ControlRenderer,
|
|
3434
5938
|
DialRoot,
|
|
3435
5939
|
DialStore,
|
|
5940
|
+
DialTimeline,
|
|
3436
5941
|
EasingVisualization,
|
|
3437
5942
|
Folder,
|
|
3438
5943
|
PresetManager,
|
|
@@ -3448,6 +5953,7 @@ export {
|
|
|
3448
5953
|
TransitionControl,
|
|
3449
5954
|
useDialKit,
|
|
3450
5955
|
useDialKitController,
|
|
5956
|
+
useDialTimeline,
|
|
3451
5957
|
useShortcutContext,
|
|
3452
5958
|
vDialKit
|
|
3453
5959
|
};
|