@bug-on/m3-expressive 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -0
- package/README.md +110 -0
- package/dist/assets/fonts/GoogleSansFlex-VariableFont.woff2 +0 -0
- package/dist/assets/fonts/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/fonts/MaterialSymbolsRounded-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/fonts/MaterialSymbolsSharp-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/loading-indicator.svg +19 -0
- package/dist/assets/material-symbols-cdn.css +65 -0
- package/dist/assets/material-symbols-self-hosted.css +94 -0
- package/dist/buttons.d.mts +180 -0
- package/dist/buttons.d.ts +180 -0
- package/dist/buttons.js +4282 -0
- package/dist/buttons.js.map +1 -0
- package/dist/buttons.mjs +4227 -0
- package/dist/buttons.mjs.map +1 -0
- package/dist/core.d.mts +422 -0
- package/dist/core.d.ts +422 -0
- package/dist/core.js +2581 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +2547 -0
- package/dist/core.mjs.map +1 -0
- package/dist/feedback.d.mts +600 -0
- package/dist/feedback.d.ts +600 -0
- package/dist/feedback.js +2357 -0
- package/dist/feedback.js.map +1 -0
- package/dist/feedback.mjs +2321 -0
- package/dist/feedback.mjs.map +1 -0
- package/dist/forms.d.mts +40 -0
- package/dist/forms.d.ts +40 -0
- package/dist/forms.js +4263 -0
- package/dist/forms.js.map +1 -0
- package/dist/forms.mjs +4228 -0
- package/dist/forms.mjs.map +1 -0
- package/dist/icon-button-D-gs0gfj.d.mts +136 -0
- package/dist/icon-button-D-gs0gfj.d.ts +136 -0
- package/dist/index.css +309 -0
- package/dist/index.css.d.ts +2 -0
- package/dist/index.d.mts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +23972 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +23668 -0
- package/dist/index.mjs.map +1 -0
- package/dist/layout.d.mts +610 -0
- package/dist/layout.d.ts +610 -0
- package/dist/layout.js +5091 -0
- package/dist/layout.js.map +1 -0
- package/dist/layout.mjs +5042 -0
- package/dist/layout.mjs.map +1 -0
- package/dist/material-symbols-cdn.css +65 -0
- package/dist/material-symbols-cdn.css.d.ts +2 -0
- package/dist/material-symbols-self-hosted.css +94 -0
- package/dist/material-symbols-self-hosted.css.d.ts +2 -0
- package/dist/md3-DFhj-NZj.d.mts +17 -0
- package/dist/md3-DFhj-NZj.d.ts +17 -0
- package/dist/navigation.d.mts +2766 -0
- package/dist/navigation.d.ts +2766 -0
- package/dist/navigation.js +6684 -0
- package/dist/navigation.js.map +1 -0
- package/dist/navigation.mjs +6573 -0
- package/dist/navigation.mjs.map +1 -0
- package/dist/overlays.d.mts +161 -0
- package/dist/overlays.d.ts +161 -0
- package/dist/overlays.js +3298 -0
- package/dist/overlays.js.map +1 -0
- package/dist/overlays.mjs +3244 -0
- package/dist/overlays.mjs.map +1 -0
- package/dist/pickers.d.mts +1074 -0
- package/dist/pickers.d.ts +1074 -0
- package/dist/pickers.js +4240 -0
- package/dist/pickers.js.map +1 -0
- package/dist/pickers.mjs +4200 -0
- package/dist/pickers.mjs.map +1 -0
- package/dist/plugin.d.mts +1 -0
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +13 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugin.mjs +3 -0
- package/dist/plugin.mjs.map +1 -0
- package/dist/scroll-area-CVS6HyLl.d.mts +33 -0
- package/dist/scroll-area-CVS6HyLl.d.ts +33 -0
- package/dist/shapes.d.mts +1119 -0
- package/dist/shapes.d.ts +1119 -0
- package/dist/shapes.js +2941 -0
- package/dist/shapes.js.map +1 -0
- package/dist/shapes.mjs +2889 -0
- package/dist/shapes.mjs.map +1 -0
- package/dist/side-sheet-modal-BY6VCC8p.d.mts +553 -0
- package/dist/side-sheet-modal-CglP6KYA.d.ts +553 -0
- package/dist/split-button-trailing-uncheckable-C5CLCIKP.d.ts +731 -0
- package/dist/split-button-trailing-uncheckable-MXj_kyNt.d.mts +731 -0
- package/dist/text-field-eAIpz9z1.d.mts +1038 -0
- package/dist/text-field-eAIpz9z1.d.ts +1038 -0
- package/dist/typography-339RV6v7.d.mts +486 -0
- package/dist/typography-339RV6v7.d.ts +486 -0
- package/dist/typography.css +22 -0
- package/dist/typography.css.d.ts +2 -0
- package/package.json +207 -0
|
@@ -0,0 +1,1119 @@
|
|
|
1
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Corner rounding parameters for polygon vertices.
|
|
5
|
+
* Ported from androidx.graphics.shapes.CornerRounding.kt
|
|
6
|
+
*
|
|
7
|
+
* @see https://m3.material.io/styles/shape/corner-radius-scale
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Defines how a polygon corner is rounded.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // Fully rounded corner with radius 16
|
|
14
|
+
* const rounding: CornerRounding = { radius: 16, smoothing: 0 };
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Rounded corner with iOS-style squircle smoothing
|
|
18
|
+
* const smoothRounding: CornerRounding = { radius: 16, smoothing: 0.6 };
|
|
19
|
+
*/
|
|
20
|
+
interface CornerRounding {
|
|
21
|
+
/**
|
|
22
|
+
* The radius of the rounding. A value of 0 means no rounding (sharp corner).
|
|
23
|
+
* @default 0
|
|
24
|
+
*/
|
|
25
|
+
readonly radius: number;
|
|
26
|
+
/**
|
|
27
|
+
* Smoothing factor in [0, 1]. Controls how the rounding curve transitions from
|
|
28
|
+
* the straight edge to the circular arc (squircle-like effect).
|
|
29
|
+
* 0 = pure circular arc, 1 = maximum smoothing.
|
|
30
|
+
* @default 0
|
|
31
|
+
*/
|
|
32
|
+
readonly smoothing: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a CornerRounding.
|
|
36
|
+
* @param radius - Rounding radius (default: 0)
|
|
37
|
+
* @param smoothing - Smoothing factor 0–1 (default: 0)
|
|
38
|
+
*/
|
|
39
|
+
declare function cornerRounding(radius?: number, smoothing?: number): CornerRounding;
|
|
40
|
+
/** No rounding: straight/sharp corners. */
|
|
41
|
+
declare const UNROUNDED: CornerRounding;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Shared utility constants and functions for the MD3 Expressive Shape Engine.
|
|
45
|
+
* Ported from androidx.graphics.shapes.Utils.kt
|
|
46
|
+
*
|
|
47
|
+
* @see https://m3.material.io/styles/shape/overview-principles
|
|
48
|
+
*/
|
|
49
|
+
/** Epsilon for floating-point distance comparisons */
|
|
50
|
+
declare const DISTANCE_EPSILON = 0.0001;
|
|
51
|
+
/** Epsilon for angle comparisons */
|
|
52
|
+
declare const ANGLE_EPSILON = 0.0001;
|
|
53
|
+
/** Pi as a float constant */
|
|
54
|
+
declare const FLOAT_PI: number;
|
|
55
|
+
/**
|
|
56
|
+
* Calculates the Euclidean distance between two coordinate offsets.
|
|
57
|
+
* @param dx - Difference in x coordinates
|
|
58
|
+
* @param dy - Difference in y coordinates
|
|
59
|
+
* @returns The distance
|
|
60
|
+
*/
|
|
61
|
+
declare function distance(dx: number, dy: number): number;
|
|
62
|
+
/**
|
|
63
|
+
* Calculates the squared Euclidean distance (cheaper than distance).
|
|
64
|
+
* @param dx - Difference in x coordinates
|
|
65
|
+
* @param dy - Difference in y coordinates
|
|
66
|
+
* @returns The squared distance
|
|
67
|
+
*/
|
|
68
|
+
declare function distanceSquared(dx: number, dy: number): number;
|
|
69
|
+
/**
|
|
70
|
+
* Converts polar coordinates to Cartesian (x, y).
|
|
71
|
+
* @param radius - The radial distance
|
|
72
|
+
* @param angle - The angle in radians
|
|
73
|
+
* @returns A tuple [x, y]
|
|
74
|
+
*/
|
|
75
|
+
declare function radialToCartesian(radius: number, angle: number): [number, number];
|
|
76
|
+
/**
|
|
77
|
+
* Returns value modulo divisor, always positive.
|
|
78
|
+
* @param value - The value
|
|
79
|
+
* @param divisor - The divisor
|
|
80
|
+
* @returns Positive modulo result
|
|
81
|
+
*/
|
|
82
|
+
declare function positiveModulo(value: number, divisor: number): number;
|
|
83
|
+
/**
|
|
84
|
+
* Linearly interpolates between start and stop.
|
|
85
|
+
* @param start - Start value (at fraction=0)
|
|
86
|
+
* @param stop - End value (at fraction=1)
|
|
87
|
+
* @param fraction - Interpolation factor [0,1]
|
|
88
|
+
* @returns Interpolated value
|
|
89
|
+
*/
|
|
90
|
+
declare function interpolate(start: number, stop: number, fraction: number): number;
|
|
91
|
+
/**
|
|
92
|
+
* Returns the square of a value.
|
|
93
|
+
* @param value - The value to square
|
|
94
|
+
*/
|
|
95
|
+
declare function square(value: number): number;
|
|
96
|
+
/**
|
|
97
|
+
* Returns a unit direction vector from (0,0) toward (dx, dy).
|
|
98
|
+
* @param dx - X component
|
|
99
|
+
* @param dy - Y component
|
|
100
|
+
* @returns [nx, ny] normalized direction
|
|
101
|
+
*/
|
|
102
|
+
declare function directionVector(dx: number, dy: number): [number, number];
|
|
103
|
+
/**
|
|
104
|
+
* Checks if the turn from prev→curr→next is convex (clockwise in screen coords).
|
|
105
|
+
* @param prevX - Previous vertex x
|
|
106
|
+
* @param prevY - Previous vertex y
|
|
107
|
+
* @param currX - Current vertex x
|
|
108
|
+
* @param currY - Current vertex y
|
|
109
|
+
* @param nextX - Next vertex x
|
|
110
|
+
* @param nextY - Next vertex y
|
|
111
|
+
* @returns true if convex
|
|
112
|
+
*/
|
|
113
|
+
declare function convex(prevX: number, prevY: number, currX: number, currY: number, nextX: number, nextY: number): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Type for a function that transforms a point (x, y) → (x', y').
|
|
116
|
+
*/
|
|
117
|
+
type PointTransformer = (x: number, y: number) => [number, number];
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Point type and operations for the MD3 Expressive Shape Engine.
|
|
121
|
+
* Ported from androidx.graphics.shapes.Point.kt
|
|
122
|
+
*
|
|
123
|
+
* In Kotlin, Point is a type alias for FloatFloatPair. Here we use a plain object
|
|
124
|
+
* for zero-overhead structural typing in TypeScript.
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
/** A 2D point or vector. */
|
|
128
|
+
interface Point {
|
|
129
|
+
readonly x: number;
|
|
130
|
+
readonly y: number;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Creates a new Point.
|
|
134
|
+
* @param x - X coordinate
|
|
135
|
+
* @param y - Y coordinate
|
|
136
|
+
*/
|
|
137
|
+
declare function point(x: number, y: number): Point;
|
|
138
|
+
/**
|
|
139
|
+
* Returns the magnitude (distance from origin) of the point.
|
|
140
|
+
* @param p - The point
|
|
141
|
+
*/
|
|
142
|
+
declare function getDistance(p: Point): number;
|
|
143
|
+
/**
|
|
144
|
+
* Returns the squared magnitude of the point (cheaper than getDistance).
|
|
145
|
+
* @param p - The point
|
|
146
|
+
*/
|
|
147
|
+
declare function getDistanceSquared(p: Point): number;
|
|
148
|
+
/**
|
|
149
|
+
* Dot product of two points (treated as vectors).
|
|
150
|
+
* @param a - First point
|
|
151
|
+
* @param b - Second point
|
|
152
|
+
*/
|
|
153
|
+
declare function dotProduct(a: Point, b: Point): number;
|
|
154
|
+
/**
|
|
155
|
+
* Rotates the point 90 degrees counter-clockwise.
|
|
156
|
+
* @param p - The point
|
|
157
|
+
* @returns New rotated point
|
|
158
|
+
*/
|
|
159
|
+
declare function rotate90(p: Point): Point;
|
|
160
|
+
/**
|
|
161
|
+
* Returns the unit vector in the direction of the point from (0,0).
|
|
162
|
+
* @param p - The point
|
|
163
|
+
* @throws Error if the point is at the origin
|
|
164
|
+
*/
|
|
165
|
+
declare function getDirection(p: Point): Point;
|
|
166
|
+
/**
|
|
167
|
+
* Checks if p0→p1→p2 turn is clockwise (positive cross product in screen coords).
|
|
168
|
+
* @param p0 - Previous point
|
|
169
|
+
* @param p1 - Current point
|
|
170
|
+
* @param p2 - Next point
|
|
171
|
+
*/
|
|
172
|
+
declare function clockwise(p0: Point, p1: Point, p2: Point): boolean;
|
|
173
|
+
/** Point addition. */
|
|
174
|
+
declare function addPoints(a: Point, b: Point): Point;
|
|
175
|
+
/** Point subtraction. */
|
|
176
|
+
declare function subtractPoints(a: Point, b: Point): Point;
|
|
177
|
+
/** Scalar multiplication. */
|
|
178
|
+
declare function scalePoint(p: Point, scalar: number): Point;
|
|
179
|
+
/** Scalar division. */
|
|
180
|
+
declare function dividePoint(p: Point, scalar: number): Point;
|
|
181
|
+
/**
|
|
182
|
+
* Linearly interpolates between two points.
|
|
183
|
+
* @param start - Start point (at fraction=0)
|
|
184
|
+
* @param stop - End point (at fraction=1)
|
|
185
|
+
* @param fraction - Interpolation factor [0,1]
|
|
186
|
+
*/
|
|
187
|
+
declare function lerpPoint(start: Point, stop: Point, fraction: number): Point;
|
|
188
|
+
/**
|
|
189
|
+
* Applies a PointTransformer to a point.
|
|
190
|
+
* @param p - The original point
|
|
191
|
+
* @param fn - The transform function
|
|
192
|
+
*/
|
|
193
|
+
declare function transformPoint(p: Point, fn: PointTransformer): Point;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Cubic Bézier curve type for the MD3 Expressive Shape Engine.
|
|
197
|
+
* Ported from androidx.graphics.shapes.Cubic.kt
|
|
198
|
+
*
|
|
199
|
+
* A cubic holds 8 floats: [anchor0X, anchor0Y, control0X, control0Y, control1X, control1Y, anchor1X, anchor1Y]
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* A single cubic Bézier curve segment.
|
|
204
|
+
*
|
|
205
|
+
* The curve goes from anchor0 → (via control0, control1) → anchor1.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* const line = Cubic.straightLine(0, 0, 1, 0);
|
|
209
|
+
* const arc = Cubic.circularArc(0, 0, 1, 0, 0, 1);
|
|
210
|
+
*/
|
|
211
|
+
declare class Cubic {
|
|
212
|
+
/** Internal storage: [a0x, a0y, c0x, c0y, c1x, c1y, a1x, a1y] */
|
|
213
|
+
readonly points: number[];
|
|
214
|
+
constructor(points: number[]);
|
|
215
|
+
/** First anchor point X */
|
|
216
|
+
get anchor0X(): number;
|
|
217
|
+
/** First anchor point Y */
|
|
218
|
+
get anchor0Y(): number;
|
|
219
|
+
/** First control point X */
|
|
220
|
+
get control0X(): number;
|
|
221
|
+
/** First control point Y */
|
|
222
|
+
get control0Y(): number;
|
|
223
|
+
/** Second control point X */
|
|
224
|
+
get control1X(): number;
|
|
225
|
+
/** Second control point Y */
|
|
226
|
+
get control1Y(): number;
|
|
227
|
+
/** Second anchor point X */
|
|
228
|
+
get anchor1X(): number;
|
|
229
|
+
/** Second anchor point Y */
|
|
230
|
+
get anchor1Y(): number;
|
|
231
|
+
/**
|
|
232
|
+
* Returns a point on the curve at parameter t (0=start, 1=end).
|
|
233
|
+
* Uses the standard cubic Bézier formula.
|
|
234
|
+
* @param t - Parameter in [0, 1]
|
|
235
|
+
*/
|
|
236
|
+
pointOnCurve(t: number): Point;
|
|
237
|
+
/**
|
|
238
|
+
* Returns true if this curve has (near) zero length.
|
|
239
|
+
*/
|
|
240
|
+
zeroLength(): boolean;
|
|
241
|
+
/**
|
|
242
|
+
* Splits this cubic at parameter t, returning two cubics.
|
|
243
|
+
* Uses De Casteljau's algorithm.
|
|
244
|
+
* @param t - Split parameter in [0, 1]
|
|
245
|
+
* @returns [left, right] pair
|
|
246
|
+
*/
|
|
247
|
+
split(t: number): [Cubic, Cubic];
|
|
248
|
+
/**
|
|
249
|
+
* Returns a reversed copy of this cubic (anchor0 ↔ anchor1, controls swapped).
|
|
250
|
+
*/
|
|
251
|
+
reverse(): Cubic;
|
|
252
|
+
/**
|
|
253
|
+
* Calculates the axis-aligned bounding box.
|
|
254
|
+
* @param approximate - If true, uses control point hull (faster). Default: false.
|
|
255
|
+
* @returns [minX, minY, maxX, maxY]
|
|
256
|
+
*/
|
|
257
|
+
calculateBounds(approximate?: boolean): [number, number, number, number];
|
|
258
|
+
/**
|
|
259
|
+
* Interpolates between this cubic and another at fraction t.
|
|
260
|
+
* @param other - Target cubic
|
|
261
|
+
* @param t - Fraction [0, 1]
|
|
262
|
+
*/
|
|
263
|
+
interpolateTo(other: Cubic, t: number): Cubic;
|
|
264
|
+
/**
|
|
265
|
+
* Applies a PointTransformer to all anchor and control points.
|
|
266
|
+
* @param fn - The transform function
|
|
267
|
+
*/
|
|
268
|
+
transformed(fn: PointTransformer): Cubic;
|
|
269
|
+
toString(): string;
|
|
270
|
+
/**
|
|
271
|
+
* Creates a cubic representing a straight line.
|
|
272
|
+
* Control points lie at 1/3 and 2/3 of the line.
|
|
273
|
+
* @param x0 - Start anchor X
|
|
274
|
+
* @param y0 - Start anchor Y
|
|
275
|
+
* @param x1 - End anchor X
|
|
276
|
+
* @param y1 - End anchor Y
|
|
277
|
+
*/
|
|
278
|
+
static straightLine(x0: number, y0: number, x1: number, y1: number): Cubic;
|
|
279
|
+
/**
|
|
280
|
+
* Creates a cubic approximating a circular arc.
|
|
281
|
+
* p0 and p1 must be equidistant from the center.
|
|
282
|
+
* For arcs > 180°, use multiple cubics.
|
|
283
|
+
*
|
|
284
|
+
* @param centerX - Arc center X
|
|
285
|
+
* @param centerY - Arc center Y
|
|
286
|
+
* @param x0 - Start point X (on circle)
|
|
287
|
+
* @param y0 - Start point Y (on circle)
|
|
288
|
+
* @param x1 - End point X (on circle)
|
|
289
|
+
* @param y1 - End point Y (on circle)
|
|
290
|
+
*/
|
|
291
|
+
static circularArc(centerX: number, centerY: number, x0: number, y0: number, x1: number, y1: number): Cubic;
|
|
292
|
+
/**
|
|
293
|
+
* Creates a zero-length cubic at the given point.
|
|
294
|
+
* @param x - X coordinate
|
|
295
|
+
* @param y - Y coordinate
|
|
296
|
+
*/
|
|
297
|
+
static empty(x: number, y: number): Cubic;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* A mutable version of Cubic used in performance-critical paths (Morph.forEachCubic).
|
|
301
|
+
* Reuses the same instance to avoid allocations.
|
|
302
|
+
*/
|
|
303
|
+
declare class MutableCubic extends Cubic {
|
|
304
|
+
constructor();
|
|
305
|
+
/**
|
|
306
|
+
* Mutably interpolates between c1 and c2 at the given progress.
|
|
307
|
+
* @param c1 - Start cubic
|
|
308
|
+
* @param c2 - End cubic
|
|
309
|
+
* @param progress - Interpolation factor [0, 1]
|
|
310
|
+
*/
|
|
311
|
+
interpolate(c1: Cubic, c2: Cubic, progress: number): void;
|
|
312
|
+
/**
|
|
313
|
+
* Mutably applies a PointTransformer to all points.
|
|
314
|
+
* @param fn - The transform function
|
|
315
|
+
*/
|
|
316
|
+
transform(fn: PointTransformer): void;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Feature types for the MD3 Expressive Shape Engine.
|
|
321
|
+
* Ported from androidx.graphics.shapes.Features.kt
|
|
322
|
+
*
|
|
323
|
+
* Features describe the outline segments of a RoundedPolygon:
|
|
324
|
+
* - Corner: a (potentially rounded) vertex
|
|
325
|
+
* - Edge: a straight or curved segment between two corners
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* A discriminated union representing one outline segment of a polygon.
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* const corner: Feature = { type: "corner", cubics: [...], convex: true };
|
|
333
|
+
* const edge: Feature = { type: "edge", cubics: [...] };
|
|
334
|
+
*/
|
|
335
|
+
type Feature = CornerFeature | EdgeFeature;
|
|
336
|
+
/** A (potentially rounded) corner vertex. */
|
|
337
|
+
interface CornerFeature {
|
|
338
|
+
readonly type: "corner";
|
|
339
|
+
/**
|
|
340
|
+
* Cubic curves making up this corner.
|
|
341
|
+
* Unrounded corner = 1 zero-length cubic. Rounded = 1–3 cubics (flanking + arc + flanking).
|
|
342
|
+
*/
|
|
343
|
+
readonly cubics: Cubic[];
|
|
344
|
+
/** True if this corner is convex (pointing outward). */
|
|
345
|
+
readonly convex: boolean;
|
|
346
|
+
}
|
|
347
|
+
/** A straight or curved edge segment between two corners. */
|
|
348
|
+
interface EdgeFeature {
|
|
349
|
+
readonly type: "edge";
|
|
350
|
+
/** Cubic curves making up this edge (usually a single straight-line cubic). */
|
|
351
|
+
readonly cubics: Cubic[];
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Creates a corner feature.
|
|
355
|
+
* @param cubics - Cubic curves defining the corner shape
|
|
356
|
+
* @param convex - Whether the corner is convex
|
|
357
|
+
*/
|
|
358
|
+
declare function cornerFeature(cubics: Cubic[], convex: boolean): CornerFeature;
|
|
359
|
+
/**
|
|
360
|
+
* Creates an edge feature.
|
|
361
|
+
* @param cubics - Cubic curves defining the edge
|
|
362
|
+
*/
|
|
363
|
+
declare function edgeFeature(cubics: Cubic[]): EdgeFeature;
|
|
364
|
+
/**
|
|
365
|
+
* Returns a transformed copy of a feature.
|
|
366
|
+
* @param feature - The feature to transform
|
|
367
|
+
* @param fn - Point transformer function
|
|
368
|
+
*/
|
|
369
|
+
declare function transformFeature(feature: Feature, fn: PointTransformer): Feature;
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* RoundedPolygon — core shape class for the MD3 Expressive Shape Engine.
|
|
373
|
+
* Ported from androidx.graphics.shapes.RoundedPolygon.kt
|
|
374
|
+
*
|
|
375
|
+
* A RoundedPolygon is defined by a list of Feature (Corner + Edge) objects.
|
|
376
|
+
* Its geometry is stored as a flat list of Cubic Bézier curves that form
|
|
377
|
+
* a closed, contiguous outline.
|
|
378
|
+
*/
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* The core shape class. Represents a closed polygon outline as a list of Cubic
|
|
382
|
+
* Bézier curves, optionally rounded at the vertices.
|
|
383
|
+
*
|
|
384
|
+
* All shapes in MD3 Expressive are represented as RoundedPolygon instances.
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* // Create a circle (8-vertex polygon, fully rounded)
|
|
388
|
+
* const circle = RoundedPolygon.circle();
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* // Create a rounded rectangle
|
|
392
|
+
* const rect = RoundedPolygon.rectangle(2, 1, { radius: 0.25, smoothing: 0 });
|
|
393
|
+
*/
|
|
394
|
+
declare class RoundedPolygon {
|
|
395
|
+
/** Flat list of cubic Bézier curves forming the closed outline. */
|
|
396
|
+
readonly cubics: Cubic[];
|
|
397
|
+
/** Feature list (corners + edges). */
|
|
398
|
+
readonly features: Feature[];
|
|
399
|
+
/** Center point of the polygon. */
|
|
400
|
+
readonly center: Point;
|
|
401
|
+
/** @internal Use static factory methods instead */
|
|
402
|
+
private constructor();
|
|
403
|
+
get centerX(): number;
|
|
404
|
+
get centerY(): number;
|
|
405
|
+
/**
|
|
406
|
+
* Creates a polygon from a vertex count (regular polygon).
|
|
407
|
+
* @param numVertices - Number of vertices (≥ 3)
|
|
408
|
+
* @param radius - Circumradius (default: 1)
|
|
409
|
+
* @param centerX - Center X (default: 0)
|
|
410
|
+
* @param centerY - Center Y (default: 0)
|
|
411
|
+
* @param rounding - Corner rounding for all vertices
|
|
412
|
+
* @param perVertexRounding - Per-vertex rounding overrides
|
|
413
|
+
*/
|
|
414
|
+
static fromNumVertices(numVertices: number, radius?: number, centerX?: number, centerY?: number, rounding?: CornerRounding, perVertexRounding?: CornerRounding[]): RoundedPolygon;
|
|
415
|
+
/**
|
|
416
|
+
* Creates a polygon from a flat vertex array [x0, y0, x1, y1, ...].
|
|
417
|
+
* @param vertices - Flat array of x,y pairs (length must be even and ≥ 6)
|
|
418
|
+
* @param rounding - Corner rounding for all vertices
|
|
419
|
+
* @param perVertexRounding - Per-vertex rounding overrides
|
|
420
|
+
* @param centerX - Center X (auto-calculated if not provided)
|
|
421
|
+
* @param centerY - Center Y (auto-calculated if not provided)
|
|
422
|
+
*/
|
|
423
|
+
static fromVertices(vertices: number[], rounding?: CornerRounding, perVertexRounding?: CornerRounding[], centerX?: number, centerY?: number): RoundedPolygon;
|
|
424
|
+
/**
|
|
425
|
+
* Creates a polygon from a pre-built Feature list.
|
|
426
|
+
* @param features - Feature list (≥ 2 features)
|
|
427
|
+
* @param centerX - Center X (auto-calculated if NaN)
|
|
428
|
+
* @param centerY - Center Y (auto-calculated if NaN)
|
|
429
|
+
*/
|
|
430
|
+
static fromFeatures(features: Feature[], centerX?: number, centerY?: number): RoundedPolygon;
|
|
431
|
+
/**
|
|
432
|
+
* Returns a new RoundedPolygon with all points transformed.
|
|
433
|
+
* @param fn - Transform function: (x, y) => [x', y']
|
|
434
|
+
*/
|
|
435
|
+
transformed(fn: PointTransformer): RoundedPolygon;
|
|
436
|
+
/**
|
|
437
|
+
* Returns a normalized copy: scaled and centered to fit in [0,1] × [0,1].
|
|
438
|
+
* Maintains aspect ratio by using the larger dimension.
|
|
439
|
+
*/
|
|
440
|
+
normalized(): RoundedPolygon;
|
|
441
|
+
/**
|
|
442
|
+
* Calculates the axis-aligned bounding box.
|
|
443
|
+
* @param approximate - If true, uses control point hull (faster). Default: true.
|
|
444
|
+
* @returns [minX, minY, maxX, maxY]
|
|
445
|
+
*/
|
|
446
|
+
calculateBounds(approximate?: boolean): [number, number, number, number];
|
|
447
|
+
/**
|
|
448
|
+
* Calculates the maximum bounding square (useful for shapes that rotate).
|
|
449
|
+
* @returns [minX, minY, maxX, maxY] of the max-bounds square
|
|
450
|
+
*/
|
|
451
|
+
calculateMaxBounds(): [number, number, number, number];
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* MD3 Expressive Shape Catalog — auto-generated from SVGs.
|
|
456
|
+
*
|
|
457
|
+
* Each shape is a pre-normalized RoundedPolygon (fits in [0,1]×[0,1], centered at (0.5, 0.5)).
|
|
458
|
+
* Regenerated via scratch/generate-shapes.ts.
|
|
459
|
+
*/
|
|
460
|
+
|
|
461
|
+
declare const MD3Shapes: {
|
|
462
|
+
readonly arch: RoundedPolygon;
|
|
463
|
+
readonly arrow: RoundedPolygon;
|
|
464
|
+
readonly boom: RoundedPolygon;
|
|
465
|
+
readonly bun: RoundedPolygon;
|
|
466
|
+
readonly burst: RoundedPolygon;
|
|
467
|
+
readonly circle: RoundedPolygon;
|
|
468
|
+
readonly clamshell: RoundedPolygon;
|
|
469
|
+
readonly diamond: RoundedPolygon;
|
|
470
|
+
readonly fan: RoundedPolygon;
|
|
471
|
+
readonly flower: RoundedPolygon;
|
|
472
|
+
readonly gem: RoundedPolygon;
|
|
473
|
+
readonly ghostish: RoundedPolygon;
|
|
474
|
+
readonly heart: RoundedPolygon;
|
|
475
|
+
readonly clover4Leaf: RoundedPolygon;
|
|
476
|
+
readonly clover8Leaf: RoundedPolygon;
|
|
477
|
+
readonly oval: RoundedPolygon;
|
|
478
|
+
readonly pentagon: RoundedPolygon;
|
|
479
|
+
readonly pill: RoundedPolygon;
|
|
480
|
+
readonly pixelCircle: RoundedPolygon;
|
|
481
|
+
readonly pixelTriangle: RoundedPolygon;
|
|
482
|
+
readonly puffyDiamond: RoundedPolygon;
|
|
483
|
+
readonly puffy: RoundedPolygon;
|
|
484
|
+
readonly semiCircle: RoundedPolygon;
|
|
485
|
+
readonly cookie12Sided: RoundedPolygon;
|
|
486
|
+
readonly cookie4Sided: RoundedPolygon;
|
|
487
|
+
readonly cookie6Sided: RoundedPolygon;
|
|
488
|
+
readonly cookie7Sided: RoundedPolygon;
|
|
489
|
+
readonly cookie9Sided: RoundedPolygon;
|
|
490
|
+
readonly slanted: RoundedPolygon;
|
|
491
|
+
readonly softBoom: RoundedPolygon;
|
|
492
|
+
readonly softBurst: RoundedPolygon;
|
|
493
|
+
readonly square: RoundedPolygon;
|
|
494
|
+
readonly sunny: RoundedPolygon;
|
|
495
|
+
readonly triangle: RoundedPolygon;
|
|
496
|
+
readonly verySunny: RoundedPolygon;
|
|
497
|
+
};
|
|
498
|
+
type MD3ShapeName = keyof typeof MD3Shapes;
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* MD3 Corner Radius Token Scale.
|
|
502
|
+
* Ported from MD3 spec: https://m3.material.io/styles/shape/corner-radius-scale
|
|
503
|
+
*
|
|
504
|
+
* The Material 3 shape system uses a 10-step size-based scale.
|
|
505
|
+
* All values are in density-independent pixels (dp).
|
|
506
|
+
*
|
|
507
|
+
* @example
|
|
508
|
+
* import { MD3CornerRadius } from "@bug-on/m3-expressive";
|
|
509
|
+
*
|
|
510
|
+
* // Use a token name
|
|
511
|
+
* const rounding = { radius: MD3CornerRadius.large, smoothing: 0 };
|
|
512
|
+
*
|
|
513
|
+
* // Use with ShapeMedia
|
|
514
|
+
* <ShapeMedia shape="pill" cornerRadius="extraLarge" ... />
|
|
515
|
+
*/
|
|
516
|
+
declare const MD3CornerRadius: {
|
|
517
|
+
/** 0dp — Sharp corners */
|
|
518
|
+
readonly none: 0;
|
|
519
|
+
/** 4dp */
|
|
520
|
+
readonly extraSmall: 4;
|
|
521
|
+
/** 8dp */
|
|
522
|
+
readonly small: 8;
|
|
523
|
+
/** 12dp */
|
|
524
|
+
readonly medium: 12;
|
|
525
|
+
/** 16dp */
|
|
526
|
+
readonly large: 16;
|
|
527
|
+
/** 20dp (new in M3 Expressive) */
|
|
528
|
+
readonly largeIncreased: 20;
|
|
529
|
+
/** 28dp */
|
|
530
|
+
readonly extraLarge: 28;
|
|
531
|
+
/** 32dp (new in M3 Expressive) */
|
|
532
|
+
readonly extraLargeIncreased: 32;
|
|
533
|
+
/** 48dp (new in M3 Expressive) */
|
|
534
|
+
readonly extraExtraLarge: 48;
|
|
535
|
+
/** 9999dp — Fully rounded (pill/circle) */
|
|
536
|
+
readonly full: 9999;
|
|
537
|
+
};
|
|
538
|
+
/** Token name for MD3 corner radius scale. */
|
|
539
|
+
type MD3CornerRadiusToken = keyof typeof MD3CornerRadius;
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Shape factory functions for the MD3 Expressive Shape Engine.
|
|
543
|
+
* Ported from androidx.graphics.shapes.Shapes.kt
|
|
544
|
+
*
|
|
545
|
+
* These functions create basic geometric shapes as RoundedPolygon instances.
|
|
546
|
+
* All shapes default to being centered at (0,0) with radius 1.
|
|
547
|
+
*/
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Creates a circular shape approximated by a rounded polygon.
|
|
551
|
+
*
|
|
552
|
+
* @param numVertices - Number of polygon vertices (≥ 3, default: 8)
|
|
553
|
+
* @param radius - Circle radius (default: 1)
|
|
554
|
+
* @param centerX - Center X (default: 0)
|
|
555
|
+
* @param centerY - Center Y (default: 0)
|
|
556
|
+
* @returns A RoundedPolygon approximating a circle
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* const myCircle = circle(8, 100, 0, 0);
|
|
560
|
+
*/
|
|
561
|
+
declare function circle(numVertices?: number, radius?: number, centerX?: number, centerY?: number): RoundedPolygon;
|
|
562
|
+
/**
|
|
563
|
+
* Creates a rectangular shape with optional rounding.
|
|
564
|
+
*
|
|
565
|
+
* @param width - Rectangle width (default: 2)
|
|
566
|
+
* @param height - Rectangle height (default: 2)
|
|
567
|
+
* @param rounding - Corner rounding for all corners (default: none)
|
|
568
|
+
* @param perVertexRounding - Per-corner rounding overrides (length must be 4)
|
|
569
|
+
* @param centerX - Center X (default: 0)
|
|
570
|
+
* @param centerY - Center Y (default: 0)
|
|
571
|
+
*
|
|
572
|
+
* @example
|
|
573
|
+
* // Rounded rectangle
|
|
574
|
+
* const roundedRect = rectangle(2, 1, { radius: 0.25, smoothing: 0 });
|
|
575
|
+
*/
|
|
576
|
+
declare function rectangle(width?: number, height?: number, rounding?: CornerRounding, perVertexRounding?: CornerRounding[], centerX?: number, centerY?: number): RoundedPolygon;
|
|
577
|
+
/**
|
|
578
|
+
* Creates a star-shaped polygon with inner and outer radii.
|
|
579
|
+
*
|
|
580
|
+
* If innerRadius equals radius, the result is a regular polygon with
|
|
581
|
+
* 2 × numVerticesPerRadius vertices.
|
|
582
|
+
*
|
|
583
|
+
* @param numVerticesPerRadius - Vertices per radius (outer + inner)
|
|
584
|
+
* @param radius - Outer radius (default: 1)
|
|
585
|
+
* @param innerRadius - Inner radius (default: 0.5)
|
|
586
|
+
* @param rounding - Corner rounding for outer vertices (default: none)
|
|
587
|
+
* @param innerRounding - Corner rounding for inner vertices (default: uses rounding)
|
|
588
|
+
* @param perVertexRounding - Full per-vertex rounding list
|
|
589
|
+
* @param centerX - Center X (default: 0)
|
|
590
|
+
* @param centerY - Center Y (default: 0)
|
|
591
|
+
*
|
|
592
|
+
* @example
|
|
593
|
+
* // 8-pointed star
|
|
594
|
+
* const star8 = star(8, 1, 0.4);
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* // Rounded sunny shape
|
|
598
|
+
* const sunny = star(8, 1, 0.75, { radius: 0.15, smoothing: 0 }, { radius: 0.05, smoothing: 0 });
|
|
599
|
+
*/
|
|
600
|
+
declare function star(numVerticesPerRadius: number, radius?: number, innerRadius?: number, rounding?: CornerRounding, innerRounding?: CornerRounding, perVertexRounding?: CornerRounding[], centerX?: number, centerY?: number): RoundedPolygon;
|
|
601
|
+
/**
|
|
602
|
+
* Creates a pill shape: rectangle with fully-rounded short ends.
|
|
603
|
+
*
|
|
604
|
+
* @param width - Width of the pill (default: 2)
|
|
605
|
+
* @param height - Height of the pill (default: 1)
|
|
606
|
+
* @param smoothing - Corner smoothing factor [0,1] (default: 0)
|
|
607
|
+
* @param centerX - Center X (default: 0)
|
|
608
|
+
* @param centerY - Center Y (default: 0)
|
|
609
|
+
*
|
|
610
|
+
* @example
|
|
611
|
+
* const pillShape = pill(3, 1);
|
|
612
|
+
*/
|
|
613
|
+
declare function pill(width?: number, height?: number, smoothing?: number, centerX?: number, centerY?: number): RoundedPolygon;
|
|
614
|
+
/**
|
|
615
|
+
* Creates a pill-star shape: like a pill but with star-like inner/outer vertices.
|
|
616
|
+
*
|
|
617
|
+
* @param width - Width (default: 2)
|
|
618
|
+
* @param height - Height (default: 1)
|
|
619
|
+
* @param numVerticesPerRadius - Number of point pairs per radius
|
|
620
|
+
* @param innerRadiusRatio - Inner radius as fraction of outer (default: 0.5)
|
|
621
|
+
* @param rounding - Outer vertex rounding (default: none)
|
|
622
|
+
* @param innerRounding - Inner vertex rounding (default: uses rounding)
|
|
623
|
+
* @param perVertexRounding - Full per-vertex rounding list
|
|
624
|
+
* @param vertexSpacing - Spacing factor [0,1] (default: 0.5)
|
|
625
|
+
* @param centerX - Center X (default: 0)
|
|
626
|
+
* @param centerY - Center Y (default: 0)
|
|
627
|
+
*/
|
|
628
|
+
declare function pillStar(width?: number, height?: number, numVerticesPerRadius?: number, innerRadiusRatio?: number, rounding?: CornerRounding, innerRounding?: CornerRounding, perVertexRounding?: CornerRounding[], vertexSpacing?: number, centerX?: number, centerY?: number): RoundedPolygon;
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* DoubleMapper: bidirectional mapper used in the Morph matching algorithm.
|
|
632
|
+
* Maps progress values from polygon1 space → polygon2 space and vice versa.
|
|
633
|
+
*/
|
|
634
|
+
interface DoubleMapper {
|
|
635
|
+
/** Maps a progress value from the start polygon to the end polygon. */
|
|
636
|
+
map(progress: number): number;
|
|
637
|
+
/** Maps a progress value from the end polygon back to the start polygon. */
|
|
638
|
+
mapBack(progress: number): number;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Creates a DoubleMapper from two parallel arrays of mapped progress values.
|
|
642
|
+
* Used internally by featureMapper.
|
|
643
|
+
*
|
|
644
|
+
* @param fromValues - Progress values in polygon1 space [0..1]
|
|
645
|
+
* @param toValues - Corresponding progress values in polygon2 space [0..1]
|
|
646
|
+
*/
|
|
647
|
+
declare function createDoubleMapper(fromValues: number[], toValues: number[]): DoubleMapper;
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Polygon measurement utilities for the Morph engine.
|
|
651
|
+
* Ported from androidx.graphics.shapes.PolygonMeasure.kt
|
|
652
|
+
*
|
|
653
|
+
* Measures the outline of a RoundedPolygon by arc length, normalizing
|
|
654
|
+
* progress values to [0, 1]. Used by Morph to match curves between polygons.
|
|
655
|
+
*/
|
|
656
|
+
|
|
657
|
+
/** A Cubic with its start/end outline progress values normalized to [0, 1]. */
|
|
658
|
+
interface MeasuredCubic {
|
|
659
|
+
readonly cubic: Cubic;
|
|
660
|
+
readonly startOutlineProgress: number;
|
|
661
|
+
readonly endOutlineProgress: number;
|
|
662
|
+
}
|
|
663
|
+
/** Feature info extracted from a measured polygon (for featureMapper). */
|
|
664
|
+
interface MeasuredFeature {
|
|
665
|
+
/** Progress at the midpoint of this feature's central arc */
|
|
666
|
+
readonly progress: number;
|
|
667
|
+
/** Whether this corner is convex */
|
|
668
|
+
readonly convex: boolean;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* A list of MeasuredCubics covering the full outline of a polygon.
|
|
672
|
+
* Provides methods to cut and shift the polygon at a given progress point.
|
|
673
|
+
*/
|
|
674
|
+
declare class MeasuredPolygon {
|
|
675
|
+
readonly measuredCubics: MeasuredCubic[];
|
|
676
|
+
readonly features: MeasuredFeature[];
|
|
677
|
+
private constructor();
|
|
678
|
+
get size(): number;
|
|
679
|
+
getOrNull(index: number): MeasuredCubic | null;
|
|
680
|
+
/**
|
|
681
|
+
* Cuts the polygon at cutPoint and rotates so that cutPoint becomes progress=0.
|
|
682
|
+
* Returns a new MeasuredPolygon with adjusted progress values.
|
|
683
|
+
* @param cutPoint - Progress value [0, 1] at which to cut
|
|
684
|
+
*/
|
|
685
|
+
cutAndShift(cutPoint: number): MeasuredPolygon;
|
|
686
|
+
/**
|
|
687
|
+
* Cuts a MeasuredCubic at a given outline progress, returning [segment, rest].
|
|
688
|
+
*/
|
|
689
|
+
cutAtProgress(measuredCubic: MeasuredCubic, progress: number): [MeasuredCubic, MeasuredCubic];
|
|
690
|
+
/**
|
|
691
|
+
* Measures a RoundedPolygon's outline by arc length.
|
|
692
|
+
* Returns a MeasuredPolygon with normalized progress in [0, 1].
|
|
693
|
+
*/
|
|
694
|
+
static measurePolygon(polygon: RoundedPolygon): MeasuredPolygon;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Feature mapping for the Morph engine.
|
|
699
|
+
* Ported from androidx.graphics.shapes.FeatureMapping.kt
|
|
700
|
+
*
|
|
701
|
+
* Maps corners between two polygons by proximity, enabling the Morph engine
|
|
702
|
+
* to create smooth transitions between shapes with different vertex counts.
|
|
703
|
+
*/
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Creates a DoubleMapper that maps progress values between two polygons
|
|
707
|
+
* based on matching their convex corners by proximity.
|
|
708
|
+
*
|
|
709
|
+
* The algorithm:
|
|
710
|
+
* 1. Extract convex corner progress values from both polygons
|
|
711
|
+
* 2. Match each corner in polygon1 to the closest corner of the same type in polygon2
|
|
712
|
+
* 3. Build a piecewise-linear bidirectional mapper
|
|
713
|
+
*
|
|
714
|
+
* @param features1 - Measured features from polygon 1
|
|
715
|
+
* @param features2 - Measured features from polygon 2
|
|
716
|
+
* @returns A DoubleMapper for bidirectional progress mapping
|
|
717
|
+
*/
|
|
718
|
+
declare function featureMapper(features1: MeasuredFeature[], features2: MeasuredFeature[]): DoubleMapper;
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Morph — animates between two RoundedPolygon shapes.
|
|
722
|
+
* Ported from androidx.graphics.shapes.Morph.kt
|
|
723
|
+
*
|
|
724
|
+
* The Morph class pre-computes a list of matched cubic pairs at construction time.
|
|
725
|
+
* Animating between shapes is then a simple per-pair linear interpolation.
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* const morph = new Morph(MD3Shapes.circle, MD3Shapes.flower);
|
|
729
|
+
* const cubics = morph.asCubics(0.5); // halfway between circle and flower
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* // Zero-allocation iteration (for animation loops)
|
|
733
|
+
* morph.forEachCubic(progress, (c) => {
|
|
734
|
+
* ctx.bezierCurveTo(c.control0X, c.control0Y, c.control1X, c.control1Y, c.anchor1X, c.anchor1Y);
|
|
735
|
+
* });
|
|
736
|
+
*/
|
|
737
|
+
|
|
738
|
+
/** A matched pair of cubics (start shape, end shape). */
|
|
739
|
+
type CubicPair = readonly [Cubic, Cubic];
|
|
740
|
+
/**
|
|
741
|
+
* Animates between two RoundedPolygon shapes.
|
|
742
|
+
*
|
|
743
|
+
* At construction time, Morph matches the cubic curves of both shapes using
|
|
744
|
+
* the featureMapper algorithm. This produces a list of CubicPairs, which can
|
|
745
|
+
* then be interpolated at any progress value.
|
|
746
|
+
*/
|
|
747
|
+
declare class Morph {
|
|
748
|
+
private readonly start;
|
|
749
|
+
private readonly end;
|
|
750
|
+
/** Pre-computed list of matched cubic pairs. @internal */
|
|
751
|
+
private readonly morphMatch;
|
|
752
|
+
/**
|
|
753
|
+
* Creates a Morph between two shapes.
|
|
754
|
+
* @param start - Starting shape
|
|
755
|
+
* @param end - Ending shape
|
|
756
|
+
*/
|
|
757
|
+
constructor(start: RoundedPolygon, end: RoundedPolygon);
|
|
758
|
+
/**
|
|
759
|
+
* Returns the interpolated shape at the given progress as a list of Cubics.
|
|
760
|
+
*
|
|
761
|
+
* Note: This allocates a new list. For performance-critical animation loops,
|
|
762
|
+
* use {@link forEachCubic} instead.
|
|
763
|
+
*
|
|
764
|
+
* @param progress - Value in [0, 1]. 0 = start shape, 1 = end shape.
|
|
765
|
+
* Values outside [0, 1] produce exaggerated shapes (useful for bounce/overshoot).
|
|
766
|
+
* @returns List of interpolated Cubic curves forming the morphed shape
|
|
767
|
+
*/
|
|
768
|
+
asCubics(progress: number): Cubic[];
|
|
769
|
+
/**
|
|
770
|
+
* Iterates over the morphed cubics without allocating new Cubic instances.
|
|
771
|
+
* Reuses a single MutableCubic for each callback invocation.
|
|
772
|
+
*
|
|
773
|
+
* @param progress - Value in [0, 1]
|
|
774
|
+
* @param callback - Called for each interpolated cubic
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* const mutable = new MutableCubic();
|
|
778
|
+
* morph.forEachCubic(progress, mutable, (c) => {
|
|
779
|
+
* path.bezierCurveTo(c.control0X, c.control0Y, c.control1X, c.control1Y, c.anchor1X, c.anchor1Y);
|
|
780
|
+
* });
|
|
781
|
+
*/
|
|
782
|
+
forEachCubic(progress: number, mutableOrCallback: MutableCubic | ((c: MutableCubic) => void), callback?: (c: MutableCubic) => void): void;
|
|
783
|
+
/**
|
|
784
|
+
* Calculates the axis-aligned bounding box of the morph (union of start + end bounds).
|
|
785
|
+
* @param approximate - Use faster approximate bounds (default: true)
|
|
786
|
+
*/
|
|
787
|
+
calculateBounds(approximate?: boolean): [number, number, number, number];
|
|
788
|
+
/**
|
|
789
|
+
* Calculates the max bounding square (union of start + end max bounds).
|
|
790
|
+
*/
|
|
791
|
+
calculateMaxBounds(): [number, number, number, number];
|
|
792
|
+
/**
|
|
793
|
+
* Matches cubic curves between two polygons.
|
|
794
|
+
*
|
|
795
|
+
* Algorithm:
|
|
796
|
+
* 1. Measure both polygons (arc-length normalized progress)
|
|
797
|
+
* 2. Use featureMapper to determine correspondence between features
|
|
798
|
+
* 3. Cut and shift polygon2 so both start at the same logical point
|
|
799
|
+
* 4. Walk both lists together, splitting curves when one extends past the other
|
|
800
|
+
*
|
|
801
|
+
* @internal
|
|
802
|
+
*/
|
|
803
|
+
private static match;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Rendering utilities: convert RoundedPolygon / Cubic[] to SVG paths and CSS clip-paths.
|
|
808
|
+
*
|
|
809
|
+
* All output paths use absolute coordinates relative to the shape's natural
|
|
810
|
+
* normalized space ([0,1]×[0,1]) or scaled to pixel dimensions.
|
|
811
|
+
*/
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Converts a list of Cubic Bézier curves to an SVG path string.
|
|
815
|
+
*
|
|
816
|
+
* @param cubics - Array of Cubic curves (must be contiguous, closed)
|
|
817
|
+
* @param width - Width in pixels to scale x coordinates (default: 1 = normalized)
|
|
818
|
+
* @param height - Height in pixels to scale y coordinates (default: 1 = normalized)
|
|
819
|
+
* @returns SVG path data string, e.g. "M 0.5 0 C 1 0 1 1 0.5 1 Z"
|
|
820
|
+
*
|
|
821
|
+
* @example
|
|
822
|
+
* const path = toSvgPath(MD3Shapes.circle.cubics, 200, 200);
|
|
823
|
+
* // Use in <path d={path} />
|
|
824
|
+
*/
|
|
825
|
+
declare function toSvgPath(cubics: Cubic[], width?: number, height?: number): string;
|
|
826
|
+
/**
|
|
827
|
+
* Converts a RoundedPolygon to a CSS `clip-path: path(...)` value.
|
|
828
|
+
*
|
|
829
|
+
* @param polygon - Normalized RoundedPolygon (values in [0,1])
|
|
830
|
+
* @param width - Element width in pixels
|
|
831
|
+
* @param height - Element height in pixels
|
|
832
|
+
* @returns CSS clip-path value, e.g. "path('M ...')"
|
|
833
|
+
*
|
|
834
|
+
* @example
|
|
835
|
+
* const clipPath = toClipPath(MD3Shapes.sunny, 200, 200);
|
|
836
|
+
* element.style.clipPath = clipPath;
|
|
837
|
+
*/
|
|
838
|
+
declare function toClipPath(polygon: RoundedPolygon, width: number, height: number): string;
|
|
839
|
+
/**
|
|
840
|
+
* Returns a CSS clip-path for a morphed shape at the given progress.
|
|
841
|
+
*
|
|
842
|
+
* @param morph - A pre-constructed Morph instance
|
|
843
|
+
* @param progress - Interpolation factor in [0, 1]
|
|
844
|
+
* @param width - Element width in pixels
|
|
845
|
+
* @param height - Element height in pixels
|
|
846
|
+
* @returns CSS clip-path value
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* const morph = new Morph(MD3Shapes.circle, MD3Shapes.flower);
|
|
850
|
+
* element.style.clipPath = interpolatePath(morph, 0.5, 200, 200);
|
|
851
|
+
*/
|
|
852
|
+
declare function interpolatePath(morph: Morph, progress: number, width: number, height: number): string;
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Types for ShapeMedia React components.
|
|
856
|
+
*/
|
|
857
|
+
|
|
858
|
+
/** A shape reference: either a named MD3 shape or a custom RoundedPolygon. */
|
|
859
|
+
type ShapeRef = MD3ShapeName | RoundedPolygon;
|
|
860
|
+
/**
|
|
861
|
+
* Trigger for morphing animation.
|
|
862
|
+
* - "hover" — morph on mouse enter/leave
|
|
863
|
+
* - "click" — morph on click (toggle)
|
|
864
|
+
* - "focus" — morph on focus/blur
|
|
865
|
+
* - "scroll" — morph driven by scroll progress (requires scrollProgress prop)
|
|
866
|
+
* - "none" — no automatic morphing (use controlled mode)
|
|
867
|
+
*/
|
|
868
|
+
type MorphTrigger = "hover" | "click" | "focus" | "scroll" | "none";
|
|
869
|
+
/** Options for the morph animation. */
|
|
870
|
+
interface ShapeMorphOptions {
|
|
871
|
+
/** Duration in seconds (default: 0.3) */
|
|
872
|
+
duration?: number;
|
|
873
|
+
/** Easing: any CSS easing string or Framer Motion easing (default: "ease-in-out") */
|
|
874
|
+
easing?: string | number[];
|
|
875
|
+
}
|
|
876
|
+
/** Return value of the useShapeMorph hook. */
|
|
877
|
+
interface UseShapeMorphResult {
|
|
878
|
+
/**
|
|
879
|
+
* CSS clip-path value for the current morphed shape.
|
|
880
|
+
* Apply to an element's style.clipPath.
|
|
881
|
+
*/
|
|
882
|
+
clipPath: string;
|
|
883
|
+
/** Whether the morph is currently at the end shape (progress=1). */
|
|
884
|
+
isActive: boolean;
|
|
885
|
+
/** Programmatically trigger morph to end shape. */
|
|
886
|
+
activate: () => void;
|
|
887
|
+
/** Programmatically reverse morph to start shape. */
|
|
888
|
+
deactivate: () => void;
|
|
889
|
+
/** Set an exact progress value (0=start, 1=end). */
|
|
890
|
+
setProgress: (progress: number) => void;
|
|
891
|
+
/** Event handlers for auto-wiring to DOM elements. */
|
|
892
|
+
handlers: {
|
|
893
|
+
onMouseEnter?: () => void;
|
|
894
|
+
onMouseLeave?: () => void;
|
|
895
|
+
onClick?: () => void;
|
|
896
|
+
onFocus?: () => void;
|
|
897
|
+
onBlur?: () => void;
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
/** Props for the ShapeMedia component. */
|
|
901
|
+
interface ShapeMediaProps {
|
|
902
|
+
/** The base shape (at rest). */
|
|
903
|
+
shape: ShapeRef;
|
|
904
|
+
/**
|
|
905
|
+
* The target shape to morph to (optional).
|
|
906
|
+
* When not provided, no morphing animation occurs.
|
|
907
|
+
*/
|
|
908
|
+
morphTo?: ShapeRef;
|
|
909
|
+
/** Which interaction triggers the morph (default: "hover"). */
|
|
910
|
+
morphOn?: MorphTrigger;
|
|
911
|
+
/** Animation options. */
|
|
912
|
+
morphOptions?: ShapeMorphOptions;
|
|
913
|
+
/**
|
|
914
|
+
* External scroll progress in [0, 1], used when morphOn="scroll".
|
|
915
|
+
* Connect to useScroll / scrollYProgress from Framer Motion.
|
|
916
|
+
*/
|
|
917
|
+
scrollProgress?: number;
|
|
918
|
+
/** Width in pixels. If not provided, uses element's natural width. */
|
|
919
|
+
width?: number;
|
|
920
|
+
/** Height in pixels. If not provided, uses element's natural height. */
|
|
921
|
+
height?: number;
|
|
922
|
+
/** Children to render inside the clipped shape. */
|
|
923
|
+
children?: ReactNode;
|
|
924
|
+
/** Additional CSS class names. */
|
|
925
|
+
className?: string;
|
|
926
|
+
/** Inline styles (merged with shape clip-path). */
|
|
927
|
+
style?: CSSProperties;
|
|
928
|
+
/** ARIA label for accessibility. */
|
|
929
|
+
"aria-label"?: string;
|
|
930
|
+
/** ARIA role (default: "presentation" if no aria-label, else "img"). */
|
|
931
|
+
role?: string;
|
|
932
|
+
/** Whether the component is disabled (disables morphing). */
|
|
933
|
+
disabled?: boolean;
|
|
934
|
+
}
|
|
935
|
+
/** Props for ShapeIcon — simplified fixed-size shape wrapper. */
|
|
936
|
+
interface ShapeIconProps {
|
|
937
|
+
/** The base shape. */
|
|
938
|
+
shape: ShapeRef;
|
|
939
|
+
/** Shape to morph to on hover. */
|
|
940
|
+
morphTo?: ShapeRef;
|
|
941
|
+
/** Size in pixels (width = height). Default: 48. */
|
|
942
|
+
size?: number;
|
|
943
|
+
/** Icon content. */
|
|
944
|
+
children?: ReactNode;
|
|
945
|
+
/** CSS class names. */
|
|
946
|
+
className?: string;
|
|
947
|
+
/** Inline styles. */
|
|
948
|
+
style?: CSSProperties;
|
|
949
|
+
/** Background color. Default: "currentColor". */
|
|
950
|
+
color?: string;
|
|
951
|
+
/** ARIA label. */
|
|
952
|
+
"aria-label"?: string;
|
|
953
|
+
}
|
|
954
|
+
/** Props for ShapeSvg — renders the shape as an SVG path. */
|
|
955
|
+
interface ShapeSvgProps {
|
|
956
|
+
/** The shape to render. */
|
|
957
|
+
shape: ShapeRef;
|
|
958
|
+
/** SVG viewport width (default: 100). */
|
|
959
|
+
width?: number;
|
|
960
|
+
/** SVG viewport height (default: 100). */
|
|
961
|
+
height?: number;
|
|
962
|
+
/** Path fill color (default: "currentColor"). */
|
|
963
|
+
fill?: string;
|
|
964
|
+
/** Path stroke color (default: "none"). */
|
|
965
|
+
stroke?: string;
|
|
966
|
+
/** Path stroke width (default: 0). */
|
|
967
|
+
strokeWidth?: number;
|
|
968
|
+
/** CSS class names. */
|
|
969
|
+
className?: string;
|
|
970
|
+
/** Inline styles. */
|
|
971
|
+
style?: CSSProperties;
|
|
972
|
+
/** ARIA label. */
|
|
973
|
+
"aria-label"?: string;
|
|
974
|
+
/** Morph progress [0, 1] — set to animate between shape and morphTo. */
|
|
975
|
+
progress?: number;
|
|
976
|
+
/** Target shape for morphed SVG rendering. */
|
|
977
|
+
morphTo?: ShapeRef;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* ShapeIcon — simplified fixed-size shape wrapper for icons and small elements.
|
|
982
|
+
* Morphs to a circle on hover by default.
|
|
983
|
+
*
|
|
984
|
+
* @example
|
|
985
|
+
* <ShapeIcon shape="sunny" size={48}>
|
|
986
|
+
* <StarIcon />
|
|
987
|
+
* </ShapeIcon>
|
|
988
|
+
*/
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* ShapeIcon renders a fixed-size shape with icon content inside.
|
|
992
|
+
*/
|
|
993
|
+
declare function ShapeIcon({ shape, morphTo, size, children, className, style, color, "aria-label": ariaLabel, }: ShapeIconProps): React.JSX.Element;
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* ShapeMedia — wraps any UI element (image, video, button, div) with an MD3
|
|
997
|
+
* Expressive shape clip-path, with optional shape morphing animation.
|
|
998
|
+
*
|
|
999
|
+
* @example
|
|
1000
|
+
* // Static shape
|
|
1001
|
+
* <ShapeMedia shape="sunny" width={200} height={200}>
|
|
1002
|
+
* <img src="/photo.jpg" alt="A sunny photo" />
|
|
1003
|
+
* </ShapeMedia>
|
|
1004
|
+
*
|
|
1005
|
+
* @example
|
|
1006
|
+
* // Shape morph on hover
|
|
1007
|
+
* <ShapeMedia shape="circle" morphTo="flower" morphOn="hover" width={200} height={200}>
|
|
1008
|
+
* <img src="/avatar.jpg" alt="Avatar" />
|
|
1009
|
+
* </ShapeMedia>
|
|
1010
|
+
*/
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* ShapeMedia wraps children in a shape clip-path with optional morphing animation.
|
|
1014
|
+
*
|
|
1015
|
+
* @remarks
|
|
1016
|
+
* - Requires "use client" (uses ResizeObserver, animation APIs).
|
|
1017
|
+
* - Use ShapeMediaServer for SSR-only static rendering.
|
|
1018
|
+
* - Automatically handles `prefers-reduced-motion`.
|
|
1019
|
+
*
|
|
1020
|
+
* @param props - {@link ShapeMediaProps}
|
|
1021
|
+
*/
|
|
1022
|
+
declare function ShapeMedia({ shape, morphTo, morphOn, morphOptions, scrollProgress, width: widthProp, height: heightProp, children, className, style, "aria-label": ariaLabel, role, disabled, }: ShapeMediaProps): React.JSX.Element;
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* ShapeMediaServer — SSR-safe static variant of ShapeMedia.
|
|
1026
|
+
*
|
|
1027
|
+
* Renders a static clip-path without any client-side JavaScript or hydration.
|
|
1028
|
+
* Use this in Next.js Server Components or any SSR context where you don't
|
|
1029
|
+
* need morphing animation.
|
|
1030
|
+
*
|
|
1031
|
+
* @example
|
|
1032
|
+
* // In a Next.js Server Component
|
|
1033
|
+
* import { ShapeMediaServer } from "@bug-on/m3-expressive";
|
|
1034
|
+
*
|
|
1035
|
+
* export default function ProfileCard() {
|
|
1036
|
+
* return (
|
|
1037
|
+
* <ShapeMediaServer shape="sunny" width={200} height={200}>
|
|
1038
|
+
* <img src="/avatar.jpg" alt="Profile" />
|
|
1039
|
+
* </ShapeMediaServer>
|
|
1040
|
+
* );
|
|
1041
|
+
* }
|
|
1042
|
+
*/
|
|
1043
|
+
|
|
1044
|
+
interface ShapeMediaServerProps {
|
|
1045
|
+
/** The shape to render. */
|
|
1046
|
+
shape: ShapeRef;
|
|
1047
|
+
/** Width in pixels. */
|
|
1048
|
+
width: number;
|
|
1049
|
+
/** Height in pixels. */
|
|
1050
|
+
height: number;
|
|
1051
|
+
/** Children to render inside the clipped area. */
|
|
1052
|
+
children?: ReactNode;
|
|
1053
|
+
/** Additional CSS class names. */
|
|
1054
|
+
className?: string;
|
|
1055
|
+
/** Inline styles. */
|
|
1056
|
+
style?: CSSProperties;
|
|
1057
|
+
/** ARIA label. */
|
|
1058
|
+
"aria-label"?: string;
|
|
1059
|
+
/** ARIA role. */
|
|
1060
|
+
role?: string;
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* SSR-safe shape clip-path wrapper. No animations, no JS required.
|
|
1064
|
+
*/
|
|
1065
|
+
declare function ShapeMediaServer({ shape, width, height, children, className, style, "aria-label": ariaLabel, role, }: ShapeMediaServerProps): React.JSX.Element;
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* ShapeSvg — renders a shape as an inline SVG path element.
|
|
1069
|
+
* Useful for decorative shapes, loading skeletons, and outlines.
|
|
1070
|
+
* Supports morphed rendering via a `progress` prop.
|
|
1071
|
+
*
|
|
1072
|
+
* @example
|
|
1073
|
+
* // Static shape
|
|
1074
|
+
* <ShapeSvg shape="sunny" width={200} height={200} fill="#6750A4" />
|
|
1075
|
+
*
|
|
1076
|
+
* @example
|
|
1077
|
+
* // Morphed shape (controlled externally)
|
|
1078
|
+
* <ShapeSvg shape="circle" morphTo="flower" progress={0.5} width={200} height={200} />
|
|
1079
|
+
*/
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* ShapeSvg renders a shape or morphed shape as a plain SVG path.
|
|
1083
|
+
*/
|
|
1084
|
+
declare function ShapeSvg({ shape, morphTo, progress, width, height, fill, stroke, strokeWidth, className, style, "aria-label": ariaLabel, }: ShapeSvgProps): React.JSX.Element;
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* useShapeMorph — React hook for shape morphing animations.
|
|
1088
|
+
*
|
|
1089
|
+
* Manages the Morph instance and animated progress value, returning a
|
|
1090
|
+
* CSS clip-path string that updates with every animation frame.
|
|
1091
|
+
*
|
|
1092
|
+
* @example
|
|
1093
|
+
* const { clipPath, handlers } = useShapeMorph({
|
|
1094
|
+
* shape: "circle",
|
|
1095
|
+
* morphTo: "flower",
|
|
1096
|
+
* morphOn: "hover",
|
|
1097
|
+
* width: 200,
|
|
1098
|
+
* height: 200,
|
|
1099
|
+
* });
|
|
1100
|
+
*
|
|
1101
|
+
* return <div style={{ clipPath }} {...handlers}>{children}</div>;
|
|
1102
|
+
*/
|
|
1103
|
+
|
|
1104
|
+
interface UseShapeMorphOptions {
|
|
1105
|
+
shape: ShapeRef;
|
|
1106
|
+
morphTo?: ShapeRef;
|
|
1107
|
+
morphOn?: MorphTrigger;
|
|
1108
|
+
morphOptions?: ShapeMorphOptions;
|
|
1109
|
+
scrollProgress?: number;
|
|
1110
|
+
width: number;
|
|
1111
|
+
height: number;
|
|
1112
|
+
disabled?: boolean;
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Hook for shape morphing with animated clip-path output.
|
|
1116
|
+
*/
|
|
1117
|
+
declare function useShapeMorph({ shape, morphTo, morphOn, morphOptions, scrollProgress, width, height, disabled, }: UseShapeMorphOptions): UseShapeMorphResult;
|
|
1118
|
+
|
|
1119
|
+
export { ANGLE_EPSILON, type CornerFeature, type CornerRounding, Cubic, type CubicPair, DISTANCE_EPSILON, type DoubleMapper, type EdgeFeature, FLOAT_PI, type Feature, MD3CornerRadius, type MD3CornerRadiusToken, type MD3ShapeName, MD3Shapes, type MeasuredCubic, type MeasuredFeature, MeasuredPolygon, Morph, type MorphTrigger, MutableCubic, type Point, type PointTransformer, RoundedPolygon, ShapeIcon, type ShapeIconProps, ShapeMedia, type ShapeMediaProps, ShapeMediaServer, type ShapeMorphOptions, type ShapeRef, ShapeSvg, type ShapeSvgProps, UNROUNDED, type UseShapeMorphResult, addPoints, circle, clockwise, convex, cornerFeature, cornerRounding, createDoubleMapper, directionVector, distance, distanceSquared, dividePoint, dotProduct, edgeFeature, featureMapper, getDirection, getDistance, getDistanceSquared, interpolate, interpolatePath, lerpPoint, pill, pillStar, point, positiveModulo, radialToCartesian, rectangle, rotate90, scalePoint, square, star, subtractPoints, toClipPath, toSvgPath, transformFeature, transformPoint, useShapeMorph };
|