@pixodesk/svg-animator-react 1.0.17 → 1.0.18

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 = {}))
@@ -2650,10 +2651,22 @@ var PixodeskAnimatorReact = (() => {
2650
2651
  outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
2651
2652
  scrollIntoViewThreshold: px.number().optional()
2652
2653
  }));
2654
+ var PxGlyphSchema = implementsInterface()(px.object({
2655
+ width: px.number(),
2656
+ d: px.string()
2657
+ }));
2658
+ var PxGlyphFontSchema = implementsInterface()(px.object({
2659
+ fFamily: px.string(),
2660
+ style: px.string(),
2661
+ ascent: px.number(),
2662
+ unitsPerEm: px.number(),
2663
+ glyphs: px.record(PxGlyphSchema)
2664
+ }));
2653
2665
  var PxDefsSchema = implementsInterface()(px.object({
2654
2666
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
2655
2667
  animations: px.record(PxAnimationDefinitionSchema).optional(),
2656
- styles: px.record(px.any()).optional()
2668
+ styles: px.record(px.any()).optional(),
2669
+ glyphs: px.record(PxGlyphFontSchema).optional()
2657
2670
  }));
2658
2671
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
2659
2672
  mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
@@ -2765,6 +2778,9 @@ var PixodeskAnimatorReact = (() => {
2765
2778
  startOffset: PxAnimatableNumberSchema.optional(),
2766
2779
  textLength: PxAnimatableNumberSchema.optional()
2767
2780
  }));
