@bug-on/m3-expressive 1.3.4 → 1.3.6

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +31 -7
  3. package/dist/assets/material-symbols-cdn.css +17 -23
  4. package/dist/buttons.js +129 -35
  5. package/dist/buttons.js.map +1 -1
  6. package/dist/buttons.mjs +129 -35
  7. package/dist/buttons.mjs.map +1 -1
  8. package/dist/{core-COvZHQ_k.d.ts → core-Cckt8qEm.d.ts} +10 -4
  9. package/dist/{core-CRkixy1y.d.mts → core-DDfG4pym.d.mts} +10 -4
  10. package/dist/core.d.mts +2 -2
  11. package/dist/core.d.ts +2 -2
  12. package/dist/core.js +6 -5
  13. package/dist/core.js.map +1 -1
  14. package/dist/core.mjs +6 -5
  15. package/dist/core.mjs.map +1 -1
  16. package/dist/fading-blur-mask--uZbBKLj.d.mts +77 -0
  17. package/dist/fading-blur-mask--uZbBKLj.d.ts +77 -0
  18. package/dist/feedback.js +1 -1
  19. package/dist/feedback.js.map +1 -1
  20. package/dist/feedback.mjs +1 -1
  21. package/dist/feedback.mjs.map +1 -1
  22. package/dist/forms.d.mts +2 -2
  23. package/dist/forms.d.ts +2 -2
  24. package/dist/forms.js +17 -7
  25. package/dist/forms.js.map +1 -1
  26. package/dist/forms.mjs +17 -7
  27. package/dist/forms.mjs.map +1 -1
  28. package/dist/index.d.mts +9 -8
  29. package/dist/index.d.ts +9 -8
  30. package/dist/index.js +988 -309
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +984 -310
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/layout.d.mts +5 -3
  35. package/dist/layout.d.ts +5 -3
  36. package/dist/layout.js +61 -6
  37. package/dist/layout.js.map +1 -1
  38. package/dist/layout.mjs +61 -7
  39. package/dist/layout.mjs.map +1 -1
  40. package/dist/material-symbols-cdn.css +17 -23
  41. package/dist/{md3-expressive-shapes-CPcfl_Hf.d.mts → md3-expressive-shapes-wk_98LJh.d.mts} +20 -1
  42. package/dist/{md3-expressive-shapes-CPcfl_Hf.d.ts → md3-expressive-shapes-wk_98LJh.d.ts} +20 -1
  43. package/dist/navigation.d.mts +26 -84
  44. package/dist/navigation.d.ts +26 -84
  45. package/dist/navigation.js +95 -29
  46. package/dist/navigation.js.map +1 -1
  47. package/dist/navigation.mjs +95 -29
  48. package/dist/navigation.mjs.map +1 -1
  49. package/dist/overlays.d.mts +4 -2
  50. package/dist/overlays.d.ts +4 -2
  51. package/dist/overlays.js +85 -44
  52. package/dist/overlays.js.map +1 -1
  53. package/dist/overlays.mjs +85 -44
  54. package/dist/overlays.mjs.map +1 -1
  55. package/dist/pickers.d.mts +12 -0
  56. package/dist/pickers.d.ts +12 -0
  57. package/dist/pickers.js +186 -120
  58. package/dist/pickers.js.map +1 -1
  59. package/dist/pickers.mjs +186 -120
  60. package/dist/pickers.mjs.map +1 -1
  61. package/dist/shapes.d.mts +141 -15
  62. package/dist/shapes.d.ts +141 -15
  63. package/dist/shapes.js +618 -126
  64. package/dist/shapes.js.map +1 -1
  65. package/dist/shapes.mjs +614 -127
  66. package/dist/shapes.mjs.map +1 -1
  67. package/dist/{side-sheet-modal-64FGhDxL.d.mts → side-sheet-modal-BycxrabB.d.mts} +70 -0
  68. package/dist/{side-sheet-modal-Bd5Qqvp9.d.ts → side-sheet-modal-Cw4vemKx.d.ts} +70 -0
  69. package/dist/{text-field-4OlT9o8s.d.mts → text-field-B1fLh5Sh.d.mts} +22 -3
  70. package/dist/{text-field-DARNdj14.d.ts → text-field-C0VQLp8Y.d.ts} +22 -3
  71. package/dist/{typography-339RV6v7.d.mts → typography-CKTjvlZ4.d.mts} +25 -0
  72. package/dist/{typography-339RV6v7.d.ts → typography-CKTjvlZ4.d.ts} +25 -0
  73. package/dist/typography.css +1 -1
  74. package/llms-full.txt +24 -13
  75. package/llms.txt +11 -6
  76. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -256,7 +256,8 @@ function schemeToCssVariables(scheme) {
256
256
  return result;
257
257
  }
