@pixerate/flair 0.13.1 → 0.15.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 +22 -0
- package/README.md +32 -1
- package/dist/catalog/index.d.ts +3 -3
- package/dist/catalog/index.js +1 -1
- package/dist/{chunk-UJDQJK2O.js → chunk-4RGHZWQC.js} +1 -1
- package/dist/{chunk-UJDQJK2O.js.map → chunk-4RGHZWQC.js.map} +1 -1
- package/dist/chunk-DVVQRZJ5.js +137 -0
- package/dist/chunk-DVVQRZJ5.js.map +1 -0
- package/dist/{chunk-L4NFQM5N.js → chunk-KWNFZ5NC.js} +10 -4
- package/dist/{chunk-L4NFQM5N.js.map → chunk-KWNFZ5NC.js.map} +1 -1
- package/dist/{chunk-KVKJCD6A.js → chunk-SHHAIWUR.js} +6 -6
- package/dist/{chunk-H355R6U4.js → chunk-VP6IEWIK.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/editor/index.d.ts +2 -2
- package/dist/editor/index.js +5 -5
- package/dist/index.d.ts +3 -3
- package/dist/index.js +24 -16
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +82 -0
- package/dist/react/index.js +132 -0
- package/dist/react/index.js.map +1 -0
- package/dist/{svg-DNEreR2p.d.ts → svg-XugR-6Ec.d.ts} +5 -2
- package/dist/{types-B23zI_jp.d.ts → types-9J6NWaN3.d.ts} +2 -2
- package/dist/vector/index.d.ts +35 -3
- package/dist/vector/index.js +10 -2
- package/package.json +16 -3
- /package/dist/{chunk-KVKJCD6A.js.map → chunk-SHHAIWUR.js.map} +0 -0
- /package/dist/{chunk-H355R6U4.js.map → chunk-VP6IEWIK.js.map} +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes } from 'react';
|
|
3
|
+
import { V as VectorEffect$1 } from '../types-9J6NWaN3.js';
|
|
4
|
+
import { C as ControlValue } from '../controls-Syr6drzO.js';
|
|
5
|
+
import { S as SvgMotion, a as SvgTrigger, C as Clock, b as SvgPlayer } from '../svg-XugR-6Ec.js';
|
|
6
|
+
|
|
7
|
+
/** When to leave the still in place of the animation. */
|
|
8
|
+
type ReducedMotion = "user" | "always" | "never";
|
|
9
|
+
interface SvgPlayerViewProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
10
|
+
/** The picture and its animations. */
|
|
11
|
+
motion: SvgMotion;
|
|
12
|
+
/** Start again at the end (default `true`); `false` plays once and stays on the last frame. */
|
|
13
|
+
loop?: boolean;
|
|
14
|
+
/** Start playing at once (default `true`). */
|
|
15
|
+
autoplay?: boolean;
|
|
16
|
+
/** Playback speed (default 1). */
|
|
17
|
+
speed?: number;
|
|
18
|
+
/** Ms to rest on the last frame before looping (default 600). */
|
|
19
|
+
hold?: number;
|
|
20
|
+
/** Loop length in ms (default: the picture's own, plus `hold`). */
|
|
21
|
+
duration?: number;
|
|
22
|
+
/** Step start times in ms, for pictures that change on steps. */
|
|
23
|
+
steps?: readonly number[];
|
|
24
|
+
/** Plays in answer to the pointer (see `SvgTrigger`). */
|
|
25
|
+
trigger?: SvgTrigger;
|
|
26
|
+
/** Pause while scrolled out of view. */
|
|
27
|
+
pauseWhenHidden?: boolean;
|
|
28
|
+
/** Wait to start until scrolled into view. */
|
|
29
|
+
playOnEnter?: boolean;
|
|
30
|
+
/** Hide the picture while paused or reset. */
|
|
31
|
+
hideWhenPaused?: boolean;
|
|
32
|
+
/** Time source (default animation frames); a `ManualClock` steps frames yourself. */
|
|
33
|
+
clock?: Clock;
|
|
34
|
+
/** Called with the id of the innermost element with an id that is clicked. */
|
|
35
|
+
onPick?: (id: string) => void;
|
|
36
|
+
/** Called with the player once it is made, and `undefined` when it is disposed. */
|
|
37
|
+
onPlayer?: (player: SvgPlayer | undefined) => void;
|
|
38
|
+
/**
|
|
39
|
+
* The still shown before the player starts (server render, hydration) and
|
|
40
|
+
* instead of it under reduced motion: `"last"` (default; the rest frame,
|
|
41
|
+
* `"first"` for a hover or press trigger), `"first"` or a time in ms.
|
|
42
|
+
*/
|
|
43
|
+
poster?: "first" | "last" | number;
|
|
44
|
+
/**
|
|
45
|
+
* `"user"` (default) shows the still when the visitor prefers reduced
|
|
46
|
+
* motion, `"always"` always does, `"never"` always plays.
|
|
47
|
+
*/
|
|
48
|
+
reducedMotion?: ReducedMotion;
|
|
49
|
+
/**
|
|
50
|
+
* Size it as a word in a line of text: `display: inline-block` with the
|
|
51
|
+
* viewBox's aspect ratio and `height` 0.72em (the cap height of a heavy
|
|
52
|
+
* sans; pass a CSS length for another). Meant for pictures framed from cap
|
|
53
|
+
* height to baseline, like drip text's `inline`. Otherwise it is a block
|
|
54
|
+
* as wide as its container with the viewBox's aspect ratio.
|
|
55
|
+
*/
|
|
56
|
+
inline?: boolean | string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Plays an {@link SvgMotion}: a still on the server and before mount, then
|
|
60
|
+
* an `SvgPlayer` (remade when the motion or its options change, disposed on
|
|
61
|
+
* unmount). Pass a memoised `motion`: a new object each render restarts it.
|
|
62
|
+
*/
|
|
63
|
+
declare function SvgPlayerView(props: SvgPlayerViewProps): react.JSX.Element;
|
|
64
|
+
interface VectorEffectProps extends Omit<SvgPlayerViewProps, "motion" | "id"> {
|
|
65
|
+
/** A vector effect's catalog id (`"drip-text"`), or the effect itself. */
|
|
66
|
+
id: string | VectorEffect$1;
|
|
67
|
+
/** Control values; missing ones take the preset's, then the defaults. */
|
|
68
|
+
values?: Record<string, ControlValue>;
|
|
69
|
+
/** A preset's name to start from. */
|
|
70
|
+
preset?: string;
|
|
71
|
+
/** The host element's own `id`. */
|
|
72
|
+
elementId?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Plays a catalog vector effect: `<VectorEffect id="drip-text" values={{ word: "Slop" }} loop={false} />`.
|
|
76
|
+
* Its `hold` and `trigger` are used unless given. With an `inline` control
|
|
77
|
+
* set (drip text's), it is sized as a word in the line (see `inline`).
|
|
78
|
+
* Throws when `id` is not a vector effect.
|
|
79
|
+
*/
|
|
80
|
+
declare function VectorEffect(props: VectorEffectProps): react.JSX.Element;
|
|
81
|
+
|
|
82
|
+
export { type ReducedMotion, SvgMotion, SvgPlayer, SvgPlayerView, type SvgPlayerViewProps, SvgTrigger, VectorEffect, type VectorEffectProps };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
effectDefaults,
|
|
3
|
+
getEffect,
|
|
4
|
+
renderVectorEffect
|
|
5
|
+
} from "../chunk-KWNFZ5NC.js";
|
|
6
|
+
import {
|
|
7
|
+
svgFrameMarkup,
|
|
8
|
+
svgViewBox
|
|
9
|
+
} from "../chunk-DVVQRZJ5.js";
|
|
10
|
+
import {
|
|
11
|
+
SvgPlayer
|
|
12
|
+
} from "../chunk-4RGHZWQC.js";
|
|
13
|
+
import "../chunk-OHW7UG6D.js";
|
|
14
|
+
import "../chunk-EHDJ3CPJ.js";
|
|
15
|
+
import "../chunk-WC3VADZC.js";
|
|
16
|
+
import "../chunk-WMZQCUFJ.js";
|
|
17
|
+
|
|
18
|
+
// src/react/index.tsx
|
|
19
|
+
import {
|
|
20
|
+
useEffect,
|
|
21
|
+
useLayoutEffect,
|
|
22
|
+
useMemo,
|
|
23
|
+
useRef
|
|
24
|
+
} from "react";
|
|
25
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
26
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
27
|
+
var CAP_HEIGHT = "0.72em";
|
|
28
|
+
function prefersReducedMotion() {
|
|
29
|
+
return typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
30
|
+
}
|
|
31
|
+
function hostStyle(svg, inline, style) {
|
|
32
|
+
const box = svgViewBox(svg);
|
|
33
|
+
const aspectRatio = box ? `${box[2]} / ${box[3]}` : void 0;
|
|
34
|
+
const base = inline ? { display: "inline-block", height: typeof inline === "string" ? inline : CAP_HEIGHT, aspectRatio } : { display: "block", aspectRatio };
|
|
35
|
+
return { position: "relative", ...base, ...style };
|
|
36
|
+
}
|
|
37
|
+
var LAYER = { position: "absolute", inset: 0, display: "block" };
|
|
38
|
+
function SvgPlayerView(props) {
|
|
39
|
+
const {
|
|
40
|
+
motion,
|
|
41
|
+
loop,
|
|
42
|
+
autoplay,
|
|
43
|
+
speed,
|
|
44
|
+
hold,
|
|
45
|
+
duration,
|
|
46
|
+
steps,
|
|
47
|
+
trigger,
|
|
48
|
+
pauseWhenHidden,
|
|
49
|
+
playOnEnter,
|
|
50
|
+
hideWhenPaused,
|
|
51
|
+
clock,
|
|
52
|
+
onPick,
|
|
53
|
+
onPlayer,
|
|
54
|
+
poster,
|
|
55
|
+
reducedMotion = "user",
|
|
56
|
+
inline,
|
|
57
|
+
style,
|
|
58
|
+
...rest
|
|
59
|
+
} = props;
|
|
60
|
+
const still = useRef(null);
|
|
61
|
+
const mount = useRef(null);
|
|
62
|
+
const player = useRef(void 0);
|
|
63
|
+
const callbacks = useRef({ onPick, onPlayer });
|
|
64
|
+
callbacks.current = { onPick, onPlayer };
|
|
65
|
+
const at = poster ?? (trigger === "hover" || trigger === "press" ? "first" : "last");
|
|
66
|
+
const markup = useMemo(() => svgFrameMarkup(motion, { at, steps }) ?? "", [motion, at, steps]);
|
|
67
|
+
const stepsKey = steps?.join(",");
|
|
68
|
+
useIsomorphicLayoutEffect(() => {
|
|
69
|
+
const host = mount.current;
|
|
70
|
+
if (!host) return;
|
|
71
|
+
if (reducedMotion === "always" || reducedMotion === "user" && prefersReducedMotion()) return;
|
|
72
|
+
const p = new SvgPlayer(host, motion, {
|
|
73
|
+
loop,
|
|
74
|
+
autoplay,
|
|
75
|
+
speed,
|
|
76
|
+
hold,
|
|
77
|
+
duration,
|
|
78
|
+
steps,
|
|
79
|
+
trigger,
|
|
80
|
+
pauseWhenHidden,
|
|
81
|
+
playOnEnter,
|
|
82
|
+
hideWhenPaused,
|
|
83
|
+
clock,
|
|
84
|
+
onPick: (id) => callbacks.current.onPick?.(id)
|
|
85
|
+
});
|
|
86
|
+
player.current = p;
|
|
87
|
+
if (still.current) still.current.style.display = "none";
|
|
88
|
+
callbacks.current.onPlayer?.(p);
|
|
89
|
+
return () => {
|
|
90
|
+
p.dispose();
|
|
91
|
+
player.current = void 0;
|
|
92
|
+
if (still.current) still.current.style.display = "block";
|
|
93
|
+
callbacks.current.onPlayer?.(void 0);
|
|
94
|
+
};
|
|
95
|
+
}, [motion, loop, autoplay, hold, duration, stepsKey, trigger, pauseWhenHidden, playOnEnter, hideWhenPaused, clock, reducedMotion]);
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
player.current?.setSpeed(speed ?? 1);
|
|
98
|
+
}, [speed]);
|
|
99
|
+
return /* @__PURE__ */ jsxs("span", { ...rest, style: hostStyle(motion.svg, inline, style), children: [
|
|
100
|
+
/* @__PURE__ */ jsx("span", { ref: still, "aria-hidden": "true", style: LAYER, dangerouslySetInnerHTML: { __html: markup } }),
|
|
101
|
+
/* @__PURE__ */ jsx("span", { ref: mount, style: LAYER })
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
function VectorEffect(props) {
|
|
105
|
+
const { id, values, preset, elementId, ...rest } = props;
|
|
106
|
+
const effect = typeof id === "string" ? getEffect(id) : id;
|
|
107
|
+
if (!effect || effect.kind !== "vector")
|
|
108
|
+
throw new Error(`"${typeof id === "string" ? id : effect?.id}" is not a vector effect; pick one from findEffects({ kind: "vector" })`);
|
|
109
|
+
const valuesKey = JSON.stringify(values ?? {});
|
|
110
|
+
const motion = useMemo(
|
|
111
|
+
() => renderVectorEffect(effect, effectDefaults(effect, { preset, values })),
|
|
112
|
+
// Values by content, so an inline object literal does not restart it.
|
|
113
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
114
|
+
[effect, preset, valuesKey]
|
|
115
|
+
);
|
|
116
|
+
return /* @__PURE__ */ jsx(
|
|
117
|
+
SvgPlayerView,
|
|
118
|
+
{
|
|
119
|
+
id: elementId,
|
|
120
|
+
motion,
|
|
121
|
+
hold: effect.hold,
|
|
122
|
+
trigger: effect.trigger,
|
|
123
|
+
inline: values?.inline === true,
|
|
124
|
+
...rest
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
SvgPlayerView,
|
|
130
|
+
VectorEffect
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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, 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 /** Wait to start until scrolled into view. */\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\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, style?: CSSProperties): CSSProperties {\n const box = svgViewBox(svg);\n const aspectRatio = box ? `${box[2]} / ${box[3]}` : undefined;\n const base: CSSProperties = inline\n ? { display: \"inline-block\", height: typeof inline === \"string\" ? inline : CAP_HEIGHT, aspectRatio }\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 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\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,\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, playOnEnter, 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, 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":[]}
|
|
@@ -265,7 +265,10 @@ interface SvgPlayerOptions extends SvgViewOptions {
|
|
|
265
265
|
clock?: Clock;
|
|
266
266
|
/** Start playing at once (default `true`). */
|
|
267
267
|
autoplay?: boolean;
|
|
268
|
-
/**
|
|
268
|
+
/**
|
|
269
|
+
* Start again at the end (default `true`). When `false` it plays once and
|
|
270
|
+
* stays on the last frame (hidden instead with `hideWhenPaused`).
|
|
271
|
+
*/
|
|
269
272
|
loop?: boolean;
|
|
270
273
|
/** Loop length in ms (default: the picture's own, see {@link svgDuration}, plus `hold`). */
|
|
271
274
|
duration?: number;
|
|
@@ -379,4 +382,4 @@ interface AnimateCountOptions {
|
|
|
379
382
|
*/
|
|
380
383
|
declare function animateCount(options: AnimateCountOptions): () => void;
|
|
381
384
|
|
|
382
|
-
export { type AnimateCountOptions as A, svgMotionIssues as B, type Clock as C, type DataKey as D, EASES as E, svgOpeningTag as F, svgView as G, writtenText as H, ManualClock as M, type SvgMotion as S, type SvgTrigger as a,
|
|
385
|
+
export { type AnimateCountOptions as A, svgMotionIssues as B, type Clock as C, type DataKey as D, EASES as E, svgOpeningTag as F, svgView as G, writtenText as H, ManualClock as M, type SvgMotion as S, type SvgTrigger as a, SvgPlayer as b, type EaseName as c, SCRAMBLE_MS as d, STEP_MS as e, SVG_PICTURE as f, type SvgAnimation as g, type SvgBox as h, type SvgElementFrame as i, type SvgPlayerOptions as j, type SvgView as k, type SvgViewOptions as l, animateCount as m, defaultDataKey as n, formatCount as o, jitter as p, lerpAttr as q, lerpData as r, pageHidden as s, parseSvg as t, realClock as u, stepData as v, stepProgress as w, stepStart as x, svgDuration as y, svgFrame as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as ControlValue, a as ControlDef } from './controls-Syr6drzO.js';
|
|
2
|
-
import { S as SvgMotion, a as SvgTrigger } from './svg-
|
|
2
|
+
import { S as SvgMotion, a as SvgTrigger } from './svg-XugR-6Ec.js';
|
|
3
3
|
|
|
4
4
|
/** What an effect is for, used to group the catalog. */
|
|
5
5
|
type EffectCategory = "gradient" | "organic" | "pattern" | "light" | "space" | "retro" | "image" | "overlay" | "text" | "morph" | "interaction" | "pyrotechnics" | "timewarp" | "melt" | "electric" | "transition" | "loader" | "data" | "icon";
|
|
@@ -111,4 +111,4 @@ declare function colorControl(name: string, hex: string, label?: string): Vector
|
|
|
111
111
|
/** A number control for vector effects. */
|
|
112
112
|
declare function numberControl(name: string, value: number, min: number, max: number, label?: string, step?: number): VectorControl;
|
|
113
113
|
|
|
114
|
-
export { type EffectDefinition as E, type ShaderEffect as S,
|
|
114
|
+
export { type EffectDefinition as E, type ShaderEffect as S, type VectorEffect as V, type EffectCategory as a, EFFECT_CATEGORIES as b, type EffectPreset as c, VECTOR_CONTROL_TYPES as d, type VectorControl as e, colorControl as f, vectorControlIssues as g, vectorControls as h, vectorEffectControls as i, numberControl as n, renderVectorEffect as r, vectorControlDef as v };
|
package/dist/vector/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { A as AnimateCountOptions, D as DataKey, E as EASES,
|
|
1
|
+
import { h as SvgBox, S as SvgMotion } from '../svg-XugR-6Ec.js';
|
|
2
|
+
export { A as AnimateCountOptions, D as DataKey, E as EASES, c as EaseName, d as SCRAMBLE_MS, e as STEP_MS, f as SVG_PICTURE, g as SvgAnimation, i as SvgElementFrame, b as SvgPlayer, j as SvgPlayerOptions, a as SvgTrigger, k as SvgView, l as SvgViewOptions, m as animateCount, n as defaultDataKey, o as formatCount, q as lerpAttr, r as lerpData, t as parseSvg, v as stepData, w as stepProgress, x as stepStart, y as svgDuration, z as svgFrame, B as svgMotionIssues, F as svgOpeningTag, G as svgView, H as writtenText } from '../svg-XugR-6Ec.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Shape morphing: any SVG paths turned into paths with the same structure, so
|
|
@@ -28,6 +28,38 @@ declare function morphSequence(paths: readonly string[], options?: MorphOptions)
|
|
|
28
28
|
*/
|
|
29
29
|
declare function morphPaths(from: string, to: string, options?: MorphOptions): [string, string];
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* An {@link SvgMotion}'s frame as markup, with no DOM: for server rendering
|
|
33
|
+
* (a still that hydrates without a blank flash), reduced motion and other
|
|
34
|
+
* places a live player is not wanted.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/** A `viewBox` attribute's box, or undefined when it has none or it is malformed. */
|
|
38
|
+
declare function parseViewBox(value: string | null | undefined): SvgBox | undefined;
|
|
39
|
+
/** The `viewBox` on an SVG's opening tag (see {@link parseViewBox}). */
|
|
40
|
+
declare function svgViewBox(markup: string): SvgBox | undefined;
|
|
41
|
+
interface SvgFrameMarkupOptions {
|
|
42
|
+
/**
|
|
43
|
+
* The time shown, in ms: a number, `"first"` (0) or `"last"` (the end of
|
|
44
|
+
* its last change, see `svgDuration`; the default).
|
|
45
|
+
*/
|
|
46
|
+
at?: number | "first" | "last";
|
|
47
|
+
/** Step start times in ms, as a player's `steps` (default none). */
|
|
48
|
+
steps?: readonly number[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The picture of an {@link SvgMotion} at a moment, as `<svg>` markup made safe
|
|
52
|
+
* the way `parseSvg` makes it (no scripts, handlers, `<foreignObject>` or
|
|
53
|
+
* outside links), with no DOM needed: render it on a server, show it under
|
|
54
|
+
* `prefers-reduced-motion`, or anywhere a still will do. It is sized to fill
|
|
55
|
+
* its container, as `SvgPlayer` draws it.
|
|
56
|
+
*
|
|
57
|
+
* It matches the player's frame except where that needs layout: a change
|
|
58
|
+
* `along` a path, and a `view` that frames an element by id, stay where the
|
|
59
|
+
* markup puts them. Undefined when `motion.svg` is not an `<svg>`.
|
|
60
|
+
*/
|
|
61
|
+
declare function svgFrameMarkup(motion: SvgMotion, options?: SvgFrameMarkupOptions): string | undefined;
|
|
62
|
+
|
|
31
63
|
type BoxFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down';
|
|
32
64
|
type BoxAlignment = 'topLeft' | 'topCenter' | 'topRight' | 'centerLeft' | 'center' | 'centerRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight';
|
|
33
65
|
interface FittedBoxResult {
|
|
@@ -81,4 +113,4 @@ interface FormatUnitOptions {
|
|
|
81
113
|
*/
|
|
82
114
|
declare function formatUnit(value: number, format?: UnitFormat, options?: FormatUnitOptions): string;
|
|
83
115
|
|
|
84
|
-
export { type BoxAlignment, type BoxFit, type FittedBoxResult, type FormatUnitOptions, type MorphOptions, type StackLayoutOptions, SvgBox, type UnitFormat, computeBoxFit, formatUnit, layoutStack, morphPaths, morphSequence, remap, stepVariant };
|
|
116
|
+
export { type BoxAlignment, type BoxFit, type FittedBoxResult, type FormatUnitOptions, type MorphOptions, type StackLayoutOptions, SvgBox, type SvgFrameMarkupOptions, SvgMotion, type UnitFormat, computeBoxFit, formatUnit, layoutStack, morphPaths, morphSequence, parseViewBox, remap, stepVariant, svgFrameMarkup, svgViewBox };
|
package/dist/vector/index.js
CHANGED
|
@@ -4,7 +4,12 @@ import {
|
|
|
4
4
|
layoutStack,
|
|
5
5
|
remap,
|
|
6
6
|
stepVariant
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-VP6IEWIK.js";
|
|
8
|
+
import {
|
|
9
|
+
parseViewBox,
|
|
10
|
+
svgFrameMarkup,
|
|
11
|
+
svgViewBox
|
|
12
|
+
} from "../chunk-DVVQRZJ5.js";
|
|
8
13
|
import {
|
|
9
14
|
EASES,
|
|
10
15
|
SCRAMBLE_MS,
|
|
@@ -26,7 +31,7 @@ import {
|
|
|
26
31
|
svgOpeningTag,
|
|
27
32
|
svgView,
|
|
28
33
|
writtenText
|
|
29
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-4RGHZWQC.js";
|
|
30
35
|
import {
|
|
31
36
|
morphPaths,
|
|
32
37
|
morphSequence
|
|
@@ -49,6 +54,7 @@ export {
|
|
|
49
54
|
morphPaths,
|
|
50
55
|
morphSequence,
|
|
51
56
|
parseSvg,
|
|
57
|
+
parseViewBox,
|
|
52
58
|
remap,
|
|
53
59
|
stepData,
|
|
54
60
|
stepProgress,
|
|
@@ -56,9 +62,11 @@ export {
|
|
|
56
62
|
stepVariant,
|
|
57
63
|
svgDuration,
|
|
58
64
|
svgFrame,
|
|
65
|
+
svgFrameMarkup,
|
|
59
66
|
svgMotionIssues,
|
|
60
67
|
svgOpeningTag,
|
|
61
68
|
svgView,
|
|
69
|
+
svgViewBox,
|
|
62
70
|
writtenText
|
|
63
71
|
};
|
|
64
72
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/flair",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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",
|
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
"types": "./dist/vector/index.d.ts",
|
|
39
39
|
"import": "./dist/vector/index.js"
|
|
40
40
|
},
|
|
41
|
+
"./react": {
|
|
42
|
+
"types": "./dist/react/index.d.ts",
|
|
43
|
+
"import": "./dist/react/index.js"
|
|
44
|
+
},
|
|
41
45
|
"./node": {
|
|
42
46
|
"types": "./dist/node.d.ts",
|
|
43
47
|
"import": "./dist/node.js"
|
|
@@ -57,25 +61,34 @@
|
|
|
57
61
|
"effects",
|
|
58
62
|
"generative",
|
|
59
63
|
"editor",
|
|
60
|
-
"ai-agents"
|
|
64
|
+
"ai-agents",
|
|
65
|
+
"react"
|
|
61
66
|
],
|
|
62
67
|
"dependencies": {
|
|
63
68
|
"commander": "^12.0.0",
|
|
64
69
|
"gifenc": "^1.0.3"
|
|
65
70
|
},
|
|
66
71
|
"peerDependencies": {
|
|
67
|
-
"@pixerate/editor": ">=0.29.0 <1"
|
|
72
|
+
"@pixerate/editor": ">=0.29.0 <1",
|
|
73
|
+
"react": ">=18"
|
|
68
74
|
},
|
|
69
75
|
"peerDependenciesMeta": {
|
|
70
76
|
"@pixerate/editor": {
|
|
71
77
|
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"react": {
|
|
80
|
+
"optional": true
|
|
72
81
|
}
|
|
73
82
|
},
|
|
74
83
|
"devDependencies": {
|
|
75
84
|
"@changesets/cli": "^2.27.12",
|
|
76
85
|
"@pixerate/editor": "^0.29.0",
|
|
77
86
|
"@types/node": "^24.19.2",
|
|
87
|
+
"@types/react": "^19.3.0",
|
|
88
|
+
"@types/react-dom": "^19.3.0",
|
|
78
89
|
"jsdom": "^30.1.3",
|
|
90
|
+
"react": "^19.3.1",
|
|
91
|
+
"react-dom": "^19.3.1",
|
|
79
92
|
"tsup": "^8.5",
|
|
80
93
|
"typescript": "^5.9",
|
|
81
94
|
"vitest": "^4.1.11"
|
|
File without changes
|
|
File without changes
|