@pixodesk/svg-animator-vue 1.0.46 → 1.0.48

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.
@@ -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, PxTimelineEngineSetting, PxTimelinePatch, PxTrigger } from '@pixodesk/svg-animator-web';\nimport type { PxInternalAnimatorOptions } from '@pixodesk/svg-animator-web/internal';\nimport { createAnimator, PxDiagnosticKind, type PxPlaybackOverride, type PxDiagnostic, type PxDiagnostics } from '@pixodesk/svg-animator-web';\nimport { applyAnimatorConfig, foldTimelineOverride, getAnimatorConfig, PxDiagnosticCode, PxControlMode, resolveControlMode, controlModeTakesOverTrigger, progressToTimeMs, type PxAnimatorHandle, type PxControlProps } from '@pixodesk/svg-animator-core';\nimport { createDiagnostics, PX_DEFAULT_DURATION_MS, prepareDocumentForRender, renderPxTree, type PxElementFactory } 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', style: 'style' } 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// 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 = PxPlaybackOverride & 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 dev-docs/plans/playback-override.md §1.1.\n const { timeline, resetTimeline, duration, delay, iterations, start } = props;\n const patch = foldTimelineOverride(timeline, { duration, delay, iterations, start });\n const fullPatch: any = controlModeTakesOverTrigger(compMode)\n ? {\n ...(patch ?? {}),\n timeline: {\n ...((patch as any)?.timeline ?? {}),\n trigger: { ...((patch as any)?.timeline?.trigger ?? {}), start: 'none' },\n },\n }\n : patch;\n\n if (fullPatch !== undefined || resetTimeline) {\n const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetTimeline: !!resetTimeline });\n for (const w of applied.warnings) diag.warn(PxDiagnosticKind.usage, PxDiagnosticCode.timelineOverrideIgnored, 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 ?? PX_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 start: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'none'> },\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 // The `<svg>` this component rendered — handed to the player, which attaches its\n // triggers to it and writes animated values to the elements under it.\n let rootElement: Element | null = null;\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, PxDiagnosticCode.controlPropsConflict, w);\n }, { immediate: true });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n // Overrides FIRST: they can change `timeline.engine` and `duration`, and\n // materialization reads both (the engine picks the stages, the duration sizes loop\n // expansion). Then render what the web player renders — materialized, fresh ids.\n // Rendering the raw document dropped every `effects` bucket, so a document painted\n // by `effects` alone came out as an empty canvas.\n const doc = applyDocOverrides(props.doc, props, compMode.value, makeDiag());\n return prepareDocumentForRender(doc);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n // The ONLY Vue-specific part of rendering: how to create a vnode. Every decision about the\n // document — tags, attribute names and values, sanitization, styles, text — is made by\n // core's `renderPxTree`, the same code the web player renders with. Vue writes an SVG\n // attribute name verbatim, so the names it is handed are used as they are.\n const createVNode: PxElementFactory<VNode> = ({ tag, attrs, style, children, text, node, isRoot, index }) => {\n const vnodeProps: Record<string, unknown> = { ...attrs, key: node.id ?? index };\n if (style) vnodeProps[VUE_PROP.style] = style;\n if (isRoot) vnodeProps[VUE_PROP.ref] = (el: Element | null) => { rootElement = el; };\n return h(tag, vnodeProps, children.length ? children : 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 // No `adapter`: the web player's OWN writer drives the elements Vue rendered, found by\n // id under the root. A second writer here was a second place for rules to go missing.\n const options: PxInternalAnimatorOptions = {\n doc,\n // Mounted (or `flush: 'post'`) by the time this runs, so the root exists.\n rootElement: rootElement ?? undefined,\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 renderPxTree(doc, createVNode, makeDiag());\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, PxMouseOutAction, PxOffScreenAction, PxTriggerStart } from '@pixodesk/svg-animator-core';\nimport { createVisibilityGate, type PxVisibilityGate } from '@pixodesk/svg-animator-web/internal';\nimport { computed, defineComponent, h, onBeforeUnmount, onMounted, ref, watch, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n/**\n * Controls playback of SVG+CSS animated files 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** (no `<script>` tag). Import the SVG as a Vue component\n * (`vite-svg-loader`) and pass it in the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg?component';\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator start=\"mouseOver\" mouseOut=\"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 * TWO AXES, the same two the JSON player has: `start` says what STARTS it, `offScreen` says\n * whether it may RUN. The gate itself is the player's (`createVisibilityGate`), so the threshold,\n * the dwell, the hysteresis and the hidden-tab rule cannot drift between the two.\n *\n * @prop start - What starts the animation:\n * - `'load'` — plays as soon as it is visible enough (default)\n * - `'mouseOver'` — plays on hover\n * - `'click'` — plays on click, toggles on second click\n * - `'none'` — **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 `PxTriggerStart` type (one enum per wire key), so the value\n * type-checks — it simply has no effect. Use `PixodeskSvgAnimator` (the JSON\n * player) when you need to start an animation from code.\n * @prop offScreen - What happens while none of it is on screen:\n * - `'pause'` — pauses at the current frame (default); resumes when it comes back\n * - `'continue'` — keeps playing, and starts without waiting to be seen\n * - `'reset'` — back to the beginning, so it replays on the next entry\n * @prop mouseOut - What happens when the pointer leaves, for `start: 'mouseOver'`:\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 `PxMouseOutAction` type.\n * @prop visibilityThreshold - How much of the element must be on screen (0–1) before it may run.\n * Defaults to the wire default (`0.5`), the same as the JSON player.\n * @prop visibilityDebounce - How long that must hold, in ms, before it starts. Defaults to the\n * wire default (`150`).\n * @public\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n // The wrapper spreads `attrs` itself and merges `class` by hand, so Vue must not ALSO\n // apply them — otherwise a host class lands on the div twice.\n inheritAttrs: false,\n props: {\n start: { type: String as PropType<PxTriggerStart>, default: PX_TRIGGER_DEFAULTS.start },\n offScreen: { type: String as PropType<PxOffScreenAction>, default: PX_TRIGGER_DEFAULTS.offScreen },\n mouseOut: { type: String as PropType<PxMouseOutAction>, default: PX_TRIGGER_DEFAULTS.mouseOut },\n visibilityThreshold: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityThreshold },\n visibilityDebounce: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityDebounce },\n },\n setup(props, { slots, attrs }) {\n const state = ref<AnimState>('idle');\n const el = ref<HTMLDivElement | null>(null);\n let gate: PxVisibilityGate | null = null;\n\n const goOut = (): void => {\n state.value =\n props.mouseOut === PxMouseOutAction.reset ? 'idle' :\n props.mouseOut === PxMouseOutAction.pause ? 'paused' : 'playing';\n };\n\n const attach = (): void => {\n gate?.dispose();\n gate = null;\n const node = el.value;\n if (!node) return;\n gate = createVisibilityGate(node, {\n start: props.start,\n offScreen: props.offScreen,\n mouseOut: props.mouseOut,\n visibilityThreshold: props.visibilityThreshold,\n visibilityDebounce: props.visibilityDebounce,\n }, {\n isPlaying: () => state.value === 'playing',\n play: () => { state.value = 'playing'; },\n pause: () => { state.value = 'paused'; },\n cancel: () => { state.value = 'idle'; },\n });\n // Only `load` is held by the gate; a hover or a click is aimed at something seen.\n if (props.start === PxTriggerStart.load) gate.requestStart(false);\n };\n\n onMounted(attach);\n watch(() => [props.start, props.offScreen, props.mouseOut, props.visibilityThreshold, props.visibilityDebounce], attach);\n onBeforeUnmount(() => { gate?.dispose(); gate = null; });\n\n const requestStart = (): void => {\n if (gate) gate.requestStart(true);\n else state.value = 'playing';\n };\n\n const cssClass = 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.start === PxTriggerStart.mouseOver\n ? { onMouseenter: requestStart, onMouseleave: goOut }\n : props.start === PxTriggerStart.click\n ? { onClick: () => { if (state.value === 'playing') state.value = 'paused'; else requestStart(); } }\n : {}\n );\n\n return () => h('div', {\n ref: el,\n ...attrs,\n class: [attrs.class, cssClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["import_svg_animator_core","import_internal","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, PxTimelineEngineSetting, PxTimelinePatch, PxTrigger } from '@pixodesk/svg-animator-web';\nimport type { PxInternalAnimatorOptions } from '@pixodesk/svg-animator-web/internal';\nimport { createAnimator, PxDiagnosticKind, type PxPlaybackOverride, type PxDiagnostic, type PxDiagnostics } from '@pixodesk/svg-animator-web';\nimport { applyAnimatorConfig, foldTimelineOverride, getAnimatorConfig, PxDiagnosticCode, PxControlMode, resolveControlMode, controlModeTakesOverTrigger, progressToTimeMs, type PxAnimatorHandle, type PxControlProps } from '@pixodesk/svg-animator-core';\nimport { createDiagnostics, PX_DEFAULT_DURATION_MS, prepareDocumentForRender, renderPxTree, type PxElementFactory } 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', style: 'style' } 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// 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 = PxPlaybackOverride & 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 dev-docs/plans/playback-override.md §1.1.\n const { timeline, resetTimeline, duration, delay, iterations, start } = props;\n const patch = foldTimelineOverride(timeline, { duration, delay, iterations, start });\n const fullPatch: any = controlModeTakesOverTrigger(compMode)\n ? {\n ...(patch ?? {}),\n timeline: {\n ...((patch as any)?.timeline ?? {}),\n trigger: { ...((patch as any)?.timeline?.trigger ?? {}), start: 'none' },\n },\n }\n : patch;\n\n if (fullPatch !== undefined || resetTimeline) {\n const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetTimeline: !!resetTimeline });\n for (const w of applied.warnings) diag.warn(PxDiagnosticKind.usage, PxDiagnosticCode.timelineOverrideIgnored, 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 ?? PX_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 start: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'none'> },\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 // The `<svg>` this component rendered — handed to the player, which attaches its\n // triggers to it and writes animated values to the elements under it.\n let rootElement: Element | null = null;\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, PxDiagnosticCode.controlPropsConflict, w);\n }, { immediate: true });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n // Overrides FIRST: they can change `timeline.engine` and `duration`, and\n // materialization reads both (the engine picks the stages, the duration sizes loop\n // expansion). Then render what the web player renders — materialized, fresh ids.\n // Rendering the raw document dropped every `effects` bucket, so a document painted\n // by `effects` alone came out as an empty canvas.\n const doc = applyDocOverrides(props.doc, props, compMode.value, makeDiag());\n return prepareDocumentForRender(doc);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n // The ONLY Vue-specific part of rendering: how to create a vnode. Every decision about the\n // document — tags, attribute names and values, sanitization, styles, text — is made by\n // core's `renderPxTree`, the same code the web player renders with. Vue writes an SVG\n // attribute name verbatim, so the names it is handed are used as they are.\n const createVNode: PxElementFactory<VNode> = ({ tag, attrs, style, children, text, node, isRoot, index }) => {\n const vnodeProps: Record<string, unknown> = { ...attrs, key: node.id ?? index };\n if (style) vnodeProps[VUE_PROP.style] = style;\n if (isRoot) vnodeProps[VUE_PROP.ref] = (el: Element | null) => { rootElement = el; };\n return h(tag, vnodeProps, children.length ? children : 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 // No `adapter`: the web player's OWN writer drives the elements Vue rendered, found by\n // id under the root. A second writer here was a second place for rules to go missing.\n const options: PxInternalAnimatorOptions = {\n doc,\n // Mounted (or `flush: 'post'`) by the time this runs, so the root exists.\n rootElement: rootElement ?? undefined,\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 renderPxTree(doc, createVNode, makeDiag());\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, PxMouseOutAction, PxOffScreenAction, PxTriggerStart } from '@pixodesk/svg-animator-core';\nimport { createVisibilityGate, type PxVisibilityGate } from '@pixodesk/svg-animator-web/internal';\nimport { computed, defineComponent, h, onBeforeUnmount, onMounted, ref, watch, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n/**\n * Controls playback of SVG+CSS animated files 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** (no `<script>` tag). Import the SVG as a Vue component\n * (`vite-svg-loader`) and pass it in the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg?component';\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator start=\"mouseOver\" mouseOut=\"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 * TWO AXES, the same two the JSON player has: `start` says what STARTS it, `offScreen` says\n * whether it may RUN. The gate itself is the player's (`createVisibilityGate`), so the threshold,\n * the dwell, the hysteresis and the hidden-tab rule cannot drift between the two.\n *\n * @prop start - What starts the animation:\n * - `'load'` — plays as soon as it is visible enough (default)\n * - `'mouseOver'` — plays on hover\n * - `'click'` — plays on click, toggles on second click\n * - `'none'` — **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 `PxTriggerStart` type (one enum per wire key), so the value\n * type-checks — it simply has no effect. Use `PixodeskSvgAnimator` (the JSON\n * player) when you need to start an animation from code.\n * @prop offScreen - What happens while none of it is on screen:\n * - `'pause'` — pauses at the current frame (default); resumes when it comes back\n * - `'continue'` — keeps playing, and starts without waiting to be seen\n * - `'reset'` — back to the beginning, so it replays on the next entry\n * @prop mouseOut - What happens when the pointer leaves, for `start: 'mouseOver'`:\n * - `'pause'` — pauses at the current frame (default)\n * - `'continue'` — keeps playing\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 `PxMouseOutAction` type.\n * @prop visibilityThreshold - How much of the element must be on screen (0–1) before it may run.\n * Defaults to the wire default (`0.5`), the same as the JSON player.\n * @prop visibilityDebounce - How long that must hold, in ms, before it starts. Defaults to the\n * wire default (`150`).\n * @public\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n // The wrapper spreads `attrs` itself and merges `class` by hand, so Vue must not ALSO\n // apply them — otherwise a host class lands on the div twice.\n inheritAttrs: false,\n props: {\n start: { type: String as PropType<PxTriggerStart>, default: PX_TRIGGER_DEFAULTS.start },\n offScreen: { type: String as PropType<PxOffScreenAction>, default: PX_TRIGGER_DEFAULTS.offScreen },\n mouseOut: { type: String as PropType<PxMouseOutAction>, default: PX_TRIGGER_DEFAULTS.mouseOut },\n visibilityThreshold: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityThreshold },\n visibilityDebounce: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityDebounce },\n },\n setup(props, { slots, attrs }) {\n const state = ref<AnimState>('idle');\n const el = ref<HTMLDivElement | null>(null);\n let gate: PxVisibilityGate | null = null;\n\n const goOut = (): void => {\n state.value =\n props.mouseOut === PxMouseOutAction.reset ? 'idle' :\n props.mouseOut === PxMouseOutAction.pause ? 'paused' : 'playing';\n };\n\n const attach = (): void => {\n gate?.dispose();\n gate = null;\n const node = el.value;\n if (!node) return;\n gate = createVisibilityGate(node, {\n start: props.start,\n offScreen: props.offScreen,\n mouseOut: props.mouseOut,\n visibilityThreshold: props.visibilityThreshold,\n visibilityDebounce: props.visibilityDebounce,\n }, {\n isPlaying: () => state.value === 'playing',\n play: () => { state.value = 'playing'; },\n pause: () => { state.value = 'paused'; },\n cancel: () => { state.value = 'idle'; },\n });\n // Only `load` is held by the gate; a hover or a click is aimed at something seen.\n if (props.start === PxTriggerStart.load) gate.requestStart(false);\n };\n\n onMounted(attach);\n watch(() => [props.start, props.offScreen, props.mouseOut, props.visibilityThreshold, props.visibilityDebounce], attach);\n onBeforeUnmount(() => { gate?.dispose(); gate = null; });\n\n const requestStart = (): void => {\n if (gate) gate.requestStart(true);\n else state.value = 'playing';\n };\n\n const cssClass = 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.start === PxTriggerStart.mouseOver\n ? { onMouseenter: requestStart, onMouseleave: goOut }\n : props.start === PxTriggerStart.click\n ? { onClick: () => { if (state.value === 'playing') state.value = 'paused'; else requestStart(); } }\n : {}\n );\n\n return () => h('div', {\n ref: el,\n ...attrs,\n class: [attrs.class, cssClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["import_svg_animator_core","import_internal","import_vue"]}
package/dist/index.d.cts CHANGED
@@ -209,8 +209,8 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
209
209
  * - `'continue'` — keeps playing, and starts without waiting to be seen
