@kyralabs/m3e-shapes 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -291,7 +291,7 @@ declare function pillStar(options?: {
291
291
  centerY?: number;
292
292
  }): RoundedPolygon;
293
293
 
294
- type PathCommand = readonly ['M', number, number] | readonly ['L', number, number] | readonly ['C', number, number, number, number, number, number] | readonly ['Z'];
294
+ type PathCommand = readonly ['M', number, number] | readonly ['L', number, number] | readonly ['Q', number, number, number, number] | readonly ['C', number, number, number, number, number, number] | readonly ['Z'];
295
295
  /** Compose `Path.translate(offset)`. */
296
296
  declare const translatePath: (path: readonly PathCommand[], dx: number, dy: number) => PathCommand[];
297
297
  /**
@@ -414,6 +414,99 @@ declare const materialShapeNames: MaterialShapeName[];
414
414
  */
415
415
  declare function materialShape(name: MaterialShapeName): RoundedPolygon;
416
416
 
417
+ declare class PathMeasure {
418
+ #private;
419
+ /** Length of the first contour. */
420
+ readonly length: number;
421
+ /**
422
+ * Measures the first contour of `path`. With `forceClosed` (or a `Z`), a closing line back to
423
+ * the contour's start is part of it.
424
+ */
425
+ constructor(path: readonly PathCommand[], forceClosed?: boolean);
426
+ /** Compose `PathMeasure.getSegment(startD, stopD, destination)` (moveTo first). */
427
+ getSegment(startD: number, stopD: number): PathCommand[];
428
+ }
429
+
430
+ /** Stroke widths (px) and whether the caps are round (StrokeCap.Round, the default). */
431
+ interface ProgressStrokes {
432
+ stroke: number;
433
+ trackStroke: number;
434
+ round?: boolean;
435
+ }
436
+ interface LinearWavyInput extends ProgressStrokes {
437
+ width: number;
438
+ height: number;
439
+ /** Wavelength in px (applies when amplitude > 0). */
440
+ wavelength: number;
441
+ /** Pairs of [start, end] fractions (0–1): one pair (determinate) or two (indeterminate). */
442
+ fractions: readonly number[];
443
+ /** 0–1 of the room the height leaves the stroke. */
444
+ amplitude: number;
445
+ /** 0–1: how far along a wavelength the wave has travelled. */
446
+ waveOffset: number;
447
+ /** Gap between the progress and the track (px). */
448
+ gap: number;
449
+ }
450
+ interface LinearWavyPaths {
451
+ track: PathCommand[];
452
+ /** One path per fraction pair (empty when the pair has no length). */
453
+ progress: PathCommand[][];
454
+ /** `currentStrokeCapWidth`. */
455
+ capWidth: number;
456
+ }
457
+ /**
458
+ * Linear wavy paths, LTR (Compose rotates the drawing 180° for RTL). Reuse one instance per
459
+ * indicator: like LinearProgressDrawingCache it caches the measured full path.
460
+ */
461
+ declare class LinearWavyPathCache {
462
+ #private;
463
+ /** `updateDrawPaths`: the progress parts and the track for these fractions. */
464
+ paths(input: LinearWavyInput): LinearWavyPaths;
465
+ }
466
+ /**
467
+ * The wavy linear stop indicator (`drawStopIndicator`): a dot of min(track stroke, `maxSize`) at the
468
+ * end of the track that shrinks away as the progress reaches it. Returns its left edge and
469
+ * diameter (LTR), or null when it has shrunk to nothing.
470
+ */
471
+ declare function linearWavyStopIndicator(progressEnd: number, width: number, maxSize: number, insets: number, trackStroke: number): {
472
+ x: number;
473
+ size: number;
474
+ } | null;
475
+ /**
476
+ * The wave count of a circular wavy indicator: as many wavelengths as fit around the circle (its
477
+ * radius inset by half the stroke), at least 5 (`MinCircularVertexCount`).
478
+ */
479
+ declare const circularWavyVertexCount: (size: number, wavelength: number, stroke: number) => number;
480
+ interface CircularWavyInput extends ProgressStrokes {
481
+ /** Square drawing size (px). */
482
+ size: number;
483
+ /** Preferred wavelength (px); the actual one fits a whole number of waves. */
484
+ wavelength: number;
485
+ start: number;
486
+ end: number;
487
+ amplitude: number;
488
+ waveOffset: number;
489
+ /** The wave offset applies (waveSpeed > 0 and a wave is drawn). */
490
+ motion: boolean;
491
+ gap: number;
492
+ }
493
+ interface CircularWavyPaths {
494
+ track: PathCommand[];
495
+ progress: PathCommand[];
496
+ /** Wave count, which scales the circular wave travel duration. */
497
+ vertexCount: number;
498
+ }
499
+ /**
500
+ * Circular wavy paths (CircularShapes + CircularProgressDrawingCache). Reuse one instance per
501
+ * indicator: it caches the polygons, the morph (created the first time the amplitude is between 0
502
+ * and 1, `requiresMorph`) and the measured full paths.
503
+ */
504
+ declare class CircularWavyPathCache {
505
+ #private;
506
+ /** The paths for `input`; `requiresMorph` as the Compose node passes it. */
507
+ paths(input: CircularWavyInput, requiresMorph: boolean): CircularWavyPaths;
508
+ }
509
+
417
510
  interface PathOptions {
418
511
  /**
419
512
  * Angle in degrees the path starts drawing from. Note that, as in Compose, the path is rotated
@@ -434,4 +527,4 @@ interface MorphPathOptions extends PathOptions {
434
527
  /** Path for a [Morph] at [progress]; the start angle is measured around the rotation pivot. */
435
528
  declare function morphToPath(morph: Morph, progress: number, options?: MorphPathOptions): PathCommand[];
436
529
 
437
- export { Corner, CornerRounding, Cubic, Edge, Feature, type LoadingIndicatorFrame, LoadingIndicatorShapes, type MaterialShapeName, Morph, type MorphPathOptions, MutableCubic, type PathCommand, type PathOptions, type Point, type PointTransformer, RoundedPolygon, calculateScaleFactor, circle, determinateFrame, determinateIndicatorPolygons, indeterminateIndicatorPolygons, loadingIndicatorShapes, materialShape, materialShapeNames, morphSequence, morphToPath, pathBounds, pill, pillStar, polygonToPath, processPath, rectangle, star, toShapeOutline, toSvgPathData, translatePath };
530
+ export { type CircularWavyInput, CircularWavyPathCache, type CircularWavyPaths, Corner, CornerRounding, Cubic, Edge, Feature, type LinearWavyInput, LinearWavyPathCache, type LinearWavyPaths, type LoadingIndicatorFrame, LoadingIndicatorShapes, type MaterialShapeName, Morph, type MorphPathOptions, MutableCubic, type PathCommand, PathMeasure, type PathOptions, type Point, type PointTransformer, type ProgressStrokes, RoundedPolygon, calculateScaleFactor, circle, circularWavyVertexCount, determinateFrame, determinateIndicatorPolygons, indeterminateIndicatorPolygons, linearWavyStopIndicator, loadingIndicatorShapes, materialShape, materialShapeNames, morphSequence, morphToPath, pathBounds, pill, pillStar, polygonToPath, processPath, rectangle, star, toShapeOutline, toSvgPathData, translatePath };
package/dist/index.js CHANGED
@@ -1529,33 +1529,35 @@ var Matrix = class {
1529
1529
  };
1530
1530
 
1531
1531
  // src/path.ts
1532
- var mapPoints = (command, f4) => {
1533
- switch (command[0]) {
1532
+ var mapPoints = (command2, f4) => {
1533
+ switch (command2[0]) {
1534
1534
  case "M":
1535
1535
  case "L":
1536
- return [command[0], ...f4(command[1], command[2])];
1536
+ return [command2[0], ...f4(command2[1], command2[2])];
1537
+ case "Q":
1538
+ return ["Q", ...f4(command2[1], command2[2]), ...f4(command2[3], command2[4])];
1537
1539
  case "C":
1538
1540
  return [
1539
1541
  "C",
1540
- ...f4(command[1], command[2]),
1541
- ...f4(command[3], command[4]),
1542
- ...f4(command[5], command[6])
1542
+ ...f4(command2[1], command2[2]),
1543
+ ...f4(command2[3], command2[4]),
1544
+ ...f4(command2[5], command2[6])
1543
1545
  ];
1544
1546
  case "Z":
1545
- return command;
1547
+ return command2;
1546
1548
  }
1547
1549
  };
1548
- var transformPath = (path, matrix) => path.map((command) => mapPoints(command, (x, y) => matrix.map(x, y)));
1549
- var translatePath = (path, dx, dy) => path.map((command) => mapPoints(command, (x, y) => [x + dx, y + dy]));
1550
+ var transformPath = (path, matrix) => path.map((command2) => mapPoints(command2, (x, y) => matrix.map(x, y)));
1551
+ var translatePath = (path, dx, dy) => path.map((command2) => mapPoints(command2, (x, y) => [x + dx, y + dy]));
1550
1552
  function pathBounds(path) {
1551
1553
  let left = Infinity;
1552
1554
  let top = Infinity;
1553
1555
  let right = -Infinity;
1554
1556
  let bottom = -Infinity;
1555
- for (const command of path) {
1556
- for (let i = 1; i + 1 < command.length; i += 2) {
1557
- const x = command[i];
1558
- const y = command[i + 1];
1557
+ for (const command2 of path) {
1558
+ for (let i = 1; i + 1 < command2.length; i += 2) {
1559
+ const x = command2[i];
1560
+ const y = command2[i + 1];
1559
1561
  left = Math.min(left, x);
1560
1562
  top = Math.min(top, y);
1561
1563
  right = Math.max(right, x);
@@ -1957,23 +1959,31 @@ function processPath(path, width, height, scaleFactor) {
1957
1959
  const [left, top, right, bottom] = pathBounds(scaled);
1958
1960
  const dx = f2(f2(width / 2) - f2(left + f2(f2(right - left) / 2)));
1959
1961
  const dy = f2(f2(height / 2) - f2(top + f2(f2(bottom - top) / 2)));
1960
- return scaled.map((command) => {
1961
- switch (command[0]) {
1962
+ return scaled.map((command2) => {
1963
+ switch (command2[0]) {
1962
1964
  case "M":
1963
1965
  case "L":
1964
- return [command[0], f2(command[1] + dx), f2(command[2] + dy)];
1966
+ return [command2[0], f2(command2[1] + dx), f2(command2[2] + dy)];
1967
+ case "Q":
1968
+ return [
1969
+ "Q",
1970
+ f2(command2[1] + dx),
1971
+ f2(command2[2] + dy),
1972
+ f2(command2[3] + dx),
1973
+ f2(command2[4] + dy)
1974
+ ];
1965
1975
  case "C":
1966
1976
  return [
1967
1977
  "C",
1968
- f2(command[1] + dx),
1969
- f2(command[2] + dy),
1970
- f2(command[3] + dx),
1971
- f2(command[4] + dy),
1972
- f2(command[5] + dx),
1973
- f2(command[6] + dy)
1978
+ f2(command2[1] + dx),
1979
+ f2(command2[2] + dy),
1980
+ f2(command2[3] + dx),
1981
+ f2(command2[4] + dy),
1982
+ f2(command2[5] + dx),
1983
+ f2(command2[6] + dy)
1974
1984
  ];
1975
1985
  case "Z":
1976
- return command;
1986
+ return command2;
1977
1987
  }
1978
1988
  });
1979
1989
  }
@@ -2027,6 +2037,319 @@ function loadingIndicatorShapes(polygons, indeterminate, activeIndicatorScale) {
2027
2037
  return shapes;
2028
2038
  }
2029
2039
 
2030
- export { Corner, CornerRounding, Cubic, Edge, Feature, LoadingIndicatorShapes, Morph, MutableCubic, RoundedPolygon, calculateScaleFactor, circle, determinateFrame, determinateIndicatorPolygons, indeterminateIndicatorPolygons, loadingIndicatorShapes, materialShape, materialShapeNames, morphSequence, morphToPath, pathBounds, pill, pillStar, polygonToPath, processPath, rectangle, star, toShapeOutline, toSvgPathData, translatePath };
2040
+ // src/path-measure.ts
2041
+ var SAMPLES = 32;
2042
+ function at(p, t) {
2043
+ let q = [...p];
2044
+ while (q.length > 2) {
2045
+ const next = [];
2046
+ for (let i = 0; i + 3 < q.length; i += 2) {
2047
+ next.push(q[i] + (q[i + 2] - q[i]) * t, q[i + 1] + (q[i + 3] - q[i + 1]) * t);
2048
+ }
2049
+ q = next;
2050
+ }
2051
+ return [q[0], q[1]];
2052
+ }
2053
+ function sub(p, t0, t1) {
2054
+ const left = (q, t) => {
2055
+ const out = [q[0], q[1]];
2056
+ let r = [...q];
2057
+ while (r.length > 2) {
2058
+ const next = [];
2059
+ for (let i = 0; i + 3 < r.length; i += 2) {
2060
+ next.push(r[i] + (r[i + 2] - r[i]) * t, r[i + 1] + (r[i + 3] - r[i + 1]) * t);
2061
+ }
2062
+ out.push(next[0], next[1]);
2063
+ r = next;
2064
+ }
2065
+ return out;
2066
+ };
2067
+ const reverse = (q) => {
2068
+ const out = [];
2069
+ for (let i = q.length - 2; i >= 0; i -= 2) out.push(q[i], q[i + 1]);
2070
+ return out;
2071
+ };
2072
+ const head = t1 < 1 ? left(p, t1) : [...p];
2073
+ const s = t1 > 0 ? t0 / t1 : 0;
2074
+ return s > 0 ? reverse(left(reverse(head), 1 - s)) : head;
2075
+ }
2076
+ var command = (p) => p.length === 4 ? ["L", p[2], p[3]] : p.length === 6 ? ["Q", p[2], p[3], p[4], p[5]] : ["C", p[2], p[3], p[4], p[5], p[6], p[7]];
2077
+ var PathMeasure = class {
2078
+ #segs = [];
2079
+ /** Length of the first contour. */
2080
+ length = 0;
2081
+ /**
2082
+ * Measures the first contour of `path`. With `forceClosed` (or a `Z`), a closing line back to
2083
+ * the contour's start is part of it.
2084
+ */
2085
+ constructor(path, forceClosed = false) {
2086
+ let x = 0;
2087
+ let y = 0;
2088
+ let startX = 0;
2089
+ let startY = 0;
2090
+ let total = 0;
2091
+ let started = false;
2092
+ let closed = forceClosed;
2093
+ const add = (p) => {
2094
+ const d = [total];
2095
+ let [px, py] = [p[0], p[1]];
2096
+ for (let i = 1; i <= SAMPLES; i++) {
2097
+ const [qx, qy] = at(p, i / SAMPLES);
2098
+ total += Math.hypot(qx - px, qy - py);
2099
+ d.push(total);
2100
+ px = qx;
2101
+ py = qy;
2102
+ }
2103
+ if (total > d[0]) this.#segs.push({ p, d });
2104
+ };
2105
+ for (const c of path) {
2106
+ if (c[0] === "M") {
2107
+ if (started) break;
2108
+ started = true;
2109
+ [x, y, startX, startY] = [c[1], c[2], c[1], c[2]];
2110
+ continue;
2111
+ }
2112
+ if (c[0] === "Z") {
2113
+ closed = true;
2114
+ break;
2115
+ }
2116
+ const p = [x, y, ...c.slice(1)];
2117
+ add(p);
2118
+ x = p[p.length - 2];
2119
+ y = p[p.length - 1];
2120
+ }
2121
+ if (closed && (x !== startX || y !== startY)) add([x, y, startX, startY]);
2122
+ this.length = total;
2123
+ }
2124
+ /** The segment and its parameter at distance `d` (0 ≤ d ≤ length). */
2125
+ #find(d) {
2126
+ const segs = this.#segs;
2127
+ let i = 0;
2128
+ while (i < segs.length - 1 && segs[i].d[SAMPLES] < d) i++;
2129
+ const seg = segs[i];
2130
+ let k = 1;
2131
+ while (k < SAMPLES && seg.d[k] < d) k++;
2132
+ const d0 = seg.d[k - 1];
2133
+ const d1 = seg.d[k];
2134
+ const t = (k - 1 + (d1 > d0 ? (d - d0) / (d1 - d0) : 0)) / SAMPLES;
2135
+ return [seg, Math.min(1, Math.max(0, t))];
2136
+ }
2137
+ /** Compose `PathMeasure.getSegment(startD, stopD, destination)` (moveTo first). */
2138
+ getSegment(startD, stopD) {
2139
+ const start = Math.max(0, startD);
2140
+ const stop = Math.min(this.length, stopD);
2141
+ if (!(start <= stop) || this.#segs.length === 0) return [];
2142
+ const [seg0, t0] = this.#find(start);
2143
+ const [seg1, t1] = this.#find(stop);
2144
+ const [mx, my] = at(seg0.p, t0);
2145
+ const out = [["M", mx, my]];
2146
+ if (seg0 === seg1) {
2147
+ out.push(t0 === t1 ? ["L", mx, my] : command(sub(seg0.p, t0, t1)));
2148
+ return out;
2149
+ }
2150
+ const segs = this.#segs;
2151
+ out.push(command(sub(seg0.p, t0, 1)));
2152
+ for (let i = segs.indexOf(seg0) + 1; segs[i] !== seg1; i++) out.push(command(segs[i].p));
2153
+ out.push(command(sub(seg1.p, 0, t1)));
2154
+ return out;
2155
+ }
2156
+ };
2157
+
2158
+ // src/progress-indicator.ts
2159
+ var capWidth = (s, width, height) => s.round === false || height > width ? 0 : Math.max(s.stroke / 2, s.trackStroke / 2);
2160
+ var LinearWavyPathCache = class {
2161
+ #full = null;
2162
+ /** `updateFullPaths`: the full wave (or line, at amplitude 0), measured. */
2163
+ #fullPath(input) {
2164
+ const { width, height, wavelength, stroke } = input;
2165
+ const wavy = input.amplitude !== 0;
2166
+ const key = [width, height, wavy ? wavelength : 0, stroke].join();
2167
+ if (this.#full?.key === key) return this.#full;
2168
+ const path = [["M", 0, height / 2]];
2169
+ if (!wavy) {
2170
+ path.push(["L", width, height / 2]);
2171
+ } else {
2172
+ const half = wavelength / 2;
2173
+ let anchorX = half;
2174
+ let controlX = half / 2;
2175
+ let controlY = height - stroke;
2176
+ const end = width + wavelength * 2;
2177
+ while (anchorX <= end) {
2178
+ path.push(["Q", controlX, controlY + height / 2, anchorX, height / 2]);
2179
+ anchorX += half;
2180
+ controlX += half;
2181
+ controlY *= -1;
2182
+ }
2183
+ }
2184
+ const measure = new PathMeasure(path, false);
2185
+ const [left, , right] = pathBounds(path);
2186
+ this.#full = { key, measure, scale: measure.length / (right - left + 1e-8) };
2187
+ return this.#full;
2188
+ }
2189
+ /** `updateDrawPaths`: the progress parts and the track for these fractions. */
2190
+ paths(input) {
2191
+ const { width, height, fractions, amplitude, waveOffset, gap } = input;
2192
+ const { measure, scale } = this.#fullPath(input);
2193
+ const cap = capWidth(input, width, height);
2194
+ const halfHeight = height / 2;
2195
+ const wavelength = input.wavelength;
2196
+ const progress = [];
2197
+ const track = [];
2198
+ let adjustedGap = gap;
2199
+ let activeVisible = false;
2200
+ let nextEnd = width - cap;
2201
+ track.push(["M", nextEnd, halfHeight]);
2202
+ for (let i = 0; i + 1 < fractions.length; i += 2) {
2203
+ const start = fractions[i];
2204
+ const end = fractions[i + 1];
2205
+ const barTail = start * width;
2206
+ const barHead = end * width;
2207
+ if (i === 0) {
2208
+ adjustedGap = barHead < cap ? 0 : Math.min(barHead - cap, gap);
2209
+ activeVisible = barHead >= cap;
2210
+ }
2211
+ const head = Math.min(Math.max(barHead, cap), width - cap);
2212
+ const tail = Math.min(Math.max(barTail, cap), width - cap);
2213
+ let part = [];
2214
+ if (Math.abs(end - start) > 0) {
2215
+ const shift = amplitude !== 0 ? waveOffset * wavelength : 0;
2216
+ part = measure.getSegment((tail + shift) * scale, (head + shift) * scale);
2217
+ part = part.map((c) => mapY(c, -Math.max(0, shift), amplitude, halfHeight));
2218
+ }
2219
+ progress.push(part);
2220
+ const spacing = activeVisible ? adjustedGap + cap * 2 : adjustedGap;
2221
+ if (nextEnd > head + spacing) track.push(["L", Math.max(cap, head + spacing), halfHeight]);
2222
+ if (barHead > barTail) {
2223
+ nextEnd = Math.max(cap, tail - spacing);
2224
+ track.push(["M", nextEnd, halfHeight]);
2225
+ }
2226
+ }
2227
+ if (nextEnd > cap) track.push(["L", cap, halfHeight]);
2228
+ return { track, progress, capWidth: cap };
2229
+ }
2230
+ };
2231
+ function mapY(c, dx, amplitude, halfHeight) {
2232
+ const y = (v) => amplitude * v + (1 - amplitude) * halfHeight;
2233
+ switch (c[0]) {
2234
+ case "M":
2235
+ case "L":
2236
+ return [c[0], c[1] + dx, y(c[2])];
2237
+ case "Q":
2238
+ return ["Q", c[1] + dx, y(c[2]), c[3] + dx, y(c[4])];
2239
+ case "C":
2240
+ return ["C", c[1] + dx, y(c[2]), c[3] + dx, y(c[4]), c[5] + dx, y(c[6])];
2241
+ case "Z":
2242
+ return c;
2243
+ }
2244
+ }
2245
+ function linearWavyStopIndicator(progressEnd, width, maxSize, insets, trackStroke) {
2246
+ let size = Math.min(trackStroke, maxSize);
2247
+ const offset = size === trackStroke ? 0 : trackStroke / 4;
2248
+ let x = width - size - offset;
2249
+ const progressX = width * progressEnd + insets;
2250
+ if (x <= progressX) {
2251
+ size = Math.max(0, size - (progressX - x));
2252
+ x = progressX;
2253
+ }
2254
+ return size > 0 ? { x, size } : null;
2255
+ }
2256
+ var MIN_VERTICES = 5;
2257
+ var circularWavyVertexCount = (size, wavelength, stroke) => Math.max(MIN_VERTICES, Math.round(2 * Math.PI * (size / 2 - stroke / 2) / wavelength));
2258
+ var CircularWavyPathCache = class {
2259
+ #shapesKey = "";
2260
+ #vertices = -1;
2261
+ #trackPolygon = null;
2262
+ #activePolygon = null;
2263
+ #morph = null;
2264
+ #full = null;
2265
+ /** `CircularShapes.update`. */
2266
+ #update(size, wavelength, stroke, requiresMorph) {
2267
+ const key = [size, wavelength].join();
2268
+ if (key === this.#shapesKey) {
2269
+ if (requiresMorph && this.#morph === null)
2270
+ this.#morph = new Morph(this.#trackPolygon, this.#activePolygon);
2271
+ return;
2272
+ }
2273
+ const n = circularWavyVertexCount(size, wavelength, stroke);
2274
+ if (n !== this.#vertices) {
2275
+ this.#trackPolygon = circle({ numVertices: n }).normalized();
2276
+ this.#activePolygon = star(n, {
2277
+ innerRadius: 0.75,
2278
+ rounding: new CornerRounding(0.35, 0.4),
2279
+ innerRounding: new CornerRounding(0.5)
2280
+ }).normalized();
2281
+ this.#morph = requiresMorph ? new Morph(this.#trackPolygon, this.#activePolygon) : null;
2282
+ this.#full = null;
2283
+ }
2284
+ this.#shapesKey = key;
2285
+ this.#vertices = n;
2286
+ }
2287
+ /** The paths for `input`; `requiresMorph` as the Compose node passes it. */
2288
+ paths(input, requiresMorph) {
2289
+ const { size, wavelength, stroke, motion, start, end, gap } = input;
2290
+ this.#update(size, wavelength, stroke, requiresMorph);
2291
+ const full = this.#fullPaths(input);
2292
+ const cap = capWidth(input, size, size);
2293
+ const pStart = start * full.length;
2294
+ const pStop = end * full.length;
2295
+ const trackGap = Math.min(pStop, gap);
2296
+ const insets = Math.min(pStop, cap);
2297
+ const spacing = insets * 2 + trackGap;
2298
+ let progress;
2299
+ if (motion) {
2300
+ const offset = Math.min(Math.max(input.waveOffset, 0), 1);
2301
+ const shift = offset * full.length;
2302
+ progress = full.measure.getSegment(pStart + shift, pStop + shift);
2303
+ const angle2 = offset * 360 % 360;
2304
+ if (angle2 !== 0) {
2305
+ const [cx, cy] = full.center;
2306
+ progress = translatePath(
2307
+ transformPath(translatePath(progress, -cx, -cy), new Matrix().rotateZ(-angle2)),
2308
+ cx,
2309
+ cy
2310
+ );
2311
+ }
2312
+ } else {
2313
+ progress = full.measure.getSegment(pStart, pStop);
2314
+ }
2315
+ const trackLength = full.track.length;
2316
+ const track = trackLength > 0 ? full.track.getSegment(end * trackLength + spacing, trackLength - spacing) : [];
2317
+ return { track, progress, vertexCount: this.#vertices };
2318
+ }
2319
+ /** `updateFullPaths` + `getProgressPath` / `getTrackPath` + `processPath`. */
2320
+ #fullPaths(input) {
2321
+ const { size, stroke, amplitude, motion } = input;
2322
+ const key = [size, stroke, amplitude, motion, this.#vertices, this.#morph !== null].join();
2323
+ if (this.#full?.key === key) return this.#full;
2324
+ const pivot = { rotationPivotX: 0.5, rotationPivotY: 0.5 };
2325
+ const raw = this.#morph !== null ? morphToPath(this.#morph, amplitude, { startAngle: 270, repeatPath: motion, ...pivot }) : polygonToPath(amplitude === 1 ? this.#activePolygon : this.#trackPolygon, {
2326
+ startAngle: 270,
2327
+ repeatPath: motion
2328
+ });
2329
+ const progress = processPath2(raw, size, stroke);
2330
+ const measure = new PathMeasure(progress, true);
2331
+ const track = new PathMeasure(
2332
+ processPath2(polygonToPath(this.#trackPolygon, { startAngle: 270 }), size, stroke),
2333
+ true
2334
+ );
2335
+ const [left, top, right, bottom] = pathBounds(progress);
2336
+ this.#full = {
2337
+ key,
2338
+ progress,
2339
+ measure,
2340
+ length: motion ? measure.length / 2 : measure.length,
2341
+ center: [(left + right) / 2, (top + bottom) / 2],
2342
+ track
2343
+ };
2344
+ return this.#full;
2345
+ }
2346
+ };
2347
+ function processPath2(path, size, stroke) {
2348
+ const scaled = transformPath(path, new Matrix().scale(size - stroke, size - stroke));
2349
+ const [left, top, right, bottom] = pathBounds(scaled);
2350
+ return translatePath(scaled, size / 2 - (left + right) / 2, size / 2 - (top + bottom) / 2);
2351
+ }
2352
+
2353
+ export { CircularWavyPathCache, Corner, CornerRounding, Cubic, Edge, Feature, LinearWavyPathCache, LoadingIndicatorShapes, Morph, MutableCubic, PathMeasure, RoundedPolygon, calculateScaleFactor, circle, circularWavyVertexCount, determinateFrame, determinateIndicatorPolygons, indeterminateIndicatorPolygons, linearWavyStopIndicator, loadingIndicatorShapes, materialShape, materialShapeNames, morphSequence, morphToPath, pathBounds, pill, pillStar, polygonToPath, processPath, rectangle, star, toShapeOutline, toSvgPathData, translatePath };
2031
2354
  //# sourceMappingURL=index.js.map
2032
2355
  //# sourceMappingURL=index.js.map