@pixodesk/svg-animator-vue 1.0.35 → 1.0.40

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,7 +64,8 @@ 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
 
@@ -79,6 +80,7 @@ Render a single frame — by time in milliseconds, or by fraction of the whole t
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,12 +89,16 @@ Render a single frame — by time in milliseconds, or by fraction of the whole t
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
- | `config` | `object \| string` | Per-instance override of the document's `animator` block, deep-merged over it — same shape as the file (`{ timeline: { mode, frameRate, fillMode, direction, trigger: { outAction, … } } }`); `null` at a slot deletes that key. A JSON string is accepted too |
91
- | `resetDocDefaults` | `boolean` | Ignore the document's playback settings and start from the player's defaults, with `config` on top |
92
- | `duration` | `number` | Shortcut for `config.timeline.duration` (ms) |
93
- | `delay` | `number` | Shortcut for `config.timeline.delay` (ms) |
94
- | `iterations` | `number \| 'infinite'` | Shortcut for `config.timeline.iterations` |
95
- | `startOn` | `'load' \| 'mouseOver' \| 'click' \| 'scrollIntoView' \| 'programmatic'` | Shortcut for `config.timeline.trigger.startOn` |
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` | it plays, but something was ignored, degraded or misspelled; without it → `console.warn` (a prop, not an event — see below) |
99
+ | `onError` | `(diagnostic) => void` | this instance will not play — failed to load, parse or build, or the render threw; without it → `console.error` |
100
+ | `muteWarn` | `boolean` | switch the `console.warn` fallback off — for when you know the player has something to say about this document and are prepared to tolerate it. `onWarn`, if you gave it, still fires: mute is about the console, not about you |
101
+ | `muteError` | `boolean` | the same switch for `console.error` |
96
102
 
97
103
  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.
98
104
 
@@ -100,11 +106,12 @@ Note: passing a different `doc` (or unmounting) throws the old animator away and
100
106
 
101
107
  ## Events
102
108
 
109
+ <!-- px-check emits PixodeskSvgAnimator pkg=vue -->
103
110
  | Event | Description |
104
111
  |---|---|
105
112
  | `play` | Animation started or resumed |
106
113
  | `pause` | Animation paused |
107
- | `cancel` | Animation cancelled |
108
- | `finish` | Animation finished naturally |
114
+ | `cancel` | Animation canceled |
115
+ | `finish` | Animation reached its end — every iteration played, or `finish()` was called |
109
116
  | `remove` | Animation cleaned up (e.g. on unmount) |
110
117
  | `stop` | Fired alongside any event that halts playback (`pause` / `cancel` / `finish` / `remove`) |
package/dist/index.cjs CHANGED
@@ -28,22 +28,24 @@ module.exports = __toCommonJS(index_exports);
28
28
 
29
29
  // src/PixodeskSvgAnimator.ts
30
30
  var import_svg_animator_web = require("@pixodesk/svg-animator-web");
31
+ var import_svg_animator_core = require("@pixodesk/svg-animator-core");
32
+ var import_internal = require("@pixodesk/svg-animator-core/internal");
31
33
  var import_vue = require("vue");
32
34
  var VUE_PROP = { ref: "ref" };
33
- function createVueAdapter(elementRefs) {
35
+ function createVueAdapter(elementRefs, diag) {
34
36
  const warnedSelectors = /* @__PURE__ */ new Set();
35
37
  const adapter = {
36
38
  isConnected: () => true,
37
39
  setAttribute: (id, attrName, value) => {
38
- attrName = (0, import_svg_animator_web.camelCaseToKebabWordIfNeeded)(attrName);
40
+ attrName = (0, import_internal.camelCaseToKebabWordIfNeeded)(attrName);
39
41
  const element = elementRefs.get(id);
40
42
  if (!element && !warnedSelectors.has(id)) {
41
43
  warnedSelectors.add(id);
42
- console.warn('setAttribute: No elements found for id "' + id + '"');
44
+ diag.warn(import_svg_animator_web.PxDiagnosticKind.host, 'setAttribute: No elements found for id "' + id + '"');
43
45
  }
44
46
  if (element) {
45
47
  element.setAttribute(attrName, value);
46
- if (import_svg_animator_web.STYLE_ATTR_NAMES.has(attrName)) {
48
+ if (import_internal.STYLE_ATTR_NAMES.has(attrName)) {
47
49
  element.style[attrName] = value;
48
50
  }
49
51
  }
@@ -51,31 +53,31 @@ function createVueAdapter(elementRefs) {
51
53
  };
52
54
  return adapter;
53
55
  }
54
- function applyDocOverrides(doc, props, compMode) {
55
- const { config, resetDocDefaults, duration, delay, iterations, startOn } = props;
56
- const patch = (0, import_svg_animator_web.foldAnimatorConfigShortcuts)(config, { duration, delay, iterations, startOn });
57
- const fullPatch = compMode !== "autoplay" /* autoplay */ ? {
56
+ function applyDocOverrides(doc, props, compMode, diag) {
57
+ const { timeline, resetTimeline, duration, delay, iterations, startOn } = props;
58
+ const patch = (0, import_svg_animator_core.foldTimelineOverride)(timeline, { duration, delay, iterations, startOn });
59
+ const fullPatch = (0, import_svg_animator_core.controlModeTakesOverTrigger)(compMode) ? {
58
60
  ...patch ?? {},
59
61
  timeline: {
60
62
  ...patch?.timeline ?? {},
61
63
  trigger: { ...patch?.timeline?.trigger ?? {}, startOn: "programmatic" }
62
64
  }
63
65
  } : patch;
64
- if (fullPatch !== void 0 || resetDocDefaults) {
65
- const applied = (0, import_svg_animator_web.applyAnimatorConfig)(doc, fullPatch ?? {}, { resetDefaults: !!resetDocDefaults });
66
- for (const w of applied.warnings) console.warn("[PixodeskSvgAnimator] config override:", w);
66
+ if (fullPatch !== void 0 || resetTimeline) {
67
+ const applied = (0, import_svg_animator_core.applyAnimatorConfig)(doc, fullPatch ?? {}, { resetDefaults: !!resetTimeline });
68
+ for (const w of applied.warnings) diag.warn(import_svg_animator_web.PxDiagnosticKind.usage, "timeline override: " + w);
67
69
  doc = applied.doc;
68
70
  }
69
71
  return doc;
70
72
  }
71
73
  function calcSeekMs(doc, props) {
72
74
  let seekMs;
73
- const animator = (0, import_svg_animator_web.getAnimatorConfig)(doc) || {};
75
+ const animator = (0, import_svg_animator_core.getAnimatorConfig)(doc) || {};
74
76
  if (props.progress !== void 0) {
75
77
  const iterationsValue = props.iterations ?? animator.iterations;
76
- const iterationsCount = typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
77
- const singleDuration = props.duration ?? animator.duration ?? 1e3;
78
- seekMs = props.progress * singleDuration * iterationsCount;
78
+ const iterationsCount = iterationsValue === "infinite" ? Infinity : typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
79
+ const singleDuration = props.duration ?? animator.duration ?? import_internal.DEFAULT_DURATION_MS;
80
+ seekMs = (0, import_svg_animator_core.progressToTimeMs)(props.progress, singleDuration, iterationsCount);
79
81
  }
80
82
  if (props.time !== void 0) seekMs = props.time;
81
83
  return seekMs;
@@ -85,10 +87,10 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
85
87
  props: {
86
88
  // -- Source
87
89
  doc: { type: Object, required: true },
88
- // -- Playback override: one object spelled exactly like `animator` in the file,
89
- // plus the four shortcuts people reach for most.
90
- config: { type: [Object, String] },
91
- resetDocDefaults: { type: Boolean, default: void 0 },
90
+ // -- Playback override: the document's `timeline` block as a patch (or a JSON string),
91
+ // plus the four shortcuts people reach for most. The same names as React / RN.
92
+ timeline: { type: [Object, String] },
93
+ resetTimeline: { type: Boolean, default: void 0 },
92
94
  duration: { type: Number },
93
95
  delay: { type: Number },
94
96
  iterations: { type: [Number, String] },
@@ -99,21 +101,42 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
99
101
  pause: { type: Boolean, default: void 0 },
100
102
  // -- Controlled time
101
103
  progress: { type: Number },
102
- time: { type: Number }
104
+ time: { type: Number },
105
+ // -- Diagnostics (API review §5).
106
+ // Function PROPS, not emits, on purpose: an emit handler always exists, so wiring
107
+ // these to `emit` would permanently suppress the console fallback for anyone who
108
+ // never listens. As props, "not given" really is undefined and the console still
109
+ // speaks by default — the same contract as React and React Native.
110
+ onWarn: { type: Function },
111
+ onError: { type: Function },
112
+ // `muteWarn` / `muteError` switch the console fallback off — for a host that knows
113
+ // about the warnings and tolerates them; a handler you passed still fires.
114
+ muteWarn: { type: Boolean, default: void 0 },
115
+ muteError: { type: Boolean, default: void 0 }
103
116
  },
104
117
  emits: ["play", "stop", "pause", "cancel", "finish", "remove"],
105
118
  setup(props, { expose, emit }) {
106
119
  const elementRefs = /* @__PURE__ */ new Map();
107
120
  const apiRef = (0, import_vue.shallowRef)(null);
108
- const compMode = (0, import_vue.computed)(() => {
109
- if (props.autoplay) return "autoplay" /* autoplay */;
110
- if (props.progress !== void 0 || props.time !== void 0) return "fixedTime" /* fixedTime */;
111
- if (props.play !== void 0 || props.pause !== void 0) return "play" /* play */;
112
- return "static" /* static */;
113
- });
121
+ const makeDiag = () => (0, import_internal.createDiagnostics)(
122
+ { onWarn: props.onWarn, onError: props.onError, muteWarn: props.muteWarn, muteError: props.muteError },
123
+ "[PixodeskSvgAnimator]"
124
+ );
125
+ const resolvedMode = (0, import_vue.computed)(() => (0, import_svg_animator_core.resolveControlMode)({
126
+ progress: props.progress,
127
+ time: props.time,
128
+ play: props.play,
129
+ pause: props.pause,
130
+ autoplay: props.autoplay
131
+ }));
132
+ const compMode = (0, import_vue.computed)(() => resolvedMode.value.mode);
133
+ (0, import_vue.watch)(resolvedMode, (r) => {
134
+ const diag = makeDiag();
135
+ for (const w of r.warnings) diag.warn(import_svg_animator_web.PxDiagnosticKind.usage, w);
136
+ }, { immediate: true });
114
137
  const resolvedDoc = (0, import_vue.computed)(() => {
115
138
  let doc = (0, import_svg_animator_web.generateNewIds)(props.doc);
116
- return applyDocOverrides(doc, props, compMode.value);
139
+ return applyDocOverrides(doc, props, compMode.value, makeDiag());
117
140
  });
118
141
  function renderNode(node) {
119
142
  if (!node) return null;
@@ -130,32 +153,29 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
130
153
  };
131
154
  }
132
155
  const childVNodes = children?.map((child) => renderNode(child)).filter(Boolean);
133
- return (0, import_vue.h)(type, normProps, childVNodes);
156
+ const text = typeof node.textContent === "string" ? node.textContent : void 0;
157
+ return (0, import_vue.h)(type, normProps, childVNodes?.length ? childVNodes : text);
134
158
  }
135
159
  function createApi() {
136
160
  destroyApi();
137
161
  const doc = resolvedDoc.value;
138
162
  if (!doc) return;
139
- const callbacks = {
163
+ const options = {
164
+ doc,
165
+ adapter: createVueAdapter(elementRefs, makeDiag()),
140
166
  onPlay: () => emit("play"),
141
- onPause: () => {
142
- emit("pause");
143
- emit("stop");
144
- },
145
- onCancel: () => {
146
- emit("cancel");
147
- emit("stop");
148
- },
149
- onFinish: () => {
150
- emit("finish");
151
- emit("stop");
152
- },
153
- onRemove: () => {
154
- emit("remove");
155
- emit("stop");
156
- }
167
+ onPause: () => emit("pause"),
168
+ onCancel: () => emit("cancel"),
169
+ onFinish: () => emit("finish"),
170
+ onRemove: () => emit("remove"),
171
+ onStop: () => emit("stop"),
172
+ // The player's own diagnostics reach the same handlers as the component's.
173
+ onWarn: props.onWarn,
174
+ onError: props.onError,
175
+ muteWarn: props.muteWarn,
176
+ muteError: props.muteError
157
177
  };
158
- apiRef.value = (0, import_svg_animator_web.createAnimator)({ data: doc, adapter: createVueAdapter(elementRefs), callbacks });
178
+ apiRef.value = (0, import_svg_animator_web.createAnimator)(options);
159
179
  syncPlayState();
160
180
  applySeek();
161
181
  }
@@ -164,19 +184,19 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
164
184
  apiRef.value = null;
165
185
  }
166
186
  function syncPlayState() {
167
- if (compMode.value !== "play" /* play */) return;
187
+ if (compMode.value !== import_svg_animator_core.PxControlMode.play) return;
168
188
  if (props.play && !props.pause) {
169
189
  apiRef.value?.play();
170
190
  } else if (props.pause) {
171
191
  apiRef.value?.pause();
172
192
  } else if (props.play === false) {
173
- apiRef.value?.finish();
193
+ apiRef.value?.pause();
174
194
  } else {
175
195
  apiRef.value?.play();
176
196
  }
177
197
  }
178
198
  function applySeek() {
179
- if (compMode.value !== "fixedTime" /* fixedTime */) return;
199
+ if (compMode.value !== import_svg_animator_core.PxControlMode.fixedTime) return;
180
200
  const doc = resolvedDoc.value;
181
201
  if (!doc) return;
182
202
  const seekMs = calcSeekMs(doc, props);
@@ -200,7 +220,9 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
200
220
  finish: () => apiRef.value?.finish(),
201
221
  setPlaybackRate: (rate) => apiRef.value?.setPlaybackRate(rate),
202
222
  getCurrentTime: () => apiRef.value?.getCurrentTime() ?? null,
203
- setCurrentTime: (time) => apiRef.value?.setCurrentTime(time)
223
+ setCurrentTime: (time) => apiRef.value?.setCurrentTime(time),
224
+ getCurrentProgress: () => apiRef.value?.getCurrentProgress() ?? null,
225
+ setCurrentProgress: (progress) => apiRef.value?.setCurrentProgress(progress)
204
226
  };
205
227
  expose(publicApi);
206
228
  return () => {
@@ -212,13 +234,15 @@ var PixodeskSvgAnimator = (0, import_vue.defineComponent)({
212
234
  var PixodeskSvgAnimator_default = PixodeskSvgAnimator;
213
235
 
214
236
  // src/PixodeskSvgCssAnimator.ts
237
+ var import_svg_animator_core2 = require("@pixodesk/svg-animator-core");
215
238
  var import_vue2 = require("vue");
216
239
  var PixodeskSvgCssAnimator = (0, import_vue2.defineComponent)({
217
240
  name: "PixodeskSvgCssAnimator",
218
241
  inheritAttrs: false,
219
242
  props: {
220
243
  startOn: { type: String, default: "load" },
221
- outAction: { type: String, default: "continue" }
244
+ outAction: { type: String, default: "continue" },
245
+ scrollIntoViewThreshold: { type: Number, default: import_svg_animator_core2.PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold }
222
246
  },
223
247
  setup(props, { slots }) {
224
248
  const attrs = (0, import_vue2.useAttrs)();
@@ -233,11 +257,13 @@ var PixodeskSvgCssAnimator = (0, import_vue2.defineComponent)({
233
257
  const el = divRef.value;
234
258
  if (!el) return;
235
259
  const outState = props.outAction === "reset" ? "idle" : props.outAction === "pause" ? "paused" : "playing";
260
+ const threshold = props.scrollIntoViewThreshold;
261
+ const visible = (entry) => threshold > 0 ? entry.intersectionRatio >= threshold : entry.isIntersecting;
236
262
  const observer = new IntersectionObserver(
237
263
  ([entry]) => {
238
- state.value = entry.isIntersecting ? "playing" : outState;
264
+ state.value = visible(entry) ? "playing" : outState;
239
265
  },
240
- { threshold: 0.1 }
266
+ { threshold }
241
267
  );
242
268
  observer.observe(el);
243
269
  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, PxAnimatorConfigPatch, PxNode, PxPlatformAdapter, PxTimelineEngineExtra, PxTrigger } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, FillMode, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES, applyAnimatorConfig, foldAnimatorConfigShortcuts, getAnimatorConfig } 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\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 /** Per-instance override of the document's `animator` config — the same shape as\n * `animator` in SCHEMA.md, deep-merged; `null` at a slot deletes it. Also accepts a\n * JSON string. Replaces the former flat mode/fill/direction/frameRate/outAction props. */\n config?: PxAnimatorConfigPatch | string;\n /** Start from the player's defaults instead of the document's playback settings. */\n resetDocDefaults?: boolean;\n duration?: number;\n delay?: number;\n iterations?: number | 'infinite';\n startOn?: 'load' | 'mouseOver' | 'click' | 'scrollIntoView' | 'programmatic';\n progress?: number;\n time?: number;\n}\n\nfunction applyDocOverrides(\n doc: PxAnimatedSvgDocument,\n props: DocOverrideProps,\n compMode: CompMode,\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 { config, resetDocDefaults, duration, delay, iterations, startOn } = props;\n const patch = foldAnimatorConfigShortcuts(config, { duration, delay, iterations, startOn });\n const fullPatch: any = compMode !== CompMode.autoplay\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 || resetDocDefaults) {\n const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetDefaults: !!resetDocDefaults });\n for (const w of applied.warnings) console.warn('[PixodeskSvgAnimator] config 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); `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 // 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 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 // -- Playback override: one object spelled exactly like `animator` in the file,\n // plus the four shortcuts people reach for most.\n config: { type: [Object, String] as PropType<PxAnimatorConfigPatch | string> },\n resetDocDefaults: { 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\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[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 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 type { PxInternalAnimatorOptions } from '@pixodesk/svg-animator-web/internal';\nimport { createAnimator, generateNewIds, getNormalizedProps, PxDiagnosticKind, type PxPlaybackOverrideProps, type PxDiagnostic, type PxDiagnostics } from '@pixodesk/svg-animator-web';\nimport { applyAnimatorConfig, foldTimelineOverride, getAnimatorConfig, PxControlMode, resolveControlMode, controlModeTakesOverTrigger, progressToTimeMs, type PxAnimatorHandle, type PxControlProps } from '@pixodesk/svg-animator-core';\nimport { camelCaseToKebabWordIfNeeded, createDiagnostics, STYLE_ATTR_NAMES, DEFAULT_DURATION_MS } from '@pixodesk/svg-animator-core/internal';\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 * @public\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 * @public\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 // `muteWarn` / `muteError` switch the console fallback off — for a host that knows\n // about the warnings and tolerates them; a handler you passed still fires.\n muteWarn: { type: Boolean, default: undefined },\n muteError: { type: Boolean, 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, muteWarn: props.muteWarn, muteError: props.muteError },\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 // `adapter` is the components' extension of the public options (`PxInternalAnimatorOptions`,\n // review §25.14): the frame loop writes to the elements Vue rendered, not to a container.\n const options: PxInternalAnimatorOptions = {\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 muteWarn: props.muteWarn,\n muteError: props.muteError,\n };\n apiRef.value = createAnimator(options);\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-core';\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 * @public\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_core","import_vue"]}