210
210
  * - `'reset'` — back to the beginning, so it replays on the next entry
211
211
  * @prop mouseOut - What happens when the pointer leaves, for `start: 'mouseOver'`:
212
- * - `'continue'` — keeps playing (default)
213
- * - `'pause'` — pauses at the current frame
212
+ * - `'pause'` — pauses at the current frame (default)
213
+ * - `'continue'` — keeps playing
214
214
  * - `'reset'` — resets to the beginning
215
215
  * - `'reverse'` — **acts as `'continue'` here.** A CSS class toggle cannot run keyframes
216
216
  * backwards. Accepted so the prop keeps the shared `PxMouseOutAction` type.
@@ -231,7 +231,7 @@ declare const PixodeskSvgCssAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
231
231
  };
232
232
  mouseOut: {
233
233
  type: PropType<PxMouseOutAction>;
234
- default: "continue";
234
+ default: "pause";
235
235
  };
236
236
  visibilityThreshold: {
237
237
  type: NumberConstructor;
@@ -254,7 +254,7 @@ declare const PixodeskSvgCssAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
254
254
  };
255
255
  mouseOut: {
256
256
  type: PropType<PxMouseOutAction>;
257
- default: "continue";
257
+ default: "pause";
258
258
  };
259
259
  visibilityThreshold: {
260
260
  type: NumberConstructor;
package/dist/index.d.ts CHANGED
@@ -209,8 +209,8 @@ declare const PixodeskSvgAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
209
209
  * - `'continue'` — keeps playing, and starts without waiting to be seen
210
210
  * - `'reset'` — back to the beginning, so it replays on the next entry
211
211
  * @prop mouseOut - What happens when the pointer leaves, for `start: 'mouseOver'`:
212
- * - `'continue'` — keeps playing (default)
213
- * - `'pause'` — pauses at the current frame
212
+ * - `'pause'` — pauses at the current frame (default)
213
+ * - `'continue'` — keeps playing
214
214
  * - `'reset'` — resets to the beginning
215
215
  * - `'reverse'` — **acts as `'continue'` here.** A CSS class toggle cannot run keyframes
216
216
  * backwards. Accepted so the prop keeps the shared `PxMouseOutAction` type.
@@ -231,7 +231,7 @@ declare const PixodeskSvgCssAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
231
231
  };
