@pixodesk/svg-animator-react 1.0.10 → 1.0.15

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/dist/index.umd.js CHANGED
@@ -1770,6 +1770,7 @@ var PixodeskAnimatorReact = (() => {
1770
1770
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
1771
1771
  var __hasOwnProp2 = Object.prototype.hasOwnProperty;
1772
1772
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
1773
+ var __pow = Math.pow;
1773
1774
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1774
1775
  var __spreadValues = (a, b) => {
1775
1776
  for (var prop in b || (b = {}))
@@ -1795,22 +1796,1236 @@ var PixodeskAnimatorReact = (() => {
1795
1796
  }
1796
1797
  return target;
1797
1798
  };
1799
+ function partsRecord(part, value, origin) {
1800
+ const rec = {};
1801
+ if (part === "translate") rec.translate = value;
1802
+ else if (part === "rotate") rec.rotate = value;
1803
+ else rec.scale = value;
1804
+ if (origin && part !== "translate") rec.origin = origin;
1805
+ return rec;
1806
+ }
1807
+ function readAnimatable(raw) {
1808
+ if (raw === void 0) return { kind: "absent" };
1809
+ if (Array.isArray(raw)) return { kind: "static", value: raw };
1810
+ if (typeof raw === "object") {
1811
+ const obj = raw;
1812
+ if (obj.keyframes) {
1813
+ return { kind: "animated", keyframes: obj.keyframes, autoOrient: obj.autoOrient };
1814
+ }
1815
+ if (obj.value !== void 0) return { kind: "static", value: obj.value };
1816
+ }
1817
+ return { kind: "static", value: raw };
1818
+ }
1819
+ function readStaticOrigin(raw, ctx) {
1820
+ var _a;
1821
+ const o = readAnimatable(raw);
1822
+ if (o.kind === "absent") return void 0;
1823
+ if (o.kind === "static") return o.value;
1824
+ ctx.warnings.push("transformation.origin: animated origin approximated by its first keyframe");
1825
+ return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
1826
+ }
1827
+ function keyframeWith(kf, value) {
1828
+ const out = { value };
1829
+ if (kf.time !== void 0) out.time = kf.time;
1830
+ if (kf.easing !== void 0) out.easing = kf.easing;
1831
+ if (kf.tangentOut !== void 0) out.tangentOut = kf.tangentOut;
1832
+ if (kf.tangentIn !== void 0) out.tangentIn = kf.tangentIn;
1833
+ return out;
1834
+ }
1835
+ function applyTransformationEffect(node, fx, ctx) {
1836
+ if (!fx) return node;
1837
+ delete node.transform;
1838
+ let n = node;
1839
+ n = wrapTransformPart(n, "skew", fx.skew, ctx);
1840
+ n = wrapOrigin(
1841
+ n,
1842
+ fx.origin,
1843
+ /*invert=*/
1844
+ true
1845
+ );
1846
+ n = wrapTransformPart(n, "scale", normalizeScale(fx.scale), ctx);
1847
+ n = wrapTransformPart(n, "rotate", fx.rotate, ctx);
1848
+ n = wrapOrigin(
1849
+ n,
1850
+ fx.origin,
1851
+ /*invert=*/
1852
+ false
1853
+ );
1854
+ if (translateHasAutoOrient(fx.translate)) {
1855
+ n = wrapOrigin(
1856
+ n,
1857
+ fx.origin,
1858
+ /*invert=*/
1859
+ true
1860
+ );
1861
+ n = wrapTransformPart(n, "translate", fx.translate, ctx);
1862
+ n = wrapOrigin(
1863
+ n,
1864
+ fx.origin,
1865
+ /*invert=*/
1866
+ false
1867
+ );
1868
+ } else {
1869
+ n = wrapTransformPart(n, "translate", fx.translate, ctx);
1870
+ }
1871
+ return n;
1872
+ }
1873
+ function translateHasAutoOrient(translate) {
1874
+ if (!translate || typeof translate !== "object") return false;
1875
+ const obj = translate;
1876
+ if (obj.autoOrient) return true;
1877
+ return Array.isArray(obj.keyframes) && obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
1878
+ }
1879
+ function normalizeScale(raw) {
1880
+ if (raw === void 0) return void 0;
1881
+ if (Array.isArray(raw)) return [raw[0] / 100, raw[1] / 100];
1882
+ return raw;
1883
+ }
1884
+ function wrapTransformPart(inner, part, raw, ctx) {
1885
+ if (raw === void 0) return inner;
1886
+ if (part === "skew") {
1887
+ const skew = readAnimatable(raw);
1888
+ if (skew.kind !== "static") {
1889
+ ctx.warnings.push("transformation.skew: only static skew is supported");
1890
+ return inner;
1891
+ }
1892
+ return { type: "g", transform: "skewX(" + skew.value[0] + ")skewY(" + skew.value[1] + ")", children: [inner] };
1893
+ }
1894
+ const v = readAnimatable(raw);
1895
+ if (v.kind === "static") {
1896
+ return { type: "g", transform: { value: partsRecord(part, v.value, void 0) }, children: [inner] };
1897
+ }
1898
+ if (v.kind === "animated") {
1899
+ const animTr = { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, kf.value, void 0))) };
1900
+ if (v.autoOrient) animTr.autoOrient = true;
1901
+ return {
1902
+ type: "g",
1903
+ animate: { transform: animTr },
1904
+ children: [inner]
1905
+ };
1906
+ }
1907
+ return inner;
1908
+ }
1909
+ function wrapOrigin(inner, raw, invert) {
1910
+ if (raw === void 0) return inner;
1911
+ const v = readAnimatable(raw);
1912
+ const sign = (value) => invert ? [-value[0], -value[1]] : value;
1913
+ if (v.kind === "absent") return inner;
1914
+ if (v.kind === "static") {
1915
+ if (v.value[0] === 0 && v.value[1] === 0) return inner;
1916
+ return { type: "g", transform: { value: { translate: sign(v.value) } }, children: [inner] };
1917
+ }
1918
+ if (v.kind === "animated") {
1919
+ return {
1920
+ type: "g",
1921
+ animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, { translate: sign(kf.value) })) } },
1922
+ children: [inner]
1923
+ };
1924
+ }
1925
+ return inner;
1926
+ }
1927
+ function identifyContentRefTargets(node, ctx, allocator) {
1928
+ var _a, _b, _c;
1929
+ if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.ref) == null ? void 0 : _b.type) === "content") {
1930
+ const baseId = node.effects.ref.baseId;
1931
+ if (typeof baseId === "string" && baseId && !ctx.contentRefInnerIds.has(baseId)) {
1932
+ ctx.contentRefInnerIds.set(baseId, allocator(baseId));
1933
+ }
1934
+ }
1935
+ (_c = node.children) == null ? void 0 : _c.forEach((c) => identifyContentRefTargets(c, ctx, allocator));
1936
+ }
1937
+ function splitForContentRef(node, transformation, originalId, innerId, ctx) {
1938
+ const outerBody = liftBodyTranslate(node, transformation);
1939
+ if (typeof node.id === "string") delete node.id;
1940
+ const { outer: outerTr, inner: innerTr } = splitTransformationEffect(transformation);
1941
+ let innerNode = node;
1942
+ innerNode = applyTransformationEffect(innerNode, innerTr, ctx);
1943
+ const innerWrapper = { type: "g", id: innerId, children: [innerNode] };
1944
+ let outerWrapper = { type: "g", id: originalId, children: [innerWrapper] };
1945
+ if (outerBody.transform !== void 0) outerWrapper.transform = outerBody.transform;
1946
+ if (outerBody.animate !== void 0) outerWrapper.animate = outerBody.animate;
1947
+ if (outerTr) {
1948
+ delete outerWrapper.id;
1949
+ outerWrapper = applyTransformationEffect(outerWrapper, outerTr, ctx);
1950
+ outerWrapper.id = originalId;
1951
+ }
1952
+ return outerWrapper;
1953
+ }
1954
+ function liftBodyTranslate(node, transformation) {
1955
+ var _a;
1956
+ const out = {};
1957
+ let didLiftAnimate = false;
1958
+ const animTr = (_a = node.animate) == null ? void 0 : _a.transform;
1959
+ if (animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes)) {
1960
+ const kfs = animTr.keyframes;
1961
+ const hasTranslate = kfs.some((kf) => kf.value && kf.value.translate);
1962
+ if (hasTranslate) {
1963
+ const outerHasOrigin = needsOriginOnOuter(animTr);
1964
+ const outerKfs = kfs.map((kf) => {
1965
+ const v = kf.value || {};
1966
+ const newValue = {};
1967
+ if (v.translate !== void 0) newValue.translate = v.translate;
1968
+ if (outerHasOrigin && v.origin !== void 0) newValue.origin = v.origin;
1969
+ const outerKf = { value: newValue };
1970
+ if (kf.time !== void 0) outerKf.time = kf.time;
1971
+ if (kf.easing !== void 0) outerKf.easing = kf.easing;
1972
+ if (kf.tangentOut !== void 0) outerKf.tangentOut = kf.tangentOut;
1973
+ if (kf.tangentIn !== void 0) outerKf.tangentIn = kf.tangentIn;
1974
+ return outerKf;
1975
+ });
1976
+ const outerAnimTr = { keyframes: outerKfs };
1977
+ if (animTr.autoOrient) outerAnimTr.autoOrient = true;
1978
+ out.animate = { transform: outerAnimTr };
1979
+ const innerHasPivotedPart = kfs.some((kf) => {
1980
+ const v = kf.value || {};
1981
+ return v.rotate !== void 0 || v.scale !== void 0;
1982
+ });
1983
+ const innerKfs = kfs.map((kf) => {
1984
+ const v = kf.value || {};
1985
+ const newValue = {};
1986
+ if (v.rotate !== void 0) newValue.rotate = v.rotate;
1987
+ if (v.scale !== void 0) newValue.scale = v.scale;
1988
+ if (v.origin !== void 0 && (!outerHasOrigin || innerHasPivotedPart)) newValue.origin = v.origin;
1989
+ const innerKf = { value: newValue };
1990
+ if (kf.time !== void 0) innerKf.time = kf.time;
1991
+ if (kf.easing !== void 0) innerKf.easing = kf.easing;
1992
+ return innerKf;
1993
+ });
1994
+ const allInnerEmpty = innerKfs.every((kf) => Object.keys(kf.value).length === 0);
1995
+ if (allInnerEmpty) {
1996
+ delete node.animate.transform;
1997
+ if (node.animate && Object.keys(node.animate).length === 0) delete node.animate;
1998
+ } else {
1999
+ node.animate.transform = { keyframes: innerKfs };
2000
+ }
2001
+ didLiftAnimate = true;
2002
+ }
2003
+ }
2004
+ const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
2005
+ const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
2006
+ if (typeof node.transform === "string") {
2007
+ const split = splitTransformString(node.transform);
2008
+ if (stripBodyTranslateOnly) {
2009
+ if (split.translate !== void 0) {
2010
+ if (split.rest) node.transform = split.rest;
2011
+ else delete node.transform;
2012
+ } else if (isPureTranslateBody(node.transform)) {
2013
+ delete node.transform;
2014
+ }
2015
+ } else if (split.translate) {
2016
+ out.transform = split.translate;
2017
+ if (split.rest) node.transform = split.rest;
2018
+ else delete node.transform;
2019
+ }
2020
+ }
2021
+ return out;
2022
+ }
2023
+ function isPureTranslateBody(s) {
2024
+ const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
2025
+ const ops = [];
2026
+ let m;
2027
+ while (m = re.exec(s)) ops.push({ name: m[1], full: m[0] });
2028
+ if (ops.length !== 1) return false;
2029
+ if (ops[0].name === "translate") return true;
2030
+ if (ops[0].name !== "matrix") return false;
2031
+ const args = /matrix\(([^)]*)\)/.exec(ops[0].full);
2032
+ if (!args) return false;
2033
+ const nums = args[1].split(/[\s,]+/).filter(Boolean).map(Number);
2034
+ return nums.length >= 4 && nums[0] === 1 && nums[1] === 0 && nums[2] === 0 && nums[3] === 1;
2035
+ }
2036
+ function splitTransformString(s) {
2037
+ const ops = [];
2038
+ const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
2039
+ let m;
2040
+ while (m = re.exec(s)) ops.push({ name: m[1], full: m[0] });
2041
+ if (!ops.length) return { rest: s || void 0 };
2042
+ if (ops.every((o) => o.name === "translate")) {
2043
+ return { translate: ops.map((o) => o.full).join("") };
2044
+ }
2045
+ const leading = ops[0];
2046
+ const trailing = ops[ops.length - 1];
2047
+ if (trailing.name === "translate" && leading.name === "translate") {
2048
+ const trailingVec = parseTranslateArgs(trailing.full);
2049
+ const leadingVec = parseTranslateArgs(leading.full);
2050
+ const ox = -trailingVec[0];
2051
+ const oy = -trailingVec[1];
2052
+ const userTx = leadingVec[0] - ox;
2053
+ const userTy = leadingVec[1] - oy;
2054
+ if (userTx === 0 && userTy === 0) return { rest: s };
2055
+ const middleAndTrailing = "translate(" + ox + "," + oy + ")" + ops.slice(1).map((o) => o.full).join("");
2056
+ return { translate: "translate(" + userTx + "," + userTy + ")", rest: middleAndTrailing };
2057
+ }
2058
+ if (trailing.name === "translate") return { rest: s };
2059
+ const lifted = [];
2060
+ let i = 0;
2061
+ while (i < ops.length && ops[i].name === "translate") {
2062
+ lifted.push(ops[i].full);
2063
+ i++;
2064
+ }
2065
+ if (!lifted.length) return { rest: s };
2066
+ const rest = ops.slice(i).map((o) => o.full).join("");
2067
+ return {
2068
+ translate: lifted.join(""),
2069
+ rest: rest || void 0
2070
+ };
2071
+ }
2072
+ function parseTranslateArgs(translateOp) {
2073
+ const m = /translate\(([^)]*)\)/.exec(translateOp);
2074
+ if (!m) return [0, 0];
2075
+ const nums = m[1].split(/[\s,]+/).filter(Boolean).map(Number);
2076
+ return [nums[0] || 0, nums[1] || 0];
2077
+ }
2078
+ function splitTransformationEffect(fx) {
2079
+ if (!fx) return {};
2080
+ const originOnOuter = needsOriginOnOuter(fx.translate);
2081
+ const innerHasPivotedPart = fx.rotate !== void 0 || fx.scale !== void 0;
2082
+ const outer = {};
2083
+ const inner = {};
2084
+ if (fx.translate !== void 0) outer.translate = fx.translate;
2085
+ if (originOnOuter && fx.origin !== void 0) outer.origin = fx.origin;
2086
+ if (fx.rotate !== void 0) inner.rotate = fx.rotate;
2087
+ if (fx.scale !== void 0) inner.scale = fx.scale;
2088
+ if (fx.skew !== void 0) inner.skew = fx.skew;
2089
+ if (fx.origin !== void 0 && (!originOnOuter || innerHasPivotedPart)) inner.origin = fx.origin;
2090
+ return {
2091
+ outer: Object.keys(outer).length ? outer : void 0,
2092
+ inner: Object.keys(inner).length ? inner : void 0
2093
+ };
2094
+ }
2095
+ function needsOriginOnOuter(translateAnim) {
2096
+ if (!translateAnim || typeof translateAnim !== "object") return false;
2097
+ const obj = translateAnim;
2098
+ if (obj.autoOrient) return true;
2099
+ if (Array.isArray(obj.keyframes)) {
2100
+ return obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
2101
+ }
2102
+ return false;
2103
+ }
2104
+ function genId(ctx, prefix) {
2105
+ return "_lw_" + prefix + "_" + ctx.nextId++;
2106
+ }
2107
+ function indexById(node, map) {
2108
+ var _a;
2109
+ if (typeof node.id === "string") map.set(node.id, node);
2110
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
2111
+ }
2112
+ function spliceDefs(root, defs) {
2113
+ if (!defs.length) return;
2114
+ const existing = root.children || (root.children = []);
2115
+ existing.unshift({ type: "defs", children: defs });
2116
+ }
2117
+ function clone(value) {
2118
+ if (value === null || typeof value !== "object") return value;
2119
+ if (Array.isArray(value)) return value.map(clone);
2120
+ const out = {};
2121
+ for (const k of Object.keys(value)) out[k] = clone(value[k]);
2122
+ return out;
2123
+ }
2124
+ function regenerateIdsInClone(root, ctx) {
2125
+ const oldToNew = /* @__PURE__ */ new Map();
2126
+ const walkAssign = (n) => {
2127
+ var _a;
2128
+ if (typeof n.id === "string") {
2129
+ const newId = genId(ctx, "retimed");
2130
+ oldToNew.set(n.id, newId);
2131
+ n.id = newId;
2132
+ }
2133
+ (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
2134
+ };
2135
+ walkAssign(root);
2136
+ const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
2137
+ const newId = oldToNew.get(oldId);
2138
+ return newId ? "url(#" + newId + ")" : m;
2139
+ });
2140
+ const walkRewrite = (n) => {
2141
+ var _a;
2142
+ if (typeof n.href === "string" && n.href.startsWith("#")) {
2143
+ const newId = oldToNew.get(n.href.slice(1));
2144
+ if (newId) n.href = "#" + newId;
2145
+ }
2146
+ for (const k of Object.keys(n)) {
2147
+ if (k === "children" || k === "effects" || k === "meta" || k === "href" || k === "id") continue;
2148
+ const v = n[k];
2149
+ if (typeof v === "string" && v.indexOf("url(#") !== -1) n[k] = rewriteUrl(v);
2150
+ }
2151
+ (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
2152
+ };
2153
+ walkRewrite(root);
2154
+ return oldToNew;
2155
+ }
2156
+ function applyMaskedByEffect(node, fx, transformation, ctx) {
2157
+ if (!fx) return node;
2158
+ if (!fx.href) {
2159
+ ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
2160
+ return node;
2161
+ }
2162
+ const maskId = genId(ctx, "mask");
2163
+ let content = { type: "use", href: "#" + fx.href };
2164
+ content = wrapInverseTransform(content, transformation, ctx);
2165
+ const mask = { type: "mask", id: maskId, children: [content] };
2166
+ if (fx.maskType) mask.maskType = fx.maskType;
2167
+ if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
2168
+ if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
2169
+ ctx.defs.push(mask);
2170
+ node.mask = "url(#" + maskId + ")";
2171
+ return node;
2172
+ }
2173
+ function wrapInverseTransform(inner, fx, ctx) {
2174
+ if (!fx) return inner;
2175
+ const origin = readStaticOrigin(fx.origin, ctx);
2176
+ let n = inner;
2177
+ n = wrapInversePart(n, "translate", fx.translate, void 0, ctx);
2178
+ n = wrapInversePart(n, "rotate", fx.rotate, origin, ctx);
2179
+ n = wrapInversePart(n, "scale", fx.scale, origin, ctx);
2180
+ return n;
2181
+ }
2182
+ function wrapInversePart(inner, part, raw, origin, ctx) {
2183
+ if (raw === void 0) return inner;
2184
+ const v = readAnimatable(raw);
2185
+ if (v.kind === "static") {
2186
+ return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
2187
+ }
2188
+ if (v.kind === "animated") {
2189
+ return {
2190
+ type: "g",
2191
+ animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, invertPartValue(part, kf.value), origin))) } },
2192
+ children: [inner]
2193
+ };
2194
+ }
2195
+ return inner;
2196
+ }
2197
+ function invertPartValue(part, value) {
2198
+ if (part === "translate") return [-value[0], -value[1]];
2199
+ if (part === "rotate") return -value;
2200
+ return [1 / value[0], 1 / value[1]];
2201
+ }
2202
+ var CONTENT_SUBREF = "content";
2203
+ function applyRefAndTransformationEffect(node, ref, transformation, ctx) {
2204
+ if (ref) {
2205
+ const baseId = ref.baseId;
2206
+ if (!baseId) {
2207
+ ctx.errors.push("ref: missing baseId");
2208
+ } else {
2209
+ const targetId = ref.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
2210
+ node.href = "#" + targetId;
2211
+ }
2212
+ }
2213
+ return applyTransformationEffect(node, transformation, ctx);
2214
+ }
2215
+ function applyRepeaterEffect(node, fx, ctx) {
2216
+ var _a, _b;
2217
+ if (!fx) return node;
2218
+ const copies = (_a = fx.copies) != null ? _a : 1;
2219
+ if (copies < 1) {
2220
+ ctx.errors.push("repeater.copies invalid: " + fx.copies);
2221
+ return node;
2222
+ }
2223
+ const sharedTransform = node.transform;
2224
+ const sharedAnimTransform = (_b = node.animate) == null ? void 0 : _b.transform;
2225
+ const base = clone(node);
2226
+ delete base.transform;
2227
+ if (base.animate) {
2228
+ delete base.animate.transform;
2229
+ if (Object.keys(base.animate).length === 0) delete base.animate;
2230
+ }
2231
+ const children = [base];
2232
+ for (let i = 1; i < copies; i++) {
2233
+ const copy = clone(base);
2234
+ copy.transform = { value: perCopyParts(fx, i) };
2235
+ children.push(copy);
2236
+ }
2237
+ const wrapper = { type: "g", children };
2238
+ if (sharedTransform !== void 0) wrapper.transform = sharedTransform;
2239
+ if (sharedAnimTransform !== void 0) wrapper.animate = { transform: sharedAnimTransform };
2240
+ return wrapper;
2241
+ }
2242
+ function perCopyParts(fx, i) {
2243
+ const parts = {};
2244
+ if (fx.translate) parts.translate = [fx.translate[0] * i, fx.translate[1] * i];
2245
+ if (fx.rotate !== void 0) parts.rotate = fx.rotate * i;
2246
+ if (fx.scale) parts.scale = [__pow(fx.scale[0] / 100, i), __pow(fx.scale[1] / 100, i)];
2247
+ if (fx.origin) parts.origin = [fx.origin[0] * i, fx.origin[1] * i];
2248
+ return parts;
2249
+ }
2250
+ var RETIME_AS_SYMBOL = true;
2251
+ function applyRetimeEffect(node, retime, ctx) {
2252
+ var _a, _b, _c, _d;
2253
+ if (!retime) return node;
2254
+ const baseId = retime.baseId;
2255
+ if (!baseId) {
2256
+ ctx.errors.push("retime: missing baseId");
2257
+ return node;
2258
+ }
2259
+ const target = ctx.idMap.get(baseId);
2260
+ if (!target) {
2261
+ ctx.warnings.push('retime: target "' + baseId + '" not found');
2262
+ return node;
2263
+ }
2264
+ const start = (_a = retime.start) != null ? _a : 0;
2265
+ const stretch = (_b = retime.stretch) != null ? _b : 1;
2266
+ if (RETIME_AS_SYMBOL) {
2267
+ const symbolClone = clone(target);
2268
+ regenerateIdsInClone(symbolClone, ctx);
2269
+ const cloneId = genId(ctx, "retime");
2270
+ symbolClone.id = cloneId;
2271
+ remapKeyframeTimes(symbolClone, start, stretch);
2272
+ ctx.defs.push(symbolClone);
2273
+ node.href = "#" + cloneId;
2274
+ return node;
2275
+ }
2276
+ const sourceNodes = target.type === "symbol" ? target.children || [] : [target];
2277
+ const content = sourceNodes.map((child) => {
2278
+ const c = clone(child);
2279
+ regenerateIdsInClone(c, ctx);
2280
+ remapKeyframeTimes(c, start, stretch);
2281
+ return c;
2282
+ });
2283
+ const g = __spreadProps(__spreadValues({}, node), { type: "g", children: content });
2284
+ delete g.href;
2285
+ const x = Number((_c = node.x) != null ? _c : 0), y = Number((_d = node.y) != null ? _d : 0);
2286
+ if (x || y) {
2287
+ const offset = "translate(" + x + "," + y + ")";
2288
+ g.transform = typeof g.transform === "string" ? offset + g.transform : offset;
2289
+ delete g.x;
2290
+ delete g.y;
2291
+ }
2292
+ return g;
2293
+ }
2294
+ function remapKeyframeTimes(node, start, stretch) {
2295
+ var _a;
2296
+ const remap2 = (kfs) => {
2297
+ for (const kf of kfs) if (typeof kf.time === "number") kf.time = start + kf.time * stretch;
2298
+ };
2299
+ if (node.transform && typeof node.transform === "object" && Array.isArray(node.transform.keyframes)) {
2300
+ remap2(node.transform.keyframes);
2301
+ }
2302
+ if (node.animate && typeof node.animate === "object") {
2303
+ for (const prop of Object.keys(node.animate)) {
2304
+ const anim = node.animate[prop];
2305
+ if (anim && Array.isArray(anim.keyframes)) remap2(anim.keyframes);
2306
+ }
2307
+ }
2308
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => remapKeyframeTimes(child, start, stretch));
2309
+ }
2310
+ function applyTrimPathEffect(node, trimPath, isCombinedShape) {
2311
+ var _a;
2312
+ if (!trimPath && !isCombinedShape) return node;
2313
+ const d = (_a = node.d) != null ? _a : rectToPathD(node);
2314
+ if (d === void 0) return node;
2315
+ const g = __spreadProps(__spreadValues({}, node), { type: "g" });
2316
+ delete g.d;
2317
+ const meta = g.meta = __spreadValues({}, g.meta || {});
2318
+ const effects = meta.effects = __spreadValues({}, meta.effects || {});
2319
+ if (trimPath) effects.trimPath = trimPath;
2320
+ effects.isCombinedShape = true;
2321
+ g.children = [{ type: "path", d }];
2322
+ return g;
2323
+ }
2324
+ function rectToPathD(node) {
2325
+ var _a, _b, _c, _d;
2326
+ if (node.type !== "rect") return void 0;
2327
+ const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
2328
+ const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
2329
+ return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
2330
+ }
2331
+ function applyPlayerEffects(root) {
2332
+ const ctx = {
2333
+ defs: [],
2334
+ warnings: [],
2335
+ errors: [],
2336
+ idMap: /* @__PURE__ */ new Map(),
2337
+ nextId: 0,
2338
+ contentRefInnerIds: /* @__PURE__ */ new Map()
2339
+ };
2340
+ const working = clone(root);
2341
+ indexById(working, ctx.idMap);
2342
+ identifyContentRefTargets(working, ctx, () => genId(ctx, "inner"));
2343
+ const afterPass1 = applyPlayerEffects_exceptRetime(working, ctx);
2344
+ const out = applyPlayerEffects_retime(afterPass1, ctx);
2345
+ spliceDefs(out, ctx.defs);
2346
+ return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
2347
+ }
2348
+ function applyPlayerEffects_exceptRetime(node, ctx) {
2349
+ if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
2350
+ const fx = node.effects;
2351
+ const originalId = typeof node.id === "string" ? node.id : void 0;
2352
+ const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
2353
+ if (!fx && !innerIdForContentRef) return node;
2354
+ const { transformation, repeater, maskedBy, trimPath, retime, ref } = fx != null ? fx : {};
2355
+ const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
2356
+ if (fx) delete node.effects;
2357
+ let n = node;
2358
+ n = applyTrimPathEffect(n, trimPath, isCombinedShape);
2359
+ n = applyRepeaterEffect(n, repeater, ctx);
2360
+ n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
2361
+ if (innerIdForContentRef) {
2362
+ n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
2363
+ } else {
2364
+ n = applyRefAndTransformationEffect(n, ref, transformation, ctx);
2365
+ }
2366
+ if (retime) node.effects = { retime };
2367
+ if (originalId) ctx.idMap.set(originalId, n);
2368
+ return n;
2369
+ }
2370
+ function applyPlayerEffects_retime(node, ctx) {
2371
+ var _a;
2372
+ if (node.children) node.children = node.children.map((child) => applyPlayerEffects_retime(child, ctx));
2373
+ const retime = (_a = node.effects) == null ? void 0 : _a.retime;
2374
+ if (!retime) return node;
2375
+ delete node.effects;
2376
+ return applyRetimeEffect(node, retime, ctx);
2377
+ }
2378
+ function pathStr(path) {
2379
+ if (!path.length) return ".";
2380
+ let result = "";
2381
+ for (const seg of path) {
2382
+ if (seg.startsWith("[")) result += seg;
2383
+ else result += (result ? "." : "") + seg;
2384
+ }
2385
+ return result;
2386
+ }
2387
+ var Base = class {
2388
+ _canSanitize(raw) {
2389
+ return this.isValid(raw);
2390
+ }
2391
+ optional() {
2392
+ return new Optional(this);
2393
+ }
2394
+ };
2395
+ var Optional = class extends Base {
2396
+ constructor(inner) {
2397
+ super();
2398
+ this.inner = inner;
2399
+ this._default = void 0;
2400
+ }
2401
+ sanitize(raw) {
2402
+ if (raw === void 0 || raw === null) return void 0;
2403
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
2404
+ }
2405
+ isValid(raw, ctx, path) {
2406
+ if (raw === void 0 || raw === null) return true;
2407
+ return this.inner.isValid(raw, ctx, path);
2408
+ }
2409
+ _canSanitize(raw) {
2410
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
2411
+ }
2412
+ };
2413
+ var Str = class extends Base {
2414
+ constructor(_default = "") {
2415
+ super();
2416
+ this._default = _default;
2417
+ }
2418
+ sanitize(raw) {
2419
+ return typeof raw === "string" ? raw : this._default;
2420
+ }
2421
+ isValid(raw, ctx, path) {
2422
+ if (typeof raw === "string") return true;
2423
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
2424
+ return false;
2425
+ }
2426
+ };
2427
+ var Num = class extends Base {
2428
+ constructor(_default = 0) {
2429
+ super();
2430
+ this._default = _default;
2431
+ }
2432
+ sanitize(raw) {
2433
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
2434
+ }
2435
+ isValid(raw, ctx, path) {
2436
+ if (typeof raw === "number" && isFinite(raw)) return true;
2437
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
2438
+ return false;
2439
+ }
2440
+ };
2441
+ var Bool = class extends Base {
2442
+ constructor(_default = false) {
2443
+ super();
2444
+ this._default = _default;
2445
+ }
2446
+ sanitize(raw) {
2447
+ return typeof raw === "boolean" ? raw : this._default;
2448
+ }
2449
+ isValid(raw, ctx, path) {
2450
+ if (typeof raw === "boolean") return true;
2451
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
2452
+ return false;
2453
+ }
2454
+ };
2455
+ var Literal = class extends Base {
2456
+ constructor(value) {
2457
+ super();
2458
+ this.value = value;
2459
+ this._default = value;
2460
+ }
2461
+ sanitize(raw) {
2462
+ return raw === this.value ? this.value : this._default;
2463
+ }
2464
+ isValid(raw, ctx, path) {
2465
+ if (raw === this.value) return true;
2466
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
2467
+ return false;
2468
+ }
2469
+ };
2470
+ var Enum = class extends Base {
2471
+ constructor(values, defaultVal) {
2472
+ super();
2473
+ this.values = values;
2474
+ this._default = defaultVal != null ? defaultVal : values[0];
2475
+ }
2476
+ sanitize(raw) {
2477
+ return this.values.includes(raw) ? raw : this._default;
2478
+ }
2479
+ isValid(raw, ctx, path) {
2480
+ if (this.values.includes(raw)) return true;
2481
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected one of " + this.values.map((v) => JSON.stringify(v)).join(" | ") + ", got " + JSON.stringify(raw));
2482
+ return false;
2483
+ }
2484
+ };
2485
+ var Union = class extends Base {
2486
+ constructor(schemas, defaultVal) {
2487
+ super();
2488
+ this.schemas = schemas;
2489
+ this._default = defaultVal != null ? defaultVal : schemas[0]._default;
2490
+ }
2491
+ sanitize(raw) {
2492
+ for (const s of this.schemas) {
2493
+ if (s.isValid(raw)) return s.sanitize(raw);
2494
+ }
2495
+ return this._default;
2496
+ }
2497
+ isValid(raw, ctx, path) {
2498
+ var _a;
2499
+ if (this.schemas.some((s) => s.isValid(raw))) return true;
2500
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a = JSON.stringify(raw)) != null ? _a : "").slice(0, 60));
2501
+ return false;
2502
+ }
2503
+ _canSanitize(raw) {
2504
+ return this.schemas.some((s) => s._canSanitize(raw));
2505
+ }
2506
+ };
2507
+ var DiscriminatedUnion = class extends Base {
2508
+ constructor(_key, _schemas, defaultVal) {
2509
+ super();
2510
+ this._key = _key;
2511
+ this._schemas = _schemas;
2512
+ this._default = defaultVal != null ? defaultVal : _schemas[0]._default;
2513
+ this._map = /* @__PURE__ */ new Map();
2514
+ for (const s of _schemas) {
2515
+ const keySchema = s._shape[_key];
2516
+ if (keySchema) this._map.set(keySchema._default, s);
2517
+ }
2518
+ }
2519
+ _findSchema(raw) {
2520
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
2521
+ const val = raw[this._key];
2522
+ if (val === void 0 || val === null) return void 0;
2523
+ return this._map.get(val);
2524
+ }
2525
+ sanitize(raw) {
2526
+ var _a;
2527
+ return ((_a = this._findSchema(raw)) != null ? _a : this._schemas[0]).sanitize(raw);
2528
+ }
2529
+ isValid(raw, ctx, path) {
2530
+ const schema = this._findSchema(raw);
2531
+ if (!schema) {
2532
+ const val = raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw[this._key] : void 0;
2533
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no discriminated union member matched " + this._key + "=" + JSON.stringify(val));
2534
+ return false;
2535
+ }
2536
+ return schema.isValid(raw, ctx, path);
2537
+ }
2538
+ _canSanitize(raw) {
2539
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return false;
2540
+ const schema = this._findSchema(raw);
2541
+ return schema ? schema._canSanitize(raw) : this._schemas[0]._canSanitize(raw);
2542
+ }
2543
+ };
2544
+ var Obj = class extends Base {
2545
+ constructor(_shape) {
2546
+ super();
2547
+ this._shape = _shape;
2548
+ const d = {};
2549
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
2550
+ this._default = d;
2551
+ }
2552
+ sanitize(raw) {
2553
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
2554
+ const out = {};
2555
+ for (const key of Object.keys(this._shape)) {
2556
+ out[key] = this._shape[key].sanitize(src[key]);
2557
+ }
2558
+ return out;
2559
+ }
2560
+ isValid(raw, ctx, path) {
2561
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
2562
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
2563
+ return false;
2564
+ }
2565
+ const obj = raw;
2566
+ const p = path != null ? path : [];
2567
+ let ok = true;
2568
+ for (const key of Object.keys(this._shape)) {
2569
+ p.push(key);
2570
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
2571
+ p.pop();
2572
+ }
2573
+ if (ctx == null ? void 0 : ctx.strict) {
2574
+ for (const key of Object.keys(obj)) {
2575
+ if (key in this._shape) continue;
2576
+ p.push(key);
2577
+ ctx.errors.push(pathStr(p) + ": unexpected extra key");
2578
+ p.pop();
2579
+ ok = false;
2580
+ }
2581
+ }
2582
+ return ok;
2583
+ }
2584
+ _canSanitize(raw) {
2585
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
2586
+ }
2587
+ };
2588
+ var OpenObj = class extends Base {
2589
+ constructor(_shape, _openSchema) {
2590
+ super();
2591
+ this._shape = _shape;
2592
+ this._openSchema = _openSchema;
2593
+ const d = {};
2594
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
2595
+ this._default = d;
2596
+ }
2597
+ sanitize(raw) {
2598
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
2599
+ const out = __spreadValues({}, src);
2600
+ for (const key of Object.keys(this._shape)) {
2601
+ out[key] = this._shape[key].sanitize(src[key]);
2602
+ }
2603
+ if (this._openSchema) {
2604
+ for (const key of Object.keys(src)) {
2605
+ if (!(key in this._shape)) out[key] = this._openSchema.sanitize(src[key]);
2606
+ }
2607
+ }
2608
+ return out;
2609
+ }
2610
+ isValid(raw, ctx, path) {
2611
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
2612
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
2613
+ return false;
2614
+ }
2615
+ const obj = raw;
2616
+ const p = path != null ? path : [];
2617
+ let ok = true;
2618
+ for (const key of Object.keys(this._shape)) {
2619
+ p.push(key);
2620
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
2621
+ p.pop();
2622
+ }
2623
+ if (this._openSchema) {
2624
+ for (const key of Object.keys(obj)) {
2625
+ if (key in this._shape) continue;
2626
+ p.push(key);
2627
+ if (!this._openSchema.isValid(obj[key], ctx, p)) ok = false;
2628
+ p.pop();
2629
+ }
2630
+ }
2631
+ return ok;
2632
+ }
2633
+ _canSanitize(raw) {
2634
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
2635
+ }
2636
+ };
2637
+ var Arr = class extends Base {
2638
+ constructor(item) {
2639
+ super();
2640
+ this.item = item;
2641
+ this._default = [];
2642
+ }
2643
+ sanitize(raw) {
2644
+ if (!Array.isArray(raw)) return [];
2645
+ const out = [];
2646
+ for (const el of raw) {
2647
+ if (this.item._canSanitize(el)) out.push(this.item.sanitize(el));
2648
+ }
2649
+ return out;
2650
+ }
2651
+ isValid(raw, ctx, path) {
2652
+ if (!Array.isArray(raw)) {
2653
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected array, got " + typeof raw);
2654
+ return false;
2655
+ }
2656
+ const p = path != null ? path : [];
2657
+ let ok = true;
2658
+ for (let i = 0; i < raw.length; i++) {
2659
+ p.push("[" + i + "]");
2660
+ if (!this.item.isValid(raw[i], ctx, p)) ok = false;
2661
+ p.pop();
2662
+ }
2663
+ return ok;
2664
+ }
2665
+ _canSanitize(raw) {
2666
+ return Array.isArray(raw);
2667
+ }
2668
+ };
2669
+ var Rec = class extends Base {
2670
+ constructor(value) {
2671
+ super();
2672
+ this.value = value;
2673
+ this._default = {};
2674
+ }
2675
+ sanitize(raw) {
2676
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
2677
+ const out = {};
2678
+ for (const [k, v] of Object.entries(raw)) {
2679
+ if (this.value._canSanitize(v)) out[k] = this.value.sanitize(v);
2680
+ }
2681
+ return out;
2682
+ }
2683
+ isValid(raw, ctx, path) {
2684
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
2685
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object/record, got " + (Array.isArray(raw) ? "array" : typeof raw));
2686
+ return false;
2687
+ }
2688
+ const p = path != null ? path : [];
2689
+ let ok = true;
2690
+ for (const [k, v] of Object.entries(raw)) {
2691
+ p.push(k);
2692
+ if (!this.value.isValid(v, ctx, p)) ok = false;
2693
+ p.pop();
2694
+ }
2695
+ return ok;
2696
+ }
2697
+ _canSanitize(raw) {
2698
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
2699
+ }
2700
+ };
2701
+ var Any = class extends Base {
2702
+ constructor() {
2703
+ super(...arguments);
2704
+ this._default = void 0;
2705
+ }
2706
+ sanitize(raw) {
2707
+ return raw;
2708
+ }
2709
+ isValid(_raw, _ctx, _path) {
2710
+ return true;
2711
+ }
2712
+ _canSanitize(_raw) {
2713
+ return true;
2714
+ }
2715
+ };
2716
+ var Lazy = class extends Base {
2717
+ constructor(fn, _default) {
2718
+ super();
2719
+ this.fn = fn;
2720
+ this._default = _default;
2721
+ this.resolved = null;
2722
+ }
2723
+ get schema() {
2724
+ var _a;
2725
+ return (_a = this.resolved) != null ? _a : this.resolved = this.fn();
2726
+ }
2727
+ sanitize(raw) {
2728
+ return this.schema.sanitize(raw);
2729
+ }
2730
+ isValid(raw, ctx, path) {
2731
+ return this.schema.isValid(raw, ctx, path);
2732
+ }
2733
+ _canSanitize(raw) {
2734
+ return this.schema._canSanitize(raw);
2735
+ }
2736
+ };
2737
+ var Tuple = class extends Base {
2738
+ constructor(schemas) {
2739
+ super();
2740
+ this.schemas = schemas;
2741
+ this._default = schemas.map((s) => s._default);
2742
+ }
2743
+ sanitize(raw) {
2744
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) return this._default;
2745
+ return this.schemas.map((s, i) => s.sanitize(raw[i]));
2746
+ }
2747
+ isValid(raw, ctx, path) {
2748
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) {
2749
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected tuple of length " + this.schemas.length + ", got " + (Array.isArray(raw) ? "array[" + raw.length + "]" : typeof raw));
2750
+ return false;
2751
+ }
2752
+ const p = path != null ? path : [];
2753
+ let ok = true;
2754
+ for (let i = 0; i < this.schemas.length; i++) {
2755
+ p.push("[" + i + "]");
2756
+ if (!this.schemas[i].isValid(raw[i], ctx, p)) ok = false;
2757
+ p.pop();
2758
+ }
2759
+ return ok;
2760
+ }
2761
+ // Require exact length so wrong-length arrays are dropped rather than repaired to default.
2762
+ _canSanitize(raw) {
2763
+ return Array.isArray(raw) && raw.length === this.schemas.length;
2764
+ }
2765
+ };
2766
+ function implementsInterface() {
2767
+ return (schema) => schema;
2768
+ }
2769
+ var px = {
2770
+ /** Matches a string. Default: '' or provided value. */
2771
+ string: (defaultVal = "") => new Str(defaultVal),
2772
+ /** Matches a finite number. Default: 0 or provided value. */
2773
+ number: (defaultVal = 0) => new Num(defaultVal),
2774
+ /** Matches a boolean. Default: false or provided value. */
2775
+ boolean: (defaultVal = false) => new Bool(defaultVal),
2776
+ /** Matches one exact primitive value; its default is the value itself. */
2777
+ literal: (value) => new Literal(value),
2778
+ /** Matches one of a fixed set of string/number values. Default: first value. */
2779
+ enum: (values, defaultVal) => new Enum(values, defaultVal),
2780
+ /**
2781
+ * Returns the first schema whose isValid passes.
2782
+ * TypeScript infers the union of all member types automatically.
2783
+ */
2784
+ union: (schemas, defaultVal) => new Union(schemas, defaultVal),
2785
+ /**
2786
+ * Discriminated union — reads `raw[key]`, finds the member schema whose
2787
+ * literal at `key` matches, then delegates sanitize/isValid to that member.
2788
+ * Each member must be an object schema with a `px.literal(...)` at `key`.
2789
+ * TypeScript infers the union of all member types automatically.
2790
+ */
2791
+ discriminatedUnion: (key, schemas) => new DiscriminatedUnion(key, schemas),
2792
+ /** Typed object — unknown keys are stripped. Required fields fall back to their default. */
2793
+ object: (shape) => new Obj(shape),
2794
+ /**
2795
+ * Open object — validates known keys; passes unknown keys through as-is,
2796
+ * or validates/sanitizes them against `openSchema` when provided.
2797
+ */
2798
+ openObject: (shape, openSchema) => new OpenObj(shape, openSchema),
2799
+ /**
2800
+ * Creates a new closed object schema by merging a base schema's shape with additional fields.
2801
+ * The base can be the result of px.object() or px.openObject() — anything with a _shape property.
2802
+ *
2803
+ * @example
2804
+ * const PxSvgNodeSchema = px.extendedObject(PxNodeBase, { width: px.number().optional() });
2805
+ */
2806
+ extendedObject: (base, extra) => new Obj(__spreadValues(__spreadValues({}, base._shape), extra)),
2807
+ /** Array whose unrecoverable items are filtered out. Default: []. */
2808
+ array: (item) => new Arr(item),
2809
+ /** String-keyed record whose unrecoverable values are dropped. Default: {}. */
2810
+ record: (value) => new Rec(value),
2811
+ /** Passes anything through unchanged — always valid. */
2812
+ any: () => new Any(),
2813
+ /** Fixed-length tuple — validates element count and each position individually. */
2814
+ tuple: (schemas) => new Tuple(schemas),
2815
+ /** Defers schema creation — required for recursive types. Must supply a default value. */
2816
+ lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
2817
+ };
1798
2818
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1799
2819
  var PX_ANIM_ATTR_NAME = "_px_animator";