package/dist/index.d.cts CHANGED
@@ -1,25 +1,14 @@
1
1
  import * as vue from 'vue';
2
2
  import { PropType, VNode } from 'vue';
3
- import { PxAnimatedSvgDocument, PxAnimatorConfigPatch, StartOn, OutAction } from '@pixodesk/svg-animator-web';
3
+ import { PxAnimatedSvgDocument, PxTimelinePatch, PxDiagnostic } from '@pixodesk/svg-animator-web';
4
+ import { PxAnimatorHandle, PxStartOn, PxOutAction } from '@pixodesk/svg-animator-core';
4
5
 
5
- interface VueAnimatorApi {
6
- /** Returns true if the animation is currently running. */
7
- isPlaying(): boolean;
8
- /** Starts or resumes the animation. */
9
- play(): void;
10
- /** Pauses the animation at its current state. */
11
- pause(): void;
12
- /** Stops the animation and resets it to its initial state. */
13
- cancel(): void;
14
- /** Jumps to the end of the animation and holds the final state. */
15
- finish(): void;
16
- /** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */
17
- setPlaybackRate(rate: number): void;
18
- /** Returns the current playback time in milliseconds. */
19
- getCurrentTime(): number | null;
20
- /** Jumps to a specific time (in milliseconds) in the animation. */
21
- setCurrentTime(time: number): void;
22
- }
6
+ /**
7
+ * The imperative handle the template ref exposes — core's `PxAnimatorHandle` under this
8
+ * package's name (review §9). One definition for React, Vue and React Native.
9
+ * @public
10
+ */
11
+ type VueAnimatorApi = PxAnimatorHandle;
23
12
  /**
24
13
  * Vue component for rendering and controlling Pixodesk SVG animations.
25
14
  *
@@ -46,16 +35,17 @@ interface VueAnimatorApi {
46
35
  * <PixodeskSvgAnimator :doc="animation" :progress="0.5" />
47
36
  * <PixodeskSvgAnimator :doc="animation" :time="500" />
48
37
  * ```
38
+ * @public
49
39
  */
