@pixodesk/svg-animator-vue 1.0.30 โ 1.0.34
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 +7 -5
- package/dist/index.cjs +7 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +254 -92
- package/dist/index.umd.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# animator-vue
|
|
2
2
|
|
|
3
|
+
> ๐ Full user guide: [docs/library/vue.md](../../docs/library/vue.md) ยท [all docs](../../README.md#documentation)
|
|
4
|
+
|
|
3
5
|
[](https://github.com/pixodesk/pixodesk-svg-animator/actions/workflows/ci.yml)
|
|
4
6
|
[](https://opensource.org/licenses/MIT)
|
|
5
7
|
|
|
@@ -71,7 +73,7 @@ Render a single frame at a specific point in time:
|
|
|
71
73
|
```vue
|
|
72
74
|
<template>
|
|
73
75
|
<PixodeskSvgAnimator :doc="animationDoc" :time="0.5" />
|
|
74
|
-
<PixodeskSvgAnimator :doc="animationDoc" :
|
|
76
|
+
<PixodeskSvgAnimator :doc="animationDoc" :time="500" />
|
|
75
77
|
</template>
|
|
76
78
|
```
|
|
77
79
|
|
|
@@ -83,8 +85,8 @@ Render a single frame at a specific point in time:
|
|
|
83
85
|
| `autoplay` | `boolean` | Use triggers from the document |
|
|
84
86
|
| `play` | `boolean` | Start playback, ignoring document triggers |
|
|
85
87
|
| `pause` | `boolean` | Pause current playback |
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
+
| `progress` | `number` | show the frame at this position in the whole timeline (duration ร iterations): `0` is the first frame, `0.5` the middle, `1` the last |
|
|
89
|
+
| `time` | `number` | show the frame at that time, in milliseconds from the start |
|
|
88
90
|
| `mode` | `'auto' \| 'waapi' \| 'frames'` | Animation engine |
|
|
89
91
|
| `duration` | `number` | Duration override (ms) |
|
|
90
92
|
| `delay` | `number` | Delay before start (ms) |
|
|
@@ -95,9 +97,9 @@ Render a single frame at a specific point in time:
|
|
|
95
97
|
| `startOn` | `'load' \| 'mouseOver' \| 'click' \| 'scrollIntoView' \| 'programmatic'` | Trigger event override |
|
|
96
98
|
| `outAction` | `'continue' \| 'pause' \| 'reset' \| 'reverse'` | Behaviour when trigger ends |
|
|
97
99
|
|
|
98
|
-
With none of `autoplay` / `play` / `pause` / `
|
|
100
|
+
With none of `autoplay` / `play` / `pause` / `progress` / `time` set, the component renders the animation statically (initial state, no playback); use the template ref for imperative control.
|
|
99
101
|
|
|
100
|
-
Note:
|
|
102
|
+
Note: passing a different `doc` (or unmounting) throws the old animator away and builds a new one; the old instance emits `cancel`, `remove`, and `stop` on its way out. Changing `progress` / `time` does **not** recreate the animator โ it just jumps the existing one to the new time.
|
|
101
103
|
|
|
102
104
|
## Events
|
|
103
105
|
|
package/dist/index.cjs
CHANGED
|
@@ -101,13 +101,13 @@ function applyDocOverrides(doc, props, compMode) {
|
|
|
101
101
|
function calcSeekMs(doc, props) {
|
|
102
102
|
let seekMs;
|
|
103
103
|
const animator = doc.animator || {};
|
|
104
|
-
if (props.
|
|
104
|
+
if (props.progress !== void 0) {
|
|
105
105
|
const iterationsValue = props.iterations ?? animator.iterations;
|
|
106
106
|
const iterationsCount = typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
|
|
107
107
|
const singleDuration = props.duration ?? animator.duration ?? 1e3;
|
|
108
|
-
seekMs = props.
|
|
108
|
+
seekMs = props.progress * singleDuration * iterationsCount;
|
|
109
109
|
}
|
|
110
|
-
if (props.
|
|
110
|
+
if (props.time !== void 0) seekMs = props.time;
|
|
111
111
|
return seekMs;
|
|
112
112
|
}
|
|
113
113
|
var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
|
|
@@ -133,8 +133,8 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
|
|
|
133
133
|
play: { type: Boolean, default: void 0 },
|
|
134
134
|
pause: { type: Boolean, default: void 0 },
|
|
135
135
|
// -- Controlled time
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
progress: { type: Number },
|
|
137
|
+
time: { type: Number }
|
|
138
138
|
},
|
|
139
139
|
emits: ["play", "stop", "pause", "cancel", "finish", "remove"],
|
|
140
140
|
setup(props, { expose, emit }) {
|
|
@@ -142,7 +142,7 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
|
|
|
142
142
|
const apiRef = (0, import_vue.shallowRef)(null);
|
|
143
143
|
const compMode = (0, import_vue.computed)(() => {
|
|
144
144
|
if (props.autoplay) return "autoplay" /* autoplay */;
|
|
145
|
-
if (props.
|
|
145
|
+
if (props.progress !== void 0 || props.time !== void 0) return "fixedTime" /* fixedTime */;
|
|
146
146
|
if (props.play !== void 0 || props.pause !== void 0) return "play" /* play */;
|
|
147
147
|
return "static" /* static */;
|
|
148
148
|
});
|
|
@@ -223,7 +223,7 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
|
|
|
223
223
|
(0, import_vue.onMounted)(() => createApi());
|
|
224
224
|
(0, import_vue.watch)(resolvedDoc, () => createApi(), { flush: "post" });
|
|
225
225
|
(0, import_vue.watch)([compMode, () => props.play, () => props.pause], () => syncPlayState());
|
|
226
|
-
(0, import_vue.watch)([compMode, () => props.
|
|
226
|
+
(0, import_vue.watch)([compMode, () => props.progress, () => props.time], () => applySeek());
|
|
227
227
|
(0, import_vue.onUnmounted)(() => {
|
|
228
228
|
destroyApi();
|
|
229
229
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/PixodeskSvgAnimator.ts","../src/PixodeskSvgCssAnimator.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport PixodeskSvgAnimator from './PixodeskSvgAnimator';\nexport { PixodeskSvgAnimator };\nexport type { VueAnimatorApi } from './PixodeskSvgAnimator';\n\nimport PixodeskSvgCssAnimator from './PixodeskSvgCssAnimator';\nexport { PixodeskSvgCssAnimator };","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxAnimatedSvgDocument, PxAnimatorAPI, PxNode, PxPlatformAdapter, PxTrigger } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, FillMode, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES } from '@pixodesk/svg-animator-web';\nimport {\n computed, defineComponent, h, onMounted, onUnmounted, ref, shallowRef, type PropType, type VNode,\n watch,\n} from 'vue';\n\n\n// -- Public types -----------------------------------------------------------\n\nexport interface VueAnimatorApi {\n /** Returns true if the animation is currently running. */\n isPlaying(): boolean;\n\n /** Starts or resumes the animation. */\n play(): void;\n\n /** Pauses the animation at its current state. */\n pause(): void;\n\n /** Stops the animation and resets it to its initial state. */\n cancel(): void;\n\n /** Jumps to the end of the animation and holds the final state. */\n finish(): void;\n\n /** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */\n setPlaybackRate(rate: number): void;\n\n /** Returns the current playback time in milliseconds. */\n getCurrentTime(): number | null;\n\n /** Jumps to a specific time (in milliseconds) in the animation. */\n setCurrentTime(time: number): void;\n}\n\n\n// -- Internal types ---------------------------------------------------------\n\nenum CompMode {\n static = 'static',\n autoplay = 'autoplay',\n play = 'play',\n fixedTime = 'fixedTime'\n}\n\n\n// -- Vue โ Animator bridge --------------------------------------------------\n\n/**\n * Creates a platform adapter that routes animator attribute updates\n * to the corresponding Vue-managed DOM element refs.\n */\nfunction createVueAdapter(elementRefs: Map<string, Element>) {\n const warnedSelectors = new Set<string>();\n\n const adapter: PxPlatformAdapter = {\n isConnected: () => true,\n setAttribute: (id, attrName, value) => {\n attrName = camelCaseToKebabWordIfNeeded(attrName);\n\n const element = elementRefs.get(id);\n\n if (!element && !warnedSelectors.has(id)) {\n warnedSelectors.add(id);\n console.warn('setAttribute: No elements found for id \"' + id + '\"');\n }\n\n if (element) {\n element.setAttribute(attrName, value);\n if (STYLE_ATTR_NAMES.has(attrName)) {\n (element as HTMLElement).style[attrName as any] = value;\n }\n }\n },\n };\n return adapter;\n}\n\n// FIXME: add model validation (e.g. isElementFileJson check)\n\n\n// -- Helper: apply doc overrides --------------------------------------------\n\ninterface DocOverrideProps {\n mode?: 'waapi' | 'frames' | 'auto';\n delay?: number;\n fill?: FillMode;\n iterations?: number | 'infinite';\n duration?: number;\n direction?: PlaybackDirection;\n frameRate?: number;\n startOn?: 'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic';\n outAction?: 'continue' | 'pause' | 'reset' | 'reverse';\n scrollIntoViewThreshold?: number;\n time?: number;\n timeMs?: number;\n}\n\nfunction applyDocOverrides(\n doc: PxAnimatedSvgDocument,\n props: DocOverrideProps,\n compMode: CompMode,\n): PxAnimatedSvgDocument {\n\n // In non-autoplay modes, override the document trigger to 'programmatic'\n // so the component can manage playback itself.\n if (compMode !== CompMode.autoplay) {\n const docStartOn = doc.animator?.trigger?.startOn;\n if (docStartOn && docStartOn !== 'programmatic') { // FIXME: use enum\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: { ...doc.animator?.trigger, startOn: 'programmatic' }\n }\n };\n }\n }\n\n // Apply timing overrides from props onto the document config.\n const { mode, duration, delay, iterations, fill, direction, frameRate } = props;\n if (\n mode !== undefined || duration !== undefined || delay !== undefined ||\n iterations !== undefined || fill !== undefined || direction !== undefined ||\n frameRate !== undefined\n ) {\n const animator = doc.animator || {};\n doc = {\n ...doc,\n animator: {\n ...animator,\n mode: mode !== undefined ? mode : animator.mode,\n duration: duration !== undefined ? duration : animator.duration,\n delay: delay !== undefined ? delay : animator.delay,\n iterations: iterations !== undefined ? iterations : animator.iterations,\n fill: fill !== undefined ? fill : animator.fill,\n direction: direction !== undefined ? direction : animator.direction,\n frameRate: frameRate !== undefined ? frameRate : animator.frameRate,\n }\n };\n }\n\n // Apply trigger overrides from props.\n const { startOn, outAction, scrollIntoViewThreshold } = props;\n if (startOn !== undefined || outAction !== undefined || scrollIntoViewThreshold !== undefined) {\n const trigger: PxTrigger = doc.animator?.trigger || {};\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...trigger,\n startOn: startOn !== undefined ? startOn : trigger.startOn,\n outAction: outAction !== undefined ? outAction : trigger.outAction,\n scrollIntoViewThreshold: scrollIntoViewThreshold !== undefined ? scrollIntoViewThreshold : trigger.scrollIntoViewThreshold,\n }\n }\n };\n }\n\n return doc;\n}\n\n/**\n * Controlled-time mode: absolute seek target in ms. `time` is a fraction\n * (0โ1) of the WHOLE timeline (duration ร iterations); `timeMs` is absolute.\n * Applied through the animator API (setCurrentTime) so scrubbing does NOT\n * recreate the animator.\n */\nfunction calcSeekMs(doc: PxAnimatedSvgDocument, props: DocOverrideProps): number | undefined {\n let seekMs: number | undefined;\n const animator = doc.animator || {};\n if (props.time !== undefined) {\n const iterationsValue = props.iterations ?? animator.iterations;\n const iterationsCount = typeof iterationsValue === 'number' && iterationsValue >= 1 ? iterationsValue : 1;\n const singleDuration = props.duration ?? animator.duration ?? 1000; // engine default duration\n seekMs = props.time * singleDuration * iterationsCount;\n }\n if (props.timeMs !== undefined) seekMs = props.timeMs;\n return seekMs;\n}\n\n\n// -- Main public component --------------------------------------------------\n\n/**\n * Vue component for rendering and controlling Pixodesk SVG animations.\n *\n * Supports four mutually-exclusive control modes:\n *\n * 1. **Autoplay** โ uses triggers from the animation document.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" autoplay />\n * ```\n *\n * 2. **Declarative play/pause** โ controlled via boolean props.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" play :pause=\"false\" />\n * ```\n *\n * 3. **Imperative** โ exposes a ref-based API for full programmatic control.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" ref=\"animator\" />\n * <button @click=\"$refs.animator.play()\">Play</button>\n * ```\n *\n * 4. **Controlled time** โ renders a single frame at a given time.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" :time=\"0.5\" />\n * <PixodeskSvgAnimator :doc=\"animation\" :timeMs=\"500\" />\n * ```\n */\nconst PixodeskSvgAnimator = defineComponent({\n name: 'PixodeskSvgAnimator',\n\n props: {\n // -- Source\n doc: { type: Object as PropType<PxAnimatedSvgDocument>, required: true },\n\n // -- Rendering mode\n mode: { type: String as PropType<'waapi' | 'frames' | 'auto'> },\n\n // -- Timing overrides\n delay: { type: Number },\n fill: { type: String as PropType<FillMode> },\n iterations: { type: [Number, String] as PropType<number | 'infinite'> },\n duration: { type: Number },\n direction: { type: String as PropType<PlaybackDirection> },\n frameRate: { type: Number },\n\n // -- Trigger overrides\n startOn: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic'> },\n outAction: { type: String as PropType<'continue' | 'pause' | 'reset' | 'reverse'> },\n scrollIntoViewThreshold: { type: Number },\n\n // -- Declarative control\n autoplay: { type: Boolean, default: undefined },\n play: { type: Boolean, default: undefined },\n pause: { type: Boolean, default: undefined },\n\n // -- Controlled time\n time: { type: Number },\n timeMs: { type: Number },\n },\n\n emits: ['play', 'stop', 'pause', 'cancel', 'finish', 'remove'],\n\n setup(props, { expose, emit }) {\n const elementRefs = new Map<string, Element>();\n const apiRef = shallowRef<PxAnimatorAPI | null>(null);\n\n // -- Determine control mode ---------------------------------------------\n\n const compMode = computed<CompMode>(() => {\n if (props.autoplay) return CompMode.autoplay;\n if (props.time !== undefined || props.timeMs !== undefined) return CompMode.fixedTime;\n if (props.play !== undefined || props.pause !== undefined) return CompMode.play;\n return CompMode.static;\n });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n let doc = generateNewIds(props.doc);\n return applyDocOverrides(doc, props, compMode.value);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n function renderNode(node: PxNode | undefined): VNode | null {\n if (!node) return null;\n\n const { type, animate, meta, children, ...attrs } = node;\n const normProps = getNormalizedProps(attrs);\n\n // Capture a ref to each element with an id.\n if (node['id']) {\n const nodeId = node['id'];\n normProps['ref'] = (el: Element | null) => {\n if (el) {\n elementRefs.set(nodeId, el);\n } else {\n elementRefs.delete(nodeId);\n }\n };\n }\n\n const childVNodes = children?.map(child => renderNode(child)).filter(Boolean) as VNode[] | undefined;\n return h(type, normProps, childVNodes);\n }\n\n // -- Animator lifecycle -------------------------------------------------\n\n function createApi() {\n destroyApi();\n const doc = resolvedDoc.value;\n if (!doc) return;\n\n // Route animator lifecycle events to Vue component events.\n // `stop` fires alongside any event that halts playback.\n const callbacks = {\n onPlay: () => emit('play'),\n onPause: () => { emit('pause'); emit('stop'); },\n onCancel: () => { emit('cancel'); emit('stop'); },\n onFinish: () => { emit('finish'); emit('stop'); },\n onRemove: () => { emit('remove'); emit('stop'); },\n };\n\n apiRef.value = createAnimator({ data: doc, adapter: createVueAdapter(elementRefs), callbacks });\n\n // (Re)apply the declarative control state to the fresh animator โ\n // covers both the initial mount (e.g. `:play=\"true\"` from the\n // start) and doc swaps.\n syncPlayState();\n applySeek();\n }\n\n function destroyApi() {\n apiRef.value?.destroy();\n apiRef.value = null;\n }\n\n /** Declarative play/pause โ animator calls. */\n function syncPlayState() {\n if (compMode.value !== CompMode.play) return;\n if (props.play && !props.pause) {\n apiRef.value?.play();\n } else if (props.pause) {\n apiRef.value?.pause();\n } else if (props.play === false) {\n // explicit play=false โ jump to the end state\n apiRef.value?.finish();\n } else {\n // pause-only usage: pause switched off โ resume\n apiRef.value?.play();\n }\n }\n\n /** Controlled-time mode: seek through the animator API (no recreate). */\n function applySeek() {\n if (compMode.value !== CompMode.fixedTime) return;\n const doc = resolvedDoc.value;\n if (!doc) return;\n const seekMs = calcSeekMs(doc, props);\n if (seekMs !== undefined) {\n apiRef.value?.setCurrentTime(seekMs);\n apiRef.value?.pause();\n }\n }\n\n // Create the animator once DOM refs are available.\n onMounted(() => createApi());\n\n // Recreate the animator when the resolved doc changes.\n // `flush: 'post'` โ the animator must be created AFTER the DOM is\n // patched, otherwise the new root element isn't in the document yet\n // and trigger setup fails (autoplay would never resume after a doc swap).\n watch(resolvedDoc, () => createApi(), { flush: 'post' });\n\n // Sync declarative play/pause props with the animator.\n watch([compMode, () => props.play, () => props.pause], () => syncPlayState());\n\n // Scrubbing time/timeMs only seeks โ the animator is NOT recreated.\n watch([compMode, () => props.time, () => props.timeMs], () => applySeek());\n\n onUnmounted(() => {\n destroyApi();\n });\n\n // -- Expose imperative API ----------------------------------------------\n\n const publicApi: VueAnimatorApi = {\n isPlaying: () => apiRef.value?.isPlaying() || false,\n play: () => apiRef.value?.play(),\n pause: () => apiRef.value?.pause(),\n cancel: () => apiRef.value?.cancel(),\n finish: () => apiRef.value?.finish(),\n setPlaybackRate: (rate: number) => apiRef.value?.setPlaybackRate(rate),\n getCurrentTime: () => apiRef.value?.getCurrentTime() ?? null,\n setCurrentTime: (time: number) => apiRef.value?.setCurrentTime(time),\n };\n\n expose(publicApi);\n\n // -- Render -------------------------------------------------------------\n\n return () => {\n const doc = resolvedDoc.value;\n return doc ? renderNode(doc) : null;\n };\n },\n});\n\nexport default PixodeskSvgAnimator;\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { OutAction, StartOn } from \"@pixodesk/svg-animator-web\";\nimport { computed, defineComponent, h, onMounted, onUnmounted, ref, useAttrs, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n\n/**\n * Controls playback of a SVG+CSS animated file by toggling class names on a wrapper div.\n *\n * Intended for use with SVG files exported from the Pixodesk editor using the\n * **CSS Keyframes** flavor (no `<script>` tag). Import the SVG as a Vue component\n * via `vite-svg-loader` and pass it as the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg'; // vite-svg-loader\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator startOn=\"mouseOver\" outAction=\"pause\">\n * <AnimationSvg />\n * </PixodeskSvgCssAnimator>\n * </template>\n * ```\n *\n * The wrapper div carries one of three animation states via CSS class names:\n * - *(no class)* โ idle, animation not started\n * - `px-anim-enabled` โ started but paused\n * - `px-anim-enabled px-anim-playing` โ actively playing\n *\n * @prop startOn - What triggers the animation to start:\n * - `'load'` โ plays immediately on mount (default)\n * - `'mouseOver'` โ plays on hover\n * - `'click'` โ plays on click, toggles on second click\n * - `'scrollIntoView'` โ plays when the element enters the viewport\n * @prop outAction - What happens when the trigger ends (hover/scroll out, second click):\n * - `'continue'` โ keeps playing (default)\n * - `'pause'` โ pauses at the current frame\n * - `'reset'` โ resets to the beginning\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n\n inheritAttrs: false,\n\n props: {\n startOn: { type: String as PropType<StartOn>, default: 'load' },\n outAction: { type: String as PropType<OutAction>, default: 'continue' },\n },\n\n setup(props, { slots }) {\n const attrs = useAttrs();\n const state = ref<AnimState>(props.startOn === 'load' ? 'playing' : 'idle');\n const divRef = ref<HTMLDivElement | null>(null);\n\n const goOut = () => {\n state.value =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n };\n\n let observerCleanup: (() => void) | undefined;\n\n onMounted(() => {\n if (props.startOn !== 'scrollIntoView') return;\n const el = divRef.value;\n if (!el) return;\n const outState: AnimState =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n const observer = new IntersectionObserver(\n ([entry]) => { state.value = entry.isIntersecting ? 'playing' : outState; },\n { threshold: 0.1 }\n );\n observer.observe(el);\n observerCleanup = () => observer.disconnect();\n });\n\n onUnmounted(() => observerCleanup?.());\n\n const animClass = computed(() =>\n state.value === 'playing' ? 'px-anim-enabled px-anim-playing' :\n state.value === 'paused' ? 'px-anim-enabled' : ''\n );\n\n const handlers = computed(() =>\n props.startOn === 'mouseOver' ? {\n onMouseenter: () => { state.value = 'playing'; },\n onMouseleave: goOut,\n } :\n props.startOn === 'click' ? {\n onClick: () => state.value === 'playing' ? goOut() : (state.value = 'playing'),\n } : {}\n );\n\n return () => h('div', {\n ref: divRef,\n ...attrs,\n class: [attrs.class, animClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\n\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["import_vue"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/PixodeskSvgAnimator.ts","../src/PixodeskSvgCssAnimator.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport PixodeskSvgAnimator from './PixodeskSvgAnimator';\nexport { PixodeskSvgAnimator };\nexport type { VueAnimatorApi } from './PixodeskSvgAnimator';\n\nimport PixodeskSvgCssAnimator from './PixodeskSvgCssAnimator';\nexport { PixodeskSvgCssAnimator };","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxAnimatedSvgDocument, PxAnimatorAPI, PxNode, PxPlatformAdapter, PxTrigger } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, FillMode, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES } from '@pixodesk/svg-animator-web';\nimport {\n computed, defineComponent, h, onMounted, onUnmounted, ref, shallowRef, type PropType, type VNode,\n watch,\n} from 'vue';\n\n\n// -- Public types -----------------------------------------------------------\n\nexport interface VueAnimatorApi {\n /** Returns true if the animation is currently running. */\n isPlaying(): boolean;\n\n /** Starts or resumes the animation. */\n play(): void;\n\n /** Pauses the animation at its current state. */\n pause(): void;\n\n /** Stops the animation and resets it to its initial state. */\n cancel(): void;\n\n /** Jumps to the end of the animation and holds the final state. */\n finish(): void;\n\n /** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */\n setPlaybackRate(rate: number): void;\n\n /** Returns the current playback time in milliseconds. */\n getCurrentTime(): number | null;\n\n /** Jumps to a specific time (in milliseconds) in the animation. */\n setCurrentTime(time: number): void;\n}\n\n\n// -- Internal types ---------------------------------------------------------\n\nenum CompMode {\n static = 'static',\n autoplay = 'autoplay',\n play = 'play',\n fixedTime = 'fixedTime'\n}\n\n\n// -- Vue โ Animator bridge --------------------------------------------------\n\n/**\n * Creates a platform adapter that routes animator attribute updates\n * to the corresponding Vue-managed DOM element refs.\n */\nfunction createVueAdapter(elementRefs: Map<string, Element>) {\n const warnedSelectors = new Set<string>();\n\n const adapter: PxPlatformAdapter = {\n isConnected: () => true,\n setAttribute: (id, attrName, value) => {\n attrName = camelCaseToKebabWordIfNeeded(attrName);\n\n const element = elementRefs.get(id);\n\n if (!element && !warnedSelectors.has(id)) {\n warnedSelectors.add(id);\n console.warn('setAttribute: No elements found for id \"' + id + '\"');\n }\n\n if (element) {\n element.setAttribute(attrName, value);\n if (STYLE_ATTR_NAMES.has(attrName)) {\n (element as HTMLElement).style[attrName as any] = value;\n }\n }\n },\n };\n return adapter;\n}\n\n// FIXME: add model validation (e.g. isElementFileJson check)\n\n\n// -- Helper: apply doc overrides --------------------------------------------\n\ninterface DocOverrideProps {\n mode?: 'waapi' | 'frames' | 'auto';\n delay?: number;\n fill?: FillMode;\n iterations?: number | 'infinite';\n duration?: number;\n direction?: PlaybackDirection;\n frameRate?: number;\n startOn?: 'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic';\n outAction?: 'continue' | 'pause' | 'reset' | 'reverse';\n scrollIntoViewThreshold?: number;\n progress?: number;\n time?: number;\n}\n\nfunction applyDocOverrides(\n doc: PxAnimatedSvgDocument,\n props: DocOverrideProps,\n compMode: CompMode,\n): PxAnimatedSvgDocument {\n\n // In non-autoplay modes, override the document trigger to 'programmatic'\n // so the component can manage playback itself.\n if (compMode !== CompMode.autoplay) {\n const docStartOn = doc.animator?.trigger?.startOn;\n if (docStartOn && docStartOn !== 'programmatic') { // FIXME: use enum\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: { ...doc.animator?.trigger, startOn: 'programmatic' }\n }\n };\n }\n }\n\n // Apply timing overrides from props onto the document config.\n const { mode, duration, delay, iterations, fill, direction, frameRate } = props;\n if (\n mode !== undefined || duration !== undefined || delay !== undefined ||\n iterations !== undefined || fill !== undefined || direction !== undefined ||\n frameRate !== undefined\n ) {\n const animator = doc.animator || {};\n doc = {\n ...doc,\n animator: {\n ...animator,\n mode: mode !== undefined ? mode : animator.mode,\n duration: duration !== undefined ? duration : animator.duration,\n delay: delay !== undefined ? delay : animator.delay,\n iterations: iterations !== undefined ? iterations : animator.iterations,\n fill: fill !== undefined ? fill : animator.fill,\n direction: direction !== undefined ? direction : animator.direction,\n frameRate: frameRate !== undefined ? frameRate : animator.frameRate,\n }\n };\n }\n\n // Apply trigger overrides from props.\n const { startOn, outAction, scrollIntoViewThreshold } = props;\n if (startOn !== undefined || outAction !== undefined || scrollIntoViewThreshold !== undefined) {\n const trigger: PxTrigger = doc.animator?.trigger || {};\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...trigger,\n startOn: startOn !== undefined ? startOn : trigger.startOn,\n outAction: outAction !== undefined ? outAction : trigger.outAction,\n scrollIntoViewThreshold: scrollIntoViewThreshold !== undefined ? scrollIntoViewThreshold : trigger.scrollIntoViewThreshold,\n }\n }\n };\n }\n\n return doc;\n}\n\n/**\n * Controlled-time mode: absolute seek target in ms. `progress` is a fraction\n * (0โ1) of the WHOLE timeline (duration ร iterations); `time` is absolute.\n * Applied through the animator API (setCurrentTime) so scrubbing does NOT\n * recreate the animator.\n */\nfunction calcSeekMs(doc: PxAnimatedSvgDocument, props: DocOverrideProps): number | undefined {\n let seekMs: number | undefined;\n const animator = doc.animator || {};\n if (props.progress !== undefined) {\n const iterationsValue = props.iterations ?? animator.iterations;\n const iterationsCount = typeof iterationsValue === 'number' && iterationsValue >= 1 ? iterationsValue : 1;\n const singleDuration = props.duration ?? animator.duration ?? 1000; // engine default duration\n seekMs = props.progress * singleDuration * iterationsCount;\n }\n if (props.time !== undefined) seekMs = props.time;\n return seekMs;\n}\n\n\n// -- Main public component --------------------------------------------------\n\n/**\n * Vue component for rendering and controlling Pixodesk SVG animations.\n *\n * Supports four mutually-exclusive control modes:\n *\n * 1. **Autoplay** โ uses triggers from the animation document.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" autoplay />\n * ```\n *\n * 2. **Declarative play/pause** โ controlled via boolean props.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" play :pause=\"false\" />\n * ```\n *\n * 3. **Imperative** โ exposes a ref-based API for full programmatic control.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" ref=\"animator\" />\n * <button @click=\"$refs.animator.play()\">Play</button>\n * ```\n *\n * 4. **Controlled time** โ renders a single frame at a given time.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" :progress=\"0.5\" />\n * <PixodeskSvgAnimator :doc=\"animation\" :time=\"500\" />\n * ```\n */\nconst PixodeskSvgAnimator = defineComponent({\n name: 'PixodeskSvgAnimator',\n\n props: {\n // -- Source\n doc: { type: Object as PropType<PxAnimatedSvgDocument>, required: true },\n\n // -- Rendering mode\n mode: { type: String as PropType<'waapi' | 'frames' | 'auto'> },\n\n // -- Timing overrides\n delay: { type: Number },\n fill: { type: String as PropType<FillMode> },\n iterations: { type: [Number, String] as PropType<number | 'infinite'> },\n duration: { type: Number },\n direction: { type: String as PropType<PlaybackDirection> },\n frameRate: { type: Number },\n\n // -- Trigger overrides\n startOn: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic'> },\n outAction: { type: String as PropType<'continue' | 'pause' | 'reset' | 'reverse'> },\n scrollIntoViewThreshold: { type: Number },\n\n // -- Declarative control\n autoplay: { type: Boolean, default: undefined },\n play: { type: Boolean, default: undefined },\n pause: { type: Boolean, default: undefined },\n\n // -- Controlled time\n progress: { type: Number },\n time: { type: Number },\n },\n\n emits: ['play', 'stop', 'pause', 'cancel', 'finish', 'remove'],\n\n setup(props, { expose, emit }) {\n const elementRefs = new Map<string, Element>();\n const apiRef = shallowRef<PxAnimatorAPI | null>(null);\n\n // -- Determine control mode ---------------------------------------------\n\n const compMode = computed<CompMode>(() => {\n if (props.autoplay) return CompMode.autoplay;\n if (props.progress !== undefined || props.time !== undefined) return CompMode.fixedTime;\n if (props.play !== undefined || props.pause !== undefined) return CompMode.play;\n return CompMode.static;\n });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n let doc = generateNewIds(props.doc);\n return applyDocOverrides(doc, props, compMode.value);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n function renderNode(node: PxNode | undefined): VNode | null {\n if (!node) return null;\n\n const { type, animate, meta, children, ...attrs } = node;\n const normProps = getNormalizedProps(attrs);\n\n // Capture a ref to each element with an id.\n if (node['id']) {\n const nodeId = node['id'];\n normProps['ref'] = (el: Element | null) => {\n if (el) {\n elementRefs.set(nodeId, el);\n } else {\n elementRefs.delete(nodeId);\n }\n };\n }\n\n const childVNodes = children?.map(child => renderNode(child)).filter(Boolean) as VNode[] | undefined;\n return h(type, normProps, childVNodes);\n }\n\n // -- Animator lifecycle -------------------------------------------------\n\n function createApi() {\n destroyApi();\n const doc = resolvedDoc.value;\n if (!doc) return;\n\n // Route animator lifecycle events to Vue component events.\n // `stop` fires alongside any event that halts playback.\n const callbacks = {\n onPlay: () => emit('play'),\n onPause: () => { emit('pause'); emit('stop'); },\n onCancel: () => { emit('cancel'); emit('stop'); },\n onFinish: () => { emit('finish'); emit('stop'); },\n onRemove: () => { emit('remove'); emit('stop'); },\n };\n\n apiRef.value = createAnimator({ data: doc, adapter: createVueAdapter(elementRefs), callbacks });\n\n // (Re)apply the declarative control state to the fresh animator โ\n // covers both the initial mount (e.g. `:play=\"true\"` from the\n // start) and doc swaps.\n syncPlayState();\n applySeek();\n }\n\n function destroyApi() {\n apiRef.value?.destroy();\n apiRef.value = null;\n }\n\n /** Declarative play/pause โ animator calls. */\n function syncPlayState() {\n if (compMode.value !== CompMode.play) return;\n if (props.play && !props.pause) {\n apiRef.value?.play();\n } else if (props.pause) {\n apiRef.value?.pause();\n } else if (props.play === false) {\n // explicit play=false โ jump to the end state\n apiRef.value?.finish();\n } else {\n // pause-only usage: pause switched off โ resume\n apiRef.value?.play();\n }\n }\n\n /** Controlled-time mode: seek through the animator API (no recreate). */\n function applySeek() {\n if (compMode.value !== CompMode.fixedTime) return;\n const doc = resolvedDoc.value;\n if (!doc) return;\n const seekMs = calcSeekMs(doc, props);\n if (seekMs !== undefined) {\n apiRef.value?.setCurrentTime(seekMs);\n apiRef.value?.pause();\n }\n }\n\n // Create the animator once DOM refs are available.\n onMounted(() => createApi());\n\n // Recreate the animator when the resolved doc changes.\n // `flush: 'post'` โ the animator must be created AFTER the DOM is\n // patched, otherwise the new root element isn't in the document yet\n // and trigger setup fails (autoplay would never resume after a doc swap).\n watch(resolvedDoc, () => createApi(), { flush: 'post' });\n\n // Sync declarative play/pause props with the animator.\n watch([compMode, () => props.play, () => props.pause], () => syncPlayState());\n\n // Scrubbing progress/time only seeks โ the animator is NOT recreated.\n watch([compMode, () => props.progress, () => props.time], () => applySeek());\n\n onUnmounted(() => {\n destroyApi();\n });\n\n // -- Expose imperative API ----------------------------------------------\n\n const publicApi: VueAnimatorApi = {\n isPlaying: () => apiRef.value?.isPlaying() || false,\n play: () => apiRef.value?.play(),\n pause: () => apiRef.value?.pause(),\n cancel: () => apiRef.value?.cancel(),\n finish: () => apiRef.value?.finish(),\n setPlaybackRate: (rate: number) => apiRef.value?.setPlaybackRate(rate),\n getCurrentTime: () => apiRef.value?.getCurrentTime() ?? null,\n setCurrentTime: (time: number) => apiRef.value?.setCurrentTime(time),\n };\n\n expose(publicApi);\n\n // -- Render -------------------------------------------------------------\n\n return () => {\n const doc = resolvedDoc.value;\n return doc ? renderNode(doc) : null;\n };\n },\n});\n\nexport default PixodeskSvgAnimator;\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { OutAction, StartOn } from \"@pixodesk/svg-animator-web\";\nimport { computed, defineComponent, h, onMounted, onUnmounted, ref, useAttrs, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n\n/**\n * Controls playback of a SVG+CSS animated file by toggling class names on a wrapper div.\n *\n * Intended for use with SVG files exported from the Pixodesk editor using the\n * **CSS Keyframes** flavor (no `<script>` tag). Import the SVG as a Vue component\n * via `vite-svg-loader` and pass it as the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg'; // vite-svg-loader\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator startOn=\"mouseOver\" outAction=\"pause\">\n * <AnimationSvg />\n * </PixodeskSvgCssAnimator>\n * </template>\n * ```\n *\n * The wrapper div carries one of three animation states via CSS class names:\n * - *(no class)* โ idle, animation not started\n * - `px-anim-enabled` โ started but paused\n * - `px-anim-enabled px-anim-playing` โ actively playing\n *\n * @prop startOn - What triggers the animation to start:\n * - `'load'` โ plays immediately on mount (default)\n * - `'mouseOver'` โ plays on hover\n * - `'click'` โ plays on click, toggles on second click\n * - `'scrollIntoView'` โ plays when the element enters the viewport\n * @prop outAction - What happens when the trigger ends (hover/scroll out, second click):\n * - `'continue'` โ keeps playing (default)\n * - `'pause'` โ pauses at the current frame\n * - `'reset'` โ resets to the beginning\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n\n inheritAttrs: false,\n\n props: {\n startOn: { type: String as PropType<StartOn>, default: 'load' },\n outAction: { type: String as PropType<OutAction>, default: 'continue' },\n },\n\n setup(props, { slots }) {\n const attrs = useAttrs();\n const state = ref<AnimState>(props.startOn === 'load' ? 'playing' : 'idle');\n const divRef = ref<HTMLDivElement | null>(null);\n\n const goOut = () => {\n state.value =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n };\n\n let observerCleanup: (() => void) | undefined;\n\n onMounted(() => {\n if (props.startOn !== 'scrollIntoView') return;\n const el = divRef.value;\n if (!el) return;\n const outState: AnimState =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n const observer = new IntersectionObserver(\n ([entry]) => { state.value = entry.isIntersecting ? 'playing' : outState; },\n { threshold: 0.1 }\n );\n observer.observe(el);\n observerCleanup = () => observer.disconnect();\n });\n\n onUnmounted(() => observerCleanup?.());\n\n const animClass = computed(() =>\n state.value === 'playing' ? 'px-anim-enabled px-anim-playing' :\n state.value === 'paused' ? 'px-anim-enabled' : ''\n );\n\n const handlers = computed(() =>\n props.startOn === 'mouseOver' ? {\n onMouseenter: () => { state.value = 'playing'; },\n onMouseleave: goOut,\n } :\n props.startOn === 'click' ? {\n onClick: () => state.value === 'playing' ? goOut() : (state.value = 'playing'),\n } : {}\n );\n\n return () => h('div', {\n ref: divRef,\n ...attrs,\n class: [attrs.class, animClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\n\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["import_vue"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -43,8 +43,8 @@ interface VueAnimatorApi {
|
|
|
43
43
|
*
|
|
44
44
|
* 4. **Controlled time** โ renders a single frame at a given time.
|
|
45
45
|
* ```vue
|
|
46
|
-
* <PixodeskSvgAnimator :doc="animation" :
|
|
47
|
-
* <PixodeskSvgAnimator :doc="animation" :
|
|
46
|
+
* <PixodeskSvgAnimator :doc="animation" :progress="0.5" />
|
|
47
|
+
* <PixodeskSvgAnimator :doc="animation" :time="500" />
|
|
48
48
|
* ```
|
|
49
49
|
*/
|
|
50
50
|
declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
@@ -94,10 +94,10 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
94
94
|
type: BooleanConstructor;
|
|
95
95
|
default: undefined;
|
|
96
96
|
};
|
|
97
|
-
|
|
97
|
+
progress: {
|
|
98
98
|
type: NumberConstructor;
|
|
99
99
|
};
|
|
100
|
-
|
|
100
|
+
time: {
|
|
101
101
|
type: NumberConstructor;
|
|
102
102
|
};
|
|
103
103
|
}>, () => VNode<vue.RendererNode, vue.RendererElement, {
|
|
@@ -149,10 +149,10 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
149
149
|
type: BooleanConstructor;
|
|
150
150
|
default: undefined;
|
|
151
151
|
};
|
|
152
|
-
|
|
152
|
+
progress: {
|
|
153
153
|
type: NumberConstructor;
|
|
154
154
|
};
|
|
155
|
-
|
|
155
|
+
time: {
|
|
156
156
|
type: NumberConstructor;
|
|
157
157
|
};
|
|
158
158
|
}>> & Readonly<{
|
package/dist/index.d.ts
CHANGED
|
@@ -43,8 +43,8 @@ interface VueAnimatorApi {
|
|
|
43
43
|
*
|
|
44
44
|
* 4. **Controlled time** โ renders a single frame at a given time.
|
|
45
45
|
* ```vue
|
|
46
|
-
* <PixodeskSvgAnimator :doc="animation" :
|
|
47
|
-
* <PixodeskSvgAnimator :doc="animation" :
|
|
46
|
+
* <PixodeskSvgAnimator :doc="animation" :progress="0.5" />
|
|
47
|
+
* <PixodeskSvgAnimator :doc="animation" :time="500" />
|
|
48
48
|
* ```
|
|
49
49
|
*/
|
|
50
50
|
declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
@@ -94,10 +94,10 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
94
94
|
type: BooleanConstructor;
|
|
95
95
|
default: undefined;
|
|
96
96
|
};
|
|
97
|
-
|
|
97
|
+
progress: {
|
|
98
98
|
type: NumberConstructor;
|
|
99
99
|
};
|
|
100
|
-
|
|
100
|
+
time: {
|
|
101
101
|
type: NumberConstructor;
|
|
102
102
|
};
|
|
103
103
|
}>, () => VNode<vue.RendererNode, vue.RendererElement, {
|
|
@@ -149,10 +149,10 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
149
149
|
type: BooleanConstructor;
|
|
150
150
|
default: undefined;
|
|
151
151
|
};
|
|
152
|
-
|
|
152
|
+
progress: {
|
|
153
153
|
type: NumberConstructor;
|
|
154
154
|
};
|
|
155
|
-
|
|
155
|
+
time: {
|
|
156
156
|
type: NumberConstructor;
|
|
157
157
|
};
|
|
158
158
|
}>> & Readonly<{
|
package/dist/index.js
CHANGED
|
@@ -83,13 +83,13 @@ function applyDocOverrides(doc, props, compMode) {
|
|
|
83
83
|
function calcSeekMs(doc, props) {
|
|
84
84
|
let seekMs;
|
|
85
85
|
const animator = doc.animator || {};
|
|
86
|
-
if (props.
|
|
86
|
+
if (props.progress !== void 0) {
|
|
87
87
|
const iterationsValue = props.iterations ?? animator.iterations;
|
|
88
88
|
const iterationsCount = typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
|
|
89
89
|
const singleDuration = props.duration ?? animator.duration ?? 1e3;
|
|
90
|
-
seekMs = props.
|
|
90
|
+
seekMs = props.progress * singleDuration * iterationsCount;
|
|
91
91
|
}
|
|
92
|
-
if (props.
|
|
92
|
+
if (props.time !== void 0) seekMs = props.time;
|
|
93
93
|
return seekMs;
|
|
94
94
|
}
|
|
95
95
|
var PixodeskSvgAnimator = defineComponent({
|
|
@@ -115,8 +115,8 @@ var PixodeskSvgAnimator = defineComponent({
|
|
|
115
115
|
play: { type: Boolean, default: void 0 },
|
|
116
116
|
pause: { type: Boolean, default: void 0 },
|
|
117
117
|
// -- Controlled time
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
progress: { type: Number },
|
|
119
|
+
time: { type: Number }
|
|
120
120
|
},
|
|
121
121
|
emits: ["play", "stop", "pause", "cancel", "finish", "remove"],
|
|
122
122
|
setup(props, { expose, emit }) {
|
|
@@ -124,7 +124,7 @@ var PixodeskSvgAnimator = defineComponent({
|
|
|
124
124
|
const apiRef = shallowRef(null);
|
|
125
125
|
const compMode = computed(() => {
|
|
126
126
|
if (props.autoplay) return "autoplay" /* autoplay */;
|
|
127
|
-
if (props.
|
|
127
|
+
if (props.progress !== void 0 || props.time !== void 0) return "fixedTime" /* fixedTime */;
|
|
128
128
|
if (props.play !== void 0 || props.pause !== void 0) return "play" /* play */;
|
|
129
129
|
return "static" /* static */;
|
|
130
130
|
});
|
|
@@ -205,7 +205,7 @@ var PixodeskSvgAnimator = defineComponent({
|
|
|
205
205
|
onMounted(() => createApi());
|
|
206
206
|
watch(resolvedDoc, () => createApi(), { flush: "post" });
|
|
207
207
|
watch([compMode, () => props.play, () => props.pause], () => syncPlayState());
|
|
208
|
-
watch([compMode, () => props.
|
|
208
|
+
watch([compMode, () => props.progress, () => props.time], () => applySeek());
|
|
209
209
|
onUnmounted(() => {
|
|
210
210
|
destroyApi();
|
|
211
211
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/PixodeskSvgAnimator.ts","../src/PixodeskSvgCssAnimator.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxAnimatedSvgDocument, PxAnimatorAPI, PxNode, PxPlatformAdapter, PxTrigger } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, FillMode, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES } from '@pixodesk/svg-animator-web';\nimport {\n computed, defineComponent, h, onMounted, onUnmounted, ref, shallowRef, type PropType, type VNode,\n watch,\n} from 'vue';\n\n\n// -- Public types -----------------------------------------------------------\n\nexport interface VueAnimatorApi {\n /** Returns true if the animation is currently running. */\n isPlaying(): boolean;\n\n /** Starts or resumes the animation. */\n play(): void;\n\n /** Pauses the animation at its current state. */\n pause(): void;\n\n /** Stops the animation and resets it to its initial state. */\n cancel(): void;\n\n /** Jumps to the end of the animation and holds the final state. */\n finish(): void;\n\n /** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */\n setPlaybackRate(rate: number): void;\n\n /** Returns the current playback time in milliseconds. */\n getCurrentTime(): number | null;\n\n /** Jumps to a specific time (in milliseconds) in the animation. */\n setCurrentTime(time: number): void;\n}\n\n\n// -- Internal types ---------------------------------------------------------\n\nenum CompMode {\n static = 'static',\n autoplay = 'autoplay',\n play = 'play',\n fixedTime = 'fixedTime'\n}\n\n\n// -- Vue โ Animator bridge --------------------------------------------------\n\n/**\n * Creates a platform adapter that routes animator attribute updates\n * to the corresponding Vue-managed DOM element refs.\n */\nfunction createVueAdapter(elementRefs: Map<string, Element>) {\n const warnedSelectors = new Set<string>();\n\n const adapter: PxPlatformAdapter = {\n isConnected: () => true,\n setAttribute: (id, attrName, value) => {\n attrName = camelCaseToKebabWordIfNeeded(attrName);\n\n const element = elementRefs.get(id);\n\n if (!element && !warnedSelectors.has(id)) {\n warnedSelectors.add(id);\n console.warn('setAttribute: No elements found for id \"' + id + '\"');\n }\n\n if (element) {\n element.setAttribute(attrName, value);\n if (STYLE_ATTR_NAMES.has(attrName)) {\n (element as HTMLElement).style[attrName as any] = value;\n }\n }\n },\n };\n return adapter;\n}\n\n// FIXME: add model validation (e.g. isElementFileJson check)\n\n\n// -- Helper: apply doc overrides --------------------------------------------\n\ninterface DocOverrideProps {\n mode?: 'waapi' | 'frames' | 'auto';\n delay?: number;\n fill?: FillMode;\n iterations?: number | 'infinite';\n duration?: number;\n direction?: PlaybackDirection;\n frameRate?: number;\n startOn?: 'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic';\n outAction?: 'continue' | 'pause' | 'reset' | 'reverse';\n scrollIntoViewThreshold?: number;\n time?: number;\n timeMs?: number;\n}\n\nfunction applyDocOverrides(\n doc: PxAnimatedSvgDocument,\n props: DocOverrideProps,\n compMode: CompMode,\n): PxAnimatedSvgDocument {\n\n // In non-autoplay modes, override the document trigger to 'programmatic'\n // so the component can manage playback itself.\n if (compMode !== CompMode.autoplay) {\n const docStartOn = doc.animator?.trigger?.startOn;\n if (docStartOn && docStartOn !== 'programmatic') { // FIXME: use enum\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: { ...doc.animator?.trigger, startOn: 'programmatic' }\n }\n };\n }\n }\n\n // Apply timing overrides from props onto the document config.\n const { mode, duration, delay, iterations, fill, direction, frameRate } = props;\n if (\n mode !== undefined || duration !== undefined || delay !== undefined ||\n iterations !== undefined || fill !== undefined || direction !== undefined ||\n frameRate !== undefined\n ) {\n const animator = doc.animator || {};\n doc = {\n ...doc,\n animator: {\n ...animator,\n mode: mode !== undefined ? mode : animator.mode,\n duration: duration !== undefined ? duration : animator.duration,\n delay: delay !== undefined ? delay : animator.delay,\n iterations: iterations !== undefined ? iterations : animator.iterations,\n fill: fill !== undefined ? fill : animator.fill,\n direction: direction !== undefined ? direction : animator.direction,\n frameRate: frameRate !== undefined ? frameRate : animator.frameRate,\n }\n };\n }\n\n // Apply trigger overrides from props.\n const { startOn, outAction, scrollIntoViewThreshold } = props;\n if (startOn !== undefined || outAction !== undefined || scrollIntoViewThreshold !== undefined) {\n const trigger: PxTrigger = doc.animator?.trigger || {};\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...trigger,\n startOn: startOn !== undefined ? startOn : trigger.startOn,\n outAction: outAction !== undefined ? outAction : trigger.outAction,\n scrollIntoViewThreshold: scrollIntoViewThreshold !== undefined ? scrollIntoViewThreshold : trigger.scrollIntoViewThreshold,\n }\n }\n };\n }\n\n return doc;\n}\n\n/**\n * Controlled-time mode: absolute seek target in ms. `time` is a fraction\n * (0โ1) of the WHOLE timeline (duration ร iterations); `timeMs` is absolute.\n * Applied through the animator API (setCurrentTime) so scrubbing does NOT\n * recreate the animator.\n */\nfunction calcSeekMs(doc: PxAnimatedSvgDocument, props: DocOverrideProps): number | undefined {\n let seekMs: number | undefined;\n const animator = doc.animator || {};\n if (props.time !== undefined) {\n const iterationsValue = props.iterations ?? animator.iterations;\n const iterationsCount = typeof iterationsValue === 'number' && iterationsValue >= 1 ? iterationsValue : 1;\n const singleDuration = props.duration ?? animator.duration ?? 1000; // engine default duration\n seekMs = props.time * singleDuration * iterationsCount;\n }\n if (props.timeMs !== undefined) seekMs = props.timeMs;\n return seekMs;\n}\n\n\n// -- Main public component --------------------------------------------------\n\n/**\n * Vue component for rendering and controlling Pixodesk SVG animations.\n *\n * Supports four mutually-exclusive control modes:\n *\n * 1. **Autoplay** โ uses triggers from the animation document.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" autoplay />\n * ```\n *\n * 2. **Declarative play/pause** โ controlled via boolean props.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" play :pause=\"false\" />\n * ```\n *\n * 3. **Imperative** โ exposes a ref-based API for full programmatic control.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" ref=\"animator\" />\n * <button @click=\"$refs.animator.play()\">Play</button>\n * ```\n *\n * 4. **Controlled time** โ renders a single frame at a given time.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" :time=\"0.5\" />\n * <PixodeskSvgAnimator :doc=\"animation\" :timeMs=\"500\" />\n * ```\n */\nconst PixodeskSvgAnimator = defineComponent({\n name: 'PixodeskSvgAnimator',\n\n props: {\n // -- Source\n doc: { type: Object as PropType<PxAnimatedSvgDocument>, required: true },\n\n // -- Rendering mode\n mode: { type: String as PropType<'waapi' | 'frames' | 'auto'> },\n\n // -- Timing overrides\n delay: { type: Number },\n fill: { type: String as PropType<FillMode> },\n iterations: { type: [Number, String] as PropType<number | 'infinite'> },\n duration: { type: Number },\n direction: { type: String as PropType<PlaybackDirection> },\n frameRate: { type: Number },\n\n // -- Trigger overrides\n startOn: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic'> },\n outAction: { type: String as PropType<'continue' | 'pause' | 'reset' | 'reverse'> },\n scrollIntoViewThreshold: { type: Number },\n\n // -- Declarative control\n autoplay: { type: Boolean, default: undefined },\n play: { type: Boolean, default: undefined },\n pause: { type: Boolean, default: undefined },\n\n // -- Controlled time\n time: { type: Number },\n timeMs: { type: Number },\n },\n\n emits: ['play', 'stop', 'pause', 'cancel', 'finish', 'remove'],\n\n setup(props, { expose, emit }) {\n const elementRefs = new Map<string, Element>();\n const apiRef = shallowRef<PxAnimatorAPI | null>(null);\n\n // -- Determine control mode ---------------------------------------------\n\n const compMode = computed<CompMode>(() => {\n if (props.autoplay) return CompMode.autoplay;\n if (props.time !== undefined || props.timeMs !== undefined) return CompMode.fixedTime;\n if (props.play !== undefined || props.pause !== undefined) return CompMode.play;\n return CompMode.static;\n });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n let doc = generateNewIds(props.doc);\n return applyDocOverrides(doc, props, compMode.value);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n function renderNode(node: PxNode | undefined): VNode | null {\n if (!node) return null;\n\n const { type, animate, meta, children, ...attrs } = node;\n const normProps = getNormalizedProps(attrs);\n\n // Capture a ref to each element with an id.\n if (node['id']) {\n const nodeId = node['id'];\n normProps['ref'] = (el: Element | null) => {\n if (el) {\n elementRefs.set(nodeId, el);\n } else {\n elementRefs.delete(nodeId);\n }\n };\n }\n\n const childVNodes = children?.map(child => renderNode(child)).filter(Boolean) as VNode[] | undefined;\n return h(type, normProps, childVNodes);\n }\n\n // -- Animator lifecycle -------------------------------------------------\n\n function createApi() {\n destroyApi();\n const doc = resolvedDoc.value;\n if (!doc) return;\n\n // Route animator lifecycle events to Vue component events.\n // `stop` fires alongside any event that halts playback.\n const callbacks = {\n onPlay: () => emit('play'),\n onPause: () => { emit('pause'); emit('stop'); },\n onCancel: () => { emit('cancel'); emit('stop'); },\n onFinish: () => { emit('finish'); emit('stop'); },\n onRemove: () => { emit('remove'); emit('stop'); },\n };\n\n apiRef.value = createAnimator({ data: doc, adapter: createVueAdapter(elementRefs), callbacks });\n\n // (Re)apply the declarative control state to the fresh animator โ\n // covers both the initial mount (e.g. `:play=\"true\"` from the\n // start) and doc swaps.\n syncPlayState();\n applySeek();\n }\n\n function destroyApi() {\n apiRef.value?.destroy();\n apiRef.value = null;\n }\n\n /** Declarative play/pause โ animator calls. */\n function syncPlayState() {\n if (compMode.value !== CompMode.play) return;\n if (props.play && !props.pause) {\n apiRef.value?.play();\n } else if (props.pause) {\n apiRef.value?.pause();\n } else if (props.play === false) {\n // explicit play=false โ jump to the end state\n apiRef.value?.finish();\n } else {\n // pause-only usage: pause switched off โ resume\n apiRef.value?.play();\n }\n }\n\n /** Controlled-time mode: seek through the animator API (no recreate). */\n function applySeek() {\n if (compMode.value !== CompMode.fixedTime) return;\n const doc = resolvedDoc.value;\n if (!doc) return;\n const seekMs = calcSeekMs(doc, props);\n if (seekMs !== undefined) {\n apiRef.value?.setCurrentTime(seekMs);\n apiRef.value?.pause();\n }\n }\n\n // Create the animator once DOM refs are available.\n onMounted(() => createApi());\n\n // Recreate the animator when the resolved doc changes.\n // `flush: 'post'` โ the animator must be created AFTER the DOM is\n // patched, otherwise the new root element isn't in the document yet\n // and trigger setup fails (autoplay would never resume after a doc swap).\n watch(resolvedDoc, () => createApi(), { flush: 'post' });\n\n // Sync declarative play/pause props with the animator.\n watch([compMode, () => props.play, () => props.pause], () => syncPlayState());\n\n // Scrubbing time/timeMs only seeks โ the animator is NOT recreated.\n watch([compMode, () => props.time, () => props.timeMs], () => applySeek());\n\n onUnmounted(() => {\n destroyApi();\n });\n\n // -- Expose imperative API ----------------------------------------------\n\n const publicApi: VueAnimatorApi = {\n isPlaying: () => apiRef.value?.isPlaying() || false,\n play: () => apiRef.value?.play(),\n pause: () => apiRef.value?.pause(),\n cancel: () => apiRef.value?.cancel(),\n finish: () => apiRef.value?.finish(),\n setPlaybackRate: (rate: number) => apiRef.value?.setPlaybackRate(rate),\n getCurrentTime: () => apiRef.value?.getCurrentTime() ?? null,\n setCurrentTime: (time: number) => apiRef.value?.setCurrentTime(time),\n };\n\n expose(publicApi);\n\n // -- Render -------------------------------------------------------------\n\n return () => {\n const doc = resolvedDoc.value;\n return doc ? renderNode(doc) : null;\n };\n },\n});\n\nexport default PixodeskSvgAnimator;\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { OutAction, StartOn } from \"@pixodesk/svg-animator-web\";\nimport { computed, defineComponent, h, onMounted, onUnmounted, ref, useAttrs, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n\n/**\n * Controls playback of a SVG+CSS animated file by toggling class names on a wrapper div.\n *\n * Intended for use with SVG files exported from the Pixodesk editor using the\n * **CSS Keyframes** flavor (no `<script>` tag). Import the SVG as a Vue component\n * via `vite-svg-loader` and pass it as the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg'; // vite-svg-loader\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator startOn=\"mouseOver\" outAction=\"pause\">\n * <AnimationSvg />\n * </PixodeskSvgCssAnimator>\n * </template>\n * ```\n *\n * The wrapper div carries one of three animation states via CSS class names:\n * - *(no class)* โ idle, animation not started\n * - `px-anim-enabled` โ started but paused\n * - `px-anim-enabled px-anim-playing` โ actively playing\n *\n * @prop startOn - What triggers the animation to start:\n * - `'load'` โ plays immediately on mount (default)\n * - `'mouseOver'` โ plays on hover\n * - `'click'` โ plays on click, toggles on second click\n * - `'scrollIntoView'` โ plays when the element enters the viewport\n * @prop outAction - What happens when the trigger ends (hover/scroll out, second click):\n * - `'continue'` โ keeps playing (default)\n * - `'pause'` โ pauses at the current frame\n * - `'reset'` โ resets to the beginning\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n\n inheritAttrs: false,\n\n props: {\n startOn: { type: String as PropType<StartOn>, default: 'load' },\n outAction: { type: String as PropType<OutAction>, default: 'continue' },\n },\n\n setup(props, { slots }) {\n const attrs = useAttrs();\n const state = ref<AnimState>(props.startOn === 'load' ? 'playing' : 'idle');\n const divRef = ref<HTMLDivElement | null>(null);\n\n const goOut = () => {\n state.value =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n };\n\n let observerCleanup: (() => void) | undefined;\n\n onMounted(() => {\n if (props.startOn !== 'scrollIntoView') return;\n const el = divRef.value;\n if (!el) return;\n const outState: AnimState =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n const observer = new IntersectionObserver(\n ([entry]) => { state.value = entry.isIntersecting ? 'playing' : outState; },\n { threshold: 0.1 }\n );\n observer.observe(el);\n observerCleanup = () => observer.disconnect();\n });\n\n onUnmounted(() => observerCleanup?.());\n\n const animClass = computed(() =>\n state.value === 'playing' ? 'px-anim-enabled px-anim-playing' :\n state.value === 'paused' ? 'px-anim-enabled' : ''\n );\n\n const handlers = computed(() =>\n props.startOn === 'mouseOver' ? {\n onMouseenter: () => { state.value = 'playing'; },\n onMouseleave: goOut,\n } :\n props.startOn === 'click' ? {\n onClick: () => state.value === 'playing' ? goOut() : (state.value = 'playing'),\n } : {}\n );\n\n return () => h('div', {\n ref: divRef,\n ...attrs,\n class: [attrs.class, animClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\n\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["computed","defineComponent","h","onMounted","onUnmounted","ref"]}
|
|
1
|
+
{"version":3,"sources":["../src/PixodeskSvgAnimator.ts","../src/PixodeskSvgCssAnimator.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxAnimatedSvgDocument, PxAnimatorAPI, PxNode, PxPlatformAdapter, PxTrigger } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, FillMode, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES } from '@pixodesk/svg-animator-web';\nimport {\n computed, defineComponent, h, onMounted, onUnmounted, ref, shallowRef, type PropType, type VNode,\n watch,\n} from 'vue';\n\n\n// -- Public types -----------------------------------------------------------\n\nexport interface VueAnimatorApi {\n /** Returns true if the animation is currently running. */\n isPlaying(): boolean;\n\n /** Starts or resumes the animation. */\n play(): void;\n\n /** Pauses the animation at its current state. */\n pause(): void;\n\n /** Stops the animation and resets it to its initial state. */\n cancel(): void;\n\n /** Jumps to the end of the animation and holds the final state. */\n finish(): void;\n\n /** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */\n setPlaybackRate(rate: number): void;\n\n /** Returns the current playback time in milliseconds. */\n getCurrentTime(): number | null;\n\n /** Jumps to a specific time (in milliseconds) in the animation. */\n setCurrentTime(time: number): void;\n}\n\n\n// -- Internal types ---------------------------------------------------------\n\nenum CompMode {\n static = 'static',\n autoplay = 'autoplay',\n play = 'play',\n fixedTime = 'fixedTime'\n}\n\n\n// -- Vue โ Animator bridge --------------------------------------------------\n\n/**\n * Creates a platform adapter that routes animator attribute updates\n * to the corresponding Vue-managed DOM element refs.\n */\nfunction createVueAdapter(elementRefs: Map<string, Element>) {\n const warnedSelectors = new Set<string>();\n\n const adapter: PxPlatformAdapter = {\n isConnected: () => true,\n setAttribute: (id, attrName, value) => {\n attrName = camelCaseToKebabWordIfNeeded(attrName);\n\n const element = elementRefs.get(id);\n\n if (!element && !warnedSelectors.has(id)) {\n warnedSelectors.add(id);\n console.warn('setAttribute: No elements found for id \"' + id + '\"');\n }\n\n if (element) {\n element.setAttribute(attrName, value);\n if (STYLE_ATTR_NAMES.has(attrName)) {\n (element as HTMLElement).style[attrName as any] = value;\n }\n }\n },\n };\n return adapter;\n}\n\n// FIXME: add model validation (e.g. isElementFileJson check)\n\n\n// -- Helper: apply doc overrides --------------------------------------------\n\ninterface DocOverrideProps {\n mode?: 'waapi' | 'frames' | 'auto';\n delay?: number;\n fill?: FillMode;\n iterations?: number | 'infinite';\n duration?: number;\n direction?: PlaybackDirection;\n frameRate?: number;\n startOn?: 'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic';\n outAction?: 'continue' | 'pause' | 'reset' | 'reverse';\n scrollIntoViewThreshold?: number;\n progress?: number;\n time?: number;\n}\n\nfunction applyDocOverrides(\n doc: PxAnimatedSvgDocument,\n props: DocOverrideProps,\n compMode: CompMode,\n): PxAnimatedSvgDocument {\n\n // In non-autoplay modes, override the document trigger to 'programmatic'\n // so the component can manage playback itself.\n if (compMode !== CompMode.autoplay) {\n const docStartOn = doc.animator?.trigger?.startOn;\n if (docStartOn && docStartOn !== 'programmatic') { // FIXME: use enum\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: { ...doc.animator?.trigger, startOn: 'programmatic' }\n }\n };\n }\n }\n\n // Apply timing overrides from props onto the document config.\n const { mode, duration, delay, iterations, fill, direction, frameRate } = props;\n if (\n mode !== undefined || duration !== undefined || delay !== undefined ||\n iterations !== undefined || fill !== undefined || direction !== undefined ||\n frameRate !== undefined\n ) {\n const animator = doc.animator || {};\n doc = {\n ...doc,\n animator: {\n ...animator,\n mode: mode !== undefined ? mode : animator.mode,\n duration: duration !== undefined ? duration : animator.duration,\n delay: delay !== undefined ? delay : animator.delay,\n iterations: iterations !== undefined ? iterations : animator.iterations,\n fill: fill !== undefined ? fill : animator.fill,\n direction: direction !== undefined ? direction : animator.direction,\n frameRate: frameRate !== undefined ? frameRate : animator.frameRate,\n }\n };\n }\n\n // Apply trigger overrides from props.\n const { startOn, outAction, scrollIntoViewThreshold } = props;\n if (startOn !== undefined || outAction !== undefined || scrollIntoViewThreshold !== undefined) {\n const trigger: PxTrigger = doc.animator?.trigger || {};\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...trigger,\n startOn: startOn !== undefined ? startOn : trigger.startOn,\n outAction: outAction !== undefined ? outAction : trigger.outAction,\n scrollIntoViewThreshold: scrollIntoViewThreshold !== undefined ? scrollIntoViewThreshold : trigger.scrollIntoViewThreshold,\n }\n }\n };\n }\n\n return doc;\n}\n\n/**\n * Controlled-time mode: absolute seek target in ms. `progress` is a fraction\n * (0โ1) of the WHOLE timeline (duration ร iterations); `time` is absolute.\n * Applied through the animator API (setCurrentTime) so scrubbing does NOT\n * recreate the animator.\n */\nfunction calcSeekMs(doc: PxAnimatedSvgDocument, props: DocOverrideProps): number | undefined {\n let seekMs: number | undefined;\n const animator = doc.animator || {};\n if (props.progress !== undefined) {\n const iterationsValue = props.iterations ?? animator.iterations;\n const iterationsCount = typeof iterationsValue === 'number' && iterationsValue >= 1 ? iterationsValue : 1;\n const singleDuration = props.duration ?? animator.duration ?? 1000; // engine default duration\n seekMs = props.progress * singleDuration * iterationsCount;\n }\n if (props.time !== undefined) seekMs = props.time;\n return seekMs;\n}\n\n\n// -- Main public component --------------------------------------------------\n\n/**\n * Vue component for rendering and controlling Pixodesk SVG animations.\n *\n * Supports four mutually-exclusive control modes:\n *\n * 1. **Autoplay** โ uses triggers from the animation document.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" autoplay />\n * ```\n *\n * 2. **Declarative play/pause** โ controlled via boolean props.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" play :pause=\"false\" />\n * ```\n *\n * 3. **Imperative** โ exposes a ref-based API for full programmatic control.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" ref=\"animator\" />\n * <button @click=\"$refs.animator.play()\">Play</button>\n * ```\n *\n * 4. **Controlled time** โ renders a single frame at a given time.\n * ```vue\n * <PixodeskSvgAnimator :doc=\"animation\" :progress=\"0.5\" />\n * <PixodeskSvgAnimator :doc=\"animation\" :time=\"500\" />\n * ```\n */\nconst PixodeskSvgAnimator = defineComponent({\n name: 'PixodeskSvgAnimator',\n\n props: {\n // -- Source\n doc: { type: Object as PropType<PxAnimatedSvgDocument>, required: true },\n\n // -- Rendering mode\n mode: { type: String as PropType<'waapi' | 'frames' | 'auto'> },\n\n // -- Timing overrides\n delay: { type: Number },\n fill: { type: String as PropType<FillMode> },\n iterations: { type: [Number, String] as PropType<number | 'infinite'> },\n duration: { type: Number },\n direction: { type: String as PropType<PlaybackDirection> },\n frameRate: { type: Number },\n\n // -- Trigger overrides\n startOn: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic'> },\n outAction: { type: String as PropType<'continue' | 'pause' | 'reset' | 'reverse'> },\n scrollIntoViewThreshold: { type: Number },\n\n // -- Declarative control\n autoplay: { type: Boolean, default: undefined },\n play: { type: Boolean, default: undefined },\n pause: { type: Boolean, default: undefined },\n\n // -- Controlled time\n progress: { type: Number },\n time: { type: Number },\n },\n\n emits: ['play', 'stop', 'pause', 'cancel', 'finish', 'remove'],\n\n setup(props, { expose, emit }) {\n const elementRefs = new Map<string, Element>();\n const apiRef = shallowRef<PxAnimatorAPI | null>(null);\n\n // -- Determine control mode ---------------------------------------------\n\n const compMode = computed<CompMode>(() => {\n if (props.autoplay) return CompMode.autoplay;\n if (props.progress !== undefined || props.time !== undefined) return CompMode.fixedTime;\n if (props.play !== undefined || props.pause !== undefined) return CompMode.play;\n return CompMode.static;\n });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n let doc = generateNewIds(props.doc);\n return applyDocOverrides(doc, props, compMode.value);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n function renderNode(node: PxNode | undefined): VNode | null {\n if (!node) return null;\n\n const { type, animate, meta, children, ...attrs } = node;\n const normProps = getNormalizedProps(attrs);\n\n // Capture a ref to each element with an id.\n if (node['id']) {\n const nodeId = node['id'];\n normProps['ref'] = (el: Element | null) => {\n if (el) {\n elementRefs.set(nodeId, el);\n } else {\n elementRefs.delete(nodeId);\n }\n };\n }\n\n const childVNodes = children?.map(child => renderNode(child)).filter(Boolean) as VNode[] | undefined;\n return h(type, normProps, childVNodes);\n }\n\n // -- Animator lifecycle -------------------------------------------------\n\n function createApi() {\n destroyApi();\n const doc = resolvedDoc.value;\n if (!doc) return;\n\n // Route animator lifecycle events to Vue component events.\n // `stop` fires alongside any event that halts playback.\n const callbacks = {\n onPlay: () => emit('play'),\n onPause: () => { emit('pause'); emit('stop'); },\n onCancel: () => { emit('cancel'); emit('stop'); },\n onFinish: () => { emit('finish'); emit('stop'); },\n onRemove: () => { emit('remove'); emit('stop'); },\n };\n\n apiRef.value = createAnimator({ data: doc, adapter: createVueAdapter(elementRefs), callbacks });\n\n // (Re)apply the declarative control state to the fresh animator โ\n // covers both the initial mount (e.g. `:play=\"true\"` from the\n // start) and doc swaps.\n syncPlayState();\n applySeek();\n }\n\n function destroyApi() {\n apiRef.value?.destroy();\n apiRef.value = null;\n }\n\n /** Declarative play/pause โ animator calls. */\n function syncPlayState() {\n if (compMode.value !== CompMode.play) return;\n if (props.play && !props.pause) {\n apiRef.value?.play();\n } else if (props.pause) {\n apiRef.value?.pause();\n } else if (props.play === false) {\n // explicit play=false โ jump to the end state\n apiRef.value?.finish();\n } else {\n // pause-only usage: pause switched off โ resume\n apiRef.value?.play();\n }\n }\n\n /** Controlled-time mode: seek through the animator API (no recreate). */\n function applySeek() {\n if (compMode.value !== CompMode.fixedTime) return;\n const doc = resolvedDoc.value;\n if (!doc) return;\n const seekMs = calcSeekMs(doc, props);\n if (seekMs !== undefined) {\n apiRef.value?.setCurrentTime(seekMs);\n apiRef.value?.pause();\n }\n }\n\n // Create the animator once DOM refs are available.\n onMounted(() => createApi());\n\n // Recreate the animator when the resolved doc changes.\n // `flush: 'post'` โ the animator must be created AFTER the DOM is\n // patched, otherwise the new root element isn't in the document yet\n // and trigger setup fails (autoplay would never resume after a doc swap).\n watch(resolvedDoc, () => createApi(), { flush: 'post' });\n\n // Sync declarative play/pause props with the animator.\n watch([compMode, () => props.play, () => props.pause], () => syncPlayState());\n\n // Scrubbing progress/time only seeks โ the animator is NOT recreated.\n watch([compMode, () => props.progress, () => props.time], () => applySeek());\n\n onUnmounted(() => {\n destroyApi();\n });\n\n // -- Expose imperative API ----------------------------------------------\n\n const publicApi: VueAnimatorApi = {\n isPlaying: () => apiRef.value?.isPlaying() || false,\n play: () => apiRef.value?.play(),\n pause: () => apiRef.value?.pause(),\n cancel: () => apiRef.value?.cancel(),\n finish: () => apiRef.value?.finish(),\n setPlaybackRate: (rate: number) => apiRef.value?.setPlaybackRate(rate),\n getCurrentTime: () => apiRef.value?.getCurrentTime() ?? null,\n setCurrentTime: (time: number) => apiRef.value?.setCurrentTime(time),\n };\n\n expose(publicApi);\n\n // -- Render -------------------------------------------------------------\n\n return () => {\n const doc = resolvedDoc.value;\n return doc ? renderNode(doc) : null;\n };\n },\n});\n\nexport default PixodeskSvgAnimator;\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { OutAction, StartOn } from \"@pixodesk/svg-animator-web\";\nimport { computed, defineComponent, h, onMounted, onUnmounted, ref, useAttrs, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n\n/**\n * Controls playback of a SVG+CSS animated file by toggling class names on a wrapper div.\n *\n * Intended for use with SVG files exported from the Pixodesk editor using the\n * **CSS Keyframes** flavor (no `<script>` tag). Import the SVG as a Vue component\n * via `vite-svg-loader` and pass it as the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg'; // vite-svg-loader\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator startOn=\"mouseOver\" outAction=\"pause\">\n * <AnimationSvg />\n * </PixodeskSvgCssAnimator>\n * </template>\n * ```\n *\n * The wrapper div carries one of three animation states via CSS class names:\n * - *(no class)* โ idle, animation not started\n * - `px-anim-enabled` โ started but paused\n * - `px-anim-enabled px-anim-playing` โ actively playing\n *\n * @prop startOn - What triggers the animation to start:\n * - `'load'` โ plays immediately on mount (default)\n * - `'mouseOver'` โ plays on hover\n * - `'click'` โ plays on click, toggles on second click\n * - `'scrollIntoView'` โ plays when the element enters the viewport\n * @prop outAction - What happens when the trigger ends (hover/scroll out, second click):\n * - `'continue'` โ keeps playing (default)\n * - `'pause'` โ pauses at the current frame\n * - `'reset'` โ resets to the beginning\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n\n inheritAttrs: false,\n\n props: {\n startOn: { type: String as PropType<StartOn>, default: 'load' },\n outAction: { type: String as PropType<OutAction>, default: 'continue' },\n },\n\n setup(props, { slots }) {\n const attrs = useAttrs();\n const state = ref<AnimState>(props.startOn === 'load' ? 'playing' : 'idle');\n const divRef = ref<HTMLDivElement | null>(null);\n\n const goOut = () => {\n state.value =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n };\n\n let observerCleanup: (() => void) | undefined;\n\n onMounted(() => {\n if (props.startOn !== 'scrollIntoView') return;\n const el = divRef.value;\n if (!el) return;\n const outState: AnimState =\n props.outAction === 'reset' ? 'idle' :\n props.outAction === 'pause' ? 'paused' : 'playing';\n const observer = new IntersectionObserver(\n ([entry]) => { state.value = entry.isIntersecting ? 'playing' : outState; },\n { threshold: 0.1 }\n );\n observer.observe(el);\n observerCleanup = () => observer.disconnect();\n });\n\n onUnmounted(() => observerCleanup?.());\n\n const animClass = computed(() =>\n state.value === 'playing' ? 'px-anim-enabled px-anim-playing' :\n state.value === 'paused' ? 'px-anim-enabled' : ''\n );\n\n const handlers = computed(() =>\n props.startOn === 'mouseOver' ? {\n onMouseenter: () => { state.value = 'playing'; },\n onMouseleave: goOut,\n } :\n props.startOn === 'click' ? {\n onClick: () => state.value === 'playing' ? goOut() : (state.value = 'playing'),\n } : {}\n );\n\n return () => h('div', {\n ref: divRef,\n ...attrs,\n class: [attrs.class, animClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\n\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["computed","defineComponent","h","onMounted","onUnmounted","ref"]}
|