@pixerate/flair 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +1 -0
- package/dist/catalog/index.js +2 -2
- package/dist/{chunk-WAMA45G3.js → chunk-5USSDEQL.js} +77 -21
- package/dist/chunk-5USSDEQL.js.map +1 -0
- package/dist/{chunk-GTIAOYOK.js → chunk-74ZLCZOG.js} +13 -10
- package/dist/chunk-74ZLCZOG.js.map +1 -0
- package/dist/{chunk-NGKNI3QX.js → chunk-CK6EV37I.js} +19 -495
- package/dist/chunk-CK6EV37I.js.map +1 -0
- package/dist/chunk-DBTLCXKY.js +332 -0
- package/dist/chunk-DBTLCXKY.js.map +1 -0
- package/dist/chunk-G2B5L234.js +414 -0
- package/dist/chunk-G2B5L234.js.map +1 -0
- package/dist/{chunk-VP6IEWIK.js → chunk-H6L67KHI.js} +1 -1
- package/dist/chunk-H6VDFBIO.js +498 -0
- package/dist/chunk-H6VDFBIO.js.map +1 -0
- package/dist/{chunk-OQ4EWZ3B.js → chunk-HVXWNGTW.js} +83 -6
- package/dist/{chunk-OQ4EWZ3B.js.map → chunk-HVXWNGTW.js.map} +1 -1
- package/dist/chunk-JL6TI6II.js +724 -0
- package/dist/chunk-JL6TI6II.js.map +1 -0
- package/dist/{chunk-OHW7UG6D.js → chunk-ORAFCHX3.js} +26 -2
- package/dist/{chunk-OHW7UG6D.js.map → chunk-ORAFCHX3.js.map} +1 -1
- package/dist/{chunk-ARKC7LDW.js → chunk-RDU63CDO.js} +2 -331
- package/dist/chunk-RDU63CDO.js.map +1 -0
- package/dist/{chunk-LVPIIWPP.js → chunk-STKEKXCK.js} +18 -8
- package/dist/chunk-STKEKXCK.js.map +1 -0
- package/dist/chunk-UCZ43ARE.js +902 -0
- package/dist/chunk-UCZ43ARE.js.map +1 -0
- package/dist/chunk-YBGRXVAE.js +407 -0
- package/dist/chunk-YBGRXVAE.js.map +1 -0
- package/dist/cli.js +74 -11
- package/dist/cli.js.map +1 -1
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.js +14 -12
- package/dist/editor/index.js.map +1 -1
- package/dist/effect-GGH3OSOT.js +47 -0
- package/dist/embed/index.d.ts +215 -0
- package/dist/embed/index.js +21 -0
- package/dist/{export-DH2HMACO.js → export-QVW474KM.js} +3 -3
- package/dist/export-QVW474KM.js.map +1 -0
- package/dist/frames-VEcqa40g.d.ts +161 -0
- package/dist/index.d.ts +47 -164
- package/dist/index.js +102 -80
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +167 -7
- package/dist/node.js +25 -3
- package/dist/react/index.d.ts +33 -2
- package/dist/react/index.js +54 -9
- package/dist/react/index.js.map +1 -1
- package/dist/recorder-CDPPTJMG.js +31 -0
- package/dist/recorder-CDPPTJMG.js.map +1 -0
- package/dist/{renderer-C2P1qGzP.d.ts → renderer-teaa98RE.d.ts} +1 -1
- package/dist/svelte/index.d.ts +33 -4
- package/dist/svelte/index.js +51 -9
- package/dist/svelte/index.js.map +1 -1
- package/dist/vector/index.d.ts +52 -1
- package/dist/vector/index.js +8 -4
- package/package.json +1 -1
- package/dist/chunk-ARKC7LDW.js.map +0 -1
- package/dist/chunk-GTIAOYOK.js.map +0 -1
- package/dist/chunk-LVPIIWPP.js.map +0 -1
- package/dist/chunk-NGKNI3QX.js.map +0 -1
- package/dist/chunk-UP6QQVRS.js +0 -331
- package/dist/chunk-UP6QQVRS.js.map +0 -1
- package/dist/chunk-WAMA45G3.js.map +0 -1
- package/dist/recorder-HKFFHQES.js +0 -10
- /package/dist/{chunk-VP6IEWIK.js.map → chunk-H6L67KHI.js.map} +0 -0
- /package/dist/{export-DH2HMACO.js.map → effect-GGH3OSOT.js.map} +0 -0
- /package/dist/{recorder-HKFFHQES.js.map → embed/index.js.map} +0 -0
package/dist/react/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes } from 'react';
|
|
3
|
-
import { V as VectorEffect$1 } from '../types-DUOMxZaq.js';
|
|
4
3
|
import { C as ControlValue } from '../controls-Ec6P0Vpy.js';
|
|
5
4
|
import { S as SvgMotion, a as SvgTrigger, C as Clock, b as SvgPlayer } from '../svg-BhRboN9q.js';
|
|
5
|
+
import { E as EffectDefinition, V as VectorEffect$1 } from '../types-DUOMxZaq.js';
|
|
6
|
+
import { EffectSubject } from '../embed/index.js';
|
|
7
|
+
import '../renderer-teaa98RE.js';
|
|
8
|
+
import '../frames-VEcqa40g.js';
|
|
6
9
|
|
|
7
10
|
/** When to leave the still in place of the animation. */
|
|
8
11
|
type ReducedMotion = "user" | "always" | "never";
|
|
@@ -90,4 +93,32 @@ interface VectorEffectProps extends Omit<SvgPlayerViewProps, "motion" | "id"> {
|
|
|
90
93
|
*/
|
|
91
94
|
declare function VectorEffect(props: VectorEffectProps): react.JSX.Element;
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
interface FlairEffectProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
97
|
+
/** A catalog effect, by id or definition: shader or vector. */
|
|
98
|
+
effect: string | EffectDefinition;
|
|
99
|
+
/** What to apply it to: a picture, a video, an SVG, words or a path (see `EffectSubject`). */
|
|
100
|
+
subject?: EffectSubject | readonly EffectSubject[];
|
|
101
|
+
/** A preset by name, under `values`. */
|
|
102
|
+
preset?: string;
|
|
103
|
+
/** Control values over the effect's defaults (and preset). */
|
|
104
|
+
values?: Record<string, ControlValue>;
|
|
105
|
+
/** Start playing at once (default `true`). */
|
|
106
|
+
autoplay?: boolean;
|
|
107
|
+
/** Pause while scrolled out of view (default `true`). */
|
|
108
|
+
pauseWhenHidden?: boolean;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Any catalog effect, shader or vector, applied to a subject: a picture, a
|
|
112
|
+
* video, an SVG, words or a path (see `mountEffect` in
|
|
113
|
+
* `@pixerate/flair/embed`). Fills its element: size it with CSS. A new
|
|
114
|
+
* subject or values update the running effect; a new effect, preset or
|
|
115
|
+
* playback option starts it again. It renders nothing on the server.
|
|
116
|
+
*
|
|
117
|
+
* ```tsx
|
|
118
|
+
* <FlairEffect effect="image-duotone" subject={{ image: "/team.jpg" }} preset="Spotify" style={{ aspectRatio: "16 / 9" }} />
|
|
119
|
+
* <FlairEffect effect="typewriter" subject={{ text: "Hello there" }} />
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
declare function FlairEffect(props: FlairEffectProps): react.JSX.Element;
|
|
123
|
+
|
|
124
|
+
export { FlairEffect, type FlairEffectProps, type ReducedMotion, SvgMotion, SvgPlayer, SvgPlayerView, type SvgPlayerViewProps, SvgTrigger, VectorEffect, type VectorEffectProps };
|
package/dist/react/index.js
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
effectDefaults,
|
|
3
|
-
getEffect,
|
|
4
|
-
renderVectorEffect
|
|
5
|
-
} from "../chunk-OQ4EWZ3B.js";
|
|
6
1
|
import {
|
|
7
2
|
svgFrameMarkup,
|
|
8
3
|
svgInlineLayout,
|
|
9
4
|
svgViewBox
|
|
10
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-STKEKXCK.js";
|
|
6
|
+
import {
|
|
7
|
+
mountEffect
|
|
8
|
+
} from "../chunk-UCZ43ARE.js";
|
|
9
|
+
import "../chunk-H6VDFBIO.js";
|
|
10
|
+
import "../chunk-RDU63CDO.js";
|
|
11
|
+
import {
|
|
12
|
+
effectDefaults,
|
|
13
|
+
getEffect,
|
|
14
|
+
renderVectorEffect
|
|
15
|
+
} from "../chunk-HVXWNGTW.js";
|
|
16
|
+
import "../chunk-EHDJ3CPJ.js";
|
|
17
|
+
import "../chunk-VYOMXE6I.js";
|
|
11
18
|
import {
|
|
12
19
|
SvgPlayer
|
|
13
20
|
} from "../chunk-PFGGPIMT.js";
|
|
14
|
-
import "../chunk-OHW7UG6D.js";
|
|
15
|
-
import "../chunk-EHDJ3CPJ.js";
|
|
16
21
|
import "../chunk-WMZQCUFJ.js";
|
|
17
|
-
import "../chunk-
|
|
22
|
+
import "../chunk-ORAFCHX3.js";
|
|
18
23
|
|
|
19
24
|
// src/react/index.tsx
|
|
20
25
|
import {
|
|
@@ -134,7 +139,47 @@ function VectorEffect(props) {
|
|
|
134
139
|
}
|
|
135
140
|
);
|
|
136
141
|
}
|
|
142
|
+
function FlairEffect(props) {
|
|
143
|
+
const { effect, subject, preset, values, autoplay, pauseWhenHidden, style, ...rest } = props;
|
|
144
|
+
const host = useRef(null);
|
|
145
|
+
const mounted = useRef(void 0);
|
|
146
|
+
const valuesKey = JSON.stringify(values ?? {});
|
|
147
|
+
const applied = useRef({ valuesKey: "" });
|
|
148
|
+
const latest = useRef({ subject, values, valuesKey });
|
|
149
|
+
latest.current = { subject, values, valuesKey };
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
const now = latest.current;
|
|
152
|
+
const m = mountEffect(host.current, effect, {
|
|
153
|
+
...now.subject ? { subject: now.subject } : {},
|
|
154
|
+
...preset ? { preset } : {},
|
|
155
|
+
...now.values ? { values: now.values } : {},
|
|
156
|
+
autoplay: autoplay ?? true,
|
|
157
|
+
pauseWhenHidden: pauseWhenHidden ?? true
|
|
158
|
+
});
|
|
159
|
+
m.element.style.display = "block";
|
|
160
|
+
m.element.style.width = "100%";
|
|
161
|
+
m.element.style.height = "100%";
|
|
162
|
+
mounted.current = m;
|
|
163
|
+
applied.current = { subject: now.subject, valuesKey: now.valuesKey };
|
|
164
|
+
return () => {
|
|
165
|
+
m.dispose();
|
|
166
|
+
mounted.current = void 0;
|
|
167
|
+
};
|
|
168
|
+
}, [effect, preset, autoplay, pauseWhenHidden]);
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!mounted.current || !subject || subject === applied.current.subject) return;
|
|
171
|
+
mounted.current.setSubject(subject);
|
|
172
|
+
applied.current.subject = subject;
|
|
173
|
+
}, [subject]);
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
if (!mounted.current || !values || valuesKey === applied.current.valuesKey) return;
|
|
176
|
+
mounted.current.setValues(values);
|
|
177
|
+
applied.current.valuesKey = valuesKey;
|
|
178
|
+
}, [valuesKey]);
|
|
179
|
+
return /* @__PURE__ */ jsx("div", { ref: host, style: { position: "relative", ...style }, ...rest });
|
|
180
|
+
}
|
|
137
181
|
export {
|
|
182
|
+
FlairEffect,
|
|
138
183
|
SvgPlayerView,
|
|
139
184
|
VectorEffect
|
|
140
185
|
};
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/index.tsx"],"sourcesContent":["/**\n * React components for Flair's vector effects: `<VectorEffect>` plays a\n * catalog effect by id, `<SvgPlayerView>` plays any {@link SvgMotion}.\n *\n * Both render a still of the picture on the server (its last frame, by\n * default), so a page hydrates with the picture in place rather than a blank\n * box that jumps; the live `SvgPlayer` takes over after mount and is disposed\n * on unmount. Under `prefers-reduced-motion: reduce` the still stays.\n *\n * Needs React 18 or later (an optional peer dependency of the package).\n *\n * @packageDocumentation\n */\n\nimport {\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n type CSSProperties,\n type HTMLAttributes,\n} from \"react\";\nimport { getEffect, effectDefaults } from \"../catalog/index.js\";\nimport { renderVectorEffect, type VectorEffect as VectorEffectDefinition } from \"../catalog/types.js\";\nimport type { ControlValue } from \"../shader/controls.js\";\nimport type { Clock } from \"../time/clock.js\";\nimport type { SvgMotion } from \"../vector/motion.js\";\nimport { svgFrameMarkup, svgInlineLayout, svgViewBox } from \"../vector/static.js\";\nimport { SvgPlayer, type SvgTrigger } from \"../vector/svg.js\";\n\n// Layout effects swap the still for the player before paint; on a server neither runs.\nconst useIsomorphicLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\n/** Cap height of a heavy sans, as a share of its font size: what an inline word is framed to. */\nconst CAP_HEIGHT = \"0.72em\";\n\n/** When to leave the still in place of the animation. */\nexport type ReducedMotion = \"user\" | \"always\" | \"never\";\n\nexport interface SvgPlayerViewProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** The picture and its animations. */\n motion: SvgMotion;\n /** Start again at the end (default `true`); `false` plays once and stays on the last frame. */\n loop?: boolean;\n /** Start playing at once (default `true`). */\n autoplay?: boolean;\n /** Playback speed (default 1). */\n speed?: number;\n /** Ms to rest on the last frame before looping (default 600). */\n hold?: number;\n /** Loop length in ms (default: the picture's own, plus `hold`). */\n duration?: number;\n /** Step start times in ms, for pictures that change on steps. */\n steps?: readonly number[];\n /** Plays in answer to the pointer (see `SvgTrigger`). */\n trigger?: SvgTrigger;\n /** Pause while scrolled out of view. */\n pauseWhenHidden?: boolean;\n /**\n * Wait to start until scrolled into view. Default `true` when it plays once\n * (`loop={false}`, no trigger), so a one-shot further down the page does not\n * finish before anyone sees it; `false` plays at mount.\n */\n playOnEnter?: boolean;\n /** Hide the picture while paused or reset. */\n hideWhenPaused?: boolean;\n /** Time source (default animation frames); a `ManualClock` steps frames yourself. */\n clock?: Clock;\n /** Called with the id of the innermost element with an id that is clicked. */\n onPick?: (id: string) => void;\n /** Called with the player once it is made, and `undefined` when it is disposed. */\n onPlayer?: (player: SvgPlayer | undefined) => void;\n /**\n * The still shown before the player starts (server render, hydration) and\n * instead of it under reduced motion: `\"last\"` (default; the rest frame,\n * `\"first\"` for a hover or press trigger), `\"first\"` or a time in ms.\n */\n poster?: \"first\" | \"last\" | number;\n /**\n * `\"user\"` (default) shows the still when the visitor prefers reduced\n * motion, `\"always\"` always does, `\"never\"` always plays.\n */\n reducedMotion?: ReducedMotion;\n /**\n * Size it as a word in a line of text: `display: inline-block` with the\n * viewBox's aspect ratio and `height` 0.72em (the cap height of a heavy\n * sans; pass a CSS length for another). Meant for pictures framed from cap\n * height to baseline, like drip text's `inline`. Otherwise it is a block\n * as wide as its container with the viewBox's aspect ratio.\n */\n inline?: boolean | string;\n /**\n * With `inline`, keep room for what spills past the word (descenders,\n * outlines, glows, drips): a margin of the picture's `data-overhang` (see\n * `svgInlineLayout`), so the lines around it make space instead of being\n * painted over. Default `false`.\n */\n contain?: boolean;\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof matchMedia === \"function\" && matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/** The host's size from the picture's viewBox, so the still and the player take the same room. */\nfunction hostStyle(svg: string, inline: boolean | string | undefined, contain: boolean | undefined, style?: CSSProperties): CSSProperties {\n const box = svgViewBox(svg);\n const aspectRatio = box ? `${box[2]} / ${box[3]}` : undefined;\n const spill = inline && contain ? svgInlineLayout(svg)?.overhang : undefined;\n const base: CSSProperties = inline\n ? {\n display: \"inline-block\",\n height: typeof inline === \"string\" ? inline : CAP_HEIGHT,\n aspectRatio,\n ...(spill && { margin: `${spill.top}em ${spill.right}em ${spill.bottom}em ${spill.left}em` }),\n }\n : { display: \"block\", aspectRatio };\n return { position: \"relative\", ...base, ...style };\n}\n\nconst LAYER: CSSProperties = { position: \"absolute\", inset: 0, display: \"block\" };\n\n/**\n * Plays an {@link SvgMotion}: a still on the server and before mount, then\n * an `SvgPlayer` (remade when the motion or its options change, disposed on\n * unmount). Pass a memoised `motion`: a new object each render restarts it.\n */\nexport function SvgPlayerView(props: SvgPlayerViewProps) {\n const {\n motion,\n loop,\n autoplay,\n speed,\n hold,\n duration,\n steps,\n trigger,\n pauseWhenHidden,\n playOnEnter,\n hideWhenPaused,\n clock,\n onPick,\n onPlayer,\n poster,\n reducedMotion = \"user\",\n inline,\n contain,\n style,\n ...rest\n } = props;\n const still = useRef<HTMLSpanElement>(null);\n const mount = useRef<HTMLSpanElement>(null);\n const player = useRef<SvgPlayer | undefined>(undefined);\n // Callbacks change every render; the player calls the latest without being remade.\n const callbacks = useRef({ onPick, onPlayer });\n callbacks.current = { onPick, onPlayer };\n\n const at = poster ?? (trigger === \"hover\" || trigger === \"press\" ? \"first\" : \"last\");\n const markup = useMemo(() => svgFrameMarkup(motion, { at, steps }) ?? \"\", [motion, at, steps]);\n const stepsKey = steps?.join(\",\");\n // A one-shot waits until it is seen.\n const enter = playOnEnter ?? (loop === false && !trigger);\n\n useIsomorphicLayoutEffect(() => {\n const host = mount.current;\n if (!host) return;\n if (reducedMotion === \"always\" || (reducedMotion === \"user\" && prefersReducedMotion())) return;\n const p = new SvgPlayer(host, motion, {\n loop,\n autoplay,\n speed,\n hold,\n duration,\n steps,\n trigger,\n pauseWhenHidden,\n playOnEnter: enter,\n hideWhenPaused,\n clock,\n onPick: (id) => callbacks.current.onPick?.(id),\n });\n player.current = p;\n // Set directly, not through props, so React leaves it be on later renders.\n if (still.current) still.current.style.display = \"none\";\n callbacks.current.onPlayer?.(p);\n return () => {\n p.dispose();\n player.current = undefined;\n if (still.current) still.current.style.display = \"block\";\n callbacks.current.onPlayer?.(undefined);\n };\n // `speed` is applied below without remaking; `steps` by value.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [motion, loop, autoplay, hold, duration, stepsKey, trigger, pauseWhenHidden, enter, hideWhenPaused, clock, reducedMotion]);\n\n useEffect(() => {\n player.current?.setSpeed(speed ?? 1);\n }, [speed]);\n\n return (\n <span {...rest} style={hostStyle(motion.svg, inline, contain, style)}>\n <span ref={still} aria-hidden=\"true\" style={LAYER} dangerouslySetInnerHTML={{ __html: markup }} />\n <span ref={mount} style={LAYER} />\n </span>\n );\n}\n\nexport interface VectorEffectProps extends Omit<SvgPlayerViewProps, \"motion\" | \"id\"> {\n /** A vector effect's catalog id (`\"drip-text\"`), or the effect itself. */\n id: string | VectorEffectDefinition;\n /** Control values; missing ones take the preset's, then the defaults. */\n values?: Record<string, ControlValue>;\n /** A preset's name to start from. */\n preset?: string;\n /** The host element's own `id`. */\n elementId?: string;\n}\n\n/**\n * Plays a catalog vector effect: `<VectorEffect id=\"drip-text\" values={{ word: \"Slop\" }} loop={false} />`.\n * Its `hold` and `trigger` are used unless given. With an `inline` control\n * set (drip text's), it is sized as a word in the line (see `inline`).\n * Throws when `id` is not a vector effect.\n */\nexport function VectorEffect(props: VectorEffectProps) {\n const { id, values, preset, elementId, ...rest } = props;\n const effect = typeof id === \"string\" ? getEffect(id) : id;\n if (!effect || effect.kind !== \"vector\")\n throw new Error(`\"${typeof id === \"string\" ? id : effect?.id}\" is not a vector effect; pick one from findEffects({ kind: \"vector\" })`);\n const valuesKey = JSON.stringify(values ?? {});\n const motion = useMemo(\n () => renderVectorEffect(effect, effectDefaults(effect, { preset, values })),\n // Values by content, so an inline object literal does not restart it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [effect, preset, valuesKey],\n );\n return (\n <SvgPlayerView\n id={elementId}\n motion={motion}\n hold={effect.hold}\n trigger={effect.trigger}\n inline={values?.inline === true}\n {...rest}\n />\n );\n}\n\nexport type { SvgPlayer, SvgMotion, SvgTrigger };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/index.tsx"],"sourcesContent":["/**\n * React components for Flair: `<FlairEffect>` runs any catalog effect (shader\n * or vector) applied to a picture, video, SVG or words; `<VectorEffect>` plays\n * a catalog vector effect by id, `<SvgPlayerView>` plays any {@link SvgMotion}.\n *\n * Both render a still of the picture on the server (its last frame, by\n * default), so a page hydrates with the picture in place rather than a blank\n * box that jumps; the live `SvgPlayer` takes over after mount and is disposed\n * on unmount. Under `prefers-reduced-motion: reduce` the still stays.\n *\n * Needs React 18 or later (an optional peer dependency of the package).\n *\n * @packageDocumentation\n */\n\nimport {\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n type CSSProperties,\n type HTMLAttributes,\n} from \"react\";\nimport { getEffect, effectDefaults, type EffectDefinition } from \"../catalog/index.js\";\nimport { mountEffect, type EffectSubject, type MountedEffect } from \"../embed/index.js\";\nimport { renderVectorEffect, type VectorEffect as VectorEffectDefinition } from \"../catalog/types.js\";\nimport type { ControlValue } from \"../shader/controls.js\";\nimport type { Clock } from \"../time/clock.js\";\nimport type { SvgMotion } from \"../vector/motion.js\";\nimport { svgFrameMarkup, svgInlineLayout, svgViewBox } from \"../vector/static.js\";\nimport { SvgPlayer, type SvgTrigger } from \"../vector/svg.js\";\n\n// Layout effects swap the still for the player before paint; on a server neither runs.\nconst useIsomorphicLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\n/** Cap height of a heavy sans, as a share of its font size: what an inline word is framed to. */\nconst CAP_HEIGHT = \"0.72em\";\n\n/** When to leave the still in place of the animation. */\nexport type ReducedMotion = \"user\" | \"always\" | \"never\";\n\nexport interface SvgPlayerViewProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** The picture and its animations. */\n motion: SvgMotion;\n /** Start again at the end (default `true`); `false` plays once and stays on the last frame. */\n loop?: boolean;\n /** Start playing at once (default `true`). */\n autoplay?: boolean;\n /** Playback speed (default 1). */\n speed?: number;\n /** Ms to rest on the last frame before looping (default 600). */\n hold?: number;\n /** Loop length in ms (default: the picture's own, plus `hold`). */\n duration?: number;\n /** Step start times in ms, for pictures that change on steps. */\n steps?: readonly number[];\n /** Plays in answer to the pointer (see `SvgTrigger`). */\n trigger?: SvgTrigger;\n /** Pause while scrolled out of view. */\n pauseWhenHidden?: boolean;\n /**\n * Wait to start until scrolled into view. Default `true` when it plays once\n * (`loop={false}`, no trigger), so a one-shot further down the page does not\n * finish before anyone sees it; `false` plays at mount.\n */\n playOnEnter?: boolean;\n /** Hide the picture while paused or reset. */\n hideWhenPaused?: boolean;\n /** Time source (default animation frames); a `ManualClock` steps frames yourself. */\n clock?: Clock;\n /** Called with the id of the innermost element with an id that is clicked. */\n onPick?: (id: string) => void;\n /** Called with the player once it is made, and `undefined` when it is disposed. */\n onPlayer?: (player: SvgPlayer | undefined) => void;\n /**\n * The still shown before the player starts (server render, hydration) and\n * instead of it under reduced motion: `\"last\"` (default; the rest frame,\n * `\"first\"` for a hover or press trigger), `\"first\"` or a time in ms.\n */\n poster?: \"first\" | \"last\" | number;\n /**\n * `\"user\"` (default) shows the still when the visitor prefers reduced\n * motion, `\"always\"` always does, `\"never\"` always plays.\n */\n reducedMotion?: ReducedMotion;\n /**\n * Size it as a word in a line of text: `display: inline-block` with the\n * viewBox's aspect ratio and `height` 0.72em (the cap height of a heavy\n * sans; pass a CSS length for another). Meant for pictures framed from cap\n * height to baseline, like drip text's `inline`. Otherwise it is a block\n * as wide as its container with the viewBox's aspect ratio.\n */\n inline?: boolean | string;\n /**\n * With `inline`, keep room for what spills past the word (descenders,\n * outlines, glows, drips): a margin of the picture's `data-overhang` (see\n * `svgInlineLayout`), so the lines around it make space instead of being\n * painted over. Default `false`.\n */\n contain?: boolean;\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof matchMedia === \"function\" && matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/** The host's size from the picture's viewBox, so the still and the player take the same room. */\nfunction hostStyle(svg: string, inline: boolean | string | undefined, contain: boolean | undefined, style?: CSSProperties): CSSProperties {\n const box = svgViewBox(svg);\n const aspectRatio = box ? `${box[2]} / ${box[3]}` : undefined;\n const spill = inline && contain ? svgInlineLayout(svg)?.overhang : undefined;\n const base: CSSProperties = inline\n ? {\n display: \"inline-block\",\n height: typeof inline === \"string\" ? inline : CAP_HEIGHT,\n aspectRatio,\n ...(spill && { margin: `${spill.top}em ${spill.right}em ${spill.bottom}em ${spill.left}em` }),\n }\n : { display: \"block\", aspectRatio };\n return { position: \"relative\", ...base, ...style };\n}\n\nconst LAYER: CSSProperties = { position: \"absolute\", inset: 0, display: \"block\" };\n\n/**\n * Plays an {@link SvgMotion}: a still on the server and before mount, then\n * an `SvgPlayer` (remade when the motion or its options change, disposed on\n * unmount). Pass a memoised `motion`: a new object each render restarts it.\n */\nexport function SvgPlayerView(props: SvgPlayerViewProps) {\n const {\n motion,\n loop,\n autoplay,\n speed,\n hold,\n duration,\n steps,\n trigger,\n pauseWhenHidden,\n playOnEnter,\n hideWhenPaused,\n clock,\n onPick,\n onPlayer,\n poster,\n reducedMotion = \"user\",\n inline,\n contain,\n style,\n ...rest\n } = props;\n const still = useRef<HTMLSpanElement>(null);\n const mount = useRef<HTMLSpanElement>(null);\n const player = useRef<SvgPlayer | undefined>(undefined);\n // Callbacks change every render; the player calls the latest without being remade.\n const callbacks = useRef({ onPick, onPlayer });\n callbacks.current = { onPick, onPlayer };\n\n const at = poster ?? (trigger === \"hover\" || trigger === \"press\" ? \"first\" : \"last\");\n const markup = useMemo(() => svgFrameMarkup(motion, { at, steps }) ?? \"\", [motion, at, steps]);\n const stepsKey = steps?.join(\",\");\n // A one-shot waits until it is seen.\n const enter = playOnEnter ?? (loop === false && !trigger);\n\n useIsomorphicLayoutEffect(() => {\n const host = mount.current;\n if (!host) return;\n if (reducedMotion === \"always\" || (reducedMotion === \"user\" && prefersReducedMotion())) return;\n const p = new SvgPlayer(host, motion, {\n loop,\n autoplay,\n speed,\n hold,\n duration,\n steps,\n trigger,\n pauseWhenHidden,\n playOnEnter: enter,\n hideWhenPaused,\n clock,\n onPick: (id) => callbacks.current.onPick?.(id),\n });\n player.current = p;\n // Set directly, not through props, so React leaves it be on later renders.\n if (still.current) still.current.style.display = \"none\";\n callbacks.current.onPlayer?.(p);\n return () => {\n p.dispose();\n player.current = undefined;\n if (still.current) still.current.style.display = \"block\";\n callbacks.current.onPlayer?.(undefined);\n };\n // `speed` is applied below without remaking; `steps` by value.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [motion, loop, autoplay, hold, duration, stepsKey, trigger, pauseWhenHidden, enter, hideWhenPaused, clock, reducedMotion]);\n\n useEffect(() => {\n player.current?.setSpeed(speed ?? 1);\n }, [speed]);\n\n return (\n <span {...rest} style={hostStyle(motion.svg, inline, contain, style)}>\n <span ref={still} aria-hidden=\"true\" style={LAYER} dangerouslySetInnerHTML={{ __html: markup }} />\n <span ref={mount} style={LAYER} />\n </span>\n );\n}\n\nexport interface VectorEffectProps extends Omit<SvgPlayerViewProps, \"motion\" | \"id\"> {\n /** A vector effect's catalog id (`\"drip-text\"`), or the effect itself. */\n id: string | VectorEffectDefinition;\n /** Control values; missing ones take the preset's, then the defaults. */\n values?: Record<string, ControlValue>;\n /** A preset's name to start from. */\n preset?: string;\n /** The host element's own `id`. */\n elementId?: string;\n}\n\n/**\n * Plays a catalog vector effect: `<VectorEffect id=\"drip-text\" values={{ word: \"Slop\" }} loop={false} />`.\n * Its `hold` and `trigger` are used unless given. With an `inline` control\n * set (drip text's), it is sized as a word in the line (see `inline`).\n * Throws when `id` is not a vector effect.\n */\nexport function VectorEffect(props: VectorEffectProps) {\n const { id, values, preset, elementId, ...rest } = props;\n const effect = typeof id === \"string\" ? getEffect(id) : id;\n if (!effect || effect.kind !== \"vector\")\n throw new Error(`\"${typeof id === \"string\" ? id : effect?.id}\" is not a vector effect; pick one from findEffects({ kind: \"vector\" })`);\n const valuesKey = JSON.stringify(values ?? {});\n const motion = useMemo(\n () => renderVectorEffect(effect, effectDefaults(effect, { preset, values })),\n // Values by content, so an inline object literal does not restart it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [effect, preset, valuesKey],\n );\n return (\n <SvgPlayerView\n id={elementId}\n motion={motion}\n hold={effect.hold}\n trigger={effect.trigger}\n inline={values?.inline === true}\n {...rest}\n />\n );\n}\n\nexport type { SvgPlayer, SvgMotion, SvgTrigger };\n\nexport interface FlairEffectProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** A catalog effect, by id or definition: shader or vector. */\n effect: string | EffectDefinition;\n /** What to apply it to: a picture, a video, an SVG, words or a path (see `EffectSubject`). */\n subject?: EffectSubject | readonly EffectSubject[];\n /** A preset by name, under `values`. */\n preset?: string;\n /** Control values over the effect's defaults (and preset). */\n values?: Record<string, ControlValue>;\n /** Start playing at once (default `true`). */\n autoplay?: boolean;\n /** Pause while scrolled out of view (default `true`). */\n pauseWhenHidden?: boolean;\n}\n\n/**\n * Any catalog effect, shader or vector, applied to a subject: a picture, a\n * video, an SVG, words or a path (see `mountEffect` in\n * `@pixerate/flair/embed`). Fills its element: size it with CSS. A new\n * subject or values update the running effect; a new effect, preset or\n * playback option starts it again. It renders nothing on the server.\n *\n * ```tsx\n * <FlairEffect effect=\"image-duotone\" subject={{ image: \"/team.jpg\" }} preset=\"Spotify\" style={{ aspectRatio: \"16 / 9\" }} />\n * <FlairEffect effect=\"typewriter\" subject={{ text: \"Hello there\" }} />\n * ```\n */\nexport function FlairEffect(props: FlairEffectProps) {\n const { effect, subject, preset, values, autoplay, pauseWhenHidden, style, ...rest } = props;\n const host = useRef<HTMLDivElement>(null);\n const mounted = useRef<MountedEffect | undefined>(undefined);\n const valuesKey = JSON.stringify(values ?? {});\n // What the running effect last took, so a re-render with the same subject or values changes nothing.\n const applied = useRef<{ subject?: FlairEffectProps[\"subject\"]; valuesKey: string }>({ valuesKey: \"\" });\n const latest = useRef({ subject, values, valuesKey });\n latest.current = { subject, values, valuesKey };\n useEffect(() => {\n const now = latest.current;\n const m = mountEffect(host.current!, effect, {\n ...(now.subject ? { subject: now.subject } : {}),\n ...(preset ? { preset } : {}),\n ...(now.values ? { values: now.values } : {}),\n autoplay: autoplay ?? true,\n pauseWhenHidden: pauseWhenHidden ?? true,\n });\n m.element.style.display = \"block\";\n m.element.style.width = \"100%\";\n m.element.style.height = \"100%\";\n mounted.current = m;\n applied.current = { subject: now.subject, valuesKey: now.valuesKey };\n return () => {\n m.dispose();\n mounted.current = undefined;\n };\n }, [effect, preset, autoplay, pauseWhenHidden]);\n useEffect(() => {\n if (!mounted.current || !subject || subject === applied.current.subject) return;\n mounted.current.setSubject(subject);\n applied.current.subject = subject;\n }, [subject]);\n useEffect(() => {\n if (!mounted.current || !values || valuesKey === applied.current.valuesKey) return;\n mounted.current.setValues(values);\n applied.current.valuesKey = valuesKey;\n }, [valuesKey]);\n return <div ref={host} style={{ position: \"relative\", ...style }} {...rest} />;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
exportMotionGraphic,
|
|
3
|
+
ffmpegPath,
|
|
4
|
+
findChrome,
|
|
5
|
+
fragmentSource,
|
|
6
|
+
frameStates,
|
|
7
|
+
imageDataUrl,
|
|
8
|
+
pageControls,
|
|
9
|
+
planOutput,
|
|
10
|
+
renderPageHtml,
|
|
11
|
+
runRender,
|
|
12
|
+
scriptedPointer,
|
|
13
|
+
sequencePath
|
|
14
|
+
} from "./chunk-JL6TI6II.js";
|
|
15
|
+
import "./chunk-RDU63CDO.js";
|
|
16
|
+
import "./chunk-VYOMXE6I.js";
|
|
17
|
+
export {
|
|
18
|
+
exportMotionGraphic,
|
|
19
|
+
ffmpegPath,
|
|
20
|
+
findChrome,
|
|
21
|
+
fragmentSource,
|
|
22
|
+
frameStates,
|
|
23
|
+
imageDataUrl,
|
|
24
|
+
pageControls,
|
|
25
|
+
planOutput,
|
|
26
|
+
renderPageHtml,
|
|
27
|
+
runRender,
|
|
28
|
+
scriptedPointer,
|
|
29
|
+
sequencePath
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=recorder-CDPPTJMG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -390,4 +390,4 @@ declare class ShaderRenderer {
|
|
|
390
390
|
private onRestored;
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
export { BUILTIN_UNIFORMS as B, type CompileError as C, type FrameState as F, ImageLoadError as I, type LiveSource as L, type RendererStats as R,
|
|
393
|
+
export { BUILTIN_UNIFORMS as B, type CompileError as C, type FrameState as F, ImageLoadError as I, type LiveSource as L, type RendererStats as R, ShaderRenderer as S, TextureCache as T, VERTEX_SOURCE as V, type CompileStatus as a, type CompileResult as b, type CompiledShader as c, SVG_EDGE as d, ShaderCompileError as e, type ShaderRendererOptions as f, type TextureSource as g, applyTextureSettings as h, compileShader as i, createContext as j, drawFrame as k, formatCompileError as l, isSvgUrl as m, loadImage as n, preloadImages as o, parseCompileLog as p, resetGlCaches as q, releaseImages as r, seekVideo as s, sizeSvg as t, wrapSource as w };
|
package/dist/svelte/index.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { ActionReturn } from 'svelte/action';
|
|
2
|
-
import { V as VectorEffect } from '../types-DUOMxZaq.js';
|
|
3
2
|
import { C as ControlValue } from '../controls-Ec6P0Vpy.js';
|
|
4
3
|
import { a as SvgTrigger, C as Clock, b as SvgPlayer, S as SvgMotion } from '../svg-BhRboN9q.js';
|
|
4
|
+
import { E as EffectDefinition, V as VectorEffect } from '../types-DUOMxZaq.js';
|
|
5
|
+
import { EffectSubject } from '../embed/index.js';
|
|
6
|
+
import '../renderer-teaa98RE.js';
|
|
7
|
+
import '../frames-VEcqa40g.js';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
|
-
* Svelte 5 bindings for Flair
|
|
8
|
-
*
|
|
10
|
+
* Svelte 5 bindings for Flair, written as plain TypeScript so they need no
|
|
11
|
+
* Svelte compiler: the `flairEffect` action runs any catalog effect (shader or
|
|
12
|
+
* vector) applied to a picture, video, SVG or words; the `vectorEffect` action plays a catalog
|
|
9
13
|
* effect (or any {@link SvgMotion}) in an element, and `vectorEffectStill`
|
|
10
14
|
* gives the markup and style of its still for server rendering.
|
|
11
15
|
*
|
|
@@ -143,4 +147,29 @@ declare function vectorEffectStill(params: VectorEffectParams): VectorEffectStil
|
|
|
143
147
|
*/
|
|
144
148
|
declare function vectorEffect(node: HTMLElement, initial: VectorEffectParams): ActionReturn<VectorEffectParams>;
|
|
145
149
|
|
|
146
|
-
|
|
150
|
+
/** What the `flairEffect` action runs: any catalog effect, applied to a subject. */
|
|
151
|
+
interface FlairEffectParams {
|
|
152
|
+
/** A catalog effect, by id or definition: shader or vector. */
|
|
153
|
+
effect: string | EffectDefinition;
|
|
154
|
+
/** What to apply it to: a picture, a video, an SVG, words or a path (see `EffectSubject`). */
|
|
155
|
+
subject?: EffectSubject | readonly EffectSubject[];
|
|
156
|
+
preset?: string;
|
|
157
|
+
values?: Record<string, ControlValue>;
|
|
158
|
+
/** Start playing at once (default `true`). */
|
|
159
|
+
autoplay?: boolean;
|
|
160
|
+
/** Pause while scrolled out of view (default `true`). */
|
|
161
|
+
pauseWhenHidden?: boolean;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Runs any catalog effect, shader or vector, in an element, applied to a
|
|
165
|
+
* subject (see `mountEffect` in `@pixerate/flair/embed`); it fills the
|
|
166
|
+
* element, so size it with CSS. A new subject or values update the running
|
|
167
|
+
* effect; a new effect, preset or playback option starts it again.
|
|
168
|
+
*
|
|
169
|
+
* ```svelte
|
|
170
|
+
* <div use:flairEffect={{ effect: "image-duotone", subject: { image: "/team.jpg" } }} style="aspect-ratio: 16 / 9"></div>
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare function flairEffect(node: HTMLElement, initial: FlairEffectParams): ActionReturn<FlairEffectParams>;
|
|
174
|
+
|
|
175
|
+
export { type FlairEffectParams, type ReducedMotion, SvgMotion, type SvgMotionParams, SvgPlayer, type SvgPlayerParams, SvgTrigger, type VectorEffectByIdParams, type VectorEffectParams, type VectorEffectStill, flairEffect, vectorEffect, vectorEffectStill };
|
package/dist/svelte/index.js
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
effectDefaults,
|
|
3
|
-
getEffect,
|
|
4
|
-
renderVectorEffect
|
|
5
|
-
} from "../chunk-OQ4EWZ3B.js";
|
|
6
1
|
import {
|
|
7
2
|
svgFrameMarkup,
|
|
8
3
|
svgInlineLayout,
|
|
9
4
|
svgViewBox
|
|
10
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-STKEKXCK.js";
|
|
6
|
+
import {
|
|
7
|
+
mountEffect
|
|
8
|
+
} from "../chunk-UCZ43ARE.js";
|
|
9
|
+
import "../chunk-H6VDFBIO.js";
|
|
10
|
+
import "../chunk-RDU63CDO.js";
|
|
11
|
+
import {
|
|
12
|
+
effectDefaults,
|
|
13
|
+
getEffect,
|
|
14
|
+
renderVectorEffect
|
|
15
|
+
} from "../chunk-HVXWNGTW.js";
|
|
16
|
+
import "../chunk-EHDJ3CPJ.js";
|
|
17
|
+
import "../chunk-VYOMXE6I.js";
|
|
11
18
|
import {
|
|
12
19
|
SvgPlayer
|
|
13
20
|
} from "../chunk-PFGGPIMT.js";
|
|
14
|
-
import "../chunk-OHW7UG6D.js";
|
|
15
|
-
import "../chunk-EHDJ3CPJ.js";
|
|
16
21
|
import "../chunk-WMZQCUFJ.js";
|
|
17
|
-
import "../chunk-
|
|
22
|
+
import "../chunk-ORAFCHX3.js";
|
|
18
23
|
|
|
19
24
|
// src/svelte/index.ts
|
|
20
25
|
var CAP_HEIGHT = "0.72em";
|
|
@@ -188,7 +193,44 @@ function vectorEffect(node, initial) {
|
|
|
188
193
|
}
|
|
189
194
|
};
|
|
190
195
|
}
|
|
196
|
+
function flairEffect(node, initial) {
|
|
197
|
+
let params = initial;
|
|
198
|
+
if (!node.style.position) node.style.position = "relative";
|
|
199
|
+
const start = () => {
|
|
200
|
+
const m = mountEffect(node, params.effect, {
|
|
201
|
+
...params.subject ? { subject: params.subject } : {},
|
|
202
|
+
...params.preset ? { preset: params.preset } : {},
|
|
203
|
+
...params.values ? { values: params.values } : {},
|
|
204
|
+
autoplay: params.autoplay ?? true,
|
|
205
|
+
pauseWhenHidden: params.pauseWhenHidden ?? true
|
|
206
|
+
});
|
|
207
|
+
m.element.style.display = "block";
|
|
208
|
+
m.element.style.width = "100%";
|
|
209
|
+
m.element.style.height = "100%";
|
|
210
|
+
return m;
|
|
211
|
+
};
|
|
212
|
+
let mounted = start();
|
|
213
|
+
return {
|
|
214
|
+
update(next) {
|
|
215
|
+
const restart = next.effect !== params.effect || next.preset !== params.preset || next.autoplay !== params.autoplay || next.pauseWhenHidden !== params.pauseWhenHidden;
|
|
216
|
+
const subjectChanged = next.subject !== params.subject;
|
|
217
|
+
const valuesChanged = JSON.stringify(next.values ?? {}) !== JSON.stringify(params.values ?? {});
|
|
218
|
+
params = next;
|
|
219
|
+
if (restart) {
|
|
220
|
+
mounted.dispose();
|
|
221
|
+
mounted = start();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (subjectChanged && next.subject) mounted.setSubject(next.subject);
|
|
225
|
+
if (valuesChanged && next.values) mounted.setValues(next.values);
|
|
226
|
+
},
|
|
227
|
+
destroy() {
|
|
228
|
+
mounted.dispose();
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
191
232
|
export {
|
|
233
|
+
flairEffect,
|
|
192
234
|
vectorEffect,
|
|
193
235
|
vectorEffectStill
|
|
194
236
|
};
|
package/dist/svelte/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/svelte/index.ts"],"sourcesContent":["/**\n * Svelte 5 bindings for Flair's vector effects, written as plain TypeScript so\n * they need no Svelte compiler: the `vectorEffect` action plays a catalog\n * effect (or any {@link SvgMotion}) in an element, and `vectorEffectStill`\n * gives the markup and style of its still for server rendering.\n *\n * ```svelte\n * <script>\n * import { vectorEffect, vectorEffectStill } from \"@pixerate/flair/svelte\";\n * const params = { id: \"drip-text\", values: { word: \"Slop\" }, loop: false };\n * const still = vectorEffectStill(params);\n * </script>\n *\n * <span use:vectorEffect={params} style={still.style}>{@html still.markup}</span>\n * ```\n *\n * The still is in place from the first paint; the live `SvgPlayer` takes over\n * after mount and is disposed on destroy. Under `prefers-reduced-motion:\n * reduce` the still stays.\n *\n * Needs Svelte 5 (an optional peer dependency of the package); only its types\n * are imported.\n *\n * @packageDocumentation\n */\n\nimport type { ActionReturn } from \"svelte/action\";\nimport { getEffect, effectDefaults } from \"../catalog/index.js\";\nimport { renderVectorEffect, type VectorEffect as VectorEffectDefinition } from \"../catalog/types.js\";\nimport type { ControlValue } from \"../shader/controls.js\";\nimport type { Clock } from \"../time/clock.js\";\nimport type { SvgMotion } from \"../vector/motion.js\";\nimport { svgFrameMarkup, svgInlineLayout, svgViewBox } from \"../vector/static.js\";\nimport { SvgPlayer, type SvgTrigger } from \"../vector/svg.js\";\n\n/** Cap height of a heavy sans, as a share of its font size: what an inline word is framed to. */\nconst CAP_HEIGHT = \"0.72em\";\n\n/** Marks the still's layer, so the action can find it (and hide it while the player runs). */\nconst STILL_ATTR = \"data-flair-still\";\n\nconst LAYER = \"position:absolute;inset:0;display:block\";\n\n/** When to leave the still in place of the animation. */\nexport type ReducedMotion = \"user\" | \"always\" | \"never\";\n\n/** Options shared by an effect by id and a motion of your own. */\nexport interface SvgPlayerParams {\n /** Start again at the end (default `true`); `false` plays once and stays on the last frame. */\n loop?: boolean;\n /** Start playing at once (default `true`). */\n autoplay?: boolean;\n /** Playback speed (default 1); changed without remaking the player. */\n speed?: number;\n /** Ms to rest on the last frame before looping (default 600, or the effect's). */\n hold?: number;\n /** Loop length in ms (default: the picture's own, plus `hold`). */\n duration?: number;\n /** Step start times in ms, for pictures that change on steps. */\n steps?: readonly number[];\n /** Plays in answer to the pointer (see `SvgTrigger`; default the effect's). */\n trigger?: SvgTrigger;\n /** Pause while scrolled out of view. */\n pauseWhenHidden?: boolean;\n /**\n * Wait to start until scrolled into view. Default `true` when it plays once\n * (`loop: false`, no trigger), so a one-shot further down the page does not\n * finish before anyone sees it; `false` plays at mount.\n */\n playOnEnter?: boolean;\n /** Hide the picture while paused or reset. */\n hideWhenPaused?: boolean;\n /** Time source (default animation frames); a `ManualClock` steps frames yourself. */\n clock?: Clock;\n /** Called with the id of the innermost element with an id that is clicked. */\n onPick?: (id: string) => void;\n /** Called with the player once it is made, and `undefined` when it is disposed. */\n onPlayer?: (player: SvgPlayer | undefined) => void;\n /**\n * The still shown before the player starts and instead of it under reduced\n * motion: `\"last\"` (default; the rest frame, `\"first\"` for a hover or press\n * trigger), `\"first\"` or a time in ms.\n */\n poster?: \"first\" | \"last\" | number;\n /**\n * `\"user\"` (default) shows the still when the visitor prefers reduced\n * motion, `\"always\"` always does, `\"never\"` always plays.\n */\n reducedMotion?: ReducedMotion;\n /**\n * Size it as a word in a line of text: `display: inline-block` with the\n * viewBox's aspect ratio and `height` 0.72em (the cap height of a heavy\n * sans; pass a CSS length for another). Default: the effect's `inline`\n * control. Otherwise it is a block as wide as its container with the\n * viewBox's aspect ratio.\n */\n inline?: boolean | string;\n /**\n * With `inline`, keep room for what spills past the word (descenders,\n * outlines, glows, drips): a margin of the picture's `data-overhang` (see\n * `svgInlineLayout`), so the lines around it make space instead of being\n * painted over. Default `false`.\n */\n contain?: boolean;\n}\n\n/** A catalog vector effect by id (or the effect itself), with its values. */\nexport interface VectorEffectByIdParams extends SvgPlayerParams {\n /** A vector effect's catalog id (`\"drip-text\"`), or the effect itself. */\n id: string | VectorEffectDefinition;\n /** Control values; missing ones take the preset's, then the defaults. Compared by content. */\n values?: Record<string, ControlValue>;\n /** A preset's name to start from. */\n preset?: string;\n motion?: never;\n}\n\n/** Any {@link SvgMotion}; a new object restarts the player. */\nexport interface SvgMotionParams extends SvgPlayerParams {\n /** The picture and its animations. */\n motion: SvgMotion;\n id?: never;\n values?: never;\n preset?: never;\n}\n\n/** What `vectorEffect` and `vectorEffectStill` take: an effect by `id`, or a `motion`. */\nexport type VectorEffectParams = VectorEffectByIdParams | SvgMotionParams;\n\n/** A still of the picture, for `{@html markup}` inside an element with `style`. */\nexport interface VectorEffectStill {\n /** The still's layer: safe `<svg>` markup (see `svgFrameMarkup`) in an absolutely placed `<span>`. */\n markup: string;\n /** The host's inline style: its position and size from the viewBox. */\n style: string;\n}\n\ninterface Resolved {\n motion: SvgMotion;\n hold?: number;\n trigger?: SvgTrigger;\n inline?: boolean | string;\n contain?: boolean;\n}\n\n/** Remembers the last motion made from an effect, so values compared by content do not remake it. */\ntype MotionCache = { key: string; effect: VectorEffectDefinition; motion: SvgMotion };\n\nfunction resolve(params: VectorEffectParams, cache?: { current?: MotionCache }): Resolved {\n if (params.motion) return { motion: params.motion, hold: params.hold, trigger: params.trigger, inline: params.inline, contain: params.contain };\n const { id, values, preset } = params as VectorEffectByIdParams;\n const effect = typeof id === \"string\" ? getEffect(id) : id;\n if (!effect || effect.kind !== \"vector\")\n throw new Error(\n `\"${typeof id === \"string\" ? id : (effect?.id ?? id)}\" is not a vector effect; pick one from findEffects({ kind: \"vector\" }), or pass a motion`,\n );\n const key = JSON.stringify([preset ?? null, values ?? {}]);\n let motion: SvgMotion;\n if (cache?.current && cache.current.effect === effect && cache.current.key === key) motion = cache.current.motion;\n else {\n motion = renderVectorEffect(effect, effectDefaults(effect, { preset, values }));\n if (cache) cache.current = { key, effect, motion };\n }\n return {\n motion,\n hold: params.hold ?? effect.hold,\n trigger: params.trigger ?? effect.trigger,\n inline: params.inline ?? values?.inline === true,\n contain: params.contain,\n };\n}\n\n/** The host's sizing from the picture's viewBox, so the still and the player take the same room. */\nfunction hostStyle(svg: string, inline: boolean | string | undefined, contain?: boolean): [string, string][] {\n const box = svgViewBox(svg);\n const style: [string, string][] = [\n [\"position\", \"relative\"],\n [\"display\", inline ? \"inline-block\" : \"block\"],\n ];\n if (inline) style.push([\"height\", typeof inline === \"string\" ? inline : CAP_HEIGHT]);\n if (box) style.push([\"aspect-ratio\", `${box[2]} / ${box[3]}`]);\n const spill = inline && contain ? svgInlineLayout(svg)?.overhang : undefined;\n if (spill) style.push([\"margin\", `${spill.top}em ${spill.right}em ${spill.bottom}em ${spill.left}em`]);\n return style;\n}\n\n/** Whether to wait until scrolled into view: as asked, else when it plays once. */\nconst enters = (r: Resolved, p: SvgPlayerParams) => p.playOnEnter ?? (p.loop === false && !r.trigger);\n\nfunction stillMarkup(r: Resolved, params: SvgPlayerParams): string {\n const at = params.poster ?? (r.trigger === \"hover\" || r.trigger === \"press\" ? \"first\" : \"last\");\n return svgFrameMarkup(r.motion, { at, steps: params.steps }) ?? \"\";\n}\n\n/**\n * The still of an effect or motion, for server rendering: put `markup` in the\n * element that has the `vectorEffect` action, with `style` as its style, so\n * the page shows the picture before the player starts (and instead of it\n * under reduced motion), in the room the player will take.\n * Throws when `id` is not a vector effect.\n */\nexport function vectorEffectStill(params: VectorEffectParams): VectorEffectStill {\n const r = resolve(params);\n return {\n markup: `<span ${STILL_ATTR} aria-hidden=\"true\" style=\"${LAYER}\">${stillMarkup(r, params)}</span>`,\n style: hostStyle(r.motion.svg, r.inline, r.contain)\n .map(([k, v]) => `${k}: ${v}`)\n .join(\"; \"),\n };\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof matchMedia === \"function\" && matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/** The options whose change remakes the player (`speed` is set on it instead). */\nfunction playerKey(r: Resolved, p: SvgPlayerParams): unknown[] {\n return [\n r.motion,\n p.loop,\n p.autoplay,\n r.hold,\n p.duration,\n p.steps?.join(\",\"),\n r.trigger,\n p.pauseWhenHidden,\n enters(r, p),\n p.hideWhenPaused,\n p.clock,\n p.reducedMotion ?? \"user\",\n ];\n}\n\n/**\n * A Svelte action that plays a vector effect in its element:\n * `<span use:vectorEffect={{ id: \"drip-text\", values: { word: \"Slop\" }, loop: false }} />`.\n *\n * It makes an `SvgPlayer` in a layer of its own, remakes it when the params\n * change (values by content; `speed` without remaking) and disposes it on\n * destroy. A still from {@link vectorEffectStill} in the element is hidden\n * while the player runs and shown again after; without one, the action makes\n * its own (so reduced motion still shows the picture) and sizes the element\n * from the viewBox, leaving alone any of `position`, `display`, `height`,\n * `aspect-ratio` and `margin` the element's style already sets.\n *\n * For an attachment, `{@attach fromAction(vectorEffect, () => params)}`\n * (`fromAction` is from `svelte/attachments`). Throws when `id` is not a\n * vector effect.\n */\nexport function vectorEffect(node: HTMLElement, initial: VectorEffectParams): ActionReturn<VectorEffectParams> {\n const cache: { current?: MotionCache } = {};\n const doc = node.ownerDocument;\n const mount = doc.createElement(\"span\");\n mount.style.cssText = LAYER;\n node.appendChild(mount);\n\n let params = initial;\n let resolved = resolve(params, cache);\n let player: SvgPlayer | undefined;\n let key: unknown[] = [];\n /** The still the action made itself, when the element had none. */\n let ownStill: HTMLElement | undefined;\n /** Sizing properties the action set (the element's own style had them empty). */\n const sized = new Set<string>();\n\n const stills = () => node.querySelectorAll<HTMLElement>(`:scope > [${STILL_ATTR}]`);\n const showStills = (show: boolean) => {\n for (const s of stills()) s.style.display = show ? \"block\" : \"none\";\n };\n // When the params change Svelte replaces a server still (`{@html}`), and when\n // it is the element's only child, by setting `innerHTML`, which takes the\n // player's layer out too: put the layer back, and keep a new still hidden.\n const reattach = () => {\n if (mount.parentNode !== node) node.appendChild(mount);\n if (player) showStills(false);\n };\n const observer = typeof MutationObserver === \"function\" ? new MutationObserver(reattach) : undefined;\n observer?.observe(node, { childList: true });\n\n const size = () => {\n const style = hostStyle(resolved.motion.svg, resolved.inline, resolved.contain);\n for (const [prop, value] of style) {\n if (!sized.has(prop) && node.style.getPropertyValue(prop)) continue;\n node.style.setProperty(prop, value);\n sized.add(prop);\n }\n // A property the new sizing drops (`height` when no longer inline) is cleared.\n for (const prop of sized)\n if (!style.some(([p]) => p === prop)) {\n node.style.removeProperty(prop);\n sized.delete(prop);\n }\n };\n\n if (stills().length === 0) {\n ownStill = doc.createElement(\"span\");\n ownStill.setAttribute(STILL_ATTR, \"\");\n ownStill.setAttribute(\"aria-hidden\", \"true\");\n ownStill.style.cssText = LAYER;\n node.insertBefore(ownStill, mount);\n size();\n }\n\n const stop = () => {\n if (!player) return;\n player.dispose();\n player = undefined;\n showStills(true);\n params.onPlayer?.(undefined);\n };\n\n const start = () => {\n const reduced = params.reducedMotion ?? \"user\";\n if (reduced === \"always\" || (reduced === \"user\" && prefersReducedMotion())) return;\n player = new SvgPlayer(mount, resolved.motion, {\n loop: params.loop,\n autoplay: params.autoplay,\n speed: params.speed,\n hold: resolved.hold,\n duration: params.duration,\n steps: params.steps,\n trigger: resolved.trigger,\n pauseWhenHidden: params.pauseWhenHidden,\n playOnEnter: enters(resolved, params),\n hideWhenPaused: params.hideWhenPaused,\n clock: params.clock,\n // The latest params' callback, without remaking the player.\n onPick: (id) => params.onPick?.(id),\n });\n showStills(false);\n params.onPlayer?.(player);\n };\n\n const apply = () => {\n reattach();\n if (ownStill) {\n ownStill.innerHTML = stillMarkup(resolved, params);\n size();\n }\n const next = playerKey(resolved, params);\n if (player && next.every((v, i) => v === key[i])) {\n player.setSpeed(params.speed ?? 1);\n return;\n }\n key = next;\n stop();\n start();\n };\n\n apply();\n\n return {\n update(next) {\n params = next;\n resolved = resolve(params, cache);\n apply();\n },\n destroy() {\n observer?.disconnect();\n stop();\n mount.remove();\n ownStill?.remove();\n for (const prop of sized) node.style.removeProperty(prop);\n },\n };\n}\n\nexport type { SvgPlayer, SvgMotion, SvgTrigger };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/svelte/index.ts"],"sourcesContent":["/**\n * Svelte 5 bindings for Flair, written as plain TypeScript so they need no\n * Svelte compiler: the `flairEffect` action runs any catalog effect (shader or\n * vector) applied to a picture, video, SVG or words; the `vectorEffect` action plays a catalog\n * effect (or any {@link SvgMotion}) in an element, and `vectorEffectStill`\n * gives the markup and style of its still for server rendering.\n *\n * ```svelte\n * <script>\n * import { vectorEffect, vectorEffectStill } from \"@pixerate/flair/svelte\";\n * const params = { id: \"drip-text\", values: { word: \"Slop\" }, loop: false };\n * const still = vectorEffectStill(params);\n * </script>\n *\n * <span use:vectorEffect={params} style={still.style}>{@html still.markup}</span>\n * ```\n *\n * The still is in place from the first paint; the live `SvgPlayer` takes over\n * after mount and is disposed on destroy. Under `prefers-reduced-motion:\n * reduce` the still stays.\n *\n * Needs Svelte 5 (an optional peer dependency of the package); only its types\n * are imported.\n *\n * @packageDocumentation\n */\n\nimport type { ActionReturn } from \"svelte/action\";\nimport { getEffect, effectDefaults, type EffectDefinition } from \"../catalog/index.js\";\nimport { mountEffect, type EffectSubject } from \"../embed/index.js\";\nimport { renderVectorEffect, type VectorEffect as VectorEffectDefinition } from \"../catalog/types.js\";\nimport type { ControlValue } from \"../shader/controls.js\";\nimport type { Clock } from \"../time/clock.js\";\nimport type { SvgMotion } from \"../vector/motion.js\";\nimport { svgFrameMarkup, svgInlineLayout, svgViewBox } from \"../vector/static.js\";\nimport { SvgPlayer, type SvgTrigger } from \"../vector/svg.js\";\n\n/** Cap height of a heavy sans, as a share of its font size: what an inline word is framed to. */\nconst CAP_HEIGHT = \"0.72em\";\n\n/** Marks the still's layer, so the action can find it (and hide it while the player runs). */\nconst STILL_ATTR = \"data-flair-still\";\n\nconst LAYER = \"position:absolute;inset:0;display:block\";\n\n/** When to leave the still in place of the animation. */\nexport type ReducedMotion = \"user\" | \"always\" | \"never\";\n\n/** Options shared by an effect by id and a motion of your own. */\nexport interface SvgPlayerParams {\n /** Start again at the end (default `true`); `false` plays once and stays on the last frame. */\n loop?: boolean;\n /** Start playing at once (default `true`). */\n autoplay?: boolean;\n /** Playback speed (default 1); changed without remaking the player. */\n speed?: number;\n /** Ms to rest on the last frame before looping (default 600, or the effect's). */\n hold?: number;\n /** Loop length in ms (default: the picture's own, plus `hold`). */\n duration?: number;\n /** Step start times in ms, for pictures that change on steps. */\n steps?: readonly number[];\n /** Plays in answer to the pointer (see `SvgTrigger`; default the effect's). */\n trigger?: SvgTrigger;\n /** Pause while scrolled out of view. */\n pauseWhenHidden?: boolean;\n /**\n * Wait to start until scrolled into view. Default `true` when it plays once\n * (`loop: false`, no trigger), so a one-shot further down the page does not\n * finish before anyone sees it; `false` plays at mount.\n */\n playOnEnter?: boolean;\n /** Hide the picture while paused or reset. */\n hideWhenPaused?: boolean;\n /** Time source (default animation frames); a `ManualClock` steps frames yourself. */\n clock?: Clock;\n /** Called with the id of the innermost element with an id that is clicked. */\n onPick?: (id: string) => void;\n /** Called with the player once it is made, and `undefined` when it is disposed. */\n onPlayer?: (player: SvgPlayer | undefined) => void;\n /**\n * The still shown before the player starts and instead of it under reduced\n * motion: `\"last\"` (default; the rest frame, `\"first\"` for a hover or press\n * trigger), `\"first\"` or a time in ms.\n */\n poster?: \"first\" | \"last\" | number;\n /**\n * `\"user\"` (default) shows the still when the visitor prefers reduced\n * motion, `\"always\"` always does, `\"never\"` always plays.\n */\n reducedMotion?: ReducedMotion;\n /**\n * Size it as a word in a line of text: `display: inline-block` with the\n * viewBox's aspect ratio and `height` 0.72em (the cap height of a heavy\n * sans; pass a CSS length for another). Default: the effect's `inline`\n * control. Otherwise it is a block as wide as its container with the\n * viewBox's aspect ratio.\n */\n inline?: boolean | string;\n /**\n * With `inline`, keep room for what spills past the word (descenders,\n * outlines, glows, drips): a margin of the picture's `data-overhang` (see\n * `svgInlineLayout`), so the lines around it make space instead of being\n * painted over. Default `false`.\n */\n contain?: boolean;\n}\n\n/** A catalog vector effect by id (or the effect itself), with its values. */\nexport interface VectorEffectByIdParams extends SvgPlayerParams {\n /** A vector effect's catalog id (`\"drip-text\"`), or the effect itself. */\n id: string | VectorEffectDefinition;\n /** Control values; missing ones take the preset's, then the defaults. Compared by content. */\n values?: Record<string, ControlValue>;\n /** A preset's name to start from. */\n preset?: string;\n motion?: never;\n}\n\n/** Any {@link SvgMotion}; a new object restarts the player. */\nexport interface SvgMotionParams extends SvgPlayerParams {\n /** The picture and its animations. */\n motion: SvgMotion;\n id?: never;\n values?: never;\n preset?: never;\n}\n\n/** What `vectorEffect` and `vectorEffectStill` take: an effect by `id`, or a `motion`. */\nexport type VectorEffectParams = VectorEffectByIdParams | SvgMotionParams;\n\n/** A still of the picture, for `{@html markup}` inside an element with `style`. */\nexport interface VectorEffectStill {\n /** The still's layer: safe `<svg>` markup (see `svgFrameMarkup`) in an absolutely placed `<span>`. */\n markup: string;\n /** The host's inline style: its position and size from the viewBox. */\n style: string;\n}\n\ninterface Resolved {\n motion: SvgMotion;\n hold?: number;\n trigger?: SvgTrigger;\n inline?: boolean | string;\n contain?: boolean;\n}\n\n/** Remembers the last motion made from an effect, so values compared by content do not remake it. */\ntype MotionCache = { key: string; effect: VectorEffectDefinition; motion: SvgMotion };\n\nfunction resolve(params: VectorEffectParams, cache?: { current?: MotionCache }): Resolved {\n if (params.motion) return { motion: params.motion, hold: params.hold, trigger: params.trigger, inline: params.inline, contain: params.contain };\n const { id, values, preset } = params as VectorEffectByIdParams;\n const effect = typeof id === \"string\" ? getEffect(id) : id;\n if (!effect || effect.kind !== \"vector\")\n throw new Error(\n `\"${typeof id === \"string\" ? id : (effect?.id ?? id)}\" is not a vector effect; pick one from findEffects({ kind: \"vector\" }), or pass a motion`,\n );\n const key = JSON.stringify([preset ?? null, values ?? {}]);\n let motion: SvgMotion;\n if (cache?.current && cache.current.effect === effect && cache.current.key === key) motion = cache.current.motion;\n else {\n motion = renderVectorEffect(effect, effectDefaults(effect, { preset, values }));\n if (cache) cache.current = { key, effect, motion };\n }\n return {\n motion,\n hold: params.hold ?? effect.hold,\n trigger: params.trigger ?? effect.trigger,\n inline: params.inline ?? values?.inline === true,\n contain: params.contain,\n };\n}\n\n/** The host's sizing from the picture's viewBox, so the still and the player take the same room. */\nfunction hostStyle(svg: string, inline: boolean | string | undefined, contain?: boolean): [string, string][] {\n const box = svgViewBox(svg);\n const style: [string, string][] = [\n [\"position\", \"relative\"],\n [\"display\", inline ? \"inline-block\" : \"block\"],\n ];\n if (inline) style.push([\"height\", typeof inline === \"string\" ? inline : CAP_HEIGHT]);\n if (box) style.push([\"aspect-ratio\", `${box[2]} / ${box[3]}`]);\n const spill = inline && contain ? svgInlineLayout(svg)?.overhang : undefined;\n if (spill) style.push([\"margin\", `${spill.top}em ${spill.right}em ${spill.bottom}em ${spill.left}em`]);\n return style;\n}\n\n/** Whether to wait until scrolled into view: as asked, else when it plays once. */\nconst enters = (r: Resolved, p: SvgPlayerParams) => p.playOnEnter ?? (p.loop === false && !r.trigger);\n\nfunction stillMarkup(r: Resolved, params: SvgPlayerParams): string {\n const at = params.poster ?? (r.trigger === \"hover\" || r.trigger === \"press\" ? \"first\" : \"last\");\n return svgFrameMarkup(r.motion, { at, steps: params.steps }) ?? \"\";\n}\n\n/**\n * The still of an effect or motion, for server rendering: put `markup` in the\n * element that has the `vectorEffect` action, with `style` as its style, so\n * the page shows the picture before the player starts (and instead of it\n * under reduced motion), in the room the player will take.\n * Throws when `id` is not a vector effect.\n */\nexport function vectorEffectStill(params: VectorEffectParams): VectorEffectStill {\n const r = resolve(params);\n return {\n markup: `<span ${STILL_ATTR} aria-hidden=\"true\" style=\"${LAYER}\">${stillMarkup(r, params)}</span>`,\n style: hostStyle(r.motion.svg, r.inline, r.contain)\n .map(([k, v]) => `${k}: ${v}`)\n .join(\"; \"),\n };\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof matchMedia === \"function\" && matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/** The options whose change remakes the player (`speed` is set on it instead). */\nfunction playerKey(r: Resolved, p: SvgPlayerParams): unknown[] {\n return [\n r.motion,\n p.loop,\n p.autoplay,\n r.hold,\n p.duration,\n p.steps?.join(\",\"),\n r.trigger,\n p.pauseWhenHidden,\n enters(r, p),\n p.hideWhenPaused,\n p.clock,\n p.reducedMotion ?? \"user\",\n ];\n}\n\n/**\n * A Svelte action that plays a vector effect in its element:\n * `<span use:vectorEffect={{ id: \"drip-text\", values: { word: \"Slop\" }, loop: false }} />`.\n *\n * It makes an `SvgPlayer` in a layer of its own, remakes it when the params\n * change (values by content; `speed` without remaking) and disposes it on\n * destroy. A still from {@link vectorEffectStill} in the element is hidden\n * while the player runs and shown again after; without one, the action makes\n * its own (so reduced motion still shows the picture) and sizes the element\n * from the viewBox, leaving alone any of `position`, `display`, `height`,\n * `aspect-ratio` and `margin` the element's style already sets.\n *\n * For an attachment, `{@attach fromAction(vectorEffect, () => params)}`\n * (`fromAction` is from `svelte/attachments`). Throws when `id` is not a\n * vector effect.\n */\nexport function vectorEffect(node: HTMLElement, initial: VectorEffectParams): ActionReturn<VectorEffectParams> {\n const cache: { current?: MotionCache } = {};\n const doc = node.ownerDocument;\n const mount = doc.createElement(\"span\");\n mount.style.cssText = LAYER;\n node.appendChild(mount);\n\n let params = initial;\n let resolved = resolve(params, cache);\n let player: SvgPlayer | undefined;\n let key: unknown[] = [];\n /** The still the action made itself, when the element had none. */\n let ownStill: HTMLElement | undefined;\n /** Sizing properties the action set (the element's own style had them empty). */\n const sized = new Set<string>();\n\n const stills = () => node.querySelectorAll<HTMLElement>(`:scope > [${STILL_ATTR}]`);\n const showStills = (show: boolean) => {\n for (const s of stills()) s.style.display = show ? \"block\" : \"none\";\n };\n // When the params change Svelte replaces a server still (`{@html}`), and when\n // it is the element's only child, by setting `innerHTML`, which takes the\n // player's layer out too: put the layer back, and keep a new still hidden.\n const reattach = () => {\n if (mount.parentNode !== node) node.appendChild(mount);\n if (player) showStills(false);\n };\n const observer = typeof MutationObserver === \"function\" ? new MutationObserver(reattach) : undefined;\n observer?.observe(node, { childList: true });\n\n const size = () => {\n const style = hostStyle(resolved.motion.svg, resolved.inline, resolved.contain);\n for (const [prop, value] of style) {\n if (!sized.has(prop) && node.style.getPropertyValue(prop)) continue;\n node.style.setProperty(prop, value);\n sized.add(prop);\n }\n // A property the new sizing drops (`height` when no longer inline) is cleared.\n for (const prop of sized)\n if (!style.some(([p]) => p === prop)) {\n node.style.removeProperty(prop);\n sized.delete(prop);\n }\n };\n\n if (stills().length === 0) {\n ownStill = doc.createElement(\"span\");\n ownStill.setAttribute(STILL_ATTR, \"\");\n ownStill.setAttribute(\"aria-hidden\", \"true\");\n ownStill.style.cssText = LAYER;\n node.insertBefore(ownStill, mount);\n size();\n }\n\n const stop = () => {\n if (!player) return;\n player.dispose();\n player = undefined;\n showStills(true);\n params.onPlayer?.(undefined);\n };\n\n const start = () => {\n const reduced = params.reducedMotion ?? \"user\";\n if (reduced === \"always\" || (reduced === \"user\" && prefersReducedMotion())) return;\n player = new SvgPlayer(mount, resolved.motion, {\n loop: params.loop,\n autoplay: params.autoplay,\n speed: params.speed,\n hold: resolved.hold,\n duration: params.duration,\n steps: params.steps,\n trigger: resolved.trigger,\n pauseWhenHidden: params.pauseWhenHidden,\n playOnEnter: enters(resolved, params),\n hideWhenPaused: params.hideWhenPaused,\n clock: params.clock,\n // The latest params' callback, without remaking the player.\n onPick: (id) => params.onPick?.(id),\n });\n showStills(false);\n params.onPlayer?.(player);\n };\n\n const apply = () => {\n reattach();\n if (ownStill) {\n ownStill.innerHTML = stillMarkup(resolved, params);\n size();\n }\n const next = playerKey(resolved, params);\n if (player && next.every((v, i) => v === key[i])) {\n player.setSpeed(params.speed ?? 1);\n return;\n }\n key = next;\n stop();\n start();\n };\n\n apply();\n\n return {\n update(next) {\n params = next;\n resolved = resolve(params, cache);\n apply();\n },\n destroy() {\n observer?.disconnect();\n stop();\n mount.remove();\n ownStill?.remove();\n for (const prop of sized) node.style.removeProperty(prop);\n },\n };\n}\n\nexport type { SvgPlayer, SvgMotion, SvgTrigger };\n\n/** What the `flairEffect` action runs: any catalog effect, applied to a subject. */\nexport interface FlairEffectParams {\n /** A catalog effect, by id or definition: shader or vector. */\n effect: string | EffectDefinition;\n /** What to apply it to: a picture, a video, an SVG, words or a path (see `EffectSubject`). */\n subject?: EffectSubject | readonly EffectSubject[];\n preset?: string;\n values?: Record<string, ControlValue>;\n /** Start playing at once (default `true`). */\n autoplay?: boolean;\n /** Pause while scrolled out of view (default `true`). */\n pauseWhenHidden?: boolean;\n}\n\n/**\n * Runs any catalog effect, shader or vector, in an element, applied to a\n * subject (see `mountEffect` in `@pixerate/flair/embed`); it fills the\n * element, so size it with CSS. A new subject or values update the running\n * effect; a new effect, preset or playback option starts it again.\n *\n * ```svelte\n * <div use:flairEffect={{ effect: \"image-duotone\", subject: { image: \"/team.jpg\" } }} style=\"aspect-ratio: 16 / 9\"></div>\n * ```\n */\nexport function flairEffect(node: HTMLElement, initial: FlairEffectParams): ActionReturn<FlairEffectParams> {\n let params = initial;\n if (!node.style.position) node.style.position = \"relative\";\n const start = () => {\n const m = mountEffect(node, params.effect, {\n ...(params.subject ? { subject: params.subject } : {}),\n ...(params.preset ? { preset: params.preset } : {}),\n ...(params.values ? { values: params.values } : {}),\n autoplay: params.autoplay ?? true,\n pauseWhenHidden: params.pauseWhenHidden ?? true,\n });\n m.element.style.display = \"block\";\n m.element.style.width = \"100%\";\n m.element.style.height = \"100%\";\n return m;\n };\n let mounted = start();\n return {\n update(next) {\n const restart =\n next.effect !== params.effect || next.preset !== params.preset || next.autoplay !== params.autoplay || next.pauseWhenHidden !== params.pauseWhenHidden;\n const subjectChanged = next.subject !== params.subject;\n const valuesChanged = JSON.stringify(next.values ?? {}) !== JSON.stringify(params.values ?? {});\n params = next;\n if (restart) {\n mounted.dispose();\n mounted = start();\n return;\n }\n if (subjectChanged && next.subject) mounted.setSubject(next.subject);\n if (valuesChanged && next.values) mounted.setValues(next.values);\n },\n destroy() {\n mounted.dispose();\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/vector/index.d.ts
CHANGED
|
@@ -86,6 +86,57 @@ interface SvgFrameMarkupOptions {
|
|
|
86
86
|
*/
|
|
87
87
|
declare function svgFrameMarkup(motion: SvgMotion, options?: SvgFrameMarkupOptions): string | undefined;
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* An {@link SvgMotion} as one self-contained animated `.svg` file, with no
|
|
91
|
+
* DOM and no script: its changes written as SMIL (`<animate>`,
|
|
92
|
+
* `<animateTransform>`, `<animateMotion>`), so it plays on its own wherever
|
|
93
|
+
* an SVG image does (an `<img src>`, a file opened directly, inline markup).
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
interface AnimatedSvgOptions {
|
|
97
|
+
/** Loop length in ms (default: `svgDuration(motion, steps)` + `hold`). */
|
|
98
|
+
duration?: number;
|
|
99
|
+
/** Ms to rest on the last frame before looping (default 600, like `SvgPlayer`). */
|
|
100
|
+
hold?: number;
|
|
101
|
+
/** Loop forever (default true); false plays once and holds the last frame. */
|
|
102
|
+
loop?: boolean;
|
|
103
|
+
/** Step start times in ms, for pictures that change on steps (like `SvgPlayer`'s `steps`). */
|
|
104
|
+
steps?: readonly number[];
|
|
105
|
+
/**
|
|
106
|
+
* Samples per second for what cannot be written exactly (counts, written
|
|
107
|
+
* text, a change cut short by the next, a `matrix` transform); default 30.
|
|
108
|
+
*/
|
|
109
|
+
fps?: number;
|
|
110
|
+
/**
|
|
111
|
+
* Added to the ids the picture refers to (its gradients, filters, clips,
|
|
112
|
+
* paths followed), so two files inlined in one page each use their own.
|
|
113
|
+
* Default: a hash of the motion, so the same motion gives the same file;
|
|
114
|
+
* `""` keeps ids as written.
|
|
115
|
+
*/
|
|
116
|
+
idSuffix?: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The {@link SvgMotion} as one animated SVG file that plays and loops on its
|
|
120
|
+
* own, as `SvgPlayer` plays it, with no script: save it as `.svg`, put it in
|
|
121
|
+
* an `<img src>`, or inline it. Each element starts as the motion's first
|
|
122
|
+
* frame, so it still shows that where SMIL does not run.
|
|
123
|
+
*
|
|
124
|
+
* Attribute changes become one `<animate>` per attribute (`<animateTransform>`
|
|
125
|
+
* per function of a `transform`), with the eases written exactly as splines;
|
|
126
|
+
* `draw` animates `stroke-dashoffset`; `along` becomes `<animateMotion>` on
|
|
127
|
+
* the path; `view` animates the root `viewBox` (keeping `data-fixed` and
|
|
128
|
+
* `data-nonscaling` elements as the player does); `solo` toggles `display`.
|
|
129
|
+
* Counts and written text are sampled at `fps`, each text shown in its own
|
|
130
|
+
* `<tspan>` in turn.
|
|
131
|
+
*
|
|
132
|
+
* Limits: a `view` that frames an element by id stays where it is (it needs
|
|
133
|
+
* layout, as in `svgFrameMarkup`); `style` and other attributes SMIL cannot
|
|
134
|
+
* interpolate change in steps; ids are suffixed only where the picture
|
|
135
|
+
* refers to them (CSS `#id` selectors in a `<style>` are left as written).
|
|
136
|
+
* Undefined when `motion.svg` is not an `<svg>`.
|
|
137
|
+
*/
|
|
138
|
+
declare function svgAnimatedMarkup(motion: SvgMotion, options?: AnimatedSvgOptions): string | undefined;
|
|
139
|
+
|
|
89
140
|
type BoxFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down';
|
|
90
141
|
type BoxAlignment = 'topLeft' | 'topCenter' | 'topRight' | 'centerLeft' | 'center' | 'centerRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight';
|
|
91
142
|
interface FittedBoxResult {
|
|
@@ -139,4 +190,4 @@ interface FormatUnitOptions {
|
|
|
139
190
|
*/
|
|
140
191
|
declare function formatUnit(value: number, format?: UnitFormat, options?: FormatUnitOptions): string;
|
|
141
192
|
|
|
142
|
-
export { type BoxAlignment, type BoxFit, type FittedBoxResult, type FormatUnitOptions, type MorphOptions, type StackLayoutOptions, SvgBox, type SvgFrameMarkupOptions, type SvgInlineLayout, SvgMotion, type UnitFormat, computeBoxFit, formatUnit, layoutStack, morphPaths, morphSequence, parseViewBox, remap, stepVariant, svgFrameMarkup, svgInlineLayout, svgViewBox };
|
|
193
|
+
export { type AnimatedSvgOptions, type BoxAlignment, type BoxFit, type FittedBoxResult, type FormatUnitOptions, type MorphOptions, type StackLayoutOptions, SvgBox, type SvgFrameMarkupOptions, type SvgInlineLayout, SvgMotion, type UnitFormat, computeBoxFit, formatUnit, layoutStack, morphPaths, morphSequence, parseViewBox, remap, stepVariant, svgAnimatedMarkup, svgFrameMarkup, svgInlineLayout, svgViewBox };
|
package/dist/vector/index.js
CHANGED
|
@@ -4,13 +4,16 @@ import {
|
|
|
4
4
|
layoutStack,
|
|
5
5
|
remap,
|
|
6
6
|
stepVariant
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-H6L67KHI.js";
|
|
8
|
+
import {
|
|
9
|
+
svgAnimatedMarkup
|
|
10
|
+
} from "../chunk-YBGRXVAE.js";
|
|
8
11
|
import {
|
|
9
12
|
parseViewBox,
|
|
10
13
|
svgFrameMarkup,
|
|
11
14
|
svgInlineLayout,
|
|
12
15
|
svgViewBox
|
|
13
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-STKEKXCK.js";
|
|
14
17
|
import {
|
|
15
18
|
EASES,
|
|
16
19
|
SCRAMBLE_MS,
|
|
@@ -33,11 +36,11 @@ import {
|
|
|
33
36
|
svgView,
|
|
34
37
|
writtenText
|
|
35
38
|
} from "../chunk-PFGGPIMT.js";
|
|
39
|
+
import "../chunk-WMZQCUFJ.js";
|
|
36
40
|
import {
|
|
37
41
|
morphPaths,
|
|
38
42
|
morphSequence
|
|
39
|
-
} from "../chunk-
|
|
40
|
-
import "../chunk-WMZQCUFJ.js";
|
|
43
|
+
} from "../chunk-ORAFCHX3.js";
|
|
41
44
|
export {
|
|
42
45
|
EASES,
|
|
43
46
|
SCRAMBLE_MS,
|
|
@@ -61,6 +64,7 @@ export {
|
|
|
61
64
|
stepProgress,
|
|
62
65
|
stepStart,
|
|
63
66
|
stepVariant,
|
|
67
|
+
svgAnimatedMarkup,
|
|
64
68
|
svgDuration,
|
|
65
69
|
svgFrame,
|
|
66
70
|
svgFrameMarkup,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/flair",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Web visual effects and motion graphics: WebGL2 shader effects, animated vector effects, a catalog of ready-made effects, and a UI-agnostic, agent-ready effect editor.",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|