@pixodesk/svg-animator-vue 1.0.34 → 1.0.39

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 CHANGED
@@ -64,21 +64,23 @@ const animator = ref<VueAnimatorApi | null>(null);
64
64
  </template>
65
65
  ```
66
66
 
67
- `VueAnimatorApi` methods: `play()`, `pause()`, `cancel()`, `finish()`, `isPlaying()`, `setPlaybackRate(rate)`, `getCurrentTime()`, `setCurrentTime(ms)`.
67
+ <!-- px-check members VueAnimatorApi pkg=vue -->
68
+ `VueAnimatorApi` methods: `play()`, `pause()`, `cancel()`, `finish()`, `isPlaying()`, `setPlaybackRate(rate)`, `getCurrentTime()`, `setCurrentTime(ms)`, `getCurrentProgress()`, `setCurrentProgress(p)`.
68
69
 
69
70
  ### Controlled time
70
71
 
71
- Render a single frame at a specific point in time:
72
+ Render a single frame — by time in milliseconds, or by fraction of the whole timeline:
72
73
 
73
74
  ```vue
74
75
  <template>
75
- <PixodeskSvgAnimator :doc="animationDoc" :time="0.5" />
76
- <PixodeskSvgAnimator :doc="animationDoc" :time="500" />
76
+ <PixodeskSvgAnimator :doc="animationDoc" :time="500" /> <!-- 500 ms in -->
77
+ <PixodeskSvgAnimator :doc="animationDoc" :progress="0.5" /> <!-- halfway through -->
77
78
  </template>
78
79
  ```
79
80
 
80
81
  ## Props
81
82
 
83
+ <!-- px-check props PixodeskSvgAnimator pkg=vue -->
82
84
  | Prop | Type | Description |
83
85
  |---|---|---|
84
86
  | `doc` | `PxAnimatedSvgDocument` | The animation document to render (required) |
@@ -87,15 +89,15 @@ Render a single frame at a specific point in time:
87
89
  | `pause` | `boolean` | Pause current playback |
88
90
  | `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
91
  | `time` | `number` | show the frame at that time, in milliseconds from the start |
90
- | `mode` | `'auto' \| 'waapi' \| 'frames'` | Animation engine |
91
- | `duration` | `number` | Duration override (ms) |
92
- | `delay` | `number` | Delay before start (ms) |
93
- | `iterations` | `number \| 'infinite'` | Loop count |
94
- | `fill` | `FillMode` | Fill behaviour |
95
- | `direction` | `PlaybackDirection` | Playback direction |
96
- | `frameRate` | `number` | Target FPS |
97
- | `startOn` | `'load' \| 'mouseOver' \| 'click' \| 'scrollIntoView' \| 'programmatic'` | Trigger event override |
98
- | `outAction` | `'continue' \| 'pause' \| 'reset' \| 'reverse'` | Behaviour when trigger ends |
92
+ | `timeline` | `object \| string` | per-instance override of the document's `timeline` block, deep-merged over it — same shape as the file; `null` at any slot deletes that key. A JSON string is accepted too. See [Playback overrides](#playback-overrides) |
93
+ | `resetTimeline` | `boolean` | ignore the document's own timeline and start from the player's default timeline, with `timeline` on top |
94
+ | `duration` | `number` | Shortcut for `timeline.duration` (ms) |
95
+ | `delay` | `number` | Shortcut for `timeline.delay` (ms) |
96
+ | `iterations` | `number \| 'infinite'` | Shortcut for `timeline.iterations` |
97
+ | `startOn` | `'load' \| 'mouseOver' \| 'click' \| 'scrollIntoView' \| 'programmatic'` | Shortcut for `timeline.trigger.startOn` |
98
+ | `onWarn` | `(diagnostic) => void` | something is off but the animation still plays; without it → `console.warn` (a prop, not an event — see below) |
99
+ | `onError` | `(diagnostic) => void` | the animation could not be produced at all; without it → `console.error` |
100
+ | `silent` | `boolean \| PxDiagnosticKind[]` | silences the console fallback — everything, or just the kinds listed |
99
101
 
100
102
  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.
101
103
 
@@ -103,11 +105,12 @@ Note: passing a different `doc` (or unmounting) throws the old animator away and
103
105
 
104
106
  ## Events
105
107
 
