@tetrax/squircle 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,809 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/react/index.tsx
32
+ var react_exports = {};
33
+ __export(react_exports, {
34
+ Squircle: () => Squircle,
35
+ SquircleNoScript: () => SquircleNoScript,
36
+ default: () => react_default,
37
+ initGlobalSquircleObserver: () => initGlobalSquircleObserver
38
+ });
39
+ module.exports = __toCommonJS(react_exports);
40
+ var import_react = __toESM(require("react"));
41
+
42
+ // src/core/squircle-path.ts
43
+ function toRadians(deg) {
44
+ return deg * Math.PI / 180;
45
+ }
46
+ function rounded(strings, ...values) {
47
+ return strings.reduce((acc, str, i) => {
48
+ const value = values[i];
49
+ return typeof value === "number" ? acc + str + value.toFixed(4) : acc + str + (value ?? "");
50
+ }, "");
51
+ }
52
+ function getPathParamsForCorner({
53
+ cornerRadius,
54
+ cornerSmoothing,
55
+ preserveSmoothing,
56
+ roundingAndSmoothingBudget
57
+ }) {
58
+ if (cornerRadius <= 0 || roundingAndSmoothingBudget <= 0) {
59
+ return { a: 0, b: 0, c: 0, d: 0, p: 0, cornerRadius: 0, arcSectionLength: 0 };
60
+ }
61
+ let p = (1 + cornerSmoothing) * cornerRadius;
62
+ if (!preserveSmoothing) {
63
+ const maxCornerSmoothing = roundingAndSmoothingBudget / cornerRadius - 1;
64
+ cornerSmoothing = Math.min(cornerSmoothing, maxCornerSmoothing);
65
+ p = Math.min(p, roundingAndSmoothingBudget);
66
+ }
67
+ const arcMeasure = 90 * (1 - cornerSmoothing);
68
+ const arcSectionLength = Math.sin(toRadians(arcMeasure / 2)) * cornerRadius * Math.sqrt(2);
69
+ const angleAlpha = (90 - arcMeasure) / 2;
70
+ const p3ToP4Distance = cornerRadius * Math.tan(toRadians(angleAlpha / 2));
71
+ const angleBeta = 45 * cornerSmoothing;
72
+ const c = p3ToP4Distance * Math.cos(toRadians(angleBeta));
73
+ const d = c * Math.tan(toRadians(angleBeta));
74
+ let b = (p - arcSectionLength - c - d) / 3;
75
+ let a = 2 * b;
76
+ if (preserveSmoothing && p > roundingAndSmoothingBudget) {
77
+ const p1ToP3MaxDistance = roundingAndSmoothingBudget - d - arcSectionLength - c;
78
+ const minA = p1ToP3MaxDistance / 6;
79
+ const maxB = p1ToP3MaxDistance - minA;
80
+ b = Math.min(b, maxB);
81
+ a = p1ToP3MaxDistance - b;
82
+ p = Math.min(p, roundingAndSmoothingBudget);
83
+ }
84
+ return { a, b, c, d, p, arcSectionLength, cornerRadius };
85
+ }
86
+ function drawTopRightPath({ cornerRadius, a, b, c, d, p, arcSectionLength }) {
87
+ if (cornerRadius) {
88
+ return rounded`c ${a} 0 ${a + b} 0 ${a + b + c} ${d} a ${cornerRadius} ${cornerRadius} 0 0 1 ${arcSectionLength} ${arcSectionLength} c ${d} ${c} ${d} ${b + c} ${d} ${a + b + c}`;
89
+ }
90
+ return rounded`l ${p} 0`;
91
+ }
92
+ function drawBottomRightPath({ cornerRadius, a, b, c, d, p, arcSectionLength }) {
93
+ if (cornerRadius) {
94
+ return rounded`c 0 ${a} 0 ${a + b} ${-d} ${a + b + c} a ${cornerRadius} ${cornerRadius} 0 0 1 ${-arcSectionLength} ${arcSectionLength} c ${-c} ${d} ${-(b + c)} ${d} ${-(a + b + c)} ${d}`;
95
+ }
96
+ return rounded`l 0 ${p}`;
97
+ }
98
+ function drawBottomLeftPath({ cornerRadius, a, b, c, d, p, arcSectionLength }) {
99
+ if (cornerRadius) {
100
+ return rounded`c ${-a} 0 ${-(a + b)} 0 ${-(a + b + c)} ${-d} a ${cornerRadius} ${cornerRadius} 0 0 1 ${-arcSectionLength} ${-arcSectionLength} c ${-d} ${-c} ${-d} ${-(b + c)} ${-d} ${-(a + b + c)}`;
101
+ }
102
+ return rounded`l ${-p} 0`;
103
+ }
104
+ function drawTopLeftPath({ cornerRadius, a, b, c, d, p, arcSectionLength }) {
105
+ if (cornerRadius) {
106
+ return rounded`c 0 ${-a} 0 ${-(a + b)} ${d} ${-(a + b + c)} a ${cornerRadius} ${cornerRadius} 0 0 1 ${arcSectionLength} ${-arcSectionLength} c ${c} ${-d} ${b + c} ${-d} ${a + b + c} ${-d}`;
107
+ }
108
+ return rounded`l 0 ${-p}`;
109
+ }
110
+ function getSVGPathFromPathParams({
111
+ width,
112
+ height,
113
+ topLeftPathParams,
114
+ topRightPathParams,
115
+ bottomRightPathParams,
116
+ bottomLeftPathParams
117
+ }) {
118
+ return `
119
+ M ${width - topRightPathParams.p} 0
120
+ ${drawTopRightPath(topRightPathParams)}
121
+ L ${width} ${height - bottomRightPathParams.p}
122
+ ${drawBottomRightPath(bottomRightPathParams)}
123
+ L ${bottomLeftPathParams.p} ${height}
124
+ ${drawBottomLeftPath(bottomLeftPathParams)}
125
+ L 0 ${topLeftPathParams.p}
126
+ ${drawTopLeftPath(topLeftPathParams)}
127
+ Z
128
+ `.replace(/[\t\s\n]+/g, " ").trim();
129
+ }
130
+ var adjacentsByCorner = {
131
+ topLeft: [
132
+ { corner: "topRight", side: "top" },
133
+ { corner: "bottomLeft", side: "left" }
134
+ ],
135
+ topRight: [
136
+ { corner: "topLeft", side: "top" },
137
+ { corner: "bottomRight", side: "right" }
138
+ ],
139
+ bottomLeft: [
140
+ { corner: "bottomRight", side: "bottom" },
141
+ { corner: "topLeft", side: "left" }
142
+ ],
143
+ bottomRight: [
144
+ { corner: "bottomLeft", side: "bottom" },
145
+ { corner: "topRight", side: "right" }
146
+ ]
147
+ };
148
+ function distributeAndNormalize({
149
+ topLeftCornerRadius,
150
+ topRightCornerRadius,
151
+ bottomRightCornerRadius,
152
+ bottomLeftCornerRadius,
153
+ width,
154
+ height
155
+ }) {
156
+ const roundingAndSmoothingBudgetMap = {
157
+ topLeft: -1,
158
+ topRight: -1,
159
+ bottomLeft: -1,
160
+ bottomRight: -1
161
+ };
162
+ const cornerRadiusMap = {
163
+ topLeft: topLeftCornerRadius,
164
+ topRight: topRightCornerRadius,
165
+ bottomLeft: bottomLeftCornerRadius,
166
+ bottomRight: bottomRightCornerRadius
167
+ };
168
+ Object.entries(cornerRadiusMap).sort(([, r1], [, r2]) => r2 - r1).forEach(([corner, radius]) => {
169
+ const adjacents = adjacentsByCorner[corner];
170
+ const budget = Math.min(
171
+ ...adjacents.map((adj) => {
172
+ const adjRadius = cornerRadiusMap[adj.corner];
173
+ if (radius === 0 && adjRadius === 0) return 0;
174
+ const adjBudget = roundingAndSmoothingBudgetMap[adj.corner];
175
+ const sideLen = adj.side === "top" || adj.side === "bottom" ? width : height;
176
+ return adjBudget >= 0 ? sideLen - roundingAndSmoothingBudgetMap[adj.corner] : radius / (radius + adjRadius) * sideLen;
177
+ })
178
+ );
179
+ roundingAndSmoothingBudgetMap[corner] = budget;
180
+ cornerRadiusMap[corner] = Math.min(radius, budget);
181
+ });
182
+ return {
183
+ topLeft: { radius: cornerRadiusMap.topLeft, roundingAndSmoothingBudget: roundingAndSmoothingBudgetMap.topLeft },
184
+ topRight: { radius: cornerRadiusMap.topRight, roundingAndSmoothingBudget: roundingAndSmoothingBudgetMap.topRight },
185
+ bottomLeft: { radius: cornerRadiusMap.bottomLeft, roundingAndSmoothingBudget: roundingAndSmoothingBudgetMap.bottomLeft },
186
+ bottomRight: { radius: cornerRadiusMap.bottomRight, roundingAndSmoothingBudget: roundingAndSmoothingBudgetMap.bottomRight }
187
+ };
188
+ }
189
+ function drawPureBezierTopRight(r) {
190
+ if (r <= 0) return "";
191
+ return rounded`c ${0.3 * r} 0 ${0.473 * r} 0 ${0.619 * r} ${0.039 * r} c ${0.185 * r} ${0.049 * r} ${0.293 * r} ${0.157 * r} ${0.342 * r} ${0.342 * r} c ${0.039 * r} ${0.146 * r} ${0.039 * r} ${0.319 * r} ${0.039 * r} ${0.619 * r}`;
192
+ }
193
+ function drawPureBezierBottomRight(r) {
194
+ if (r <= 0) return "";
195
+ return rounded`c 0 ${0.3 * r} 0 ${0.473 * r} ${-0.039 * r} ${0.619 * r} c ${-0.049 * r} ${0.185 * r} ${-0.157 * r} ${0.293 * r} ${-0.342 * r} ${0.342 * r} c ${-0.146 * r} ${0.039 * r} ${-0.319 * r} ${0.039 * r} ${-0.619 * r} ${0.039 * r}`;
196
+ }
197
+ function drawPureBezierBottomLeft(r) {
198
+ if (r <= 0) return "";
199
+ return rounded`c ${-0.3 * r} 0 ${-0.473 * r} 0 ${-0.619 * r} ${-0.039 * r} c ${-0.185 * r} ${-0.049 * r} ${-0.293 * r} ${-0.157 * r} ${-0.342 * r} ${-0.342 * r} c ${-0.039 * r} ${-0.146 * r} ${-0.039 * r} ${-0.319 * r} ${-0.039 * r} ${-0.619 * r}`;
200
+ }
201
+ function drawPureBezierTopLeft(r) {
202
+ if (r <= 0) return "";
203
+ return rounded`c 0 ${-0.3 * r} 0 ${-0.473 * r} ${0.039 * r} ${-0.619 * r} c ${0.049 * r} ${-0.185 * r} ${0.157 * r} ${-0.293 * r} ${0.342 * r} ${-0.342 * r} c ${0.146 * r} ${-0.039 * r} ${0.319 * r} ${-0.039 * r} ${0.619 * r} ${-0.039 * r}`;
204
+ }
205
+ function getPureBezierSVGPath(width, height, tl, tr, br, bl) {
206
+ return `
207
+ M ${width - tr} 0
208
+ ${drawPureBezierTopRight(tr)}
209
+ L ${width} ${height - br}
210
+ ${drawPureBezierBottomRight(br)}
211
+ L ${bl} ${height}
212
+ ${drawPureBezierBottomLeft(bl)}
213
+ L 0 ${tl}
214
+ ${drawPureBezierTopLeft(tl)}
215
+ Z
216
+ `.replace(/[\t\s\n]+/g, " ").trim();
217
+ }
218
+ function getSvgPath({
219
+ cornerRadius = 0,
220
+ topLeftCornerRadius,
221
+ topRightCornerRadius,
222
+ bottomRightCornerRadius,
223
+ bottomLeftCornerRadius,
224
+ cornerSmoothing = 1,
225
+ width,
226
+ height,
227
+ preserveSmoothing = false,
228
+ g2Continuous = false
229
+ }) {
230
+ const tl = topLeftCornerRadius ?? cornerRadius;
231
+ const tr = topRightCornerRadius ?? cornerRadius;
232
+ const bl = bottomLeftCornerRadius ?? cornerRadius;
233
+ const br = bottomRightCornerRadius ?? cornerRadius;
234
+ if (g2Continuous) {
235
+ const { topLeft: topLeft2, topRight: topRight2, bottomLeft: bottomLeft2, bottomRight: bottomRight2 } = distributeAndNormalize({
236
+ topLeftCornerRadius: tl,
237
+ topRightCornerRadius: tr,
238
+ bottomRightCornerRadius: br,
239
+ bottomLeftCornerRadius: bl,
240
+ width,
241
+ height
242
+ });
243
+ return getPureBezierSVGPath(
244
+ width,
245
+ height,
246
+ topLeft2.radius,
247
+ topRight2.radius,
248
+ bottomRight2.radius,
249
+ bottomLeft2.radius
250
+ );
251
+ }
252
+ if (tl === tr && tr === br && br === bl) {
253
+ const roundingAndSmoothingBudget = Math.min(width, height) / 2;
254
+ const clampedRadius = Math.min(tl, roundingAndSmoothingBudget);
255
+ const params = getPathParamsForCorner({
256
+ cornerRadius: clampedRadius,
257
+ cornerSmoothing,
258
+ preserveSmoothing,
259
+ roundingAndSmoothingBudget
260
+ });
261
+ return getSVGPathFromPathParams({
262
+ width,
263
+ height,
264
+ topLeftPathParams: params,
265
+ topRightPathParams: params,
266
+ bottomLeftPathParams: params,
267
+ bottomRightPathParams: params
268
+ });
269
+ }
270
+ const { topLeft, topRight, bottomLeft, bottomRight } = distributeAndNormalize({
271
+ topLeftCornerRadius: tl,
272
+ topRightCornerRadius: tr,
273
+ bottomRightCornerRadius: br,
274
+ bottomLeftCornerRadius: bl,
275
+ width,
276
+ height
277
+ });
278
+ return getSVGPathFromPathParams({
279
+ width,
280
+ height,
281
+ topLeftPathParams: getPathParamsForCorner({ cornerSmoothing, preserveSmoothing, cornerRadius: topLeft.radius, roundingAndSmoothingBudget: topLeft.roundingAndSmoothingBudget }),
282
+ topRightPathParams: getPathParamsForCorner({ cornerSmoothing, preserveSmoothing, cornerRadius: topRight.radius, roundingAndSmoothingBudget: topRight.roundingAndSmoothingBudget }),
283
+ bottomRightPathParams: getPathParamsForCorner({ cornerSmoothing, preserveSmoothing, cornerRadius: bottomRight.radius, roundingAndSmoothingBudget: bottomRight.roundingAndSmoothingBudget }),
284
+ bottomLeftPathParams: getPathParamsForCorner({ cornerSmoothing, preserveSmoothing, cornerRadius: bottomLeft.radius, roundingAndSmoothingBudget: bottomLeft.roundingAndSmoothingBudget })
285
+ });
286
+ }
287
+ function computeSquirclePath(width, height, cornerRadius, cornerSmoothing = 1, preserveSmoothing = false, g2Continuous = false) {
288
+ if (width <= 0 || height <= 0 || cornerRadius <= 0) return "";
289
+ return getSvgPath({ width, height, cornerRadius, cornerSmoothing, preserveSmoothing, g2Continuous });
290
+ }
291
+
292
+ // src/core/class-parser.ts
293
+ var ROUNDED_RE = /^rounded-squircle-(\d+)$/;
294
+ var SMOOTHING_RE = /^corner-smoothing-(\d{1,3})$/;
295
+ var SQUIRCLE_BORDER_WIDTH_RE = /^squircle-border-(\d+(\.\d+)?)$/;
296
+ var TW_BORDER_COLOR_RE = /^border-(\[.+\]|[\w-]+)(\/(\d+))?$/;
297
+ var TW_BORDER_WIDTH_RE = /^border-(\d+)$/;
298
+ var TW_BORDER_BASE_RE = /^border$/;
299
+ var BORDER_COLORS = {
300
+ "gray-50": "#f9fafb",
301
+ "gray-100": "#f3f4f6",
302
+ "gray-200": "#e5e7eb",
303
+ "gray-300": "#d1d5db",
304
+ "gray-400": "#9ca3af",
305
+ "gray-500": "#6b7280",
306
+ "gray-600": "#4b5563",
307
+ "gray-700": "#374151",
308
+ "gray-800": "#1f2937",
309
+ "gray-900": "#111827",
310
+ "slate-50": "#f8fafc",
311
+ "slate-100": "#f1f5f9",
312
+ "slate-200": "#e2e8f0",
313
+ "slate-300": "#cbd5e1",
314
+ "slate-400": "#94a3b8",
315
+ "slate-500": "#64748b",
316
+ "slate-600": "#475569",
317
+ "slate-700": "#334155",
318
+ "slate-800": "#1e293b",
319
+ "slate-900": "#0f172a",
320
+ "red-50": "#fef2f2",
321
+ "red-100": "#fee2e2",
322
+ "red-200": "#fecaca",
323
+ "red-300": "#fca5a5",
324
+ "red-400": "#f87171",
325
+ "red-500": "#ef4444",
326
+ "red-600": "#dc2626",
327
+ "red-700": "#b91c1c",
328
+ "red-800": "#991b1b",
329
+ "red-900": "#7f1d1d",
330
+ "blue-50": "#eff6ff",
331
+ "blue-100": "#dbeafe",
332
+ "blue-200": "#bfdbfe",
333
+ "blue-300": "#93c5fd",
334
+ "blue-400": "#60a5fa",
335
+ "blue-500": "#3b82f6",
336
+ "blue-600": "#2563eb",
337
+ "blue-700": "#1d4ed8",
338
+ "blue-800": "#1e40af",
339
+ "blue-900": "#1e3a8a",
340
+ "green-50": "#f0fdf4",
341
+ "green-100": "#dcfce7",
342
+ "green-200": "#bbf7d0",
343
+ "green-300": "#86efac",
344
+ "green-400": "#4ade80",
345
+ "green-500": "#22c55e",
346
+ "green-600": "#16a34a",
347
+ "green-700": "#15803d",
348
+ "green-800": "#166534",
349
+ "green-900": "#14532d",
350
+ "yellow-50": "#fefce8",
351
+ "yellow-100": "#fef9c3",
352
+ "yellow-200": "#fef08a",
353
+ "yellow-300": "#fde047",
354
+ "yellow-400": "#facc15",
355
+ "yellow-500": "#eab308",
356
+ "yellow-600": "#ca8a04",
357
+ "yellow-700": "#a16207",
358
+ "yellow-800": "#854d0e",
359
+ "yellow-900": "#713f12",
360
+ "purple-50": "#faf5ff",
361
+ "purple-100": "#f3e8ff",
362
+ "purple-200": "#e9d5ff",
363
+ "purple-300": "#d8b4fe",
364
+ "purple-400": "#c084fc",
365
+ "purple-500": "#a855f7",
366
+ "purple-600": "#9333ea",
367
+ "purple-700": "#7e22ce",
368
+ "purple-800": "#6b21a8",
369
+ "purple-900": "#581c87",
370
+ "pink-50": "#fdf2f8",
371
+ "pink-100": "#fce7f3",
372
+ "pink-200": "#fbcfe8",
373
+ "pink-300": "#f9a8d4",
374
+ "pink-400": "#f472b6",
375
+ "pink-500": "#ec4899",
376
+ "pink-600": "#db2777",
377
+ "pink-700": "#be185d",
378
+ "pink-800": "#9d174d",
379
+ "pink-900": "#831843",
380
+ "orange-50": "#fff7ed",
381
+ "orange-100": "#ffedd5",
382
+ "orange-200": "#fed7aa",
383
+ "orange-300": "#fdba74",
384
+ "orange-400": "#fb923c",
385
+ "orange-500": "#f97316",
386
+ "orange-600": "#ea580c",
387
+ "orange-700": "#c2410c",
388
+ "orange-800": "#9a3412",
389
+ "orange-900": "#7c2d12",
390
+ "teal-50": "#f0fdfa",
391
+ "teal-100": "#ccfbf1",
392
+ "teal-200": "#99f6e4",
393
+ "teal-300": "#5eead4",
394
+ "teal-400": "#2dd4bf",
395
+ "teal-500": "#14b8a6",
396
+ "teal-600": "#0d9488",
397
+ "teal-700": "#0f766e",
398
+ "teal-800": "#115e59",
399
+ "teal-900": "#134e4a",
400
+ white: "#ffffff",
401
+ black: "#000000",
402
+ transparent: "transparent"
403
+ };
404
+ function hexToRgba(hex, opacity) {
405
+ const h = hex.replace(/#/g, "");
406
+ const r = parseInt(h.substring(0, 2), 16);
407
+ const g = parseInt(h.substring(2, 4), 16);
408
+ const b = parseInt(h.substring(4, 6), 16);
409
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
410
+ }
411
+ function resolveColorToken(token, opacity) {
412
+ if (token.startsWith("[") && token.endsWith("]")) {
413
+ const raw = token.slice(1, -1);
414
+ if (opacity !== void 0 && raw.startsWith("#")) {
415
+ return hexToRgba(raw, opacity);
416
+ }
417
+ return raw;
418
+ }
419
+ const hex = BORDER_COLORS[token];
420
+ if (!hex) return null;
421
+ if (opacity !== void 0) return hexToRgba(hex, opacity);
422
+ return hex;
423
+ }
424
+ function parseSquircleClasses(className = "") {
425
+ const classes = className.split(/\s+/).filter(Boolean);
426
+ let cornerRadius = null;
427
+ let cornerSmoothing = 1;
428
+ let squircleBorder = false;
429
+ let borderColor = null;
430
+ let borderWidth = null;
431
+ let g2Continuous = false;
432
+ const rest = [];
433
+ for (const cls of classes) {
434
+ let matched = false;
435
+ let m = cls.match(ROUNDED_RE);
436
+ if (m) {
437
+ cornerRadius = Number(m[1]);
438
+ matched = true;
439
+ }
440
+ if (!matched) {
441
+ m = cls.match(SMOOTHING_RE);
442
+ if (m) {
443
+ cornerSmoothing = Math.min(100, Math.max(0, Number(m[1]))) / 100;
444
+ matched = true;
445
+ }
446
+ }
447
+ if (!matched && cls === "squircle-border") {
448
+ squircleBorder = true;
449
+ matched = true;
450
+ }
451
+ if (!matched && cls === "squircle-g2") {
452
+ g2Continuous = true;
453
+ matched = true;
454
+ }
455
+ if (!matched) {
456
+ m = cls.match(SQUIRCLE_BORDER_WIDTH_RE);
457
+ if (m) {
458
+ squircleBorder = true;
459
+ borderWidth = Number(m[1]);
460
+ matched = true;
461
+ }
462
+ }
463
+ if (!matched && squircleBorder) {
464
+ m = cls.match(TW_BORDER_WIDTH_RE);
465
+ if (m) {
466
+ borderWidth = Number(m[1]);
467
+ matched = true;
468
+ }
469
+ if (!matched && cls.match(TW_BORDER_BASE_RE)) {
470
+ borderWidth = 1;
471
+ matched = true;
472
+ }
473
+ if (!matched) {
474
+ m = cls.match(TW_BORDER_COLOR_RE);
475
+ if (m) {
476
+ const colorToken = m[1];
477
+ const opacityPercent = m[3] ? Number(m[3]) / 100 : void 0;
478
+ const resolved = resolveColorToken(colorToken, opacityPercent);
479
+ if (resolved) {
480
+ borderColor = resolved;
481
+ matched = true;
482
+ }
483
+ }
484
+ }
485
+ }
486
+ if (!matched) rest.push(cls);
487
+ }
488
+ return {
489
+ cornerRadius,
490
+ cornerSmoothing,
491
+ squircleBorder,
492
+ borderColor,
493
+ borderWidth: borderWidth ?? 1,
494
+ g2Continuous,
495
+ restClasses: rest.join(" ")
496
+ };
497
+ }
498
+
499
+ // src/react/index.tsx
500
+ var import_jsx_runtime = require("react/jsx-runtime");
501
+ function SquircleSvgBorder({
502
+ width,
503
+ height,
504
+ cornerRadius,
505
+ cornerSmoothing,
506
+ borderColor,
507
+ borderWidth,
508
+ g2Continuous
509
+ }) {
510
+ if (width <= 0 || height <= 0 || cornerRadius <= 0 || borderWidth <= 0) return null;
511
+ const inset = borderWidth / 2;
512
+ const innerW = Math.max(1, width - inset * 2);
513
+ const innerH = Math.max(1, height - inset * 2);
514
+ const innerR = Math.max(0, cornerRadius - inset);
515
+ const pathData = computeSquirclePath(innerW, innerH, innerR, cornerSmoothing, false, g2Continuous);
516
+ if (!pathData) return null;
517
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
518
+ "svg",
519
+ {
520
+ width,
521
+ height,
522
+ viewBox: `0 0 ${width} ${height}`,
523
+ style: {
524
+ position: "absolute",
525
+ top: 0,
526
+ left: 0,
527
+ pointerEvents: "none",
528
+ overflow: "visible"
529
+ },
530
+ "aria-hidden": "true",
531
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", { transform: `translate(${inset}, ${inset})`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
532
+ "path",
533
+ {
534
+ d: pathData,
535
+ fill: "none",
536
+ stroke: borderColor,
537
+ strokeWidth: borderWidth,
538
+ strokeLinejoin: "round"
539
+ }
540
+ ) })
541
+ }
542
+ );
543
+ }
544
+ function Squircle(props) {
545
+ const {
546
+ children,
547
+ className = "",
548
+ cornerRadius: cornerRadiusProp,
549
+ cornerSmoothing: cornerSmoothingProp = 1,
550
+ preserveSmoothing: preserveSmoothingProp = false,
551
+ as: Tag = "div",
552
+ g2Continuous = false,
553
+ style,
554
+ ...rest
555
+ } = props;
556
+ const [mounted, setMounted] = (0, import_react.useState)(false);
557
+ const [el, setEl] = (0, import_react.useState)(null);
558
+ const [size, setSize] = (0, import_react.useState)({ width: 0, height: 0 });
559
+ const outerRef = (0, import_react.useRef)(null);
560
+ (0, import_react.useEffect)(() => {
561
+ setMounted(true);
562
+ }, []);
563
+ const parsed = (0, import_react.useMemo)(() => parseSquircleClasses(className), [className]);
564
+ const cornerRadius = cornerRadiusProp ?? parsed.cornerRadius ?? 0;
565
+ const cornerSmoothing = "cornerSmoothing" in props ? cornerSmoothingProp : parsed.cornerSmoothing ?? 1;
566
+ const preserveSmoothing = "preserveSmoothing" in props ? !!preserveSmoothingProp : false;
567
+ const setRef = import_react.default.useCallback((node) => {
568
+ outerRef.current = node;
569
+ setEl(node);
570
+ }, []);
571
+ (0, import_react.useEffect)(() => {
572
+ if (!el) return;
573
+ const update = () => setSize({ width: el.offsetWidth || 0, height: el.offsetHeight || 0 });
574
+ update();
575
+ const ro = new ResizeObserver(update);
576
+ ro.observe(el);
577
+ return () => ro.disconnect();
578
+ }, [el]);
579
+ const clipPath = (0, import_react.useMemo)(() => {
580
+ if (!mounted || !cornerRadius || size.width === 0 || size.height === 0) return "none";
581
+ const pathData = computeSquirclePath(size.width, size.height, cornerRadius, cornerSmoothing, preserveSmoothing, g2Continuous);
582
+ return pathData ? `path('${pathData}')` : "none";
583
+ }, [mounted, size.width, size.height, cornerRadius, cornerSmoothing, preserveSmoothing, g2Continuous]);
584
+ const squircleReady = mounted && cornerRadius > 0 && size.width > 0 && size.height > 0;
585
+ const showSvgBorder = squircleReady && parsed.squircleBorder;
586
+ const squircleStyle = {
587
+ ...style,
588
+ position: "relative",
589
+ opacity: squircleReady ? 1 : 0,
590
+ transition: squircleReady ? "opacity 80ms ease-in" : void 0
591
+ };
592
+ if (squircleReady && cornerRadius) {
593
+ squircleStyle.clipPath = clipPath;
594
+ squircleStyle.WebkitClipPath = clipPath;
595
+ } else if (cornerRadius) {
596
+ squircleStyle.borderRadius = cornerRadius;
597
+ }
598
+ const Component = Tag;
599
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
600
+ Component,
601
+ {
602
+ ref: setRef,
603
+ "data-squircle": cornerRadius || void 0,
604
+ className: parsed.restClasses,
605
+ style: squircleStyle,
606
+ ...rest,
607
+ children: [
608
+ children,
609
+ showSvgBorder && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
610
+ SquircleSvgBorder,
611
+ {
612
+ width: size.width,
613
+ height: size.height,
614
+ cornerRadius,
615
+ cornerSmoothing,
616
+ borderColor: parsed.borderColor || "currentColor",
617
+ borderWidth: parsed.borderWidth,
618
+ g2Continuous
619
+ }
620
+ )
621
+ ]
622
+ }
623
+ );
624
+ }
625
+ function SquircleNoScript() {
626
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("noscript", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
627
+ "style",
628
+ {
629
+ type: "text/css",
630
+ dangerouslySetInnerHTML: {
631
+ __html: "[data-squircle]{clip-path:none!important;border-radius:attr(data-squircle)px!important;-webkit-clip-path:none!important}"
632
+ }
633
+ }
634
+ ) });
635
+ }
636
+ var globalObserverInitialized = false;
637
+ function initGlobalSquircleObserver() {
638
+ if (typeof window === "undefined" || globalObserverInitialized) return;
639
+ globalObserverInitialized = true;
640
+ const resizeObservers = /* @__PURE__ */ new Map();
641
+ const applySquircle = (el) => {
642
+ const className = String(el.className || "");
643
+ const hasSquircleClass = className.split(/\s+/).some((cls) => cls.startsWith("rounded-squircle-"));
644
+ const isVoid = ["INPUT", "IMG", "BR", "HR", "SELECT", "TEXTAREA"].includes(el.tagName);
645
+ if (!hasSquircleClass) {
646
+ if (resizeObservers.has(el)) {
647
+ resizeObservers.get(el)?.disconnect();
648
+ resizeObservers.delete(el);
649
+ el.style.clipPath = "";
650
+ el.style.WebkitClipPath = "";
651
+ el.style.borderRadius = "";
652
+ const svgEl = el.__squircleBorderSvg || el.querySelector("[data-squircle-border]");
653
+ if (svgEl) {
654
+ svgEl.remove();
655
+ }
656
+ }
657
+ return;
658
+ }
659
+ const parsed = parseSquircleClasses(className);
660
+ const cornerRadius = parsed.cornerRadius;
661
+ const cornerSmoothing = parsed.cornerSmoothing;
662
+ const g2Continuous = parsed.g2Continuous;
663
+ if (!cornerRadius) return;
664
+ el.__squircleConfig = parsed;
665
+ if (parsed.squircleBorder) {
666
+ if (isVoid) {
667
+ const parent = el.parentElement;
668
+ if (parent && parent.style.position !== "absolute" && parent.style.position !== "fixed" && parent.style.position !== "relative") {
669
+ parent.style.position = "relative";
670
+ }
671
+ } else if (el.style.position !== "absolute" && el.style.position !== "fixed" && el.style.position !== "relative") {
672
+ el.style.position = "relative";
673
+ }
674
+ }
675
+ if (resizeObservers.has(el)) {
676
+ const updateFn = el.__squircleUpdate;
677
+ if (updateFn) {
678
+ updateFn();
679
+ }
680
+ return;
681
+ }
682
+ if (!resizeObservers.has(el)) {
683
+ const updateSize = () => {
684
+ const config = el.__squircleConfig || parsed;
685
+ const width = el.offsetWidth || 0;
686
+ const height = el.offsetHeight || 0;
687
+ if (width === 0 || height === 0) return;
688
+ const pathData = computeSquirclePath(width, height, config.cornerRadius || 0, config.cornerSmoothing, false, config.g2Continuous);
689
+ const clipPath = pathData ? `path('${pathData}')` : "none";
690
+ el.style.clipPath = clipPath;
691
+ el.style.WebkitClipPath = clipPath;
692
+ el.style.borderRadius = "0px";
693
+ if (config.squircleBorder) {
694
+ let svgEl = el.__squircleBorderSvg;
695
+ if (!svgEl && isVoid && el.nextElementSibling?.getAttribute("data-squircle-border") === "true") {
696
+ svgEl = el.nextElementSibling;
697
+ el.__squircleBorderSvg = svgEl;
698
+ }
699
+ if (!svgEl) {
700
+ svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
701
+ svgEl.setAttribute("data-squircle-border", "true");
702
+ el.__squircleBorderSvg = svgEl;
703
+ if (isVoid) {
704
+ el.after(svgEl);
705
+ } else {
706
+ el.appendChild(svgEl);
707
+ }
708
+ }
709
+ const bw = config.borderWidth;
710
+ const inset = bw / 2;
711
+ const innerW = Math.max(1, width - inset * 2);
712
+ const innerH = Math.max(1, height - inset * 2);
713
+ const innerR = Math.max(0, (config.cornerRadius || 0) - inset);
714
+ const borderPathData = computeSquirclePath(innerW, innerH, innerR, config.cornerSmoothing, false, config.g2Continuous);
715
+ svgEl.setAttribute("width", String(width));
716
+ svgEl.setAttribute("height", String(height));
717
+ svgEl.setAttribute("viewBox", `0 0 ${width} ${height}`);
718
+ svgEl.setAttribute("aria-hidden", "true");
719
+ const posStyle = {
720
+ position: "absolute",
721
+ pointerEvents: "none",
722
+ overflow: "visible"
723
+ };
724
+ if (isVoid) {
725
+ posStyle.top = `${el.offsetTop}px`;
726
+ posStyle.left = `${el.offsetLeft}px`;
727
+ } else {
728
+ posStyle.top = `0px`;
729
+ posStyle.left = `0px`;
730
+ }
731
+ Object.assign(svgEl.style, posStyle);
732
+ let gEl = svgEl.querySelector("g");
733
+ if (!gEl) {
734
+ gEl = document.createElementNS("http://www.w3.org/2000/svg", "g");
735
+ svgEl.appendChild(gEl);
736
+ }
737
+ gEl.setAttribute("transform", `translate(${inset}, ${inset})`);
738
+ let pathEl = svgEl.querySelector("path");
739
+ if (!pathEl) {
740
+ pathEl = document.createElementNS("http://www.w3.org/2000/svg", "path");
741
+ gEl.appendChild(pathEl);
742
+ }
743
+ pathEl.setAttribute("d", borderPathData || "");
744
+ pathEl.setAttribute("fill", "none");
745
+ pathEl.setAttribute("stroke", config.borderColor || "currentColor");
746
+ pathEl.setAttribute("stroke-width", String(bw));
747
+ pathEl.setAttribute("stroke-linejoin", "round");
748
+ } else {
749
+ const svgEl = el.__squircleBorderSvg || el.querySelector("[data-squircle-border]");
750
+ if (svgEl) {
751
+ svgEl.remove();
752
+ el.__squircleBorderSvg = null;
753
+ }
754
+ }
755
+ };
756
+ el.__squircleUpdate = updateSize;
757
+ updateSize();
758
+ const ro = new ResizeObserver(updateSize);
759
+ ro.observe(el);
760
+ resizeObservers.set(el, ro);
761
+ }
762
+ };
763
+ const scan = () => {
764
+ const elements = document.querySelectorAll('[class*="rounded-squircle-"]');
765
+ elements.forEach((el) => applySquircle(el));
766
+ };
767
+ if (document.readyState === "loading") {
768
+ document.addEventListener("DOMContentLoaded", () => {
769
+ requestAnimationFrame(scan);
770
+ });
771
+ } else {
772
+ requestAnimationFrame(scan);
773
+ }
774
+ const mutationObserver = new MutationObserver((mutations) => {
775
+ for (const mutation of mutations) {
776
+ if (mutation.type === "childList") {
777
+ mutation.addedNodes.forEach((node) => {
778
+ if (node.nodeType === Node.ELEMENT_NODE) {
779
+ const el = node;
780
+ if (el.className && String(el.className).split(/\s+/).some((c) => c.startsWith("rounded-squircle-"))) {
781
+ applySquircle(el);
782
+ }
783
+ el.querySelectorAll('[class*="rounded-squircle-"]').forEach((child) => {
784
+ applySquircle(child);
785
+ });
786
+ }
787
+ });
788
+ } else if (mutation.type === "attributes" && mutation.attributeName === "class") {
789
+ applySquircle(mutation.target);
790
+ }
791
+ }
792
+ });
793
+ mutationObserver.observe(document.body, {
794
+ childList: true,
795
+ subtree: true,
796
+ attributes: true,
797
+ attributeFilter: ["class"]
798
+ });
799
+ }
800
+ if (typeof window !== "undefined") {
801
+ initGlobalSquircleObserver();
802
+ }
803
+ var react_default = Squircle;
804
+ // Annotate the CommonJS export names for ESM import in node:
805
+ 0 && (module.exports = {
806
+ Squircle,
807
+ SquircleNoScript,
808
+ initGlobalSquircleObserver
809
+ });