2781
+ var PxTextEffectSchema = implementsInterface()(px.object({
2782
+ useGlyphs: px.boolean().optional()
2783
+ }));
2768
2784
  var PxEffectsSchema = implementsInterface()(px.object({
2769
2785
  transformation: PxTransformationEffectSchema.optional(),
2770
2786
  repeater: PxRepeaterEffectSchema.optional(),
@@ -2774,7 +2790,8 @@ var PixodeskAnimatorReact = (() => {
2774
2790
  isCombinedShape: px.boolean().optional(),
2775
2791
  fillGradient: PxFillGradientEffectSchema.optional(),
2776
2792
  strokeGradient: PxStrokeGradientEffectSchema.optional(),
2777
- textAlongPath: PxTextAlongPathEffectSchema.optional()
2793
+ textAlongPath: PxTextAlongPathEffectSchema.optional(),
2794
+ text: PxTextEffectSchema.optional()
2778
2795
  }));
2779
2796
  function validateNodeEffects(root, opts) {
2780
2797
  const warnings = [];
@@ -3664,6 +3681,57 @@ var PixodeskAnimatorReact = (() => {
3664
3681
  }
3665
3682
  }
3666
3683
  }
3684
+ var jsonElementFactory = (type, props, children) => {
3685
+ const node = { type };
3686
+ for (const k in props) if (props[k] !== void 0) node[k] = props[k];
3687
+ const arr = Array.isArray(children) ? children.filter((c) => c != null) : children != null ? [children] : [];
3688
+ if (arr.length) node.children = arr;
3689
+ return node;
3690
+ };
3691
+ function fmt(v, decimals) {
3692
+ return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
3693
+ }
3694
+ function pack(nums, decimals) {
3695
+ let s = "";
3696
+ for (let i = 0; i < nums.length; i++) {
3697
+ const str2 = fmt(nums[i], decimals);
3698
+ if (i > 0 && str2.charCodeAt(0) !== 45) s += " ";
3699
+ s += str2;
3700
+ }
3701
+ return s;
3702
+ }
3703
+ function apply(m, x, y) {
3704
+ return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
3705
+ }
3706
+ var TOKEN_RE = /([MLCQZ])|(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi;
3707
+ function transformPathData(d, m, decimals = 2) {
3708
+ const tokens = [];
3709
+ let match;
3710
+ TOKEN_RE.lastIndex = 0;
3711
+ while ((match = TOKEN_RE.exec(d)) !== null) tokens.push(match[0]);
3712
+ let out = "";
3713
+ let i = 0;
3714
+ const num2 = () => parseFloat(tokens[i++]);
3715
+ while (i < tokens.length) {
3716
+ const cmd = tokens[i++];
3717
+ if (cmd === "M" || cmd === "L") {
3718
+ const [x, y] = apply(m, num2(), num2());
3719
+ out += cmd + pack([x, y], decimals);
3720
+ } else if (cmd === "C") {
3721
+ const [x1, y1] = apply(m, num2(), num2());
3722
+ const [x2, y2] = apply(m, num2(), num2());
3723
+ const [x, y] = apply(m, num2(), num2());
3724
+ out += "C" + pack([x1, y1, x2, y2, x, y], decimals);
3725
+ } else if (cmd === "Q") {
3726
+ const [x1, y1] = apply(m, num2(), num2());
3727
+ const [x, y] = apply(m, num2(), num2());
3728
+ out += "Q" + pack([x1, y1, x, y], decimals);
3729
+ } else if (cmd === "Z" || cmd === "z") {
3730
+ out += "Z";
3731
+ }
3732
+ }
3733
+ return out;
3734
+ }
3667
3735
  function bezierToSvgPath(path) {
3668
3736
  var _a, _b, _c, _d;
3669
3737
  const v = path.v;
@@ -4035,6 +4103,24 @@ var PixodeskAnimatorReact = (() => {
4035
4103
  }
4036
4104
  return { ts, ds };
4037
4105
  }
4106
+ function bezier2D_tForDistance(lut, distance) {
4107
+ const { ts, ds } = lut;
4108
+ const last = ds.length - 1;
4109
+ if (distance <= 0) return ts[0];
4110
+ if (distance >= ds[last]) return ts[last];
4111
+ let lo = 1;
4112
+ let hi = last;
4113
+ while (lo < hi) {
4114
+ const mid = lo + hi >>> 1;
4115
+ if (ds[mid] < distance) lo = mid + 1;
4116
+ else hi = mid;
4117
+ }
4118
+ const dPrev = ds[hi - 1];
4119
+ const dCur = ds[hi];
4120
+ const span = dCur - dPrev;
4121
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
4122
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
4123
+ }
4038
4124
  function bezier2D_arcAtT(lut, t) {
4039
4125
  const { ts, ds } = lut;
4040
4126
  const last = ts.length - 1;
@@ -4056,6 +4142,435 @@ var PixodeskAnimatorReact = (() => {
4056
4142
  const flipped = [easing[1], easing[0], easing[3], easing[2]];
4057
4143
  return cubicBezier(flipped);
4058
4144
  }
4145
+ var LUT_STEPS = 48;
4146
+ var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
4147
+ function tokenize(d) {
4148
+ const tokens = [];
4149
+ const re = /([MmLlHhVvCcSsQqTtAaZz])|(-?\d*\.?\d+(?:[eE][-+]?\d+)?)/g;
4150
+ let m;
4151
+ while ((m = re.exec(d)) !== null) tokens.push(m[0]);
4152
+ return tokens;
4153
+ }
4154
+ function quadToCubic(P0, Qc, P3) {
4155
+ return {
4156
+ P1: [P0[0] + 2 / 3 * (Qc[0] - P0[0]), P0[1] + 2 / 3 * (Qc[1] - P0[1])],
4157
+ P2: [P3[0] + 2 / 3 * (Qc[0] - P3[0]), P3[1] + 2 / 3 * (Qc[1] - P3[1])]
4158
+ };
4159
+ }
4160
+ function parseCubics(d) {
4161
+ const tokens = tokenize(d);
4162
+ const segs = [];
4163
+ let i = 0;
4164
+ let cx = 0, cy = 0;
4165
+ let sx = 0, sy = 0;
4166
+ let pcx = 0, pcy = 0;
4167
+ let pqx = 0, pqy = 0;
4168
+ let prevCmd = "";
4169
+ const num2 = () => parseFloat(tokens[i++]);
4170
+ const push = (P1, P2, P3) => {
4171
+ const P0 = [cx, cy];
4172
+ const lut = bezier2D_arcLengthLUT(P0, P1, P2, P3, LUT_STEPS);
4173
+ segs.push({ P0, P1, P2, P3, lut, len: lut.ds[lut.ds.length - 1] });
4174
+ cx = P3[0];
4175
+ cy = P3[1];
4176
+ };
4177
+ const pushLine = (x, y) => {
4178
+ push(
4179
+ [cx + (x - cx) / 3, cy + (y - cy) / 3],
4180
+ [cx + 2 * (x - cx) / 3, cy + 2 * (y - cy) / 3],
4181
+ [x, y]
4182
+ );
4183
+ };
4184
+ while (i < tokens.length) {
4185
+ let cmd = tokens[i];
4186
+ if (CMD_RE.test(cmd)) i++;
4187
+ else cmd = prevCmd === "M" ? "L" : prevCmd === "m" ? "l" : prevCmd;
4188
+ const rel = cmd >= "a";
4189
+ const U = cmd.toUpperCase();
4190
+ if (U === "Z") {
4191
+ pushLine(sx, sy);
4192
+ cx = sx;
4193
+ cy = sy;
4194
+ prevCmd = cmd;
4195
+ continue;
4196
+ }
4197
+ if (U === "M") {
4198
+ const x = num2() + (rel ? cx : 0), y = num2() + (rel ? cy : 0);
4199
+ cx = x;
4200
+ cy = y;
4201
+ sx = x;
4202
+ sy = y;
4203
+ prevCmd = cmd;
4204
+ continue;
4205
+ }
4206
+ if (U === "L") {
4207
+ pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
4208
+ } else if (U === "H") {
4209
+ pushLine(num2() + (rel ? cx : 0), cy);
4210
+ } else if (U === "V") {
4211
+ pushLine(cx, num2() + (rel ? cy : 0));
4212
+ } else if (U === "C") {
4213
+ const p1 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4214
+ const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4215
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4216
+ pcx = p2[0];
4217
+ pcy = p2[1];
4218
+ push(p1, p2, p3);
4219
+ } else if (U === "S") {
4220
+ const smooth = prevCmd.toUpperCase() === "C" || prevCmd.toUpperCase() === "S";
4221
+ const p1 = smooth ? [2 * cx - pcx, 2 * cy - pcy] : [cx, cy];
4222
+ const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4223
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4224
+ pcx = p2[0];
4225
+ pcy = p2[1];
4226
+ push(p1, p2, p3);
4227
+ } else if (U === "Q") {
4228
+ const qc = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4229
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4230
+ pqx = qc[0];
4231
+ pqy = qc[1];
4232
+ const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
4233
+ push(P1, P2, p3);
4234
+ } else if (U === "T") {
4235
+ const smooth = prevCmd.toUpperCase() === "Q" || prevCmd.toUpperCase() === "T";
4236
+ const qc = smooth ? [2 * cx - pqx, 2 * cy - pqy] : [cx, cy];
4237
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
4238
+ pqx = qc[0];
4239
+ pqy = qc[1];
4240
+ const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
4241
+ push(P1, P2, p3);
4242
+ } else if (U === "A") {
4243
+ i += 5;
4244
+ pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
4245
+ } else {
4246
+ i++;
4247
+ continue;
4248
+ }
4249
+ prevCmd = cmd;
4250
+ }
4251
+ return segs.length ? segs : null;
4252
+ }
4253
+ function clamp2(v, lo, hi) {
4254
+ return v < lo ? lo : v > hi ? hi : v;
4255
+ }
4256
+ function createPathSampler(d) {
4257
+ const segs = parseCubics(d);
4258
+ if (!segs) return null;
4259
+ const cum = new Float64Array(segs.length + 1);
4260
+ for (let k = 0; k < segs.length; k++) cum[k + 1] = cum[k] + segs[k].len;
4261
+ const totalLength = cum[segs.length];
4262
+ const start = segs[0].P0, end = segs[segs.length - 1].P3;
4263
+ const closed = Math.hypot(end[0] - start[0], end[1] - start[1]) < 1e-3;
4264
+ const sampleOn = (dist) => {
4265
+ let k = 0;
4266
+ while (k < segs.length - 1 && dist > cum[k + 1]) k++;
4267
+ const seg = segs[k];
4268
+ const local = dist - cum[k];
4269
+ const t = seg.len > 0 ? bezier2D_tForDistance(seg.lut, local) : 0;
4270
+ const [x, y] = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
4271
+ const [dx, dy] = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
4272
+ return { x, y, angle: Math.atan2(dy, dx) };
4273
+ };
4274
+ return {
4275
+ totalLength,
4276
+ sampleAtDistance(dist) {
4277
+ if (!closed && (dist < 0 || dist > totalLength)) {
4278
+ const edge = dist < 0 ? 0 : totalLength;
4279
+ const p = sampleOn(edge);
4280
+ const over = dist - edge;
4281
+ return { x: p.x + Math.cos(p.angle) * over, y: p.y + Math.sin(p.angle) * over, angle: p.angle };
4282
+ }
4283
+ return sampleOn(clamp2(dist, 0, totalLength));
4284
+ }
4285
+ };
4286
+ }
4287
+ var DEFAULT_FONT_SIZE = 16;
4288
+ var TEXT_ATTR_KEYS = [
4289
+ "fontFamily",
4290
+ "fontSize",
4291
+ "fontWeight",
4292
+ "fontStyle",
4293
+ "textAnchor",
4294
+ "letterSpacing",
4295
+ "wordSpacing",
4296
+ "textDecoration",
4297
+ "textTransform",
4298
+ "whiteSpace",
4299
+ "x",
4300
+ "y",
4301
+ "dx",
4302
+ "dy",
4303
+ "lengthAdjust",
4304
+ "fill",
4305
+ "stroke",
4306
+ "strokeWidth",
4307
+ "effects",
4308
+ TEXT_ATTR,
4309
+ TEXT_CONTENT_ATTR,
4310
+ "xml:space"
4311
+ ];
4312
+ function parseLen(v) {
4313
+ if (typeof v === "number") return v;
4314
+ if (typeof v === "string") {
4315
+ const n = parseFloat(v);
4316
+ return isNaN(n) ? void 0 : n;
4317
+ }
4318
+ return void 0;
4319
+ }
4320
+ function str(v) {
4321
+ return typeof v === "string" ? v : void 0;
4322
+ }
4323
+ function resolveStyle(node, parent) {
4324
+ var _a, _b, _c, _d, _e, _f, _g;
4325
+ return {
4326
+ fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
4327
+ fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
4328
+ fill: (_c = node.fill) != null ? _c : parent.fill,
4329
+ stroke: (_d = node.stroke) != null ? _d : parent.stroke,
4330
+ strokeWidth: (_e = node.strokeWidth) != null ? _e : parent.strokeWidth,
4331
+ letterSpacing: (_f = parseLen(node.letterSpacing)) != null ? _f : parent.letterSpacing,
4332
+ wordSpacing: (_g = parseLen(node.wordSpacing)) != null ? _g : parent.wordSpacing
4333
+ };
4334
+ }
4335
+ function rootStyleOf(node) {
4336
+ var _a, _b, _c;
4337
+ return {
4338
+ fontFamily: str(node.fontFamily),
4339
+ fontSize: (_a = parseLen(node.fontSize)) != null ? _a : DEFAULT_FONT_SIZE,
4340
+ fill: node.fill,
4341
+ stroke: node.stroke,
4342
+ strokeWidth: node.strokeWidth,
4343
+ letterSpacing: (_b = parseLen(node.letterSpacing)) != null ? _b : 0,
4344
+ wordSpacing: (_c = parseLen(node.wordSpacing)) != null ? _c : 0
4345
+ };
4346
+ }
4347
+ function paintOf(s) {
4348
+ const p = {};
4349
+ if (s.fill !== void 0) p.fill = s.fill;
4350
+ if (s.stroke !== void 0) p.stroke = s.stroke;
4351
+ if (s.strokeWidth !== void 0) p.strokeWidth = s.strokeWidth;
4352
+ return p;
4353
+ }
4354
+ function glyphFontFor(s, glyphs, soleFont, warnings) {
4355
+ var _a;
4356
+ const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;
4357
+ if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a = s.fontFamily) != null ? _a : "") + '"');
4358
+ return gf;
4359
+ }
4360
+ function soleFontOf(glyphs) {
4361
+ const names = Object.keys(glyphs);
4362
+ return names.length === 1 ? glyphs[names[0]] : void 0;
4363
+ }
4364
+ function materialiseGlyphTextHorizontal(node, opts) {
4365
+ var _a, _b, _c, _d;
4366
+ const { glyphs, create = jsonElementFactory, warnings } = opts;
4367
+ const soleFont = soleFontOf(glyphs);
4368
+ const pen = { x: (_a = parseLen(node.x)) != null ? _a : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
4369
+ const placements = [];
4370
+ const lines = [{ start: pen.x, end: pen.x }];
4371
+ let line = 0;
4372
+ const renderChars = (content, s) => {
4373
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4374
+ if (!gf) return;
4375
+ const scale = s.fontSize / gf.unitsPerEm;
4376
+ const paint = paintOf(s);
4377
+ for (let i = 0; i < content.length; i++) {
4378
+ const ch = content.charAt(i);
4379
+ const g = gf.glyphs[ch];
4380
+ if (g && g.d) placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
4381
+ pen.x += (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
4382
+ lines[line].end = pen.x;
4383
+ }
4384
+ };
4385
+ const walk = (el, parentStyle) => {
4386
+ var _a2, _b2, _c2, _d2;
4387
+ const s = resolveStyle(el, parentStyle);
4388
+ const x = parseLen(el.x);
4389
+ const y = parseLen(el.y);
4390
+ if (x !== void 0) {
4391
+ pen.x = x;
4392
+ line = lines.length;
4393
+ lines.push({ start: pen.x, end: pen.x });
4394
+ }
4395
+ if (y !== void 0) pen.y = y;
4396
+ pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
4397
+ pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4398
+ const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
4399
+ if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
4400
+ if (el.children) for (const ch of el.children) walk(ch, s);
4401
+ };
4402
+ const rootStyle = rootStyleOf(node);
4403
+ if (node.children) for (const ch of node.children) walk(ch, rootStyle);
4404
+ const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
4405
+ if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
4406
+ const anchor = str(node.textAnchor);
4407
+ if (anchor === "middle" || anchor === "end") {
4408
+ for (const p of placements) {
4409
+ const w = lines[p.line].end - lines[p.line].start;
4410
+ const shift = anchor === "middle" ? -w / 2 : -w;
4411
+ p.m = [p.scale, 0, 0, p.scale, p.x + shift, p.y];
4412
+ }
4413
+ }
4414
+ return toGroup(node, buildPaths(placements, create, warnings), create);
4415
+ }
4416
+ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4417
+ const cells = [];
4418
+ let adv = 0;
4419
+ const walk = (el, parentStyle) => {
4420
+ var _a, _b;
4421
+ const s = resolveStyle(el, parentStyle);
4422
+ const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
4423
+ if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
4424
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4425
+ if (gf) {
4426
+ const scale = s.fontSize / gf.unitsPerEm;
4427
+ const paint = paintOf(s);
4428
+ for (let i = 0; i < content.length; i++) {
4429
+ const ch = content.charAt(i);
4430
+ const g = gf.glyphs[ch];
4431
+ const glyphAdv = (g ? g.width : 0) * scale;
4432
+ if (g && g.d) cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
4433
+ adv += glyphAdv + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
4434
+ }
4435
+ }
4436
+ }
4437
+ if (el.children) for (const ch of el.children) walk(ch, s);
4438
+ };
4439
+ walk(node, rootStyleOf(node));
4440
+ return { cells, width: adv };
4441
+ }
4442
+ function alongAffine(sampler, dist, scale, widthEm) {
4443
+ const { x, y, angle } = sampler.sampleAtDistance(dist);
4444
+ const cos = Math.cos(angle), sin = Math.sin(angle), hw = widthEm / 2;
4445
+ return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw, y - scale * sin * hw];
4446
+ }
4447
+ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength) {
4448
+ var _a;
4449
+ const { glyphs, create = jsonElementFactory, warnings } = opts;
4450
+ const sampler = pathD ? createPathSampler(pathD) : null;
4451
+ if (!sampler) {
4452
+ warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry");
4453
+ return null;
4454
+ }
4455
+ const soleFont = soleFontOf(glyphs);
4456
+ const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
4457
+ if (!cells.length) return toGroup(node, [], create);
4458
+ if (textLength && textLength > 0 && width > 0) {
4459
+ const k = textLength / width;
4460
+ for (const c of cells) c.midBase *= k;
4461
+ }
4462
+ const so = readAnimatable(startOffset);
4463
+ if (so.kind === "animated" && so.keyframes.length >= 2) {
4464
+ return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create), create);
4465
+ }
4466
+ const base = so.kind === "animated" ? Number((_a = so.keyframes[0]) == null ? void 0 : _a.value) || 0 : so.kind === "static" ? Number(so.value) || 0 : 0;
4467
+ const placements = cells.map((c) => ({
4468
+ glyphD: c.glyphD,
4469
+ paint: c.paint,
4470
+ m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm)
4471
+ }));
4472
+ return toGroup(node, buildPaths(placements, create, warnings), create);
4473
+ }
4474
+ var ALONG_PATH_MAX_STEPS = 48;
4475
+ var ALONG_PATH_MAX_STEPS_PER_SEGMENT = 64;
4476
+ function roundN(v, n) {
4477
+ const f = __pow(10, n);
4478
+ return Math.round(v * f) / f;
4479
+ }
4480
+ function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create) {
4481
+ const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
4482
+ const timeOf = (kf) => Number(kf.time) || 0;
4483
+ const offOf = (kf) => Number(kf.value) || 0;
4484
+ const out = [];
4485
+ for (const c of cells) {
4486
+ const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
4487
+ const d = transformPathData(c.glyphD, centred);
4488
+ const sampleKf = (dist, time) => {
4489
+ const { x, y, angle } = sampler.sampleAtDistance(dist);
4490
+ return {
4491
+ time,
4492
+ value: {
4493
+ [
4494
+ "translate"
4495
+ /* Translate */
4496
+ ]: [roundN(x, 3), roundN(y, 3)],
4497
+ [
4498
+ "rotate"
4499
+ /* Rotate */
4500
+ ]: roundN(angle * 180 / Math.PI, 3)
4501
+ }
4502
+ };
4503
+ };
4504
+ const kfs = [sampleKf(offOf(sokfs[0]) + c.midBase, timeOf(sokfs[0]))];
4505
+ for (let k = 1; k < sokfs.length; k++) {
4506
+ const t0 = timeOf(sokfs[k - 1]), t1 = timeOf(sokfs[k]);
4507
+ const o0 = offOf(sokfs[k - 1]), o1 = offOf(sokfs[k]);
4508
+ const n = Math.min(ALONG_PATH_MAX_STEPS_PER_SEGMENT, Math.max(1, Math.ceil(Math.abs(o1 - o0) / step)));
4509
+ for (let s = 1; s <= n; s++) {
4510
+ const f = s / n;
4511
+ kfs.push(sampleKf(o0 + f * (o1 - o0) + c.midBase, t0 + f * (t1 - t0)));
4512
+ }
4513
+ }
4514
+ const transform = { keyframes: kfs };
4515
+ if (loop !== void 0) transform.loop = loop;
4516
+ out.push(create("path", __spreadProps(__spreadValues({ d }, paintProps(c.paint)), { animate: { transform } }), []));
4517
+ }
4518
+ return out;
4519
+ }
4520
+ function paintProps(paint) {
4521
+ const p = {};
4522
+ if (paint.fill !== void 0) p.fill = paint.fill;
4523
+ if (paint.stroke !== void 0) p.stroke = paint.stroke;
4524
+ if (paint.strokeWidth !== void 0) p.strokeWidth = paint.strokeWidth;
4525
+ return p;
4526
+ }
4527
+ function buildPaths(placements, create, warnings) {
4528
+ var _a, _b, _c;
4529
+ if (!placements.length) {
4530
+ warnings == null ? void 0 : warnings.push("textGlyphs: nothing to render");
4531
+ return [];
4532
+ }
4533
+ const byPaint = /* @__PURE__ */ new Map();
4534
+ for (const p of placements) {
4535
+ const key = JSON.stringify([(_a = p.paint.fill) != null ? _a : null, (_b = p.paint.stroke) != null ? _b : null, (_c = p.paint.strokeWidth) != null ? _c : null]);
4536
+ const baked = transformPathData(p.glyphD, p.m);
4537
+ const entry = byPaint.get(key);
4538
+ if (entry) entry.d += baked;
4539
+ else byPaint.set(key, { paint: p.paint, d: baked });
4540
+ }
4541
+ const out = [];
4542
+ for (const { paint, d } of byPaint.values()) out.push(create("path", __spreadValues({ d }, paintProps(paint)), []));
4543
+ return out;
4544
+ }
4545
+ function toGroup(node, children, create) {
4546
+ const gProps = {};
4547
+ for (const k of Object.keys(node)) {
4548
+ if (k === "type" || k === "children" || TEXT_ATTR_KEYS.indexOf(k) !== -1) continue;
4549
+ gProps[k] = node[k];
4550
+ }
4551
+ if (gProps.style && typeof gProps.style === "object") {
4552
+ const style = __spreadValues({}, gProps.style);
4553
+ delete style["white-space"];
4554
+ if (Object.keys(style).length) gProps.style = style;
4555
+ else delete gProps.style;
4556
+ }
4557
+ return create("g", gProps, children);
4558
+ }
4559
+ function applyTextGlyphsEffect(node, fx, ctx) {
4560
+ if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
4561
+ if (!ctx.glyphs) {
4562
+ ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
4563
+ return node;
4564
+ }
4565
+ return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
4566
+ }
4567
+ function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength) {
4568
+ if (!ctx.glyphs) {
4569
+ ctx.warnings.push("textGlyphs: no definitions.glyphs");
4570
+ return null;
4571
+ }
4572
+ return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength);
4573
+ }
4059
4574
  function getKfTranslate(kf) {
4060
4575
  var _a;
4061
4576
  const v = (_a = kf.value) != null ? _a : kf.v;
@@ -4496,12 +5011,12 @@ var PixodeskAnimatorReact = (() => {
4496
5011
  }
4497
5012
  return res;
4498
5013
  }
4499
- function extractPathData(str) {
4500
- if (str.startsWith("path(") && str.endsWith(")")) {
4501
- return str.slice(5, -1);
5014
+ function extractPathData(str2) {
5015
+ if (str2.startsWith("path(") && str2.endsWith(")")) {
5016
+ return str2.slice(5, -1);
4502
5017
  }
4503
- if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str)) {
4504
- return str;
5018
+ if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str2)) {
5019
+ return str2;
4505
5020
  }
4506
5021
  return void 0;
4507
5022
  }