258
258
  function MaterialSymbolsPreconnect({
259
- variants = ["outlined"]
259
+ variants = ["rounded"],
260
+ display = "block"
260
261
  }) {
261
262
  return /* @__PURE__ */ jsxs(Fragment, { children: [
262
263
  /* @__PURE__ */ jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }),
@@ -271,7 +272,7 @@ function MaterialSymbolsPreconnect({
271
272
  variants.includes("outlined") && /* @__PURE__ */ jsx(
272
273
  "link",
273
274
  {
274
- href: "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap",
275
+ href: `https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=${display}`,
275
276
  rel: "stylesheet",
276
277
  precedence: "default"
277
278
  }
@@ -279,7 +280,7 @@ function MaterialSymbolsPreconnect({
279
280
  variants.includes("rounded") && /* @__PURE__ */ jsx(
280
281
  "link",
281
282
  {
282
- href: "https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap",
283
+ href: `https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=${display}`,
283
284
  rel: "stylesheet",
284
285
  precedence: "default"
285
286
  }
@@ -287,7 +288,7 @@ function MaterialSymbolsPreconnect({
287
288
  variants.includes("sharp") && /* @__PURE__ */ jsx(
288
289
  "link",
289
290
  {
290
- href: "https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap",
291
+ href: `https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=${display}`,
291
292
  rel: "stylesheet",
292
293
  precedence: "default"
293
294
  }
@@ -309,6 +310,13 @@ function transformFeature(feature, fn) {
309
310
  }
310
311
  return edgeFeature(cubics);
311
312
  }
313
+ function reverseFeature(feature) {
314
+ const cubics = feature.cubics.slice().reverse().map((c) => c.reverse());
315
+ if (feature.type === "corner") {
316
+ return cornerFeature(cubics, feature.convex);
317
+ }
318
+ return edgeFeature(cubics);
319
+ }
312
320
 
313
321
  // src/shapes/math/corner-rounding.ts
314
322
  function cornerRounding(radius = 0, smoothing = 0) {
@@ -353,6 +361,10 @@ function convex(prevX, prevY, currX, currY, nextX, nextY) {
353
361
  const v2y = nextY - currY;
354
362
  return v1x * v2y - v1y * v2x > 0;
355
363
  }
364
+ function formatCoordinate(v) {
365
+ const rounded = Math.round(v * 1e4) / 1e4;
366
+ return (rounded === 0 ? 0 : rounded).toString();
367
+ }
356
368
 
357
369
  // src/shapes/math/point.ts
358
370
  function point(x, y) {
@@ -452,9 +464,16 @@ var Cubic = class _Cubic {
452
464
  */
453
465
  pointOnCurve(t) {
454
466
  const u = 1 - t;
467
+ const uu = u * u;
468
+ const tt = t * t;
469
+ const uuu = uu * u;
470
+ const ttt = tt * t;
471
+ const c0 = 3 * t * uu;
472
+ const c1 = 3 * tt * u;
473
+ const p = this.points;
455
474
  return point(
456
- this.anchor0X * (u * u * u) + this.control0X * (3 * t * u * u) + this.control1X * (3 * t * t * u) + this.anchor1X * (t * t * t),
457
- this.anchor0Y * (u * u * u) + this.control0Y * (3 * t * u * u) + this.control1Y * (3 * t * t * u) + this.anchor1Y * (t * t * t)
475
+ p[0] * uuu + p[2] * c0 + p[4] * c1 + p[6] * ttt,
476
+ p[1] * uuu + p[3] * c0 + p[5] * c1 + p[7] * ttt
458
477
  );
459
478
  }
460
479
  /**
@@ -677,13 +696,17 @@ var MutableCubic = class extends Cubic {
677
696
  * @param progress - Interpolation factor [0, 1]
678
697
  */
679
698
  interpolate(c1, c2, progress) {
680
- for (let i = 0; i < 8; i++) {
681
- this.points[i] = interpolate(
682
- c1.points[i],
683
- c2.points[i],
684
- progress
685
- );
686
- }
699
+ const p1 = c1.points;
700
+ const p2 = c2.points;
701
+ const p = this.points;
702
+ p[0] = p1[0] + (p2[0] - p1[0]) * progress;
703
+ p[1] = p1[1] + (p2[1] - p1[1]) * progress;
704
+ p[2] = p1[2] + (p2[2] - p1[2]) * progress;
705
+ p[3] = p1[3] + (p2[3] - p1[3]) * progress;
706
+ p[4] = p1[4] + (p2[4] - p1[4]) * progress;
707
+ p[5] = p1[5] + (p2[5] - p1[5]) * progress;
708
+ p[6] = p1[6] + (p2[6] - p1[6]) * progress;
709
+ p[7] = p1[7] + (p2[7] - p1[7]) * progress;
687
710
  }
688
711
  /**
689
712
  * Mutably applies a PointTransformer to all points.
@@ -1095,6 +1118,36 @@ var RoundedPolygon = class _RoundedPolygon {
1095
1118
  this.centerY + d
1096
1119
  ];
1097
1120
  }
1121
+ /**
1122
+ * Calculates the approximate signed area of the polygon using anchor points.
1123
+ * Returns > 0 for Clockwise (in screen coords, y down), < 0 for Counter-Clockwise.
1124
+ */
1125
+ calculateSignedArea() {
1126
+ let area = 0;
1127
+ const n = this.cubics.length;
1128
+ for (let i = 0; i < n; i++) {
1129
+ const c = this.cubics[i];
1130
+ area += c.anchor0X * c.anchor1Y - c.anchor1X * c.anchor0Y;
1131
+ }
1132
+ return area / 2;
1133
+ }
1134
+ /**
1135
+ * Returns true if the polygon outline runs in Clockwise order (screen coords).
1136
+ */
1137
+ isClockwise() {
1138
+ return this.calculateSignedArea() > 0;
1139
+ }
1140
+ /**
1141
+ * Returns a reversed copy of the polygon with reversed traversal order.
1142
+ * Flips the winding direction (CW ↔ CCW).
1143
+ */
1144
+ reversed() {
1145
+ const reversedFeatures = this.features.slice().reverse().map((f) => reverseFeature(f));
1146
+ return new _RoundedPolygon(
1147
+ reversedFeatures,
1148
+ point(this.centerX, this.centerY)
1149
+ );
1150
+ }
1098
1151
  };
1099
1152
  function buildCubicsList(features) {
1100
1153
  const result = [];
@@ -1163,10 +1216,21 @@ function validateContiguity(cubics) {
1163
1216
 
1164
1217
  // src/shapes/catalog/md3-expressive-shapes.ts
1165
1218
  function createShape(pts) {
1166
- const cubics = pts.map((p) => new Cubic(p));
1167
- return RoundedPolygon.fromFeatures(
1168
- cubics.map((c) => cornerFeature([c], false))
1169
- );
1219
+ let rawArea = 0;
1220
+ for (const p of pts) {
1221
+ rawArea += p[0] * p[7] - p[6] * p[1];
1222
+ }
1223
+ const normalizedPts = rawArea < 0 ? pts.slice().reverse().map((p) => [p[6], p[7], p[4], p[5], p[2], p[3], p[0], p[1]]) : pts;
1224
+ const cubics = normalizedPts.map((p) => new Cubic(p));
1225
+ const n = cubics.length;
1226
+ const features = cubics.map((c, i) => {
1227
+ const prev = cubics[(i - 1 + n) % n].pointOnCurve(0.5);
1228
+ const curr = c.pointOnCurve(0.5);
1229
+ const next = cubics[(i + 1) % n].pointOnCurve(0.5);
1230
+ const isConvex = convex(prev.x, prev.y, curr.x, curr.y, next.x, next.y);
1231
+ return cornerFeature([c], isConvex);
1232
+ });
1233
+ return RoundedPolygon.fromFeatures(features);
1170
1234
  }
1171
1235
  var archShape = createShape([
1172
1236
  [1, 0.83461, 1, 0.8547, 1, 0.86477, 0.99898, 0.87322],
@@ -2264,6 +2328,94 @@ function resolveShape(ref) {
2264
2328
  return shape;
2265
2329
  }
2266
2330
 
2331
+ // src/shapes/catalog/shape-pairings.ts
2332
+ var MD3_SHAPE_PAIRINGS = {
2333
+ // ─── Organic & Floral ──────────────────────────────────────────
2334
+ circle: "flower",
2335
+ flower: "sunny",
2336
+ sunny: "verySunny",
2337
+ verySunny: "flower",
2338
+ bun: "clamshell",
2339
+ clamshell: "bun",
2340
+ puffy: "circle",
2341
+ // ─── Starburst & Explosive ─────────────────────────────────────
2342
+ burst: "softBurst",
2343
+ softBurst: "boom",
2344
+ boom: "softBoom",
2345
+ softBoom: "burst",
2346
+ cookie12Sided: "softBurst",
2347
+ // ─── Clover, Gem & Diamond ─────────────────────────────────────
2348
+ diamond: "puffyDiamond",
2349
+ puffyDiamond: "diamond",
2350
+ clover4Leaf: "clover8Leaf",
2351
+ clover8Leaf: "clover4Leaf",
2352
+ gem: "diamond",
2353
+ heart: "clover4Leaf",
2354
+ // ─── Cookies & Geometric Multi-sided ───────────────────────────
2355
+ cookie4Sided: "cookie6Sided",
2356
+ cookie6Sided: "cookie9Sided",
2357
+ cookie7Sided: "cookie12Sided",
2358
+ cookie9Sided: "cookie7Sided",
2359
+ square: "cookie4Sided",
2360
+ // ─── Rounded & Architectural ───────────────────────────────────
2361
+ pill: "oval",
2362
+ oval: "arch",
2363
+ arch: "semiCircle",
2364
+ semiCircle: "pill",
2365
+ slanted: "arch",
2366
+ // ─── Polygonal, Directional & Pixel ────────────────────────────
2367
+ triangle: "arrow",
2368
+ arrow: "pentagon",
2369
+ pentagon: "triangle",
2370
+ fan: "ghostish",
2371
+ ghostish: "fan",
2372
+ pixelTriangle: "pixelCircle",
2373
+ pixelCircle: "circle"
2374
+ };
2375
+ var MD3_SHAPE_FAMILIES = {
2376
+ organic: [
2377
+ "circle",
2378
+ "flower",
2379
+ "sunny",
2380
+ "verySunny",
2381
+ "bun",
2382
+ "clamshell",
2383
+ "puffy"
2384
+ ],
2385
+ starburst: ["burst", "softBurst", "boom", "softBoom", "cookie12Sided"],
2386
+ cloverAndGems: [
2387
+ "diamond",
2388
+ "puffyDiamond",
2389
+ "clover4Leaf",
2390
+ "clover8Leaf",
2391
+ "gem",
2392
+ "heart"
2393
+ ],
2394
+ cookiesAndPolygons: [
2395
+ "cookie4Sided",
2396
+ "cookie6Sided",
2397
+ "cookie7Sided",
2398
+ "cookie9Sided",
2399
+ "square"
2400
+ ],
2401
+ roundedContainers: ["pill", "oval", "arch", "semiCircle", "slanted"],
2402
+ directionalAndPixel: [
2403
+ "triangle",
2404
+ "arrow",
2405
+ "pentagon",
2406
+ "fan",
2407
+ "ghostish",
2408
+ "pixelTriangle",
2409
+ "pixelCircle"
2410
+ ]
2411
+ };
2412
+ function getRecommendedMorphShape(shape) {
2413
+ if (typeof shape === "string" && shape in MD3_SHAPE_PAIRINGS) {
2414
+ return MD3_SHAPE_PAIRINGS[shape];
2415
+ }
2416
+ return "circle";
2417
+ }
2418
+
2267
2419
  // src/shapes/catalog/shape-tokens.ts
2268
2420
  var MD3CornerRadius = {
2269
2421
  /** 0dp — Sharp corners */
@@ -2429,6 +2581,56 @@ function pillStarVertices(width, height, numVerticesPerRadius, innerRadiusRatio,
2429
2581
  return result;
2430
2582
  }
2431
2583
 
2584
+ // src/shapes/morph/feature-mapping.ts
2585
+ function angleDiff(a1, a2) {
2586
+ let diff = Math.abs(a1 - a2);
2587
+ if (diff > Math.PI) diff = 2 * Math.PI - diff;
2588
+ return diff;
2589
+ }
2590
+ var TWO_PI_SQ = 4 * Math.PI * Math.PI;
2591
+ function featureMapper(features1, features2) {
2592
+ const convex1 = features1.filter((f) => f.convex);
2593
+ const convex2 = features2.filter((f) => f.convex);
2594
+ const set1 = convex1.length > 0 ? convex1 : features1;
2595
+ const set2 = convex2.length > 0 ? convex2 : features2;
2596
+ if (set1.length === 0 || set2.length === 0) {
2597
+ return { map: (v) => v, mapBack: (v) => v };
2598
+ }
2599
+ let bestShift = 0;
2600
+ let minCost = Number.MAX_VALUE;
2601
+ for (const f1 of set1) {
2602
+ for (const f2 of set2) {
2603
+ const shift = positiveModulo(f2.progress - f1.progress, 1);
2604
+ let cost = 0;
2605
+ for (const c1 of set1) {
2606
+ const expected = positiveModulo(c1.progress + shift, 1);
2607
+ let dMin = Number.MAX_VALUE;
2608
+ let matchedC2 = set2[0];
2609
+ for (const c2 of set2) {
2610
+ const diff = Math.abs(expected - c2.progress);
2611
+ const d = diff > 0.5 ? 1 - diff : diff;
2612
+ if (d < dMin) {
2613
+ dMin = d;
2614
+ matchedC2 = c2;
2615
+ }
2616
+ }
2617
+ const progErrorSq = dMin * dMin * TWO_PI_SQ;
2618
+ const angDiff = c1.angle !== void 0 && matchedC2.angle !== void 0 ? angleDiff(c1.angle, matchedC2.angle) : 0;
2619
+ cost += progErrorSq + angDiff * angDiff;
2620
+ if (cost >= minCost) break;
2621
+ }
2622
+ if (cost < minCost) {
2623
+ minCost = cost;
2624
+ bestShift = shift;
2625
+ }
2626
+ }
2627
+ }
2628
+ return {
2629
+ map: (v) => positiveModulo(v + bestShift, 1),
2630
+ mapBack: (v) => positiveModulo(v - bestShift, 1)
2631
+ };
2632
+ }
2633
+
2432
2634
  // src/shapes/morph/float-mapping.ts
2433
2635
  function mapSegments(value, segments) {
2434
2636
  for (const seg of segments) {
@@ -2473,32 +2675,6 @@ function createDoubleMapper(fromValues, toValues) {
2473
2675
  };
2474
2676
  }
2475
2677
 
2476
- // src/shapes/morph/feature-mapping.ts
2477
- function featureMapper(features1, features2) {
2478
- const convex1 = features1.filter((f) => f.convex);
2479
- const convex2 = features2.filter((f) => f.convex);
2480
- if (convex1.length === 0 || convex2.length === 0) {
2481
- return createDoubleMapper([], []);
2482
- }
2483
- const fromValues = [];
2484
- const toValues = [];
2485
- for (const f1 of convex1) {
2486
- let bestDist = Number.MAX_VALUE;
2487
- let bestProgress = 0;
2488
- for (const f2 of convex2) {
2489
- const diff = Math.abs(f1.progress - f2.progress);
2490
- const dist = Math.min(diff, 1 - diff);
2491
- if (dist < bestDist) {
2492
- bestDist = dist;
2493
- bestProgress = f2.progress;
2494
- }
2495
- }
2496
- fromValues.push(f1.progress);
2497
- toValues.push(bestProgress);
2498
- }
2499
- return createDoubleMapper(fromValues, toValues);
2500
- }
2501
-
2502
2678
  // src/shapes/morph/polygon-measure.ts
2503
2679
  var MeasuredPolygon = class _MeasuredPolygon {
2504
2680
  constructor(measuredCubics, features) {
@@ -2532,9 +2708,8 @@ var MeasuredPolygon = class _MeasuredPolygon {
2532
2708
  const t = segLen > 0 ? (cutPoint - cutCubic.startOutlineProgress) / segLen : 0;
2533
2709
  const [left, right] = cutCubic.cubic.split(t);
2534
2710
  const shift = (p) => {
2535
- let s = p - cutPoint;
2536
- if (s < 0) s += 1;
2537
- return s;
2711
+ const s = p - cutPoint;
2712
+ return s < 0 ? s + 1 : s;
2538
2713
  };
2539
2714
  if (!right.zeroLength()) {
2540
2715
  result.push({
@@ -2543,9 +2718,19 @@ var MeasuredPolygon = class _MeasuredPolygon {
2543
2718
  endOutlineProgress: shift(cutCubic.endOutlineProgress)
2544
2719
  });
2545
2720
  }
2546
- for (let i = 1; i < this.measuredCubics.length; i++) {
2547
- const idx = (cutCubicIdx + i) % this.measuredCubics.length;
2548
- const mc = this.measuredCubics[idx];
2721
+ const totalCubics = this.measuredCubics.length;
2722
+ for (let i = cutCubicIdx + 1; i < totalCubics; i++) {
2723
+ const mc = this.measuredCubics[i];
2724
+ if (!mc.cubic.zeroLength()) {
2725
+ result.push({
2726
+ cubic: mc.cubic,
2727
+ startOutlineProgress: shift(mc.startOutlineProgress),
2728
+ endOutlineProgress: shift(mc.endOutlineProgress)
2729
+ });
2730
+ }
2731
+ }
2732
+ for (let i = 0; i < cutCubicIdx; i++) {
2733
+ const mc = this.measuredCubics[i];
2549
2734
  if (!mc.cubic.zeroLength()) {
2550
2735
  result.push({
2551
2736
  cubic: mc.cubic,
@@ -2627,7 +2812,16 @@ var MeasuredPolygon = class _MeasuredPolygon {
2627
2812
  const mc = measured[Math.min(cubicIdx + middleCubicIdx, measured.length - 1)];
2628
2813
  if (mc) {
2629
2814
  const midProgress = (mc.startOutlineProgress + mc.endOutlineProgress) / 2;
2630
- featureList.push({ progress: midProgress, convex: feature.convex });
2815
+ const pt = mc.cubic.pointOnCurve(0.5);
2816
+ const angle = Math.atan2(
2817
+ pt.y - polygon.centerY,
2818
+ pt.x - polygon.centerX
2819
+ );
2820
+ featureList.push({
2821
+ progress: midProgress,
2822
+ convex: feature.convex,
2823
+ angle
2824
+ });
2631
2825
  }
2632
2826
  }
2633
2827
  cubicIdx += feature.cubics.length;
@@ -2637,18 +2831,30 @@ var MeasuredPolygon = class _MeasuredPolygon {
2637
2831
  };
2638
2832
  function approximateLength(cubic) {
2639
2833
  let len = 0;
2640
- let prevX = cubic.anchor0X, prevY = cubic.anchor0Y;
2834
+ const p = cubic.points;
2835
+ let prevX = p[0];
2836
+ let prevY = p[1];
2641
2837
  const steps = 4;
2642
2838
  for (let i = 1; i <= steps; i++) {
2643
- const p = cubic.pointOnCurve(i / steps);
2644
- len += distance(p.x - prevX, p.y - prevY);
2645
- prevX = p.x;
2646
- prevY = p.y;
2839
+ const t = i / steps;
2840
+ const u = 1 - t;
2841
+ const uu = u * u;
2842
+ const tt = t * t;
2843
+ const uuu = uu * u;
2844
+ const ttt = tt * t;
2845
+ const c0 = 3 * t * uu;
2846
+ const c1 = 3 * tt * u;
2847
+ const px = p[0] * uuu + p[2] * c0 + p[4] * c1 + p[6] * ttt;
2848
+ const py = p[1] * uuu + p[3] * c0 + p[5] * c1 + p[7] * ttt;
2849
+ len += distance(px - prevX, py - prevY);
2850
+ prevX = px;
2851
+ prevY = py;
2647
2852
  }
2648
2853
  return len;
2649
2854
  }
2650
2855
 
2651
2856
  // src/shapes/morph/morph.ts
2857
+ var morphMatchCache = /* @__PURE__ */ new WeakMap();
2652
2858
  var Morph = class _Morph {
2653
2859
  /**
2654
2860
  * Creates a Morph between two shapes.
@@ -2664,23 +2870,79 @@ var Morph = class _Morph {
2664
2870
  * Returns the interpolated shape at the given progress as a list of Cubics.
2665
2871
  *
2666
2872
  * Note: This allocates a new list. For performance-critical animation loops,
2667
- * use {@link forEachCubic} instead.
2873
+ * use {@link toSvgPath} or {@link forEachCubic} instead.
2668
2874
  *
2669
2875
  * @param progress - Value in [0, 1]. 0 = start shape, 1 = end shape.
2670
2876
  * Values outside [0, 1] produce exaggerated shapes (useful for bounce/overshoot).
2671
2877
  * @returns List of interpolated Cubic curves forming the morphed shape
2672
2878
  */
2673
2879
  asCubics(progress) {
2674
- const result = [];
2675
- for (const [c1, c2] of this.morphMatch) {
2676
- result.push(
2677
- new Cubic(
2678
- c1.points.map((v, i) => interpolate(v, c2.points[i], progress))
2679
- )
2680
- );
2880
+ const match = this.morphMatch;
2881
+ const len = match.length;
2882
+ const result = new Array(len);
2883
+ for (let i = 0; i < len; i++) {
2884
+ const [c1, c2] = match[i];
2885
+ const p1 = c1.points;
2886
+ const p2 = c2.points;
2887
+ result[i] = new Cubic([
2888
+ p1[0] + (p2[0] - p1[0]) * progress,
2889
+ p1[1] + (p2[1] - p1[1]) * progress,
2890
+ p1[2] + (p2[2] - p1[2]) * progress,
2891
+ p1[3] + (p2[3] - p1[3]) * progress,
2892
+ p1[4] + (p2[4] - p1[4]) * progress,
2893
+ p1[5] + (p2[5] - p1[5]) * progress,
2894
+ p1[6] + (p2[6] - p1[6]) * progress,
2895
+ p1[7] + (p2[7] - p1[7]) * progress
2896
+ ]);
2681
2897
  }
2682
2898
  return result;
2683
2899
  }
2900
+ /**
2901
+ * Returns an SVG path data string for the morphed shape at the given progress.
2902
+ * Directly evaluates coordinates without allocating intermediate Cubic objects.
2903
+ *
2904
+ * @param progress - Value in [0, 1]
2905
+ * @param width - Target pixel width (default: 1)
2906
+ * @param height - Target pixel height (default: 1)
2907
+ */
2908
+ toSvgPath(progress, width = 1, height = 1) {
2909
+ const match = this.morphMatch;
2910
+ const len = match.length;
2911
+ if (len === 0) return "";
2912
+ const paddingX = width * 0.015;
2913
+ const paddingY = height * 0.015;
2914
+ const sx = width - 2 * paddingX;
2915
+ const sy = height - 2 * paddingY;
2916
+ const [firstC1, firstC2] = match[0];
2917
+ const f1 = firstC1.points;
2918
+ const f2 = firstC2.points;
2919
+ const a0x = f1[0] + (f2[0] - f1[0]) * progress;
2920
+ const a0y = f1[1] + (f2[1] - f1[1]) * progress;
2921
+ let d = `M ${formatCoordinate(paddingX + a0x * sx)} ${formatCoordinate(paddingY + sy * (1 - a0y))}`;
2922
+ for (let i = 0; i < len; i++) {
2923
+ const [c1, c2] = match[i];
2924
+ const p1 = c1.points;
2925
+ const p2 = c2.points;
2926
+ const c0x = p1[2] + (p2[2] - p1[2]) * progress;
2927
+ const c0y = p1[3] + (p2[3] - p1[3]) * progress;
2928
+ const c1x = p1[4] + (p2[4] - p1[4]) * progress;
2929
+ const c1y = p1[5] + (p2[5] - p1[5]) * progress;
2930
+ const a1x = p1[6] + (p2[6] - p1[6]) * progress;
2931
+ const a1y = p1[7] + (p2[7] - p1[7]) * progress;
2932
+ d += ` C ${formatCoordinate(paddingX + c0x * sx)} ${formatCoordinate(paddingY + sy * (1 - c0y))},${formatCoordinate(paddingX + c1x * sx)} ${formatCoordinate(paddingY + sy * (1 - c1y))},${formatCoordinate(paddingX + a1x * sx)} ${formatCoordinate(paddingY + sy * (1 - a1y))}`;
2933
+ }
2934
+ return `${d} Z`;
2935
+ }
2936
+ /**
2937
+ * Returns a CSS clip-path value for the morphed shape at the given progress.
2938
+ *
2939
+ * @param progress - Value in [0, 1]
2940
+ * @param width - Element width in pixels
2941
+ * @param height - Element height in pixels
2942
+ */
2943
+ toClipPath(progress, width, height) {
2944
+ return `path('${this.toSvgPath(progress, width, height)}')`;
2945
+ }
2684
2946
  /**
2685
2947
  * Iterates over the morphed cubics without allocating new Cubic instances.
2686
2948
  * Reuses a single MutableCubic for each callback invocation.
@@ -2754,8 +3016,15 @@ var Morph = class _Morph {
2754
3016
  * @internal
2755
3017
  */
2756
3018
  static match(p1, p2) {
2757
- const measured1 = MeasuredPolygon.measurePolygon(p1);
2758
- const measured2 = MeasuredPolygon.measurePolygon(p2);
3019
+ let cachedMap = morphMatchCache.get(p1);
3020
+ if (cachedMap) {
3021
+ const cached = cachedMap.get(p2);
3022
+ if (cached) return cached;
3023
+ }
3024
+ const poly1 = p1.isClockwise() ? p1 : p1.reversed();
3025
+ const poly2 = p2.isClockwise() ? p2 : p2.reversed();
3026
+ const measured1 = MeasuredPolygon.measurePolygon(poly1);
3027
+ const measured2 = MeasuredPolygon.measurePolygon(poly2);
2759
3028
  const doubleMapper = featureMapper(measured1.features, measured2.features);
2760
3029
  const polygon2CutPoint = doubleMapper.map(0);
2761
3030
  const bs1 = measured1;
@@ -2766,11 +3035,12 @@ var Morph = class _Morph {
2766
3035
  let b2 = bs2.getOrNull(i2++);
2767
3036
  while (b1 !== null && b2 !== null) {
2768
3037
  const b1a = i1 >= bs1.size ? 1 : b1.endOutlineProgress;
2769
- const b2aRaw = i2 >= bs2.size ? 1 : positiveModulo(b2.endOutlineProgress + polygon2CutPoint, 1);
2770
- const b2a = doubleMapper.mapBack(b2aRaw);
3038
+ const b2a = i2 >= bs2.size ? 1 : b2.endOutlineProgress;
2771
3039
  const minb = Math.min(b1a, b2a);
2772
- let seg1 = b1, newb1 = bs1.getOrNull(i1);
2773
- let seg2 = b2, newb2 = bs2.getOrNull(i2);
3040
+ let seg1 = b1;
3041
+ let newb1 = bs1.getOrNull(i1);
3042
+ let seg2 = b2;
3043
+ let newb2 = bs2.getOrNull(i2);
2774
3044
  if (b1a > minb + ANGLE_EPSILON) {
2775
3045
  const [cut, rest] = bs1.cutAtProgress(b1, minb);
2776
3046
  seg1 = cut;
@@ -2779,11 +3049,7 @@ var Morph = class _Morph {
2779
3049
  i1++;
2780
3050
  }
2781
3051
  if (b2a > minb + ANGLE_EPSILON) {
2782
- const targetProgress = positiveModulo(
2783
- doubleMapper.map(minb) - polygon2CutPoint,
2784
- 1
2785
- );
2786
- const [cut, rest] = bs2.cutAtProgress(b2, targetProgress);
3052
+ const [cut, rest] = bs2.cutAtProgress(b2, minb);
2787
3053
  seg2 = cut;
2788
3054
  newb2 = rest;
2789
3055
  } else {
@@ -2793,39 +3059,37 @@ var Morph = class _Morph {
2793
3059
  b1 = newb1;
2794
3060
  b2 = newb2;
2795
3061
  }
3062
+ if (!cachedMap) {
3063
+ cachedMap = /* @__PURE__ */ new WeakMap();
3064
+ morphMatchCache.set(p1, cachedMap);
3065
+ }
3066
+ cachedMap.set(p2, result);
2796
3067
  return result;
2797
3068
  }
2798
3069
  };
2799
3070
 
2800
3071
  // src/shapes/render/shape-rendering.ts
2801
3072
  function toSvgPath(cubics, width = 1, height = 1) {
2802
- if (cubics.length === 0) return "";
3073
+ const len = cubics.length;
3074
+ if (len === 0) return "";
2803
3075
  const paddingX = width * 0.015;
2804
3076
  const paddingY = height * 0.015;
2805
3077
  const sx = width - 2 * paddingX;
2806
3078
  const sy = height - 2 * paddingY;
2807
- const flipY = (y) => paddingY + sy * (1 - y);
2808
- const parts = [
2809
- `M ${fmt(paddingX + cubics[0].anchor0X * sx)} ${fmt(flipY(cubics[0].anchor0Y))}`
2810
- ];
2811
- for (const c of cubics) {
2812
- parts.push(
2813
- `C ${fmt(paddingX + c.control0X * sx)} ${fmt(flipY(c.control0Y))},${fmt(paddingX + c.control1X * sx)} ${fmt(flipY(c.control1Y))},${fmt(paddingX + c.anchor1X * sx)} ${fmt(flipY(c.anchor1Y))}`
2814
- );
3079
+ const c0 = cubics[0];
3080
+ let d = `M ${formatCoordinate(paddingX + c0.anchor0X * sx)} ${formatCoordinate(paddingY + sy * (1 - c0.anchor0Y))}`;
3081
+ for (let i = 0; i < len; i++) {
3082
+ const c = cubics[i];
3083
+ d += ` C ${formatCoordinate(paddingX + c.control0X * sx)} ${formatCoordinate(paddingY + sy * (1 - c.control0Y))},${formatCoordinate(paddingX + c.control1X * sx)} ${formatCoordinate(paddingY + sy * (1 - c.control1Y))},${formatCoordinate(paddingX + c.anchor1X * sx)} ${formatCoordinate(paddingY + sy * (1 - c.anchor1Y))}`;
2815
3084
  }
2816
- parts.push("Z");
2817
- return parts.join(" ");
3085
+ return `${d} Z`;
2818
3086
  }
2819
3087
  function toClipPath(polygon, width, height) {
2820
3088
  const pathData = toSvgPath(polygon.cubics, width, height);
2821
3089
  return `path('${pathData}')`;
2822
3090
  }
2823
3091
  function interpolatePath(morph, progress, width, height) {
2824
- const cubics = morph.asCubics(progress);
2825
- return toClipPath({ cubics }, width, height);
2826
- }
2827
- function fmt(v) {
2828
- return Number(v.toFixed(4)).toString();
3092
+ return morph.toClipPath(progress, width, height);
2829
3093
  }
2830
3094
  function cn(...inputs) {
2831
3095
  return twMerge(clsx(inputs));
@@ -2835,7 +3099,7 @@ function getMaskGradient(direction) {
2835
3099
  case "bottom":
2836
3100
  return "linear-gradient(to top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 1) 45%, rgba(0, 0, 0, 0.7) 75%, rgba(0, 0, 0, 0) 100%)";
2837
3101
  case "both":
2838
- return "linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 20%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 1) 60%, rgba(0, 0, 0, 0.7) 80%, rgba(0, 0, 0, 0) 100%)";
3102
+ return "linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.7) 15%, rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 0) 70%, rgba(0, 0, 0, 0.7) 85%, rgba(0, 0, 0, 1) 100%)";
2839
3103
  default:
2840
3104
  return "linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 1) 45%, rgba(0, 0, 0, 0.7) 75%, rgba(0, 0, 0, 0) 100%)";
2841
3105
  }
@@ -2852,11 +3116,16 @@ function FadingBlurMask({
2852
3116
  const shouldReduceMotion = useReducedMotion();
2853
3117
  const activeBlur = shouldReduceMotion ? 0 : blurIntensity;
2854
3118
  const maskGradient = getMaskGradient(direction);
3119
+ const isFullHeight = direction === "both" || blurHeight === "100%";
3120
+ const computedHeight = isFullHeight ? "100%" : typeof blurHeight === "number" ? `${blurHeight}px` : blurHeight;
2855
3121
  const maskStyle = __spreadValues({
2856
3122
  position: "absolute",
2857
- inset: 0,
3123
+ top: direction === "bottom" && !isFullHeight ? "auto" : 0,
3124
+ bottom: direction === "top" && !isFullHeight ? "auto" : 0,
3125
+ left: 0,
3126
+ right: 0,
2858
3127
  pointerEvents: "none",
2859
- height: typeof blurHeight === "number" ? `${blurHeight}px` : blurHeight,
3128
+ height: computedHeight,
2860
3129
  backdropFilter: activeBlur > 0 ? `blur(${activeBlur}px)` : void 0,
2861
3130
  WebkitBackdropFilter: activeBlur > 0 ? `blur(${activeBlur}px)` : void 0,
2862
3131
  maskImage: maskGradient,
@@ -2868,7 +3137,7 @@ function FadingBlurMask({
2868
3137
  {
2869
3138
  "aria-hidden": "true",
2870
3139
  className: cn(
2871
- "absolute inset-0 pointer-events-none z-0 rounded-[inherit]",
3140
+ "absolute pointer-events-none z-10 rounded-[inherit]",
2872
3141
  className
2873
3142
  ),
2874
3143
  style: maskStyle,
@@ -3996,7 +4265,7 @@ var IconComponent = React67.forwardRef(
3996
4265
  (_a, ref) => {
3997
4266
  var _b = _a, {
3998
4267
  name,
3999
- variant = "outlined",
4268
+ variant = "rounded",
4000
4269
  fill = 0,
4001
4270
  weight = 400,
4002
4271
  grade = 0,
@@ -8331,6 +8600,7 @@ var ExtendedFABComponent = React67.forwardRef(
8331
8600
  onClick,
8332
8601
  onKeyDown,
8333
8602
  layoutId,
8603
+ layout,
8334
8604
  "aria-label": ariaLabel
8335
8605
  } = _b, restProps = __objRest(_b, [
8336
8606
  "className",
@@ -8352,6 +8622,7 @@ var ExtendedFABComponent = React67.forwardRef(
8352
8622
  "onClick",
8353
8623
  "onKeyDown",
8354
8624
  "layoutId",
8625
+ "layout",
8355
8626
  "aria-label"
8356
8627
  ]);
8357
8628
  var _a2, _b2, _c, _d;
@@ -8376,6 +8647,13 @@ var ExtendedFABComponent = React67.forwardRef(
8376
8647
  const colors = (_a2 = COLOR_CLASSES[colorStyle]) != null ? _a2 : COLOR_CLASSES.primary;
8377
8648
  const radiusConfig = (_b2 = MORPH_RADIUS[size]) != null ? _b2 : MORPH_RADIUS.sm;
8378
8649
  const sizeIcon = (_c = SIZE_ICON[size]) != null ? _c : SIZE_ICON.sm;
8650
+ const motionRadius = useMotionValue(radiusConfig.default);
8651
+ React67.useEffect(() => {
8652
+ const controls = animate(motionRadius, radiusConfig.default, __spreadProps(__spreadValues({}, SPRING_TRANSITION), {
8653
+ type: "spring"
8654
+ }));
8655
+ return () => controls.stop();
8656
+ }, [radiusConfig.default, motionRadius]);
8379
8657
  const { ripples, onPointerDown, removeRipple } = useRippleState({
8380
8658
  disabled: loading
8381
8659
  });
@@ -8470,13 +8748,25 @@ var ExtendedFABComponent = React67.forwardRef(
8470
8748
  {
8471
8749
  layout: "position",
8472
8750
  initial: { opacity: 0, width: 0 },
8473
- animate: { opacity: 1, width: "auto" },
8474
- exit: { opacity: 0, width: 0 },
8475
- transition: {
8476
- opacity: { duration: 0.15, ease: "linear" },
8477
- width: SPRING_TRANSITION
8751
+ animate: {
8752
+ opacity: 1,
8753
+ width: "auto",
8754
+ transition: {
8755
+ width: SPRING_TRANSITION,
8756
+ opacity: { delay: 0.08, duration: 0.15, ease: "easeIn" },
8757
+ layout: SPRING_TRANSITION
8758
+ }
8759
+ },
8760
+ exit: {
8761
+ opacity: 0,
8762
+ width: 0,
8763
+ transition: {
8764
+ opacity: { duration: 0.1, ease: "linear" },
8765
+ width: __spreadProps(__spreadValues({}, SPRING_TRANSITION), { delay: 0.03 }),
8766
+ layout: SPRING_TRANSITION
8767
+ }
8478
8768
  },
8479
- className: "overflow-hidden whitespace-nowrap",
8769
+ className: "overflow-hidden whitespace-nowrap shrink-0 inline-block",
8480
8770
  children: label
8481
8771
  },
8482
8772
  "label"
@@ -8507,7 +8797,7 @@ var ExtendedFABComponent = React67.forwardRef(
8507
8797
  __spreadProps(__spreadValues({
8508
8798
  ref: localRef,
8509
8799
  type: "button",
8510
- layout: true,
8800
+ layout: layout !== void 0 ? layout : "position",
8511
8801
  layoutId,
8512
8802
  "aria-label": ariaLabel || label,
8513
8803
  "aria-busy": loading || void 0,
@@ -8515,21 +8805,23 @@ var ExtendedFABComponent = React67.forwardRef(
8515
8805
  onClick: handleClick,
8516
8806
  onPointerDown,
8517
8807
  onKeyDown: handleKeyDown,
8518
- style,
8808
+ style: __spreadProps(__spreadValues({}, style), {
8809
+ borderRadius: motionRadius
8810
+ }),
8519
8811
  initial: {
8520
8812
  scale: 0.6,
8521
- opacity: 0,
8522
- borderRadius: radiusConfig.default
8813
+ opacity: 0
8523
8814
  },
8524
8815
  animate: {
8525
8816
  scale: 1,
8526
- opacity: 1,
8527
- borderRadius: radiusConfig.default
8817
+ opacity: 1
8528
8818
  },
8529
8819
  exit: { scale: 0.6, opacity: 0 },
8530
- whileTap: { borderRadius: radiusConfig.pressed },
8820
+ whileTap: {
8821
+ borderRadius: radiusConfig.pressed,
8822
+ transition: { borderRadius: SPRING_TRANSITION_FAST }
8823
+ },
8531
8824
  transition: {
8532
- borderRadius: { type: "spring", stiffness: 500, damping: 30 },
8533
8825
  scale: SPRING_TRANSITION,
8534
8826
  opacity: { duration: 0.2, ease: "linear" },
8535
8827
  layout: SPRING_TRANSITION
@@ -8561,6 +8853,18 @@ var SIZE_TEXT_CLASS = {
8561
8853
  lg: "text-xl font-semibold",
8562
8854
  xl: "text-2xl font-semibold"
8563
8855
  };
8856
+ var SIZE_PADDING_COLLAPSED = {
8857
+ sm: "px-2",
8858
+ md: "px-4",
8859
+ lg: "px-8",
8860
+ xl: "px-12"
8861
+ };
8862
+ var SIZE_PADDING_EXTENDED = {
8863
+ sm: "pl-2 pr-4",
8864
+ md: "pl-4 pr-6",
8865
+ lg: "pl-8 pr-8",
8866
+ xl: "pl-12 pr-10"
8867
+ };
8564
8868
  var MORPH_RADIUS2 = {
8565
8869
  sm: { default: 12, pressed: 8, extended: 12, extended_pressed: 8 },
8566
8870
  md: { default: 16, pressed: 10, extended: 16, extended_pressed: 10 },
@@ -8652,7 +8956,7 @@ var FABComponent = React67.forwardRef(
8652
8956
  "layout",
8653
8957
  "layoutId"
8654
8958
  ]);
8655
- var _a2, _b2, _c, _d;
8959
+ var _a2, _b2, _c, _d, _e, _f;
8656
8960
  const colors = (_a2 = COLOR_CLASSES2[colorStyle]) != null ? _a2 : COLOR_CLASSES2.primary;
8657
8961
  const radiusConfig = (_b2 = MORPH_RADIUS2[size]) != null ? _b2 : MORPH_RADIUS2.md;
8658
8962
  const animateRadius = extended ? radiusConfig.extended : radiusConfig.default;
@@ -8737,22 +9041,37 @@ var FABComponent = React67.forwardRef(
8737
9041
  m.span,
8738
9042
  {
8739
9043
  layout: "position",
8740
- initial: { width: 0, opacity: 0 },
8741
- animate: { width: "auto", opacity: 1 },
8742
- exit: { width: 0, opacity: 0 },
8743
- transition: {
8744
- opacity: { duration: 0.15, ease: "linear" },
8745
- width: SPRING_TRANSITION,
8746
- layout: SPRING_TRANSITION
9044
+ initial: { width: 0, opacity: 0, marginLeft: 0 },
9045
+ animate: {
9046
+ width: "auto",
9047
+ opacity: 1,
9048
+ marginLeft: 12,
9049
+ transition: {
9050
+ width: SPRING_TRANSITION,
9051
+ marginLeft: SPRING_TRANSITION,
9052
+ opacity: { delay: 0.08, duration: 0.15, ease: "easeIn" },
9053
+ layout: SPRING_TRANSITION
9054
+ }
8747
9055
  },
8748
- className: "overflow-hidden whitespace-nowrap ml-3",
9056
+ exit: {
9057
+ width: 0,
9058
+ opacity: 0,
9059
+ marginLeft: 0,
9060
+ transition: {
9061
+ opacity: { duration: 0.1, ease: "linear" },
9062
+ width: __spreadProps(__spreadValues({}, SPRING_TRANSITION), { delay: 0.03 }),
9063
+ marginLeft: __spreadProps(__spreadValues({}, SPRING_TRANSITION), { delay: 0.03 }),
9064
+ layout: SPRING_TRANSITION
9065
+ }
9066
+ },
9067
+ className: "overflow-hidden whitespace-nowrap shrink-0 inline-block",
8749
9068
  children: labelContent
8750
9069
  },
8751
9070
  "label"
8752
9071
  ) })
8753
9072
  ] });
8754
9073
  const containerClassName = cn(
8755
- "relative shrink-0 inline-flex items-center justify-center",
9074
+ "relative shrink-0 inline-flex items-center justify-start",
8756
9075
  "select-none cursor-pointer overflow-hidden",
8757
9076
  "transition-[box-shadow,opacity,filter] duration-200",
8758
9077
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-m3-primary focus-visible:ring-offset-2",
@@ -8761,21 +9080,62 @@ var FABComponent = React67.forwardRef(
8761
9080
  colors.text,
8762
9081
  lowered ? "shadow-sm" : colors.shadow,
8763
9082
  (_d = SIZE_STYLES[size]) != null ? _d : "h-14 w-14",
8764
- extended && "w-auto pl-4 pr-6",
9083
+ extended ? cn("w-auto", (_e = SIZE_PADDING_EXTENDED[size]) != null ? _e : "pl-4 pr-6") : (_f = SIZE_PADDING_COLLAPSED[size]) != null ? _f : "px-4",
8765
9084
  SIZE_TEXT_CLASS[size],
8766
9085
  loading && "pointer-events-none opacity-75 cursor-not-allowed",
8767
9086
  className
8768
9087
  );
9088
+ const motionRadius = useMotionValue(animateRadius);
9089
+ const asChildRef = React67.useRef(null);
9090
+ const mergedRef = React67.useCallback(
9091
+ (node) => {
9092
+ asChildRef.current = node;
9093
+ if (typeof ref === "function") ref(node);
9094
+ else if (ref)
9095
+ ref.current = node;
9096
+ },
9097
+ [ref]
9098
+ );
9099
+ React67.useEffect(() => {
9100
+ if (!asChild) return;
9101
+ return motionRadius.on("change", (v) => {
9102
+ if (asChildRef.current)
9103
+ asChildRef.current.style.borderRadius = `${v}px`;
9104
+ });
9105
+ }, [motionRadius, asChild]);
9106
+ React67.useEffect(() => {
9107
+ const controls = animate(motionRadius, animateRadius, __spreadProps(__spreadValues({}, SPRING_TRANSITION), {
9108
+ type: "spring"
9109
+ }));
9110
+ return () => controls.stop();
9111
+ }, [animateRadius, motionRadius]);
9112
+ const handleAsChildPointerDown = React67.useCallback(
9113
+ (e) => {
9114
+ onPointerDown(e);
9115
+ animate(motionRadius, pressedRadius, __spreadProps(__spreadValues({}, SPRING_TRANSITION_FAST), {
9116
+ type: "spring"
9117
+ }));
9118
+ },
9119
+ [onPointerDown, motionRadius, pressedRadius]
9120
+ );
9121
+ const handleAsChildPointerUp = React67.useCallback(() => {
9122
+ animate(motionRadius, animateRadius, __spreadProps(__spreadValues({}, SPRING_TRANSITION_FAST), {
9123
+ type: "spring"
9124
+ }));
9125
+ }, [motionRadius, animateRadius]);
8769
9126
  const computedAriaLabel = ariaLabel || (typeof children === "string" ? children : void 0);
8770
9127
  return /* @__PURE__ */ jsx(LazyMotion, { features: domMax, strict: true, children: /* @__PURE__ */ jsx(AnimatePresence, { children: visible && (asChild ? /* @__PURE__ */ jsx(
8771
9128
  Slot,
8772
9129
  __spreadProps(__spreadValues({
8773
- ref,
9130
+ ref: mergedRef,
8774
9131
  "aria-label": computedAriaLabel,
8775
9132
  "aria-busy": loading || void 0,
8776
9133
  "aria-disabled": loading || restProps.disabled,
8777
9134
  onClick: handleClick,
8778
- onPointerDown,
9135
+ onPointerDown: handleAsChildPointerDown,
9136
+ onPointerUp: handleAsChildPointerUp,
9137
+ onPointerLeave: handleAsChildPointerUp,
9138
+ onPointerCancel: handleAsChildPointerUp,
8779
9139
  onKeyDown: handleKeyDown,
8780
9140
  style: __spreadProps(__spreadValues({}, style), {
8781
9141
  borderRadius: `${animateRadius}px`
@@ -8792,7 +9152,7 @@ var FABComponent = React67.forwardRef(
8792
9152
  __spreadProps(__spreadValues({
8793
9153
  ref,
8794
9154
  type: "button",
8795
- layout: layout !== void 0 ? layout : true,
9155
+ layout: layout !== void 0 ? layout : "position",
8796
9156
  layoutId,
8797
9157
  "aria-label": computedAriaLabel,
8798
9158
  "aria-busy": loading || void 0,
@@ -8800,17 +9160,20 @@ var FABComponent = React67.forwardRef(
8800
9160
  onClick: handleClick,
8801
9161
  onPointerDown,
8802
9162
  onKeyDown: handleKeyDown,
8803
- style,
9163
+ style: __spreadProps(__spreadValues({}, style), {
9164
+ borderRadius: motionRadius
9165
+ }),
8804
9166
  initial: {
8805
9167
  scale: 0.5,
8806
- opacity: 0,
8807
- borderRadius: animateRadius
9168
+ opacity: 0
8808
9169
  },
8809
- animate: { scale: 1, opacity: 1, borderRadius: animateRadius },
9170
+ animate: { scale: 1, opacity: 1 },
8810
9171
  exit: { scale: 0.5, opacity: 0 },
8811
- whileTap: { borderRadius: pressedRadius },
9172
+ whileTap: {
9173
+ borderRadius: pressedRadius,
9174
+ transition: { borderRadius: SPRING_TRANSITION_FAST }
9175
+ },
8812
9176
  transition: {
8813
- borderRadius: SPRING_TRANSITION_FAST,
8814
9177
  scale: SPRING_TRANSITION,
8815
9178
  opacity: { duration: 0.25, ease: "easeOut" },
8816
9179
  layout: SPRING_TRANSITION
@@ -13287,7 +13650,7 @@ var CalendarGrid = ({
13287
13650
  ] });
13288
13651
  };
13289
13652
  CalendarGrid.displayName = "CalendarGrid";
13290
- var selectorClassName = "flex items-center gap-1 rounded-m3-full px-2 py-1 text-[length:var(--md-typescale-title-small-size,14px)] font-[number:var(--md-typescale-title-small-weight,500)] text-m3-on-surface transition-m3-fast-effects hover:bg-m3-on-surface/8 focus-visible:outline-2 focus-visible:outline-m3-primary";
13653
+ var selectorClassName = "flex items-center gap-1 rounded-m3-full px-2 py-1 text-[length:var(--md-typescale-title-small-size,14px)] font-[number:var(--md-typescale-title-small-weight,500)] text-m3-on-surface transition-m3-fast-effects hover:bg-m3-on-surface/8 focus-visible:outline-2 focus-visible:outline-m3-primary whitespace-nowrap select-none min-w-0";
13291
13654
  var CalendarHeader = ({
13292
13655
  displayedMonthMs,
13293
13656
  activeSelector,
@@ -13313,57 +13676,70 @@ var CalendarHeader = ({
13313
13676
  timeZone: "UTC"
13314
13677
  }).format(date);
13315
13678
  const yearLabel = String(date.getUTCFullYear());
13316
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-6 pb-4 pt-5", children: [
13317
- /* @__PURE__ */ jsx("div", { className: "text-(length:--md-typescale-label-large-size,14px) font-(--md-typescale-label-large-weight,500) text-m3-on-surface-variant", children: title }),
13318
- /* @__PURE__ */ jsx("div", { className: "mb-2 leading-tight text-(length:--md-typescale-headline-large-size,32px) font-(--md-typescale-headline-large-weight,400) text-m3-on-surface-variant", children: headline }),
13319
- displayMode === "picker" && /* @__PURE__ */ jsxs("div", { className: "flex min-h-10 items-center gap-0.5", children: [
13320
- activeSelector === null && /* @__PURE__ */ jsx(
13321
- IconButton,
13322
- {
13323
- onClick: onPrev,
13324
- "aria-label": "Previous month",
13325
- disabled: !canNavigatePrev,
13326
- size: "xs",
13327
- children: /* @__PURE__ */ jsx(Icon, { name: "chevron_left" })
13328
- }
13329
- ),
13330
- /* @__PURE__ */ jsxs(
13331
- "button",
13332
- {
13333
- type: "button",
13334
- onClick: () => onToggleSelector("month"),
13335
- "aria-expanded": activeSelector === "month",
13336
- "aria-controls": "date-picker-selection",
13337
- className: cn(
13338
- selectorClassName,
13339
- activeSelector === "month" && "bg-m3-on-surface/8"
13340
- ),
13341
- children: [
13342
- monthLabel,
13343
- /* @__PURE__ */ jsx(
13344
- Icon,
13345
- {
13346
- name: "arrow_drop_down",
13347
- className: cn(
13348
- "text-[20px] transition-transform duration-200",
13349
- activeSelector === "month" && "rotate-180"
13350
- )
13351
- }
13352
- )
13353
- ]
13354
- }
13355
- ),
13356
- activeSelector === null && /* @__PURE__ */ jsx(
13357
- IconButton,
13358
- {
13359
- onClick: onNext,
13360
- "aria-label": "Next month",
13361
- disabled: !canNavigateNext,
13362
- size: "xs",
13363
- children: /* @__PURE__ */ jsx(Icon, { name: "chevron_right" })
13364
- }
13365
- ),
13366
- /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-0.5", children: [
13679
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-4 sm:px-6 pb-3 pt-5 w-full", children: [
13680
+ /* @__PURE__ */ jsx("div", { className: "text-(length:--md-typescale-label-large-size,14px) font-(--md-typescale-label-large-weight,500) text-m3-on-surface-variant truncate", children: title }),
13681
+ /* @__PURE__ */ jsx(
13682
+ "div",
13683
+ {
13684
+ className: "mb-2 leading-tight text-[26px] sm:text-[32px] font-(--md-typescale-headline-large-weight,400) text-m3-on-surface-variant truncate",
13685
+ title: typeof headline === "string" ? headline : void 0,
13686
+ children: headline
13687
+ }
13688
+ ),
13689
+ displayMode === "picker" && /* @__PURE__ */ jsxs("div", { className: "flex min-h-10 items-center justify-between gap-0.5 w-full overflow-hidden", children: [
13690
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 min-w-0 shrink", children: [
13691
+ activeSelector === null && /* @__PURE__ */ jsx(
13692
+ IconButton,
13693
+ {
13694
+ onClick: onPrev,
13695
+ "aria-label": "Previous month",
13696
+ disabled: !canNavigatePrev,
13697
+ size: "xs",
13698
+ className: "shrink-0",
13699
+ children: /* @__PURE__ */ jsx(Icon, { name: "chevron_left" })
13700
+ }
13701
+ ),
13702
+ /* @__PURE__ */ jsxs(
13703
+ "button",
13704
+ {
13705
+ type: "button",
13706
+ onClick: () => onToggleSelector("month"),
13707
+ "aria-expanded": activeSelector === "month",
13708
+ "aria-controls": "date-picker-selection",
13709
+ className: cn(
13710
+ selectorClassName,
13711
+ "min-w-0 max-w-[125px] shrink",
13712
+ activeSelector === "month" && "bg-m3-on-surface/8"
13713
+ ),
13714
+ title: monthLabel,
13715
+ children: [
13716
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: monthLabel }),
13717
+ /* @__PURE__ */ jsx(
13718
+ Icon,
13719
+ {
13720
+ name: "arrow_drop_down",
13721
+ className: cn(
13722
+ "text-[20px] shrink-0 transition-transform duration-200",
13723
+ activeSelector === "month" && "rotate-180"
13724
+ )
13725
+ }
13726
+ )
13727
+ ]
13728
+ }
13729
+ ),
13730
+ activeSelector === null && /* @__PURE__ */ jsx(
13731
+ IconButton,
13732
+ {
13733
+ onClick: onNext,
13734
+ "aria-label": "Next month",
13735
+ disabled: !canNavigateNext,
13736
+ size: "xs",
13737
+ className: "shrink-0",
13738
+ children: /* @__PURE__ */ jsx(Icon, { name: "chevron_right" })
13739
+ }
13740
+ )
13741
+ ] }),
13742
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-0.5 shrink-0", children: [
13367
13743
  activeSelector === null && /* @__PURE__ */ jsx(
13368
13744
  IconButton,
13369
13745
  {
@@ -13371,6 +13747,7 @@ var CalendarHeader = ({
13371
13747
  "aria-label": "Previous year",
13372
13748
  disabled: !canNavigatePreviousYear,
13373
13749
  size: "xs",
13750
+ className: "shrink-0",
13374
13751
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron_left" })
13375
13752
  }
13376
13753
  ),
@@ -13383,16 +13760,18 @@ var CalendarHeader = ({
13383
13760
  "aria-controls": "date-picker-selection",
13384
13761
  className: cn(
13385
13762
  selectorClassName,
13763
+ "shrink-0",
13386
13764
  activeSelector === "year" && "bg-m3-on-surface/8"
13387
13765
  ),
13766
+ title: yearLabel,
13388
13767
  children: [
13389
- yearLabel,
13768
+ /* @__PURE__ */ jsx("span", { children: yearLabel }),
13390
13769
  /* @__PURE__ */ jsx(
13391
13770
  Icon,
13392
13771
  {
13393
13772
  name: "arrow_drop_down",
13394
13773
  className: cn(
13395
- "text-[20px] transition-transform duration-200",
13774
+ "text-[20px] shrink-0 transition-transform duration-200",
13396
13775
  activeSelector === "year" && "rotate-180"
13397
13776
  )
13398
13777
  }
@@ -13407,6 +13786,7 @@ var CalendarHeader = ({
13407
13786
  "aria-label": "Next year",
13408
13787
  disabled: !canNavigateNextYear,
13409
13788
  size: "xs",
13789
+ className: "shrink-0",
13410
13790
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron_right" })
13411
13791
  }
13412
13792
  ),
@@ -13416,6 +13796,7 @@ var CalendarHeader = ({
13416
13796
  onClick: onToggleMode,
13417
13797
  "aria-label": "Switch to text input",
13418
13798
  size: "xs",
13799
+ className: "shrink-0",
13419
13800
  children: /* @__PURE__ */ jsx(Icon, { name: "keyboard" })
13420
13801
  }
13421
13802
  )
@@ -13427,7 +13808,7 @@ var CalendarHeader = ({
13427
13808
  onClick: onToggleMode,
13428
13809
  "aria-label": "Switch to calendar",
13429
13810
  size: "xs",
13430
- className: "self-end",
13811
+ className: "self-end shrink-0",
13431
13812
  children: /* @__PURE__ */ jsx(Icon, { name: "calendar_month" })
13432
13813
  }
13433
13814
  ),
@@ -13474,14 +13855,14 @@ var MonthPickerList = ({
13474
13855
  onClick: () => onMonthSelect(month),
13475
13856
  className: cn(
13476
13857
  "flex min-h-12 w-full items-center gap-4 px-6 text-left",
13477
- "text-[length:var(--md-typescale-body-large-size,16px)]",
13858
+ "text-(length:--md-typescale-body-large-size,16px)",
13478
13859
  "text-m3-on-surface transition-m3-fast-effects",
13479
13860
  "hover:bg-m3-on-surface/8 focus-visible:outline-2 focus-visible:outline-m3-primary",
13480
13861
  isSelected && "bg-m3-secondary-container text-m3-on-secondary-container"
13481
13862
  ),
13482
13863
  children: [
13483
- /* @__PURE__ */ jsx("span", { className: "w-6", "aria-hidden": true, children: isSelected && /* @__PURE__ */ jsx(Icon, { name: "check", className: "text-[20px]" }) }),
13484
- getMonthLabel(month, locale.locale)
13864
+ /* @__PURE__ */ jsx("span", { className: "w-6 shrink-0", "aria-hidden": true, children: isSelected && /* @__PURE__ */ jsx(Icon, { name: "check", className: "text-[20px]" }) }),
13865
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: getMonthLabel(month, locale.locale) })
13485
13866
  ]
13486
13867
  },
13487
13868
  month
@@ -13559,7 +13940,9 @@ var DatePicker = ({
13559
13940
  showModeToggle = true,
13560
13941
  title,
13561
13942
  headline,
13562
- className
13943
+ className,
13944
+ width,
13945
+ maxWidth
13563
13946
  }) => {
13564
13947
  const {
13565
13948
  selectedDateMs,
@@ -13640,7 +14023,10 @@ var DatePicker = ({
13640
14023
  "fieldset",
13641
14024
  {
13642
14025
  className: cn("flex flex-col select-none", className),
13643
- style: { width: "min(100%, 360px)" },
14026
+ style: {
14027
+ width: typeof width === "number" ? `${width}px` : width != null ? width : "min(100%, 360px)",
14028
+ maxWidth: typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth
14029
+ },
13644
14030
  "aria-label": computedAriaLabel,
13645
14031
  children: [
13646
14032
  /* @__PURE__ */ jsx("legend", { className: "sr-only", children: computedAriaLabel }),
@@ -13887,45 +14273,64 @@ var DialogOverlay = React67.forwardRef((_a, ref) => {
13887
14273
  ) }));
13888
14274
  });
13889
14275
  DialogOverlay.displayName = "DialogOverlay";
13890
- var DialogContent = React67.forwardRef((_a, ref) => {
13891
- var _b = _a, { className, children, hideCloseButton = false } = _b, props = __objRest(_b, ["className", "children", "hideCloseButton"]);
13892
- return /* @__PURE__ */ jsx(
13893
- RadixDialog.Content,
13894
- __spreadProps(__spreadValues({
13895
- ref,
13896
- asChild: true,
13897
- "aria-describedby": void 0
13898
- }, props), {
13899
- children: /* @__PURE__ */ jsxs(
13900
- m.div,
13901
- __spreadProps(__spreadValues({
13902
- className: cn(
13903
- "fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2",
13904
- "w-[calc(100%-2rem)] max-w-140",
13905
- "rounded-[28px] bg-m3-surface-container-high p-6",
13906
- "shadow-lg outline-none focus-visible:ring-2 focus-visible:ring-m3-primary",
13907
- className
13908
- ),
13909
- role: "dialog"
13910
- }, MD3_CONTENT_ANIM), {
13911
- children: [
13912
- children,
13913
- !hideCloseButton && /* @__PURE__ */ jsx(RadixDialog.Close, { asChild: true, "aria-label": "Close dialog", children: /* @__PURE__ */ jsx(
13914
- IconButton,
13915
- {
13916
- size: "sm",
13917
- colorStyle: "filled",
13918
- className: "absolute right-4 top-4",
13919
- "aria-label": "Close",
13920
- children: /* @__PURE__ */ jsx(Icon, { name: "close", "aria-hidden": "true" })
13921
- }
13922
- ) })
13923
- ]
13924
- })
13925
- )
13926
- })
13927
- );
13928
- });
14276
+ var DEFAULT_CLOSE_BTN_PROPS = {
14277
+ size: "sm",
14278
+ colorStyle: "standard",
14279
+ className: "absolute right-4 top-4",
14280
+ "aria-label": "Close"
14281
+ };
14282
+ var DialogContent = React67.forwardRef(
14283
+ (_a, ref) => {
14284
+ var _b = _a, {
14285
+ className,
14286
+ children,
14287
+ hideCloseButton = false,
14288
+ closeButtonProps,
14289
+ closeButton
14290
+ } = _b, props = __objRest(_b, [
14291
+ "className",
14292
+ "children",
14293
+ "hideCloseButton",
14294
+ "closeButtonProps",
14295
+ "closeButton"
14296
+ ]);
14297
+ const closeAriaLabel = (() => {
14298
+ var _a2, _b2, _c;
14299
+ if (closeButton == null) {
14300
+ return (_a2 = closeButtonProps == null ? void 0 : closeButtonProps["aria-label"]) != null ? _a2 : DEFAULT_CLOSE_BTN_PROPS["aria-label"];
14301
+ }
14302
+ const el = closeButton;
14303
+ return (_c = (_b2 = el == null ? void 0 : el.props) == null ? void 0 : _b2["aria-label"]) != null ? _c : "Close";
14304
+ })();
14305
+ return /* @__PURE__ */ jsx(
14306
+ RadixDialog.Content,
14307
+ __spreadProps(__spreadValues({
14308
+ ref,
14309
+ asChild: true,
14310
+ "aria-describedby": void 0
14311
+ }, props), {
14312
+ children: /* @__PURE__ */ jsxs(
14313
+ m.div,
14314
+ __spreadProps(__spreadValues({
14315
+ className: cn(
14316
+ "fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2",
14317
+ "w-[calc(100%-2rem)] max-w-140",
14318
+ "rounded-[28px] bg-m3-surface-container-high p-6",
14319
+ "shadow-lg outline-none focus-visible:ring-2 focus-visible:ring-m3-primary",
14320
+ className
14321
+ ),
14322
+ role: "dialog"
14323
+ }, MD3_CONTENT_ANIM), {
14324
+ children: [
14325
+ children,
14326
+ closeButton != null ? /* @__PURE__ */ jsx(RadixDialog.Close, { asChild: true, "aria-label": closeAriaLabel, children: closeButton }) : !hideCloseButton ? /* @__PURE__ */ jsx(RadixDialog.Close, { asChild: true, "aria-label": closeAriaLabel, children: /* @__PURE__ */ jsx(IconButton, __spreadProps(__spreadValues(__spreadValues({}, DEFAULT_CLOSE_BTN_PROPS), closeButtonProps), { children: /* @__PURE__ */ jsx(Icon, { name: "close", "aria-hidden": "true" }) })) }) : null
14327
+ ]
14328
+ })
14329
+ )
14330
+ })
14331
+ );
14332
+ }
14333
+ );
13929
14334
  DialogContent.displayName = "DialogContent";
13930
14335
  var DialogIcon = React67.forwardRef((_a, ref) => {
13931
14336
  var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
@@ -14016,6 +14421,8 @@ var DialogFullScreenContent = React67.forwardRef(
14016
14421
  title,
14017
14422
  actionLabel,
14018
14423
  onAction,
14424
+ actionButtonProps,
14425
+ closeButtonProps,
14019
14426
  showDivider
14020
14427
  } = _b, props = __objRest(_b, [
14021
14428
  "className",
@@ -14023,8 +14430,11 @@ var DialogFullScreenContent = React67.forwardRef(
14023
14430
  "title",
14024
14431
  "actionLabel",
14025
14432
  "onAction",
14433
+ "actionButtonProps",
14434
+ "closeButtonProps",
14026
14435
  "showDivider"
14027
14436
  ]);
14437
+ var _a2;
14028
14438
  return /* @__PURE__ */ jsx(
14029
14439
  RadixDialog.Content,
14030
14440
  __spreadProps(__spreadValues({
@@ -14044,16 +14454,33 @@ var DialogFullScreenContent = React67.forwardRef(
14044
14454
  }, MD3_FULLSCREEN_ANIM), {
14045
14455
  children: [
14046
14456
  /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center px-4 h-14 gap-2 bg-m3-surface", children: [
14047
- /* @__PURE__ */ jsx(RadixDialog.Close, { asChild: true, "aria-label": "Close dialog", children: /* @__PURE__ */ jsx(IconButton, { size: "sm", colorStyle: "filled", "aria-label": "Close", children: /* @__PURE__ */ jsx(Icon, { name: "close", "aria-hidden": "true" }) }) }),
14457
+ /* @__PURE__ */ jsx(
14458
+ RadixDialog.Close,
14459
+ {
14460
+ asChild: true,
14461
+ "aria-label": (_a2 = closeButtonProps == null ? void 0 : closeButtonProps["aria-label"]) != null ? _a2 : "Close",
14462
+ children: /* @__PURE__ */ jsx(
14463
+ IconButton,
14464
+ __spreadProps(__spreadValues({
14465
+ size: "sm",
14466
+ colorStyle: "standard",
14467
+ "aria-label": "Close"
14468
+ }, closeButtonProps), {
14469
+ children: /* @__PURE__ */ jsx(Icon, { name: "close", "aria-hidden": "true" })
14470
+ })
14471
+ )
14472
+ }
14473
+ ),
14048
14474
  title && /* @__PURE__ */ jsx(DialogTitle, { className: "flex-1 text-[22px] leading-7 font-medium truncate pr-2", children: title }),
14049
14475
  actionLabel && onAction && /* @__PURE__ */ jsx(
14050
14476
  "button",
14051
- {
14477
+ __spreadProps(__spreadValues({
14052
14478
  type: "button",
14053
14479
  onClick: onAction,
14054
- className: "text-sm font-medium text-m3-primary px-3 py-2 rounded-full hover:bg-m3-primary/8 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-m3-primary transition-colors whitespace-nowrap",
14480
+ className: "text-sm font-medium text-m3-primary px-3 py-2 rounded-full hover:bg-m3-primary/8 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-m3-primary transition-colors whitespace-nowrap disabled:opacity-[0.38] disabled:pointer-events-none"
14481
+ }, actionButtonProps), {
14055
14482
  children: actionLabel
14056
- }
14483
+ })
14057
14484
  )
14058
14485
  ] }),
14059
14486
  showDivider && /* @__PURE__ */ jsx("hr", { className: "border-m3-outline-variant w-full shrink-0 m-0" }),
@@ -14081,7 +14508,9 @@ var DatePickerDialog = ({
14081
14508
  dismissButton,
14082
14509
  children,
14083
14510
  className,
14084
- title = "Select date"
14511
+ title = "Select date",
14512
+ width,
14513
+ maxWidth
14085
14514
  }) => {
14086
14515
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (v) => !v && onDismiss(), children: /* @__PURE__ */ jsxs(DialogPortal, { open, children: [
14087
14516
  /* @__PURE__ */ jsx(RadixDialog.Overlay, { asChild: true, forceMount: true, children: /* @__PURE__ */ jsx(
@@ -14117,7 +14546,10 @@ var DatePickerDialog = ({
14117
14546
  "elevation-3",
14118
14547
  className
14119
14548
  ),
14120
- style: { width: "min(calc(100vw - 32px), 360px)" },
14549
+ style: {
14550
+ width: typeof width === "number" ? `${width}px` : width != null ? width : "min(calc(100vw - 32px), 360px)",
14551
+ maxWidth: typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth
14552
+ },
14121
14553
  initial: PICKER_CONTENT_ANIM.initial,
14122
14554
  animate: PICKER_CONTENT_ANIM.animate,
14123
14555
  exit: PICKER_CONTENT_ANIM.exit,
@@ -14141,7 +14573,9 @@ var DateRangePicker = ({
14141
14573
  state,
14142
14574
  showModeToggle = false,
14143
14575
  title,
14144
- className
14576
+ className,
14577
+ width,
14578
+ maxWidth
14145
14579
  }) => {
14146
14580
  const {
14147
14581
  selectedStartMs,
@@ -14213,7 +14647,10 @@ var DateRangePicker = ({
14213
14647
  "fieldset",
14214
14648
  {
14215
14649
  className: cn("flex flex-col select-none", className),
14216
- style: { width: "min(100%, 360px)" },
14650
+ style: {
14651
+ width: typeof width === "number" ? `${width}px` : width != null ? width : "min(100%, 360px)",
14652
+ maxWidth: typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth
14653
+ },
14217
14654
  "aria-label": computedAriaLabel,
14218
14655
  children: [
14219
14656
  /* @__PURE__ */ jsx("legend", { className: "sr-only", children: computedAriaLabel }),
@@ -15039,21 +15476,13 @@ var normalizeAngle = (angle) => {
15039
15476
  return a;
15040
15477
  };
15041
15478
  var angleToHour12 = (angle) => {
15042
- const hourOffset = RADIANS_PER_HOUR / 2;
15043
- const totalOffset = hourOffset + QUARTER_CIRCLE;
15044
- const hour = Math.round((angle + totalOffset) / RADIANS_PER_HOUR) % 12;
15479
+ const normalized = normalizeAngle(angle + QUARTER_CIRCLE);
15480
+ const hour = Math.round(normalized / RADIANS_PER_HOUR) % 12;
15045
15481
  return hour === 0 ? 12 : hour;
15046
15482
  };
15047
- var angleToMinute = (angle, snap = true) => {
15048
- if (snap) {
15049
- const minuteOffset = RADIANS_PER_MINUTE / 2;
15050
- const totalOffset = minuteOffset + QUARTER_CIRCLE;
15051
- const raw2 = Math.round((angle + totalOffset) / RADIANS_PER_MINUTE) % 60;
15052
- return raw2 < 0 ? raw2 + 60 : raw2;
15053
- }
15483
+ var angleToMinute = (angle, _snap = true) => {
15054
15484
  const normalized = normalizeAngle(angle + QUARTER_CIRCLE);
15055
- const raw = Math.round(normalized / FULL_CIRCLE * 60) % 60;
15056
- return raw < 0 ? raw + 60 : raw;
15485
+ return Math.round(normalized / RADIANS_PER_MINUTE) % 60;
15057
15486
  };
15058
15487
  var getSelectorPosition = (angle, selection, is24hour, isPm) => {
15059
15488
  const useInner = is24hour && isPm && selection === "hour";
@@ -15560,13 +15989,16 @@ var useTimePickerState = (options) => {
15560
15989
  };
15561
15990
  function buildWavePath(startX, endX, amplitude = 2, wavelength = 32, yCenter = 4) {
15562
15991
  if (startX >= endX) return "";
15992
+ const totalWidth = endX - startX;
15563
15993
  const halfCycle = wavelength / 2;
15564
- const numHalfCycles = Math.ceil((endX - startX) / halfCycle);
15565
- const cpDistanceY = amplitude * (4 / 3);
15994
+ const numHalfCycles = Math.max(1, Math.round(totalWidth / halfCycle));
15995
+ const actualHalfCycle = totalWidth / numHalfCycles;
15996
+ const scale = Math.min(1, actualHalfCycle / halfCycle);
15997
+ const cpDistanceY = amplitude * (4 / 3) * scale;
15566
15998
  let d = `M ${startX},${yCenter}`;
15567
15999
  for (let i = 0; i < numHalfCycles; i++) {
15568
- const x0 = startX + i * halfCycle;
15569
- const x1 = Math.min(startX + (i + 1) * halfCycle, endX);
16000
+ const x0 = startX + i * actualHalfCycle;
16001
+ const x1 = i === numHalfCycles - 1 ? endX : startX + (i + 1) * actualHalfCycle;
15570
16002
  const peak = i % 2 === 0 ? yCenter - cpDistanceY : yCenter + cpDistanceY;
15571
16003
  const segLen = x1 - x0;
15572
16004
  const cp1x = x0 + segLen / 3;
@@ -15584,7 +16016,7 @@ var DividerImpl = React67.forwardRef(
15584
16016
  insetStart = "standard",
15585
16017
  waveConfig,
15586
16018
  decorative = false,
15587
- animate: animate5 = true,
16019
+ animate: animate7 = true,
15588
16020
  className,
15589
16021
  style
15590
16022
  } = _b, props = __objRest(_b, [
@@ -15600,7 +16032,7 @@ var DividerImpl = React67.forwardRef(
15600
16032
  ]);
15601
16033
  var _a2, _b2, _c;
15602
16034
  const reducedMotion = useReducedMotion();
15603
- const shouldAnimate = animate5 && !reducedMotion;
16035
+ const shouldAnimate = animate7 && !reducedMotion;
15604
16036
  const effectiveShape = shape === "wavy" && orientation === "vertical" ? "flat" : shape;
15605
16037
  if (shape === "wavy" && orientation === "vertical") {
15606
16038
  console.warn(
@@ -17341,7 +17773,7 @@ var ListItemImpl = React67.forwardRef(
17341
17773
  "cursor-grab active:cursor-grabbing text-m3-on-surface-variant p-2 -mr-2"
17342
17774
  )
17343
17775
  }, attributes), listeners), {
17344
- children: /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-[24px]", children: "drag_handle" })
17776
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded text-[24px]", children: "drag_handle" })
17345
17777
  })
17346
17778
  );
17347
17779
  }
@@ -18694,6 +19126,7 @@ var NavigationRailComponent = React67.forwardRef(
18694
19126
  m.div,
18695
19127
  {
18696
19128
  layout: true,
19129
+ transition: SPRING_TRANSITION,
18697
19130
  className: cn(
18698
19131
  "flex w-full flex-col justify-start shrink-0 empty:hidden",
18699
19132
  isExpanded ? "items-start px-3" : "items-center",
@@ -19000,6 +19433,7 @@ function SearchBar({
19000
19433
  onSearch,
19001
19434
  active,
19002
19435
  onActiveChange,
19436
+ showLeadingIcon = true,
19003
19437
  leadingIcon,
19004
19438
  trailingIcon,
19005
19439
  avatar,
@@ -19062,7 +19496,7 @@ function SearchBar({
19062
19496
  layoutId: shouldReduceMotion ? void 0 : searchId,
19063
19497
  transition: shouldReduceMotion ? void 0 : SEARCH_BAR_EXPAND_SPRING,
19064
19498
  className: cn(
19065
- "relative group select-none",
19499
+ "relative group select-none rounded-full",
19066
19500
  SEARCH_ELEVATION.level3,
19067
19501
  className
19068
19502
  ),
@@ -19102,7 +19536,7 @@ function SearchBar({
19102
19536
  "aria-label": ariaLabel,
19103
19537
  className: "relative flex h-full items-center gap-2 rounded-full px-4",
19104
19538
  children: /* @__PURE__ */ jsxs("form", { className: "contents", onSubmit: handleFormSubmit, children: [
19105
- /* @__PURE__ */ jsx(
19539
+ showLeadingIcon && /* @__PURE__ */ jsx(
19106
19540
  "span",
19107
19541
  {
19108
19542
  className: "flex shrink-0 items-center justify-center",
@@ -19309,6 +19743,7 @@ function SearchViewDocked({
19309
19743
  onSearch,
19310
19744
  active,
19311
19745
  onActiveChange,
19746
+ showLeadingIcon = true,
19312
19747
  leadingIcon,
19313
19748
  trailingIcon,
19314
19749
  avatar,
@@ -19365,7 +19800,7 @@ function SearchViewDocked({
19365
19800
  className: "flex items-center gap-2 px-4",
19366
19801
  style: { height: SearchTokens.heights.dockedHeader },
19367
19802
  children: /* @__PURE__ */ jsxs("form", { className: "contents", onSubmit: handleFormSubmit, children: [
19368
- /* @__PURE__ */ jsx(
19803
+ showLeadingIcon && /* @__PURE__ */ jsx(
19369
19804
  "span",
19370
19805
  {
19371
19806
  className: "flex shrink-0 items-center justify-center",
@@ -19460,6 +19895,7 @@ function SearchViewFullScreen({
19460
19895
  onSearch,
19461
19896
  active,
19462
19897
  onActiveChange,
19898
+ showCloseButton = true,
19463
19899
  leadingIcon,
19464
19900
  trailingIcon,
19465
19901
  avatar,
@@ -19526,7 +19962,7 @@ function SearchViewFullScreen({
19526
19962
  className: "flex shrink-0 items-center gap-2 px-4",
19527
19963
  style: { height: SearchTokens.heights.fullScreenHeader },
19528
19964
  children: /* @__PURE__ */ jsxs("form", { className: "contents", onSubmit: handleFormSubmit, children: [
19529
- /* @__PURE__ */ jsx(
19965
+ showCloseButton && /* @__PURE__ */ jsx(
19530
19966
  IconButton,
19531
19967
  {
19532
19968
  size: "sm",
@@ -19627,6 +20063,8 @@ function SearchComponent({
19627
20063
  variant = "docked",
19628
20064
  styleType = "contained",
19629
20065
  hasGap = false,
20066
+ showLeadingIcon = true,
20067
+ showCloseButton = true,
19630
20068
  leadingIcon,
19631
20069
  trailingIcon,
19632
20070
  avatar,
@@ -19655,6 +20093,7 @@ function SearchComponent({
19655
20093
  onSearch,
19656
20094
  active,
19657
20095
  onActiveChange,
20096
+ showLeadingIcon,
19658
20097
  leadingIcon,
19659
20098
  trailingIcon,
19660
20099
  avatar,
@@ -19671,6 +20110,7 @@ function SearchComponent({
19671
20110
  variant === "fullscreen" ? /* @__PURE__ */ jsx(
19672
20111
  SearchViewFullScreen,
19673
20112
  __spreadProps(__spreadValues({}, sharedProps), {
20113
+ showCloseButton,
19674
20114
  styleType,
19675
20115
  viewClassName,
19676
20116
  children
@@ -20323,12 +20763,13 @@ var TextFieldComponent = React67.forwardRef(
20323
20763
  if (autoResize) {
20324
20764
  textarea.style.height = "auto";
20325
20765
  textarea.style.height = `${textarea.scrollHeight}px`;
20326
- if (maxRows) {
20327
- textarea.style.maxHeight = `${maxRows * LINE_HEIGHT_PX}px`;
20328
- }
20766
+ textarea.style.overflowY = "hidden";
20767
+ } else {
20768
+ textarea.style.height = "";
20769
+ textarea.style.maxHeight = "";
20770
+ textarea.style.overflowY = "";
20329
20771
  }
20330
- textarea.style.overflowY = "hidden";
20331
- }, [type, autoResize, maxRows, currentValue]);
20772
+ }, [type, autoResize, currentValue]);
20332
20773
  const handleValueChange = React67.useCallback(
20333
20774
  (newValue) => {
20334
20775
  var _a2, _b;
@@ -20551,7 +20992,7 @@ var TextFieldComponent = React67.forwardRef(
20551
20992
  className: cn(
20552
20993
  inputClass,
20553
20994
  "resize-none mt-2",
20554
- autoResize ? "h-auto" : "h-full"
20995
+ autoResize ? "h-auto" : "min-h-full overflow-y-auto"
20555
20996
  ),
20556
20997
  style: { direction: textDirection || void 0 }
20557
20998
  }, inputProps)
@@ -20690,6 +21131,15 @@ var Select = React67.forwardRef(
20690
21131
  openRef.current = open;
20691
21132
  const [searchQuery, setSearchQuery] = React67.useState("");
20692
21133
  const [scrollViewport, setScrollViewport] = React67.useState(null);
21134
+ React67.useEffect(() => {
21135
+ var _a3, _b3;
21136
+ const isDev = ((_b3 = (_a3 = globalThis.process) == null ? void 0 : _a3.env) == null ? void 0 : _b3.NODE_ENV) !== "production";
21137
+ if (isDev && onSearchChange && !searchable) {
21138
+ console.warn(
21139
+ "[Select] `onSearchChange` was provided but `searchable` is false. The callback will never be called unless you also set `searchable={true}`."
21140
+ );
21141
+ }
21142
+ }, [onSearchChange, searchable]);
20693
21143
  const selectedOption = React67.useMemo(
20694
21144
  () => options.find((opt) => opt.value === currentValue),
20695
21145
  [options, currentValue]
@@ -20915,10 +21365,51 @@ function SelectEmpty(_a) {
20915
21365
  })
20916
21366
  );
20917
21367
  }
21368
+
21369
+ // src/ui/shape-media/animation-utils.ts
20918
21370
  function prefersReducedMotion() {
20919
- if (typeof window === "undefined") return false;
21371
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
21372
+ return false;
21373
+ }
20920
21374
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
20921
21375
  }
21376
+ function easeCubicInOut(t) {
21377
+ return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
21378
+ }
21379
+ function cubicBezier(x1, y1, x2, y2) {
21380
+ return (t) => {
21381
+ if (t === 0 || t === 1) return t;
21382
+ let tParam = t;
21383
+ for (let i = 0; i < 8; i++) {
21384
+ const x = 3 * (1 - tParam) ** 2 * tParam * x1 + 3 * (1 - tParam) * tParam ** 2 * x2 + tParam ** 3;
21385
+ const dx = 3 * (1 - tParam) ** 2 * x1 + 6 * (1 - tParam) * tParam * (x2 - x1) + 3 * tParam ** 2 * (1 - x2);
21386
+ if (Math.abs(dx) < 1e-6) break;
21387
+ tParam -= (x - t) / dx;
21388
+ }
21389
+ return 3 * (1 - tParam) ** 2 * tParam * y1 + 3 * (1 - tParam) * tParam ** 2 * y2 + tParam ** 3;
21390
+ };
21391
+ }
21392
+ function getEasingFunction(easing) {
21393
+ if (Array.isArray(easing)) {
21394
+ if (easing.length === 4) {
21395
+ const [x1, y1, x2, y2] = easing;
21396
+ return cubicBezier(x1, y1, x2, y2);
21397
+ }
21398
+ return easeCubicInOut;
21399
+ }
21400
+ switch (easing) {
21401
+ case "linear":
21402
+ return (t) => t;
21403
+ case "ease-in":
21404
+ return (t) => t * t * t;
21405
+ case "ease-out":
21406
+ return (t) => 1 - (1 - t) ** 3;
21407
+ default:
21408
+ return easeCubicInOut;
21409
+ }
21410
+ }
21411
+
21412
+ // src/ui/shape-media/useShapeMorph.ts
20922
21413
  function useShapeMorph({
20923
21414
  shape,
20924
21415
  morphTo,
@@ -20933,10 +21424,16 @@ function useShapeMorph({
20933
21424
  const duration = (_a = morphOptions == null ? void 0 : morphOptions.duration) != null ? _a : 0.3;
20934
21425
  const easing = (_b = morphOptions == null ? void 0 : morphOptions.easing) != null ? _b : "ease-in-out";
20935
21426
  const easingFunction = useMemo(() => getEasingFunction(easing), [easing]);
21427
+ const resolvedTarget = useMemo(() => {
21428
+ if (morphTo === "auto") {
21429
+ return getRecommendedMorphShape(shape);
21430
+ }
21431
+ return morphTo;
21432
+ }, [morphTo, shape]);
20936
21433
  const startShape = useMemo(() => resolveShape(shape), [shape]);
20937
21434
  const endShape = useMemo(
20938
- () => morphTo ? resolveShape(morphTo) : null,
20939
- [morphTo]
21435
+ () => resolvedTarget ? resolveShape(resolvedTarget) : null,
21436
+ [resolvedTarget]
20940
21437
  );
20941
21438
  const morph = useMemo(
20942
21439
  () => endShape ? new Morph(startShape, endShape) : null,
@@ -20951,7 +21448,45 @@ function useShapeMorph({
20951
21448
  const startProgressRef = useRef(0);
20952
21449
  const targetProgressRef = useRef(0);
20953
21450
  const currentProgressRef = useRef(0);
21451
+ const prevShapeRef = useRef(shape);
20954
21452
  useEffect(() => {
21453
+ if (prevShapeRef.current === shape) return;
21454
+ const oldShape = prevShapeRef.current;
21455
+ prevShapeRef.current = shape;
21456
+ if (disabled || prefersReducedMotion()) {
21457
+ setClipPath(toClipPath(resolveShape(shape), width, height));
21458
+ return;
21459
+ }
21460
+ try {
21461
+ const transitionMorph = new Morph(
21462
+ resolveShape(oldShape),
21463
+ resolveShape(shape)
21464
+ );
21465
+ const start = performance.now();
21466
+ const durationMs = duration * 1e3;
21467
+ const animateTransition = (timestamp) => {
21468
+ const elapsed = timestamp - start;
21469
+ const rawT = Math.min(elapsed / durationMs, 1);
21470
+ const ease = easingFunction(rawT);
21471
+ setClipPath(interpolatePath(transitionMorph, ease, width, height));
21472
+ if (rawT < 1) {
21473
+ animRef.current = requestAnimationFrame(animateTransition);
21474
+ } else {
21475
+ animRef.current = null;
21476
+ }
21477
+ };
21478
+ if (animRef.current !== null) cancelAnimationFrame(animRef.current);
21479
+ animRef.current = requestAnimationFrame(animateTransition);
21480
+ } catch (e) {
21481
+ setClipPath(toClipPath(resolveShape(shape), width, height));
21482
+ }
21483
+ }, [shape, disabled, duration, easingFunction, width, height]);
21484
+ const prevDimsRef = useRef({ width, height, startShape, morph });
21485
+ useEffect(() => {
21486
+ if (prevDimsRef.current.width === width && prevDimsRef.current.height === height && prevDimsRef.current.startShape === startShape && prevDimsRef.current.morph === morph) {
21487
+ return;
21488
+ }
21489
+ prevDimsRef.current = { width, height, startShape, morph };
20955
21490
  if (morph) {
20956
21491
  setClipPath(
20957
21492
  interpolatePath(morph, currentProgressRef.current, width, height)
@@ -20966,7 +21501,7 @@ function useShapeMorph({
20966
21501
  currentProgressRef.current = p;
20967
21502
  setClipPath(interpolatePath(morph, p, width, height));
20968
21503
  }, [scrollProgress, morphOn, morph, width, height]);
20969
- const animate5 = useCallback(
21504
+ const animate7 = useCallback(
20970
21505
  (timestamp) => {
20971
21506
  if (!morph) return;
20972
21507
  const elapsed = timestamp - startTimeRef.current;
@@ -20977,7 +21512,7 @@ function useShapeMorph({
20977
21512
  currentProgressRef.current = progress;
20978
21513
  setClipPath(interpolatePath(morph, progress, width, height));
20979
21514
  if (rawT < 1) {
20980
- animRef.current = requestAnimationFrame(animate5);
21515
+ animRef.current = requestAnimationFrame(animate7);
20981
21516
  } else {
20982
21517
  animRef.current = null;
20983
21518
  }
@@ -20996,9 +21531,9 @@ function useShapeMorph({
20996
21531
  startProgressRef.current = currentProgressRef.current;
20997
21532
  targetProgressRef.current = toProgress;
20998
21533
  startTimeRef.current = performance.now();
20999
- animRef.current = requestAnimationFrame(animate5);
21534
+ animRef.current = requestAnimationFrame(animate7);
21000
21535
  },
21001
- [morph, animate5, width, height]
21536
+ [morph, animate7, width, height]
21002
21537
  );
21003
21538
  useEffect(() => {
21004
21539
  return () => {
@@ -21045,41 +21580,6 @@ function useShapeMorph({
21045
21580
  }, [morphTo, disabled, morphOn, activate, deactivate, isActive]);
21046
21581
  return { clipPath, isActive, activate, deactivate, setProgress, handlers };
21047
21582
  }
21048
- function easeCubicInOut(t) {
21049
- return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
21050
- }
21051
- function cubicBezier(x1, y1, x2, y2) {
21052
- return (t) => {
21053
- if (t === 0 || t === 1) return t;
21054
- let tParam = t;
21055
- for (let i = 0; i < 8; i++) {
21056
- const x = 3 * (1 - tParam) ** 2 * tParam * x1 + 3 * (1 - tParam) * tParam ** 2 * x2 + tParam ** 3;
21057
- const dx = 3 * (1 - tParam) ** 2 * x1 + 6 * (1 - tParam) * tParam * (x2 - x1) + 3 * tParam ** 2 * (1 - x2);
21058
- if (Math.abs(dx) < 1e-6) break;
21059
- tParam -= (x - t) / dx;
21060
- }
21061
- return 3 * (1 - tParam) ** 2 * tParam * y1 + 3 * (1 - tParam) * tParam ** 2 * y2 + tParam ** 3;
21062
- };
21063
- }
21064
- function getEasingFunction(easing) {
21065
- if (Array.isArray(easing)) {
21066
- if (easing.length === 4) {
21067
- const [x1, y1, x2, y2] = easing;
21068
- return cubicBezier(x1, y1, x2, y2);
21069
- }
21070
- return easeCubicInOut;
21071
- }
21072
- switch (easing) {
21073
- case "linear":
21074
- return (t) => t;
21075
- case "ease-in":
21076
- return (t) => t * t * t;
21077
- case "ease-out":
21078
- return (t) => 1 - (1 - t) ** 3;
21079
- default:
21080
- return easeCubicInOut;
21081
- }
21082
- }
21083
21583
  function ShapeMedia({
21084
21584
  shape,
21085
21585
  morphTo,
@@ -21207,10 +21707,14 @@ function ShapeSvg({
21207
21707
  style,
21208
21708
  "aria-label": ariaLabel
21209
21709
  }) {
21710
+ const resolvedTarget = useMemo(() => {
21711
+ if (morphTo === "auto") return getRecommendedMorphShape(shape);
21712
+ return morphTo;
21713
+ }, [morphTo, shape]);
21210
21714
  const startPolygon = useMemo(() => resolveShape(shape), [shape]);
21211
21715
  const endPolygon = useMemo(
21212
- () => morphTo ? resolveShape(morphTo) : null,
21213
- [morphTo]
21716
+ () => resolvedTarget ? resolveShape(resolvedTarget) : null,
21717
+ [resolvedTarget]
21214
21718
  );
21215
21719
  const morph = useMemo(
21216
21720
  () => endPolygon ? new Morph(startPolygon, endPolygon) : null,
@@ -21244,6 +21748,176 @@ function ShapeSvg({
21244
21748
  }
21245
21749
  );
21246
21750
  }
21751
+ function useShapeSequenceMorph({
21752
+ shapes,
21753
+ duration = 0.6,
21754
+ interval = 2,
21755
+ autoplay = false,
21756
+ loop = true,
21757
+ morphOptions,
21758
+ width,
21759
+ height,
21760
+ disabled = false
21761
+ }) {
21762
+ var _a;
21763
+ const resolvedDuration = (_a = morphOptions == null ? void 0 : morphOptions.duration) != null ? _a : duration;
21764
+ const [currentIndex, setCurrentIndex] = useState(0);
21765
+ const [nextIndex, setNextIndex] = useState(() => shapes.length > 1 ? 1 : 0);
21766
+ const [progress, setProgress] = useState(0);
21767
+ const [isPlaying, setIsPlaying] = useState(autoplay);
21768
+ const animRef = useRef(null);
21769
+ const timerRef = useRef(null);
21770
+ const startTimeRef = useRef(0);
21771
+ const isTransitioningRef = useRef(false);
21772
+ const numShapes = shapes.length;
21773
+ const currentShape = useMemo(() => {
21774
+ if (numShapes === 0) return resolveShape("circle");
21775
+ const safeIdx = (currentIndex % numShapes + numShapes) % numShapes;
21776
+ return resolveShape(shapes[safeIdx]);
21777
+ }, [shapes, currentIndex, numShapes]);
21778
+ const targetShape = useMemo(() => {
21779
+ if (numShapes === 0) return resolveShape("circle");
21780
+ const safeIdx = (nextIndex % numShapes + numShapes) % numShapes;
21781
+ return resolveShape(shapes[safeIdx]);
21782
+ }, [shapes, nextIndex, numShapes]);
21783
+ const morph = useMemo(() => {
21784
+ if (currentShape === targetShape) return null;
21785
+ return new Morph(currentShape, targetShape);
21786
+ }, [currentShape, targetShape]);
21787
+ const [clipPath, setClipPath] = useState(
21788
+ () => toClipPath(currentShape, width, height)
21789
+ );
21790
+ const prevDimsRef = useRef({ width, height, currentShape, morph, progress });
21791
+ useEffect(() => {
21792
+ if (prevDimsRef.current.width === width && prevDimsRef.current.height === height && prevDimsRef.current.currentShape === currentShape && prevDimsRef.current.morph === morph && prevDimsRef.current.progress === progress) {
21793
+ return;
21794
+ }
21795
+ prevDimsRef.current = { width, height, currentShape, morph, progress };
21796
+ if (morph && progress > 0) {
21797
+ setClipPath(interpolatePath(morph, progress, width, height));
21798
+ } else {
21799
+ setClipPath(toClipPath(currentShape, width, height));
21800
+ }
21801
+ }, [width, height, currentShape, morph, progress]);
21802
+ const transitionTo = useCallback(
21803
+ (toIndex) => {
21804
+ if (disabled || numShapes <= 1 || isTransitioningRef.current) return;
21805
+ const targetSafe = (toIndex % numShapes + numShapes) % numShapes;
21806
+ if (targetSafe === currentIndex) return;
21807
+ setNextIndex(targetSafe);
21808
+ if (prefersReducedMotion()) {
21809
+ setCurrentIndex(targetSafe);
21810
+ setNextIndex((targetSafe + 1) % numShapes);
21811
+ setProgress(0);
21812
+ setClipPath(
21813
+ toClipPath(resolveShape(shapes[targetSafe]), width, height)
21814
+ );
21815
+ return;
21816
+ }
21817
+ isTransitioningRef.current = true;
21818
+ startTimeRef.current = performance.now();
21819
+ const fromPoly = resolveShape(shapes[currentIndex]);
21820
+ const toPoly = resolveShape(shapes[targetSafe]);
21821
+ const activeMorph = new Morph(fromPoly, toPoly);
21822
+ const animate7 = (timestamp) => {
21823
+ const elapsed = timestamp - startTimeRef.current;
21824
+ const durationMs = resolvedDuration * 1e3;
21825
+ const rawT = Math.min(elapsed / durationMs, 1);
21826
+ const ease = easeCubicInOut(rawT);
21827
+ setProgress(rawT);
21828
+ setClipPath(interpolatePath(activeMorph, ease, width, height));
21829
+ if (rawT < 1) {
21830
+ animRef.current = requestAnimationFrame(animate7);
21831
+ } else {
21832
+ animRef.current = null;
21833
+ isTransitioningRef.current = false;
21834
+ setCurrentIndex(targetSafe);
21835
+ setNextIndex((targetSafe + 1) % numShapes);
21836
+ setProgress(0);
21837
+ }
21838
+ };
21839
+ if (animRef.current !== null) cancelAnimationFrame(animRef.current);
21840
+ animRef.current = requestAnimationFrame(animate7);
21841
+ },
21842
+ [
21843
+ disabled,
21844
+ numShapes,
21845
+ currentIndex,
21846
+ shapes,
21847
+ resolvedDuration,
21848
+ width,
21849
+ height
21850
+ ]
21851
+ );
21852
+ const next = useCallback(() => {
21853
+ if (numShapes <= 1) return;
21854
+ if (!loop && currentIndex >= numShapes - 1) return;
21855
+ transitionTo((currentIndex + 1) % numShapes);
21856
+ }, [numShapes, loop, currentIndex, transitionTo]);
21857
+ const prev = useCallback(() => {
21858
+ if (numShapes <= 1) return;
21859
+ if (!loop && currentIndex <= 0) return;
21860
+ transitionTo((currentIndex - 1 + numShapes) % numShapes);
21861
+ }, [numShapes, loop, currentIndex, transitionTo]);
21862
+ const goTo = useCallback(
21863
+ (index) => {
21864
+ transitionTo(index);
21865
+ },
21866
+ [transitionTo]
21867
+ );
21868
+ const play = useCallback(() => {
21869
+ setIsPlaying(true);
21870
+ }, []);
21871
+ const pause = useCallback(() => {
21872
+ setIsPlaying(false);
21873
+ if (timerRef.current !== null) {
21874
+ clearTimeout(timerRef.current);
21875
+ timerRef.current = null;
21876
+ }
21877
+ }, []);
21878
+ useEffect(() => {
21879
+ if (!isPlaying || disabled || numShapes <= 1) return;
21880
+ timerRef.current = setTimeout(() => {
21881
+ if (!loop && currentIndex >= numShapes - 1) {
21882
+ setIsPlaying(false);
21883
+ return;
21884
+ }
21885
+ next();
21886
+ }, interval * 1e3);
21887
+ return () => {
21888
+ if (timerRef.current !== null) {
21889
+ clearTimeout(timerRef.current);
21890
+ timerRef.current = null;
21891
+ }
21892
+ };
21893
+ }, [isPlaying, disabled, numShapes, loop, currentIndex, interval, next]);
21894
+ useEffect(() => {
21895
+ return () => {
21896
+ if (animRef.current !== null) cancelAnimationFrame(animRef.current);
21897
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
21898
+ };
21899
+ }, []);
21900
+ useEffect(() => {
21901
+ if (currentIndex >= shapes.length) {
21902
+ setCurrentIndex(0);
21903
+ setNextIndex(shapes.length > 1 ? 1 : 0);
21904
+ }
21905
+ }, [shapes.length, currentIndex]);
21906
+ const safeCurrentIndex = numShapes > 0 ? (currentIndex % numShapes + numShapes) % numShapes : 0;
21907
+ const safeNextIndex = numShapes > 0 ? (nextIndex % numShapes + numShapes) % numShapes : 0;
21908
+ return {
21909
+ clipPath,
21910
+ currentIndex: safeCurrentIndex,
21911
+ nextIndex: safeNextIndex,
21912
+ progress,
21913
+ isPlaying,
21914
+ next,
21915
+ prev,
21916
+ goTo,
21917
+ play,
21918
+ pause
21919
+ };
21920
+ }
21247
21921
  var INDICATOR = "h-1 w-8 rounded-full bg-m3-on-surface-variant/40";
21248
21922
  var DragHandle = React67.forwardRef(
21249
21923
  ({ className, onCycle, "aria-label": ariaLabel }, ref) => {
@@ -27272,6 +27946,6 @@ function TooltipBox({
27272
27946
  ] });
27273
27947
  }
27274
27948
 
27275
- export { ANGLE_EPSILON, APP_BAR_BOTTOM_SPRING, APP_BAR_COLORS, APP_BAR_COLOR_TRANSITION, APP_BAR_ENTER_ALWAYS_SPRING, APP_BAR_TITLE_FADE, AppBarColumn, AppBarOverflowIndicator, AppBarRow, AppBarTokens, BUTTON_COLOR_TOKENS, BUTTON_SIZE_TOKENS, Badge, BadgedBox, BottomAppBar, BottomDockedToolbar, BottomSheet, BottomSheetModal, Button, ButtonDistribute, ButtonGroup, CHECK_ICON_VARIANTS, Card, CardContent, CardFooter, CardHeader, CardMedia, Carousel, CarouselGrid, CarouselItem, CarouselScrollClient, CarouselTokens, Checkbox, Chip, CodeBlock, ContextMenu, ContextMenuContent, ContextMenuTrigger, Cubic, DISTANCE_EPSILON, DIVIDER_COLOR, DIVIDER_PADDING, DP_CLASSES, DP_COLORS, DP_SHAPE, DP_SIZE, DatePicker, DatePickerDialog, DatePickerInput, DateRangePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogFullScreenContent, DialogHeader, DialogIcon, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Divider, DockedToolbar, DragHandle, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, ElevatedSplitButtonLeading, ElevatedSplitButtonTrailing, ElevatedSplitButtonTrailingUncheckable, ExtendedFAB, FAB, FABMenu, FABMenuItem, FABPosition, FAST_EFFECTS_TRANSITION, FAST_SPATIAL_SPRING, FLOAT_PI, FadingBlurMask, FilledSplitButtonLeading, FilledSplitButtonTrailing, FilledSplitButtonTrailingUncheckable, GROUP_SHAPES, HorizontalFloatingToolbar, HorizontalFloatingToolbarWithFab, ITEM_SHAPE_CLASSES, Icon, IconButton, LIST_TOKENS, LargeFlexibleAppBar, List, ListContext, ListDivider, ListItem, LoadingIndicator, MD3CornerRadius, MD3Shapes, MD3ThemeProvider, MD3_EXPRESSIVE_FONT_VARIATION, MENU_CHECK_ICON_SIZE, MENU_CONTAINER_VARIANTS, MENU_GROUP_GAP, MENU_ICON_SIZE, MENU_ITEM_MIN_HEIGHT, MENU_MAX_WIDTH, MENU_MIN_WIDTH, MaterialSymbolsPreconnect, MeasuredPolygon, MediumFlexibleAppBar, Menu, MenuContent, MenuDivider, MenuGroup, MenuItem, MenuProvider, MenuTrigger, Morph, MutableCubic, NavigationBar, NavigationBarItem, NavigationRail, NavigationRailItem, OutlinedSplitButtonLeading, OutlinedSplitButtonTrailing, OutlinedSplitButtonTrailingUncheckable, PlainTooltip, ProgressIndicator, RadioButton, RadioGroup, RangeSlider, RichTooltip, Ripple, RoundedPolygon, SEARCH_BAR_EXPAND_SPRING, SEARCH_COLORS, SEARCH_DOCKED_REVEAL_SPRING, SEARCH_FULLSCREEN_SPRING, SEARCH_TYPOGRAPHY, SEARCH_VIEW_SPRING, STANDARD_COLORS, SUBMENU_CONTAINER_VARIANTS, Scrim, ScrollArea, ScrollAreaScrollbar, Search, SearchAppBar, SearchBar, SearchTokens, SearchView, SearchViewContainer, SearchViewDocked, SearchViewFullScreen, Select, ShapeIcon, ShapeMedia, ShapeMediaServer, ShapeSvg, SideSheet, SideSheetModal, Slider, SliderColors, SliderTokens, SmallAppBar, Snackbar, SnackbarContext, SnackbarHost, SnackbarProvider, SplitButtonLayout, SplitButtonLeading, SplitButtonTrailing, SplitButtonTrailingUncheckable, SubMenu, Switch, SwitchColors, SwitchTokens, TP_CLASSES, TP_COLORS, TP_SHAPE, TP_SIZE, Tab, TableOfContents, Tabs, TabsColors, TabsContent, TabsList, TabsTokens, Text, TextField, TimeInput, TimePicker, TimePickerDialog, ToggleFAB, TonalSplitButtonLeading, TonalSplitButtonTrailing, TonalSplitButtonTrailingUncheckable, ToolbarDivider, ToolbarDividerTokens, ToolbarIconButton, ToolbarIconButtonTokens, ToolbarToggleButton, ToolbarToggleButtonTokens, TooltipBox, TooltipCaretShape, TooltipTokens, TriStateCheckbox, TypeScaleTokens, Typography, TypographyContext, TypographyKeyTokens, TypographyProvider, TypographyTokens, UNROUNDED, VIBRANT_COLORS, VerticalFloatingToolbar, VerticalFloatingToolbarWithFab, VerticalMenu, VerticalMenuContent, VerticalMenuDivider, VerticalMenuGroup, addPoints, appBarTypography, applyTheme, buildWavePath, cardVariants, circle, clockwise, convex, cornerFeature, cornerRounding, createDoubleMapper, createMd3ExpressiveTheme, directionVector, distance, distanceSquared, dividePoint, dotProduct, edgeFeature, featureMapper, generateM3Theme, getDirection, getDistance, getDistanceSquared, getExpressiveShape, getListItemHeight, getToolbarColors, interpolate, interpolatePath, lerpPoint, pill, pillStar, point, positiveModulo, radialToCartesian, rectangle, resolveMode, rotate90, scalePoint, shouldTopAlign, square, standardFloatingToolbarColors, star, subtractPoints, surfaceContainerHighFloatingToolbarColors, surfaceContainerHighestFloatingToolbarColors, tertiaryContainerFloatingToolbarColors, toClipPath, toSvgPath, transformFeature, transformPoint, useAppBarScroll, useBottomSheet, useCarouselA11y, useCarouselKeylines, useRipple as useDOMRipple, useDatePickerState, useDateRangePickerState, useFloatingToolbarScrollBehavior, useListContext, useMediaQuery, useMenuContext, useRipple2 as useRipple, useRippleState, useSearchKeyboard, useShapeMorph, useSnackbar, useSnackbarState, useTheme, useThemeMode, useTimePickerState, useTooltipPosition, useTooltipState, useTypography, vibrantFloatingToolbarColors, xrFloatingToolbarColors };
27949
+ export { ANGLE_EPSILON, APP_BAR_BOTTOM_SPRING, APP_BAR_COLORS, APP_BAR_COLOR_TRANSITION, APP_BAR_ENTER_ALWAYS_SPRING, APP_BAR_TITLE_FADE, AppBarColumn, AppBarOverflowIndicator, AppBarRow, AppBarTokens, BUTTON_COLOR_TOKENS, BUTTON_SIZE_TOKENS, Badge, BadgedBox, BottomAppBar, BottomDockedToolbar, BottomSheet, BottomSheetModal, Button, ButtonDistribute, ButtonGroup, CHECK_ICON_VARIANTS, Card, CardContent, CardFooter, CardHeader, CardMedia, Carousel, CarouselGrid, CarouselItem, CarouselScrollClient, CarouselTokens, Checkbox, Chip, CodeBlock, ContextMenu, ContextMenuContent, ContextMenuTrigger, Cubic, DISTANCE_EPSILON, DIVIDER_COLOR, DIVIDER_PADDING, DP_CLASSES, DP_COLORS, DP_SHAPE, DP_SIZE, DatePicker, DatePickerDialog, DatePickerInput, DateRangePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogFullScreenContent, DialogHeader, DialogIcon, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Divider, DockedToolbar, DragHandle, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, ElevatedSplitButtonLeading, ElevatedSplitButtonTrailing, ElevatedSplitButtonTrailingUncheckable, ExtendedFAB, FAB, FABMenu, FABMenuItem, FABPosition, FAST_EFFECTS_TRANSITION, FAST_SPATIAL_SPRING, FLOAT_PI, FadingBlurMask, FilledSplitButtonLeading, FilledSplitButtonTrailing, FilledSplitButtonTrailingUncheckable, GROUP_SHAPES, HorizontalFloatingToolbar, HorizontalFloatingToolbarWithFab, ITEM_SHAPE_CLASSES, Icon, IconButton, LIST_TOKENS, LargeFlexibleAppBar, List, ListContext, ListDivider, ListItem, LoadingIndicator, MD3CornerRadius, MD3Shapes, MD3ThemeProvider, MD3_EXPRESSIVE_FONT_VARIATION, MD3_SHAPE_FAMILIES, MD3_SHAPE_PAIRINGS, MENU_CHECK_ICON_SIZE, MENU_CONTAINER_VARIANTS, MENU_GROUP_GAP, MENU_ICON_SIZE, MENU_ITEM_MIN_HEIGHT, MENU_MAX_WIDTH, MENU_MIN_WIDTH, MaterialSymbolsPreconnect, MeasuredPolygon, MediumFlexibleAppBar, Menu, MenuContent, MenuDivider, MenuGroup, MenuItem, MenuProvider, MenuTrigger, Morph, MutableCubic, NavigationBar, NavigationBarItem, NavigationRail, NavigationRailItem, OutlinedSplitButtonLeading, OutlinedSplitButtonTrailing, OutlinedSplitButtonTrailingUncheckable, PlainTooltip, ProgressIndicator, RadioButton, RadioGroup, RangeSlider, RichTooltip, Ripple, RoundedPolygon, SEARCH_BAR_EXPAND_SPRING, SEARCH_COLORS, SEARCH_DOCKED_REVEAL_SPRING, SEARCH_FULLSCREEN_SPRING, SEARCH_TYPOGRAPHY, SEARCH_VIEW_SPRING, STANDARD_COLORS, SUBMENU_CONTAINER_VARIANTS, Scrim, ScrollArea, ScrollAreaScrollbar, Search, SearchAppBar, SearchBar, SearchTokens, SearchView, SearchViewContainer, SearchViewDocked, SearchViewFullScreen, Select, ShapeIcon, ShapeMedia, ShapeMediaServer, ShapeSvg, SideSheet, SideSheetModal, Slider, SliderColors, SliderTokens, SmallAppBar, Snackbar, SnackbarContext, SnackbarHost, SnackbarProvider, SplitButtonLayout, SplitButtonLeading, SplitButtonTrailing, SplitButtonTrailingUncheckable, SubMenu, Switch, SwitchColors, SwitchTokens, TP_CLASSES, TP_COLORS, TP_SHAPE, TP_SIZE, Tab, TableOfContents, Tabs, TabsColors, TabsContent, TabsList, TabsTokens, Text, TextField, TimeInput, TimePicker, TimePickerDialog, ToggleFAB, TonalSplitButtonLeading, TonalSplitButtonTrailing, TonalSplitButtonTrailingUncheckable, ToolbarDivider, ToolbarDividerTokens, ToolbarIconButton, ToolbarIconButtonTokens, ToolbarToggleButton, ToolbarToggleButtonTokens, TooltipBox, TooltipCaretShape, TooltipTokens, TriStateCheckbox, TypeScaleTokens, Typography, TypographyContext, TypographyKeyTokens, TypographyProvider, TypographyTokens, UNROUNDED, VIBRANT_COLORS, VerticalFloatingToolbar, VerticalFloatingToolbarWithFab, VerticalMenu, VerticalMenuContent, VerticalMenuDivider, VerticalMenuGroup, addPoints, appBarTypography, applyTheme, buildWavePath, cardVariants, circle, clockwise, convex, cornerFeature, cornerRounding, createDoubleMapper, createMd3ExpressiveTheme, directionVector, distance, distanceSquared, dividePoint, dotProduct, edgeFeature, featureMapper, formatCoordinate, generateM3Theme, getDirection, getDistance, getDistanceSquared, getExpressiveShape, getListItemHeight, getRecommendedMorphShape, getToolbarColors, interpolate, interpolatePath, lerpPoint, pill, pillStar, point, positiveModulo, radialToCartesian, rectangle, resolveMode, rotate90, scalePoint, shouldTopAlign, square, standardFloatingToolbarColors, star, subtractPoints, surfaceContainerHighFloatingToolbarColors, surfaceContainerHighestFloatingToolbarColors, tertiaryContainerFloatingToolbarColors, toClipPath, toSvgPath, transformFeature, transformPoint, useAppBarScroll, useBottomSheet, useCarouselA11y, useCarouselKeylines, useRipple as useDOMRipple, useDatePickerState, useDateRangePickerState, useFloatingToolbarScrollBehavior, useListContext, useMediaQuery, useMenuContext, useRipple2 as useRipple, useRippleState, useSearchKeyboard, useShapeMorph, useShapeSequenceMorph, useSnackbar, useSnackbarState, useTheme, useThemeMode, useTimePickerState, useTooltipPosition, useTooltipState, useTypography, vibrantFloatingToolbarColors, xrFloatingToolbarColors };
27276
27950
  //# sourceMappingURL=index.mjs.map
27277
27951
  //# sourceMappingURL=index.mjs.map