@kyralabs/m3e-shapes 0.0.0-stage → 1.0.1

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.
@@ -0,0 +1,437 @@
1
+ /**
2
+ * CornerRounding defines the amount and quality around a given vertex of a shape. [radius] defines
3
+ * the radius of the circle which forms the basis of the rounding for the vertex. [smoothing]
4
+ * defines the amount by which the curve is extended from the circular arc around the corner to the
5
+ * edge between vertices.
6
+ *
7
+ * Each corner of a shape can be thought of as either:
8
+ * - unrounded (with a corner radius of 0 and no smoothing)
9
+ * - rounded with only a circular arc (with smoothing of 0). In this case, the rounding around
10
+ * the corner follows an approximated circular arc between the edges to adjacent vertices.
11
+ * - rounded with three curves: There is an inner circular arc and two symmetric flanking curves.
12
+ * The flanking curves determine the curvature from the inner curve to the edges, with a value of
13
+ * 0 (no smoothing) meaning that it is purely a circular curve and a value of 1 meaning that the
14
+ * flanking curves are maximized between the inner curve and the edges.
15
+ *
16
+ * @param radius a value of 0 or greater, representing the radius of the circle which defines the
17
+ * inner rounding arc of the corner. A value of 0 indicates that the corner is sharp, or
18
+ * completely unrounded. A positive value is the requested size of the radius. Note that this
19
+ * radius is an absolute size that should relate to the overall size of its shape.
20
+ * @param smoothing the amount by which the arc is "smoothed" by extending the curve from the inner
21
+ * circular arc to the edge between vertices. A value of 0 (no smoothing) indicates that the
22
+ * corner is rounded by only a circular arc; there are no flanking curves. A value of 1 indicates
23
+ * that there is no circular arc in the center; the flanking curves on either side meet at the
24
+ * middle.
25
+ */
26
+ declare class CornerRounding {
27
+ /** [Unrounded] has a rounding radius of zero, producing a sharp corner at a vertex. */
28
+ static readonly Unrounded: CornerRounding;
29
+ readonly radius: number;
30
+ readonly smoothing: number;
31
+ /** Both values are Kotlin `Float`s (rounded to float32). */
32
+ constructor(radius?: number, smoothing?: number);
33
+ }
34
+
35
+ interface Point {
36
+ readonly x: number;
37
+ readonly y: number;
38
+ }
39
+ /** Interface for a function that can transform (rotate/scale/translate/etc.) points. */
40
+ type PointTransformer = (x: number, y: number) => readonly [number, number];
41
+
42
+ /**
43
+ * This class holds the anchor and control point data for a single cubic Bézier curve, with anchor
44
+ * points ([anchor0X], [anchor0Y]) and ([anchor1X], [anchor1Y]) at either end and control points
45
+ * ([control0X], [control0Y]) and ([control1X], [control1Y]) determining the slope of the curve
46
+ * between the anchor points.
47
+ */
48
+ declare class Cubic {
49
+ /** Kotlin `FloatArray`: values are stored as float32. */
50
+ readonly points: Float32Array;
51
+ constructor(points?: ArrayLike<number>);
52
+ /** Creates a Cubic from its eight coordinates (the top-level Kotlin `Cubic(...)` factory). */
53
+ static of(anchor0X: number, anchor0Y: number, control0X: number, control0Y: number, control1X: number, control1Y: number, anchor1X: number, anchor1Y: number): Cubic;
54
+ static fromPoints(anchor0: Point, control0: Point, control1: Point, anchor1: Point): Cubic;
55
+ get anchor0X(): number;
56
+ get anchor0Y(): number;
57
+ get control0X(): number;
58
+ get control0Y(): number;
59
+ get control1X(): number;
60
+ get control1Y(): number;
61
+ get anchor1X(): number;
62
+ get anchor1Y(): number;
63
+ pointOnCurve(t: number): Point;
64
+ zeroLength(): boolean;
65
+ /**
66
+ * Fills [bounds] with `[minX, minY, maxX, maxY]`. With [approximate], the bounding box of all
67
+ * anchors and controls; otherwise the exact extrema (solving the derivative quadratic).
68
+ */
69
+ calculateBounds(bounds?: number[], approximate?: boolean): void;
70
+ /** Returns two Cubics, created by splitting this curve at the given distance of [t]. */
71
+ split(t: number): [Cubic, Cubic];
72
+ /** Utility function to reverse the control/anchor points for this curve. */
73
+ reverse(): Cubic;
74
+ plus(o: Cubic): Cubic;
75
+ times(x: number): Cubic;
76
+ div(x: number): Cubic;
77
+ toString(): string;
78
+ equals(other: unknown): boolean;
79
+ /** Transforms the points in this [Cubic] with the given [PointTransformer]. */
80
+ transformed(f: PointTransformer): Cubic;
81
+ /** Generates a bezier curve that is a straight line between the given anchor points. */
82
+ static straightLine(x0: number, y0: number, x1: number, y1: number): Cubic;
83
+ /**
84
+ * Generates a bezier curve that approximates a circular arc, with p0 and p1 as the starting and
85
+ * ending anchor points. The curve generated is the smallest of the two possible arcs around the
86
+ * entire 360-degree circle. Arcs of greater than 180 degrees should use more than one arc
87
+ * together. Note that p0 and p1 should be equidistant from the center.
88
+ */
89
+ static circularArc(centerX: number, centerY: number, x0: number, y0: number, x1: number, y1: number): Cubic;
90
+ }
91
+ /** This is a Mutable version of [Cubic], used mostly for performance critical paths. */
92
+ declare class MutableCubic extends Cubic {
93
+ private transformOnePoint;
94
+ transform(f: PointTransformer): void;
95
+ interpolate(c1: Cubic, c2: Cubic, progress: number): void;
96
+ }
97
+
98
+ /**
99
+ * This class holds information about a corner (rounded or not) or an edge of a given polygon. The
100
+ * features of a Polygon can be used to manipulate the shape with more context of what the shape
101
+ * actually is, rather than simply manipulating the raw curves and lines which describe it.
102
+ */
103
+ declare abstract class Feature {
104
+ readonly cubics: readonly Cubic[];
105
+ constructor(cubics: readonly Cubic[]);
106
+ abstract transformed(f: PointTransformer): Feature;
107
+ abstract toString(): string;
108
+ }
109
+ /**
110
+ * Edges have only a list of the cubic curves which make up the edge. Edges lie between corners
111
+ * and have no vertex or concavity; the curves are simply straight lines (represented by Cubic
112
+ * curves).
113
+ */
114
+ declare class Edge extends Feature {
115
+ transformed(f: PointTransformer): Edge;
116
+ toString(): string;
117
+ }
118
+ /**
119
+ * Corners contain the list of cubic curves which describe how the corner is rounded (or not),
120
+ * plus the vertex at the corner (which the cubics may or may not pass through, depending on
121
+ * whether the corner is rounded) and a flag indicating whether the corner is convex. A regular
122
+ * polygon has all convex corners, while a star polygon generally (but not necessarily) has both
123
+ * convex (outer) and concave (inner) corners.
124
+ */
125
+ declare class Corner extends Feature {
126
+ readonly vertex: Point;
127
+ readonly roundedCenter: Point;
128
+ readonly convex: boolean;
129
+ constructor(cubics: readonly Cubic[], vertex: Point, roundedCenter: Point, convex?: boolean);
130
+ transformed(f: PointTransformer): Corner;
131
+ toString(): string;
132
+ }
133
+
134
+ /**
135
+ * The RoundedPolygon class allows simple construction of polygonal shapes with optional rounding
136
+ * at the vertices. Polygons can be constructed with either the number of vertices desired or an
137
+ * ordered list of vertices.
138
+ */
139
+ declare class RoundedPolygon {
140
+ readonly features: readonly Feature[];
141
+ readonly cubics: readonly Cubic[];
142
+ readonly centerX: number;
143
+ readonly centerY: number;
144
+ constructor(features: readonly Feature[], centerX: number, centerY: number);
145
+ /** Transforms (scales/translates/etc.) this [RoundedPolygon] with the given [PointTransformer]. */
146
+ transformed(f: PointTransformer): RoundedPolygon;
147
+ /**
148
+ * Creates a new RoundedPolygon, moving and resizing this one, so it is completely inside the
149
+ * (0, 0) -> (1, 1) square, centered if there extra space in one direction
150
+ */
151
+ normalized(): RoundedPolygon;
152
+ toString(): string;
153
+ /**
154
+ * Like [calculateBounds], this function calculates the axis-aligned bounds of the object and
155
+ * returns that rectangle. But this function determines the max dimension of the shape (by
156
+ * calculating the distance from its center to the start and midpoint of each curve) and returns
157
+ * a square which can be used to hold the object in any rotation.
158
+ */
159
+ calculateMaxBounds(bounds?: number[]): number[];
160
+ /**
161
+ * Calculates the axis-aligned bounds of the object. With [approximate] (the default), uses the
162
+ * bounding box of every anchor and control point.
163
+ */
164
+ calculateBounds(bounds?: number[], approximate?: boolean): number[];
165
+ /** Copy constructor (Kotlin `RoundedPolygon(source)`). */
166
+ static copy(source: RoundedPolygon): RoundedPolygon;
167
+ /**
168
+ * Regular polygon of [numVertices] vertices around ([centerX], [centerY]) at [radius]
169
+ * (Kotlin `RoundedPolygon(numVertices, …)`).
170
+ */
171
+ static fromVertexCount(numVertices: number, options?: {
172
+ radius?: number;
173
+ centerX?: number;
174
+ centerY?: number;
175
+ rounding?: CornerRounding;
176
+ perVertexRounding?: readonly CornerRounding[] | null;
177
+ }): RoundedPolygon;
178
+ /**
179
+ * Polygon from an ordered list of `[x0, y0, x1, y1, …]` vertices (Kotlin
180
+ * `RoundedPolygon(vertices, …)`). Center defaults to the (1.0.1) estimate from the vertices.
181
+ */
182
+ static fromVertices(vertices: ArrayLike<number>, options?: {
183
+ rounding?: CornerRounding;
184
+ perVertexRounding?: readonly CornerRounding[] | null;
185
+ centerX?: number;
186
+ centerY?: number;
187
+ }): RoundedPolygon;
188
+ }
189
+
190
+ /**
191
+ * This class is used to animate between start and end polygons objects.
192
+ *
193
+ * Morphing between arbitrary objects can be problematic because it can be difficult to determine
194
+ * how the points of a given shape map to the points of some other shape. [Morph] simplifies the
195
+ * problem by only operating on [RoundedPolygon] objects, which are known to have similar,
196
+ * contiguous structures. For one thing, the shape of a polygon is contiguous from start to end
197
+ * (compared to an arbitrary Path object, which could have one or more `moveTo` operations in the
198
+ * shape). Also, all edges of a polygon shape are represented by [Cubic] objects, thus the start
199
+ * and end shapes use similar operations. Two Polygon shapes then only differ in the quantity and
200
+ * placement of their curves. The morph works by determining how to map the curves of the two
201
+ * shapes together (based on proximity and other information, such as distance to polygon
202
+ * vertices and concavity), and splitting curves when the shapes do not have the same number of
203
+ * curves or when the curve placement within the shapes is very different.
204
+ */
205
+ declare class Morph {
206
+ private readonly start;
207
+ private readonly end;
208
+ /** The structure which holds the actual shape being morphed: matched start/end cubics. */
209
+ readonly morphMatch: readonly (readonly [Cubic, Cubic])[];
210
+ constructor(start: RoundedPolygon, end: RoundedPolygon);
211
+ /** Axis-aligned bounds covering both start and end shapes (and so the whole morph). */
212
+ calculateBounds(bounds?: number[], approximate?: boolean): number[];
213
+ /** A square that holds both shapes in any rotation (see RoundedPolygon.calculateMaxBounds). */
214
+ calculateMaxBounds(bounds?: number[]): number[];
215
+ /**
216
+ * Returns a representation of the morph object at a given [progress] value as a list of Cubics.
217
+ * Note that this function causes a new list to be created and populated, so there is some
218
+ * overhead.
219
+ */
220
+ asCubics(progress: number): Cubic[];
221
+ /**
222
+ * Calls [callback] for each of the cubics of the morph at [progress], reusing [mutableCubic]
223
+ * (no per-frame allocation).
224
+ */
225
+ forEachCubic(progress: number, callback: (cubic: MutableCubic) => void, mutableCubic?: MutableCubic): void;
226
+ /**
227
+ * Matches the cubics of two polygons: measures both outlines, maps their corners, cuts and
228
+ * shifts the end polygon, then walks both, cutting curves so every pair spans the same progress.
229
+ */
230
+ static match(p1: RoundedPolygon, p2: RoundedPolygon): [Cubic, Cubic][];
231
+ }
232
+
233
+ /**
234
+ * Creates a circular shape, approximating the rounding of the shape around the underlying polygon
235
+ * vertices.
236
+ */
237
+ declare function circle(options?: {
238
+ numVertices?: number;
239
+ radius?: number;
240
+ centerX?: number;
241
+ centerY?: number;
242
+ }): RoundedPolygon;
243
+ /** Creates a rectangular shape with the given width/height around the given center. */
244
+ declare function rectangle(options?: {
245
+ width?: number;
246
+ height?: number;
247
+ rounding?: CornerRounding;
248
+ perVertexRounding?: readonly CornerRounding[] | null;
249
+ centerX?: number;
250
+ centerY?: number;
251
+ }): RoundedPolygon;
252
+ /**
253
+ * Creates a star polygon, which is like a regular polygon except every other vertex is on either
254
+ * an inner or outer radius.
255
+ */
256
+ declare function star(numVerticesPerRadius: number, options?: {
257
+ radius?: number;
258
+ innerRadius?: number;
259
+ rounding?: CornerRounding;
260
+ innerRounding?: CornerRounding | null;
261
+ perVertexRounding?: readonly CornerRounding[] | null;
262
+ centerX?: number;
263
+ centerY?: number;
264
+ }): RoundedPolygon;
265
+ /**
266
+ * A pill shape consists of a rectangle shape bounded by two semicircles at either of the long
267
+ * ends of the rectangle.
268
+ */
269
+ declare function pill(options?: {
270
+ width?: number;
271
+ height?: number;
272
+ smoothing?: number;
273
+ centerX?: number;
274
+ centerY?: number;
275
+ }): RoundedPolygon;
276
+ /**
277
+ * A pillStar shape is like a [pill] except it has inner and outer radii along its pill-shaped
278
+ * outline, just like a [star] has inner and outer radii along its circular outline.
279
+ */
280
+ declare function pillStar(options?: {
281
+ width?: number;
282
+ height?: number;
283
+ numVerticesPerRadius?: number;
284
+ innerRadiusRatio?: number;
285
+ rounding?: CornerRounding;
286
+ innerRounding?: CornerRounding | null;
287
+ perVertexRounding?: readonly CornerRounding[] | null;
288
+ vertexSpacing?: number;
289
+ startLocation?: number;
290
+ centerX?: number;
291
+ centerY?: number;
292
+ }): RoundedPolygon;
293
+
294
+ type PathCommand = readonly ['M', number, number] | readonly ['L', number, number] | readonly ['C', number, number, number, number, number, number] | readonly ['Z'];
295
+ /** Compose `Path.translate(offset)`. */
296
+ declare const translatePath: (path: readonly PathCommand[], dx: number, dy: number) => PathCommand[];
297
+ /**
298
+ * Compose `Path.getBounds()`: `[left, top, right, bottom]` over every point, control points
299
+ * included (Skia's `SkPath::getBounds`). Empty paths give `[0, 0, 0, 0]`.
300
+ */
301
+ declare function pathBounds(path: readonly PathCommand[]): [number, number, number, number];
302
+ /**
303
+ * Serializes a path to an SVG `d` attribute with absolute commands. [fractionDigits] bounds the
304
+ * decimals per number (trailing zeros dropped).
305
+ */
306
+ declare function toSvgPathData(path: readonly PathCommand[], fractionDigits?: number): string;
307
+
308
+ /**
309
+ * `LoadingIndicatorDefaults.IndeterminateIndicatorPolygons`: the seven shapes the indeterminate
310
+ * indicator morphs between, in order.
311
+ */
312
+ declare const indeterminateIndicatorPolygons: () => RoundedPolygon[];
313
+ /**
314
+ * `LoadingIndicatorDefaults.DeterminateIndicatorPolygons`: a circle rotated by 360° / 20 (for a
315
+ * smoother morph into the soft burst, which is rotated by the same angle) and the soft burst.
316
+ */
317
+ declare const determinateIndicatorPolygons: () => RoundedPolygon[];
318
+ /**
319
+ * A morph between each consecutive pair of polygons (each normalized) and, when
320
+ * [circularSequence], a final morph from the last back to the first.
321
+ */
322
+ declare function morphSequence(polygons: readonly RoundedPolygon[], circularSequence: boolean): Morph[];
323
+ /**
324
+ * The scale factor that keeps every polygon inside its box while it rotates: the smallest
325
+ * bounds-to-max-bounds ratio (using the larger of the x and y ratios, for pill-like shapes).
326
+ */
327
+ declare function calculateScaleFactor(polygons: readonly RoundedPolygon[]): number;
328
+ /**
329
+ * Scales a normalized path by `size × scaleFactor` and centers it (by its control-point bounds)
330
+ * in a `width` x `height` box.
331
+ */
332
+ declare function processPath(path: readonly PathCommand[], width: number, height: number, scaleFactor: number): PathCommand[];
333
+ /** What the indicator draws in one frame: a morph at a progress, rotated about the center. */
334
+ interface LoadingIndicatorFrame {
335
+ morphIndex: number;
336
+ morphProgress: number;
337
+ /** Degrees, clockwise. */
338
+ rotation: number;
339
+ }
340
+ /**
341
+ * The determinate draw step: picks the active morph for [progress] (coerced to 0..1), its local
342
+ * progress, and rotates counterclockwise by half a turn over the whole range.
343
+ */
344
+ declare function determinateFrame(progress: number, morphCount: number): LoadingIndicatorFrame;
345
+ /**
346
+ * A loading indicator's shapes, prepared once: the morph sequence and the scale factor
347
+ * (`calculateScaleFactor × activeIndicatorScale`, where the active indicator scale is the token
348
+ * ratio `ActiveSize / min(ContainerWidth, ContainerHeight)`).
349
+ */
350
+ declare class LoadingIndicatorShapes {
351
+ readonly morphs: readonly Morph[];
352
+ readonly scaleFactor: number;
353
+ constructor(polygons: readonly RoundedPolygon[], circularSequence: boolean, activeIndicatorScale: number);
354
+ /** The processed path of morph [morphIndex] at [progress] in a [size]-sided square. */
355
+ path(morphIndex: number, progress: number, size: number): PathCommand[];
356
+ /** {@link path} as an SVG `d` attribute. */
357
+ pathData(morphIndex: number, progress: number, size: number): string;
358
+ }
359
+ /**
360
+ * {@link LoadingIndicatorShapes} for an indicator, built once per polygon list (null = the
361
+ * Compose defaults for the kind), kind and active indicator scale. Morph construction is the
362
+ * expensive part, so every indicator on a page shares it.
363
+ */
364
+ declare function loadingIndicatorShapes(polygons: readonly RoundedPolygon[] | null, indeterminate: boolean, activeIndicatorScale: number): LoadingIndicatorShapes;
365
+
366
+ /**
367
+ * The outline Compose's `RoundedPolygon.toShape(startAngle).createOutline(size, …)` produces: the
368
+ * path scaled to [width] x [height], then centered by its control-point bounds.
369
+ */
370
+ declare function toShapeOutline(polygon: RoundedPolygon, width: number, height: number, startAngle?: number): PathCommand[];
371
+ declare const builders: {
372
+ Circle: () => RoundedPolygon;
373
+ Square: () => RoundedPolygon;
374
+ Slanted: () => RoundedPolygon;
375
+ Arch: () => RoundedPolygon;
376
+ Fan: () => RoundedPolygon;
377
+ Arrow: () => RoundedPolygon;
378
+ SemiCircle: () => RoundedPolygon;
379
+ Oval: () => RoundedPolygon;
380
+ Pill: () => RoundedPolygon;
381
+ Triangle: () => RoundedPolygon;
382
+ Diamond: () => RoundedPolygon;
383
+ ClamShell: () => RoundedPolygon;
384
+ Pentagon: () => RoundedPolygon;
385
+ Gem: () => RoundedPolygon;
386
+ Sunny: () => RoundedPolygon;
387
+ VerySunny: () => RoundedPolygon;
388
+ Cookie4Sided: () => RoundedPolygon;
389
+ Cookie6Sided: () => RoundedPolygon;
390
+ Cookie7Sided: () => RoundedPolygon;
391
+ Cookie9Sided: () => RoundedPolygon;
392
+ Cookie12Sided: () => RoundedPolygon;
393
+ Ghostish: () => RoundedPolygon;
394
+ Clover4Leaf: () => RoundedPolygon;
395
+ Clover8Leaf: () => RoundedPolygon;
396
+ Burst: () => RoundedPolygon;
397
+ SoftBurst: () => RoundedPolygon;
398
+ Boom: () => RoundedPolygon;
399
+ SoftBoom: () => RoundedPolygon;
400
+ Flower: () => RoundedPolygon;
401
+ Puffy: () => RoundedPolygon;
402
+ PuffyDiamond: () => RoundedPolygon;
403
+ PixelCircle: () => RoundedPolygon;
404
+ PixelTriangle: () => RoundedPolygon;
405
+ Bun: () => RoundedPolygon;
406
+ Heart: () => RoundedPolygon;
407
+ };
408
+ type MaterialShapeName = keyof typeof builders;
409
+ /** The 35 Material shape names, in MaterialShapes.kt order. */
410
+ declare const materialShapeNames: MaterialShapeName[];
411
+ /**
412
+ * A predefined Material shape as a normalized [RoundedPolygon] (fits the unit square), created on
413
+ * first use and cached, like the `MaterialShapes.<Name>` getters.
414
+ */
415
+ declare function materialShape(name: MaterialShapeName): RoundedPolygon;
416
+
417
+ interface PathOptions {
418
+ /**
419
+ * Angle in degrees the path starts drawing from. Note that, as in Compose, the path is rotated
420
+ * around the origin; the pivot only measures the angle of the first anchor.
421
+ */
422
+ startAngle?: number;
423
+ /** Draws the outline twice (for stroke animations). */
424
+ repeatPath?: boolean;
425
+ /** Closes the path. */
426
+ closePath?: boolean;
427
+ }
428
+ /** Path for a [RoundedPolygon]; the start angle is measured around its center. */
429
+ declare function polygonToPath(polygon: RoundedPolygon, options?: PathOptions): PathCommand[];
430
+ interface MorphPathOptions extends PathOptions {
431
+ rotationPivotX?: number;
432
+ rotationPivotY?: number;
433
+ }
434
+ /** Path for a [Morph] at [progress]; the start angle is measured around the rotation pivot. */
435
+ declare function morphToPath(morph: Morph, progress: number, options?: MorphPathOptions): PathCommand[];
436
+
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 };