@@ -5422,7 +5937,7 @@ var PixodeskAnimatorReact = (() => {
5422
5937
  return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
5423
5938
  }
5424
5939
  function applyPlayerEffects(root) {
5425
- var _a;
5940
+ var _a, _b;
5426
5941
  const ctx = {
5427
5942
  defs: [],
5428
5943
  warnings: [],
@@ -5433,7 +5948,8 @@ var PixodeskAnimatorReact = (() => {
5433
5948
  maskAncestorChains: /* @__PURE__ */ new Map(),
5434
5949
  // Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
5435
5950
  // webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5436
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi
5951
+ engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
5952
+ glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
5437
5953
  };
5438
5954
  const working = clone(root);
5439
5955
  indexById(working, ctx.idMap);
@@ -5445,16 +5961,34 @@ var PixodeskAnimatorReact = (() => {
5445
5961
  return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
5446
5962
  }
5447
5963
  function applyPlayerEffects_exceptRetime(node, ctx) {
5964
+ var _a;
5448
5965
  if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
5449
5966
  const fx = node.effects;
5450
5967
  const originalId = typeof node.id === "string" ? node.id : void 0;
5451
5968
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
5452
5969
  if (!fx && !innerIdForContentRef) return node;
5453
- const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textAlongPath } = fx != null ? fx : {};
5970
+ const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textAlongPath, text } = fx != null ? fx : {};
5454
5971
  const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
5455
5972
  if (fx) delete node.effects;
5456
5973
  let n = node;
5457
- n = applyTextAlongPathEffect(n, textAlongPath, ctx);
5974
+ let consumedByGlyphs = false;
5975
+ if (text == null ? void 0 : text.useGlyphs) {
5976
+ if (textAlongPath) {
5977
+ const pathNode = typeof textAlongPath.href === "string" ? ctx.idMap.get(textAlongPath.href) : void 0;
5978
+ const pathD = pathNode && typeof pathNode.d === "string" ? pathNode.d : void 0;
5979
+ const rawTL = textAlongPath.textLength;
5980
+ const textLength = typeof rawTL === "number" ? rawTL : rawTL && typeof rawTL === "object" ? typeof rawTL.value === "number" ? rawTL.value : Array.isArray(rawTL.keyframes) && rawTL.keyframes.length ? Number((_a = rawTL.keyframes[0]) == null ? void 0 : _a.value) : void 0 : void 0;
5981
+ const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textAlongPath.startOffset, textLength);
5982
+ if (glyphed) {
5983
+ n = glyphed;
5984
+ consumedByGlyphs = true;
5985
+ }
5986
+ } else {
5987
+ n = applyTextGlyphsEffect(n, text, ctx);
5988
+ consumedByGlyphs = true;
5989
+ }
5990
+ }
5991
+ if (!consumedByGlyphs) n = applyTextAlongPathEffect(n, textAlongPath, ctx);
5458
5992
  n = applyFillGradientEffect(n, fillGradient, ctx);
5459
5993
  n = applyStrokeGradientEffect(n, strokeGradient, ctx);
5460
5994
  n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
@@ -5691,8 +6225,8 @@ var PixodeskAnimatorReact = (() => {
5691
6225
  var DATA_SVG_IMAGE_RE = /^data:image\/svg\+xml(?:;[^,]*)?,/i;
5692
6226
  var DATA_IMAGE_BASE64_PAYLOAD_RE = /^data:image\/[^;,]*;base64,([A-Za-z0-9+/]{8})/i;
5693
6227
  var BASE64_RASTER_MAGICS = ["iVBORw0K", "/9j/", "R0lGOD", "UklGR", "Qk"];
5694
- function isContentSniffedRasterImage(str) {
5695
- const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str);
6228
+ function isContentSniffedRasterImage(str2) {
6229
+ const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str2);
5696
6230
  return !!m && BASE64_RASTER_MAGICS.some((magic) => m[1].startsWith(magic));
5697
6231
  }
5698
6232
  function isDangerousAttrName(nameLower) {
@@ -5706,18 +6240,18 @@ var PixodeskAnimatorReact = (() => {
5706
6240
  return void 0;
5707
6241
  }
5708
6242
  if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopcolor") {
5709
- const str = String(value);
5710
- if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
6243
+ const str2 = String(value);
6244
+ if (str2.includes("url(") && !/^url\(#[^)]+\)$/.test(str2)) {
5711
6245
  console.warn('Attribute "' + nameLower + '" blocked: url() must be internal url(#id), got:', value);
5712
6246
  return void 0;
5713
6247
  }
5714
6248
  return value;
5715
6249
  }
5716
6250
  if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {
5717
- const str = String(value);
5718
- if (str.startsWith("#")) return value;
5719
- if (/^url\(#[^)]+\)$/.test(str)) return value;
5720
- if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str) || DATA_SVG_IMAGE_RE.test(str) || isContentSniffedRasterImage(str))) return value;
6251
+ const str2 = String(value);
6252
+ if (str2.startsWith("#")) return value;
6253
+ if (/^url\(#[^)]+\)$/.test(str2)) return value;
6254
+ if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str2) || DATA_SVG_IMAGE_RE.test(str2) || isContentSniffedRasterImage(str2))) return value;
5721
6255
  console.warn('Attribute "' + nameLower + '" blocked: must be #id, url(#id), or data:image/\u2026 URI, got:', value);
5722
6256
  return void 0;
5723
6257
  }
@@ -5747,7 +6281,7 @@ var PixodeskAnimatorReact = (() => {
5747
6281
  if (textContent) element.textContent = textContent;
5748
6282
  return element;
5749
6283
  }
5750
- function resolveStyle(style, defs) {
6284
+ function resolveStyle2(style, defs) {
5751
6285
  var _a;
5752
6286
  if (!style) return void 0;
5753
6287
  if (typeof style === "string") {
@@ -5783,7 +6317,7 @@ var PixodeskAnimatorReact = (() => {
5783
6317
  if (!node) return null;
5784
6318
  const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
5785
6319
  const nodeDefs = getDefs(node) || defs;
5786
- const resolvedStyle = resolveStyle(style, nodeDefs);
6320
+ const resolvedStyle = resolveStyle2(style, nodeDefs);
5787
6321
  let childElements;
5788
6322
  if (children) {
5789
6323
  for (const ch of children) {