108
+ <!-- px-check emits PixodeskSvgAnimator pkg=vue -->
106
109
  | Event | Description |
107
110
  |---|---|
108
111
  | `play` | Animation started or resumed |
109
112
  | `pause` | Animation paused |
110
- | `cancel` | Animation cancelled |
111
- | `finish` | Animation finished naturally |
113
+ | `cancel` | Animation canceled |
114
+ | `finish` | Animation reached its end — every iteration played, or `finish()` was called |
112
115
  | `remove` | Animation cleaned up (e.g. on unmount) |
113
116
  | `stop` | Fired alongside any event that halts playback (`pause` / `cancel` / `finish` / `remove`) |
package/dist/index.cjs CHANGED
@@ -29,7 +29,8 @@ module.exports = __toCommonJS(index_exports);
29
29
  // src/PixodeskSvgAnimator.ts
30
30
  var import_svg_animator_web = require("@pixodesk/svg-animator-web");
31
31
  var import_vue = require("vue");
32
- function createVueAdapter(elementRefs) {
32
+ var VUE_PROP = { ref: "ref" };
33
+ function createVueAdapter(elementRefs, diag) {
33
34
  const warnedSelectors = /* @__PURE__ */ new Set();
34
35
  const adapter = {
35
36
  isConnected: () => true,
@@ -38,7 +39,7 @@ function createVueAdapter(elementRefs) {
38
39
  const element = elementRefs.get(id);
39
40
  if (!element && !warnedSelectors.has(id)) {
40
41
  warnedSelectors.add(id);
41
- console.warn('setAttribute: No elements found for id "' + id + '"');
42
+ diag.warn(import_svg_animator_web.PxDiagnosticKind.host, 'setAttribute: No elements found for id "' + id + '"');
42
43
  }
43
44
  if (element) {
44
45
  element.setAttribute(attrName, value);
@@ -50,62 +51,31 @@ function createVueAdapter(elementRefs) {
50
51
  };
51
52
  return adapter;
52
53
  }
53
- function applyDocOverrides(doc, props, compMode) {
54
- if (compMode !== "autoplay" /* autoplay */) {
55
- const docStartOn = doc.animator?.trigger?.startOn;
56
- if (docStartOn && docStartOn !== "programmatic") {
57
- doc = {
58
- ...doc,
59
- animator: {
60
- ...doc.animator,
61
- trigger: { ...doc.animator?.trigger, startOn: "programmatic" }
62
- }
63
- };
54
+ function applyDocOverrides(doc, props, compMode, diag) {
55
+ const { timeline, resetTimeline, duration, delay, iterations, startOn } = props;
56
+ const patch = (0, import_svg_animator_web.foldTimelineOverride)(timeline, { duration, delay, iterations, startOn });
57
+ const fullPatch = (0, import_svg_animator_web.controlModeTakesOverTrigger)(compMode) ? {
58
+ ...patch ?? {},
59
+ timeline: {
60
+ ...patch?.timeline ?? {},
61
+ trigger: { ...patch?.timeline?.trigger ?? {}, startOn: "programmatic" }
64
62
  }
65
- }
66
- const { mode, duration, delay, iterations, fill, direction, frameRate } = props;
67
- if (mode !== void 0 || duration !== void 0 || delay !== void 0 || iterations !== void 0 || fill !== void 0 || direction !== void 0 || frameRate !== void 0) {
68
- const animator = doc.animator || {};
69
- doc = {
70
- ...doc,
71
- animator: {
72
- ...animator,
73
- mode: mode !== void 0 ? mode : animator.mode,
74
- duration: duration !== void 0 ? duration : animator.duration,
75
- delay: delay !== void 0 ? delay : animator.delay,
76
- iterations: iterations !== void 0 ? iterations : animator.iterations,
77
- fill: fill !== void 0 ? fill : animator.fill,
78
- direction: direction !== void 0 ? direction : animator.direction,
79
- frameRate: frameRate !== void 0 ? frameRate : animator.frameRate
80
- }
81
- };
82
- }
83
- const { startOn, outAction, scrollIntoViewThreshold } = props;
84
- if (startOn !== void 0 || outAction !== void 0 || scrollIntoViewThreshold !== void 0) {
85
- const trigger = doc.animator?.trigger || {};
86
- doc = {
87
- ...doc,
88
- animator: {
89
- ...doc.animator,
90
- trigger: {
91
- ...trigger,
92
- startOn: startOn !== void 0 ? startOn : trigger.startOn,
93
- outAction: outAction !== void 0 ? outAction : trigger.outAction,
94
- scrollIntoViewThreshold: scrollIntoViewThreshold !== void 0 ? scrollIntoViewThreshold : trigger.scrollIntoViewThreshold
95
- }
96
- }
97
- };
63
+ } : patch;
64
+ if (fullPatch !== void 0 || resetTimeline) {
65
+ const applied = (0, import_svg_animator_web.applyAnimatorConfig)(doc, fullPatch ?? {}, { resetDefaults: !!resetTimeline });
66
+ for (const w of applied.warnings) diag.warn(import_svg_animator_web.PxDiagnosticKind.usage, "timeline override: " + w);
67
+ doc = applied.doc;
98
68
  }
99
69
  return doc;
100
70
  }
101
71
  function calcSeekMs(doc, props) {
102
72
  let seekMs;
103
- const animator = doc.animator || {};
73
+ const animator = (0, import_svg_animator_web.getAnimatorConfig)(doc) || {};
104
74
  if (props.progress !== void 0) {
105
75
  const iterationsValue = props.iterations ?? animator.iterations;
106
- const iterationsCount = typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
107
- const singleDuration = props.duration ?? animator.duration ?? 1e3;
108
- seekMs = props.progress * singleDuration * iterationsCount;
76
+ const iterationsCount = iterationsValue === "infinite" ? Infinity : typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
77
+ const singleDuration = props.duration ?? animator.duration ?? import_svg_animator_web.DEFAULT_DURATION_MS;
78
+ seekMs = (0, import_svg_animator_web.progressToTimeMs)(props.progress, singleDuration, iterationsCount);
109
79
  }
110
80
  if (props.time !== void 0) seekMs = props.time;
111
81
  return seekMs;
@@ -115,48 +85,63 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
115
85
  props: {
116
86
  // -- Source
117
87
  doc: { type: Object, required: true },
118
- // -- Rendering mode
119
- mode: { type: String },
120
- // -- Timing overrides
88
+ // -- Playback override: the document's `timeline` block as a patch (or a JSON string),
89
+ // plus the four shortcuts people reach for most. The same names as React / RN.
90
+ timeline: { type: [Object, String] },
91
+ resetTimeline: { type: Boolean, default: void 0 },
92
+ duration: { type: Number },
121
93
  delay: { type: Number },
122
- fill: { type: String },
123
94
  iterations: { type: [Number, String] },
124
- duration: { type: Number },
125
- direction: { type: String },
126
- frameRate: { type: Number },
127
- // -- Trigger overrides
128
95
  startOn: { type: String },
129
- outAction: { type: String },
130
- scrollIntoViewThreshold: { type: Number },
131
96
  // -- Declarative control
132
97
  autoplay: { type: Boolean, default: void 0 },
133
98
  play: { type: Boolean, default: void 0 },
134
99
  pause: { type: Boolean, default: void 0 },
135
100
  // -- Controlled time
136
101
  progress: { type: Number },
137
- time: { type: Number }
102
+ time: { type: Number },
103
+ // -- Diagnostics (API review §5).
104
+ // Function PROPS, not emits, on purpose: an emit handler always exists, so wiring
105
+ // these to `emit` would permanently suppress the console fallback for anyone who
106
+ // never listens. As props, "not given" really is undefined and the console still
107
+ // speaks by default — the same contract as React and React Native.
108
+ onWarn: { type: Function },
109
+ onError: { type: Function },
110
+ // `silent` takes `true` or just the kinds to quiet, so `platform` chatter can be
111
+ // silenced while `document` problems still speak.
112
+ silent: { type: [Boolean, Array], default: void 0 }
138
113
  },
139
114
  emits: ["play", "stop", "pause", "cancel", "finish", "remove"],
140
115
  setup(props, { expose, emit }) {
141
116
  const elementRefs = /* @__PURE__ */ new Map();
142
117
  const apiRef = (0, import_vue.shallowRef)(null);
143
- const compMode = (0, import_vue.computed)(() => {
144
- if (props.autoplay) return "autoplay" /* autoplay */;
145
- if (props.progress !== void 0 || props.time !== void 0) return "fixedTime" /* fixedTime */;
146
- if (props.play !== void 0 || props.pause !== void 0) return "play" /* play */;
147
- return "static" /* static */;
148
- });
118
+ const makeDiag = () => (0, import_svg_animator_web.createDiagnostics)(
119
+ { onWarn: props.onWarn, onError: props.onError, silent: props.silent },
120
+ "[PixodeskSvgAnimator]"
121
+ );
122
+ const resolvedMode = (0, import_vue.computed)(() => (0, import_svg_animator_web.resolveControlMode)({
123
+ progress: props.progress,
124
+ time: props.time,
125
+ play: props.play,
126
+ pause: props.pause,
127
+ autoplay: props.autoplay
128
+ }));
129
+ const compMode = (0, import_vue.computed)(() => resolvedMode.value.mode);
130
+ (0, import_vue.watch)(resolvedMode, (r) => {
131
+ const diag = makeDiag();
132
+ for (const w of r.warnings) diag.warn(import_svg_animator_web.PxDiagnosticKind.usage, w);
133
+ }, { immediate: true });
149
134
  const resolvedDoc = (0, import_vue.computed)(() => {
150
135
  let doc = (0, import_svg_animator_web.generateNewIds)(props.doc);
151
- return applyDocOverrides(doc, props, compMode.value);
136
+ return applyDocOverrides(doc, props, compMode.value, makeDiag());
152
137
  });
153
138
  function renderNode(node) {
154
139
  if (!node) return null;
155
140
  const { type, animate, meta, children, ...attrs } = node;
156
141
  const normProps = (0, import_svg_animator_web.getNormalizedProps)(attrs);
157
- if (node["id"]) {
158
- const nodeId = node["id"];
159
- normProps["ref"] = (el) => {
142
+ if (node.id) {
143
+ const nodeId = node.id;
144
+ normProps[VUE_PROP.ref] = (el) => {
160
145
  if (el) {
161
146
  elementRefs.set(nodeId, el);
162
147
  } else {
@@ -165,32 +150,27 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
165
150
  };
166
151
  }
167
152
  const childVNodes = children?.map((child) => renderNode(child)).filter(Boolean);
168
- return (0, import_vue.h)(type, normProps, childVNodes);
153
+ const text = typeof node.textContent === "string" ? node.textContent : void 0;
154
+ return (0, import_vue.h)(type, normProps, childVNodes?.length ? childVNodes : text);
169
155
  }
170
156
  function createApi() {
171
157
  destroyApi();
172
158
  const doc = resolvedDoc.value;
173
159
  if (!doc) return;
174
- const callbacks = {
160
+ apiRef.value = (0, import_svg_animator_web.createAnimator)({
161
+ doc,
162
+ adapter: createVueAdapter(elementRefs, makeDiag()),
175
163
  onPlay: () => emit("play"),
176
- onPause: () => {
177
- emit("pause");
178
- emit("stop");
179
- },
180
- onCancel: () => {
181
- emit("cancel");
182
- emit("stop");
183
- },
184
- onFinish: () => {
185
- emit("finish");
186
- emit("stop");
187
- },
188
- onRemove: () => {
189
- emit("remove");
190
- emit("stop");
191
- }
192
- };
193
- apiRef.value = (0, import_svg_animator_web.createAnimator)({ data: doc, adapter: createVueAdapter(elementRefs), callbacks });
164
+ onPause: () => emit("pause"),
165
+ onCancel: () => emit("cancel"),
166
+ onFinish: () => emit("finish"),
167
+ onRemove: () => emit("remove"),
168
+ onStop: () => emit("stop"),
169
+ // The player's own diagnostics reach the same handlers as the component's.
170
+ onWarn: props.onWarn,
171
+ onError: props.onError,
172
+ silent: props.silent
173
+ });
194
174
  syncPlayState();
195
175
  applySeek();
196
176
  }
@@ -199,19 +179,19 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
199
179
  apiRef.value = null;
200
180
  }
201
181
  function syncPlayState() {
202
- if (compMode.value !== "play" /* play */) return;
182
+ if (compMode.value !== import_svg_animator_web.PxControlMode.play) return;
203
183
  if (props.play && !props.pause) {
204
184
  apiRef.value?.play();
205
185
  } else if (props.pause) {
206
186
  apiRef.value?.pause();
207
187
  } else if (props.play === false) {
208
- apiRef.value?.finish();
188
+ apiRef.value?.pause();
209
189
  } else {
210
190
  apiRef.value?.play();
211
191
  }
212
192
  }
213
193
  function applySeek() {
214
- if (compMode.value !== "fixedTime" /* fixedTime */) return;
194
+ if (compMode.value !== import_svg_animator_web.PxControlMode.fixedTime) return;
215
195
  const doc = resolvedDoc.value;
216
196
  if (!doc) return;
217
197
  const seekMs = calcSeekMs(doc, props);
@@ -235,7 +215,9 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
235
215
  finish: () => apiRef.value?.finish(),
236
216
  setPlaybackRate: (rate) => apiRef.value?.setPlaybackRate(rate),
237
217
  getCurrentTime: () => apiRef.value?.getCurrentTime() ?? null,
238
- setCurrentTime: (time) => apiRef.value?.setCurrentTime(time)
218
+ setCurrentTime: (time) => apiRef.value?.setCurrentTime(time),
219
+ getCurrentProgress: () => apiRef.value?.getCurrentProgress() ?? null,
220
+ setCurrentProgress: (progress) => apiRef.value?.setCurrentProgress(progress)
239
221
  };
240
222
  expose(publicApi);
241
223
  return () => {
@@ -247,13 +229,15 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
247
229
  var PixodeskSvgAnimator_default = PixodeskSvgAnimator;
248
230
 
249
231
  // src/PixodeskSvgCssAnimator.ts
232
+ var import_svg_animator_web2 = require("@pixodesk/svg-animator-web");
250
233
  var import_vue2 = require("vue");
251
234
  var PixodeskSvgCssAnimator = (0, import_vue2.defineComponent)({
252
235
  name: "PixodeskSvgCssAnimator",
253
236
  inheritAttrs: false,
254
237
  props: {
255
238
  startOn: { type: String, default: "load" },
256
- outAction: { type: String, default: "continue" }
239
+ outAction: { type: String, default: "continue" },
240
+ scrollIntoViewThreshold: { type: Number, default: import_svg_animator_web2.PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold }
257
241
  },
258
242
  setup(props, { slots }) {
259
243
  const attrs = (0, import_vue2.useAttrs)();
@@ -268,11 +252,13 @@ var PixodeskSvgCssAnimator = (0, import_vue2.defineComponent)({
268
252
  const el = divRef.value;
269
253
  if (!el) return;
270
254
  const outState = props.outAction === "reset" ? "idle" : props.outAction === "pause" ? "paused" : "playing";
255
+ const threshold = props.scrollIntoViewThreshold;
256
+ const visible = (entry) => threshold > 0 ? entry.intersectionRatio >= threshold : entry.isIntersecting;
271
257
  const observer = new IntersectionObserver(
272
258
  ([entry]) => {
273
- state.value = entry.isIntersecting ? "playing" : outState;
259
+ state.value = visible(entry) ? "playing" : outState;
274
260
  },
275
- { threshold: 0.1 }
261
+ { threshold }
276
262
  );
277
263
  observer.observe(el);
278
264
  observerCleanup = () => observer.disconnect();
@@ -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 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"]}
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, PxTimelineEngineExtra, PxTimelinePatch, PxTrigger } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, createDiagnostics, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES, applyAnimatorConfig, foldTimelineOverride, getAnimatorConfig, PxControlMode, resolveControlMode, controlModeTakesOverTrigger, PxDiagnosticKind, progressToTimeMs, DEFAULT_DURATION_MS, type PxAnimatorHandle, type PxControlProps, type PxPlaybackOverrideProps, type PxDiagnostic, type PxDiagnostics } 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\n/** Vue's own prop names on the vnode — not wire keys. See the React twin. */\nconst VUE_PROP = { ref: 'ref' } as const;\n\n/**\n * The imperative handle the template ref exposes — core's `PxAnimatorHandle` under this\n * package's name (review §9). One definition for React, Vue and React Native.\n */\nexport type VueAnimatorApi = PxAnimatorHandle;\n\n\n// -- Internal types ---------------------------------------------------------\n\n// The control mode is core's `PxControlMode`, shared with React and React Native\n// (API review §1/§7) — one precedence rule, one set of conflict warnings.\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>, diag: PxDiagnostics) {\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 diag.warn(PxDiagnosticKind.host, '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\n/**\n * What `applyDocOverrides` / `calcSeekMs` read off the props — core's shared shapes, not a local\n * copy (review §9). The runtime `props: {…}` block below stays Vue's own, because Vue needs\n * runtime prop declarations; this is only the TypeScript view of the same members.\n */\ntype DocOverrideProps = PxPlaybackOverrideProps & Pick<PxControlProps, 'progress' | 'time'>;\n\nfunction applyDocOverrides(\n doc: PxAnimatedSvgDocument,\n props: DocOverrideProps,\n compMode: PxControlMode,\n diag: PxDiagnostics,\n): PxAnimatedSvgDocument {\n\n // ONE patch, applied ONCE: the props, plus the component's own need to take the trigger\n // over in the non-autoplay control modes.\n //\n // This replaces three hand-rolled spread blocks that wrote the FLAT runtime keys. On a\n // wire-format document — which is what every writer emits — `flattenAnimatorTimeline`\n // overwrote them from `timeline` immediately afterwards, so the overrides were silently\n // discarded. See PLAYBACK-OVERRIDE-PLAN.md §1.1.\n const { timeline, resetTimeline, duration, delay, iterations, startOn } = props;\n const patch = foldTimelineOverride(timeline, { duration, delay, iterations, startOn });\n const fullPatch: any = controlModeTakesOverTrigger(compMode)\n ? {\n ...(patch ?? {}),\n timeline: {\n ...((patch as any)?.timeline ?? {}),\n trigger: { ...((patch as any)?.timeline?.trigger ?? {}), startOn: 'programmatic' },\n },\n }\n : patch;\n\n if (fullPatch !== undefined || resetTimeline) {\n const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetDefaults: !!resetTimeline });\n for (const w of applied.warnings) diag.warn(PxDiagnosticKind.usage, 'timeline override: ' + w);\n doc = applied.doc;\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 — ONE iteration when\n * endless); `time` is absolute. Applied through the animator API\n * (setCurrentTime) so scrubbing does NOT recreate the animator.\n */\nfunction calcSeekMs(doc: PxAnimatedSvgDocument, props: DocOverrideProps): number | undefined {\n let seekMs: number | undefined;\n // The FLAT runtime view, so this works on a wire-format document too — reading\n // `doc.animator.duration` directly finds nothing there.\n const animator = getAnimatorConfig(doc) || {};\n if (props.progress !== undefined) {\n // ONE rule for progress → time (core's `progressToTimeMs`): the same mapping\n // `getCurrentProgress` reads back, so a prop of 0.5 and a read of 0.5 agree.\n const iterationsValue = props.iterations ?? animator.iterations;\n const iterationsCount = iterationsValue === 'infinite' ? Infinity\n : (typeof iterationsValue === 'number' && iterationsValue >= 1 ? iterationsValue : 1);\n const singleDuration = props.duration ?? animator.duration ?? DEFAULT_DURATION_MS;\n seekMs = progressToTimeMs(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 // -- Playback override: the document's `timeline` block as a patch (or a JSON string),\n // plus the four shortcuts people reach for most. The same names as React / RN.\n timeline: { type: [Object, String] as PropType<PxTimelinePatch | string> },\n resetTimeline: { type: Boolean, default: undefined },\n duration: { type: Number },\n delay: { type: Number },\n iterations: { type: [Number, String] as PropType<number | 'infinite'> },\n startOn: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic'> },\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 // -- Diagnostics (API review §5).\n // Function PROPS, not emits, on purpose: an emit handler always exists, so wiring\n // these to `emit` would permanently suppress the console fallback for anyone who\n // never listens. As props, \"not given\" really is undefined and the console still\n // speaks by default — the same contract as React and React Native.\n onWarn: { type: Function as PropType<(diagnostic: PxDiagnostic) => void> },\n onError: { type: Function as PropType<(diagnostic: PxDiagnostic) => void> },\n // `silent` takes `true` or just the kinds to quiet, so `platform` chatter can be\n // silenced while `document` problems still speak.\n silent: { type: [Boolean, Array] as PropType<boolean | ReadonlyArray<PxDiagnosticKind>>, default: undefined },\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 /**\n * The diagnostics channel, built from the CURRENT props each time (API review §5).\n * Not hoisted into a constant wrapper: `(m, d) => props.onWarn?.(m, d)` would always be\n * a function, so the channel would think a handler exists and the console fallback\n * would never fire for anyone who passed nothing.\n */\n const makeDiag = (): PxDiagnostics => createDiagnostics(\n { onWarn: props.onWarn, onError: props.onError, silent: props.silent },\n '[PixodeskSvgAnimator]',\n );\n\n // -- Determine control mode ---------------------------------------------\n\n // ONE control-mode rule, decided in core (API review §1/§7). The template ref is not an\n // input: it is exposed in every mode and never changes which one is chosen.\n const resolvedMode = computed(() => resolveControlMode({\n progress: props.progress, time: props.time,\n play: props.play, pause: props.pause, autoplay: props.autoplay,\n }));\n const compMode = computed<PxControlMode>(() => resolvedMode.value.mode);\n\n // Warn where the mode is COMPUTED, not inside `applyDocOverrides` — that runs again on\n // every doc recompute and would repeat the same sentence.\n watch(resolvedMode, r => {\n const diag = makeDiag();\n for (const w of r.warnings) diag.warn(PxDiagnosticKind.usage, w);\n }, { immediate: true });\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, makeDiag());\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[VUE_PROP.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 // Text content: a node's own `textContent` renders only when it has no child nodes — a\n // line <tspan> can carry both, and then its children are the styled spans (the React\n // Native renderer's rule). `getNormalizedProps` strips `textContent` from the attributes.\n const text = typeof node.textContent === 'string' ? node.textContent : undefined;\n return h(type, normProps, childVNodes?.length ? childVNodes : text);\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, INLINE under the same\n // names every surface uses (review §9). `stop` fires alongside any event that halts\n // playback — that is the PLAYER's rule, so `onStop` is passed through, not re-derived.\n apiRef.value = createAnimator({\n doc,\n adapter: createVueAdapter(elementRefs, makeDiag()),\n onPlay: () => emit('play'),\n onPause: () => emit('pause'),\n onCancel: () => emit('cancel'),\n onFinish: () => emit('finish'),\n onRemove: () => emit('remove'),\n onStop: () => emit('stop'),\n // The player's own diagnostics reach the same handlers as the component's.\n onWarn: props.onWarn,\n onError: props.onError,\n silent: props.silent,\n });\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 !== PxControlMode.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 → hold where it is (review §8). This used to `finish()`;\n // a boolean whose `false` means \"jump to the end\" is not what anyone guesses.\n apiRef.value?.pause();\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 !== PxControlMode.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 getCurrentProgress: () => apiRef.value?.getCurrentProgress() ?? null,\n setCurrentProgress: (progress: number) => apiRef.value?.setCurrentProgress(progress),\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 { PX_TRIGGER_DEFAULTS, PxOutAction, PxStartOn } 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 * - `'programmatic'` — **not supported here.** This wrapper exposes no `play()`, so there is\n * nothing to wait for and the animation never starts. The prop keeps the\n * shared `PxStartOn` type (one enum per wire key), so the value type-checks\n * — it simply has no effect. Use `PixodeskSvgAnimator` (the JSON player)\n * when you need to start an animation from code.\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 * - `'reverse'` — **acts as `'continue'` here.** A CSS class toggle cannot run keyframes\n * backwards. Accepted so the prop keeps the shared `PxOutAction` type.\n * @prop scrollIntoViewThreshold - For `'scrollIntoView'`: how much of the element must be\n * visible (0–1) before it starts, and below which the out action applies. Defaults to the\n * wire default (`0`, any pixel) — the same as the JSON player, not a private `0.1`.\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n\n inheritAttrs: false,\n\n props: {\n startOn: { type: String as PropType<PxStartOn>, default: 'load' },\n outAction: { type: String as PropType<PxOutAction>, default: 'continue' },\n scrollIntoViewThreshold: { type: Number, default: PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold },\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 // `isIntersecting` is true at ONE visible pixel, so with a threshold above 0 it could\n // never report \"out\" — read the ratio against the threshold instead (review §13).\n const threshold = props.scrollIntoViewThreshold;\n const visible = (entry: IntersectionObserverEntry): boolean =>\n threshold > 0 ? entry.intersectionRatio >= threshold : entry.isIntersecting;\n const observer = new IntersectionObserver(\n ([entry]) => { state.value = visible(entry) ? 'playing' : outState; },\n { threshold }\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_svg_animator_web","import_vue"]}