50
40
  declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
51
41
  doc: {
52
42
  type: PropType<PxAnimatedSvgDocument>;
53
43
  required: true;
54
44
  };
55
- config: {
56
- type: PropType<PxAnimatorConfigPatch | string>;
45
+ timeline: {
46
+ type: PropType<PxTimelinePatch | string>;
57
47
  };
58
- resetDocDefaults: {
48
+ resetTimeline: {
59
49
  type: BooleanConstructor;
60
50
  default: undefined;
61
51
  };
@@ -89,17 +79,31 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
89
79
  time: {
90
80
  type: NumberConstructor;
91
81
  };
82
+ onWarn: {
83
+ type: PropType<(diagnostic: PxDiagnostic) => void>;
84
+ };
85
+ onError: {
86
+ type: PropType<(diagnostic: PxDiagnostic) => void>;
87
+ };
88
+ muteWarn: {
89
+ type: BooleanConstructor;
90
+ default: undefined;
91
+ };
92
+ muteError: {
93
+ type: BooleanConstructor;
94
+ default: undefined;
95
+ };
92
96
  }>, () => VNode<vue.RendererNode, vue.RendererElement, {
93
97
  [key: string]: any;
94
- }> | null, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("play" | "stop" | "pause" | "cancel" | "finish" | "remove")[], "play" | "stop" | "pause" | "cancel" | "finish" | "remove", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
98
+ }> | null, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("finish" | "play" | "pause" | "cancel" | "stop" | "remove")[], "finish" | "play" | "pause" | "cancel" | "stop" | "remove", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
95
99
  doc: {
96
100
  type: PropType<PxAnimatedSvgDocument>;
97
101
  required: true;
98
102
  };
