@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 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"]}
@@ -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 };
@@ -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
+ }