232
232
  mouseOut: {
233
233
  type: PropType<PxMouseOutAction>;
234
- default: "continue";
234
+ default: "pause";
235
235
  };
236
236
  visibilityThreshold: {
237
237
  type: NumberConstructor;
@@ -254,7 +254,7 @@ declare const PixodeskSvgCssAnimator: vue.DefineComponent<vue.ExtractPropTypes<{
254
254
  };
255
255
  mouseOut: {
256
256
  type: PropType<PxMouseOutAction>;
257
- default: "continue";
257
+ default: "pause";
258
258
  };
259
259
  visibilityThreshold: {
260
260
  type: NumberConstructor;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/PixodeskSvgAnimator.ts","../src/PixodeskSvgCssAnimator.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxAnimatedSvgDocument, PxAnimatorApi, PxTimelineEngineSetting, PxTimelinePatch, PxTrigger } from '@pixodesk/svg-animator-web';\nimport type { PxInternalAnimatorOptions } from '@pixodesk/svg-animator-web/internal';\nimport { createAnimator, PxDiagnosticKind, type PxPlaybackOverride, type PxDiagnostic, type PxDiagnostics } from '@pixodesk/svg-animator-web';\nimport { applyAnimatorConfig, foldTimelineOverride, getAnimatorConfig, PxDiagnosticCode, PxControlMode, resolveControlMode, controlModeTakesOverTrigger, progressToTimeMs, type PxAnimatorHandle, type PxControlProps } from '@pixodesk/svg-animator-core';\nimport { createDiagnostics, PX_DEFAULT_DURATION_MS, prepareDocumentForRender, renderPxTree, type PxElementFactory } 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', style: 'style' } 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// 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 = PxPlaybackOverride & 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 dev-docs/plans/playback-override.md §1.1.\n const { timeline, resetTimeline, duration, delay, iterations, start } = props;\n const patch = foldTimelineOverride(timeline, { duration, delay, iterations, start });\n const fullPatch: any = controlModeTakesOverTrigger(compMode)\n ? {\n ...(patch ?? {}),\n timeline: {\n ...((patch as any)?.timeline ?? {}),\n trigger: { ...((patch as any)?.timeline?.trigger ?? {}), start: 'none' },\n },\n }\n : patch;\n\n if (fullPatch !== undefined || resetTimeline) {\n const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetTimeline: !!resetTimeline });\n for (const w of applied.warnings) diag.warn(PxDiagnosticKind.usage, PxDiagnosticCode.timelineOverrideIgnored, 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 ?? PX_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 start: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'none'> },\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 // The `<svg>` this component rendered — handed to the player, which attaches its\n // triggers to it and writes animated values to the elements under it.\n let rootElement: Element | null = null;\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, PxDiagnosticCode.controlPropsConflict, w);\n }, { immediate: true });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n // Overrides FIRST: they can change `timeline.engine` and `duration`, and\n // materialization reads both (the engine picks the stages, the duration sizes loop\n // expansion). Then render what the web player renders — materialized, fresh ids.\n // Rendering the raw document dropped every `effects` bucket, so a document painted\n // by `effects` alone came out as an empty canvas.\n const doc = applyDocOverrides(props.doc, props, compMode.value, makeDiag());\n return prepareDocumentForRender(doc);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n // The ONLY Vue-specific part of rendering: how to create a vnode. Every decision about the\n // document — tags, attribute names and values, sanitization, styles, text — is made by\n // core's `renderPxTree`, the same code the web player renders with. Vue writes an SVG\n // attribute name verbatim, so the names it is handed are used as they are.\n const createVNode: PxElementFactory<VNode> = ({ tag, attrs, style, children, text, node, isRoot, index }) => {\n const vnodeProps: Record<string, unknown> = { ...attrs, key: node.id ?? index };\n if (style) vnodeProps[VUE_PROP.style] = style;\n if (isRoot) vnodeProps[VUE_PROP.ref] = (el: Element | null) => { rootElement = el; };\n return h(tag, vnodeProps, children.length ? children : 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 // No `adapter`: the web player's OWN writer drives the elements Vue rendered, found by\n // id under the root. A second writer here was a second place for rules to go missing.\n const options: PxInternalAnimatorOptions = {\n doc,\n // Mounted (or `flush: 'post'`) by the time this runs, so the root exists.\n rootElement: rootElement ?? undefined,\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 renderPxTree(doc, createVNode, makeDiag());\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, PxMouseOutAction, PxOffScreenAction, PxTriggerStart } from '@pixodesk/svg-animator-core';\nimport { createVisibilityGate, type PxVisibilityGate } from '@pixodesk/svg-animator-web/internal';\nimport { computed, defineComponent, h, onBeforeUnmount, onMounted, ref, watch, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n/**\n * Controls playback of SVG+CSS animated files 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** (no `<script>` tag). Import the SVG as a Vue component\n * (`vite-svg-loader`) and pass it in the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg?component';\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator start=\"mouseOver\" mouseOut=\"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 * TWO AXES, the same two the JSON player has: `start` says what STARTS it, `offScreen` says\n * whether it may RUN. The gate itself is the player's (`createVisibilityGate`), so the threshold,\n * the dwell, the hysteresis and the hidden-tab rule cannot drift between the two.\n *\n * @prop start - What starts the animation:\n * - `'load'` — plays as soon as it is visible enough (default)\n * - `'mouseOver'` — plays on hover\n * - `'click'` — plays on click, toggles on second click\n * - `'none'` — **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 `PxTriggerStart` type (one enum per wire key), so the value\n * type-checks — it simply has no effect. Use `PixodeskSvgAnimator` (the JSON\n * player) when you need to start an animation from code.\n * @prop offScreen - What happens while none of it is on screen:\n * - `'pause'` — pauses at the current frame (default); resumes when it comes back\n * - `'continue'` — keeps playing, and starts without waiting to be seen\n * - `'reset'` — back to the beginning, so it replays on the next entry\n * @prop mouseOut - What happens when the pointer leaves, for `start: 'mouseOver'`:\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 `PxMouseOutAction` type.\n * @prop visibilityThreshold - How much of the element must be on screen (0–1) before it may run.\n * Defaults to the wire default (`0.5`), the same as the JSON player.\n * @prop visibilityDebounce - How long that must hold, in ms, before it starts. Defaults to the\n * wire default (`150`).\n * @public\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n // The wrapper spreads `attrs` itself and merges `class` by hand, so Vue must not ALSO\n // apply them — otherwise a host class lands on the div twice.\n inheritAttrs: false,\n props: {\n start: { type: String as PropType<PxTriggerStart>, default: PX_TRIGGER_DEFAULTS.start },\n offScreen: { type: String as PropType<PxOffScreenAction>, default: PX_TRIGGER_DEFAULTS.offScreen },\n mouseOut: { type: String as PropType<PxMouseOutAction>, default: PX_TRIGGER_DEFAULTS.mouseOut },\n visibilityThreshold: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityThreshold },\n visibilityDebounce: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityDebounce },\n },\n setup(props, { slots, attrs }) {\n const state = ref<AnimState>('idle');\n const el = ref<HTMLDivElement | null>(null);\n let gate: PxVisibilityGate | null = null;\n\n const goOut = (): void => {\n state.value =\n props.mouseOut === PxMouseOutAction.reset ? 'idle' :\n props.mouseOut === PxMouseOutAction.pause ? 'paused' : 'playing';\n };\n\n const attach = (): void => {\n gate?.dispose();\n gate = null;\n const node = el.value;\n if (!node) return;\n gate = createVisibilityGate(node, {\n start: props.start,\n offScreen: props.offScreen,\n mouseOut: props.mouseOut,\n visibilityThreshold: props.visibilityThreshold,\n visibilityDebounce: props.visibilityDebounce,\n }, {\n isPlaying: () => state.value === 'playing',\n play: () => { state.value = 'playing'; },\n pause: () => { state.value = 'paused'; },\n cancel: () => { state.value = 'idle'; },\n });\n // Only `load` is held by the gate; a hover or a click is aimed at something seen.\n if (props.start === PxTriggerStart.load) gate.requestStart(false);\n };\n\n onMounted(attach);\n watch(() => [props.start, props.offScreen, props.mouseOut, props.visibilityThreshold, props.visibilityDebounce], attach);\n onBeforeUnmount(() => { gate?.dispose(); gate = null; });\n\n const requestStart = (): void => {\n if (gate) gate.requestStart(true);\n else state.value = 'playing';\n };\n\n const cssClass = 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.start === PxTriggerStart.mouseOver\n ? { onMouseenter: requestStart, onMouseleave: goOut }\n : props.start === PxTriggerStart.click\n ? { onClick: () => { if (state.value === 'playing') state.value = 'paused'; else requestStart(); } }\n : {}\n );\n\n return () => h('div', {\n ref: el,\n ...attrs,\n class: [attrs.class, cssClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["computed","defineComponent","h","onMounted","ref","watch"]}
1
+ {"version":3,"sources":["../src/PixodeskSvgAnimator.ts","../src/PixodeskSvgCssAnimator.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxAnimatedSvgDocument, PxAnimatorApi, PxTimelineEngineSetting, PxTimelinePatch, PxTrigger } from '@pixodesk/svg-animator-web';\nimport type { PxInternalAnimatorOptions } from '@pixodesk/svg-animator-web/internal';\nimport { createAnimator, PxDiagnosticKind, type PxPlaybackOverride, type PxDiagnostic, type PxDiagnostics } from '@pixodesk/svg-animator-web';\nimport { applyAnimatorConfig, foldTimelineOverride, getAnimatorConfig, PxDiagnosticCode, PxControlMode, resolveControlMode, controlModeTakesOverTrigger, progressToTimeMs, type PxAnimatorHandle, type PxControlProps } from '@pixodesk/svg-animator-core';\nimport { createDiagnostics, PX_DEFAULT_DURATION_MS, prepareDocumentForRender, renderPxTree, type PxElementFactory } 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', style: 'style' } 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// 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 = PxPlaybackOverride & 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 dev-docs/plans/playback-override.md §1.1.\n const { timeline, resetTimeline, duration, delay, iterations, start } = props;\n const patch = foldTimelineOverride(timeline, { duration, delay, iterations, start });\n const fullPatch: any = controlModeTakesOverTrigger(compMode)\n ? {\n ...(patch ?? {}),\n timeline: {\n ...((patch as any)?.timeline ?? {}),\n trigger: { ...((patch as any)?.timeline?.trigger ?? {}), start: 'none' },\n },\n }\n : patch;\n\n if (fullPatch !== undefined || resetTimeline) {\n const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetTimeline: !!resetTimeline });\n for (const w of applied.warnings) diag.warn(PxDiagnosticKind.usage, PxDiagnosticCode.timelineOverrideIgnored, 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 ?? PX_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 start: { type: String as PropType<'load' | 'mouseOver' | 'click' | 'none'> },\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 // The `<svg>` this component rendered — handed to the player, which attaches its\n // triggers to it and writes animated values to the elements under it.\n let rootElement: Element | null = null;\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, PxDiagnosticCode.controlPropsConflict, w);\n }, { immediate: true });\n\n // -- Prepare the document with overrides --------------------------------\n\n const resolvedDoc = computed(() => {\n // Overrides FIRST: they can change `timeline.engine` and `duration`, and\n // materialization reads both (the engine picks the stages, the duration sizes loop\n // expansion). Then render what the web player renders — materialized, fresh ids.\n // Rendering the raw document dropped every `effects` bucket, so a document painted\n // by `effects` alone came out as an empty canvas.\n const doc = applyDocOverrides(props.doc, props, compMode.value, makeDiag());\n return prepareDocumentForRender(doc);\n });\n\n // -- Render the SVG node tree -------------------------------------------\n\n // The ONLY Vue-specific part of rendering: how to create a vnode. Every decision about the\n // document — tags, attribute names and values, sanitization, styles, text — is made by\n // core's `renderPxTree`, the same code the web player renders with. Vue writes an SVG\n // attribute name verbatim, so the names it is handed are used as they are.\n const createVNode: PxElementFactory<VNode> = ({ tag, attrs, style, children, text, node, isRoot, index }) => {\n const vnodeProps: Record<string, unknown> = { ...attrs, key: node.id ?? index };\n if (style) vnodeProps[VUE_PROP.style] = style;\n if (isRoot) vnodeProps[VUE_PROP.ref] = (el: Element | null) => { rootElement = el; };\n return h(tag, vnodeProps, children.length ? children : 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 // No `adapter`: the web player's OWN writer drives the elements Vue rendered, found by\n // id under the root. A second writer here was a second place for rules to go missing.\n const options: PxInternalAnimatorOptions = {\n doc,\n // Mounted (or `flush: 'post'`) by the time this runs, so the root exists.\n rootElement: rootElement ?? undefined,\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 renderPxTree(doc, createVNode, makeDiag());\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, PxMouseOutAction, PxOffScreenAction, PxTriggerStart } from '@pixodesk/svg-animator-core';\nimport { createVisibilityGate, type PxVisibilityGate } from '@pixodesk/svg-animator-web/internal';\nimport { computed, defineComponent, h, onBeforeUnmount, onMounted, ref, watch, type PropType } from 'vue';\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n/**\n * Controls playback of SVG+CSS animated files 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** (no `<script>` tag). Import the SVG as a Vue component\n * (`vite-svg-loader`) and pass it in the default slot:\n *\n * ```vue\n * <script setup>\n * import AnimationSvg from './animation.svg?component';\n * </script>\n *\n * <template>\n * <PixodeskSvgCssAnimator start=\"mouseOver\" mouseOut=\"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 * TWO AXES, the same two the JSON player has: `start` says what STARTS it, `offScreen` says\n * whether it may RUN. The gate itself is the player's (`createVisibilityGate`), so the threshold,\n * the dwell, the hysteresis and the hidden-tab rule cannot drift between the two.\n *\n * @prop start - What starts the animation:\n * - `'load'` — plays as soon as it is visible enough (default)\n * - `'mouseOver'` — plays on hover\n * - `'click'` — plays on click, toggles on second click\n * - `'none'` — **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 `PxTriggerStart` type (one enum per wire key), so the value\n * type-checks — it simply has no effect. Use `PixodeskSvgAnimator` (the JSON\n * player) when you need to start an animation from code.\n * @prop offScreen - What happens while none of it is on screen:\n * - `'pause'` — pauses at the current frame (default); resumes when it comes back\n * - `'continue'` — keeps playing, and starts without waiting to be seen\n * - `'reset'` — back to the beginning, so it replays on the next entry\n * @prop mouseOut - What happens when the pointer leaves, for `start: 'mouseOver'`:\n * - `'pause'` — pauses at the current frame (default)\n * - `'continue'` — keeps playing\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 `PxMouseOutAction` type.\n * @prop visibilityThreshold - How much of the element must be on screen (0–1) before it may run.\n * Defaults to the wire default (`0.5`), the same as the JSON player.\n * @prop visibilityDebounce - How long that must hold, in ms, before it starts. Defaults to the\n * wire default (`150`).\n * @public\n */\nconst PixodeskSvgCssAnimator = defineComponent({\n name: 'PixodeskSvgCssAnimator',\n // The wrapper spreads `attrs` itself and merges `class` by hand, so Vue must not ALSO\n // apply them — otherwise a host class lands on the div twice.\n inheritAttrs: false,\n props: {\n start: { type: String as PropType<PxTriggerStart>, default: PX_TRIGGER_DEFAULTS.start },\n offScreen: { type: String as PropType<PxOffScreenAction>, default: PX_TRIGGER_DEFAULTS.offScreen },\n mouseOut: { type: String as PropType<PxMouseOutAction>, default: PX_TRIGGER_DEFAULTS.mouseOut },\n visibilityThreshold: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityThreshold },\n visibilityDebounce: { type: Number, default: PX_TRIGGER_DEFAULTS.visibilityDebounce },\n },\n setup(props, { slots, attrs }) {\n const state = ref<AnimState>('idle');\n const el = ref<HTMLDivElement | null>(null);\n let gate: PxVisibilityGate | null = null;\n\n const goOut = (): void => {\n state.value =\n props.mouseOut === PxMouseOutAction.reset ? 'idle' :\n props.mouseOut === PxMouseOutAction.pause ? 'paused' : 'playing';\n };\n\n const attach = (): void => {\n gate?.dispose();\n gate = null;\n const node = el.value;\n if (!node) return;\n gate = createVisibilityGate(node, {\n start: props.start,\n offScreen: props.offScreen,\n mouseOut: props.mouseOut,\n visibilityThreshold: props.visibilityThreshold,\n visibilityDebounce: props.visibilityDebounce,\n }, {\n isPlaying: () => state.value === 'playing',\n play: () => { state.value = 'playing'; },\n pause: () => { state.value = 'paused'; },\n cancel: () => { state.value = 'idle'; },\n });\n // Only `load` is held by the gate; a hover or a click is aimed at something seen.\n if (props.start === PxTriggerStart.load) gate.requestStart(false);\n };\n\n onMounted(attach);\n watch(() => [props.start, props.offScreen, props.mouseOut, props.visibilityThreshold, props.visibilityDebounce], attach);\n onBeforeUnmount(() => { gate?.dispose(); gate = null; });\n\n const requestStart = (): void => {\n if (gate) gate.requestStart(true);\n else state.value = 'playing';\n };\n\n const cssClass = 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.start === PxTriggerStart.mouseOver\n ? { onMouseenter: requestStart, onMouseleave: goOut }\n : props.start === PxTriggerStart.click\n ? { onClick: () => { if (state.value === 'playing') state.value = 'paused'; else requestStart(); } }\n : {}\n );\n\n return () => h('div', {\n ref: el,\n ...attrs,\n class: [attrs.class, cssClass.value],\n ...handlers.value,\n }, slots.default?.());\n },\n});\nexport default PixodeskSvgCssAnimator;\n"],"mappings":"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","names":["computed","defineComponent","h","onMounted","ref","watch"]}
package/dist/index.umd.js CHANGED
@@ -56761,7 +56761,7 @@ ${codeFrame}` : message);
56761
56761
  PixodeskSvgCssAnimator: () => PixodeskSvgCssAnimator_default
56762
56762
  });
56763
56763
 
56764
- // ../svg-animator-web/dist/chunk-ZBGGXE5W.js
56764
+ // ../svg-animator-web/dist/chunk-ZEUVRAKS.js
56765
56765
  var __defProp2 = Object.defineProperty;
56766
56766
  var __defProps = Object.defineProperties;
56767
56767
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
@@ -57445,13 +57445,14 @@ ${codeFrame}` : message);
57445
57445
  var PX_TRIGGER_DEFAULTS = {
57446
57446
  start: "load",
57447
57447
  offScreen: "pause",
57448
- mouseOut: "continue",
57448
+ mouseOut: "pause",
57449
57449
  visibilityThreshold: 0.5,
57450
57450
  visibilityDebounce: 150,
57451
57451
  finish: "hold"
57452
57452
  };