1800
- var ANIMATE_ATTR = "animate";
1801
2820
  var TEXT_ATTR = "text";
1802
2821
  var TEXT_CONTENT_ATTR = "textContent";
1803
2822
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1804
2823
  "type",
1805
2824
  "children",
1806
- ANIMATE_ATTR,
1807
2825
  "animator",
1808
2826
  "meta",
1809
- "defs",
1810
- "bindings",
2827
+ "animate",
1811
2828
  TEXT_ATTR,
1812
2829
  TEXT_CONTENT_ATTR
1813
2830
  ]);
2831
+ var PxEasingOrRefSchema = px.union([
2832
+ px.string(),
2833
+ px.tuple([px.number(), px.number(), px.number(), px.number()])
2834
+ ]);
2835
+ var PxKeyframeValueSchema = implementsInterface()(px.union([
2836
+ px.string(),
2837
+ // e.g. for colors
2838
+ px.number(),
2839
+ px.array(px.number()),
2840
+ px.lazy(() => PxTransformPartsSchema, {}),
2841
+ px.object({ path: px.string() }),
2842
+ px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] })
2843
+ ]));
2844
+ var PxKeyframeSchema = implementsInterface()(px.object({
2845
+ time: px.number().optional(),
2846
+ t: px.number().optional(),
2847
+ value: px.any().optional(),
2848
+ v: px.any().optional(),
2849
+ easing: PxEasingOrRefSchema.optional(),
2850
+ e: PxEasingOrRefSchema.optional(),
2851
+ tangentOut: px.tuple([px.number(), px.number()]).optional(),
2852
+ to: px.tuple([px.number(), px.number()]).optional(),
2853
+ // short alias
2854
+ tangentIn: px.tuple([px.number(), px.number()]).optional(),
2855
+ ti: px.tuple([px.number(), px.number()]).optional(),
2856
+ // short alias
2857
+ selected: px.boolean().optional()
2858
+ // editor-side UI state (Player ignores it)
2859
+ }));
2860
+ var PxLoopSchema = implementsInterface()(px.object({
2861
+ segmentCount: px.number().optional(),
2862
+ before: px.boolean().optional(),
2863
+ alternate: px.boolean().optional()
2864
+ }));
2865
+ var PxPropertyAnimationSchema = implementsInterface()(px.object({
2866
+ keyframes: px.array(PxKeyframeSchema).optional(),
2867
+ kfs: px.array(PxKeyframeSchema).optional(),
2868
+ loop: px.union([PxLoopSchema, px.boolean()]).optional(),
2869
+ autoOrient: px.boolean().optional()
2870
+ }));
2871
+ var PxTransformPartsSchema = implementsInterface()(px.object({
2872
+ translate: px.tuple([px.number(), px.number()]).optional(),
2873
+ rotate: px.number().optional(),
2874
+ scale: px.tuple([px.number(), px.number()]).optional(),
2875
+ origin: px.tuple([px.number(), px.number()]).optional()
2876
+ }));
2877
+ var PxTransformValueSchema = px.union([
2878
+ px.string(),
2879
+ px.object({ value: PxTransformPartsSchema }),
2880
+ PxPropertyAnimationSchema
2881
+ ]);
2882
+ var PxAnimationDefinitionSchema = implementsInterface()(
2883
+ px.record(PxPropertyAnimationSchema)
2884
+ );
2885
+ var PxElementAnimationSchema = implementsInterface()(px.union([
2886
+ px.string(),
2887
+ px.array(px.union([px.string(), PxAnimationDefinitionSchema])),
2888
+ PxAnimationDefinitionSchema
2889
+ ]));
2890
+ var PxTriggerSchema = implementsInterface()(px.object({
2891
+ startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
2892
+ outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
2893
+ scrollIntoViewThreshold: px.number().optional()
2894
+ }));
2895
+ var PxDefsSchema = implementsInterface()(px.object({
2896
+ easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
2897
+ animations: px.record(PxAnimationDefinitionSchema).optional(),
2898
+ styles: px.record(px.any()).optional()
2899
+ }));
2900
+ var PxAnimatorConfigSchema = implementsInterface()(px.object({
2901
+ mode: px.enum(["auto", "webapi", "frames"]).optional(),
2902
+ duration: px.number().optional(),
2903
+ delay: px.number().optional(),
2904
+ iterations: px.union([px.number(), px.literal("infinite")]).optional(),
2905
+ fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
2906
+ direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
2907
+ frameRate: px.number().optional(),
2908
+ trigger: PxTriggerSchema.optional(),
2909
+ definitions: PxDefsSchema.optional(),
2910
+ animate: px.record(PxElementAnimationSchema).optional(),
2911
+ debug: px.boolean().optional(),
2912
+ debugInstName: px.string().optional()
2913
+ }));
2914
+ var PxBindingSchema = implementsInterface()(px.object({
2915
+ id: px.string(),
2916
+ animate: PxElementAnimationSchema
2917
+ }));
2918
+ var PxAttrValueSchema = px.union([
2919
+ px.string(),
2920
+ px.number(),
2921
+ px.object({ value: px.any() }),
2922
+ PxPropertyAnimationSchema
2923
+ ]);
2924
+ var PxAnimatableNumberSchema = px.union([
2925
+ px.number(),
2926
+ px.object({ value: px.number() }),
2927
+ px.object({
2928
+ keyframes: px.array(PxKeyframeSchema),
2929
+ autoOrient: px.boolean().optional()
2930
+ })
2931
+ ]);
2932
+ var PxAnimatableVec2Schema = px.union([
2933
+ px.tuple([px.number(), px.number()]),
2934
+ px.object({ value: px.tuple([px.number(), px.number()]) }),
2935
+ px.object({
2936
+ keyframes: px.array(PxKeyframeSchema),
2937
+ autoOrient: px.boolean().optional()
2938
+ })
2939
+ ]);
2940
+ var PxTransformationEffectSchema = px.object({
2941
+ translate: PxAnimatableVec2Schema.optional(),
2942
+ rotate: PxAnimatableNumberSchema.optional(),
2943
+ scale: PxAnimatableVec2Schema.optional(),
2944
+ skew: PxAnimatableVec2Schema.optional(),
2945
+ origin: PxAnimatableVec2Schema.optional()
2946
+ });
2947
+ var PxRepeaterEffectSchema = px.object({
2948
+ copies: px.number().optional(),
2949
+ translate: px.tuple([px.number(), px.number()]).optional(),
2950
+ rotate: px.number().optional(),
2951
+ scale: px.tuple([px.number(), px.number()]).optional(),
2952
+ // per-copy scale, PERCENT (85 → 0.85)
2953
+ origin: px.tuple([px.number(), px.number()]).optional()
2954
+ });
2955
+ var PxMaskedByEffectSchema = px.object({
2956
+ href: px.string().optional(),
2957
+ maskType: px.string().optional(),
2958
+ maskUnits: px.string().optional(),
2959
+ maskContentUnits: px.string().optional()
2960
+ });
2961
+ var PxTrimPathEffectSchema = px.any();
2962
+ var PxRetimeEffectSchema = px.object({
2963
+ baseId: px.string().optional(),
2964
+ start: px.number().optional(),
2965
+ stretch: px.number().optional(),
2966
+ timeCrop: px.tuple([px.number(), px.number()]).optional()
2967
+ });
2968
+ var PxRefEffectSchema = px.object({
2969
+ baseId: px.string().optional(),
2970
+ type: px.string().optional()
2971
+ });
2972
+ var PxEffectsSchema = px.object({
2973
+ transformation: PxTransformationEffectSchema.optional(),
2974
+ repeater: PxRepeaterEffectSchema.optional(),
2975
+ maskedBy: PxMaskedByEffectSchema.optional(),
2976
+ trimPath: PxTrimPathEffectSchema.optional(),
2977
+ retime: PxRetimeEffectSchema.optional(),
2978
+ isCombinedShape: px.boolean().optional(),
2979
+ ref: PxRefEffectSchema.optional()
2980
+ });
2981
+ function validateNodeEffects(root, opts) {
2982
+ const warnings = [];
2983
+ const walk = (node, path) => {
2984
+ if (node && node.effects) {
2985
+ const ctx = { errors: [], warnings: [], strict: !!(opts == null ? void 0 : opts.strict) };
2986
+ const ok = PxEffectsSchema.isValid(node.effects, ctx, [path + ".effects"]);
2987
+ if (!ok) {
2988
+ for (const err of ctx.errors) warnings.push(err);
2989
+ }
2990
+ }
2991
+ if (node && Array.isArray(node.children)) {
2992
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]"));
2993
+ }
2994
+ };
2995
+ walk(root, "root");
2996
+ return warnings;
2997
+ }
2998
+ var PxNodeBase = px.openObject({
2999
+ type: px.string(),
3000
+ id: px.string().optional(),
3001
+ meta: px.any().optional(),
3002
+ // Player-effects bucket emitted by the Editor's lightweight design format.
3003
+ // Consumed and removed by `applyPlayerEffects` before any other normalisation
3004
+ // (see `createAnimatorImpl`), so downstream code never sees it.
3005
+ effects: PxEffectsSchema.optional(),
3006
+ animate: PxAnimationDefinitionSchema.optional(),
3007
+ style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
3008
+ }, PxAttrValueSchema);
3009
+ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
3010
+ children: px.lazy(() => px.array(PxNodeSchema), []).optional()
3011
+ }), PxAttrValueSchema);
3012
+ var PxSvgNodeExtra = px.object({
3013
+ width: px.number().optional(),
3014
+ height: px.number().optional(),
3015
+ viewBox: px.string().optional(),
3016
+ animator: PxAnimatorConfigSchema.optional()
3017
+ });
3018
+ var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
3019
+ type: px.literal("svg"),
3020
+ // override string → literal to require 'svg'
3021
+ children: px.array(PxNodeSchema).optional()
3022
+ }), PxAttrValueSchema);
3023
+ var PxBezierPathSchema = implementsInterface()(px.object({
3024
+ v: px.array(px.array(px.number())),
3025
+ i: px.array(px.array(px.number())).optional(),
3026
+ o: px.array(px.array(px.number())).optional(),
3027
+ c: px.boolean().optional()
3028
+ }));
1814
3029
  function isPxElementFileFormat(fileJson) {
1815
3030
  if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
1816
3031
  return false;
@@ -1824,12 +3039,14 @@ var PixodeskAnimatorReact = (() => {
1824
3039
  function getDefs(doc) {
1825
3040
  var _a;
1826
3041
  if (!doc) return void 0;
1827
- return doc.defs || ((_a = doc.meta) == null ? void 0 : _a.defs);
3042
+ return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
1828
3043
  }
1829
3044
  function getBindings(doc) {
1830
3045
  var _a;
1831
3046
  if (!doc) return void 0;
1832
- return doc.bindings || ((_a = doc.meta) == null ? void 0 : _a.bindings);
3047
+ const animate = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animate;
3048
+ if (!animate) return void 0;
3049
+ return Object.entries(animate).map(([id, anim]) => ({ id, animate: anim }));
1833
3050
  }
1834
3051
  function bezierToSvgPath(path) {
1835
3052
  var _a, _b, _c, _d;
@@ -2063,6 +3280,24 @@ var PixodeskAnimatorReact = (() => {
2063
3280
  var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
2064
3281
  var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
2065
3282
  var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
3283
+ function composeTransformParts(parts, opts) {
3284
+ var _a;
3285
+ if (!parts) return "";
3286
+ const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
3287
+ const segs = [];
3288
+ const t = parts.translate;
3289
+ const o = parts.origin;
3290
+ const r = parts.rotate;
3291
+ const s = parts.scale;
3292
+ const tu = withUnits ? "px" : "";
3293
+ const ru = withUnits ? "deg" : "";
3294
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
3295
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
3296
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
3297
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
3298
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
3299
+ return segs.join("");
3300
+ }
2066
3301
  var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
2067
3302
  var DEFAULT_DURATION_MS = 1e3;
2068
3303
  function kebabToCamelCaseWord(kebab) {
@@ -2122,6 +3357,80 @@ var PixodeskAnimatorReact = (() => {
2122
3357
  function clamp(value, min, max) {
2123
3358
  return Math.max(min, Math.min(value, max));
2124
3359
  }
3360
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
3361
+ if (t <= 0) return [P0[0], P0[1]];
3362
+ if (t >= 1) return [P3[0], P3[1]];
3363
+ const u = 1 - t;
3364
+ const u2 = u * u;
3365
+ const u3 = u2 * u;
3366
+ const t2 = t * t;
3367
+ const t3 = t2 * t;
3368
+ const w0 = u3;
3369
+ const w1 = 3 * t * u2;
3370
+ const w2 = 3 * t2 * u;
3371
+ const w3 = t3;
3372
+ return [
3373
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
3374
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
3375
+ ];
3376
+ }
3377
+ var BEZIER_T_NUDGE = 1e-4;
3378
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
3379
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
3380
+ if (result[0] === 0 && result[1] === 0) {
3381
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
3382
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
3383
+ }
3384
+ return result;
3385
+ }
3386
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
3387
+ const u = 1 - t;
3388
+ const a = 3 * u * u;
3389
+ const b = 6 * t * u;
3390
+ const c = 3 * t * t;
3391
+ return [
3392
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
3393
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
3394
+ ];
3395
+ }
3396
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
3397
+ const n = steps + 1;
3398
+ const ts = new Float64Array(n);
3399
+ const ds = new Float64Array(n);
3400
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
3401
+ ts[0] = 0;
3402
+ ds[0] = 0;
3403
+ let cum = 0;
3404
+ for (let i = 1; i < n; i++) {
3405
+ const t = i / steps;
3406
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
3407
+ const dx = cur[0] - prev[0];
3408
+ const dy = cur[1] - prev[1];
3409
+ cum += Math.sqrt(dx * dx + dy * dy);
3410
+ ts[i] = t;
3411
+ ds[i] = cum;
3412
+ prev = cur;
3413
+ }
3414
+ return { ts, ds };
3415
+ }
3416
+ function bezier2D_tForDistance(lut, distance) {
3417
+ const { ts, ds } = lut;
3418
+ const last = ds.length - 1;
3419
+ if (distance <= 0) return ts[0];
3420
+ if (distance >= ds[last]) return ts[last];
3421
+ let lo = 1;
3422
+ let hi = last;
3423
+ while (lo < hi) {
3424
+ const mid = lo + hi >>> 1;
3425
+ if (ds[mid] < distance) lo = mid + 1;
3426
+ else hi = mid;
3427
+ }
3428
+ const dPrev = ds[hi - 1];
3429
+ const dCur = ds[hi];
3430
+ const span = dCur - dPrev;
3431
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
3432
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
3433
+ }
2125
3434
  var SVG_NS = "http://www.w3.org/2000/svg";
2126
3435
  var ALLOWED_SVG_TAGS_LOWER_CASE = new Set([
2127
3436
  "svg",
@@ -2135,6 +3444,7 @@ var PixodeskAnimatorReact = (() => {
2135
3444
  "polygon",
2136
3445
  "text",
2137
3446
  "tspan",
3447
+ "textPath",
2138
3448
  "defs",
2139
3449
  "clipPath",
2140
3450
  "mask",
@@ -2175,13 +3485,21 @@ var PixodeskAnimatorReact = (() => {
2175
3485
  // Don't allow 'cursor', can use external SVG, // url(cursor.svg)
2176
3486
  ];
2177
3487
  var ALLOWED_RESOURCE_ATTRIBUTES_SET = new Set(ALLOWED_RESOURCE_ATTRIBUTES);
2178
- var ALLOWED_ATTRIBUTES_SET = /* @__PURE__ */ new Set([
3488
+ var ALLOWED_ATTRIBUTES = [
2179
3489
  "href",
2180
3490
  "src",
2181
3491
  // Presentation
2182
3492
  "fill",
3493
+ "fillOpacity",
3494
+ "fillRule",
2183
3495
  "stroke",
2184
3496
  "strokeWidth",
3497
+ "strokeOpacity",
3498
+ "strokeLinecap",
3499
+ "strokeLinejoin",
3500
+ "strokeMiterlimit",
3501
+ "strokeDasharray",
3502
+ "strokeDashoffset",
2185
3503
  "opacity",
2186
3504
  "transform",
2187
3505
  // Geometry
@@ -2200,10 +3518,27 @@ var PixodeskAnimatorReact = (() => {
2200
3518
  "x2",
2201
3519
  "y2",
2202
3520
  "points",
2203
- // Text
3521
+ "dx",
3522
+ "dy",
3523
+ // Font
2204
3524
  "fontSize",
2205
3525
  "fontFamily",
3526
+ "fontWeight",
3527
+ "fontStyle",
3528
+ // Text
2206
3529
  "textAnchor",
3530
+ "letterSpacing",
3531
+ "wordSpacing",
3532
+ "space",
3533
+ "xml:space",
3534
+ "textDecoration",
3535
+ "textTransform",
3536
+ "whiteSpace",
3537
+ "white-space",
3538
+ "dominantBaseline",
3539
+ "alignmentBaseline",
3540
+ "rotate",
3541
+ // per-glyph rotation array, currently not supported
2207
3542
  // Structure
2208
3543
  "id",
2209
3544
  "class",
@@ -2217,6 +3552,16 @@ var PixodeskAnimatorReact = (() => {
2217
3552
  // Clippath/Mask
2218
3553
  "clipPath",
2219
3554
  "mask",
3555
+ // Motion path
3556
+ "offsetPath",
3557
+ "offsetDistance",
3558
+ "offsetRotate",
3559
+ "offsetAnchor",
3560
+ "offsetPosition",
3561
+ // Text path
3562
+ "startOffset",
3563
+ "textLength",
3564
+ "lengthAdjust",
2220
3565
  // Filter
2221
3566
  "filter",
2222
3567
  "stdDeviation",
@@ -2225,10 +3570,11 @@ var PixodeskAnimatorReact = (() => {
2225
3570
  "result",
2226
3571
  "mode",
2227
3572
  ...ALLOWED_RESOURCE_ATTRIBUTES
2228
- ]);
3573
+ ];
3574
+ var ALLOWED_ATTRIBUTES_LOW_SET = new Set(ALLOWED_ATTRIBUTES.map((str) => str.toLowerCase()));
2229
3575
  function sanitiseAttributeValue(name, value) {
2230
3576
  const nameLower = name.toLowerCase();
2231
- if (!ALLOWED_ATTRIBUTES_SET.has(nameLower)) {
3577
+ if (!ALLOWED_ATTRIBUTES_LOW_SET.has(nameLower)) {
2232
3578
  console.warn("Attribute not in whitelist: ", nameLower);
2233
3579
  return void 0;
2234
3580
  }
@@ -2253,7 +3599,10 @@ var PixodeskAnimatorReact = (() => {
2253
3599
  return value;
2254
3600
  }
2255
3601
  function createElement(tagName, normalisedProps, style, children, textContent) {
2256
- if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) return null;
3602
+ if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) {
3603
+ console.warn("Attribute not in whitelist: ", tagName);
3604
+ return null;
3605
+ }
2257
3606
  const element = document.createElementNS(SVG_NS, tagName);
2258
3607
  for (const propName in normalisedProps) {
2259
3608
  element.setAttribute(
@@ -2290,6 +3639,8 @@ var PixodeskAnimatorReact = (() => {
2290
3639
  let value = props[key];
2291
3640
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2292
3641
  propsCopy[key] = toRGBA(value);
3642
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
3643
+ propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
2293
3644
  } else if (TRANSFORM_FN_NAMES.has(key)) {
2294
3645
  if (Array.isArray(value)) {
2295
3646
  if (key === "translate") value = value.map((v) => v + "px");
@@ -2305,8 +3656,8 @@ var PixodeskAnimatorReact = (() => {
2305
3656
  }
2306
3657
  function renderNode(node, defs) {
2307
3658
  if (!node) return null;
2308
- const _a = node, { type, children, animate, style } = _a, props = __objRest(_a, ["type", "children", "animate", "style"]);
2309
- const nodeDefs = node.defs || defs;
3659
+ const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
3660
+ const nodeDefs = getDefs(node) || defs;
2310
3661
  const resolvedStyle = resolveStyle(style, nodeDefs);
2311
3662
  let childElements;
2312
3663
  if (children) {
@@ -2401,6 +3752,45 @@ var PixodeskAnimatorReact = (() => {
2401
3752
  }
2402
3753
  return api;
2403
3754
  }
3755
+ function propAnimIsMotionPath(anim) {
3756
+ var _a;
3757
+ const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
3758
+ if (!Array.isArray(kfs)) return false;
3759
+ if (anim.autoOrient) return true;
3760
+ for (const kf of kfs) {
3761
+ if (kf.tangentIn || kf.tangentOut) return true;
3762
+ }
3763
+ return false;
3764
+ }
3765
+ var _segmentCache = /* @__PURE__ */ new WeakMap();
3766
+ function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
3767
+ const existing = _segmentCache.get(prevKf);
3768
+ if (existing) return existing;
3769
+ const to = prevKf.tangentOut;
3770
+ const ti = nextKf.tangentIn;
3771
+ const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
3772
+ const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
3773
+ const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
3774
+ const entry = {
3775
+ P0: prevPos,
3776
+ P1,
3777
+ P2,
3778
+ P3: nextPos,
3779
+ lut,
3780
+ totalArc: lut.ds[lut.ds.length - 1]
3781
+ };
3782
+ _segmentCache.set(prevKf, entry);
3783
+ return entry;
3784
+ }
3785
+ function evaluateMotionPathSegment(prevKf, nextKf, prevPos, nextPos, localProgress, autoOrient) {
3786
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
3787
+ const t = seg.totalArc === 0 ? localProgress : bezier2D_tForDistance(seg.lut, localProgress * seg.totalArc);
3788
+ const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
3789
+ if (!autoOrient) return { translate: point };
3790
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
3791
+ const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
3792
+ return { translate: point, rotateDeg };
3793
+ }
2404
3794
  function parsePathCommands(d) {
2405
3795
  const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
2406
3796
  const commands = [];
@@ -2463,6 +3853,8 @@ var PixodeskAnimatorReact = (() => {
2463
3853
  currentPath.o.push([x2, y2]);
2464
3854
  } else if (type === "Z" || type === "z") {
2465
3855
  currentPath.c = true;
3856
+ } else {
3857
+ console.warn('Unsupported path command "' + type + '"');
2466
3858
  }
2467
3859
  }
2468
3860
  return res;
@@ -2480,13 +3872,17 @@ var PixodeskAnimatorReact = (() => {
2480
3872
  return typeof value === "string" && extractPathData(value) !== void 0;
2481
3873
  }
2482
3874
  function normalizePathValue(value) {
3875
+ if (value && typeof value === "object" && typeof value.path === "string") {
3876
+ const d = extractPathData(value.path);
3877
+ return d ? { paths: parseSvgPathToBezier(d) } : value;
3878
+ }
2483
3879
  if (value && typeof value === "object" && "paths" in value) {
2484
3880
  const pathsArray = value.paths;
2485
3881
  if (Array.isArray(pathsArray) && pathsArray.length > 0) {
2486
3882
  if (isPathString(pathsArray[0])) {
2487
3883
  const paths = [];
2488
- for (const pathStr of pathsArray) {
2489
- const d = extractPathData(pathStr);
3884
+ for (const pathStr2 of pathsArray) {
3885
+ const d = extractPathData(pathStr2);
2490
3886
  if (d) {
2491
3887
  paths.push(...parseSvgPathToBezier(d));
2492
3888
  }
@@ -2499,8 +3895,8 @@ var PixodeskAnimatorReact = (() => {
2499
3895
  if (Array.isArray(value)) {
2500
3896
  if (value.length > 0 && isPathString(value[0])) {
2501
3897
  const paths = [];
2502
- for (const pathStr of value) {
2503
- const d = extractPathData(pathStr);
3898
+ for (const pathStr2 of value) {
3899
+ const d = extractPathData(pathStr2);
2504
3900
  if (d) {
2505
3901
  paths.push(...parseSvgPathToBezier(d));
2506
3902
  }
@@ -2738,10 +4134,11 @@ var PixodeskAnimatorReact = (() => {
2738
4134
  }
2739
4135
  }
2740
4136
  const processNode = (node) => {
2741
- if (node.animate) {
4137
+ const inlineAnim = node.animate;
4138
+ if (inlineAnim && Object.keys(inlineAnim).length > 0) {
2742
4139
  const nodeId = node.id || generateElementId();
2743
4140
  node.id = nodeId;
2744
- const normalized = processAnimation(nodeId, node.animate);
4141
+ const normalized = processAnimation(nodeId, inlineAnim);
2745
4142
  if (normalized) bindings.push(normalized);
2746
4143
  }
2747
4144
  if (node.children) {
@@ -2812,6 +4209,41 @@ var PixodeskAnimatorReact = (() => {
2812
4209
  localProgress
2813
4210
  ).join(" ");
2814
4211
  cssAttrName = propName;
4212
+ } else if (cssAttrName === "transform" && prevV !== null && typeof prevV === "object" && !Array.isArray(prevV)) {
4213
+ const partKeys = /* @__PURE__ */ new Set([
4214
+ ...prevV ? Object.keys(prevV) : [],
4215
+ ...nextV ? Object.keys(nextV) : []
4216
+ ]);
4217
+ const partsResult = {};
4218
+ for (const partKey of partKeys) {
4219
+ const prevPart = prevV == null ? void 0 : prevV[partKey];
4220
+ const nextPart = nextV == null ? void 0 : nextV[partKey];
4221
+ if (partKey === "rotate") {
4222
+ partsResult.rotate = interpolateNum(+(prevPart != null ? prevPart : 0), +(nextPart != null ? nextPart : 0), localProgress);
4223
+ } else if (partKey === "translate" || partKey === "scale" || partKey === "origin") {
4224
+ const fallback = partKey === "scale" ? [1, 1] : [0, 0];
4225
+ const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);
4226
+ partsResult[partKey] = interp;
4227
+ }
4228
+ }
4229
+ if (propAnimIsMotionPath(propAnim)) {
4230
+ const prevTr = prevV.translate;
4231
+ const nextTr = nextV.translate;
4232
+ if (Array.isArray(prevTr) && Array.isArray(nextTr)) {
4233
+ const sample = evaluateMotionPathSegment(
4234
+ prevKf,
4235
+ nextKf,
4236
+ [+prevTr[0], +prevTr[1]],
4237
+ [+nextTr[0], +nextTr[1]],
4238
+ localProgress,
4239
+ !!propAnim.autoOrient
4240
+ );
4241
+ partsResult.translate = [sample.translate[0], sample.translate[1]];
4242
+ if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
4243
+ }
4244
+ }
4245
+ cssValue = composeTransformParts(partsResult, { withUnits: false });
4246
+ cssAttrName = "transform";
2815
4247
  } else if (cssAttrName === "translate") {
2816
4248
  const v = interpolateVec(
2817
4249
  prevV || [0, 0],
@@ -2837,12 +4269,12 @@ var PixodeskAnimatorReact = (() => {
2837
4269
  cssValue = "scale(" + v.join(",") + ")";
2838
4270
  cssAttrName = "transform";
2839
4271
  } else {
2840
- const num = interpolateNum(
4272
+ const num2 = interpolateNum(
2841
4273
  +(prevV || 0),
2842
4274
  +(nextV || 0),
2843
4275
  localProgress
2844
4276
  );
2845
- cssValue = num;
4277
+ cssValue = num2;
2846
4278
  }
2847
4279
  if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
2848
4280
  cssValue = cssValue * 100 + "%";
@@ -3130,6 +4562,9 @@ var PixodeskAnimatorReact = (() => {
3130
4562
  let cssKey = propName;
3131
4563
  if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
3132
4564
  cssValue = toRGBA(value);
4565
+ } else if (propName === "transform" && value !== null && typeof value === "object" && !Array.isArray(value)) {
4566
+ cssValue = composeTransformParts(value, { withUnits: true });
4567
+ cssKey = "transform";
3133
4568
  } else if (TRANSFORM_FN_NAMES.has(propName)) {
3134
4569
  if (Array.isArray(value)) {
3135
4570
  if (propName === "translate") value = value.map((v) => v + "px");
@@ -3146,28 +4581,59 @@ var PixodeskAnimatorReact = (() => {
3146
4581
  cssKf[cssKey] = cssValue;
3147
4582
  return cssKf;
3148
4583
  }
4584
+ function clipKeyframesToDuration(propName, keyframes, duration) {
4585
+ var _a, _b, _c, _d, _e;
4586
+ const result = [];
4587
+ for (let i = 0; i < keyframes.length; i++) {
4588
+ const kf = keyframes[i];
4589
+ const t = (_a = kf.t) != null ? _a : 0;
4590
+ if (t < 0) {
4591
+ const next = keyframes[i + 1];
4592
+ if (next && ((_b = next.t) != null ? _b : 0) >= 0) {
4593
+ const nextT = (_c = next.t) != null ? _c : 0;
4594
+ const localFrac = (0 - t) / (nextT - t);
4595
+ const easedFrac = kf.e ? cubicBezier(kf.e)(localFrac) : localFrac;
4596
+ const { right: rightEasing } = splitEasing(kf.e, localFrac);
4597
+ result.push({ t: 0, v: interpolateValue(propName, kf.v, next.v, easedFrac), e: rightEasing });
4598
+ }
4599
+ continue;
4600
+ }
4601
+ if (t > duration) {
4602
+ const prev = keyframes[i - 1];
4603
+ if (prev && ((_d = prev.t) != null ? _d : 0) <= duration) {
4604
+ const prevT = (_e = prev.t) != null ? _e : 0;
4605
+ const localFrac = (duration - prevT) / (t - prevT);
4606
+ const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
4607
+ const { left: leftEasing } = splitEasing(prev.e, localFrac);
4608
+ if (result.length > 0) result[result.length - 1] = __spreadProps(__spreadValues({}, result[result.length - 1]), { e: leftEasing });
4609
+ result.push({ t: duration, v: interpolateValue(propName, prev.v, kf.v, easedFrac), e: void 0 });
4610
+ }
4611
+ break;
4612
+ }
4613
+ result.push(kf);
4614
+ }
4615
+ return result;
4616
+ }
3149
4617
  function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
3150
- var _a, _b;
4618
+ var _a;
3151
4619
  const result = /* @__PURE__ */ new Map();
3152
4620
  for (const [propName, propAnim] of Object.entries(animDef)) {
3153
- const keyframes = propAnim.kfs || propAnim.keyframes || [];
4621
+ const duration = config.duration || 1;
4622
+ const clippedKeyframes = clipKeyframesToDuration(propName, propAnim.kfs || propAnim.keyframes || [], duration);
3154
4623
  const cssKeyframes = [];
3155
- for (let i = 0; i < keyframes.length; i++) {
3156
- const kf = keyframes[i];
3157
- let t = (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
3158
- t = clamp(t / (config.duration || 1), 0, 1);
4624
+ for (let i = 0; i < clippedKeyframes.length; i++) {
4625
+ const kf = clippedKeyframes[i];
4626
+ const t = clamp(((_a = kf.t) != null ? _a : 0) / duration, 0, 1);
3159
4627
  const cssKf = createCssKf(kf, t, propName, unsupportedSet);
3160
4628
  if (i === 0 && (cssKf.offset || 0) > 0) {
3161
- cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
3162
- offset: 0
3163
- }));
4629
+ cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), { offset: 0 }));
3164
4630
  }
3165
4631
  cssKeyframes.push(cssKf);
3166
- if (i === keyframes.length - 1 && (cssKf.offset || 0) < 1) {
3167
- cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
3168
- offset: 1
3169
- }));
3170
- }
4632
+ }
4633
+ if (cssKeyframes.length > 0 && (cssKeyframes[cssKeyframes.length - 1].offset || 0) < 1) {
4634
+ cssKeyframes.push(__spreadProps(__spreadValues({}, cssKeyframes[cssKeyframes.length - 1]), {
4635
+ offset: 1
4636
+ }));
3171
4637
  }
3172
4638
  if (cssKeyframes.length > 0) {
3173
4639
  result.set(propName, cssKeyframes);
@@ -3176,6 +4642,7 @@ var PixodeskAnimatorReact = (() => {
3176
4642
  return result;
3177
4643
  }
3178
4644
  function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs) {
4645
+ var _a;
3179
4646
  const config = getAnimatorConfig(doc) || {};
3180
4647
  const bindings = getNormalisedBindings(doc);
3181
4648
  if (!rootElement) {
@@ -3213,7 +4680,11 @@ var PixodeskAnimatorReact = (() => {
3213
4680
  const effectOptions = {
3214
4681
  duration: config.duration,
3215
4682
  delay: positiveDelay,
3216
- fill: config.fill,
4683
+ // Default to 'forwards' so elements hold their final state after the
4684
+ // animation ends — consistent with Lottie and other animation runtimes.
4685
+ // Without this, seeking to the last frame reverts elements to their
4686
+ // pre-animation state (the Web Animations API "after" phase with fill:'none').
4687
+ fill: (_a = config.fill) != null ? _a : "forwards",
3217
4688
  direction: config.direction,
3218
4689
  iterations
3219
4690
  };
@@ -3225,12 +4696,12 @@ var PixodeskAnimatorReact = (() => {
3225
4696
  const effect = new KeyframeEffect(element, keyframes, effectOptions);
3226
4697
  const anim = new Animation(effect, document.timeline);
3227
4698
  if (callbacks == null ? void 0 : callbacks.onFinish) anim.onfinish = () => {
3228
- var _a;
3229
- return (_a = callbacks.onFinish) == null ? void 0 : _a.call(callbacks);
4699
+ var _a2;
4700
+ return (_a2 = callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
3230
4701
  };
3231
4702
  if (callbacks == null ? void 0 : callbacks.onRemove) anim.onremove = () => {
3232
- var _a;
3233
- return (_a = callbacks.onRemove) == null ? void 0 : _a.call(callbacks);
4703
+ var _a2;
4704
+ return (_a2 = callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
3234
4705
  };
3235
4706
  if (seekPosition) {
3236
4707
  anim.currentTime = seekPosition;
@@ -3251,29 +4722,29 @@ var PixodeskAnimatorReact = (() => {
3251
4722
  "isReady": () => true,
3252
4723
  "getRootElement": () => rootElement || null,
3253
4724
  "isPlaying": () => {
3254
- var _a;
3255
- return ((_a = animations[0]) == null ? void 0 : _a.playState) === "running";
4725
+ var _a2;
4726
+ return ((_a2 = animations[0]) == null ? void 0 : _a2.playState) === "running";
3256
4727
  },
3257
4728
  "play": () => {
3258
- var _a;
4729
+ var _a2;
3259
4730
  animations.forEach((a) => a.play());
3260
- (_a = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a.call(callbacks);
4731
+ (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
3261
4732
  },
3262
4733
  "pause": () => {
3263
- var _a;
4734
+ var _a2;
3264
4735
  animations.forEach((a) => a.pause());
3265
- (_a = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a.call(callbacks);
4736
+ (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
3266
4737
  },
3267
4738
  "cancel": () => {
3268
- var _a;
4739
+ var _a2;
3269
4740
  animations.forEach((a) => a.cancel());
3270
- (_a = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a.call(callbacks);
4741
+ (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
3271
4742
  },
3272
4743
  "finish": () => {
3273
- var _a;
4744
+ var _a2;
3274
4745
  for (const a of animations) {
3275
4746
  try {
3276
- if (((_a = a.effect) == null ? void 0 : _a.getTiming().iterations) === Infinity) {
4747
+ if (((_a2 = a.effect) == null ? void 0 : _a2.getTiming().iterations) === Infinity) {
3277
4748
  a.effect.updateTiming({ iterations: 1 });
3278
4749
  a.finish();
3279
4750
  a.effect.updateTiming({ iterations: Infinity });
@@ -3290,8 +4761,8 @@ var PixodeskAnimatorReact = (() => {
3290
4761
  return api;
3291
4762
  },
3292
4763
  "getCurrentTime": () => {
3293
- var _a, _b;
3294
- const res = (_b = (_a = animations[0]) == null ? void 0 : _a.currentTime) != null ? _b : null;
4764
+ var _a2, _b;
4765
+ const res = (_b = (_a2 = animations[0]) == null ? void 0 : _a2.currentTime) != null ? _b : null;
3295
4766
  return res !== null ? +res : null;
3296
4767
  },
3297
4768
  "setCurrentTime": (time) => {
@@ -3346,6 +4817,7 @@ var PixodeskAnimatorReact = (() => {
3346
4817
  return cloned;
3347
4818
  }
3348
4819
  function generateNewIds(doc) {
4820
+ var _a, _b;
3349
4821
  const cloned = deepClone(doc);
3350
4822
  const idMap = /* @__PURE__ */ new Map();
3351
4823
  const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
@@ -3371,6 +4843,8 @@ var PixodeskAnimatorReact = (() => {
3371
4843
  const newId = generateUniqueId();
3372
4844
  idMap.set(oldId, newId);
3373
4845
  node.id = newId;
4846
+ } else if (node.animate) {
4847
+ node.id = generateUniqueId();
3374
4848
  }
3375
4849
  if (Array.isArray(node.children)) {
3376
4850
  for (const child of node.children) {
@@ -3412,23 +4886,21 @@ var PixodeskAnimatorReact = (() => {
3412
4886
  value[styleProp] = replaceUrlRefs(styleValue, idMap);
3413
4887
  }
3414
4888
  }
3415
- } else if (typeof value === "object" && value !== null && key !== ANIMATE_ATTR) {
4889
+ } else if (typeof value === "object" && value !== null) {
3416
4890
  updateRefs(value);
3417
4891
  }
3418
4892
  }
3419
4893
  }
3420
4894
  collectIds(cloned);
3421
4895
  updateRefs(cloned);
3422
- const docBindings = cloned.bindings;
3423
- if (Array.isArray(docBindings)) {
3424
- for (const binding of docBindings) {
3425
- if (binding.id) {
3426
- const newId = idMap.get(binding.id);
3427
- if (newId) {
3428
- binding.id = newId;
3429
- }
3430
- }
4896
+ const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animate;
4897
+ if (docAnimate && typeof docAnimate === "object") {
4898
+ const updatedAnimate = {};
4899
+ for (const [id, anim] of Object.entries(docAnimate)) {
4900
+ const newId = (_b = idMap.get(id)) != null ? _b : id;
4901
+ updatedAnimate[newId] = anim;
3431
4902
  }
4903
+ cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animate: updatedAnimate });
3432
4904
  }
3433
4905
  return cloned;
3434
4906
  }
@@ -3439,6 +4911,9 @@ var PixodeskAnimatorReact = (() => {
3439
4911
  });
3440
4912
  }
3441
4913
  function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
4914
+ const effectsWarnings = validateNodeEffects(doc);
4915
+ for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
4916
+ doc = applyPlayerEffects(doc).root;
3442
4917
  const animatorConfig = getAnimatorConfig(doc) || {};
3443
4918
  animatorConfig.debug = true;
3444
4919
  let rootElement = null;
@@ -3454,14 +4929,21 @@ var PixodeskAnimatorReact = (() => {
3454
4929
  }
3455
4930
  return createAnimatorFromConfig(doc, adapter, callbacks, rootElement);
3456
4931
  }
3457
- function createAnimator(docOrUrl, adapter, callbacks, containerElement) {
3458
- if (typeof docOrUrl === "object") {
3459
- return createAnimatorImpl(docOrUrl, adapter, callbacks, containerElement);
4932
+ function createAnimator(options) {
4933
+ const { src, data, adapter, callbacks, container } = options;
4934
+ if (data !== void 0 && src !== void 0) {
4935
+ throw new Error("createAnimator: provide either `src` or `data`, not both");
4936
+ }
4937
+ if (data === void 0 && src === void 0) {
4938
+ throw new Error("createAnimator: either `src` or `data` is required");
4939
+ }
4940
+ if (data !== void 0) {
4941
+ return createAnimatorImpl(data, adapter, callbacks, container);
3460
4942
  }
3461
4943
  let animator = null;
3462
- fetch(docOrUrl).then((res) => res.json()).then((json) => {
4944
+ fetch(src).then((res) => res.json()).then((json) => {
3463
4945
  if (isPxElementFileFormat(json)) {
3464
- animator = createAnimatorImpl(json, adapter, callbacks, containerElement);
4946
+ animator = createAnimatorImpl(json, adapter, callbacks, container);
3465
4947
  } else {
3466
4948
  console.error("Invalid animation document format");
3467
4949
  }
@@ -3501,7 +4983,7 @@ var PixodeskAnimatorReact = (() => {
3501
4983
  if (!element[PX_ANIM_ATTR_NAME]) {
3502
4984
  const src = element.getAttribute(PX_ANIM_SRC_ATTR_NAME);
3503
4985
  if (src) {
3504
- element[PX_ANIM_ATTR_NAME] = createAnimator(src, void 0, void 0, element);
4986
+ element[PX_ANIM_ATTR_NAME] = createAnimator({ src, container: element });
3505
4987
  }
3506
4988
  }
3507
4989
  }
@@ -3627,7 +5109,7 @@ var PixodeskAnimatorReact = (() => {
3627
5109
  };
3628
5110
  const root = doc ? renderNode2(doc) : null;
3629
5111
  (0, import_react2.useEffect)(() => {
3630
- let api = createAnimator(doc, createReactAdapter(elementRefs));
5112
+ let api = createAnimator({ data: doc, adapter: createReactAdapter(elementRefs) });
3631
5113
  apiHolderRef.current = api;
3632
5114
  return () => {
3633
5115
  api?.destroy();