99
- config: {
100
- type: PropType<PxAnimatorConfigPatch | string>;
103
+ timeline: {
104
+ type: PropType<PxTimelinePatch | string>;
101
105
  };
102
- resetDocDefaults: {
106
+ resetTimeline: {
103
107
  type: BooleanConstructor;
104
108
  default: undefined;
105
109
  };
@@ -133,18 +137,34 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
133
137
  time: {
134
138
  type: NumberConstructor;
135
139
  };
140
+ onWarn: {
141
+ type: PropType<(diagnostic: PxDiagnostic) => void>;
142
+ };
143
+ onError: {
144
+ type: PropType<(diagnostic: PxDiagnostic) => void>;
145
+ };
146
+ muteWarn: {
147
+ type: BooleanConstructor;
148
+ default: undefined;
149
+ };
150
+ muteError: {
151
+ type: BooleanConstructor;
152
+ default: undefined;
153
+ };
136
154
  }>> & Readonly<{
155
+ onFinish?: ((...args: any[]) => any) | undefined;
137
156
  onPlay?: ((...args: any[]) => any) | undefined;
138
- onStop?: ((...args: any[]) => any) | undefined;
139
157
  onPause?: ((...args: any[]) => any) | undefined;
140
158
  onCancel?: ((...args: any[]) => any) | undefined;
141
- onFinish?: ((...args: any[]) => any) | undefined;
159
+ onStop?: ((...args: any[]) => any) | undefined;
142
160
  onRemove?: ((...args: any[]) => any) | undefined;
143
161
  }>, {
144
- autoplay: boolean;
145
162
  play: boolean;
146
- resetDocDefaults: boolean;
147
163
  pause: boolean;
164
+ autoplay: boolean;
165
+ resetTimeline: boolean;
166
+ muteWarn: boolean;
167
+ muteError: boolean;
148
168
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
149
169
 
150
170
  /**
@@ -176,34 +196,54 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
176
196
  * - `'mouseOver'` — plays on hover
177
197
  * - `'click'` — plays on click, toggles on second click
178
198
  * - `'scrollIntoView'` — plays when the element enters the viewport
199
+ * - `'programmatic'` — **not supported here.** This wrapper exposes no `play()`, so there is
200
+ * nothing to wait for and the animation never starts. The prop keeps the
201
+ * shared `PxStartOn` type (one enum per wire key), so the value type-checks
202
+ * — it simply has no effect. Use `PixodeskSvgAnimator` (the JSON player)
203
+ * when you need to start an animation from code.
179
204
  * @prop outAction - What happens when the trigger ends (hover/scroll out, second click):
180
205
  * - `'continue'` — keeps playing (default)
181
206
  * - `'pause'` — pauses at the current frame
182
207
  * - `'reset'` — resets to the beginning
208
+ * - `'reverse'` — **acts as `'continue'` here.** A CSS class toggle cannot run keyframes
209
+ * backwards. Accepted so the prop keeps the shared `PxOutAction` type.
210
+ * @prop scrollIntoViewThreshold - For `'scrollIntoView'`: how much of the element must be
211
+ * visible (0–1) before it starts, and below which the out action applies. Defaults to the
212
+ * wire default (`0`, any pixel) — the same as the JSON player, not a private `0.1`.
213
+ * @public
183
214
  */
184
215
  declare const PixodeskSvgCssAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
185
216
  startOn: {
186
- type: PropType<StartOn>;
217
+ type: PropType<PxStartOn>;
187
218
  default: string;
188
219
  };
189
220
  outAction: {
190
- type: PropType<OutAction>;
221
+ type: PropType<PxOutAction>;
191
222
  default: string;
192
223
  };
224
+ scrollIntoViewThreshold: {
225
+ type: NumberConstructor;
226
+ default: 0;
227
+ };
193
228
  }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
194
229
  [key: string]: any;
195
230
  }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
196
231
  startOn: {
197
- type: PropType<StartOn>;
232
+ type: PropType<PxStartOn>;
198
233
  default: string;
199
234
  };
200
235
  outAction: {
201
- type: PropType<OutAction>;
236
+ type: PropType<PxOutAction>;
202
237
  default: string;
203
238
  };
239
+ scrollIntoViewThreshold: {
240
+ type: NumberConstructor;
241
+ default: 0;
242
+ };
204
243
  }>> & Readonly<{}>, {
205
- startOn: StartOn;
206
- outAction: OutAction;
244
+ startOn: PxStartOn;
245
+ outAction: PxOutAction;
246
+ scrollIntoViewThreshold: number;
207
247
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
208
248
 
209
249
  export { PixodeskSvgAnimator, PixodeskSvgCssAnimator, type VueAnimatorApi };