57453
57453
  var PX_DEFAULT_DURATION_MS = 1e3;
57454
57454
  var PX_DEFAULT_ITERATIONS = 1;
57455
+ var PX_DEFAULT_UNITS_PER_EM = 1e3;
57455
57456
  function resolveTrigger(trigger) {
57456
57457
  var _a22, _b, _c, _d, _e;
57457
57458
  return {
@@ -57714,7 +57715,7 @@ ${codeFrame}` : message);
57714
57715
  fontFamily: px.string(),
57715
57716
  fontStyle: px.string(),
57716
57717
  ascent: px.number(),
57717
- unitsPerEm: px.number(),
57718
+ unitsPerEm: px.number(PX_DEFAULT_UNITS_PER_EM).optional(),
57718
57719
  glyphs: px.record(PxGlyphSchema)
57719
57720
  }));
57720
57721
  var PxDefinitionsSchema = implementsInterface()(px.object({
@@ -60404,6 +60405,9 @@ ${codeFrame}` : message);
60404
60405
  if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a22 = s.fontFamily) != null ? _a22 : "") + '"');
60405
60406
  return gf;
60406
60407
  }
60408
+ function unitsPerEmOf(gf) {
60409
+ return (gf == null ? void 0 : gf.unitsPerEm) || PX_DEFAULT_UNITS_PER_EM;
60410
+ }
60407
60411
  function soleFontOf(glyphs) {
60408
60412
  const names = Object.keys(glyphs);
60409
60413
  return names.length === 1 ? glyphs[names[0]] : void 0;
@@ -60433,7 +60437,7 @@ ${codeFrame}` : message);
60433
60437
  const renderChars = (content, s) => {
60434
60438
  var _a3;
60435
60439
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
60436
- const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
60440
+ const upm = unitsPerEmOf(gf);
60437
60441
  const scale = s.fontSize / upm;
60438
60442
  const ascentEm = (_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm;
60439
60443
  const paint = paintOf(s);
@@ -60495,8 +60499,9 @@ ${codeFrame}` : message);
60495
60499
  if (content && !((_a22 = el.children) == null ? void 0 : _a22.length)) {
60496
60500
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
60497
60501
  if (gf) {
60498
- const scale = s.fontSize / gf.unitsPerEm;
60499
- const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
60502
+ const upm = unitsPerEmOf(gf);
60503
+ const scale = s.fontSize / upm;
60504
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * upm;
60500
60505
  const paint = paintOf(s);
60501
60506
  for (let i = 0; i < content.length; i++) {
60502
60507
  const ch = content.charAt(i);
@@ -60506,7 +60511,7 @@ ${codeFrame}` : message);
60506
60511
  cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
60507
60512
  adv += glyphAdv;
60508
60513
  } else if (/\S/.test(ch)) {
60509
- const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
60514
+ const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
60510
60515
  const boxAdv = wEm * scale;
60511
60516
  cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, isMissing: true, midBase: adv + boxAdv / 2 });
60512
60517
  adv += boxAdv;
@@ -64401,7 +64406,7 @@ ${codeFrame}` : message);
64401
64406
  return proxy;
64402
64407
  }
64403
64408
 
64404
- // ../svg-animator-core/dist/chunk-37OFJ3RX.js
64409
+ // ../svg-animator-core/dist/chunk-J5V5JJDT.js
64405
64410
  var __defProp3 = Object.defineProperty;
64406
64411
  var __defProps3 = Object.defineProperties;
64407
64412
  var __getOwnPropDescs3 = Object.getOwnPropertyDescriptors;
@@ -65060,13 +65065,14 @@ ${codeFrame}` : message);
65060
65065
  var PX_TRIGGER_DEFAULTS2 = {
65061
65066
  start: "load",
65062
65067
  offScreen: "pause",
65063
- mouseOut: "continue",
65068
+ mouseOut: "pause",
65064
65069
  visibilityThreshold: 0.5,
65065
65070
  visibilityDebounce: 150,
65066
65071
  finish: "hold"
65067
65072
  };
65068
65073
  var PX_DEFAULT_DURATION_MS2 = 1e3;
65069
65074
  var PX_DEFAULT_ITERATIONS2 = 1;
65075
+ var PX_DEFAULT_UNITS_PER_EM2 = 1e3;
65070
65076
  var PxControlMode = {
65071
65077
  /** No control props — the document's trigger decides, and nothing is taken over. */
65072
65078
  static: "static",
@@ -65344,7 +65350,7 @@ ${codeFrame}` : message);
65344
65350
  fontFamily: px2.string(),
