@multitrack/vue 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +178 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +95 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.js +169 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vue = require('vue');
|
|
4
|
+
var core = require('@multitrack/core');
|
|
5
|
+
|
|
6
|
+
// src/provider.ts
|
|
7
|
+
|
|
8
|
+
// src/context.ts
|
|
9
|
+
var MULTITRACK_KEY = /* @__PURE__ */ Symbol("multitrack");
|
|
10
|
+
|
|
11
|
+
// src/provider.ts
|
|
12
|
+
var MultitrackProvider = vue.defineComponent({
|
|
13
|
+
name: "MultitrackProvider",
|
|
14
|
+
props: {
|
|
15
|
+
config: {
|
|
16
|
+
type: Array,
|
|
17
|
+
required: true
|
|
18
|
+
},
|
|
19
|
+
devtools: {
|
|
20
|
+
type: Boolean,
|
|
21
|
+
default: false
|
|
22
|
+
},
|
|
23
|
+
breakpoints: {
|
|
24
|
+
type: Object,
|
|
25
|
+
default: void 0
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
setup(props, { slots }) {
|
|
29
|
+
let timeline = null;
|
|
30
|
+
let scope = null;
|
|
31
|
+
const state = vue.shallowRef(null);
|
|
32
|
+
function setupTimeline() {
|
|
33
|
+
scope?.dispose();
|
|
34
|
+
timeline?.destroy();
|
|
35
|
+
const t = new core.Timeline({
|
|
36
|
+
config: props.config,
|
|
37
|
+
devtools: props.devtools,
|
|
38
|
+
breakpoints: props.breakpoints
|
|
39
|
+
});
|
|
40
|
+
timeline = t;
|
|
41
|
+
state.value = {
|
|
42
|
+
timeline: t,
|
|
43
|
+
steps: t.steps,
|
|
44
|
+
totalSteps: t.totalSteps,
|
|
45
|
+
scrollPercentage: 0,
|
|
46
|
+
currentStep: 0,
|
|
47
|
+
opacities: t.getOpacities(0)
|
|
48
|
+
};
|
|
49
|
+
scope = t.scope(() => {
|
|
50
|
+
t.on("scroll", ({ scrollPercentage, currentStep }) => {
|
|
51
|
+
state.value = {
|
|
52
|
+
...state.value,
|
|
53
|
+
scrollPercentage,
|
|
54
|
+
currentStep,
|
|
55
|
+
opacities: t.getOpacities(scrollPercentage)
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
t.on("timeline:reconfigure", () => {
|
|
59
|
+
state.value = {
|
|
60
|
+
...state.value,
|
|
61
|
+
steps: t.steps,
|
|
62
|
+
totalSteps: t.totalSteps,
|
|
63
|
+
scrollPercentage: t.scrollPercentage,
|
|
64
|
+
currentStep: t.currentStep,
|
|
65
|
+
opacities: t.getOpacities()
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
t.start();
|
|
70
|
+
}
|
|
71
|
+
vue.provide(MULTITRACK_KEY, state);
|
|
72
|
+
vue.onMounted(() => {
|
|
73
|
+
setupTimeline();
|
|
74
|
+
});
|
|
75
|
+
vue.watch(
|
|
76
|
+
() => [props.config, props.devtools, props.breakpoints],
|
|
77
|
+
() => {
|
|
78
|
+
if (timeline) {
|
|
79
|
+
setupTimeline();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
vue.onUnmounted(() => {
|
|
84
|
+
scope?.dispose();
|
|
85
|
+
timeline?.destroy();
|
|
86
|
+
});
|
|
87
|
+
return () => slots.default?.();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
function useMultitrackContext() {
|
|
91
|
+
const state = vue.inject(MULTITRACK_KEY);
|
|
92
|
+
if (!state) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
"[@multitrack/vue] Composables must be used within a <MultitrackProvider>"
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return state;
|
|
98
|
+
}
|
|
99
|
+
function useTimeline() {
|
|
100
|
+
return useMultitrackContext().value.timeline;
|
|
101
|
+
}
|
|
102
|
+
function useOpacities() {
|
|
103
|
+
const state = useMultitrackContext();
|
|
104
|
+
return vue.computed(() => state.value.opacities);
|
|
105
|
+
}
|
|
106
|
+
function useStep(name) {
|
|
107
|
+
const state = useMultitrackContext();
|
|
108
|
+
return {
|
|
109
|
+
opacity: vue.computed(() => state.value.opacities[name] ?? 0),
|
|
110
|
+
isActive: vue.computed(() => (state.value.opacities[name] ?? 0) > 0)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function useScrollProgress() {
|
|
114
|
+
const state = useMultitrackContext();
|
|
115
|
+
return {
|
|
116
|
+
scrollPercentage: vue.computed(() => state.value.scrollPercentage),
|
|
117
|
+
currentStep: vue.computed(() => state.value.currentStep),
|
|
118
|
+
totalSteps: vue.computed(() => state.value.totalSteps)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
var ScrollContainer = vue.defineComponent({
|
|
122
|
+
name: "ScrollContainer",
|
|
123
|
+
setup(_, { slots, attrs }) {
|
|
124
|
+
const { totalSteps } = useScrollProgress();
|
|
125
|
+
return () => vue.h(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
style: {
|
|
129
|
+
height: `${totalSteps.value * 100}vh`,
|
|
130
|
+
position: "relative"
|
|
131
|
+
},
|
|
132
|
+
...attrs
|
|
133
|
+
},
|
|
134
|
+
slots.default?.()
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
var FixedStage = vue.defineComponent({
|
|
139
|
+
name: "FixedStage",
|
|
140
|
+
setup(_, { slots, attrs }) {
|
|
141
|
+
return () => vue.h(
|
|
142
|
+
"div",
|
|
143
|
+
{
|
|
144
|
+
style: {
|
|
145
|
+
position: "fixed",
|
|
146
|
+
top: "0",
|
|
147
|
+
left: "0",
|
|
148
|
+
width: "100%",
|
|
149
|
+
height: "100vh",
|
|
150
|
+
touchAction: "pan-y"
|
|
151
|
+
},
|
|
152
|
+
...attrs
|
|
153
|
+
},
|
|
154
|
+
slots.default?.()
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
var Show = vue.defineComponent({
|
|
159
|
+
name: "Show",
|
|
160
|
+
props: {
|
|
161
|
+
when: { type: String, required: true }
|
|
162
|
+
},
|
|
163
|
+
setup(props, { slots }) {
|
|
164
|
+
const { isActive } = useStep(props.when);
|
|
165
|
+
return () => isActive.value ? slots.default?.() : null;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
exports.FixedStage = FixedStage;
|
|
170
|
+
exports.MultitrackProvider = MultitrackProvider;
|
|
171
|
+
exports.ScrollContainer = ScrollContainer;
|
|
172
|
+
exports.Show = Show;
|
|
173
|
+
exports.useOpacities = useOpacities;
|
|
174
|
+
exports.useScrollProgress = useScrollProgress;
|
|
175
|
+
exports.useStep = useStep;
|
|
176
|
+
exports.useTimeline = useTimeline;
|
|
177
|
+
//# sourceMappingURL=index.cjs.map
|
|
178
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/provider.ts","../src/composables.ts","../src/components.ts"],"names":["defineComponent","shallowRef","Timeline","provide","onMounted","watch","onUnmounted","inject","computed","h"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { InjectionKey, ShallowRef } from \"vue\";\nimport type { Timeline, Opacities, Step } from \"@multitrack/core\";\n\nexport interface MultitrackContextValue {\n timeline: Timeline;\n steps: Step[];\n totalSteps: number;\n scrollPercentage: number;\n currentStep: number;\n opacities: Opacities;\n}\n\nexport const MULTITRACK_KEY: InjectionKey<\n ShallowRef<MultitrackContextValue>\n> = Symbol(\"multitrack\");\n","import {\n defineComponent,\n h,\n shallowRef,\n provide,\n onMounted,\n onUnmounted,\n watch,\n type PropType,\n} from \"vue\";\nimport { Timeline, type StepConfig, type Scope } from \"@multitrack/core\";\nimport { MULTITRACK_KEY, type MultitrackContextValue } from \"./context.js\";\n\nexport const MultitrackProvider = defineComponent({\n name: \"MultitrackProvider\",\n props: {\n config: {\n type: Array as PropType<StepConfig[]>,\n required: true,\n },\n devtools: {\n type: Boolean,\n default: false,\n },\n breakpoints: {\n type: Object as PropType<Record<string, string>>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n let timeline: Timeline | null = null;\n let scope: Scope | null = null;\n\n const state = shallowRef<MultitrackContextValue>(null!);\n\n function setupTimeline() {\n // Clean up previous instance\n scope?.dispose();\n timeline?.destroy();\n\n const t = new Timeline({\n config: props.config,\n devtools: props.devtools,\n breakpoints: props.breakpoints,\n });\n timeline = t;\n\n state.value = {\n timeline: t,\n steps: t.steps,\n totalSteps: t.totalSteps,\n scrollPercentage: 0,\n currentStep: 0,\n opacities: t.getOpacities(0),\n };\n\n scope = t.scope(() => {\n t.on(\"scroll\", ({ scrollPercentage, currentStep }) => {\n state.value = {\n ...state.value,\n scrollPercentage,\n currentStep,\n opacities: t.getOpacities(scrollPercentage),\n };\n });\n\n t.on(\"timeline:reconfigure\", () => {\n state.value = {\n ...state.value,\n steps: t.steps,\n totalSteps: t.totalSteps,\n scrollPercentage: t.scrollPercentage,\n currentStep: t.currentStep,\n opacities: t.getOpacities(),\n };\n });\n });\n\n t.start();\n }\n\n provide(MULTITRACK_KEY, state);\n\n onMounted(() => {\n setupTimeline();\n });\n\n // Recreate timeline when props change\n watch(\n () => [props.config, props.devtools, props.breakpoints],\n () => {\n if (timeline) {\n setupTimeline();\n }\n },\n );\n\n onUnmounted(() => {\n scope?.dispose();\n timeline?.destroy();\n });\n\n return () => slots.default?.();\n },\n});\n","import { inject, computed } from \"vue\";\nimport type { Timeline, Opacities } from \"@multitrack/core\";\nimport { MULTITRACK_KEY } from \"./context.js\";\n\nfunction useMultitrackContext() {\n const state = inject(MULTITRACK_KEY);\n if (!state) {\n throw new Error(\n \"[@multitrack/vue] Composables must be used within a <MultitrackProvider>\",\n );\n }\n return state;\n}\n\n/**\n * Access the Timeline instance directly.\n */\nexport function useTimeline(): Timeline {\n return useMultitrackContext().value.timeline;\n}\n\n/**\n * Get current opacities for all steps.\n */\nexport function useOpacities<T extends string = string>() {\n const state = useMultitrackContext();\n return computed(() => state.value.opacities as Opacities<T>);\n}\n\n/**\n * Get opacity and active state for a single named step.\n */\nexport function useStep(name: string) {\n const state = useMultitrackContext();\n return {\n opacity: computed(() => state.value.opacities[name] ?? 0),\n isActive: computed(() => (state.value.opacities[name] ?? 0) > 0),\n };\n}\n\n/**\n * Get raw scroll progress and current step position.\n */\nexport function useScrollProgress() {\n const state = useMultitrackContext();\n return {\n scrollPercentage: computed(() => state.value.scrollPercentage),\n currentStep: computed(() => state.value.currentStep),\n totalSteps: computed(() => state.value.totalSteps),\n };\n}\n","import { defineComponent, h } from \"vue\";\nimport { useScrollProgress, useStep } from \"./composables.js\";\n\n/**\n * Creates the tall scrollable container that drives the timeline.\n * Height = totalSteps * 100vh.\n */\nexport const ScrollContainer = defineComponent({\n name: \"ScrollContainer\",\n setup(_, { slots, attrs }) {\n const { totalSteps } = useScrollProgress();\n\n return () =>\n h(\n \"div\",\n {\n style: {\n height: `${totalSteps.value * 100}vh`,\n position: \"relative\",\n },\n ...attrs,\n },\n slots.default?.(),\n );\n },\n});\n\n/**\n * Fixed viewport stage that stays in place while the user scrolls.\n * All animated content lives inside this.\n */\nexport const FixedStage = defineComponent({\n name: \"FixedStage\",\n setup(_, { slots, attrs }) {\n return () =>\n h(\n \"div\",\n {\n style: {\n position: \"fixed\",\n top: \"0\",\n left: \"0\",\n width: \"100%\",\n height: \"100vh\",\n touchAction: \"pan-y\",\n },\n ...attrs,\n },\n slots.default?.(),\n );\n },\n});\n\n/**\n * Conditionally renders children based on a step's opacity.\n * Unmounts children when the step is inactive (opacity 0) for performance.\n */\nexport const Show = defineComponent({\n name: \"Show\",\n props: {\n when: { type: String, required: true },\n },\n setup(props, { slots }) {\n const { isActive } = useStep(props.when);\n\n return () => (isActive.value ? slots.default?.() : null);\n },\n});\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { PropType } from 'vue';
|
|
3
|
+
import { StepConfig, Opacities, Timeline } from '@multitrack/core';
|
|
4
|
+
export { EasingPreset, Opacities, StepConfig } from '@multitrack/core';
|
|
5
|
+
|
|
6
|
+
declare const MultitrackProvider: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
7
|
+
config: {
|
|
8
|
+
type: PropType<StepConfig[]>;
|
|
9
|
+
required: true;
|
|
10
|
+
};
|
|
11
|
+
devtools: {
|
|
12
|
+
type: BooleanConstructor;
|
|
13
|
+
default: boolean;
|
|
14
|
+
};
|
|
15
|
+
breakpoints: {
|
|
16
|
+
type: PropType<Record<string, string>>;
|
|
17
|
+
default: undefined;
|
|
18
|
+
};
|
|
19
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}>[] | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
22
|
+
config: {
|
|
23
|
+
type: PropType<StepConfig[]>;
|
|
24
|
+
required: true;
|
|
25
|
+
};
|
|
26
|
+
devtools: {
|
|
27
|
+
type: BooleanConstructor;
|
|
28
|
+
default: boolean;
|
|
29
|
+
};
|
|
30
|
+
breakpoints: {
|
|
31
|
+
type: PropType<Record<string, string>>;
|
|
32
|
+
default: undefined;
|
|
33
|
+
};
|
|
34
|
+
}>> & Readonly<{}>, {
|
|
35
|
+
devtools: boolean;
|
|
36
|
+
breakpoints: Record<string, string>;
|
|
37
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Access the Timeline instance directly.
|
|
41
|
+
*/
|
|
42
|
+
declare function useTimeline(): Timeline;
|
|
43
|
+
/**
|
|
44
|
+
* Get current opacities for all steps.
|
|
45
|
+
*/
|
|
46
|
+
declare function useOpacities<T extends string = string>(): vue.ComputedRef<Opacities<T>>;
|
|
47
|
+
/**
|
|
48
|
+
* Get opacity and active state for a single named step.
|
|
49
|
+
*/
|
|
50
|
+
declare function useStep(name: string): {
|
|
51
|
+
opacity: vue.ComputedRef<number>;
|
|
52
|
+
isActive: vue.ComputedRef<boolean>;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Get raw scroll progress and current step position.
|
|
56
|
+
*/
|
|
57
|
+
declare function useScrollProgress(): {
|
|
58
|
+
scrollPercentage: vue.ComputedRef<number>;
|
|
59
|
+
currentStep: vue.ComputedRef<number>;
|
|
60
|
+
totalSteps: vue.ComputedRef<number>;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Creates the tall scrollable container that drives the timeline.
|
|
65
|
+
* Height = totalSteps * 100vh.
|
|
66
|
+
*/
|
|
67
|
+
declare const ScrollContainer: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
68
|
+
[key: string]: any;
|
|
69
|
+
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
70
|
+
/**
|
|
71
|
+
* Fixed viewport stage that stays in place while the user scrolls.
|
|
72
|
+
* All animated content lives inside this.
|
|
73
|
+
*/
|
|
74
|
+
declare const FixedStage: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
75
|
+
[key: string]: any;
|
|
76
|
+
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
77
|
+
/**
|
|
78
|
+
* Conditionally renders children based on a step's opacity.
|
|
79
|
+
* Unmounts children when the step is inactive (opacity 0) for performance.
|
|
80
|
+
*/
|
|
81
|
+
declare const Show: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
82
|
+
when: {
|
|
83
|
+
type: StringConstructor;
|
|
84
|
+
required: true;
|
|
85
|
+
};
|
|
86
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
87
|
+
[key: string]: any;
|
|
88
|
+
}>[] | null | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
89
|
+
when: {
|
|
90
|
+
type: StringConstructor;
|
|
91
|
+
required: true;
|
|
92
|
+
};
|
|
93
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
94
|
+
|
|
95
|
+
export { FixedStage, MultitrackProvider, ScrollContainer, Show, useOpacities, useScrollProgress, useStep, useTimeline };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { PropType } from 'vue';
|
|
3
|
+
import { StepConfig, Opacities, Timeline } from '@multitrack/core';
|
|
4
|
+
export { EasingPreset, Opacities, StepConfig } from '@multitrack/core';
|
|
5
|
+
|
|
6
|
+
declare const MultitrackProvider: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
7
|
+
config: {
|
|
8
|
+
type: PropType<StepConfig[]>;
|
|
9
|
+
required: true;
|
|
10
|
+
};
|
|
11
|
+
devtools: {
|
|
12
|
+
type: BooleanConstructor;
|
|
13
|
+
default: boolean;
|
|
14
|
+
};
|
|
15
|
+
breakpoints: {
|
|
16
|
+
type: PropType<Record<string, string>>;
|
|
17
|
+
default: undefined;
|
|
18
|
+
};
|
|
19
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}>[] | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
22
|
+
config: {
|
|
23
|
+
type: PropType<StepConfig[]>;
|
|
24
|
+
required: true;
|
|
25
|
+
};
|
|
26
|
+
devtools: {
|
|
27
|
+
type: BooleanConstructor;
|
|
28
|
+
default: boolean;
|
|
29
|
+
};
|
|
30
|
+
breakpoints: {
|
|
31
|
+
type: PropType<Record<string, string>>;
|
|
32
|
+
default: undefined;
|
|
33
|
+
};
|
|
34
|
+
}>> & Readonly<{}>, {
|
|
35
|
+
devtools: boolean;
|
|
36
|
+
breakpoints: Record<string, string>;
|
|
37
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Access the Timeline instance directly.
|
|
41
|
+
*/
|
|
42
|
+
declare function useTimeline(): Timeline;
|
|
43
|
+
/**
|
|
44
|
+
* Get current opacities for all steps.
|
|
45
|
+
*/
|
|
46
|
+
declare function useOpacities<T extends string = string>(): vue.ComputedRef<Opacities<T>>;
|
|
47
|
+
/**
|
|
48
|
+
* Get opacity and active state for a single named step.
|
|
49
|
+
*/
|
|
50
|
+
declare function useStep(name: string): {
|
|
51
|
+
opacity: vue.ComputedRef<number>;
|
|
52
|
+
isActive: vue.ComputedRef<boolean>;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Get raw scroll progress and current step position.
|
|
56
|
+
*/
|
|
57
|
+
declare function useScrollProgress(): {
|
|
58
|
+
scrollPercentage: vue.ComputedRef<number>;
|
|
59
|
+
currentStep: vue.ComputedRef<number>;
|
|
60
|
+
totalSteps: vue.ComputedRef<number>;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Creates the tall scrollable container that drives the timeline.
|
|
65
|
+
* Height = totalSteps * 100vh.
|
|
66
|
+
*/
|
|
67
|
+
declare const ScrollContainer: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
68
|
+
[key: string]: any;
|
|
69
|
+
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
70
|
+
/**
|
|
71
|
+
* Fixed viewport stage that stays in place while the user scrolls.
|
|
72
|
+
* All animated content lives inside this.
|
|
73
|
+
*/
|
|
74
|
+
declare const FixedStage: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
75
|
+
[key: string]: any;
|
|
76
|
+
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
77
|
+
/**
|
|
78
|
+
* Conditionally renders children based on a step's opacity.
|
|
79
|
+
* Unmounts children when the step is inactive (opacity 0) for performance.
|
|
80
|
+
*/
|
|
81
|
+
declare const Show: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
82
|
+
when: {
|
|
83
|
+
type: StringConstructor;
|
|
84
|
+
required: true;
|
|
85
|
+
};
|
|
86
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
87
|
+
[key: string]: any;
|
|
88
|
+
}>[] | null | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
89
|
+
when: {
|
|
90
|
+
type: StringConstructor;
|
|
91
|
+
required: true;
|
|
92
|
+
};
|
|
93
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
94
|
+
|
|
95
|
+
export { FixedStage, MultitrackProvider, ScrollContainer, Show, useOpacities, useScrollProgress, useStep, useTimeline };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { defineComponent, shallowRef, provide, onMounted, watch, onUnmounted, h, computed, inject } from 'vue';
|
|
2
|
+
import { Timeline } from '@multitrack/core';
|
|
3
|
+
|
|
4
|
+
// src/provider.ts
|
|
5
|
+
|
|
6
|
+
// src/context.ts
|
|
7
|
+
var MULTITRACK_KEY = /* @__PURE__ */ Symbol("multitrack");
|
|
8
|
+
|
|
9
|
+
// src/provider.ts
|
|
10
|
+
var MultitrackProvider = defineComponent({
|
|
11
|
+
name: "MultitrackProvider",
|
|
12
|
+
props: {
|
|
13
|
+
config: {
|
|
14
|
+
type: Array,
|
|
15
|
+
required: true
|
|
16
|
+
},
|
|
17
|
+
devtools: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: false
|
|
20
|
+
},
|
|
21
|
+
breakpoints: {
|
|
22
|
+
type: Object,
|
|
23
|
+
default: void 0
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
setup(props, { slots }) {
|
|
27
|
+
let timeline = null;
|
|
28
|
+
let scope = null;
|
|
29
|
+
const state = shallowRef(null);
|
|
30
|
+
function setupTimeline() {
|
|
31
|
+
scope?.dispose();
|
|
32
|
+
timeline?.destroy();
|
|
33
|
+
const t = new Timeline({
|
|
34
|
+
config: props.config,
|
|
35
|
+
devtools: props.devtools,
|
|
36
|
+
breakpoints: props.breakpoints
|
|
37
|
+
});
|
|
38
|
+
timeline = t;
|
|
39
|
+
state.value = {
|
|
40
|
+
timeline: t,
|
|
41
|
+
steps: t.steps,
|
|
42
|
+
totalSteps: t.totalSteps,
|
|
43
|
+
scrollPercentage: 0,
|
|
44
|
+
currentStep: 0,
|
|
45
|
+
opacities: t.getOpacities(0)
|
|
46
|
+
};
|
|
47
|
+
scope = t.scope(() => {
|
|
48
|
+
t.on("scroll", ({ scrollPercentage, currentStep }) => {
|
|
49
|
+
state.value = {
|
|
50
|
+
...state.value,
|
|
51
|
+
scrollPercentage,
|
|
52
|
+
currentStep,
|
|
53
|
+
opacities: t.getOpacities(scrollPercentage)
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
t.on("timeline:reconfigure", () => {
|
|
57
|
+
state.value = {
|
|
58
|
+
...state.value,
|
|
59
|
+
steps: t.steps,
|
|
60
|
+
totalSteps: t.totalSteps,
|
|
61
|
+
scrollPercentage: t.scrollPercentage,
|
|
62
|
+
currentStep: t.currentStep,
|
|
63
|
+
opacities: t.getOpacities()
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
t.start();
|
|
68
|
+
}
|
|
69
|
+
provide(MULTITRACK_KEY, state);
|
|
70
|
+
onMounted(() => {
|
|
71
|
+
setupTimeline();
|
|
72
|
+
});
|
|
73
|
+
watch(
|
|
74
|
+
() => [props.config, props.devtools, props.breakpoints],
|
|
75
|
+
() => {
|
|
76
|
+
if (timeline) {
|
|
77
|
+
setupTimeline();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
onUnmounted(() => {
|
|
82
|
+
scope?.dispose();
|
|
83
|
+
timeline?.destroy();
|
|
84
|
+
});
|
|
85
|
+
return () => slots.default?.();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
function useMultitrackContext() {
|
|
89
|
+
const state = inject(MULTITRACK_KEY);
|
|
90
|
+
if (!state) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"[@multitrack/vue] Composables must be used within a <MultitrackProvider>"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return state;
|
|
96
|
+
}
|
|
97
|
+
function useTimeline() {
|
|
98
|
+
return useMultitrackContext().value.timeline;
|
|
99
|
+
}
|
|
100
|
+
function useOpacities() {
|
|
101
|
+
const state = useMultitrackContext();
|
|
102
|
+
return computed(() => state.value.opacities);
|
|
103
|
+
}
|
|
104
|
+
function useStep(name) {
|
|
105
|
+
const state = useMultitrackContext();
|
|
106
|
+
return {
|
|
107
|
+
opacity: computed(() => state.value.opacities[name] ?? 0),
|
|
108
|
+
isActive: computed(() => (state.value.opacities[name] ?? 0) > 0)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function useScrollProgress() {
|
|
112
|
+
const state = useMultitrackContext();
|
|
113
|
+
return {
|
|
114
|
+
scrollPercentage: computed(() => state.value.scrollPercentage),
|
|
115
|
+
currentStep: computed(() => state.value.currentStep),
|
|
116
|
+
totalSteps: computed(() => state.value.totalSteps)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
var ScrollContainer = defineComponent({
|
|
120
|
+
name: "ScrollContainer",
|
|
121
|
+
setup(_, { slots, attrs }) {
|
|
122
|
+
const { totalSteps } = useScrollProgress();
|
|
123
|
+
return () => h(
|
|
124
|
+
"div",
|
|
125
|
+
{
|
|
126
|
+
style: {
|
|
127
|
+
height: `${totalSteps.value * 100}vh`,
|
|
128
|
+
position: "relative"
|
|
129
|
+
},
|
|
130
|
+
...attrs
|
|
131
|
+
},
|
|
132
|
+
slots.default?.()
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
var FixedStage = defineComponent({
|
|
137
|
+
name: "FixedStage",
|
|
138
|
+
setup(_, { slots, attrs }) {
|
|
139
|
+
return () => h(
|
|
140
|
+
"div",
|
|
141
|
+
{
|
|
142
|
+
style: {
|
|
143
|
+
position: "fixed",
|
|
144
|
+
top: "0",
|
|
145
|
+
left: "0",
|
|
146
|
+
width: "100%",
|
|
147
|
+
height: "100vh",
|
|
148
|
+
touchAction: "pan-y"
|
|
149
|
+
},
|
|
150
|
+
...attrs
|
|
151
|
+
},
|
|
152
|
+
slots.default?.()
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
var Show = defineComponent({
|
|
157
|
+
name: "Show",
|
|
158
|
+
props: {
|
|
159
|
+
when: { type: String, required: true }
|
|
160
|
+
},
|
|
161
|
+
setup(props, { slots }) {
|
|
162
|
+
const { isActive } = useStep(props.when);
|
|
163
|
+
return () => isActive.value ? slots.default?.() : null;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
export { FixedStage, MultitrackProvider, ScrollContainer, Show, useOpacities, useScrollProgress, useStep, useTimeline };
|
|
168
|
+
//# sourceMappingURL=index.js.map
|
|
169
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/provider.ts","../src/composables.ts","../src/components.ts"],"names":["defineComponent","h"],"mappings":"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","file":"index.js","sourcesContent":["import type { InjectionKey, ShallowRef } from \"vue\";\nimport type { Timeline, Opacities, Step } from \"@multitrack/core\";\n\nexport interface MultitrackContextValue {\n timeline: Timeline;\n steps: Step[];\n totalSteps: number;\n scrollPercentage: number;\n currentStep: number;\n opacities: Opacities;\n}\n\nexport const MULTITRACK_KEY: InjectionKey<\n ShallowRef<MultitrackContextValue>\n> = Symbol(\"multitrack\");\n","import {\n defineComponent,\n h,\n shallowRef,\n provide,\n onMounted,\n onUnmounted,\n watch,\n type PropType,\n} from \"vue\";\nimport { Timeline, type StepConfig, type Scope } from \"@multitrack/core\";\nimport { MULTITRACK_KEY, type MultitrackContextValue } from \"./context.js\";\n\nexport const MultitrackProvider = defineComponent({\n name: \"MultitrackProvider\",\n props: {\n config: {\n type: Array as PropType<StepConfig[]>,\n required: true,\n },\n devtools: {\n type: Boolean,\n default: false,\n },\n breakpoints: {\n type: Object as PropType<Record<string, string>>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n let timeline: Timeline | null = null;\n let scope: Scope | null = null;\n\n const state = shallowRef<MultitrackContextValue>(null!);\n\n function setupTimeline() {\n // Clean up previous instance\n scope?.dispose();\n timeline?.destroy();\n\n const t = new Timeline({\n config: props.config,\n devtools: props.devtools,\n breakpoints: props.breakpoints,\n });\n timeline = t;\n\n state.value = {\n timeline: t,\n steps: t.steps,\n totalSteps: t.totalSteps,\n scrollPercentage: 0,\n currentStep: 0,\n opacities: t.getOpacities(0),\n };\n\n scope = t.scope(() => {\n t.on(\"scroll\", ({ scrollPercentage, currentStep }) => {\n state.value = {\n ...state.value,\n scrollPercentage,\n currentStep,\n opacities: t.getOpacities(scrollPercentage),\n };\n });\n\n t.on(\"timeline:reconfigure\", () => {\n state.value = {\n ...state.value,\n steps: t.steps,\n totalSteps: t.totalSteps,\n scrollPercentage: t.scrollPercentage,\n currentStep: t.currentStep,\n opacities: t.getOpacities(),\n };\n });\n });\n\n t.start();\n }\n\n provide(MULTITRACK_KEY, state);\n\n onMounted(() => {\n setupTimeline();\n });\n\n // Recreate timeline when props change\n watch(\n () => [props.config, props.devtools, props.breakpoints],\n () => {\n if (timeline) {\n setupTimeline();\n }\n },\n );\n\n onUnmounted(() => {\n scope?.dispose();\n timeline?.destroy();\n });\n\n return () => slots.default?.();\n },\n});\n","import { inject, computed } from \"vue\";\nimport type { Timeline, Opacities } from \"@multitrack/core\";\nimport { MULTITRACK_KEY } from \"./context.js\";\n\nfunction useMultitrackContext() {\n const state = inject(MULTITRACK_KEY);\n if (!state) {\n throw new Error(\n \"[@multitrack/vue] Composables must be used within a <MultitrackProvider>\",\n );\n }\n return state;\n}\n\n/**\n * Access the Timeline instance directly.\n */\nexport function useTimeline(): Timeline {\n return useMultitrackContext().value.timeline;\n}\n\n/**\n * Get current opacities for all steps.\n */\nexport function useOpacities<T extends string = string>() {\n const state = useMultitrackContext();\n return computed(() => state.value.opacities as Opacities<T>);\n}\n\n/**\n * Get opacity and active state for a single named step.\n */\nexport function useStep(name: string) {\n const state = useMultitrackContext();\n return {\n opacity: computed(() => state.value.opacities[name] ?? 0),\n isActive: computed(() => (state.value.opacities[name] ?? 0) > 0),\n };\n}\n\n/**\n * Get raw scroll progress and current step position.\n */\nexport function useScrollProgress() {\n const state = useMultitrackContext();\n return {\n scrollPercentage: computed(() => state.value.scrollPercentage),\n currentStep: computed(() => state.value.currentStep),\n totalSteps: computed(() => state.value.totalSteps),\n };\n}\n","import { defineComponent, h } from \"vue\";\nimport { useScrollProgress, useStep } from \"./composables.js\";\n\n/**\n * Creates the tall scrollable container that drives the timeline.\n * Height = totalSteps * 100vh.\n */\nexport const ScrollContainer = defineComponent({\n name: \"ScrollContainer\",\n setup(_, { slots, attrs }) {\n const { totalSteps } = useScrollProgress();\n\n return () =>\n h(\n \"div\",\n {\n style: {\n height: `${totalSteps.value * 100}vh`,\n position: \"relative\",\n },\n ...attrs,\n },\n slots.default?.(),\n );\n },\n});\n\n/**\n * Fixed viewport stage that stays in place while the user scrolls.\n * All animated content lives inside this.\n */\nexport const FixedStage = defineComponent({\n name: \"FixedStage\",\n setup(_, { slots, attrs }) {\n return () =>\n h(\n \"div\",\n {\n style: {\n position: \"fixed\",\n top: \"0\",\n left: \"0\",\n width: \"100%\",\n height: \"100vh\",\n touchAction: \"pan-y\",\n },\n ...attrs,\n },\n slots.default?.(),\n );\n },\n});\n\n/**\n * Conditionally renders children based on a step's opacity.\n * Unmounts children when the step is inactive (opacity 0) for performance.\n */\nexport const Show = defineComponent({\n name: \"Show\",\n props: {\n when: { type: String, required: true },\n },\n setup(props, { slots }) {\n const { isActive } = useStep(props.when);\n\n return () => (isActive.value ? slots.default?.() : null);\n },\n});\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@multitrack/vue",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Vue 3 bindings for @multitrack/core",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": ["dist"],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"dev": "tsup --watch"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"vue": ">=3.3.0"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@multitrack/core": "workspace:^"
|
|
31
|
+
},
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"author": "Jack Hsu",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/jakhsu/multitrack.git",
|
|
38
|
+
"directory": "packages/vue"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/jakhsu/multitrack/tree/main/packages/vue",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/jakhsu/multitrack/issues"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"scroll-animation",
|
|
46
|
+
"scroll-driven",
|
|
47
|
+
"timeline",
|
|
48
|
+
"vue",
|
|
49
|
+
"vue3",
|
|
50
|
+
"vue-composables",
|
|
51
|
+
"scrollytelling",
|
|
52
|
+
"multi-track"
|
|
53
|
+
],
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20"
|
|
59
|
+
}
|
|
60
|
+
}
|