65345
65351
  fontStyle: px2.string(),
65346
65352
  ascent: px2.number(),
65347
- unitsPerEm: px2.number(),
65353
+ unitsPerEm: px2.number(PX_DEFAULT_UNITS_PER_EM2).optional(),
65348
65354
  glyphs: px2.record(PxGlyphSchema2)
65349
65355
  }));
65350
65356
  var PxDefinitionsSchema2 = implementsInterface2()(px2.object({
@@ -67946,6 +67952,9 @@ ${codeFrame}` : message);
67946
67952
  if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a22 = s.fontFamily) != null ? _a22 : "") + '"');
67947
67953
  return gf;
67948
67954
  }
67955
+ function unitsPerEmOf2(gf) {
67956
+ return (gf == null ? void 0 : gf.unitsPerEm) || PX_DEFAULT_UNITS_PER_EM2;
67957
+ }
67949
67958
  function soleFontOf2(glyphs) {
67950
67959
  const names = Object.keys(glyphs);
67951
67960
  return names.length === 1 ? glyphs[names[0]] : void 0;
@@ -67975,7 +67984,7 @@ ${codeFrame}` : message);
67975
67984
  const renderChars = (content, s) => {
67976
67985
  var _a3;
67977
67986
  const gf = glyphFontFor2(s, glyphs, soleFont, warnings);
67978
- const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
67987
+ const upm = unitsPerEmOf2(gf);
67979
67988
  const scale = s.fontSize / upm;
67980
67989
  const ascentEm = (_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm;
67981
67990
  const paint = paintOf2(s);
@@ -68037,8 +68046,9 @@ ${codeFrame}` : message);
68037
68046
  if (content && !((_a22 = el.children) == null ? void 0 : _a22.length)) {
68038
68047
  const gf = glyphFontFor2(s, glyphs, soleFont, warnings);
68039
68048
  if (gf) {
68040
- const scale = s.fontSize / gf.unitsPerEm;
68041
- const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
68049
+ const upm = unitsPerEmOf2(gf);
68050
+ const scale = s.fontSize / upm;
68051
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * upm;
68042
68052
  const paint = paintOf2(s);
68043
68053
  for (let i = 0; i < content.length; i++) {
68044
68054
  const ch = content.charAt(i);
@@ -68048,7 +68058,7 @@ ${codeFrame}` : message);
68048
68058
  cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
68049
68059
  adv += glyphAdv;
68050
68060
  } else if (/\S/.test(ch)) {
68051
- const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM2 * gf.unitsPerEm;
68061
+ const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM2 * upm;
68052
68062
  const boxAdv = wEm * scale;
68053
68063
  cells.push({ glyphD: missingGlyphBoxEm2(wEm, ascentEm), widthEm: wEm, scale, paint, isMissing: true, midBase: adv + boxAdv / 2 });
68054
68064
  adv += boxAdv;