From 128a97a3876bf4c11a7c4dc29a82885d55c26b21 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Sun, 3 May 2026 13:35:18 -0700 Subject: [PATCH 01/15] feat: add Panda CSS preset (#27) Ships a definePreset-style export at @klinking/squircle/panda-preset covering the full 15-utility radius matrix. Property names follow Panda's own border-radius convention (e.g. `squircleTopLeftRadius` mirrors `borderTopLeftRadius`, with the shorthand `squircleTopLeft` mirroring `roundedTopLeft`). Radius utilities resolve through the consumer's `radii` theme tokens; `squircleAmount` accepts numeric values. A `_squircleSupported` condition is registered for one-off overrides, and `amtVar`/`rVar` options match the Tailwind plugin. Refactors the shared math into `squircleCssObj()` in variants.ts, which the Tailwind plugin and the static-CSS generator now both consume. Tailwind output is byte-identical (existing snapshots unchanged). Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 139 +- package/package.json | 11 + package/scripts/generate-squircle-css.ts | 54 +- package/src/panda-preset.test.ts | 149 ++ package/src/panda-preset.ts | 101 ++ package/src/tw-plugin.ts | 78 +- package/src/variants.ts | 167 ++ package/vite.config.ts | 6 +- pnpm-lock.yaml | 1887 ++++++++++++++++++++++ 9 files changed, 2423 insertions(+), 169 deletions(-) create mode 100644 package/src/panda-preset.test.ts create mode 100644 package/src/panda-preset.ts diff --git a/README.md b/README.md index cb436ca..d2eff1a 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no ## Contents - - [Requirements](#requirements) - [Install & setup](#install--setup) - [Utilities](#utilities) @@ -43,7 +42,7 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no npm install @klinking/squircle ``` -Then pick one of two integration paths. But don't pick wrong, else the Integration Ogre might… oh wait, no, just pick the one that suits your needs, they're essentially the same, but one allows more customization, in case my vars and classes conflict with ur existing vars and classes. +Then pick the integration path that fits your project. Tailwind is the original target (paths A and B). Path C is the [Panda CSS](https://panda-css.com/) preset, which produces the exact same `@supports`-gated visual correction wired through Panda's utility pipeline. ### Path A: CSS import (recommended) @@ -88,6 +87,58 @@ const twMerge = extendTailwindMerge(squircleMergeConfig, { }); ``` +### Path C: Panda CSS preset + +For [Panda CSS](https://panda-css.com/) projects, register the preset in `panda.config.ts`: + +```ts +import { defineConfig } from "@pandacss/dev"; +import squirclePreset from "@klinking/squircle/panda-preset"; + +export default defineConfig({ + presets: ["@pandacss/dev/presets", squirclePreset()], + // ... +}); +``` + +Then use the utilities anywhere `css(...)` accepts properties: + +```tsx +
+
+``` + +The naming follows Panda's own border-radius convention exactly — substitute `border` ↔ `squircle` and `rounded` ↔ `squircle` (the shorthand) and the table is identical to Panda's: + +| Full property name | Shorthand | CSS targets | +| ------------------------------- | ---------------------- | ---------------------------------------- | +| `squircleRadius` | `squircle` | `border-radius` (all four corners) | +| `squircleTopRadius` | `squircleTop` | top corners | +| `squircleRightRadius` | `squircleRight` | right corners | +| `squircleBottomRadius` | `squircleBottom` | bottom corners | +| `squircleLeftRadius` | `squircleLeft` | left corners | +| `squircleStartRadius` | `squircleStart` | inline-start corners (logical) | +| `squircleEndRadius` | `squircleEnd` | inline-end corners (logical) | +| `squircleTopLeftRadius` | `squircleTopLeft` | top-left corner | +| `squircleTopRightRadius` | `squircleTopRight` | top-right corner | +| `squircleBottomRightRadius` | `squircleBottomRight` | bottom-right corner | +| `squircleBottomLeftRadius` | `squircleBottomLeft` | bottom-left corner | +| `squircleStartStartRadius` | `squircleStartStart` | start-start corner (logical) | +| `squircleStartEndRadius` | `squircleStartEnd` | start-end corner (logical) | +| `squircleEndStartRadius` | `squircleEndStart` | end-start corner (logical) | +| `squircleEndEndRadius` | `squircleEndEnd` | end-end corner (logical) | +| `squircleAmount` | `squircleAmt` | superellipse exponent (default 2) | + +All radius utilities resolve through your `radii` theme tokens, so `squircle: "md"` reads the same `--radii-md` your `borderRadius: "md"` does. The preset also registers a `_squircleSupported` condition (`@supports (corner-shape: superellipse(2))`) for one-off overrides. + +The preset accepts the same `amtVar` / `rVar` options as the Tailwind plugin if you need to rename the underlying CSS variables: + +```ts +squirclePreset({ amtVar: "--my-amt", rVar: "--my-r" }); +``` + +Panda is usage-driven — utilities only appear in the output for properties found in scanned source. If you want every variant emitted unconditionally, opt in via Panda's [`staticCss`](https://panda-css.com/docs/guides/static-css). + ## Utilities | Utility | Equivalent | Description | @@ -355,7 +406,6 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tw-utils.css — the Tailwind utilities - ```css /* ── Squircle utilities ─────────────────────────────────────── */ /* squircle-amt-[n] sets the superellipse amount (default 2) */ @@ -515,7 +565,6 @@ If you'd rather not add a dependency, copy the source directly. Click to expand } } ``` - @@ -524,90 +573,26 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tw-plugin.mjs — the JS plugin - -````js +```js +import { c as variantEntries, i as SUPPORTS_RULE, s as squircleCssObj } from "./variants-vQRRK8yy.mjs"; import plugin from "tailwindcss/plugin"; -const DEFAULT_AMOUNT_VAR_NAME = "--squircle-amt"; -const DEFAULT_AMT_CSS = `var(${DEFAULT_AMOUNT_VAR_NAME}, 2)`; -const getCornerShape = (varName = DEFAULT_AMOUNT_VAR_NAME) => `superellipse(var(${varName}, 2))`; -function correctedRadius(radius, amt = DEFAULT_AMT_CSS) { - return `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt}))))`; -} -function isComment(entry) { - return !Array.isArray(entry); -} -const SUPPORTS_RULE = "@supports (corner-shape: superellipse(2))"; -const VARIANTS = { - "": ["border-radius"], - "$comment-physical-sides": { comment: "/* --- Per-side physical variants --- */" }, - t: ["border-top-left-radius", "border-top-right-radius"], - r: ["border-top-right-radius", "border-bottom-right-radius"], - b: ["border-bottom-left-radius", "border-bottom-right-radius"], - l: ["border-top-left-radius", "border-bottom-left-radius"], - "$comment-logical-sides": { comment: "/* --- Per-side logical variants --- */" }, - s: ["border-start-start-radius", "border-end-start-radius"], - e: ["border-start-end-radius", "border-end-end-radius"], - "$comment-physical-corners": { comment: "/* --- Per-corner physical variants --- */" }, - tl: ["border-top-left-radius"], - tr: ["border-top-right-radius"], - br: ["border-bottom-right-radius"], - bl: ["border-bottom-left-radius"], - "$comment-logical-corners": { comment: "/* --- Per-corner logical variants --- */" }, - ss: ["border-start-start-radius"], - se: ["border-start-end-radius"], - es: ["border-end-start-radius"], - ee: ["border-end-end-radius"] -}; -function variantEntries() { - return Object.entries(VARIANTS).filter((entry) => !isComment(entry[1])); -} -function usesIntermediateVar(suffix) { - const entry = VARIANTS[suffix]; - if (!entry || isComment(entry)) return false; - return suffix === "" || entry.length > 1; -} -//#endregion //#region src/tw-plugin.ts const squircle = plugin.withOptions((options = {}) => ({ matchUtilities, theme }) => { const amtVar = options.amtVar ?? options["amt-var"] ?? "--squircle-amt"; const rVar = options.rVar ?? options["r-var"] ?? "--squircle-r"; const prefix = options.prefix ?? "squircle"; const radiusValues = theme("borderRadius"); - const amtCss = `var(${amtVar}, 2)`; - const rCss = `var(${rVar})`; - const cornerShape = getCornerShape(amtVar); matchUtilities({ [`${prefix}-amt`]: (value) => ({ [amtVar]: value, [SUPPORTS_RULE]: { "corner-shape": `superellipse(var(${amtVar}))` } }) }, { type: "number" }); - for (const [suffix, props] of variantEntries()) { - const name = suffix ? `${prefix}-${suffix}` : prefix; - if (usesIntermediateVar(suffix)) matchUtilities({ [name]: (value) => ({ - ...Object.fromEntries(props.map((p) => [p, value])), - [SUPPORTS_RULE]: { - [rVar]: correctedRadius(value, amtCss), - ...Object.fromEntries(props.map((p) => [p, rCss])), - "corner-shape": cornerShape - } - }) }, { - type: "length", - values: radiusValues - }); - else { - const prop = props[0]; - matchUtilities({ [name]: (value) => { - const result = { [prop]: value }; - result[SUPPORTS_RULE] = { - [prop]: correctedRadius(value, amtCss), - "corner-shape": cornerShape - }; - return result; - } }, { - type: "length", - values: radiusValues - }); - } - } + for (const [suffix, props] of variantEntries()) matchUtilities({ [suffix ? `${prefix}-${suffix}` : prefix]: (value) => squircleCssObj(props, value, { + amtVar, + rVar + }) }, { + type: "length", + values: radiusValues + }); }); //#endregion export { squircle as default }; diff --git a/package/package.json b/package/package.json index a2bb4bb..15e57ba 100644 --- a/package/package.json +++ b/package/package.json @@ -30,6 +30,10 @@ "./tw-plugin": { "types": "./dist/tw-plugin.d.mts", "import": "./dist/tw-plugin.mjs" + }, + "./panda-preset": { + "types": "./dist/panda-preset.d.mts", + "import": "./dist/panda-preset.mjs" } }, "scripts": { @@ -46,12 +50,19 @@ "vitest": "npm:@voidzero-dev/vite-plus-test@^0.1.15" }, "peerDependencies": { + "@pandacss/dev": ">=0.40.0", "tailwind-merge": ">=2.0.0", "tailwindcss": ">=4.0.0" }, "peerDependenciesMeta": { + "@pandacss/dev": { + "optional": true + }, "tailwind-merge": { "optional": true + }, + "tailwindcss": { + "optional": true } }, "packageManager": "pnpm@10.33.0" diff --git a/package/scripts/generate-squircle-css.ts b/package/scripts/generate-squircle-css.ts index 5673d1b..a4dbf56 100644 --- a/package/scripts/generate-squircle-css.ts +++ b/package/scripts/generate-squircle-css.ts @@ -1,46 +1,31 @@ import { copyFileSync, mkdirSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; -import { - getCornerShape, - DEFAULT_AMT, - VARIANTS, - correctedRadius, - isComment, - usesIntermediateVar, - SUPPORTS_RULE, -} from "../src/variants"; +import { DEFAULT_AMT, SUPPORTS_RULE, VARIANTS, isComment, squircleCssObj } from "../src/variants"; const __dirname = dirname(fileURLToPath(import.meta.url)); // Support arbitrary, bare, and theme values in one --value() call. // https://tailwindcss.com/docs/adding-custom-styles#functional-utilities const value = "--value(--radius-*, [length])"; -const formula = correctedRadius(value); -function multiPropUtility(name: string, props: string[]) { - const fallbacks = props.map((p) => ` ${p}: ${value};`).join("\n"); - const corrected = props.map((p) => ` ${p}: var(--squircle-r);`).join("\n"); - return `\ -@utility ${name} { -${fallbacks} - ${SUPPORTS_RULE} { - --squircle-r: ${formula}; -${corrected} - corner-shape: ${getCornerShape()}; - } -}`; -} +function renderUtility(name: string, props: string[]): string { + const obj = squircleCssObj(props, value); + const lines: string[] = [`@utility ${name} {`]; -function singlePropUtility(name: string, prop: string) { - return `\ -@utility ${name} { - ${prop}: ${value}; - ${SUPPORTS_RULE} { - ${prop}: ${formula}; - corner-shape: ${getCornerShape()}; + for (const [key, val] of Object.entries(obj)) { + if (key === SUPPORTS_RULE && typeof val === "object" && val !== null) { + lines.push(` ${SUPPORTS_RULE} {`); + for (const [innerKey, innerVal] of Object.entries(val)) { + lines.push(` ${innerKey}: ${innerVal as string};`); + } + lines.push(` }`); + } else { + lines.push(` ${key}: ${val as string};`); + } } -}`; + lines.push(`}`); + return lines.join("\n"); } function generateCss(): string { @@ -65,12 +50,7 @@ function generateCss(): string { } const name = suffix ? `squircle-${suffix}-*` : "squircle-*"; - - if (usesIntermediateVar(suffix)) { - blocks.push(multiPropUtility(name, entry)); - } else { - blocks.push(singlePropUtility(name, entry[0]!)); - } + blocks.push(renderUtility(name, entry)); } return blocks.join("\n\n") + "\n"; diff --git a/package/src/panda-preset.test.ts b/package/src/panda-preset.test.ts new file mode 100644 index 0000000..0bb9b69 --- /dev/null +++ b/package/src/panda-preset.test.ts @@ -0,0 +1,149 @@ +import { describe, expect, it } from "vitest"; +import squirclePandaPreset from "./panda-preset"; +import { CAMEL_VARIANTS } from "./variants"; + +describe("panda preset shape", () => { + const preset = squirclePandaPreset(); + + it("has the canonical name", () => { + expect(preset.name).toBe("@klinking/squircle"); + }); + + it("registers the squircleSupported condition", () => { + expect(preset.conditions.extend["squircleSupported"]).toBe( + "@supports (corner-shape: superellipse(2))", + ); + }); + + it("registers a utility for every CAMEL_VARIANTS entry plus squircleAmount", () => { + const keys = Object.keys(preset.utilities.extend).sort(); + const expected = [ + ...CAMEL_VARIANTS.map((v) => v.property), + "squircleAmount", + ].sort(); + expect(keys).toEqual(expected); + }); + + it("uses Panda's built-in `radii` token category for radius utilities", () => { + for (const variant of CAMEL_VARIANTS) { + const u = preset.utilities.extend[variant.property]; + if (!u) throw new Error(`missing utility for ${variant.property}`); + expect(u.values).toBe("radii"); + expect(u.shorthand).toBe(variant.shorthand); + } + }); + + it("squircleAmount accepts numeric values via shorthand squircleAmt", () => { + const u = preset.utilities.extend["squircleAmount"]!; + expect(u.shorthand).toBe("squircleAmt"); + expect(u.values).toEqual({ type: "number" }); + }); +}); + +describe("panda preset transform output", () => { + const preset = squirclePandaPreset(); + const radiusToken = "var(--radii-md)"; // Panda passes the resolved CSS variable string + + it("squircleRadius (all corners) emits camelCase keys with @supports block", () => { + const out = preset.utilities.extend["squircleRadius"]!.transform!(radiusToken, { + token: () => radiusToken, + raw: "md", + }); + expect(out).toMatchInlineSnapshot(` + { + "@supports (corner-shape: superellipse(2))": { + "--squircle-r": "calc(var(--radii-md) * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * var(--squircle-amt, 2)))))", + "borderRadius": "var(--squircle-r)", + "cornerShape": "superellipse(var(--squircle-amt, 2))", + }, + "borderRadius": "var(--radii-md)", + } + `); + }); + + it("squircleTopLeftRadius (single corner) inlines calc without --squircle-r", () => { + const out = preset.utilities.extend["squircleTopLeftRadius"]!.transform!(radiusToken, { + token: () => radiusToken, + raw: "md", + }); + expect(out).toMatchInlineSnapshot(` + { + "@supports (corner-shape: superellipse(2))": { + "borderTopLeftRadius": "calc(var(--radii-md) * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * var(--squircle-amt, 2)))))", + "cornerShape": "superellipse(var(--squircle-amt, 2))", + }, + "borderTopLeftRadius": "var(--radii-md)", + } + `); + }); + + it("squircleTopRadius (multi-prop side) shares --squircle-r across both corners", () => { + const out = preset.utilities.extend["squircleTopRadius"]!.transform!(radiusToken, { + token: () => radiusToken, + raw: "md", + }); + expect(out).toMatchInlineSnapshot(` + { + "@supports (corner-shape: superellipse(2))": { + "--squircle-r": "calc(var(--radii-md) * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * var(--squircle-amt, 2)))))", + "borderTopLeftRadius": "var(--squircle-r)", + "borderTopRightRadius": "var(--squircle-r)", + "cornerShape": "superellipse(var(--squircle-amt, 2))", + }, + "borderTopLeftRadius": "var(--radii-md)", + "borderTopRightRadius": "var(--radii-md)", + } + `); + }); + + it("squircleAmount sets the variable and gates corner-shape", () => { + const out = preset.utilities.extend["squircleAmount"]!.transform!("3", { + token: () => "3", + raw: "3", + }); + expect(out).toMatchInlineSnapshot(` + { + "--squircle-amt": "3", + "@supports (corner-shape: superellipse(2))": { + "cornerShape": "superellipse(var(--squircle-amt))", + }, + } + `); + }); +}); + +describe("panda preset options", () => { + it("custom amtVar threads through every transform", () => { + const preset = squirclePandaPreset({ amtVar: "--my-amt" }); + const out = preset.utilities.extend["squircleRadius"]!.transform!("1rem", { + token: () => "1rem", + raw: "1rem", + }) as Record; + const supports = out["@supports (corner-shape: superellipse(2))"] as Record< + string, + string + >; + expect(supports["cornerShape"]).toBe("superellipse(var(--my-amt, 2))"); + + const amtOut = preset.utilities.extend["squircleAmount"]!.transform!("3", { + token: () => "3", + raw: "3", + }) as Record; + expect(amtOut["--my-amt"]).toBe("3"); + }); + + it("custom rVar threads through multi-prop side transforms", () => { + const preset = squirclePandaPreset({ rVar: "--my-r" }); + const out = preset.utilities.extend["squircleTopRadius"]!.transform!("1rem", { + token: () => "1rem", + raw: "1rem", + }) as Record; + const supports = out["@supports (corner-shape: superellipse(2))"] as Record< + string, + string + >; + expect(supports["--my-r"]).toContain("calc(1rem"); + expect(supports["borderTopLeftRadius"]).toBe("var(--my-r)"); + expect(supports["borderTopRightRadius"]).toBe("var(--my-r)"); + }); +}); diff --git a/package/src/panda-preset.ts b/package/src/panda-preset.ts new file mode 100644 index 0000000..73b29d0 --- /dev/null +++ b/package/src/panda-preset.ts @@ -0,0 +1,101 @@ +import { + CAMEL_VARIANTS, + DEFAULT_AMOUNT_VAR_NAME, + SUPPORTS_RULE, + squircleCssObj, + variantEntries, +} from "./variants"; + +/** + * Panda CSS utility entry shape (subset). We do not depend on `@pandacss/dev` + * at runtime — the preset is a plain object literal and the consumer's Panda + * install loads it. Typing the public surface manually keeps `@pandacss/dev` + * an *optional* peer dependency and avoids versioning entanglement. + */ +type PandaUtility = { + shorthand?: string | string[]; + values?: string | string[] | Record | { type: string }; + transform?: ( + value: string, + helpers: { token: (path: string) => string; raw: string }, + ) => Record; +}; + +export interface SquirclePandaPresetOptions { + /** CSS custom property name for the superellipse amount (default: "--squircle-amt"). */ + amtVar?: string; + /** CSS custom property name for the intermediate corrected radius (default: "--squircle-r"). */ + rVar?: string; +} + +export interface SquirclePandaPreset { + name: string; + utilities: { extend: Record }; + conditions: { extend: Record }; +} + +/** + * Build the Panda preset object. Pass directly to `presets:` in `panda.config.ts`: + * + * ```ts + * import { defineConfig } from '@pandacss/dev' + * import squirclePreset from '@klinking/squircle/panda-preset' + * + * export default defineConfig({ + * presets: ['@pandacss/dev/presets', squirclePreset()], + * }) + * ``` + * + * Naming follows Panda's own border-radius convention: full property names like + * `squircleTopLeftRadius` mirror `borderTopLeftRadius`, and shorthands like + * `squircleTopLeft` mirror `roundedTopLeft`. The shape table is identical to + * Panda's built-in radius utilities. + */ +export function squirclePandaPreset( + options: SquirclePandaPresetOptions = {}, +): SquirclePandaPreset { + const amtVar = options.amtVar ?? DEFAULT_AMOUNT_VAR_NAME; + const rVar = options.rVar ?? "--squircle-r"; + + const utilities: Record = {}; + + const variantBySuffix = new Map(variantEntries()); + + for (const variant of CAMEL_VARIANTS) { + const props = variantBySuffix.get(variant.suffix); + if (!props) continue; + + utilities[variant.property] = { + shorthand: variant.shorthand, + values: "radii", + transform: (value: string) => + squircleCssObj(props, value, { amtVar, rVar, case: "camel" }) as Record< + string, + unknown + >, + }; + } + + utilities["squircleAmount"] = { + shorthand: "squircleAmt", + values: { type: "number" }, + transform: (value: string) => ({ + [amtVar]: value, + [SUPPORTS_RULE]: { + cornerShape: `superellipse(var(${amtVar}))`, + }, + }), + }; + + return { + name: "@klinking/squircle", + utilities: { extend: utilities }, + conditions: { + extend: { + squircleSupported: SUPPORTS_RULE, + }, + }, + }; +} + +export default squirclePandaPreset; diff --git a/package/src/tw-plugin.ts b/package/src/tw-plugin.ts index 6e68e2b..5940065 100644 --- a/package/src/tw-plugin.ts +++ b/package/src/tw-plugin.ts @@ -1,12 +1,9 @@ import plugin from "tailwindcss/plugin"; import { - DEFAULT_AMT, DEFAULT_AMOUNT_VAR_NAME, DEFAULT_R_VAR_NAME, SUPPORTS_RULE, - correctedRadius, - getCornerShape, - usesIntermediateVar, + squircleCssObj, variantEntries, } from "./variants"; @@ -27,63 +24,36 @@ const squircle: ReturnType> = plugin.withOptions((options = {}) => // eslint-disable-next-line @typescript-eslint/unbound-method ({ matchUtilities, theme }) => { - const amtVar = options.amtVar ?? options["amt-var"] ?? DEFAULT_AMOUNT_VAR_NAME; - const rVar = options.rVar ?? options["r-var"] ?? DEFAULT_R_VAR_NAME; - const prefix = options.prefix ?? "squircle"; - const radiusValues = theme("borderRadius"); + const amtVar = options.amtVar ?? options["amt-var"] ?? DEFAULT_AMOUNT_VAR_NAME; + const rVar = options.rVar ?? options["r-var"] ?? DEFAULT_R_VAR_NAME; + const prefix = options.prefix ?? "squircle"; + const radiusValues = theme("borderRadius"); - const amtCss = `var(${amtVar}, ${DEFAULT_AMT})`; - const rCss = `var(${rVar})`; - const cornerShape = getCornerShape(amtVar); - - matchUtilities( - { - [`${prefix}-amt`]: (value: string) => ({ - [amtVar]: value, - [SUPPORTS_RULE]: { - "corner-shape": `superellipse(var(${amtVar}))`, - }, - }), - }, - { type: "number" }, - ); - - for (const [suffix, props] of variantEntries()) { - const name = suffix ? `${prefix}-${suffix}` : prefix; + matchUtilities( + { + [`${prefix}-amt`]: (value: string) => ({ + [amtVar]: value, + [SUPPORTS_RULE]: { + "corner-shape": `superellipse(var(${amtVar}))`, + }, + }), + }, + { type: "number" }, + ); - if (usesIntermediateVar(suffix)) { - matchUtilities( - { - [name]: (value: string) => ({ - ...Object.fromEntries(props.map((p) => [p, value])), - [SUPPORTS_RULE]: { - [rVar]: correctedRadius(value, amtCss), - ...Object.fromEntries(props.map((p) => [p, rCss])), - "corner-shape": cornerShape, - }, - }), - }, - { type: "length", values: radiusValues }, - ); - } else { - const prop = props[0]!; + for (const [suffix, props] of variantEntries()) { + const name = suffix ? `${prefix}-${suffix}` : prefix; matchUtilities( { - [name]: (value: string) => { - const result: Record> = { - [prop]: value, - }; - result[SUPPORTS_RULE] = { - [prop]: correctedRadius(value, amtCss), - "corner-shape": cornerShape, - }; - return result; - }, + [name]: (value: string) => + squircleCssObj(props, value, { amtVar, rVar }) as Record< + string, + string | Record + >, }, { type: "length", values: radiusValues }, ); } - } - }); + }); export default squircle; diff --git a/package/src/variants.ts b/package/src/variants.ts index 8817e69..9f2ea0a 100644 --- a/package/src/variants.ts +++ b/package/src/variants.ts @@ -54,5 +54,172 @@ export function usesIntermediateVar(suffix: string): boolean { return suffix === "" || entry.length > 1; } +/** + * Property-name table used by the Panda preset and StyleX module. + * Each entry maps a Tailwind variant suffix to the camelCase utility name and + * Panda-style shorthand. The descriptive label is used in generated docs and + * snapshot tests. Order matches `VARIANTS`. + */ +export type CamelVariant = { + /** Suffix from `VARIANTS` ("" for all-corners). */ + suffix: string; + /** Full camelCase property name, e.g. "squircleTopLeftRadius". */ + property: string; + /** Short alias following Panda's `rounded*` shorthand convention. */ + shorthand: string; + /** Side/corner direction key (passed to a side-aware factory). */ + side: + | "all" + | "top" + | "right" + | "bottom" + | "left" + | "start" + | "end" + | "topLeft" + | "topRight" + | "bottomRight" + | "bottomLeft" + | "startStart" + | "startEnd" + | "endStart" + | "endEnd"; +}; + +export const CAMEL_VARIANTS: readonly CamelVariant[] = [ + { suffix: "", property: "squircleRadius", shorthand: "squircle", side: "all" }, + { suffix: "t", property: "squircleTopRadius", shorthand: "squircleTop", side: "top" }, + { suffix: "r", property: "squircleRightRadius", shorthand: "squircleRight", side: "right" }, + { suffix: "b", property: "squircleBottomRadius", shorthand: "squircleBottom", side: "bottom" }, + { suffix: "l", property: "squircleLeftRadius", shorthand: "squircleLeft", side: "left" }, + { suffix: "s", property: "squircleStartRadius", shorthand: "squircleStart", side: "start" }, + { suffix: "e", property: "squircleEndRadius", shorthand: "squircleEnd", side: "end" }, + { + suffix: "tl", + property: "squircleTopLeftRadius", + shorthand: "squircleTopLeft", + side: "topLeft", + }, + { + suffix: "tr", + property: "squircleTopRightRadius", + shorthand: "squircleTopRight", + side: "topRight", + }, + { + suffix: "br", + property: "squircleBottomRightRadius", + shorthand: "squircleBottomRight", + side: "bottomRight", + }, + { + suffix: "bl", + property: "squircleBottomLeftRadius", + shorthand: "squircleBottomLeft", + side: "bottomLeft", + }, + { + suffix: "ss", + property: "squircleStartStartRadius", + shorthand: "squircleStartStart", + side: "startStart", + }, + { + suffix: "se", + property: "squircleStartEndRadius", + shorthand: "squircleStartEnd", + side: "startEnd", + }, + { + suffix: "es", + property: "squircleEndStartRadius", + shorthand: "squircleEndStart", + side: "endStart", + }, + { + suffix: "ee", + property: "squircleEndEndRadius", + shorthand: "squircleEndEnd", + side: "endEnd", + }, +]; + +const KEBAB_TO_CAMEL_CACHE = new Map(); +function toCamel(kebab: string): string { + const cached = KEBAB_TO_CAMEL_CACHE.get(kebab); + if (cached) return cached; + const camel = kebab.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()); + KEBAB_TO_CAMEL_CACHE.set(kebab, camel); + return camel; +} + +export type CssLikeObject = Record>; + +export interface SquircleCssObjOptions { + /** Override the `--squircle-amt` variable name (default `--squircle-amt`). */ + amtVar?: string; + /** Override the intermediate corrected-radius variable name (default `--squircle-r`). */ + rVar?: string; + /** + * Output property name case. `kebab` (default) emits `border-radius`-style keys + * for Tailwind plugins and raw CSS. `camel` emits `borderRadius`-style keys + * for Panda/StyleX/CSS-in-JS callers. + */ + case?: "kebab" | "camel"; + /** + * When false, never emit the `--squircle-r` intermediate variable: the corrected + * `calc(...)` is inlined into each property. Defaults to the same heuristic + * Tailwind uses (true for all-corners and multi-prop sides, false for single + * corners). Pass `false` for callers that prefer flat output (StyleX cannot + * read a custom property set in the same rule it's used in without a separate + * declaration cycle, so the inlined form is more portable). + */ + useIntermediateVar?: boolean; +} + +/** + * Build the framework-agnostic CSS-in-JS object for one squircle utility. + * Returns the same shape Tailwind's `matchUtilities` consumes, with an + * `@supports` block that gates the corrected radius behind `corner-shape` + * support. Used by the Tailwind plugin, the static-CSS generator, the Panda + * preset, and the StyleX helpers. + */ +export function squircleCssObj( + props: string[], + radius: string, + options: SquircleCssObjOptions = {}, +): CssLikeObject { + const amtVar = options.amtVar ?? DEFAULT_AMOUNT_VAR_NAME; + const rVar = options.rVar ?? DEFAULT_R_VAR_NAME; + const keyCase = options.case ?? "kebab"; + const useIntermediate = + options.useIntermediateVar ?? (props.length > 1 || props[0] === "border-radius"); + + const amtCss = `var(${amtVar}, ${DEFAULT_AMT})`; + const rCss = `var(${rVar})`; + const cornerShape = getCornerShape(amtVar); + const corrected = correctedRadius(radius, amtCss); + + const cornerShapeKey = keyCase === "camel" ? "cornerShape" : "corner-shape"; + const propKey = (p: string) => (keyCase === "camel" ? toCamel(p) : p); + + const fallback: Record = {}; + for (const p of props) fallback[propKey(p)] = radius; + + const supportsBlock: Record = {}; + if (useIntermediate) { + supportsBlock[rVar] = corrected; + for (const p of props) supportsBlock[propKey(p)] = rCss; + } else { + for (const p of props) supportsBlock[propKey(p)] = corrected; + } + supportsBlock[cornerShapeKey] = cornerShape; + + return { + ...fallback, + [SUPPORTS_RULE]: supportsBlock, + }; +} + export { isComment }; export type { SectionComment, VariantEntry }; diff --git a/package/vite.config.ts b/package/vite.config.ts index 5d90ba5..454faaa 100644 --- a/package/vite.config.ts +++ b/package/vite.config.ts @@ -10,6 +10,7 @@ export default defineConfig({ entry: { "tw-plugin": "./src/tw-plugin.ts", "tw-merge-cfg": "./src/tw-merge-cfg.ts", + "panda-preset": "./src/panda-preset.ts", }, format: "esm", dts: true, @@ -27,9 +28,12 @@ export default defineConfig({ command: "vp test run squircle-radius", dependsOn: ["build"], }, + "test:panda": { + command: "vp test run panda-preset", + }, test: { command: "echo 'All tests passed'", - dependsOn: ["test:plugin", "test:css", "test:radius"], + dependsOn: ["test:plugin", "test:css", "test:radius", "test:panda"], }, build: { command: "vp pack && tsx scripts/generate-squircle-css.ts", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0b77fd..386df3f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,6 +66,9 @@ importers: package: dependencies: + '@pandacss/dev': + specifier: '>=0.40.0' + version: 1.11.0(typescript@6.0.2) tailwind-merge: specifier: '>=2.0.0' version: 3.5.0 @@ -282,10 +285,28 @@ packages: resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} engines: {node: '>=18'} + '@clack/core@0.5.0': + resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + + '@clack/prompts@0.11.0': + resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} + '@csstools/postcss-cascade-layers@5.0.2': + resolution: {integrity: sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + '@emnapi/core@1.9.2': resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} @@ -295,156 +316,312 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.27.7': resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.27.7': resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.27.7': resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.27.7': resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.27.7': resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.27.7': resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.27.7': resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.27.7': resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.27.7': resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.27.7': resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.27.7': resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.27.7': resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.27.7': resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.27.7': resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.27.7': resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.27.7': resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.27.7': resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.27.7': resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.27.7': resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.27.7': resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.27.7': resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/openharmony-arm64@0.27.7': resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.27.7': resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.27.7': resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.27.7': resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.27.7': resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} @@ -455,6 +632,12 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -659,12 +842,34 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/wasm-runtime@1.1.2': resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + '@octokit/auth-token@6.0.0': resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} engines: {node: '>= 20'} @@ -1009,6 +1214,67 @@ packages: cpu: [x64] os: [win32] + '@pandacss/config@1.11.0': + resolution: {integrity: sha512-GYBhyhAwTFdHNJmFmly3uOwa3BDxSdGDEXiacBmJv0iZlk2O6IXEccsZcaJmCbFRPMfGqYbvcdz40D+3w/uQjA==} + + '@pandacss/core@1.11.0': + resolution: {integrity: sha512-0VHZa7Zo4du0WZAh4AxnRiDkQJRPrGgk/9Micts6rPnmGTTh09WZoZiGZHOproJu0JvGry9QnUrHJwz65x3cRA==} + + '@pandacss/dev@1.11.0': + resolution: {integrity: sha512-cj2LsSmtt1Bu+z2mUWy9aS1yU7IdGjeM78wSpGnMwSyVvaJ76tKgAC79zPxPFxDOiw7V5xjEcToScjJ5b44Wag==} + hasBin: true + + '@pandacss/extractor@1.11.0': + resolution: {integrity: sha512-LJ8yOWmxn3d8VQ22ZtU5g+1AJDyaL5grBk8xriySJI/k0kuLD+D30aEaouTrajCxWeX/Ic9GH34ZG+KoIbG/xQ==} + + '@pandacss/generator@1.11.0': + resolution: {integrity: sha512-8F//+g8llURrNdV4O7arWHlUMZhSn4mIdQGDDcO3SpPBcUU/Xc1UwEC7nQM8APuePKFNAubyRQ6eS3Ek2r0Eiw==} + + '@pandacss/is-valid-prop@1.11.0': + resolution: {integrity: sha512-KVR+mv3rhlY4meObtp7SZh7EGMaNsuVh/a5lk0UbxRWJrjPIRdkIgJAXxRt+Rlv883RFgnVxnn2Nv2nVtKVdDA==} + + '@pandacss/logger@1.11.0': + resolution: {integrity: sha512-VvMk88jb6zbyF6yuy3Td9GTK4635XRpsr4vcdUhCPbcbDH2Adb6UgpxTsp+6ot5Wm2CqqB/3GIxQ5jXDMMFkBw==} + + '@pandacss/mcp@1.11.0': + resolution: {integrity: sha512-Ajb8FIBNfwMhvlUz6iDjMxQ9DU1njekvjwUvvEg5rAz5Iau2VAYV/yLE1/SAk5mQ8HqvZLIRaAoaRHmBjE7jrA==} + + '@pandacss/node@1.11.0': + resolution: {integrity: sha512-KD8/fTMldGoEch8+X3gA0KFIBNfo6wiQ23s9ZMqFC18FNZKLFyQlHaGt956X7pDwSVHoaZPytlbk78dnYXQkMw==} + + '@pandacss/parser@1.11.0': + resolution: {integrity: sha512-qQsRR/SJUELLdBg2maeqzH/+4TSUv67CUIxEHYybYP1nf/tb0mM/nR+++n++LS6JxCX2Y94GeZwhXHfnJr0HfA==} + + '@pandacss/plugin-lightningcss@1.11.0': + resolution: {integrity: sha512-NbbfbMpgda5PZEpmAlk/iiVplVytbbrSScHIqlUdMQzwjXAb/r3syAyPaqxJu1C1jXI9Kn2oPyiKKWGcVntbzQ==} + + '@pandacss/plugin-svelte@1.11.0': + resolution: {integrity: sha512-FLuwYaBkvdzziPbEkZU7DgKvCFnM6eDC4o3nix1lgMVTMXHY49VnMhH8yVlZLqfZUV1Nu4fJ4DHC+LRpuxUUvQ==} + + '@pandacss/plugin-vue@1.11.0': + resolution: {integrity: sha512-IDYi6s853IJTqTORiWkWMcbH+lRhlQTerCOY8f2RSWSIKFU6XvNkxVDoNAgVhv4UjBGc+lLutkCLN5M59unIYQ==} + + '@pandacss/postcss@1.11.0': + resolution: {integrity: sha512-QdBDOYsvdIsyz5lmxkg4mEjxzHBOeXe4MmSqDdwdYkfdpdq/rM9hOHDKVsCmGe9sQy/YJEpP0mlSq6QaYW3JxQ==} + + '@pandacss/preset-base@1.11.0': + resolution: {integrity: sha512-/P4ZW2g9fbIN7eBMyrIDqPvAIGep1rkA7r0AmwDXKp1qZ0amCbXKRmUgC53NvbK6BOcz3faLFJD0Vb8x929g3g==} + + '@pandacss/preset-panda@1.11.0': + resolution: {integrity: sha512-+4GPhmur6v4H0K9l+lfCdd2OxgwUQKkbXFaFAkcXHt8i+Sf7vzSmcycANFUnXBnot4HWK5WJVJ5Ql6tvMMBo1Q==} + + '@pandacss/reporter@1.11.0': + resolution: {integrity: sha512-ZqWHlk0Xdp5X5VZf0cSxI1+hTUE8JOil20VR/oVujzF160yulURNGEZgzZ7ySjvpuatuySvd1ZyfrUy/aTWRjQ==} + + '@pandacss/shared@1.11.0': + resolution: {integrity: sha512-VsAfzG4K4jBkt8dxjXTE66mKVUcXAUEsd05jyCqZr51gumGMni60pOr6WQOdlJxxdncbrNr1g46CzKbcxFeJTA==} + + '@pandacss/token-dictionary@1.11.0': + resolution: {integrity: sha512-Kq23p56VmprZoQSYWFjMtaxiC+QLRS7jOaKUi9eJCKykl51rOMelFo6Ch/akserqIQcwAcTRYlFjnNW8GIynFg==} + + '@pandacss/types@1.11.0': + resolution: {integrity: sha512-7TBzd9QDTu6boJIU4Bf4SuvZ+bCwl9evsn9ymr8c7ISHyil1nJqC02V5O6j6H9w6XlKFFSYLQU7v1f3FOMeQew==} + '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} @@ -1301,6 +1567,9 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 + '@ts-morph/common@0.29.0': + resolution: {integrity: sha512-35oUmphHbJvQ/+UTwFNme/t2p3FoKiGJ5auTjjpNTop2dyREspirjMy82PLSC1pnDJ8ah1GU98hwpVt64YXQsg==} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -1340,6 +1609,9 @@ packages: '@types/nlcst@2.0.3': resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + '@types/node@24.12.2': resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} @@ -1526,6 +1798,25 @@ packages: cpu: [x64] os: [win32] + '@vue/compiler-core@3.5.25': + resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} + + '@vue/compiler-dom@3.5.25': + resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} + + '@vue/compiler-sfc@3.5.25': + resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} + + '@vue/compiler-ssr@3.5.25': + resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} + + '@vue/shared@3.5.25': + resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -1539,9 +1830,24 @@ packages: resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} engines: {node: '>=18'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-escapes@7.3.0: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} @@ -1593,6 +1899,10 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + astro@5.18.1: resolution: {integrity: sha512-m4VWilWZ+Xt6NPoYzC4CgGZim/zQUO7WFL0RHCH0AiEavF1153iC3+me2atDvXpf/yX4PyGUeD8wZLq1cirT3g==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} @@ -1605,6 +1915,10 @@ packages: bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base-64@1.0.0: resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} @@ -1616,6 +1930,10 @@ packages: before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -1626,19 +1944,47 @@ packages: resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} engines: {node: '>=18'} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + browserslist@4.28.2: resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bundle-n-require@1.1.2: + resolution: {integrity: sha512-bEk2jakVK1ytnZ9R2AAiZEeK/GxPUM8jvcRxHZXifZDMcjkI4EG/GlsJ2YGSVYT9y/p/gA9/0yDY8rCGsSU6Tg==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} engines: {node: '>=20.19.0'} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1678,6 +2024,10 @@ packages: character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chokidar@5.0.0: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} @@ -1718,6 +2068,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -1744,9 +2097,20 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + conventional-changelog-angular@8.3.1: resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} @@ -1779,6 +2143,14 @@ packages: cookie-es@1.2.3: resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + cookie@1.1.1: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} @@ -1786,6 +2158,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + cosmiconfig@9.0.1: resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} engines: {node: '>=14'} @@ -1799,6 +2175,10 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crosspath@2.0.0: + resolution: {integrity: sha512-ju88BYCQ2uvjO2bR+SsgLSTwTSctU+6Vp2ePbKPgSCZyy4MWZxYsT738DlKVRE5utUjobjPRm1MkTYKJxCmpTA==} + engines: {node: '>=14.9.0'} + crossws@0.3.5: resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} @@ -1852,6 +2232,10 @@ packages: defu@6.1.6: resolution: {integrity: sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug==} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1905,9 +2289,16 @@ packages: resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} engines: {node: '>=4'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.331: resolution: {integrity: sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==} @@ -1920,6 +2311,10 @@ packages: emojilib@2.4.0: resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + enhanced-resolve@5.20.1: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} @@ -1947,9 +2342,26 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} @@ -1959,6 +2371,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -1973,9 +2388,21 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + eventsource-parser@3.0.8: + resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} @@ -1984,12 +2411,38 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} + express-rate-limit@8.4.1: + resolution: {integrity: sha512-NGVYwQSAyEQgzxX1iCM978PP9AdO/hW93gMcF6ZwQCm+rFvLsBH6w4xcXWTcliS8La5EPRN3p9wzItqBwJrfNw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2011,6 +2464,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} @@ -2034,6 +2491,10 @@ packages: resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} engines: {node: '>=20'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + framer-motion@12.38.0: resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} peerDependencies: @@ -2048,9 +2509,17 @@ packages: react-dom: optional: true + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + from2@2.3.0: resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + engines: {node: '>=14.14'} + fs-extra@11.3.4: resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} engines: {node: '>=14.14'} @@ -2060,6 +2529,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-timeout@1.0.2: resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} engines: {node: '>=18'} @@ -2076,6 +2548,14 @@ packages: resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -2101,6 +2581,18 @@ packages: github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -2123,6 +2615,14 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + hast-util-from-html@2.0.3: resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} @@ -2156,6 +2656,10 @@ packages: highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + hono@4.12.16: + resolution: {integrity: sha512-jN0ZewiNAWSe5khM3EyCmBb250+b40wWbwNILNfEvq84VREWwOIkuUsFONk/3i3nqkz7Oe1PcpM2mwQEK2L9Kg==} + engines: {node: '>=16.9.0'} + hook-std@4.0.0: resolution: {integrity: sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ==} engines: {node: '>=20'} @@ -2177,6 +2681,10 @@ packages: http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -2193,6 +2701,10 @@ packages: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -2226,6 +2738,14 @@ packages: resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} engines: {node: '>=12'} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -2237,10 +2757,18 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} @@ -2258,6 +2786,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2288,10 +2819,16 @@ packages: resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} engines: {node: '>= 0.6.0'} + javascript-stringify@2.1.0: + resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2310,6 +2847,12 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-with-bigint@3.5.8: resolution: {integrity: sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==} @@ -2328,36 +2871,77 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-arm64@1.32.0: resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-darwin-x64@1.32.0: resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-freebsd-x64@1.32.0: resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm-gnueabihf@1.32.0: resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} @@ -2365,6 +2949,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} @@ -2372,6 +2963,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} @@ -2379,6 +2977,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} @@ -2386,18 +2991,34 @@ packages: os: [linux] libc: [musl] + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss-win32-x64-msvc@1.32.0: resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + engines: {node: '>= 12.0.0'} + lightningcss@1.32.0: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} @@ -2428,12 +3049,21 @@ packages: lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + lodash.uniqby@4.7.0: resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + look-it-up@2.1.0: + resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -2468,6 +3098,10 @@ packages: engines: {node: '>= 18'} hasBin: true + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} @@ -2513,13 +3147,28 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + microdiff@1.5.0: + resolution: {integrity: sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -2608,6 +3257,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@4.1.0: resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} engines: {node: '>=16'} @@ -2617,6 +3274,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2645,6 +3306,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -2662,6 +3327,10 @@ packages: resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} engines: {node: '>=18'} + node-eval@2.0.0: + resolution: {integrity: sha512-Ap+L9HznXAVeJj3TJ1op6M6bg5xtTq8L5CU/PJxtkhea/DrIxdTknGKIECKd/v/Lgql95iuMAYvIzBNd0pmcMg==} + engines: {node: '>= 4'} + node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} @@ -2777,6 +3446,14 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-path@0.11.8: + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} + obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -2786,6 +3463,13 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -2796,6 +3480,9 @@ packages: oniguruma-to-es@4.3.5: resolution: {integrity: sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==} + outdent@0.8.0: + resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} + oxfmt@0.43.0: resolution: {integrity: sha512-KTYNG5ISfHSdmeZ25Xzb3qgz9EmQvkaGAxgBY/p38+ZiAet3uZeu7FnMwcSQJg152Qwl0wnYAxDc+Z/H6cvrwA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2835,6 +3522,10 @@ packages: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + p-limit@6.2.0: resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==} engines: {node: '>=18'} @@ -2901,10 +3592,21 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2913,10 +3615,19 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + piccolore@0.1.3: resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} @@ -2939,18 +3650,75 @@ packages: resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} hasBin: true + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-conf@2.1.0: resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} engines: {node: '>=4'} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + pngjs@7.0.0: resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} engines: {node: '>=14.19.0'} + postcss-discard-duplicates@7.0.2: + resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-empty@7.0.1: + resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-selectors@7.0.5: + resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-nested@7.0.2: + resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-normalize-whitespace@7.0.1: + resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + postcss@8.5.8: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + pretty-ms@9.3.0: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} @@ -2972,9 +3740,28 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + qs@6.15.1: + resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -3011,6 +3798,10 @@ packages: readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + readdirp@5.0.0: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} @@ -3060,6 +3851,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3083,14 +3878,28 @@ packages: retext@9.0.0: resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rolldown@1.0.0-rc.12: resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.6.0: resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} @@ -3116,6 +3925,17 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + sharp@0.34.5: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3131,6 +3951,22 @@ packages: shiki@3.23.0: resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -3150,6 +3986,10 @@ packages: resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} engines: {node: '>=8'} + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + smol-toml@1.6.1: resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} engines: {node: '>= 18'} @@ -3183,6 +4023,10 @@ packages: split2@1.0.0: resolution: {integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@4.0.0: resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} @@ -3248,6 +4092,10 @@ packages: engines: {node: '>=16'} hasBin: true + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -3306,6 +4154,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -3324,6 +4176,22 @@ packages: resolution: {integrity: sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==} engines: {node: '>=14.13.1'} + ts-evaluator@1.2.0: + resolution: {integrity: sha512-ncSGek1p92bj2ifB7s9UBgryHCkU9vwC5d+Lplt12gT9DH+e41X8dMoHRQjIMeAvyG7j9dEnuHmwgOtuRIQL+Q==} + engines: {node: '>=14.19.0'} + peerDependencies: + jsdom: '>=14.x || >=15.x || >=16.x || >=17.x || >=18.x || >=19.x || >=20.x || >=21.x || >=22.x' + typescript: '>=3.2.x || >= 4.x || >= 5.x' + peerDependenciesMeta: + jsdom: + optional: true + + ts-morph@28.0.0: + resolution: {integrity: sha512-Wp3tnZ2bzwxyTZMtgWVzXDfm7lB1Drz+y9DmmYH/L702PQhPyVrp3pkou3yIz4qjS14GY9kcpmLiOOMvl8oG1g==} + + ts-pattern@5.9.0: + resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} + tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} @@ -3362,6 +4230,10 @@ packages: resolution: {integrity: sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==} engines: {node: '>=20'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -3464,6 +4336,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unstorage@1.17.5: resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==} peerDependencies: @@ -3542,6 +4418,10 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -3629,6 +4509,10 @@ packages: wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + wordwrapjs@5.1.1: + resolution: {integrity: sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==} + engines: {node: '>=12.17'} + wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -3641,6 +4525,9 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.20.0: resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} @@ -3722,6 +4609,9 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.4.2: + resolution: {integrity: sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -3985,9 +4875,30 @@ snapshots: dependencies: fontkitten: 1.0.3 + '@clack/core@0.5.0': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.11.0': + dependencies: + '@clack/core': 0.5.0 + picocolors: 1.1.1 + sisteransi: 1.0.5 + '@colors/colors@1.5.0': optional: true + '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.6)': + dependencies: + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + '@emnapi/core@1.9.2': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -4004,86 +4915,168 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.25.12': + optional: true + '@esbuild/aix-ppc64@0.27.7': optional: true + '@esbuild/android-arm64@0.25.12': + optional: true + '@esbuild/android-arm64@0.27.7': optional: true + '@esbuild/android-arm@0.25.12': + optional: true + '@esbuild/android-arm@0.27.7': optional: true + '@esbuild/android-x64@0.25.12': + optional: true + '@esbuild/android-x64@0.27.7': optional: true + '@esbuild/darwin-arm64@0.25.12': + optional: true + '@esbuild/darwin-arm64@0.27.7': optional: true + '@esbuild/darwin-x64@0.25.12': + optional: true + '@esbuild/darwin-x64@0.27.7': optional: true + '@esbuild/freebsd-arm64@0.25.12': + optional: true + '@esbuild/freebsd-arm64@0.27.7': optional: true + '@esbuild/freebsd-x64@0.25.12': + optional: true + '@esbuild/freebsd-x64@0.27.7': optional: true + '@esbuild/linux-arm64@0.25.12': + optional: true + '@esbuild/linux-arm64@0.27.7': optional: true + '@esbuild/linux-arm@0.25.12': + optional: true + '@esbuild/linux-arm@0.27.7': optional: true + '@esbuild/linux-ia32@0.25.12': + optional: true + '@esbuild/linux-ia32@0.27.7': optional: true + '@esbuild/linux-loong64@0.25.12': + optional: true + '@esbuild/linux-loong64@0.27.7': optional: true + '@esbuild/linux-mips64el@0.25.12': + optional: true + '@esbuild/linux-mips64el@0.27.7': optional: true + '@esbuild/linux-ppc64@0.25.12': + optional: true + '@esbuild/linux-ppc64@0.27.7': optional: true + '@esbuild/linux-riscv64@0.25.12': + optional: true + '@esbuild/linux-riscv64@0.27.7': optional: true + '@esbuild/linux-s390x@0.25.12': + optional: true + '@esbuild/linux-s390x@0.27.7': optional: true + '@esbuild/linux-x64@0.25.12': + optional: true + '@esbuild/linux-x64@0.27.7': optional: true + '@esbuild/netbsd-arm64@0.25.12': + optional: true + '@esbuild/netbsd-arm64@0.27.7': optional: true + '@esbuild/netbsd-x64@0.25.12': + optional: true + '@esbuild/netbsd-x64@0.27.7': optional: true + '@esbuild/openbsd-arm64@0.25.12': + optional: true + '@esbuild/openbsd-arm64@0.27.7': optional: true + '@esbuild/openbsd-x64@0.25.12': + optional: true + '@esbuild/openbsd-x64@0.27.7': optional: true + '@esbuild/openharmony-arm64@0.25.12': + optional: true + '@esbuild/openharmony-arm64@0.27.7': optional: true + '@esbuild/sunos-x64@0.25.12': + optional: true + '@esbuild/sunos-x64@0.27.7': optional: true + '@esbuild/win32-arm64@0.25.12': + optional: true + '@esbuild/win32-arm64@0.27.7': optional: true + '@esbuild/win32-ia32@0.25.12': + optional: true + '@esbuild/win32-ia32@0.27.7': optional: true + '@esbuild/win32-x64@0.25.12': + optional: true + '@esbuild/win32-x64@0.27.7': optional: true '@fastify/busboy@2.1.1': {} + '@hono/node-server@1.19.14(hono@4.12.16)': + dependencies: + hono: 4.12.16 + '@img/colour@1.1.0': optional: true @@ -4228,6 +5221,28 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@modelcontextprotocol/sdk@1.29.0(zod@4.4.2)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.16) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.8 + express: 5.2.1 + express-rate-limit: 8.4.1(express@5.2.1) + hono: 4.12.16 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.4.2 + zod-to-json-schema: 3.25.2(zod@4.4.2) + transitivePeerDependencies: + - supports-color + '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: '@emnapi/core': 1.9.2 @@ -4235,6 +5250,18 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + '@octokit/auth-token@6.0.0': {} '@octokit/core@7.0.6': @@ -4444,6 +5471,211 @@ snapshots: '@oxlint/binding-win32-x64-msvc@1.58.0': optional: true + '@pandacss/config@1.11.0': + dependencies: + '@pandacss/logger': 1.11.0 + '@pandacss/preset-base': 1.11.0 + '@pandacss/preset-panda': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/types': 1.11.0 + bundle-n-require: 1.1.2 + escalade: 3.2.0 + microdiff: 1.5.0 + typescript: 6.0.2 + + '@pandacss/core@1.11.0': + dependencies: + '@csstools/postcss-cascade-layers': 5.0.2(postcss@8.5.6) + '@pandacss/is-valid-prop': 1.11.0 + '@pandacss/logger': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + browserslist: 4.28.1 + lodash.merge: 4.6.2 + outdent: 0.8.0 + postcss: 8.5.6 + postcss-discard-duplicates: 7.0.2(postcss@8.5.6) + postcss-discard-empty: 7.0.1(postcss@8.5.6) + postcss-minify-selectors: 7.0.5(postcss@8.5.6) + postcss-nested: 7.0.2(postcss@8.5.6) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.6) + postcss-selector-parser: 7.1.1 + ts-pattern: 5.9.0 + + '@pandacss/dev@1.11.0(typescript@6.0.2)': + dependencies: + '@clack/prompts': 0.11.0 + '@pandacss/config': 1.11.0 + '@pandacss/logger': 1.11.0 + '@pandacss/mcp': 1.11.0(typescript@6.0.2) + '@pandacss/node': 1.11.0(typescript@6.0.2) + '@pandacss/postcss': 1.11.0(typescript@6.0.2) + '@pandacss/preset-base': 1.11.0 + '@pandacss/preset-panda': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + cac: 6.7.14 + transitivePeerDependencies: + - '@cfworker/json-schema' + - jsdom + - supports-color + - typescript + + '@pandacss/extractor@1.11.0(typescript@6.0.2)': + dependencies: + '@pandacss/shared': 1.11.0 + ts-evaluator: 1.2.0(typescript@6.0.2) + ts-morph: 28.0.0 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/generator@1.11.0': + dependencies: + '@pandacss/core': 1.11.0 + '@pandacss/is-valid-prop': 1.11.0 + '@pandacss/logger': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + javascript-stringify: 2.1.0 + outdent: 0.8.0 + pluralize: 8.0.0 + postcss: 8.5.6 + ts-pattern: 5.9.0 + + '@pandacss/is-valid-prop@1.11.0': {} + + '@pandacss/logger@1.11.0': + dependencies: + '@pandacss/types': 1.11.0 + kleur: 4.1.5 + + '@pandacss/mcp@1.11.0(typescript@6.0.2)': + dependencies: + '@clack/prompts': 0.11.0 + '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.2) + '@pandacss/logger': 1.11.0 + '@pandacss/node': 1.11.0(typescript@6.0.2) + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + zod: 4.4.2 + transitivePeerDependencies: + - '@cfworker/json-schema' + - jsdom + - supports-color + - typescript + + '@pandacss/node@1.11.0(typescript@6.0.2)': + dependencies: + '@pandacss/config': 1.11.0 + '@pandacss/core': 1.11.0 + '@pandacss/generator': 1.11.0 + '@pandacss/logger': 1.11.0 + '@pandacss/parser': 1.11.0(typescript@6.0.2) + '@pandacss/plugin-lightningcss': 1.11.0 + '@pandacss/plugin-svelte': 1.11.0 + '@pandacss/plugin-vue': 1.11.0 + '@pandacss/reporter': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + browserslist: 4.28.1 + chokidar: 4.0.3 + fast-glob: 3.3.3 + fs-extra: 11.3.2 + get-tsconfig: 4.13.7 + glob-parent: 6.0.2 + is-glob: 4.0.3 + lodash.merge: 4.6.2 + look-it-up: 2.1.0 + outdent: 0.8.0 + p-limit: 5.0.0 + package-manager-detector: 1.6.0 + perfect-debounce: 1.0.0 + picomatch: 4.0.4 + pkg-types: 2.3.0 + pluralize: 8.0.0 + postcss: 8.5.6 + prettier: 3.2.5 + ts-morph: 28.0.0 + ts-pattern: 5.9.0 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/parser@1.11.0(typescript@6.0.2)': + dependencies: + '@pandacss/config': 1.11.0 + '@pandacss/core': 1.11.0 + '@pandacss/extractor': 1.11.0(typescript@6.0.2) + '@pandacss/logger': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/types': 1.11.0 + ts-morph: 28.0.0 + ts-pattern: 5.9.0 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/plugin-lightningcss@1.11.0': + dependencies: + '@pandacss/logger': 1.11.0 + '@pandacss/types': 1.11.0 + browserslist: 4.28.1 + lightningcss: 1.31.1 + + '@pandacss/plugin-svelte@1.11.0': + dependencies: + '@pandacss/types': 1.11.0 + magic-string: 0.30.21 + + '@pandacss/plugin-vue@1.11.0': + dependencies: + '@pandacss/types': 1.11.0 + '@vue/compiler-sfc': 3.5.25 + magic-string: 0.30.21 + + '@pandacss/postcss@1.11.0(typescript@6.0.2)': + dependencies: + '@pandacss/node': 1.11.0(typescript@6.0.2) + postcss: 8.5.6 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/preset-base@1.11.0': + dependencies: + '@pandacss/types': 1.11.0 + + '@pandacss/preset-panda@1.11.0': + dependencies: + '@pandacss/types': 1.11.0 + + '@pandacss/reporter@1.11.0': + dependencies: + '@pandacss/core': 1.11.0 + '@pandacss/generator': 1.11.0 + '@pandacss/logger': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/types': 1.11.0 + table: 6.9.0 + wordwrapjs: 5.1.1 + + '@pandacss/shared@1.11.0': {} + + '@pandacss/token-dictionary@1.11.0': + dependencies: + '@pandacss/logger': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/types': 1.11.0 + picomatch: 4.0.4 + ts-pattern: 5.9.0 + + '@pandacss/types@1.11.0': {} + '@pnpm/config.env-replace@1.1.0': {} '@pnpm/network.ca-file@1.0.2': @@ -4732,6 +5964,12 @@ snapshots: tailwindcss: 4.2.2 vite: 8.0.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + '@ts-morph/common@0.29.0': + dependencies: + minimatch: 10.2.5 + path-browserify: 1.0.1 + tinyglobby: 0.2.15 + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -4785,6 +6023,8 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/node@17.0.45': {} + '@types/node@24.12.2': dependencies: undici-types: 7.16.0 @@ -4987,6 +6227,43 @@ snapshots: '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.15': optional: true + '@vue/compiler-core@3.5.25': + dependencies: + '@babel/parser': 7.29.2 + '@vue/shared': 3.5.25 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.25': + dependencies: + '@vue/compiler-core': 3.5.25 + '@vue/shared': 3.5.25 + + '@vue/compiler-sfc@3.5.25': + dependencies: + '@babel/parser': 7.29.2 + '@vue/compiler-core': 3.5.25 + '@vue/compiler-dom': 3.5.25 + '@vue/compiler-ssr': 3.5.25 + '@vue/shared': 3.5.25 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.8 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.25': + dependencies: + '@vue/compiler-dom': 3.5.25 + '@vue/shared': 3.5.25 + + '@vue/shared@3.5.25': {} + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn@8.16.0: {} agent-base@7.1.4: {} @@ -4996,10 +6273,23 @@ snapshots: clean-stack: 5.3.0 indent-string: 5.0.0 + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-align@3.0.1: dependencies: string-width: 4.2.3 + ansi-colors@4.1.3: {} + ansi-escapes@7.3.0: dependencies: environment: 1.1.0 @@ -5037,6 +6327,8 @@ snapshots: assertion-error@2.0.1: {} + astral-regex@2.0.0: {} + astro@5.18.1(@types/node@25.5.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): dependencies: '@astrojs/compiler': 2.13.1 @@ -5148,12 +6440,28 @@ snapshots: bail@2.0.2: {} + balanced-match@4.0.4: {} + base-64@1.0.0: {} baseline-browser-mapping@2.10.15: {} before-after-hook@4.0.0: {} + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.1 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} bottleneck@2.19.5: {} @@ -5169,10 +6477,22 @@ snapshots: widest-line: 5.0.0 wrap-ansi: 9.0.2 + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.15 + caniuse-lite: 1.0.30001785 + electron-to-chromium: 1.5.331 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + browserslist@4.28.2: dependencies: baseline-browser-mapping: 2.10.15 @@ -5181,8 +6501,27 @@ snapshots: node-releases: 2.0.37 update-browserslist-db: 1.2.3(browserslist@4.28.2) + bundle-n-require@1.1.2: + dependencies: + esbuild: 0.25.12 + node-eval: 2.0.0 + + bytes@3.1.2: {} + + cac@6.7.14: {} + cac@7.0.0: {} + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + callsites@3.1.0: {} camelcase@8.0.0: {} @@ -5212,6 +6551,10 @@ snapshots: character-entities@2.0.2: {} + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chokidar@5.0.0: dependencies: readdirp: 5.0.0 @@ -5255,6 +6598,8 @@ snapshots: clsx@2.1.1: {} + code-block-writer@13.0.3: {} + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -5278,11 +6623,17 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 + confbox@0.2.4: {} + config-chain@1.1.13: dependencies: ini: 1.3.8 proto-list: 1.2.4 + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + conventional-changelog-angular@8.3.1: dependencies: compare-func: 2.0.0 @@ -5312,10 +6663,19 @@ snapshots: cookie-es@1.2.3: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + cookie@1.1.1: {} core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cosmiconfig@9.0.1(typescript@6.0.2): dependencies: env-paths: 2.2.1 @@ -5331,6 +6691,10 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crosspath@2.0.0: + dependencies: + '@types/node': 17.0.45 + crossws@0.3.5: dependencies: uncrypto: 0.1.3 @@ -5379,6 +6743,8 @@ snapshots: defu@6.1.6: {} + depd@2.0.0: {} + dequal@2.0.3: {} destr@2.0.5: {} @@ -5427,10 +6793,18 @@ snapshots: dset@3.1.4: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + duplexer2@0.1.4: dependencies: readable-stream: 2.3.8 + ee-first@1.1.1: {} + electron-to-chromium@1.5.331: {} emoji-regex@10.6.0: {} @@ -5439,6 +6813,8 @@ snapshots: emojilib@2.4.0: {} + encodeurl@2.0.0: {} + enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 @@ -5461,8 +6837,45 @@ snapshots: dependencies: is-arrayish: 0.2.1 + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.7: optionalDependencies: '@esbuild/aix-ppc64': 0.27.7 @@ -5494,6 +6907,8 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} escape-string-regexp@5.0.0: {} @@ -5504,8 +6919,16 @@ snapshots: dependencies: '@types/estree': 1.0.8 + etag@1.8.1: {} + eventemitter3@5.0.4: {} + eventsource-parser@3.0.8: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.8 + execa@8.0.1: dependencies: cross-spawn: 7.0.6 @@ -5533,10 +6956,66 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 + express-rate-limit@8.4.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.1 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + exsolve@1.0.8: {} + extend@3.0.2: {} fast-content-type-parse@3.0.0: {} + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-uri@3.1.0: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -5553,6 +7032,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up-simple@1.0.1: {} find-up@2.1.0: @@ -5574,6 +7064,8 @@ snapshots: dependencies: tiny-inflate: 1.0.3 + forwarded@0.2.0: {} + framer-motion@12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: motion-dom: 12.38.0 @@ -5583,11 +7075,19 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + fresh@2.0.0: {} + from2@2.3.0: dependencies: inherits: 2.0.4 readable-stream: 2.3.8 + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-extra@11.3.4: dependencies: graceful-fs: 4.2.11 @@ -5597,6 +7097,8 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + function-timeout@1.0.2: {} gensync@1.0.0-beta.2: {} @@ -5605,6 +7107,24 @@ snapshots: get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.3 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-stream@6.0.1: {} get-stream@7.0.1: {} @@ -5631,6 +7151,16 @@ snapshots: github-slugger@2.0.0: {} + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + gopd@1.2.0: {} + graceful-fs@4.2.10: {} graceful-fs@4.2.11: {} @@ -5660,6 +7190,12 @@ snapshots: has-flag@4.0.0: {} + has-symbols@1.1.0: {} + + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + hast-util-from-html@2.0.3: dependencies: '@types/hast': 3.0.4 @@ -5749,6 +7285,8 @@ snapshots: highlight.js@10.7.3: {} + hono@4.12.16: {} + hook-std@4.0.0: {} hosted-git-info@7.0.2: @@ -5765,6 +7303,14 @@ snapshots: http-cache-semantics@4.2.0: {} + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -5783,6 +7329,10 @@ snapshots: human-signals@8.0.1: {} + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -5812,14 +7362,24 @@ snapshots: from2: 2.3.0 p-is-promise: 3.0.0 + ip-address@10.1.0: {} + + ipaddr.js@1.9.1: {} + iron-webcrypto@1.2.1: {} is-arrayish@0.2.1: {} is-docker@3.0.0: {} + is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 @@ -5830,6 +7390,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-promise@4.0.0: {} + is-stream@3.0.0: {} is-stream@4.0.1: {} @@ -5854,8 +7416,12 @@ snapshots: java-properties@1.0.2: {} + javascript-stringify@2.1.0: {} + jiti@2.6.1: {} + jose@6.2.3: {} + js-tokens@4.0.0: {} js-yaml@4.1.1: @@ -5868,6 +7434,10 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + json-with-bigint@3.5.8: {} json5@2.2.3: {} @@ -5882,39 +7452,90 @@ snapshots: kleur@3.0.3: {} + kleur@4.1.5: {} + + lightningcss-android-arm64@1.31.1: + optional: true + lightningcss-android-arm64@1.32.0: optional: true + lightningcss-darwin-arm64@1.31.1: + optional: true + lightningcss-darwin-arm64@1.32.0: optional: true + lightningcss-darwin-x64@1.31.1: + optional: true + lightningcss-darwin-x64@1.32.0: optional: true + lightningcss-freebsd-x64@1.31.1: + optional: true + lightningcss-freebsd-x64@1.32.0: optional: true + lightningcss-linux-arm-gnueabihf@1.31.1: + optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true + lightningcss-linux-arm64-gnu@1.31.1: + optional: true + lightningcss-linux-arm64-gnu@1.32.0: optional: true + lightningcss-linux-arm64-musl@1.31.1: + optional: true + lightningcss-linux-arm64-musl@1.32.0: optional: true + lightningcss-linux-x64-gnu@1.31.1: + optional: true + lightningcss-linux-x64-gnu@1.32.0: optional: true + lightningcss-linux-x64-musl@1.31.1: + optional: true + lightningcss-linux-x64-musl@1.32.0: optional: true + lightningcss-win32-arm64-msvc@1.31.1: + optional: true + lightningcss-win32-arm64-msvc@1.32.0: optional: true + lightningcss-win32-x64-msvc@1.31.1: + optional: true + lightningcss-win32-x64-msvc@1.32.0: optional: true + lightningcss@1.31.1: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 @@ -5955,10 +7576,16 @@ snapshots: lodash.isstring@4.0.1: {} + lodash.merge@4.6.2: {} + + lodash.truncate@4.4.2: {} + lodash.uniqby@4.7.0: {} longest-streak@3.1.0: {} + look-it-up@2.1.0: {} + lru-cache@10.4.3: {} lru-cache@11.3.0: {} @@ -5998,6 +7625,8 @@ snapshots: marked@15.0.12: {} + math-intrinsics@1.1.0: {} + mdast-util-definitions@6.0.0: dependencies: '@types/mdast': 4.0.4 @@ -6122,10 +7751,18 @@ snapshots: mdn-data@2.27.1: {} + media-typer@1.1.0: {} + meow@13.2.0: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} + merge2@1.4.1: {} + + microdiff@1.5.0: {} + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -6322,10 +7959,20 @@ snapshots: braces: 3.0.3 picomatch: 2.3.2 + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@4.1.0: {} mimic-fn@4.0.0: {} + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + minimist@1.2.8: {} motion-dom@12.38.0: @@ -6348,6 +7995,8 @@ snapshots: nanoid@3.3.11: {} + negotiator@1.0.0: {} + neo-async@2.6.2: {} neotraverse@0.6.18: {} @@ -6365,6 +8014,10 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 + node-eval@2.0.0: + dependencies: + path-is-absolute: 1.0.1 + node-fetch-native@1.6.7: {} node-mock-http@1.0.4: {} @@ -6406,6 +8059,10 @@ snapshots: object-assign@4.1.1: {} + object-inspect@1.13.4: {} + + object-path@0.11.8: {} + obug@2.1.1: {} ofetch@1.5.1: @@ -6416,6 +8073,14 @@ snapshots: ohash@2.0.11: {} + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@6.0.0: dependencies: mimic-fn: 4.0.0 @@ -6428,6 +8093,8 @@ snapshots: regex: 6.1.0 regex-recursion: 6.0.2 + outdent@0.8.0: {} + oxfmt@0.43.0: dependencies: tinypool: 2.1.0 @@ -6500,6 +8167,10 @@ snapshots: dependencies: p-try: 1.0.0 + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.2 + p-limit@6.2.0: dependencies: yocto-queue: 1.2.2 @@ -6568,14 +8239,26 @@ snapshots: dependencies: entities: 6.0.1 + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + path-exists@3.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-key@4.0.0: {} + path-to-regexp@8.4.2: {} + path-type@4.0.0: {} + pathe@2.0.3: {} + + perfect-debounce@1.0.0: {} + piccolore@0.1.3: {} picocolors@1.1.1: {} @@ -6590,19 +8273,68 @@ snapshots: dependencies: pngjs: 7.0.0 + pkce-challenge@5.0.1: {} + pkg-conf@2.1.0: dependencies: find-up: 2.1.0 load-json-file: 4.0.0 + pkg-types@2.3.0: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + + pluralize@8.0.0: {} + pngjs@7.0.0: {} + postcss-discard-duplicates@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-discard-empty@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-minify-selectors@7.0.5(postcss@8.5.6): + dependencies: + cssesc: 3.0.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-nested@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-normalize-whitespace@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postcss@8.5.8: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 + prettier@3.2.5: {} + pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 @@ -6620,8 +8352,28 @@ snapshots: proto-list@1.2.4: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + qs@6.15.1: + dependencies: + side-channel: 1.1.0 + + queue-microtask@1.2.3: {} + radix3@1.1.2: {} + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -6676,6 +8428,8 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 + readdirp@4.1.2: {} + readdirp@5.0.0: {} regex-recursion@6.0.2: @@ -6760,6 +8514,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -6791,6 +8547,8 @@ snapshots: retext-stringify: 4.0.0 unified: 11.0.5 + reusify@1.1.0: {} + rolldown@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): dependencies: '@oxc-project/types': 0.122.0 @@ -6815,8 +8573,24 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + safe-buffer@5.1.2: {} + safer-buffer@2.1.2: {} + sax@1.6.0: {} scheduler@0.27.0: {} @@ -6861,6 +8635,33 @@ snapshots: semver@7.7.4: {} + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + sharp@0.34.5: dependencies: '@img/colour': 1.1.0 @@ -6910,6 +8711,34 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + signal-exit@4.1.0: {} signale@1.4.0: @@ -6930,6 +8759,12 @@ snapshots: dependencies: unicode-emoji-modifier-base: 1.0.0 + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + smol-toml@1.6.1: {} source-map-js@1.2.1: {} @@ -6958,6 +8793,8 @@ snapshots: dependencies: through2: 2.0.5 + statuses@2.0.2: {} + std-env@4.0.0: {} stream-combiner2@1.1.1: @@ -7031,6 +8868,14 @@ snapshots: picocolors: 1.1.1 sax: 1.6.0 + table@6.9.0: + dependencies: + ajv: 8.20.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + tagged-tag@1.0.0: {} tailwind-merge@3.5.0: {} @@ -7082,6 +8927,8 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + totalist@3.0.1: {} traverse@0.6.8: {} @@ -7092,6 +8939,20 @@ snapshots: ts-deepmerge@7.0.3: {} + ts-evaluator@1.2.0(typescript@6.0.2): + dependencies: + ansi-colors: 4.1.3 + crosspath: 2.0.0 + object-path: 0.11.8 + typescript: 6.0.2 + + ts-morph@28.0.0: + dependencies: + '@ts-morph/common': 0.29.0 + code-block-writer: 13.0.3 + + ts-pattern@5.9.0: {} + tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -7117,6 +8978,12 @@ snapshots: dependencies: tagged-tag: 1.0.0 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typescript@5.9.3: {} typescript@6.0.2: {} @@ -7216,6 +9083,8 @@ snapshots: universalify@2.0.1: {} + unpipe@1.0.0: {} + unstorage@1.17.5: dependencies: anymatch: 3.1.3 @@ -7227,6 +9096,12 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: browserslist: 4.28.2 @@ -7242,6 +9117,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + vary@1.1.2: {} + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 @@ -7411,6 +9288,8 @@ snapshots: wordwrap@1.0.0: {} + wordwrapjs@5.1.1: {} + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -7429,6 +9308,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.2.0 + wrappy@1.0.2: {} + ws@8.20.0: {} xtend@4.0.2: {} @@ -7480,6 +9361,10 @@ snapshots: dependencies: zod: 3.25.76 + zod-to-json-schema@3.25.2(zod@4.4.2): + dependencies: + zod: 4.4.2 + zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76): dependencies: typescript: 5.9.3 @@ -7487,4 +9372,6 @@ snapshots: zod@3.25.76: {} + zod@4.4.2: {} + zwitch@2.0.4: {} From bca21a930524042c8ad2e09e9d5b811646b5907f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 3 May 2026 20:36:23 +0000 Subject: [PATCH 02/15] docs: sync README code blocks --- README.md | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d2eff1a..c9c0b95 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no ## Contents + - [Requirements](#requirements) - [Install & setup](#install--setup) - [Utilities](#utilities) @@ -110,24 +111,24 @@ Then use the utilities anywhere `css(...)` accepts properties: The naming follows Panda's own border-radius convention exactly — substitute `border` ↔ `squircle` and `rounded` ↔ `squircle` (the shorthand) and the table is identical to Panda's: -| Full property name | Shorthand | CSS targets | -| ------------------------------- | ---------------------- | ---------------------------------------- | -| `squircleRadius` | `squircle` | `border-radius` (all four corners) | -| `squircleTopRadius` | `squircleTop` | top corners | -| `squircleRightRadius` | `squircleRight` | right corners | -| `squircleBottomRadius` | `squircleBottom` | bottom corners | -| `squircleLeftRadius` | `squircleLeft` | left corners | -| `squircleStartRadius` | `squircleStart` | inline-start corners (logical) | -| `squircleEndRadius` | `squircleEnd` | inline-end corners (logical) | -| `squircleTopLeftRadius` | `squircleTopLeft` | top-left corner | -| `squircleTopRightRadius` | `squircleTopRight` | top-right corner | -| `squircleBottomRightRadius` | `squircleBottomRight` | bottom-right corner | -| `squircleBottomLeftRadius` | `squircleBottomLeft` | bottom-left corner | -| `squircleStartStartRadius` | `squircleStartStart` | start-start corner (logical) | -| `squircleStartEndRadius` | `squircleStartEnd` | start-end corner (logical) | -| `squircleEndStartRadius` | `squircleEndStart` | end-start corner (logical) | -| `squircleEndEndRadius` | `squircleEndEnd` | end-end corner (logical) | -| `squircleAmount` | `squircleAmt` | superellipse exponent (default 2) | +| Full property name | Shorthand | CSS targets | +| --------------------------- | --------------------- | ---------------------------------- | +| `squircleRadius` | `squircle` | `border-radius` (all four corners) | +| `squircleTopRadius` | `squircleTop` | top corners | +| `squircleRightRadius` | `squircleRight` | right corners | +| `squircleBottomRadius` | `squircleBottom` | bottom corners | +| `squircleLeftRadius` | `squircleLeft` | left corners | +| `squircleStartRadius` | `squircleStart` | inline-start corners (logical) | +| `squircleEndRadius` | `squircleEnd` | inline-end corners (logical) | +| `squircleTopLeftRadius` | `squircleTopLeft` | top-left corner | +| `squircleTopRightRadius` | `squircleTopRight` | top-right corner | +| `squircleBottomRightRadius` | `squircleBottomRight` | bottom-right corner | +| `squircleBottomLeftRadius` | `squircleBottomLeft` | bottom-left corner | +| `squircleStartStartRadius` | `squircleStartStart` | start-start corner (logical) | +| `squircleStartEndRadius` | `squircleStartEnd` | start-end corner (logical) | +| `squircleEndStartRadius` | `squircleEndStart` | end-start corner (logical) | +| `squircleEndEndRadius` | `squircleEndEnd` | end-end corner (logical) | +| `squircleAmount` | `squircleAmt` | superellipse exponent (default 2) | All radius utilities resolve through your `radii` theme tokens, so `squircle: "md"` reads the same `--radii-md` your `borderRadius: "md"` does. The preset also registers a `_squircleSupported` condition (`@supports (corner-shape: superellipse(2))`) for one-off overrides. @@ -406,6 +407,7 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tw-utils.css — the Tailwind utilities + ```css /* ── Squircle utilities ─────────────────────────────────────── */ /* squircle-amt-[n] sets the superellipse amount (default 2) */ @@ -565,6 +567,7 @@ If you'd rather not add a dependency, copy the source directly. Click to expand } } ``` + @@ -573,8 +576,9 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tw-plugin.mjs — the JS plugin -```js -import { c as variantEntries, i as SUPPORTS_RULE, s as squircleCssObj } from "./variants-vQRRK8yy.mjs"; + +````js +import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries } from "./variants-CUhqvLRq.mjs"; import plugin from "tailwindcss/plugin"; //#region src/tw-plugin.ts const squircle = plugin.withOptions((options = {}) => ({ matchUtilities, theme }) => { From c9b32362fb5ff566aa4fb33052cb537a4f704772 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 14:06:06 -0700 Subject: [PATCH 03/15] feat: add StyleX preset using dynamic-style functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each variant is `(radius, amt) => ({...})` inside a single `stylex.create({...})` literal. The babel plugin rejects spreads, factory-in-arg, and computed `@-rule` keys, but accepts dynamic styles whose body is a static literal — this lets us ship 15 corner variants behind one statically-analyzable call site. `amt` defaults via nullish-coalesce inside template literals (`${amt ?? 'var(--squircle-amt, 2)'}`) since StyleX disallows default parameter values on dynamic-style functions. Tests compile the module through `@stylexjs/babel-plugin` and assert the emitted CSS contains the expected `@supports` rules and `--x-*` custom-property substitutions for every variant. Co-Authored-By: Claude Opus 4.7 (1M context) --- package/package.json | 12 + package/src/squircle.stylex.test.ts | 134 +++++++++++ package/src/squircle.stylex.ts | 227 ++++++++++++++++++ package/vite.config.ts | 12 +- pnpm-lock.yaml | 359 ++++++++++++++++++++++++++++ 5 files changed, 743 insertions(+), 1 deletion(-) create mode 100644 package/src/squircle.stylex.test.ts create mode 100644 package/src/squircle.stylex.ts diff --git a/package/package.json b/package/package.json index 15e57ba..f573e17 100644 --- a/package/package.json +++ b/package/package.json @@ -34,12 +34,20 @@ "./panda-preset": { "types": "./dist/panda-preset.d.mts", "import": "./dist/panda-preset.mjs" + }, + "./stylex": { + "types": "./dist/stylex.d.mts", + "import": "./dist/stylex.mjs" } }, "scripts": { "prepublishOnly": "vp run build" }, "devDependencies": { + "@babel/core": "^7.29.0", + "@babel/preset-typescript": "^7.28.0", + "@stylexjs/babel-plugin": "^0.18.3", + "@stylexjs/stylex": "^0.18.3", "@tailwindcss/vite": "^4.2.2", "@types/node": "^25.5.2", "oxlint": "^1.58.0", @@ -51,6 +59,7 @@ }, "peerDependencies": { "@pandacss/dev": ">=0.40.0", + "@stylexjs/stylex": ">=0.18.0", "tailwind-merge": ">=2.0.0", "tailwindcss": ">=4.0.0" }, @@ -58,6 +67,9 @@ "@pandacss/dev": { "optional": true }, + "@stylexjs/stylex": { + "optional": true + }, "tailwind-merge": { "optional": true }, diff --git a/package/src/squircle.stylex.test.ts b/package/src/squircle.stylex.test.ts new file mode 100644 index 0000000..bef39eb --- /dev/null +++ b/package/src/squircle.stylex.test.ts @@ -0,0 +1,134 @@ +import { transformSync } from "@babel/core"; +import stylexPlugin from "@stylexjs/babel-plugin"; +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +/** + * Real-StyleX-compiler integration tests for `squircle.stylex.ts`. + * + * The package's source is fed through `@stylexjs/babel-plugin` to confirm: + * 1. The `stylex.create(...)` literal compiles (no static-analysis errors). + * 2. The emitted CSS contains the expected `@supports` block, `border-*-radius` + * properties, and `corner-shape: var(...)` for each variant. + * 3. Dynamic styles work — the runtime substitutes `radius` and `amt` via + * CSS custom properties. + * + * If a future StyleX release breaks the dynamic-style pattern, these tests + * will catch it before it reaches consumers. + */ + +interface Meta { + stylex?: Array<[string, { ltr: string; rtl?: string | null }, number]>; +} + +function compileFromSource(source: string, filename: string) { + const result = transformSync(source, { + filename, + babelrc: false, + configFile: false, + presets: [["@babel/preset-typescript", { allowDeclareFields: true }]], + plugins: [ + [ + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any + (stylexPlugin as any).default ?? stylexPlugin, + { + dev: false, + unstable_moduleResolution: { + type: "commonJS", + rootDir: import.meta.dirname, + }, + }, + ], + ], + }); + if (!result) throw new Error("babel returned null"); + const meta = (result.metadata ?? {}) as Meta; + return { + rules: meta.stylex ?? [], + code: result.code ?? "", + }; +} + +const MODULE_PATH = `${import.meta.dirname}/squircle.stylex.ts`; +const MODULE_SOURCE = readFileSync(MODULE_PATH, "utf8"); + +describe("squircle.stylex", () => { + const compiled = compileFromSource(MODULE_SOURCE, MODULE_PATH); + const css = compiled.rules.map((r) => r[1].ltr).join("\n"); + + it("compiles cleanly through the StyleX babel plugin", () => { + expect(compiled.rules.length).toBeGreaterThan(0); + expect(compiled.code).toContain("export const squircle"); + }); + + it("emits @supports-gated rules for the all-corners variant", () => { + expect(css).toContain("@supports (corner-shape: superellipse(2))"); + // border-radius shorthand and cornerShape both appear. + expect(css).toMatch(/border-radius:var\(--/); + expect(css).toMatch(/corner-shape:var\(--/); + }); + + it("emits per-side properties for the top variant", () => { + expect(css).toMatch(/border-top-left-radius:var\(--/); + expect(css).toMatch(/border-top-right-radius:var\(--/); + }); + + it("emits per-side properties for the right/bottom/left variants", () => { + expect(css).toMatch(/border-bottom-right-radius:var\(--/); + expect(css).toMatch(/border-bottom-left-radius:var\(--/); + }); + + it("emits logical-side properties for start/end variants", () => { + expect(css).toMatch(/border-start-start-radius:var\(--/); + expect(css).toMatch(/border-start-end-radius:var\(--/); + expect(css).toMatch(/border-end-start-radius:var\(--/); + expect(css).toMatch(/border-end-end-radius:var\(--/); + }); + + it("emits a runtime that injects --x-* custom properties from each variant's args", () => { + // The babel plugin lowers `(radius, amt) => ({...})` to a runtime that + // returns `[classObj, varObj]`. Every variant should emit a function. + expect(compiled.code).toMatch(/all:\s*\(radius/); + expect(compiled.code).toMatch(/topLeft:\s*\(radius/); + expect(compiled.code).toMatch(/endEnd:\s*\(radius/); + // Variables get unique --x-* names. + expect(compiled.code).toMatch(/"--x-/); + }); + + it("inlines the corrected-radius calc into the @supports branch", () => { + // The dynamic-style runtime should set a CSS var to the calc expression + // built from the radius and amt arguments. + expect(compiled.code).toContain("calc("); + expect(compiled.code).toContain("(1 - pow(2, -0.5))"); + expect(compiled.code).toContain("pow(2, -1 *"); + }); + + it("uses the var(--squircle-amt, 2) default for amt", () => { + expect(compiled.code).toContain("var(--squircle-amt, 2)"); + }); + + it("emits all 15 variants", () => { + const variantNames = [ + "all", + "top", + "right", + "bottom", + "left", + "start", + "end", + "topLeft", + "topRight", + "bottomRight", + "bottomLeft", + "startStart", + "startEnd", + "endStart", + "endEnd", + ]; + for (const name of variantNames) { + expect(compiled.code, `variant '${name}' should be present`).toMatch( + new RegExp(`${name}:\\s*\\(radius`), + ); + } + }); +}); diff --git a/package/src/squircle.stylex.ts b/package/src/squircle.stylex.ts new file mode 100644 index 0000000..16cfe84 --- /dev/null +++ b/package/src/squircle.stylex.ts @@ -0,0 +1,227 @@ +import * as stylex from "@stylexjs/stylex"; + +/** + * StyleX squircle utilities. + * + * Each entry is a *dynamic* style — a function that takes a `radius` (and an + * optional superellipse `amt`) and produces a `borderRadius` + `cornerShape` + * pair gated behind `@supports (corner-shape: superellipse(2))`. Browsers that + * don't support `corner-shape` fall back to a plain rounded rectangle at the + * same radius. + * + * ```tsx + * import * as stylex from '@stylexjs/stylex'; + * import { squircle } from '@klinking/squircle/stylex'; + * + *
+ *
+ * ``` + * + * If `amt` is omitted, the corrected radius and `corner-shape` resolve through + * `var(--squircle-amt, 2)` — set that custom property anywhere up the cascade + * to drive the superellipse exponent globally. + * + * **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to receive + * a fully-static object literal, and forbids destructuring, spreading, or + * default values on dynamic-style function parameters. The whole 15-variant + * table is therefore spelled out here verbatim. Keep it that way; tooling + * relies on every variant being statically analyzable at this call site. + */ +export const squircle = stylex.create({ + all: (radius: string | number, amt: string | number | undefined) => ({ + borderRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + // --- Per-side physical variants --- + + top: (radius: string | number, amt: string | number | undefined) => ({ + borderTopLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + borderTopRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + right: (radius: string | number, amt: string | number | undefined) => ({ + borderTopRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + borderBottomRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + bottom: (radius: string | number, amt: string | number | undefined) => ({ + borderBottomLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + borderBottomRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + left: (radius: string | number, amt: string | number | undefined) => ({ + borderTopLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + borderBottomLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + // --- Per-side logical variants --- + + start: (radius: string | number, amt: string | number | undefined) => ({ + borderStartStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + borderEndStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + end: (radius: string | number, amt: string | number | undefined) => ({ + borderStartEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + borderEndEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + // --- Per-corner physical variants --- + + topLeft: (radius: string | number, amt: string | number | undefined) => ({ + borderTopLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + topRight: (radius: string | number, amt: string | number | undefined) => ({ + borderTopRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + bottomRight: (radius: string | number, amt: string | number | undefined) => ({ + borderBottomRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + bottomLeft: (radius: string | number, amt: string | number | undefined) => ({ + borderBottomLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + // --- Per-corner logical variants --- + + startStart: (radius: string | number, amt: string | number | undefined) => ({ + borderStartStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + startEnd: (radius: string | number, amt: string | number | undefined) => ({ + borderStartEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + endStart: (radius: string | number, amt: string | number | undefined) => ({ + borderEndStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), + + endEnd: (radius: string | number, amt: string | number | undefined) => ({ + borderEndEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + }, + }), +}); diff --git a/package/vite.config.ts b/package/vite.config.ts index 454faaa..96b800f 100644 --- a/package/vite.config.ts +++ b/package/vite.config.ts @@ -11,6 +11,7 @@ export default defineConfig({ "tw-plugin": "./src/tw-plugin.ts", "tw-merge-cfg": "./src/tw-merge-cfg.ts", "panda-preset": "./src/panda-preset.ts", + stylex: "./src/squircle.stylex.ts", }, format: "esm", dts: true, @@ -31,9 +32,18 @@ export default defineConfig({ "test:panda": { command: "vp test run panda-preset", }, + "test:stylex": { + command: "vp test run squircle.stylex", + }, test: { command: "echo 'All tests passed'", - dependsOn: ["test:plugin", "test:css", "test:radius", "test:panda"], + dependsOn: [ + "test:plugin", + "test:css", + "test:radius", + "test:panda", + "test:stylex", + ], }, build: { command: "vp pack && tsx scripts/generate-squircle-css.ts", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 386df3f..a734c7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -76,6 +76,18 @@ importers: specifier: '>=4.0.0' version: 4.2.2 devDependencies: + '@babel/core': + specifier: ^7.29.0 + version: 7.29.0 + '@babel/preset-typescript': + specifier: ^7.28.0 + version: 7.28.5(@babel/core@7.29.0) + '@stylexjs/babel-plugin': + specifier: ^0.18.3 + version: 0.18.3 + '@stylexjs/stylex': + specifier: ^0.18.3 + version: 0.18.3 '@tailwindcss/vite': specifier: ^4.2.2 version: 4.2.2(@voidzero-dev/vite-plus-core@0.1.15(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) @@ -106,6 +118,12 @@ importers: '@astrojs/react': specifier: ^4 version: 4.4.2(@types/node@25.5.2)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(esbuild@0.27.7)(jiti@2.6.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@klinking/squircle': + specifier: workspace:* + version: link:../package + '@stylexjs/stylex': + specifier: ^0.18.3 + version: 0.18.3 astro: specifier: ^5 version: 5.18.1(@types/node@25.5.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) @@ -119,6 +137,18 @@ importers: specifier: ^19 version: 19.2.4(react@19.2.4) devDependencies: + '@babel/core': + specifier: ^7.29.0 + version: 7.29.0 + '@pandacss/dev': + specifier: ^1.11.0 + version: 1.11.0(typescript@5.9.3) + '@stylexjs/babel-plugin': + specifier: ^0.18.3 + version: 0.18.3 + '@stylexjs/dev-runtime': + specifier: ^0.11.1 + version: 0.11.1 '@tailwindcss/vite': specifier: ^4.2.2 version: 4.2.2(vite@8.0.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -214,14 +244,28 @@ packages: resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.28.6': resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} + '@babel/helper-create-class-features-plugin@7.29.3': + resolution: {integrity: sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.28.6': resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} @@ -232,10 +276,24 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.28.6': resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -257,6 +315,24 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -269,6 +345,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -307,6 +395,9 @@ packages: peerDependencies: postcss-selector-parser: ^7.0.0 + '@dual-bundle/import-meta-resolve@4.2.1': + resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} + '@emnapi/core@1.9.2': resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} @@ -1473,6 +1564,23 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@stylexjs/babel-plugin@0.18.3': + resolution: {integrity: sha512-5VeMIChNaXWlizLUL6c7WrMfuhydHXl3ASTlbj3O0qlEkNOlcgZMH3zzZ0iUrOSFTSgbHAOWUsVJKX5bFeZk4A==} + + '@stylexjs/dev-runtime@0.11.1': + resolution: {integrity: sha512-nbId4arvJcyj1zD6i6C+dZ8KQhb3pu6JNUzzyQ5mNe38xbAhmv2z7DDE7618Sim9Ar2fRaX1I67St1iLGqjt1Q==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + '@stylexjs/shared@0.11.1': + resolution: {integrity: sha512-siBoO0yg6KbhHbtkwWGhZWu0pH61gEAsdSYYv+vQRkaX3iSADByrqFuhD/KQku8AfKq78u5dWGc3FDA0H90VEw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + '@stylexjs/shared@0.18.3': + resolution: {integrity: sha512-g72AKGGhLTFsaez19zod2je9IQeaub2eM85jwJPvfmxymKW8Aleoxm5/pYIsnyxx3MZNOB5AVN6khfo90f9Lgw==} + + '@stylexjs/stylex@0.18.3': + resolution: {integrity: sha512-15gDzAJAorOE0yzxaWLNxldW2aqdmCiLG5QcPD8nmVCVqvrWp0Asgv45zk7LtN86WJb/4Ym9eQ6qT5MJW59tWQ==} + '@tailwindcss/node@4.2.2': resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} @@ -2186,6 +2294,9 @@ packages: resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} engines: {node: '>=12'} + css-mediaquery@0.1.2: + resolution: {integrity: sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==} + css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -2738,6 +2849,9 @@ packages: resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} engines: {node: '>=12'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ip-address@10.1.0: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} @@ -3064,6 +3178,10 @@ packages: look-it-up@2.1.0: resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -4071,6 +4189,9 @@ packages: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} + styleq@0.2.1: + resolution: {integrity: sha512-L0TR0NQb+X4/ktDEKmjWyp27gla+LUYi/by5k5SjKXf6/pvZP7wbwEB5J+tqxdFVPgzbsuz+d4RTScO/QZquBw==} + super-regex@1.1.0: resolution: {integrity: sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==} engines: {node: '>=18'} @@ -4795,6 +4916,10 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + '@babel/helper-compilation-targets@7.28.6': dependencies: '@babel/compat-data': 7.29.0 @@ -4803,8 +4928,28 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.29.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/helper-globals@7.28.0': {} + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.28.6': dependencies: '@babel/traverse': 7.29.0 @@ -4821,8 +4966,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + '@babel/helper-plugin-utils@7.28.6': {} + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} @@ -4838,6 +5003,24 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -4848,6 +5031,28 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 @@ -4899,6 +5104,8 @@ snapshots: dependencies: postcss-selector-parser: 7.1.1 + '@dual-bundle/import-meta-resolve@4.2.1': {} + '@emnapi/core@1.9.2': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -5503,6 +5710,26 @@ snapshots: postcss-selector-parser: 7.1.1 ts-pattern: 5.9.0 + '@pandacss/dev@1.11.0(typescript@5.9.3)': + dependencies: + '@clack/prompts': 0.11.0 + '@pandacss/config': 1.11.0 + '@pandacss/logger': 1.11.0 + '@pandacss/mcp': 1.11.0(typescript@5.9.3) + '@pandacss/node': 1.11.0(typescript@5.9.3) + '@pandacss/postcss': 1.11.0(typescript@5.9.3) + '@pandacss/preset-base': 1.11.0 + '@pandacss/preset-panda': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + cac: 6.7.14 + transitivePeerDependencies: + - '@cfworker/json-schema' + - jsdom + - supports-color + - typescript + '@pandacss/dev@1.11.0(typescript@6.0.2)': dependencies: '@clack/prompts': 0.11.0 @@ -5523,6 +5750,15 @@ snapshots: - supports-color - typescript + '@pandacss/extractor@1.11.0(typescript@5.9.3)': + dependencies: + '@pandacss/shared': 1.11.0 + ts-evaluator: 1.2.0(typescript@5.9.3) + ts-morph: 28.0.0 + transitivePeerDependencies: + - jsdom + - typescript + '@pandacss/extractor@1.11.0(typescript@6.0.2)': dependencies: '@pandacss/shared': 1.11.0 @@ -5553,6 +5789,21 @@ snapshots: '@pandacss/types': 1.11.0 kleur: 4.1.5 + '@pandacss/mcp@1.11.0(typescript@5.9.3)': + dependencies: + '@clack/prompts': 0.11.0 + '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.2) + '@pandacss/logger': 1.11.0 + '@pandacss/node': 1.11.0(typescript@5.9.3) + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + zod: 4.4.2 + transitivePeerDependencies: + - '@cfworker/json-schema' + - jsdom + - supports-color + - typescript + '@pandacss/mcp@1.11.0(typescript@6.0.2)': dependencies: '@clack/prompts': 0.11.0 @@ -5568,6 +5819,44 @@ snapshots: - supports-color - typescript + '@pandacss/node@1.11.0(typescript@5.9.3)': + dependencies: + '@pandacss/config': 1.11.0 + '@pandacss/core': 1.11.0 + '@pandacss/generator': 1.11.0 + '@pandacss/logger': 1.11.0 + '@pandacss/parser': 1.11.0(typescript@5.9.3) + '@pandacss/plugin-lightningcss': 1.11.0 + '@pandacss/plugin-svelte': 1.11.0 + '@pandacss/plugin-vue': 1.11.0 + '@pandacss/reporter': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/token-dictionary': 1.11.0 + '@pandacss/types': 1.11.0 + browserslist: 4.28.1 + chokidar: 4.0.3 + fast-glob: 3.3.3 + fs-extra: 11.3.2 + get-tsconfig: 4.13.7 + glob-parent: 6.0.2 + is-glob: 4.0.3 + lodash.merge: 4.6.2 + look-it-up: 2.1.0 + outdent: 0.8.0 + p-limit: 5.0.0 + package-manager-detector: 1.6.0 + perfect-debounce: 1.0.0 + picomatch: 4.0.4 + pkg-types: 2.3.0 + pluralize: 8.0.0 + postcss: 8.5.6 + prettier: 3.2.5 + ts-morph: 28.0.0 + ts-pattern: 5.9.0 + transitivePeerDependencies: + - jsdom + - typescript + '@pandacss/node@1.11.0(typescript@6.0.2)': dependencies: '@pandacss/config': 1.11.0 @@ -5606,6 +5895,20 @@ snapshots: - jsdom - typescript + '@pandacss/parser@1.11.0(typescript@5.9.3)': + dependencies: + '@pandacss/config': 1.11.0 + '@pandacss/core': 1.11.0 + '@pandacss/extractor': 1.11.0(typescript@5.9.3) + '@pandacss/logger': 1.11.0 + '@pandacss/shared': 1.11.0 + '@pandacss/types': 1.11.0 + ts-morph: 28.0.0 + ts-pattern: 5.9.0 + transitivePeerDependencies: + - jsdom + - typescript + '@pandacss/parser@1.11.0(typescript@6.0.2)': dependencies: '@pandacss/config': 1.11.0 @@ -5638,6 +5941,14 @@ snapshots: '@vue/compiler-sfc': 3.5.25 magic-string: 0.30.21 + '@pandacss/postcss@1.11.0(typescript@5.9.3)': + dependencies: + '@pandacss/node': 1.11.0(typescript@5.9.3) + postcss: 8.5.6 + transitivePeerDependencies: + - jsdom + - typescript + '@pandacss/postcss@1.11.0(typescript@6.0.2)': dependencies: '@pandacss/node': 1.11.0(typescript@6.0.2) @@ -5889,6 +6200,35 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@stylexjs/babel-plugin@0.18.3': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@dual-bundle/import-meta-resolve': 4.2.1 + '@stylexjs/shared': 0.18.3 + '@stylexjs/stylex': 0.18.3 + postcss-value-parser: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@stylexjs/dev-runtime@0.11.1': + dependencies: + '@stylexjs/shared': 0.11.1 + + '@stylexjs/shared@0.11.1': + dependencies: + postcss-value-parser: 4.2.0 + + '@stylexjs/shared@0.18.3': {} + + '@stylexjs/stylex@0.18.3': + dependencies: + css-mediaquery: 0.1.2 + invariant: 2.2.4 + styleq: 0.2.1 + '@tailwindcss/node@4.2.2': dependencies: '@jridgewell/remapping': 2.3.5 @@ -6703,6 +7043,8 @@ snapshots: dependencies: type-fest: 1.4.0 + css-mediaquery@0.1.2: {} + css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -7362,6 +7704,10 @@ snapshots: from2: 2.3.0 p-is-promise: 3.0.0 + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + ip-address@10.1.0: {} ipaddr.js@1.9.1: {} @@ -7586,6 +7932,10 @@ snapshots: look-it-up@2.1.0: {} + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + lru-cache@10.4.3: {} lru-cache@11.3.0: {} @@ -8839,6 +9189,8 @@ snapshots: strip-json-comments@2.0.1: {} + styleq@0.2.1: {} + super-regex@1.1.0: dependencies: function-timeout: 1.0.2 @@ -8939,6 +9291,13 @@ snapshots: ts-deepmerge@7.0.3: {} + ts-evaluator@1.2.0(typescript@5.9.3): + dependencies: + ansi-colors: 4.1.3 + crosspath: 2.0.0 + object-path: 0.11.8 + typescript: 5.9.3 + ts-evaluator@1.2.0(typescript@6.0.2): dependencies: ansi-colors: 4.1.3 From 306872bb7399b979edac1247c826357271548b5e Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 14:06:30 -0700 Subject: [PATCH 04/15] feat(website): add StyleX and Panda demo pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two new demo pages exercise the squircle preset on rectangles via each integration: `/demos/stylex` uses `stylex.props(squircle.all('1rem'))` and friends; `/demos/panda` uses `css({ squircle: 'md' })` shorthands. StyleX: a custom Vite plugin runs `@stylexjs/babel-plugin` on the package's compiled `dist/stylex.mjs` (which @vitejs/plugin-react skips since it's outside the source root), in addition to the inline plugin used for local `.tsx` files. Panda: configured with `prefix: 'pd'` so generated utilities cannot collide with the Tailwind classes used elsewhere on the site. A small Vite plugin runs `panda codegen` + `panda cssgen` at server start and re-runs cssgen on source-file HMR. `styled-system/` and `src/styles/panda.css` are gitignored — both are generated outputs. Co-Authored-By: Claude Opus 4.7 (1M context) --- website/.gitignore | 2 + website/astro.config.mjs | 99 ++++++++++++++++- website/package.json | 10 +- website/panda.config.ts | 19 ++++ website/src/components/PandaDemo.tsx | 154 ++++++++++++++++++++++++++ website/src/components/StyleXDemo.tsx | 154 ++++++++++++++++++++++++++ website/src/pages/demos/index.astro | 24 ++++ website/src/pages/demos/panda.astro | 26 +++++ website/src/pages/demos/stylex.astro | 27 +++++ 9 files changed, 512 insertions(+), 3 deletions(-) create mode 100644 website/.gitignore create mode 100644 website/panda.config.ts create mode 100644 website/src/components/PandaDemo.tsx create mode 100644 website/src/components/StyleXDemo.tsx create mode 100644 website/src/pages/demos/panda.astro create mode 100644 website/src/pages/demos/stylex.astro diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 0000000..93de9e1 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,2 @@ +styled-system/ +src/styles/panda.css diff --git a/website/astro.config.mjs b/website/astro.config.mjs index c51109d..1164155 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -1,10 +1,105 @@ import { defineConfig } from "astro/config"; import react from "@astrojs/react"; import tailwindcss from "@tailwindcss/vite"; +import babel from "@babel/core"; +import { execFileSync } from "node:child_process"; +import path from "node:path"; +import stylexPluginRaw from "@stylexjs/babel-plugin"; + +const stylexPlugin = stylexPluginRaw.default ?? stylexPluginRaw; + +const stylexBabelOpts = { + dev: true, + runtimeInjection: true, + unstable_moduleResolution: { + type: "commonJS", + rootDir: process.cwd(), + }, +}; + +/** + * Run `@stylexjs/babel-plugin` on files outside of `@vitejs/plugin-react`'s + * reach — notably the package's compiled `dist/stylex.mjs`, resolved through + * the pnpm workspace. + */ +function stylexForExternalModules() { + return { + name: "stylex-external", + enforce: "pre", + async transform(code, id) { + if (!/\.m?jsx?$|\.tsx?$/.test(id)) return null; + if ( + !id.includes("/package/dist/stylex.mjs") && + !id.includes("squircle.stylex.") + ) { + return null; + } + const result = await babel.transformAsync(code, { + filename: id, + babelrc: false, + configFile: false, + sourceMaps: true, + plugins: [[stylexPlugin, stylexBabelOpts]], + }); + if (!result?.code) return null; + return { code: result.code, map: result.map }; + }, + }; +} + +/** + * Run Panda's codegen + cssgen at server start, then re-run cssgen whenever a + * source file that might contain a `css({...})` call changes. The output is + * written to `src/styles/panda.css`, which the panda demo page imports. + */ +function pandaCodegen() { + const PANDA_BIN = path.resolve("node_modules/.bin/panda"); + const CSS_OUT = "src/styles/panda.css"; + + function codegen() { + execFileSync(PANDA_BIN, ["codegen"], { stdio: "inherit" }); + } + function cssgen() { + execFileSync(PANDA_BIN, ["cssgen", "--outfile", CSS_OUT], { + stdio: "inherit", + }); + } + + return { + name: "panda-codegen", + config() { + codegen(); + cssgen(); + }, + handleHotUpdate({ file }) { + if (file.endsWith("panda.config.ts")) { + codegen(); + cssgen(); + } else if ( + /\/src\/.*\.(?:tsx?|astro)$/.test(file) && + !file.endsWith("/src/styles/panda.css") + ) { + cssgen(); + } + }, + }; +} export default defineConfig({ - integrations: [react()], + integrations: [ + react({ + babel: { + plugins: [[stylexPlugin, stylexBabelOpts]], + }, + }), + ], vite: { - plugins: [tailwindcss()], + plugins: [pandaCodegen(), stylexForExternalModules(), tailwindcss()], + optimizeDeps: { + exclude: ["@klinking/squircle"], + }, + ssr: { + noExternal: ["@klinking/squircle"], + }, }, }); diff --git a/website/package.json b/website/package.json index df8c548..bd64486 100644 --- a/website/package.json +++ b/website/package.json @@ -4,16 +4,24 @@ "private": true, "type": "module", "scripts": { - "preview": "astro preview" + "preview": "astro preview", + "panda": "panda codegen", + "panda:watch": "panda codegen --watch" }, "dependencies": { "@astrojs/react": "^4", + "@klinking/squircle": "workspace:*", + "@stylexjs/stylex": "^0.18.3", "astro": "^5", "framer-motion": "^12.38.0", "react": "^19", "react-dom": "^19" }, "devDependencies": { + "@babel/core": "^7.29.0", + "@pandacss/dev": "^1.11.0", + "@stylexjs/babel-plugin": "^0.18.3", + "@stylexjs/dev-runtime": "^0.11.1", "@tailwindcss/vite": "^4.2.2", "@types/react": "^19", "@types/react-dom": "^19", diff --git a/website/panda.config.ts b/website/panda.config.ts new file mode 100644 index 0000000..b48e130 --- /dev/null +++ b/website/panda.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from "@pandacss/dev"; +import squirclePreset from "@klinking/squircle/panda-preset"; + +export default defineConfig({ + // Tailwind also runs on this site; prefix Panda's generated classes so they + // never collide with a tailwind utility (`pd-bg-rose-500` vs `bg-rose-500`). + prefix: "pd", + + preflight: false, + + jsxFramework: "react", + + presets: ["@pandacss/dev/presets", squirclePreset()], + + include: ["./src/**/*.{ts,tsx,astro}"], + exclude: [], + + outdir: "styled-system", +}); diff --git a/website/src/components/PandaDemo.tsx b/website/src/components/PandaDemo.tsx new file mode 100644 index 0000000..2534680 --- /dev/null +++ b/website/src/components/PandaDemo.tsx @@ -0,0 +1,154 @@ +import { css } from "../../styled-system/css"; + +const rect = css({ + width: "96px", + height: "96px", + backgroundImage: + "linear-gradient(135deg, token(colors.indigo.400), token(colors.violet.400))", +}); + +const rectAlt = css({ + width: "96px", + height: "96px", + backgroundImage: + "linear-gradient(135deg, token(colors.pink.400), token(colors.purple.400))", +}); + +const row = css({ + display: "flex", + gap: "24px", + flexWrap: "wrap", + alignItems: "flex-start", +}); + +const cell = css({ + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: "8px", +}); + +const label = css({ + fontSize: "12px", + color: "zinc.400", + fontFamily: "mono", + textAlign: "center", + maxWidth: "120px", +}); + +const heading = css({ + fontSize: "16px", + fontWeight: 600, + color: "zinc.300", + marginBottom: "16px", +}); + +const section = css({ + marginBottom: "40px", +}); + +function Cell({ label: l, className }: { label: string; className: string }) { + return ( +
+
+ {l} +
+ ); +} + +export default function PandaDemo() { + return ( +
+
+

All-corners (`squircle`) — varying radius

+
+ + + + +
+
+ +
+

+ Varying superellipse exponent via{" "} + squircleAmt +

+
+ + + + +
+
+ +
+

Per-side variants

+
+ + + + +
+
+ +
+

Per-corner variants

+
+ + + + +
+
+
+ ); +} diff --git a/website/src/components/StyleXDemo.tsx b/website/src/components/StyleXDemo.tsx new file mode 100644 index 0000000..d683778 --- /dev/null +++ b/website/src/components/StyleXDemo.tsx @@ -0,0 +1,154 @@ +import * as stylex from "@stylexjs/stylex"; +import { squircle } from "@klinking/squircle/stylex"; + +const styles = stylex.create({ + rect: { + width: 96, + height: 96, + backgroundImage: "linear-gradient(135deg, #818cf8, #a78bfa)", + }, + rectAlt: { + width: 96, + height: 96, + backgroundImage: "linear-gradient(135deg, #f472b6, #c084fc)", + }, + row: { + display: "flex", + gap: 24, + flexWrap: "wrap", + alignItems: "flex-start", + }, + cell: { + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: 8, + }, + label: { + fontSize: 12, + color: "#a1a1aa", + fontFamily: "ui-monospace, SFMono-Regular, monospace", + textAlign: "center", + maxWidth: 120, + }, + section: { + marginBottom: 40, + }, + heading: { + fontSize: 16, + fontWeight: 600, + color: "#d4d4d8", + marginBottom: 16, + }, +}); + +function Cell({ + label, + styleProps, +}: { + label: string; + styleProps: Readonly>; +}) { + return ( +
+
)} /> + {label} +
+ ); +} + +export default function StyleXDemo() { + return ( +
+
+

All-corners variant — varying radius

+
+ + + + +
+
+ +
+

+ Varying superellipse exponent (amt) +

+
+ + + + +
+
+ +
+

Per-side variants

+
+ + + + +
+
+ +
+

Per-corner variants

+
+ + + + +
+
+
+ ); +} diff --git a/website/src/pages/demos/index.astro b/website/src/pages/demos/index.astro index 7b289d3..481243d 100644 --- a/website/src/pages/demos/index.astro +++ b/website/src/pages/demos/index.astro @@ -22,5 +22,29 @@ import Layout from "../../components/Layout.astro";

+
  • + +

    StyleX

    +

    + Squircle utilities authored as StyleX dynamic styles — + stylex.props(squircle.all('1rem')). +

    +
    +
  • +
  • + +

    Panda CSS

    +

    + Squircle utilities via the Panda preset, prefixed to coexist with + Tailwind on the same page. +

    +
    +
  • diff --git a/website/src/pages/demos/panda.astro b/website/src/pages/demos/panda.astro new file mode 100644 index 0000000..21c8391 --- /dev/null +++ b/website/src/pages/demos/panda.astro @@ -0,0 +1,26 @@ +--- +import "../../styles/panda.css"; +import Layout from "../../components/Layout.astro"; +import PandaDemo from "../../components/PandaDemo"; +--- + + +

    Panda CSS

    +

    + Squircle utilities consumed via the Panda preset's squircle* shorthands. Panda is configured with prefix: 'pd' so its generated classes (e.g. .pd-bd-r_md) cannot collide with Tailwind utilities used elsewhere on this site. +

    + +
    {`import { css } from '../styled-system/css';
    +
    +
    +
    `}
    + + +
    diff --git a/website/src/pages/demos/stylex.astro b/website/src/pages/demos/stylex.astro new file mode 100644 index 0000000..7dfcffe --- /dev/null +++ b/website/src/pages/demos/stylex.astro @@ -0,0 +1,27 @@ +--- +import Layout from "../../components/Layout.astro"; +import StyleXDemo from "../../components/StyleXDemo"; +--- + + +

    StyleX

    +

    + Squircle utilities authored as StyleX dynamic styles. Each variant is a + function that takes a radius (and an optional + superellipse amt) and produces a + borderRadius + cornerShape pair gated behind @supports (corner-shape: superellipse(2)). +

    + +
    {`import * as stylex from '@stylexjs/stylex';
    +import { squircle } from '@klinking/squircle/stylex';
    +
    +
    +
    `}
    + + +
    From 56c95f08125da4b0d12ece2747d5102bb9afebac Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 14:52:13 -0700 Subject: [PATCH 05/15] feat(website): rewrite demos for visual + token consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename react-basic demo to "Tailwind" (it uses Tailwind, not plain CSS). - All three demo pages now follow the same visual structure: live in-page demo first, then the StackBlitz embed of the same code under an "Edit on StackBlitz" heading. The in-page demos all use the h-28 boxed layout from the original react-basic demo so the three pages look like the same demo re-implemented in three styling systems. - Drop the .raw-superellipse comparison column (only the rounded-vs-squircle comparison remains). - Add semantic color tokens — demoPlain / demoSquircle / demoAmount / demoCorner — natively in each system: Tailwind via @theme, StyleX via defineVars, Panda via semanticTokens. Same names + values everywhere, so the three demos render with the same color palette. - New StackBlitz example projects website/examples/stylex and website/examples/panda, each using its system's native tokens. Co-Authored-By: Claude Opus 4.7 (1M context) --- website/examples/panda/.gitignore | 2 + website/examples/panda/index.html | 12 + website/examples/panda/package.json | 22 ++ website/examples/panda/panda.config.ts | 26 ++ website/examples/panda/src/App.tsx | 181 ++++++++++++ website/examples/panda/src/main.tsx | 10 + website/examples/panda/tsconfig.json | 11 + website/examples/panda/vite.config.ts | 6 + website/examples/react-basic/src/styles.css | 7 - website/examples/stylex/index.html | 12 + website/examples/stylex/package.json | 25 ++ website/examples/stylex/src/App.tsx | 149 ++++++++++ website/examples/stylex/src/colors.stylex.ts | 8 + .../{react-basic => stylex}/src/main.tsx | 0 website/examples/stylex/src/radii.stylex.ts | 10 + website/examples/stylex/src/styles.css | 1 + .../{react-basic => stylex}/tsconfig.json | 0 website/examples/stylex/vite.config.ts | 48 ++++ .../{react-basic => tailwind}/index.html | 0 .../{react-basic => tailwind}/package.json | 2 +- .../{react-basic => tailwind}/src/App.tsx | 60 ++-- website/examples/tailwind/src/main.tsx | 10 + website/examples/tailwind/src/styles.css | 9 + website/examples/tailwind/tsconfig.json | 11 + .../{react-basic => tailwind}/vite.config.ts | 0 website/panda.config.ts | 16 ++ website/src/components/PandaDemo.tsx | 256 +++++++++-------- website/src/components/StyleXDemo.tsx | 269 ++++++++++-------- website/src/components/TailwindDemo.tsx | 90 ++++++ website/src/components/colors.stylex.ts | 12 + website/src/components/radii.stylex.ts | 15 + website/src/pages/demos/index.astro | 4 +- website/src/pages/demos/panda.astro | 26 +- website/src/pages/demos/stylex.astro | 20 +- .../{react-basic.astro => tailwind.astro} | 13 +- website/src/styles/global.css | 8 + 36 files changed, 1053 insertions(+), 298 deletions(-) create mode 100644 website/examples/panda/.gitignore create mode 100644 website/examples/panda/index.html create mode 100644 website/examples/panda/package.json create mode 100644 website/examples/panda/panda.config.ts create mode 100644 website/examples/panda/src/App.tsx create mode 100644 website/examples/panda/src/main.tsx create mode 100644 website/examples/panda/tsconfig.json create mode 100644 website/examples/panda/vite.config.ts delete mode 100644 website/examples/react-basic/src/styles.css create mode 100644 website/examples/stylex/index.html create mode 100644 website/examples/stylex/package.json create mode 100644 website/examples/stylex/src/App.tsx create mode 100644 website/examples/stylex/src/colors.stylex.ts rename website/examples/{react-basic => stylex}/src/main.tsx (100%) create mode 100644 website/examples/stylex/src/radii.stylex.ts create mode 100644 website/examples/stylex/src/styles.css rename website/examples/{react-basic => stylex}/tsconfig.json (100%) create mode 100644 website/examples/stylex/vite.config.ts rename website/examples/{react-basic => tailwind}/index.html (100%) rename website/examples/{react-basic => tailwind}/package.json (91%) rename website/examples/{react-basic => tailwind}/src/App.tsx (70%) create mode 100644 website/examples/tailwind/src/main.tsx create mode 100644 website/examples/tailwind/src/styles.css create mode 100644 website/examples/tailwind/tsconfig.json rename website/examples/{react-basic => tailwind}/vite.config.ts (100%) create mode 100644 website/src/components/TailwindDemo.tsx create mode 100644 website/src/components/colors.stylex.ts create mode 100644 website/src/components/radii.stylex.ts rename website/src/pages/demos/{react-basic.astro => tailwind.astro} (63%) diff --git a/website/examples/panda/.gitignore b/website/examples/panda/.gitignore new file mode 100644 index 0000000..ec77d39 --- /dev/null +++ b/website/examples/panda/.gitignore @@ -0,0 +1,2 @@ +styled-system/ +src/styles.generated.css diff --git a/website/examples/panda/index.html b/website/examples/panda/index.html new file mode 100644 index 0000000..6a29d3f --- /dev/null +++ b/website/examples/panda/index.html @@ -0,0 +1,12 @@ + + + + + + squircle Panda Demo + + +
    + + + diff --git a/website/examples/panda/package.json b/website/examples/panda/package.json new file mode 100644 index 0000000..69f4b53 --- /dev/null +++ b/website/examples/panda/package.json @@ -0,0 +1,22 @@ +{ + "name": "squircle-panda-demo", + "private": true, + "type": "module", + "scripts": { + "prepare": "panda codegen && panda cssgen --outfile src/styles.generated.css", + "dev": "panda --watch & vite" + }, + "dependencies": { + "@klinking/squircle": "latest", + "react": "^19", + "react-dom": "^19" + }, + "devDependencies": { + "@pandacss/dev": "^1.11.0", + "@types/react": "^19", + "@types/react-dom": "^19", + "@vitejs/plugin-react": "^4", + "typescript": "^5", + "vite": "^6" + } +} diff --git a/website/examples/panda/panda.config.ts b/website/examples/panda/panda.config.ts new file mode 100644 index 0000000..5021a51 --- /dev/null +++ b/website/examples/panda/panda.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from "@pandacss/dev"; +import squirclePreset from "@klinking/squircle/panda-preset"; + +export default defineConfig({ + prefix: "pd", + preflight: true, + jsxFramework: "react", + presets: ["@pandacss/dev/presets", squirclePreset()], + + theme: { + extend: { + semanticTokens: { + colors: { + demoPlain: { value: "#4f46e5" }, + demoSquircle: { value: "#db2777" }, + demoAmount: { value: "#059669" }, + demoCorner: { value: "#7c3aed" }, + }, + }, + }, + }, + + include: ["./src/**/*.{ts,tsx}"], + exclude: [], + outdir: "styled-system", +}); diff --git a/website/examples/panda/src/App.tsx b/website/examples/panda/src/App.tsx new file mode 100644 index 0000000..10edb1c --- /dev/null +++ b/website/examples/panda/src/App.tsx @@ -0,0 +1,181 @@ +import { css, cx } from "../styled-system/css"; + +function Box({ label, className }: { label: string; className: string }) { + return ( +
    +
    + + {label} + +
    + ); +} + +const root = css({ + minHeight: "100vh", + backgroundColor: "zinc.950", + padding: "40px", + color: "zinc.100", +}); + +const heading = css({ + marginBottom: "8px", + fontSize: "24px", + fontWeight: 700, +}); + +const lead = css({ + marginBottom: "32px", + color: "zinc.400", +}); + +const stack = css({ display: "flex", flexDirection: "column", gap: "40px" }); +const sectionH = css({ + marginBottom: "16px", + fontSize: "18px", + fontWeight: 600, + color: "zinc.300", +}); +const row = css({ display: "flex", gap: "24px", flexWrap: "wrap" }); + +export default function App() { + return ( +
    +

    squircle Panda Demo

    +

    Squircle utilities consumed via the Panda preset.

    + +
    +
    +

    Small radius

    +
    + + +
    +
    + +
    +

    Medium radius

    +
    + + +
    +
    + +
    +

    Large radius

    +
    + + +
    +
    + +
    +

    Squircle amount via squircleAmt

    +

    + Higher = more square. Default is 2. +

    +
    + + + + + +
    +
    + +
    +

    Per-corner squircles

    +
    + + + + + + +
    +
    +
    +
    + ); +} diff --git a/website/examples/panda/src/main.tsx b/website/examples/panda/src/main.tsx new file mode 100644 index 0000000..cc101b0 --- /dev/null +++ b/website/examples/panda/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import App from "./App"; +import "./styles.generated.css"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/website/examples/panda/tsconfig.json b/website/examples/panda/tsconfig.json new file mode 100644 index 0000000..0f1c3fe --- /dev/null +++ b/website/examples/panda/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true + }, + "include": ["src", "styled-system"] +} diff --git a/website/examples/panda/vite.config.ts b/website/examples/panda/vite.config.ts new file mode 100644 index 0000000..081c8d9 --- /dev/null +++ b/website/examples/panda/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [react()], +}); diff --git a/website/examples/react-basic/src/styles.css b/website/examples/react-basic/src/styles.css deleted file mode 100644 index a4046b9..0000000 --- a/website/examples/react-basic/src/styles.css +++ /dev/null @@ -1,7 +0,0 @@ -@import "tailwindcss"; -@import "@klinking/squircle/tw-utils.css"; - -/* Raw superellipse with no radius correction — shows the problem */ -.raw-superellipse { - corner-shape: superellipse; -} diff --git a/website/examples/stylex/index.html b/website/examples/stylex/index.html new file mode 100644 index 0000000..7eec328 --- /dev/null +++ b/website/examples/stylex/index.html @@ -0,0 +1,12 @@ + + + + + + squircle StyleX Demo + + +
    + + + diff --git a/website/examples/stylex/package.json b/website/examples/stylex/package.json new file mode 100644 index 0000000..c90c364 --- /dev/null +++ b/website/examples/stylex/package.json @@ -0,0 +1,25 @@ +{ + "name": "squircle-stylex-demo", + "private": true, + "type": "module", + "scripts": { + "dev": "vite" + }, + "dependencies": { + "@klinking/squircle": "latest", + "@stylexjs/stylex": "^0.18.3", + "react": "^19", + "react-dom": "^19" + }, + "devDependencies": { + "@stylexjs/babel-plugin": "^0.18.3", + "@stylexjs/dev-runtime": "^0.11.1", + "@tailwindcss/vite": "^4", + "@types/react": "^19", + "@types/react-dom": "^19", + "@vitejs/plugin-react": "^4", + "tailwindcss": "^4", + "typescript": "^5", + "vite": "^6" + } +} diff --git a/website/examples/stylex/src/App.tsx b/website/examples/stylex/src/App.tsx new file mode 100644 index 0000000..fff9a17 --- /dev/null +++ b/website/examples/stylex/src/App.tsx @@ -0,0 +1,149 @@ +import * as stylex from "@stylexjs/stylex"; +import { squircle } from "@klinking/squircle/stylex"; +import { radii } from "./radii.stylex"; +import { colors } from "./colors.stylex"; + +const swatch = stylex.create({ + plain: { backgroundColor: colors.demoPlain }, + squircle: { backgroundColor: colors.demoSquircle }, + amount: { backgroundColor: colors.demoAmount }, + corner: { backgroundColor: colors.demoCorner }, +}); + +const plainRadius = stylex.create({ + lg: { borderRadius: radii.lg }, + "2xl": { borderRadius: radii["2xl"] }, + "3xl": { borderRadius: radii["3xl"] }, +}); + +function Box({ + label, + styleProps, +}: { + label: string; + styleProps: ReturnType; +}) { + return ( +
    +
    + {label} +
    + ); +} + +export default function App() { + return ( +
    +

    squircle StyleX Demo

    +

    + Squircle utilities authored as StyleX dynamic styles. +

    + +
    +
    +

    Small radius

    +
    + + +
    +
    + +
    +

    Medium radius

    +
    + + +
    +
    + +
    +

    Large radius

    +
    + + +
    +
    + +
    +

    Squircle amount

    +

    + Higher = more square. Default is 2. +

    +
    + + + + + +
    +
    + +
    +

    Per-corner squircles

    +
    + + + + + + +
    +
    +
    +
    + ); +} diff --git a/website/examples/stylex/src/colors.stylex.ts b/website/examples/stylex/src/colors.stylex.ts new file mode 100644 index 0000000..5ea2288 --- /dev/null +++ b/website/examples/stylex/src/colors.stylex.ts @@ -0,0 +1,8 @@ +import * as stylex from "@stylexjs/stylex"; + +export const colors = stylex.defineVars({ + demoPlain: "#4f46e5", + demoSquircle: "#db2777", + demoAmount: "#059669", + demoCorner: "#7c3aed", +}); diff --git a/website/examples/react-basic/src/main.tsx b/website/examples/stylex/src/main.tsx similarity index 100% rename from website/examples/react-basic/src/main.tsx rename to website/examples/stylex/src/main.tsx diff --git a/website/examples/stylex/src/radii.stylex.ts b/website/examples/stylex/src/radii.stylex.ts new file mode 100644 index 0000000..68d4156 --- /dev/null +++ b/website/examples/stylex/src/radii.stylex.ts @@ -0,0 +1,10 @@ +import * as stylex from "@stylexjs/stylex"; + +export const radii = stylex.defineVars({ + sm: "0.25rem", + md: "0.375rem", + lg: "0.5rem", + xl: "0.75rem", + "2xl": "1rem", + "3xl": "1.5rem", +}); diff --git a/website/examples/stylex/src/styles.css b/website/examples/stylex/src/styles.css new file mode 100644 index 0000000..f1d8c73 --- /dev/null +++ b/website/examples/stylex/src/styles.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/website/examples/react-basic/tsconfig.json b/website/examples/stylex/tsconfig.json similarity index 100% rename from website/examples/react-basic/tsconfig.json rename to website/examples/stylex/tsconfig.json diff --git a/website/examples/stylex/vite.config.ts b/website/examples/stylex/vite.config.ts new file mode 100644 index 0000000..c94aae1 --- /dev/null +++ b/website/examples/stylex/vite.config.ts @@ -0,0 +1,48 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; +import babel from "@babel/core"; +import stylexPluginRaw from "@stylexjs/babel-plugin"; + +const stylexPlugin = (stylexPluginRaw as { default?: unknown }).default ?? stylexPluginRaw; + +const stylexBabelOpts = { + dev: true, + runtimeInjection: true, + unstable_moduleResolution: { type: "commonJS", rootDir: process.cwd() }, +}; + +/** + * Run @stylexjs/babel-plugin on `@klinking/squircle/stylex` (which @vitejs/plugin-react + * skips because it lives inside node_modules). + */ +function stylexForExternalModules() { + return { + name: "stylex-external", + enforce: "pre" as const, + async transform(code: string, id: string) { + if (!/\.m?jsx?$|\.tsx?$/.test(id)) return null; + if (!id.includes("@klinking/squircle/dist/stylex.mjs")) return null; + const result = await babel.transformAsync(code, { + filename: id, + babelrc: false, + configFile: false, + sourceMaps: true, + plugins: [[stylexPlugin, stylexBabelOpts]], + }); + if (!result?.code) return null; + return { code: result.code, map: result.map }; + }, + }; +} + +export default defineConfig({ + plugins: [ + react({ + babel: { plugins: [[stylexPlugin, stylexBabelOpts]] }, + }), + stylexForExternalModules(), + tailwindcss(), + ], + optimizeDeps: { exclude: ["@klinking/squircle"] }, +}); diff --git a/website/examples/react-basic/index.html b/website/examples/tailwind/index.html similarity index 100% rename from website/examples/react-basic/index.html rename to website/examples/tailwind/index.html diff --git a/website/examples/react-basic/package.json b/website/examples/tailwind/package.json similarity index 91% rename from website/examples/react-basic/package.json rename to website/examples/tailwind/package.json index 323b25b..8b30b45 100644 --- a/website/examples/react-basic/package.json +++ b/website/examples/tailwind/package.json @@ -1,5 +1,5 @@ { - "name": "squircle-react-basic-demo", + "name": "squircle-tailwind-demo", "private": true, "type": "module", "scripts": { diff --git a/website/examples/react-basic/src/App.tsx b/website/examples/tailwind/src/App.tsx similarity index 70% rename from website/examples/react-basic/src/App.tsx rename to website/examples/tailwind/src/App.tsx index 0ed18d0..b891eee 100644 --- a/website/examples/react-basic/src/App.tsx +++ b/website/examples/tailwind/src/App.tsx @@ -19,36 +19,24 @@ export default function App() {

    Small radius

    - - - + +

    Medium radius

    - - - + +

    Large radius

    - - - + +
    @@ -62,20 +50,20 @@ export default function App() {
    - +
    @@ -83,24 +71,24 @@ export default function App() {

    Per-corner squircles

    - - - - - - + + + + + +
    -

    Per-corner squircles

    +

    Logical-side squircles

    - - - - - - + + + + + +
    diff --git a/website/examples/tailwind/src/main.tsx b/website/examples/tailwind/src/main.tsx new file mode 100644 index 0000000..693ac2e --- /dev/null +++ b/website/examples/tailwind/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import App from "./App"; +import "./styles.css"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/website/examples/tailwind/src/styles.css b/website/examples/tailwind/src/styles.css new file mode 100644 index 0000000..65f7d7d --- /dev/null +++ b/website/examples/tailwind/src/styles.css @@ -0,0 +1,9 @@ +@import "tailwindcss"; +@import "@klinking/squircle/tw-utils.css"; + +@theme { + --color-demo-plain: #4f46e5; + --color-demo-squircle: #db2777; + --color-demo-amount: #059669; + --color-demo-corner: #7c3aed; +} diff --git a/website/examples/tailwind/tsconfig.json b/website/examples/tailwind/tsconfig.json new file mode 100644 index 0000000..db98a13 --- /dev/null +++ b/website/examples/tailwind/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/website/examples/react-basic/vite.config.ts b/website/examples/tailwind/vite.config.ts similarity index 100% rename from website/examples/react-basic/vite.config.ts rename to website/examples/tailwind/vite.config.ts diff --git a/website/panda.config.ts b/website/panda.config.ts index b48e130..729186b 100644 --- a/website/panda.config.ts +++ b/website/panda.config.ts @@ -12,6 +12,22 @@ export default defineConfig({ presets: ["@pandacss/dev/presets", squirclePreset()], + // Semantic colors used by the demo boxes — names line up with the StyleX + // and Tailwind demos so the same logical concept is the same color in all + // three styling systems. + theme: { + extend: { + semanticTokens: { + colors: { + demoPlain: { value: "#4f46e5" }, + demoSquircle: { value: "#db2777" }, + demoAmount: { value: "#059669" }, + demoCorner: { value: "#7c3aed" }, + }, + }, + }, + }, + include: ["./src/**/*.{ts,tsx,astro}"], exclude: [], diff --git a/website/src/components/PandaDemo.tsx b/website/src/components/PandaDemo.tsx index 2534680..8c727a1 100644 --- a/website/src/components/PandaDemo.tsx +++ b/website/src/components/PandaDemo.tsx @@ -1,151 +1,181 @@ -import { css } from "../../styled-system/css"; +import { css, cx } from "../../styled-system/css"; -const rect = css({ - width: "96px", - height: "96px", - backgroundImage: - "linear-gradient(135deg, token(colors.indigo.400), token(colors.violet.400))", +const boxBase = css({ + width: "112px", + height: "112px", }); -const rectAlt = css({ - width: "96px", - height: "96px", - backgroundImage: - "linear-gradient(135deg, token(colors.pink.400), token(colors.purple.400))", -}); - -const row = css({ - display: "flex", - gap: "24px", - flexWrap: "wrap", - alignItems: "flex-start", -}); - -const cell = css({ +const cellLayout = css({ display: "flex", flexDirection: "column", alignItems: "center", gap: "8px", }); -const label = css({ +const labelStyle = css({ + maxWidth: "112px", + textAlign: "center", fontSize: "12px", color: "zinc.400", - fontFamily: "mono", - textAlign: "center", - maxWidth: "120px", -}); - -const heading = css({ - fontSize: "16px", - fontWeight: 600, - color: "zinc.300", - marginBottom: "16px", }); -const section = css({ - marginBottom: "40px", -}); - -function Cell({ label: l, className }: { label: string; className: string }) { +function Box({ label, className }: { label: string; className: string }) { return ( -
    -
    - {l} +
    +
    + {label}
    ); } export default function PandaDemo() { return ( -
    -
    -

    All-corners (`squircle`) — varying radius

    -
    - - - - +
    +

    Small radius

    +
    + +
    -
    -

    - Varying superellipse exponent via{" "} - squircleAmt -

    -
    - - - - +

    Medium radius

    +
    + +
    -
    -

    Per-side variants

    -
    - +

    Large radius

    +
    + + +
    +
    + +
    +

    + Squircle amount via squircleAmt +

    +

    + Controls the superellipse exponent. Higher = more square. Default is 2. +

    +
    + + + + + +
    +
    + +
    +

    Per-corner squircles

    +
    + + + - - -
    -
    -

    Per-corner variants

    -
    - - - - +

    Logical-side squircles

    +
    + + + + + +
    diff --git a/website/src/components/StyleXDemo.tsx b/website/src/components/StyleXDemo.tsx index d683778..e6e3827 100644 --- a/website/src/components/StyleXDemo.tsx +++ b/website/src/components/StyleXDemo.tsx @@ -1,151 +1,186 @@ import * as stylex from "@stylexjs/stylex"; import { squircle } from "@klinking/squircle/stylex"; +import { radii } from "./radii.stylex"; +import { colors } from "./colors.stylex"; -const styles = stylex.create({ - rect: { - width: 96, - height: 96, - backgroundImage: "linear-gradient(135deg, #818cf8, #a78bfa)", - }, - rectAlt: { - width: 96, - height: 96, - backgroundImage: "linear-gradient(135deg, #f472b6, #c084fc)", - }, - row: { - display: "flex", - gap: 24, - flexWrap: "wrap", - alignItems: "flex-start", - }, - cell: { - display: "flex", - flexDirection: "column", - alignItems: "center", - gap: 8, - }, - label: { - fontSize: 12, - color: "#a1a1aa", - fontFamily: "ui-monospace, SFMono-Regular, monospace", - textAlign: "center", - maxWidth: 120, - }, - section: { - marginBottom: 40, - }, - heading: { - fontSize: 16, - fontWeight: 600, - color: "#d4d4d8", - marginBottom: 16, - }, +const swatch = stylex.create({ + plain: { backgroundColor: colors.demoPlain }, + squircle: { backgroundColor: colors.demoSquircle }, + amount: { backgroundColor: colors.demoAmount }, + corner: { backgroundColor: colors.demoCorner }, }); -function Cell({ +const plainRadius = stylex.create({ + lg: { borderRadius: radii.lg }, + "2xl": { borderRadius: radii["2xl"] }, + "3xl": { borderRadius: radii["3xl"] }, +}); + +function Box({ label, - styleProps, + className, + style, }: { label: string; - styleProps: Readonly>; + className: string; + style?: React.CSSProperties; }) { return ( -
    -
    )} /> - {label} +
    +
    + {label}
    ); } +function StylexBox({ + label, + styleProps, +}: { + label: string; + styleProps: ReturnType; +}) { + return ( + + ); +} + export default function StyleXDemo() { return ( -
    -
    -

    All-corners variant — varying radius

    -
    - - - - +
    +

    Small radius

    +
    + +
    -
    -

    - Varying superellipse exponent (amt) -

    -
    - - - - +

    Medium radius

    +
    + + +
    +
    + +
    +

    Large radius

    +
    + +
    -
    -

    Per-side variants

    -
    - +

    + Squircle amount (the superellipse exponent) +

    +

    + Controls the superellipse exponent. Higher = more square. Default is 2. +

    +
    + + + + + +
    +
    + +
    +

    Per-corner squircles

    +
    + + + - - -
    -
    -

    Per-corner variants

    -
    - - - - +

    Logical-side squircles

    +
    + + + + + +
    diff --git a/website/src/components/TailwindDemo.tsx b/website/src/components/TailwindDemo.tsx new file mode 100644 index 0000000..e6b944e --- /dev/null +++ b/website/src/components/TailwindDemo.tsx @@ -0,0 +1,90 @@ +function Box({ label, className }: { label: string; className: string }) { + return ( +
    +
    + {label} +
    + ); +} + +export default function TailwindDemo() { + return ( +
    +
    +

    Small radius

    +
    + + +
    +
    + +
    +

    Medium radius

    +
    + + +
    +
    + +
    +

    Large radius

    +
    + + +
    +
    + +
    +

    + Squircle amount (squircle-amt-*) +

    +

    + Controls the superellipse exponent. Higher = more square. Default is 2. +

    +
    + + + + + +
    +
    + +
    +

    Per-corner squircles

    +
    + + + + + + +
    +
    + +
    +

    Logical-side squircles

    +
    + + + + + + +
    +
    +
    + ); +} diff --git a/website/src/components/colors.stylex.ts b/website/src/components/colors.stylex.ts new file mode 100644 index 0000000..03087a9 --- /dev/null +++ b/website/src/components/colors.stylex.ts @@ -0,0 +1,12 @@ +import * as stylex from "@stylexjs/stylex"; + +/** + * Semantic demo colors. Each token names what the box is showing, so the same + * logical names line up across Tailwind / StyleX / Panda demos. + */ +export const colors = stylex.defineVars({ + demoPlain: "#4f46e5", + demoSquircle: "#db2777", + demoAmount: "#059669", + demoCorner: "#7c3aed", +}); diff --git a/website/src/components/radii.stylex.ts b/website/src/components/radii.stylex.ts new file mode 100644 index 0000000..af73ddb --- /dev/null +++ b/website/src/components/radii.stylex.ts @@ -0,0 +1,15 @@ +import * as stylex from "@stylexjs/stylex"; + +/** + * Radii tokens mirroring Panda's default `radii` scale, declared via + * `stylex.defineVars` so the StyleX demo can pass `radii.md` etc. into + * `squircle.all(...)` instead of hard-coded rem strings. + */ +export const radii = stylex.defineVars({ + sm: "0.25rem", + md: "0.375rem", + lg: "0.5rem", + xl: "0.75rem", + "2xl": "1rem", + "3xl": "1.5rem", +}); diff --git a/website/src/pages/demos/index.astro b/website/src/pages/demos/index.astro index 481243d..c38a1df 100644 --- a/website/src/pages/demos/index.astro +++ b/website/src/pages/demos/index.astro @@ -12,10 +12,10 @@ import Layout from "../../components/Layout.astro";
    • -

      React + CSS-only

      +

      Tailwind

      Compare regular rounded corners with squircle corners at different radii using Tailwind CSS utilities. diff --git a/website/src/pages/demos/panda.astro b/website/src/pages/demos/panda.astro index 21c8391..105ece3 100644 --- a/website/src/pages/demos/panda.astro +++ b/website/src/pages/demos/panda.astro @@ -1,26 +1,32 @@ --- import "../../styles/panda.css"; import Layout from "../../components/Layout.astro"; +import DemoEmbed from "../../components/DemoEmbed"; import PandaDemo from "../../components/PandaDemo"; ---

      Panda CSS

      -

      +

      Squircle utilities consumed via the Panda preset's squircle* shorthands. Panda is configured with prefix: 'pd' so its generated classes (e.g. .pd-bd-r_md) cannot collide with Tailwind utilities used elsewhere on this site. + > so its generated classes cannot collide with Tailwind utilities used elsewhere + on this site.

      -
      {`import { css } from '../styled-system/css';
      -
      -
      -
      `}
      - + +

      Edit on StackBlitz

      + +

      + Powered by StackBlitz. + Requires a Chromium-based browser. +

      diff --git a/website/src/pages/demos/stylex.astro b/website/src/pages/demos/stylex.astro index 7dfcffe..fe01bf8 100644 --- a/website/src/pages/demos/stylex.astro +++ b/website/src/pages/demos/stylex.astro @@ -1,5 +1,6 @@ --- import Layout from "../../components/Layout.astro"; +import DemoEmbed from "../../components/DemoEmbed"; import StyleXDemo from "../../components/StyleXDemo"; --- @@ -16,12 +17,17 @@ import StyleXDemo from "../../components/StyleXDemo"; >.

      -
      {`import * as stylex from '@stylexjs/stylex';
      -import { squircle } from '@klinking/squircle/stylex';
      -
      -
      -
      `}
      - + +

      Edit on StackBlitz

      + +

      + Powered by StackBlitz. + Requires a Chromium-based browser. +

      diff --git a/website/src/pages/demos/react-basic.astro b/website/src/pages/demos/tailwind.astro similarity index 63% rename from website/src/pages/demos/react-basic.astro rename to website/src/pages/demos/tailwind.astro index 1216751..a84de56 100644 --- a/website/src/pages/demos/react-basic.astro +++ b/website/src/pages/demos/tailwind.astro @@ -1,23 +1,26 @@ --- import Layout from "../../components/Layout.astro"; import DemoEmbed from "../../components/DemoEmbed"; +import TailwindDemo from "../../components/TailwindDemo"; --- - -

      React + CSS-only

      + +

      Tailwind

      This demo compares regular rounded-* corners with squircle squircle-* corners at several - radii. Edit the code to experiment. + radii.

      + + +

      Edit on StackBlitz

      -

      Powered by StackBlitz. Requires a Chromium-based browser. diff --git a/website/src/styles/global.css b/website/src/styles/global.css index 08bdfad..7f781c4 100644 --- a/website/src/styles/global.css +++ b/website/src/styles/global.css @@ -2,6 +2,14 @@ @plugin "../../../package/dist/tw-plugin.mjs"; @theme { + /* Semantic colors used by the demo boxes. Each names what the box is + showing, so the same logical names line up across Tailwind / StyleX / + Panda demos. */ + --color-demo-plain: #4f46e5; + --color-demo-squircle: #db2777; + --color-demo-amount: #059669; + --color-demo-corner: #7c3aed; + --color-rounded-border: oklch(0.7 0.17 257.57); --color-rounded-border-hover: oklch(from var(--color-rounded-border) min(1, calc(l + 0.15)) c h); --color-squircle-border: oklch(0.7 0.24 2.48); From bd093cc9d8904fbc8bacce54cb367c551b767d98 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 15:06:31 -0700 Subject: [PATCH 06/15] refactor!: reorganize package exports under tailwind/ panda/ stylex/ folders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: every public subpath has moved. Old → new: @klinking/squircle/tw-plugin → @klinking/squircle/tailwind @klinking/squircle/tw-merge-cfg → @klinking/squircle/tailwind (now exports `squircleMergeConfig` as a named export from the same file) @klinking/squircle/tw-utils.css → @klinking/squircle/tailwind/utils.css @klinking/squircle/squircle-radius.css → @klinking/squircle/tailwind/radius.css @klinking/squircle/panda-preset → @klinking/squircle/panda @klinking/squircle/stylex → @klinking/squircle/stylex (unchanged) The Tailwind plugin and tailwind-merge config now ship from a single file (`dist/tailwind/index.mjs`) — the plugin is the default export, the merge config is a named export. Source files are renamed to match (src/tailwind.ts, src/panda.ts, src/stylex.ts). Updated: - package.json exports - vite-plus pack entries (folder/index pattern) - generate-squircle-css.ts (writes into dist/tailwind/) - test-utils.ts, squircle-radius.test.ts (new dist paths) - website + examples imports - README + sync-readme.sh (re-synced appendix to the new layout, added Path D for the StyleX integration) All 183 package tests pass and the website builds + dev-renders against the new dist layout. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 354 ++++++++++++++++-- package/package.json | 24 +- package/scripts/generate-squircle-css.ts | 8 +- ...gin.test.ts.snap => tailwind.test.ts.snap} | 0 .../{panda-preset.test.ts => panda.test.ts} | 2 +- package/src/{panda-preset.ts => panda.ts} | 2 +- package/src/squircle-radius.test.ts | 2 +- ...squircle.stylex.test.ts => stylex.test.ts} | 4 +- package/src/{squircle.stylex.ts => stylex.ts} | 0 .../{tw-plugin.test.ts => tailwind.test.ts} | 0 package/src/{tw-plugin.ts => tailwind.ts} | 51 +++ package/src/test-utils.ts | 6 +- package/src/tw-merge-cfg.ts | 46 --- package/vite.config.ts | 17 +- scripts/sync-readme.sh | 7 +- website/astro.config.mjs | 8 +- website/examples/panda/panda.config.ts | 2 +- website/examples/stylex/vite.config.ts | 2 +- website/examples/tailwind/src/styles.css | 2 +- website/panda.config.ts | 2 +- website/src/styles/global.css | 2 +- 21 files changed, 411 insertions(+), 130 deletions(-) rename package/src/__snapshots__/{tw-plugin.test.ts.snap => tailwind.test.ts.snap} (100%) rename package/src/{panda-preset.test.ts => panda.test.ts} (99%) rename package/src/{panda-preset.ts => panda.ts} (97%) rename package/src/{squircle.stylex.test.ts => stylex.test.ts} (97%) rename package/src/{squircle.stylex.ts => stylex.ts} (100%) rename package/src/{tw-plugin.test.ts => tailwind.test.ts} (100%) rename package/src/{tw-plugin.ts => tailwind.ts} (57%) delete mode 100644 package/src/tw-merge-cfg.ts diff --git a/README.md b/README.md index c9c0b95..7327100 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no ## Contents - - [Requirements](#requirements) - [Install & setup](#install--setup) - [Utilities](#utilities) @@ -43,13 +42,13 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no npm install @klinking/squircle ``` -Then pick the integration path that fits your project. Tailwind is the original target (paths A and B). Path C is the [Panda CSS](https://panda-css.com/) preset, which produces the exact same `@supports`-gated visual correction wired through Panda's utility pipeline. +Then pick the integration path that fits your project. Tailwind is the original target (paths A and B). Path C is the [Panda CSS](https://panda-css.com/) preset and Path D is the [StyleX](https://stylexjs.com/) preset — both produce the exact same `@supports`-gated visual correction wired through their host's utility pipeline. ### Path A: CSS import (recommended) ```css @import "tailwindcss"; -@import "@klinking/squircle/tw-utils.css"; +@import "@klinking/squircle/tailwind/utils.css"; ``` That's it. All `squircle-*` classes are available. This path uses Tailwind v4's `@utility` directive, so everything is generated at build time with zero runtime cost. @@ -60,14 +59,14 @@ Use this if you want to change the class prefix or the `--squircle-amt` CSS vari ```css @import "tailwindcss"; -@plugin "@klinking/squircle/tw-plugin"; +@plugin "@klinking/squircle/tailwind"; ``` Or with options: ```css @import "tailwindcss"; -@plugin "@klinking/squircle/tw-plugin" { +@plugin "@klinking/squircle/tailwind" { prefix: sq; /* use `sq-md`, `sq-t-lg`, etc. */ amt-var: --my-amt; /* use `--my-amt` instead of `--squircle-amt` */ } @@ -80,7 +79,7 @@ See [Configuring theme tokens](#configuring-theme-tokens) for what else you can If your project already uses [`tailwind-merge`](https://github.com/dcastil/tailwind-merge) to de-duplicate conflicting classes, pull in the squircle conflict config so `rounded-lg squircle-md` resolves the way you'd expect: ```js -import { squircleMergeConfig } from "@klinking/squircle/tw-merge-cfg"; +import { squircleMergeConfig } from "@klinking/squircle/tailwind"; import { extendTailwindMerge } from "tailwind-merge"; const twMerge = extendTailwindMerge(squircleMergeConfig, { @@ -94,7 +93,7 @@ For [Panda CSS](https://panda-css.com/) projects, register the preset in `panda. ```ts import { defineConfig } from "@pandacss/dev"; -import squirclePreset from "@klinking/squircle/panda-preset"; +import squirclePreset from "@klinking/squircle/panda"; export default defineConfig({ presets: ["@pandacss/dev/presets", squirclePreset()], @@ -140,6 +139,22 @@ squirclePreset({ amtVar: "--my-amt", rVar: "--my-r" }); Panda is usage-driven — utilities only appear in the output for properties found in scanned source. If you want every variant emitted unconditionally, opt in via Panda's [`staticCss`](https://panda-css.com/docs/guides/static-css). +### Path D: StyleX + +For [StyleX](https://stylexjs.com/) projects, import the dynamic-style helpers from `@klinking/squircle/stylex`: + +```tsx +import * as stylex from "@stylexjs/stylex"; +import { squircle } from "@klinking/squircle/stylex"; + +

      +
      +``` + +Each variant (`all`, `top`, `right`, …, `topLeft`, `endEnd`, …) is a function that takes a `radius` and an optional superellipse `amt`, then emits a `borderRadius` + `cornerShape` pair gated behind `@supports (corner-shape: superellipse(2))`. If `amt` is omitted, it falls through `var(--squircle-amt, 2)` so the same custom property used by the Tailwind / Panda integrations applies. + +The whole 15-variant table is a single statically-analyzable `stylex.create({ … })` literal — your StyleX bundler picks it up the same way it picks up your own create calls. + ## Utilities | Utility | Equivalent | Description | @@ -252,7 +267,7 @@ All three are exposed as kebab-case inside the `@plugin` block and as camelCase For the footure. Less total CSS than all those tailwind utilities. So beautiful. So utterly currently unusable. ```css -@import "@klinking/squircle/squircle-radius.css"; +@import "@klinking/squircle/tailwind/radius.css"; .card { --squircle-amt: 2; @@ -361,7 +376,7 @@ Partially, at time of writing — recent Chrome ships `corner-shape`, Safari and ### Does it work with Tailwind v3? -The **CSS utilities** (`tw-utils.css`) are v4-only — they use `@utility` and `--value()`, which don't exist in v3. +The **CSS utilities** (`tailwind/utils.css`) are v4-only — they use `@utility` and `--value()`, which don't exist in v3. The **JS plugin** uses only APIs that exist in both v3 and v4 (`plugin.withOptions`, `matchUtilities`, `type: "length" | "number"`, `theme()`), so it's likely to work in v3 via a `tailwind.config.js`-style registration — but it's not currently tested or declared against v3. Tracked in [#26](https://github.com/dogmar/squircle/pull/26). @@ -404,10 +419,9 @@ Kinda. Honestly I wrote the basic tailwind utilities by hand using a weird cobbl If you'd rather not add a dependency, copy the source directly. Click to expand each file.
      -tw-utils.css — the Tailwind utilities - - +tailwind/utils.css — the Tailwind utilities + ```css /* ── Squircle utilities ─────────────────────────────────────── */ /* squircle-amt-[n] sets the superellipse amount (default 2) */ @@ -567,20 +581,18 @@ If you'd rather not add a dependency, copy the source directly. Click to expand } } ``` - - +
      -tw-plugin.mjs — the JS plugin - - +tailwind/index.mjs — the Tailwind plugin and tailwind-merge config -````js -import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries } from "./variants-CUhqvLRq.mjs"; + +```js +import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries } from "../variants-CUhqvLRq.mjs"; import plugin from "tailwindcss/plugin"; -//#region src/tw-plugin.ts +//#region src/tailwind.ts const squircle = plugin.withOptions((options = {}) => ({ matchUtilities, theme }) => { const amtVar = options.amtVar ?? options["amt-var"] ?? "--squircle-amt"; const rVar = options.rVar ?? options["r-var"] ?? "--squircle-r"; @@ -598,20 +610,6 @@ const squircle = plugin.withOptions((options = {}) => ({ matchUtilities, theme } values: radiusValues }); }); -//#endregion -export { squircle as default }; - -//# sourceMappingURL=tw-plugin.mjs.map``` - - -
      - -
      -tw-merge-cfg.mjs — the tailwind-merge config - - -```js -//#region src/tw-merge-cfg.ts const allRoundedGroups = [ "rounded", "rounded-s", @@ -656,10 +654,292 @@ const squircleMergeConfig = { extend: { } } }; //#endregion -export { squircleMergeConfig }; +export { squircle as default, squircleMergeConfig }; + +//# sourceMappingURL=index.mjs.map``` + + +
      + +
      +panda/index.mjs — the Panda CSS preset + + +```js +import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries, t as CAMEL_VARIANTS } from "../variants-CUhqvLRq.mjs"; +//#region src/panda.ts +/** +* Build the Panda preset object. Pass directly to `presets:` in `panda.config.ts`: +* +* ```ts +* import { defineConfig } from '@pandacss/dev' +* import squirclePreset from '@klinking/squircle/panda' +* +* export default defineConfig({ +* presets: ['@pandacss/dev/presets', squirclePreset()], +* }) +* ``` +* +* Naming follows Panda's own border-radius convention: full property names like +* `squircleTopLeftRadius` mirror `borderTopLeftRadius`, and shorthands like +* `squircleTopLeft` mirror `roundedTopLeft`. The shape table is identical to +* Panda's built-in radius utilities. +*/ +function squirclePandaPreset(options = {}) { + const amtVar = options.amtVar ?? "--squircle-amt"; + const rVar = options.rVar ?? "--squircle-r"; + const utilities = {}; + const variantBySuffix = new Map(variantEntries()); + for (const variant of CAMEL_VARIANTS) { + const props = variantBySuffix.get(variant.suffix); + if (!props) continue; + utilities[variant.property] = { + shorthand: variant.shorthand, + values: "radii", + transform: (value) => squircleCssObj(props, value, { + amtVar, + rVar, + case: "camel" + }) + }; + } + utilities["squircleAmount"] = { + shorthand: "squircleAmt", + values: { type: "number" }, + transform: (value) => ({ + [amtVar]: value, + [SUPPORTS_RULE]: { cornerShape: `superellipse(var(${amtVar}))` } + }) + }; + return { + name: "@klinking/squircle", + utilities: { extend: utilities }, + conditions: { extend: { squircleSupported: SUPPORTS_RULE } } + }; +} +//#endregion +export { squirclePandaPreset as default, squirclePandaPreset }; + +//# sourceMappingURL=index.mjs.map``` + + +
      + +
      +stylex/index.mjs — the StyleX dynamic-style preset + + +```js +import * as stylex from "@stylexjs/stylex"; +//#region src/stylex.ts +/** +* StyleX squircle utilities. +* +* Each entry is a *dynamic* style — a function that takes a `radius` (and an +* optional superellipse `amt`) and produces a `borderRadius` + `cornerShape` +* pair gated behind `@supports (corner-shape: superellipse(2))`. Browsers that +* don't support `corner-shape` fall back to a plain rounded rectangle at the +* same radius. +* +* ```tsx +* import * as stylex from '@stylexjs/stylex'; +* import { squircle } from '@klinking/squircle/stylex'; +* +*
      +*
      +* ``` +* +* If `amt` is omitted, the corrected radius and `corner-shape` resolve through +* `var(--squircle-amt, 2)` — set that custom property anywhere up the cascade +* to drive the superellipse exponent globally. +* +* **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to receive +* a fully-static object literal, and forbids destructuring, spreading, or +* default values on dynamic-style function parameters. The whole 15-variant +* table is therefore spelled out here verbatim. Keep it that way; tooling +* relies on every variant being statically analyzable at this call site. +*/ +const squircle = stylex.create({ + all: (radius, amt) => ({ + borderRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + top: (radius, amt) => ({ + borderTopLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + borderTopRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + right: (radius, amt) => ({ + borderTopRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + borderBottomRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + bottom: (radius, amt) => ({ + borderBottomLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + borderBottomRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + left: (radius, amt) => ({ + borderTopLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + borderBottomLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + start: (radius, amt) => ({ + borderStartStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + borderEndStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + end: (radius, amt) => ({ + borderStartEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + borderEndEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + topLeft: (radius, amt) => ({ + borderTopLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + topRight: (radius, amt) => ({ + borderTopRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + bottomRight: (radius, amt) => ({ + borderBottomRightRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + bottomLeft: (radius, amt) => ({ + borderBottomLeftRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + startStart: (radius, amt) => ({ + borderStartStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + startEnd: (radius, amt) => ({ + borderStartEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + endStart: (radius, amt) => ({ + borderEndStartRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }), + endEnd: (radius, amt) => ({ + borderEndEndRadius: { + default: radius, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + }, + cornerShape: { + default: null, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + } + }) +}); +//#endregion +export { squircle }; -//# sourceMappingURL=tw-merge-cfg.mjs.map``` - +//# sourceMappingURL=index.mjs.map``` +
      diff --git a/package/package.json b/package/package.json index f573e17..e278d09 100644 --- a/package/package.json +++ b/package/package.json @@ -21,23 +21,19 @@ ], "type": "module", "exports": { - "./tw-utils.css": "./dist/tw-utils.css", - "./squircle-radius.css": "./dist/squircle-radius.css", - "./tw-merge-cfg": { - "types": "./dist/tw-merge-cfg.d.mts", - "import": "./dist/tw-merge-cfg.mjs" + "./tailwind": { + "types": "./dist/tailwind/index.d.mts", + "import": "./dist/tailwind/index.mjs" }, - "./tw-plugin": { - "types": "./dist/tw-plugin.d.mts", - "import": "./dist/tw-plugin.mjs" - }, - "./panda-preset": { - "types": "./dist/panda-preset.d.mts", - "import": "./dist/panda-preset.mjs" + "./tailwind/utils.css": "./dist/tailwind/utils.css", + "./tailwind/radius.css": "./dist/tailwind/radius.css", + "./panda": { + "types": "./dist/panda/index.d.mts", + "import": "./dist/panda/index.mjs" }, "./stylex": { - "types": "./dist/stylex.d.mts", - "import": "./dist/stylex.mjs" + "types": "./dist/stylex/index.d.mts", + "import": "./dist/stylex/index.mjs" } }, "scripts": { diff --git a/package/scripts/generate-squircle-css.ts b/package/scripts/generate-squircle-css.ts index a4dbf56..e4083b0 100644 --- a/package/scripts/generate-squircle-css.ts +++ b/package/scripts/generate-squircle-css.ts @@ -57,13 +57,13 @@ function generateCss(): string { } const output = generateCss(); -const distDir = join(__dirname, "..", "dist"); -mkdirSync(distDir, { recursive: true }); -const outPath = join(distDir, "tw-utils.css"); +const tailwindDir = join(__dirname, "..", "dist", "tailwind"); +mkdirSync(tailwindDir, { recursive: true }); +const outPath = join(tailwindDir, "utils.css"); writeFileSync(outPath, output); console.log(`Generated ${outPath} (skipping fmt)`); const radiusSrc = join(__dirname, "..", "src", "squircle-radius.css"); -const radiusDest = join(distDir, "squircle-radius.css"); +const radiusDest = join(tailwindDir, "radius.css"); copyFileSync(radiusSrc, radiusDest); console.log(`Copied ${radiusDest}`); diff --git a/package/src/__snapshots__/tw-plugin.test.ts.snap b/package/src/__snapshots__/tailwind.test.ts.snap similarity index 100% rename from package/src/__snapshots__/tw-plugin.test.ts.snap rename to package/src/__snapshots__/tailwind.test.ts.snap diff --git a/package/src/panda-preset.test.ts b/package/src/panda.test.ts similarity index 99% rename from package/src/panda-preset.test.ts rename to package/src/panda.test.ts index 0bb9b69..3769518 100644 --- a/package/src/panda-preset.test.ts +++ b/package/src/panda.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import squirclePandaPreset from "./panda-preset"; +import squirclePandaPreset from "./panda"; import { CAMEL_VARIANTS } from "./variants"; describe("panda preset shape", () => { diff --git a/package/src/panda-preset.ts b/package/src/panda.ts similarity index 97% rename from package/src/panda-preset.ts rename to package/src/panda.ts index 73b29d0..03e0449 100644 --- a/package/src/panda-preset.ts +++ b/package/src/panda.ts @@ -39,7 +39,7 @@ export interface SquirclePandaPreset { * * ```ts * import { defineConfig } from '@pandacss/dev' - * import squirclePreset from '@klinking/squircle/panda-preset' + * import squirclePreset from '@klinking/squircle/panda' * * export default defineConfig({ * presets: ['@pandacss/dev/presets', squirclePreset()], diff --git a/package/src/squircle-radius.test.ts b/package/src/squircle-radius.test.ts index c376acb..679d36a 100644 --- a/package/src/squircle-radius.test.ts +++ b/package/src/squircle-radius.test.ts @@ -3,7 +3,7 @@ import { join } from "node:path"; import { describe, expect, it } from "vitest"; import { correctedRadius } from "./variants"; -const distPath = join(import.meta.dirname, "..", "dist", "squircle-radius.css"); +const distPath = join(import.meta.dirname, "..", "dist", "tailwind", "radius.css"); describe("squircle-radius.css ships", () => { it("is copied into dist during build", () => { diff --git a/package/src/squircle.stylex.test.ts b/package/src/stylex.test.ts similarity index 97% rename from package/src/squircle.stylex.test.ts rename to package/src/stylex.test.ts index bef39eb..a3d27a8 100644 --- a/package/src/squircle.stylex.test.ts +++ b/package/src/stylex.test.ts @@ -49,10 +49,10 @@ function compileFromSource(source: string, filename: string) { }; } -const MODULE_PATH = `${import.meta.dirname}/squircle.stylex.ts`; +const MODULE_PATH = `${import.meta.dirname}/stylex.ts`; const MODULE_SOURCE = readFileSync(MODULE_PATH, "utf8"); -describe("squircle.stylex", () => { +describe("stylex", () => { const compiled = compileFromSource(MODULE_SOURCE, MODULE_PATH); const css = compiled.rules.map((r) => r[1].ltr).join("\n"); diff --git a/package/src/squircle.stylex.ts b/package/src/stylex.ts similarity index 100% rename from package/src/squircle.stylex.ts rename to package/src/stylex.ts diff --git a/package/src/tw-plugin.test.ts b/package/src/tailwind.test.ts similarity index 100% rename from package/src/tw-plugin.test.ts rename to package/src/tailwind.test.ts diff --git a/package/src/tw-plugin.ts b/package/src/tailwind.ts similarity index 57% rename from package/src/tw-plugin.ts rename to package/src/tailwind.ts index 5940065..f638b99 100644 --- a/package/src/tw-plugin.ts +++ b/package/src/tailwind.ts @@ -7,6 +7,8 @@ import { variantEntries, } from "./variants"; +// --- Tailwind plugin --------------------------------------------------------- + export interface SquirclePluginOptions { /** CSS custom property name for the superellipse amount (default: "--squircle-amt") */ amtVar?: string; @@ -57,3 +59,52 @@ const squircle: ReturnType> = }); export default squircle; + +// --- tailwind-merge config --------------------------------------------------- + +const allRoundedGroups: string[] = [ + "rounded", + "rounded-s", + "rounded-e", + "rounded-t", + "rounded-r", + "rounded-b", + "rounded-l", + "rounded-ss", + "rounded-se", + "rounded-es", + "rounded-ee", + "rounded-tl", + "rounded-tr", + "rounded-br", + "rounded-bl", +]; + +export const squircleMergeConfig = { + extend: { + classGroups: { + squircle: [ + { squircle: [() => true] }, + { "squircle-t": [() => true] }, + { "squircle-r": [() => true] }, + { "squircle-b": [() => true] }, + { "squircle-l": [() => true] }, + { "squircle-s": [() => true] }, + { "squircle-e": [() => true] }, + { "squircle-tl": [() => true] }, + { "squircle-tr": [() => true] }, + { "squircle-br": [() => true] }, + { "squircle-bl": [() => true] }, + { "squircle-ss": [() => true] }, + { "squircle-se": [() => true] }, + { "squircle-es": [() => true] }, + { "squircle-ee": [() => true] }, + ], + "squircle-amt": [{ "squircle-amt": [() => true] }], + }, + conflictingClassGroups: { + squircle: [...allRoundedGroups, "squircle-amt"], + ...Object.fromEntries(allRoundedGroups.map((g) => [g, ["squircle", "squircle-amt"]])), + }, + }, +} as const; diff --git a/package/src/test-utils.ts b/package/src/test-utils.ts index 739d5e4..72ad974 100644 --- a/package/src/test-utils.ts +++ b/package/src/test-utils.ts @@ -54,7 +54,7 @@ export function createCompiler(srcDir: string) { async function compileCss(candidates: string[]): Promise { const input = ` @import "tailwindcss"; -@import "../dist/tw-utils.css"; +@import "../dist/tailwind/utils.css"; `; const compiler = await compile(input, { base: srcDir, @@ -66,8 +66,8 @@ export function createCompiler(srcDir: string) { async function compilePlugin(candidates: string[], pluginBlock = ""): Promise { const pluginDecl = pluginBlock - ? `@plugin "./tw-plugin.ts" {\n${pluginBlock}\n}` - : `@plugin "./tw-plugin.ts";`; + ? `@plugin "./tailwind.ts" {\n${pluginBlock}\n}` + : `@plugin "./tailwind.ts";`; const input = ` @import "tailwindcss"; ${pluginDecl} diff --git a/package/src/tw-merge-cfg.ts b/package/src/tw-merge-cfg.ts deleted file mode 100644 index 64aff0b..0000000 --- a/package/src/tw-merge-cfg.ts +++ /dev/null @@ -1,46 +0,0 @@ -const allRoundedGroups: string[] = [ - "rounded", - "rounded-s", - "rounded-e", - "rounded-t", - "rounded-r", - "rounded-b", - "rounded-l", - "rounded-ss", - "rounded-se", - "rounded-es", - "rounded-ee", - "rounded-tl", - "rounded-tr", - "rounded-br", - "rounded-bl", -]; - -export const squircleMergeConfig = { - extend: { - classGroups: { - squircle: [ - { squircle: [() => true] }, - { "squircle-t": [() => true] }, - { "squircle-r": [() => true] }, - { "squircle-b": [() => true] }, - { "squircle-l": [() => true] }, - { "squircle-s": [() => true] }, - { "squircle-e": [() => true] }, - { "squircle-tl": [() => true] }, - { "squircle-tr": [() => true] }, - { "squircle-br": [() => true] }, - { "squircle-bl": [() => true] }, - { "squircle-ss": [() => true] }, - { "squircle-se": [() => true] }, - { "squircle-es": [() => true] }, - { "squircle-ee": [() => true] }, - ], - "squircle-amt": [{ "squircle-amt": [() => true] }], - }, - conflictingClassGroups: { - squircle: [...allRoundedGroups, "squircle-amt"], - ...Object.fromEntries(allRoundedGroups.map((g) => [g, ["squircle", "squircle-amt"]])), - }, - }, -} as const; diff --git a/package/vite.config.ts b/package/vite.config.ts index 96b800f..1784949 100644 --- a/package/vite.config.ts +++ b/package/vite.config.ts @@ -8,18 +8,17 @@ export default defineConfig({ }, pack: { entry: { - "tw-plugin": "./src/tw-plugin.ts", - "tw-merge-cfg": "./src/tw-merge-cfg.ts", - "panda-preset": "./src/panda-preset.ts", - stylex: "./src/squircle.stylex.ts", + "tailwind/index": "./src/tailwind.ts", + "panda/index": "./src/panda.ts", + "stylex/index": "./src/stylex.ts", }, format: "esm", dts: true, }, run: { tasks: { - "test:plugin": { - command: "vp test run tw-plugin", + "test:tailwind": { + command: "vp test run tailwind", }, "test:css": { command: "vp test run squircle-css", @@ -30,15 +29,15 @@ export default defineConfig({ dependsOn: ["build"], }, "test:panda": { - command: "vp test run panda-preset", + command: "vp test run panda", }, "test:stylex": { - command: "vp test run squircle.stylex", + command: "vp test run stylex", }, test: { command: "echo 'All tests passed'", dependsOn: [ - "test:plugin", + "test:tailwind", "test:css", "test:radius", "test:panda", diff --git a/scripts/sync-readme.sh b/scripts/sync-readme.sh index 6d7f8fc..f7f0230 100755 --- a/scripts/sync-readme.sh +++ b/scripts/sync-readme.sh @@ -75,9 +75,10 @@ sync_toc() { rm -f "$tocfile" } -sync_file "dist/tw-utils.css" "css" "package/dist/tw-utils.css" -sync_file "dist/tw-merge-cfg.mjs" "js" "package/dist/tw-merge-cfg.mjs" -sync_file "dist/tw-plugin.mjs" "js" "package/dist/tw-plugin.mjs" +sync_file "dist/tailwind/utils.css" "css" "package/dist/tailwind/utils.css" +sync_file "dist/tailwind/index.mjs" "js" "package/dist/tailwind/index.mjs" +sync_file "dist/panda/index.mjs" "js" "package/dist/panda/index.mjs" +sync_file "dist/stylex/index.mjs" "js" "package/dist/stylex/index.mjs" sync_toc echo "README synced." diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 1164155..c7ff44d 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -19,8 +19,8 @@ const stylexBabelOpts = { /** * Run `@stylexjs/babel-plugin` on files outside of `@vitejs/plugin-react`'s - * reach — notably the package's compiled `dist/stylex.mjs`, resolved through - * the pnpm workspace. + * reach — notably the package's compiled `dist/stylex/index.mjs`, resolved + * through the pnpm workspace. */ function stylexForExternalModules() { return { @@ -29,8 +29,8 @@ function stylexForExternalModules() { async transform(code, id) { if (!/\.m?jsx?$|\.tsx?$/.test(id)) return null; if ( - !id.includes("/package/dist/stylex.mjs") && - !id.includes("squircle.stylex.") + !id.includes("/package/dist/stylex/index.mjs") && + !id.includes(".stylex.") ) { return null; } diff --git a/website/examples/panda/panda.config.ts b/website/examples/panda/panda.config.ts index 5021a51..8a9d76b 100644 --- a/website/examples/panda/panda.config.ts +++ b/website/examples/panda/panda.config.ts @@ -1,5 +1,5 @@ import { defineConfig } from "@pandacss/dev"; -import squirclePreset from "@klinking/squircle/panda-preset"; +import squirclePreset from "@klinking/squircle/panda"; export default defineConfig({ prefix: "pd", diff --git a/website/examples/stylex/vite.config.ts b/website/examples/stylex/vite.config.ts index c94aae1..3e7f2fe 100644 --- a/website/examples/stylex/vite.config.ts +++ b/website/examples/stylex/vite.config.ts @@ -22,7 +22,7 @@ function stylexForExternalModules() { enforce: "pre" as const, async transform(code: string, id: string) { if (!/\.m?jsx?$|\.tsx?$/.test(id)) return null; - if (!id.includes("@klinking/squircle/dist/stylex.mjs")) return null; + if (!id.includes("@klinking/squircle/dist/stylex/index.mjs")) return null; const result = await babel.transformAsync(code, { filename: id, babelrc: false, diff --git a/website/examples/tailwind/src/styles.css b/website/examples/tailwind/src/styles.css index 65f7d7d..b6b1368 100644 --- a/website/examples/tailwind/src/styles.css +++ b/website/examples/tailwind/src/styles.css @@ -1,5 +1,5 @@ @import "tailwindcss"; -@import "@klinking/squircle/tw-utils.css"; +@import "@klinking/squircle/tailwind/utils.css"; @theme { --color-demo-plain: #4f46e5; diff --git a/website/panda.config.ts b/website/panda.config.ts index 729186b..42e0559 100644 --- a/website/panda.config.ts +++ b/website/panda.config.ts @@ -1,5 +1,5 @@ import { defineConfig } from "@pandacss/dev"; -import squirclePreset from "@klinking/squircle/panda-preset"; +import squirclePreset from "@klinking/squircle/panda"; export default defineConfig({ // Tailwind also runs on this site; prefix Panda's generated classes so they diff --git a/website/src/styles/global.css b/website/src/styles/global.css index 7f781c4..390fd1f 100644 --- a/website/src/styles/global.css +++ b/website/src/styles/global.css @@ -1,5 +1,5 @@ @import "tailwindcss"; -@plugin "../../../package/dist/tw-plugin.mjs"; +@plugin "../../../package/dist/tailwind/index.mjs"; @theme { /* Semantic colors used by the demo boxes. Each names what the box is From ec3287f81e582f7496e2ddfbf4b817df9ebb82a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 4 May 2026 22:07:09 +0000 Subject: [PATCH 07/15] docs: sync README code blocks --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7327100..80de710 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no ## Contents + - [Requirements](#requirements) - [Install & setup](#install--setup) - [Utilities](#utilities) @@ -422,6 +423,7 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tailwind/utils.css — the Tailwind utilities + ```css /* ── Squircle utilities ─────────────────────────────────────── */ /* squircle-amt-[n] sets the superellipse amount (default 2) */ @@ -581,6 +583,7 @@ If you'd rather not add a dependency, copy the source directly. Click to expand } } ``` + @@ -589,7 +592,8 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tailwind/index.mjs — the Tailwind plugin and tailwind-merge config -```js + +````js import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries } from "../variants-CUhqvLRq.mjs"; import plugin from "tailwindcss/plugin"; //#region src/tailwind.ts From c259c45a22c21aa288e7f2bf61ba9d0a7d63a560 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 15:21:50 -0700 Subject: [PATCH 08/15] fix(stylex): default amt to literal 2, drop --squircle-amt fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Tailwind and Panda integrations both honor `var(--squircle-amt, 2)` because they emit a static @supports block — the consumer can override the exponent globally through the cascade. The StyleX preset is per-call parametric instead: each variant accepts an explicit `amt`. Mixing both mechanisms muddied the API for no real win, since StyleX dynamic styles don't read the page's CSS scope at compile time. When `amt` is omitted the runtime now substitutes the literal `2` directly into the calc and superellipse expressions. Tune via the second argument. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 81 +++++++++++++++++++------------------- package/src/stylex.test.ts | 7 +++- package/src/stylex.ts | 79 +++++++++++++++++++------------------ 3 files changed, 86 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 80de710..1254feb 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ import { squircle } from "@klinking/squircle/stylex";
      ``` -Each variant (`all`, `top`, `right`, …, `topLeft`, `endEnd`, …) is a function that takes a `radius` and an optional superellipse `amt`, then emits a `borderRadius` + `cornerShape` pair gated behind `@supports (corner-shape: superellipse(2))`. If `amt` is omitted, it falls through `var(--squircle-amt, 2)` so the same custom property used by the Tailwind / Panda integrations applies. +Each variant (`all`, `top`, `right`, …, `topLeft`, `endEnd`, …) is a function that takes a `radius` and an optional superellipse `amt`, then emits a `borderRadius` + `cornerShape` pair gated behind `@supports (corner-shape: superellipse(2))`. If `amt` is omitted, the default exponent `2` is used; unlike the Tailwind and Panda integrations, this preset does not read `--squircle-amt` — pass `amt` explicitly per call site to tune it. The whole 15-variant table is a single statically-analyzable `stylex.create({ … })` literal — your StyleX bundler picks it up the same way it picks up your own create calls. @@ -753,9 +753,10 @@ import * as stylex from "@stylexjs/stylex"; *
      * ``` * -* If `amt` is omitted, the corrected radius and `corner-shape` resolve through -* `var(--squircle-amt, 2)` — set that custom property anywhere up the cascade -* to drive the superellipse exponent globally. +* If `amt` is omitted, the corrected radius and `corner-shape` use the +* literal default exponent of `2` — pass `amt` explicitly per-call site to +* tune it. Unlike the Tailwind and Panda integrations, this preset does not +* read `--squircle-amt`; StyleX's per-call parameter is the only knob. * * **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to receive * a fully-static object literal, and forbids destructuring, spreading, or @@ -767,175 +768,175 @@ const squircle = stylex.create({ all: (radius, amt) => ({ borderRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), top: (radius, amt) => ({ borderTopLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, borderTopRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), right: (radius, amt) => ({ borderTopRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, borderBottomRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), bottom: (radius, amt) => ({ borderBottomLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, borderBottomRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), left: (radius, amt) => ({ borderTopLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, borderBottomLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), start: (radius, amt) => ({ borderStartStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, borderEndStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), end: (radius, amt) => ({ borderStartEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, borderEndEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), topLeft: (radius, amt) => ({ borderTopLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), topRight: (radius, amt) => ({ borderTopRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), bottomRight: (radius, amt) => ({ borderBottomRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), bottomLeft: (radius, amt) => ({ borderBottomLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), startStart: (radius, amt) => ({ borderStartStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), startEnd: (radius, amt) => ({ borderStartEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), endStart: (radius, amt) => ({ borderEndStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }), endEnd: (radius, amt) => ({ borderEndEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))` + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))` }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})` + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})` } }) }); diff --git a/package/src/stylex.test.ts b/package/src/stylex.test.ts index a3d27a8..529d93d 100644 --- a/package/src/stylex.test.ts +++ b/package/src/stylex.test.ts @@ -103,8 +103,11 @@ describe("stylex", () => { expect(compiled.code).toContain("pow(2, -1 *"); }); - it("uses the var(--squircle-amt, 2) default for amt", () => { - expect(compiled.code).toContain("var(--squircle-amt, 2)"); + it("defaults amt to the literal exponent 2 when omitted", () => { + // Each variant function emits `${amt ?? 2}` inside its template literals. + expect(compiled.code).toMatch(/amt\s*\?\?\s*2/); + // And does not bake in a `var(--squircle-amt, …)` fallback at runtime. + expect(compiled.code).not.toContain("var(--squircle-amt"); }); it("emits all 15 variants", () => { diff --git a/package/src/stylex.ts b/package/src/stylex.ts index 16cfe84..cec42fe 100644 --- a/package/src/stylex.ts +++ b/package/src/stylex.ts @@ -17,9 +17,10 @@ import * as stylex from "@stylexjs/stylex"; *
      * ``` * - * If `amt` is omitted, the corrected radius and `corner-shape` resolve through - * `var(--squircle-amt, 2)` — set that custom property anywhere up the cascade - * to drive the superellipse exponent globally. + * If `amt` is omitted, the corrected radius and `corner-shape` use the + * literal default exponent of `2` — pass `amt` explicitly per-call site to + * tune it. Unlike the Tailwind and Panda integrations, this preset does not + * read `--squircle-amt`; StyleX's per-call parameter is the only knob. * * **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to receive * a fully-static object literal, and forbids destructuring, spreading, or @@ -31,11 +32,11 @@ export const squircle = stylex.create({ all: (radius: string | number, amt: string | number | undefined) => ({ borderRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), @@ -44,60 +45,60 @@ export const squircle = stylex.create({ top: (radius: string | number, amt: string | number | undefined) => ({ borderTopLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, borderTopRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), right: (radius: string | number, amt: string | number | undefined) => ({ borderTopRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, borderBottomRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), bottom: (radius: string | number, amt: string | number | undefined) => ({ borderBottomLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, borderBottomRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), left: (radius: string | number, amt: string | number | undefined) => ({ borderTopLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, borderBottomLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), @@ -106,30 +107,30 @@ export const squircle = stylex.create({ start: (radius: string | number, amt: string | number | undefined) => ({ borderStartStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, borderEndStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), end: (radius: string | number, amt: string | number | undefined) => ({ borderStartEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, borderEndEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), @@ -138,44 +139,44 @@ export const squircle = stylex.create({ topLeft: (radius: string | number, amt: string | number | undefined) => ({ borderTopLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), topRight: (radius: string | number, amt: string | number | undefined) => ({ borderTopRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), bottomRight: (radius: string | number, amt: string | number | undefined) => ({ borderBottomRightRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), bottomLeft: (radius: string | number, amt: string | number | undefined) => ({ borderBottomLeftRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), @@ -184,44 +185,44 @@ export const squircle = stylex.create({ startStart: (radius: string | number, amt: string | number | undefined) => ({ borderStartStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), startEnd: (radius: string | number, amt: string | number | undefined) => ({ borderStartEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), endStart: (radius: string | number, amt: string | number | undefined) => ({ borderEndStartRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), endEnd: (radius: string | number, amt: string | number | undefined) => ({ borderEndEndRadius: { default: radius, - "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? "var(--squircle-amt, 2)"}))))`, + "@supports (corner-shape: superellipse(2))": `calc(${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * ${amt ?? 2}))))`, }, cornerShape: { default: null, - "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? "var(--squircle-amt, 2)"})`, + "@supports (corner-shape: superellipse(2))": `superellipse(${amt ?? 2})`, }, }), }); From fca7865449c30c5644c14bd02d8213fdd1d3d7c9 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 15:32:12 -0700 Subject: [PATCH 09/15] feat: generate package/src/stylex.ts from a template + variants table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the tw-utils.css codegen pattern: - New `package/src/stylex.template.ts` is a valid TS file with the import, full docstring, and the wrapping `stylex.create({ … })` call. A single marker comment (`// @stylex-generate:variants`) sits inside the create literal where the 15 variant entries get stamped in. - New `package/scripts/generate-stylex.ts` reads the template, walks `CAMEL_VARIANTS` × `VARIANTS` from `variants.ts`, and renders each variant's `(radius, amt) => ({ … })` body via `renderVariant` — change that one function to retune every variant body at once. - The output `package/src/stylex.ts` carries a "DO NOT EDIT — generated" header pointing back at the template and the script. - vp build now runs the generator before pack, alongside the existing Tailwind CSS codegen. - New `.github/workflows/sync-stylex.yml` regenerates the file on any PR that touches the template, the generator, the variants table, or the generated output itself, and force-commits the regenerated file back to the PR branch if it drifts — same shape as `sync-readme.yml`. - Extended `panda.test.ts` with broader coverage of the existing `amtVar` / `rVar` overrides — the custom name lands in every place the default `--squircle-amt` / `--squircle-r` does, and the defaults are absent when overridden. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/sync-stylex.yml | 45 ++++++++++++ package/scripts/generate-stylex.ts | 108 +++++++++++++++++++++++++++++ package/src/panda.test.ts | 44 ++++++++++-- package/src/stylex.template.ts | 47 +++++++++++++ package/src/stylex.ts | 53 ++++++++++---- package/vite.config.ts | 6 +- 6 files changed, 280 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/sync-stylex.yml create mode 100644 package/scripts/generate-stylex.ts create mode 100644 package/src/stylex.template.ts diff --git a/.github/workflows/sync-stylex.yml b/.github/workflows/sync-stylex.yml new file mode 100644 index 0000000..70b440e --- /dev/null +++ b/.github/workflows/sync-stylex.yml @@ -0,0 +1,45 @@ +name: Sync generated stylex.ts + +on: + pull_request: + branches: [main] + paths: + - package/src/stylex.template.ts + - package/src/stylex.ts + - package/src/variants.ts + - package/scripts/generate-stylex.ts + workflow_dispatch: + +permissions: + contents: write + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: voidzero-dev/setup-vp@v1 + with: + node-version: "22" + cache: true + + - run: vp install + + - name: Regenerate package/src/stylex.ts + run: vp run @klinking/squircle#generate:stylex + + - name: Commit and push if changed + run: | + git diff --quiet package/src/stylex.ts && exit 0 + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add package/src/stylex.ts + git commit -m "chore: regenerate package/src/stylex.ts" + git push || { + echo "::error::package/src/stylex.ts is out of sync and could not push fix to branch" + exit 1 + } diff --git a/package/scripts/generate-stylex.ts b/package/scripts/generate-stylex.ts new file mode 100644 index 0000000..fdbca5b --- /dev/null +++ b/package/scripts/generate-stylex.ts @@ -0,0 +1,108 @@ +import { readFileSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { CAMEL_VARIANTS, VARIANTS, isComment, SUPPORTS_RULE } from "../src/variants"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const TEMPLATE_PATH = join(__dirname, "..", "src", "stylex.template.ts"); +const OUTPUT_PATH = join(__dirname, "..", "src", "stylex.ts"); +const VARIANTS_MARKER = /^[ \t]*\/\/ @stylex-generate:variants[ \t]*$/m; + +const DO_NOT_EDIT = `// THIS FILE IS GENERATED — DO NOT EDIT. +// Source: scripts/generate-stylex.ts (template: src/stylex.template.ts) +// +// To regenerate: tsx package/scripts/generate-stylex.ts (also runs in vp build). +// To modify variant shape, edit \`renderVariant\` in the generator. +// To add/rename variants, edit \`CAMEL_VARIANTS\` and \`VARIANTS\` in src/variants.ts. + +`; + +const KEBAB_TO_CAMEL = new Map(); +function toCamel(kebab: string): string { + const cached = KEBAB_TO_CAMEL.get(kebab); + if (cached) return cached; + const camel = kebab.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()); + KEBAB_TO_CAMEL.set(kebab, camel); + return camel; +} + +/** + * Render one `key: (radius, amt) => ({ ... })` entry for the + * `stylex.create({...})` literal. The body is one CSS-property block per + * radius prop plus a single `cornerShape` block, both gated by `@supports`. + * + * Tweak the indentation, comment style, or fallback expression here — the + * template file just stamps these strings into its create() call. + */ +function renderVariant(side: string, kebabProps: string[]): string { + const indent = " "; + const radiusBlocks = kebabProps + .map((prop) => { + const camel = toCamel(prop); + return [ + `${indent}${indent}${camel}: {`, + `${indent}${indent}${indent}default: radius,`, + `${indent}${indent}${indent}"${SUPPORTS_RULE}": \`calc(\${radius} * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * \${amt ?? 2}))))\`,`, + `${indent}${indent}},`, + ].join("\n"); + }) + .join("\n"); + + return [ + `${indent}${side}: (radius: string | number, amt: string | number | undefined) => ({`, + radiusBlocks, + `${indent}${indent}cornerShape: {`, + `${indent}${indent}${indent}default: null,`, + `${indent}${indent}${indent}"${SUPPORTS_RULE}": \`superellipse(\${amt ?? 2})\`,`, + `${indent}${indent}},`, + `${indent}}),`, + ].join("\n"); +} + +function renderAllVariants(): string { + const blocks: string[] = []; + let lastSection: string | null = null; + + for (const camel of CAMEL_VARIANTS) { + const entry = VARIANTS[camel.suffix]; + if (!entry || isComment(entry)) continue; + + // Emit a section comment when we transition between physical/logical + // groups, mirroring the structure of the variants table. + const section = sectionFor(camel.side); + if (section !== lastSection) { + blocks.push(` // --- ${section} ---`); + lastSection = section; + } + + blocks.push(renderVariant(camel.side, entry)); + } + + return blocks.join("\n\n"); +} + +function sectionFor(side: string): string { + if (side === "all") return "All corners"; + if (["top", "right", "bottom", "left"].includes(side)) return "Per-side physical"; + if (["start", "end"].includes(side)) return "Per-side logical"; + if (["topLeft", "topRight", "bottomRight", "bottomLeft"].includes(side)) { + return "Per-corner physical"; + } + return "Per-corner logical"; +} + +const template = readFileSync(TEMPLATE_PATH, "utf8"); + +if (!VARIANTS_MARKER.test(template)) { + console.error( + `generate-stylex: template ${TEMPLATE_PATH} is missing the // @stylex-generate:variants marker line.`, + ); + process.exit(1); +} + +const variantsBlock = renderAllVariants(); +const filled = template.replace(VARIANTS_MARKER, variantsBlock); +writeFileSync(OUTPUT_PATH, DO_NOT_EDIT + filled); + +console.log(`Generated ${OUTPUT_PATH} (${CAMEL_VARIANTS.length} variants)`); diff --git a/package/src/panda.test.ts b/package/src/panda.test.ts index 3769518..f1b8691 100644 --- a/package/src/panda.test.ts +++ b/package/src/panda.test.ts @@ -113,23 +113,36 @@ describe("panda preset transform output", () => { }); describe("panda preset options", () => { - it("custom amtVar threads through every transform", () => { + it("custom amtVar lands in every place the default --squircle-amt does", () => { const preset = squirclePandaPreset({ amtVar: "--my-amt" }); - const out = preset.utilities.extend["squircleRadius"]!.transform!("1rem", { + + // 1. radius transform — @supports calc references the custom var, and + // cornerShape uses it as the superellipse argument. + const radiusOut = preset.utilities.extend["squircleRadius"]!.transform!("1rem", { token: () => "1rem", raw: "1rem", }) as Record; - const supports = out["@supports (corner-shape: superellipse(2))"] as Record< - string, - string - >; - expect(supports["cornerShape"]).toBe("superellipse(var(--my-amt, 2))"); + const radiusSupports = radiusOut[ + "@supports (corner-shape: superellipse(2))" + ] as Record; + expect(radiusSupports["--squircle-r"]).toContain("var(--my-amt, 2)"); + expect(radiusSupports["cornerShape"]).toBe("superellipse(var(--my-amt, 2))"); + // 2. squircleAmount transform — writes the custom var and the @supports + // block reads it back. const amtOut = preset.utilities.extend["squircleAmount"]!.transform!("3", { token: () => "3", raw: "3", }) as Record; expect(amtOut["--my-amt"]).toBe("3"); + const amtSupports = amtOut[ + "@supports (corner-shape: superellipse(2))" + ] as Record; + expect(amtSupports["cornerShape"]).toBe("superellipse(var(--my-amt))"); + + // 3. The default name does not appear anywhere when overridden. + const allOutput = JSON.stringify({ radiusOut, amtOut }); + expect(allOutput).not.toContain("--squircle-amt"); }); it("custom rVar threads through multi-prop side transforms", () => { @@ -145,5 +158,22 @@ describe("panda preset options", () => { expect(supports["--my-r"]).toContain("calc(1rem"); expect(supports["borderTopLeftRadius"]).toBe("var(--my-r)"); expect(supports["borderTopRightRadius"]).toBe("var(--my-r)"); + // And the default --squircle-r is gone. + expect(JSON.stringify(out)).not.toContain("--squircle-r"); + }); + + it("amtVar and rVar can both be overridden together", () => { + const preset = squirclePandaPreset({ amtVar: "--a", rVar: "--r" }); + const out = preset.utilities.extend["squircleRadius"]!.transform!("1rem", { + token: () => "1rem", + raw: "1rem", + }) as Record; + const supports = out["@supports (corner-shape: superellipse(2))"] as Record< + string, + string + >; + expect(supports["--r"]).toContain("var(--a, 2)"); + expect(supports["borderRadius"]).toBe("var(--r)"); + expect(supports["cornerShape"]).toBe("superellipse(var(--a, 2))"); }); }); diff --git a/package/src/stylex.template.ts b/package/src/stylex.template.ts new file mode 100644 index 0000000..4054324 --- /dev/null +++ b/package/src/stylex.template.ts @@ -0,0 +1,47 @@ +import * as stylex from "@stylexjs/stylex"; + +/** + * StyleX squircle utilities — generated from this template by + * `scripts/generate-stylex.ts`. + * + * Each variant is a *dynamic* style — a function that takes a `radius` (and + * an optional superellipse `amt`) and produces a `borderRadius` + + * `cornerShape` pair gated behind `@supports (corner-shape: superellipse(2))`. + * Browsers that don't support `corner-shape` fall back to a plain rounded + * rectangle at the same radius. + * + * ```tsx + * import * as stylex from '@stylexjs/stylex'; + * import { squircle } from '@klinking/squircle/stylex'; + * + *
      + *
      + * ``` + * + * If `amt` is omitted, the corrected radius and `corner-shape` use the + * literal default exponent of `2` — pass `amt` explicitly per-call site to + * tune it. Unlike the Tailwind and Panda integrations, this preset does not + * read `--squircle-amt`; StyleX's per-call parameter is the only knob. + * + * **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to + * receive a fully-static object literal, and forbids destructuring, + * spreading, or default values on dynamic-style function parameters. The + * whole 15-variant table is therefore spelled out verbatim in the generated + * output. Every entry in this template must remain statically analyzable at + * its final call site. + * + * **How to modify** + * + * - To tweak a *variant's body* (the `borderRadius`/`cornerShape` block), + * edit `renderVariant` in `scripts/generate-stylex.ts`. + * - To add or rename variants, edit `CAMEL_VARIANTS` and `VARIANTS` in + * `variants.ts`. + * - To tweak the *file shell* (imports, docstring, the wrapping + * `stylex.create({ ... })` call), edit this template. + * + * Then run `tsx scripts/generate-stylex.ts` (or just `vp run build`) to + * regenerate `stylex.ts`. Do not hand-edit `stylex.ts`. + */ +export const squircle = stylex.create({ + // @stylex-generate:variants +}); diff --git a/package/src/stylex.ts b/package/src/stylex.ts index cec42fe..7ff1cec 100644 --- a/package/src/stylex.ts +++ b/package/src/stylex.ts @@ -1,13 +1,21 @@ +// THIS FILE IS GENERATED — DO NOT EDIT. +// Source: scripts/generate-stylex.ts (template: src/stylex.template.ts) +// +// To regenerate: tsx package/scripts/generate-stylex.ts (also runs in vp build). +// To modify variant shape, edit `renderVariant` in the generator. +// To add/rename variants, edit `CAMEL_VARIANTS` and `VARIANTS` in src/variants.ts. + import * as stylex from "@stylexjs/stylex"; /** - * StyleX squircle utilities. + * StyleX squircle utilities — generated from this template by + * `scripts/generate-stylex.ts`. * - * Each entry is a *dynamic* style — a function that takes a `radius` (and an - * optional superellipse `amt`) and produces a `borderRadius` + `cornerShape` - * pair gated behind `@supports (corner-shape: superellipse(2))`. Browsers that - * don't support `corner-shape` fall back to a plain rounded rectangle at the - * same radius. + * Each variant is a *dynamic* style — a function that takes a `radius` (and + * an optional superellipse `amt`) and produces a `borderRadius` + + * `cornerShape` pair gated behind `@supports (corner-shape: superellipse(2))`. + * Browsers that don't support `corner-shape` fall back to a plain rounded + * rectangle at the same radius. * * ```tsx * import * as stylex from '@stylexjs/stylex'; @@ -22,13 +30,28 @@ import * as stylex from "@stylexjs/stylex"; * tune it. Unlike the Tailwind and Panda integrations, this preset does not * read `--squircle-amt`; StyleX's per-call parameter is the only knob. * - * **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to receive - * a fully-static object literal, and forbids destructuring, spreading, or - * default values on dynamic-style function parameters. The whole 15-variant - * table is therefore spelled out here verbatim. Keep it that way; tooling - * relies on every variant being statically analyzable at this call site. + * **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to + * receive a fully-static object literal, and forbids destructuring, + * spreading, or default values on dynamic-style function parameters. The + * whole 15-variant table is therefore spelled out verbatim in the generated + * output. Every entry in this template must remain statically analyzable at + * its final call site. + * + * **How to modify** + * + * - To tweak a *variant's body* (the `borderRadius`/`cornerShape` block), + * edit `renderVariant` in `scripts/generate-stylex.ts`. + * - To add or rename variants, edit `CAMEL_VARIANTS` and `VARIANTS` in + * `variants.ts`. + * - To tweak the *file shell* (imports, docstring, the wrapping + * `stylex.create({ ... })` call), edit this template. + * + * Then run `tsx scripts/generate-stylex.ts` (or just `vp run build`) to + * regenerate `stylex.ts`. Do not hand-edit `stylex.ts`. */ export const squircle = stylex.create({ + // --- All corners --- + all: (radius: string | number, amt: string | number | undefined) => ({ borderRadius: { default: radius, @@ -40,7 +63,7 @@ export const squircle = stylex.create({ }, }), - // --- Per-side physical variants --- + // --- Per-side physical --- top: (radius: string | number, amt: string | number | undefined) => ({ borderTopLeftRadius: { @@ -102,7 +125,7 @@ export const squircle = stylex.create({ }, }), - // --- Per-side logical variants --- + // --- Per-side logical --- start: (radius: string | number, amt: string | number | undefined) => ({ borderStartStartRadius: { @@ -134,7 +157,7 @@ export const squircle = stylex.create({ }, }), - // --- Per-corner physical variants --- + // --- Per-corner physical --- topLeft: (radius: string | number, amt: string | number | undefined) => ({ borderTopLeftRadius: { @@ -180,7 +203,7 @@ export const squircle = stylex.create({ }, }), - // --- Per-corner logical variants --- + // --- Per-corner logical --- startStart: (radius: string | number, amt: string | number | undefined) => ({ borderStartStartRadius: { diff --git a/package/vite.config.ts b/package/vite.config.ts index 1784949..66aa937 100644 --- a/package/vite.config.ts +++ b/package/vite.config.ts @@ -44,8 +44,12 @@ export default defineConfig({ "test:stylex", ], }, + "generate:stylex": { + command: "tsx scripts/generate-stylex.ts", + }, build: { - command: "vp pack && tsx scripts/generate-squircle-css.ts", + command: + "tsx scripts/generate-stylex.ts && vp pack && tsx scripts/generate-squircle-css.ts", }, }, }, From 0bfb2eed961b31b1e4e35781fc3979fd63f7d4f9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 4 May 2026 22:32:39 +0000 Subject: [PATCH 10/15] docs: sync README code blocks --- README.md | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1254feb..97119ed 100644 --- a/README.md +++ b/README.md @@ -737,13 +737,14 @@ export { squirclePandaPreset as default, squirclePandaPreset }; import * as stylex from "@stylexjs/stylex"; //#region src/stylex.ts /** -* StyleX squircle utilities. +* StyleX squircle utilities — generated from this template by +* `scripts/generate-stylex.ts`. * -* Each entry is a *dynamic* style — a function that takes a `radius` (and an -* optional superellipse `amt`) and produces a `borderRadius` + `cornerShape` -* pair gated behind `@supports (corner-shape: superellipse(2))`. Browsers that -* don't support `corner-shape` fall back to a plain rounded rectangle at the -* same radius. +* Each variant is a *dynamic* style — a function that takes a `radius` (and +* an optional superellipse `amt`) and produces a `borderRadius` + +* `cornerShape` pair gated behind `@supports (corner-shape: superellipse(2))`. +* Browsers that don't support `corner-shape` fall back to a plain rounded +* rectangle at the same radius. * * ```tsx * import * as stylex from '@stylexjs/stylex'; @@ -758,11 +759,24 @@ import * as stylex from "@stylexjs/stylex"; * tune it. Unlike the Tailwind and Panda integrations, this preset does not * read `--squircle-amt`; StyleX's per-call parameter is the only knob. * -* **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to receive -* a fully-static object literal, and forbids destructuring, spreading, or -* default values on dynamic-style function parameters. The whole 15-variant -* table is therefore spelled out here verbatim. Keep it that way; tooling -* relies on every variant being statically analyzable at this call site. +* **Constraint** — StyleX's babel plugin requires `stylex.create(...)` to +* receive a fully-static object literal, and forbids destructuring, +* spreading, or default values on dynamic-style function parameters. The +* whole 15-variant table is therefore spelled out verbatim in the generated +* output. Every entry in this template must remain statically analyzable at +* its final call site. +* +* **How to modify** +* +* - To tweak a *variant's body* (the `borderRadius`/`cornerShape` block), +* edit `renderVariant` in `scripts/generate-stylex.ts`. +* - To add or rename variants, edit `CAMEL_VARIANTS` and `VARIANTS` in +* `variants.ts`. +* - To tweak the *file shell* (imports, docstring, the wrapping +* `stylex.create({ ... })` call), edit this template. +* +* Then run `tsx scripts/generate-stylex.ts` (or just `vp run build`) to +* regenerate `stylex.ts`. Do not hand-edit `stylex.ts`. */ const squircle = stylex.create({ all: (radius, amt) => ({ From 1547ef54891b2f117986459adf25d8cb60a3d691 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 15:36:28 -0700 Subject: [PATCH 11/15] docs: expand README install/usage for Panda and StyleX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both Path C (Panda) and Path D (StyleX) now have step-numbered install sections matching the depth of the existing Tailwind paths: Panda - Splits install / register-preset / use-utilities into separate steps with a `panda codegen` reminder. - Adds the cva-recipe and arbitrary-value usage examples consumers reach for first. - Documents the `_squircleSupported` condition with a worked example. - Documents the `prefix:` knob for coexisting with other utility frameworks. - Adds usage-driven extraction + optional-peer notes. StyleX - Spells out the bundler wiring, including the gotcha that `@klinking/squircle/dist/stylex/index.mjs` needs the babel plugin run on it just like consumer source — full Vite snippet, with a pointer to the website's astro.config.mjs as a working reference. - Documents the `(radius, amt) => …` signature and accepted value types, and reiterates that `amt` does *not* read `--squircle-amt` from the cascade (per-call only). - Adds mix-with-own-styles and shared-radius-tokens (`defineVars`) examples. - Closes with notes on why no CSS-var knobs, how the literal stays statically analyzable, and the optional-peer status. The Copy/paste appendix already had collapsed details for the panda and stylex bundles (added when exports moved under tailwind/ panda/ stylex/); re-synced from the freshly rebuilt dist for completeness. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 203 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 184 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 97119ed..483355b 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no ## Contents - - [Requirements](#requirements) - [Install & setup](#install--setup) - [Utilities](#utilities) @@ -90,24 +89,30 @@ const twMerge = extendTailwindMerge(squircleMergeConfig, { ### Path C: Panda CSS preset -For [Panda CSS](https://panda-css.com/) projects, register the preset in `panda.config.ts`: +#### 1. Install Panda + +```bash +npm install -D @pandacss/dev @klinking/squircle +``` + +If you don't have Panda set up yet, follow the [official quickstart](https://panda-css.com/docs/installation/cli) to initialize a `panda.config.ts` and your `styled-system/` codegen output. + +#### 2. Register the preset ```ts +// panda.config.ts import { defineConfig } from "@pandacss/dev"; import squirclePreset from "@klinking/squircle/panda"; export default defineConfig({ presets: ["@pandacss/dev/presets", squirclePreset()], - // ... + // ... your other config }); ``` -Then use the utilities anywhere `css(...)` accepts properties: +Re-run `panda codegen` so the new `squircle*` properties show up in the typed `css({ … })` and `cva({ … })` APIs. -```tsx -
      -
      -``` +#### 3. Use the utilities The naming follows Panda's own border-radius convention exactly — substitute `border` ↔ `squircle` and `rounded` ↔ `squircle` (the shorthand) and the table is identical to Panda's: @@ -130,31 +135,194 @@ The naming follows Panda's own border-radius convention exactly — substitute ` | `squircleEndEndRadius` | `squircleEndEnd` | end-end corner (logical) | | `squircleAmount` | `squircleAmt` | superellipse exponent (default 2) | -All radius utilities resolve through your `radii` theme tokens, so `squircle: "md"` reads the same `--radii-md` your `borderRadius: "md"` does. The preset also registers a `_squircleSupported` condition (`@supports (corner-shape: superellipse(2))`) for one-off overrides. +All radius utilities resolve through your `radii` theme tokens, so `squircle: "md"` reads the same `--radii-md` your `borderRadius: "md"` does: + +```tsx +import { css, cva } from "../styled-system/css"; + +// All four corners, token radius +
      + +// Single corner with explicit superellipse amount +
      + +// Arbitrary value (any string Panda would accept for borderRadius) +
      + +// Inside a recipe +const button = cva({ + base: { squircle: "md", paddingInline: "4" }, + variants: { tone: { brand: { squircleAmt: 3 } } }, +}); +``` + +The preset also registers a `_squircleSupported` condition mapped to `@supports (corner-shape: superellipse(2))`. Use it to layer on extra styles in the squircle branch only: -The preset accepts the same `amtVar` / `rVar` options as the Tailwind plugin if you need to rename the underlying CSS variables: +```tsx +
      +``` + +#### 4. (Optional) customize CSS variable names + +If you've already standardized on different variable names — say your design system uses `--corner-amt` everywhere — pass them when calling the preset: ```ts -squirclePreset({ amtVar: "--my-amt", rVar: "--my-r" }); +squirclePreset({ + amtVar: "--corner-amt", // default: --squircle-amt + rVar: "--corner-r", // default: --squircle-r +}); ``` -Panda is usage-driven — utilities only appear in the output for properties found in scanned source. If you want every variant emitted unconditionally, opt in via Panda's [`staticCss`](https://panda-css.com/docs/guides/static-css). +The override flows through every transform: the `@supports` calc, the `cornerShape: superellipse(var(--corner-amt))`, and the `squircleAmount` utility's variable write. + +#### 5. (Optional) prefix the generated classes + +If you're running Panda alongside another utility framework (Tailwind, Mantine, etc.) and worried about class collisions, use Panda's own [`prefix`](https://panda-css.com/docs/concepts/extend) option in `panda.config.ts`. It applies to every Panda utility, this preset included: + +```ts +export default defineConfig({ + prefix: "pd", + presets: ["@pandacss/dev/presets", squirclePreset()], +}); +``` + +#### Notes + +- **Usage-driven extraction.** Panda only emits CSS for properties it finds in scanned source. If you want every `squircle*` variant in the output regardless of usage, opt them in via Panda's [`staticCss`](https://panda-css.com/docs/guides/static-css) config. +- **Optional peer.** `@pandacss/dev` is an *optional* peer dependency on `@klinking/squircle` — installing the package without Panda doesn't pull Panda in. ### Path D: StyleX -For [StyleX](https://stylexjs.com/) projects, import the dynamic-style helpers from `@klinking/squircle/stylex`: +#### 1. Install StyleX + +```bash +npm install @stylexjs/stylex @klinking/squircle +npm install -D @stylexjs/babel-plugin +``` + +Wire `@stylexjs/babel-plugin` into your bundler the standard way ([Vite](https://stylexjs.com/docs/learn/installation/#using-vite), [Next.js](https://stylexjs.com/docs/learn/installation/#using-nextjs), etc.). One detail specific to consuming this package: `@klinking/squircle/stylex` ships a pre-compiled `dist/stylex/index.mjs` that *also* contains a `stylex.create({ … })` call, so the babel plugin must run on it too. + +For a Vite project, that means excluding the package from `optimizeDeps` and either `noExternal`-ing it (Vite SSR mode) or running babel on it via a small custom transform: + +```ts +// vite.config.ts +import babel from "@babel/core"; +import stylexPlugin from "@stylexjs/babel-plugin"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +const stylexBabelOpts = { + dev: true, // or false for prod + runtimeInjection: true, + unstable_moduleResolution: { type: "commonJS", rootDir: process.cwd() }, +}; + +export default defineConfig({ + plugins: [ + react({ + babel: { plugins: [[stylexPlugin, stylexBabelOpts]] }, + }), + // Run the stylex plugin on @klinking/squircle/stylex too — the + // package ships a compiled file that still needs babel processing. + { + name: "stylex-external", + enforce: "pre", + async transform(code, id) { + if (!id.includes("@klinking/squircle/dist/stylex/index.mjs")) return; + const result = await babel.transformAsync(code, { + filename: id, + babelrc: false, + configFile: false, + plugins: [[stylexPlugin, stylexBabelOpts]], + }); + return result?.code ? { code: result.code, map: result.map } : null; + }, + }, + ], + optimizeDeps: { exclude: ["@klinking/squircle"] }, + ssr: { noExternal: ["@klinking/squircle"] }, +}); +``` + +The website's [`astro.config.mjs`](website/astro.config.mjs) does this end-to-end if you'd like a complete reference. + +#### 2. Use the utilities ```tsx import * as stylex from "@stylexjs/stylex"; import { squircle } from "@klinking/squircle/stylex"; +// All four corners
      + +// Single corner with custom superellipse amount
      + +// Per-side +
      + +// Logical (inline-start/inline-end aware) +
      ``` -Each variant (`all`, `top`, `right`, …, `topLeft`, `endEnd`, …) is a function that takes a `radius` and an optional superellipse `amt`, then emits a `borderRadius` + `cornerShape` pair gated behind `@supports (corner-shape: superellipse(2))`. If `amt` is omitted, the default exponent `2` is used; unlike the Tailwind and Panda integrations, this preset does not read `--squircle-amt` — pass `amt` explicitly per call site to tune it. +`squircle` exposes one entry per variant — same 15-name table as the Panda preset (`all`, `top`, `right`, `bottom`, `left`, `start`, `end`, `topLeft`, `topRight`, `bottomRight`, `bottomLeft`, `startStart`, `startEnd`, `endStart`, `endEnd`). Each entry is a function with this signature: -The whole 15-variant table is a single statically-analyzable `stylex.create({ … })` literal — your StyleX bundler picks it up the same way it picks up your own create calls. +```ts +(radius: string | number, amt?: string | number) => StyleXStyles +``` + +- `radius` — any value valid for `border-radius` (rem, px, %, a `var(--…)` reference, or a number which StyleX converts to px). +- `amt` — the superellipse exponent. **Defaults to `2`.** Unlike the Tailwind and Panda integrations, this preset does *not* read `--squircle-amt` from the cascade — pass `amt` explicitly per call site to tune it. + +Browsers without `corner-shape` support fall back to a plain `border-radius` at the same size (the `@supports` block silently drops out). + +#### 3. Mix with your own styles + +`stylex.props` accepts any number of style references and merges them. Layer squircle on top of your own component styles: + +```tsx +const styles = stylex.create({ + card: { padding: 16, backgroundColor: "#fff", boxShadow: "0 1px 2px #0002" }, +}); + +
      +``` + +#### 4. Use shared radius tokens + +Pull radii out into a `defineVars` file so multiple components share one scale: + +```ts +// theme/radii.stylex.ts +import * as stylex from "@stylexjs/stylex"; + +export const radii = stylex.defineVars({ + sm: "0.25rem", + md: "0.5rem", + lg: "1rem", +}); +``` + +```tsx +import { radii } from "./theme/radii.stylex"; +import { squircle } from "@klinking/squircle/stylex"; + +
      +``` + +`radii.md` is a `var(--xR-…)` reference at runtime, which StyleX wraps in another custom property and the squircle calc resolves transitively. + +#### Notes + +- **No CSS-variable knobs.** The Tailwind and Panda integrations expose `amtVar` / `rVar` because they emit static `@supports` blocks the cascade can override. StyleX's preset is per-call parametric instead — there's nothing to rename. +- **Static analysis.** The 15-variant table is a single statically-analyzable `stylex.create({ … })` literal, so your StyleX bundler picks it up the same way it picks up your own create calls. The literal is generated from a template — see `package/scripts/generate-stylex.ts`. +- **Optional peer.** `@stylexjs/stylex` is an *optional* peer dependency on `@klinking/squircle` — installing the package without StyleX doesn't pull it in. ## Utilities @@ -423,7 +591,6 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tailwind/utils.css — the Tailwind utilities - ```css /* ── Squircle utilities ─────────────────────────────────────── */ /* squircle-amt-[n] sets the superellipse amount (default 2) */ @@ -583,7 +750,6 @@ If you'd rather not add a dependency, copy the source directly. Click to expand } } ``` - @@ -592,8 +758,7 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tailwind/index.mjs — the Tailwind plugin and tailwind-merge config - -````js +```js import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries } from "../variants-CUhqvLRq.mjs"; import plugin from "tailwindcss/plugin"; //#region src/tailwind.ts From 43323f2746397995fdbda942a8a4b426b9b76627 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 4 May 2026 22:37:14 +0000 Subject: [PATCH 12/15] docs: sync README code blocks --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 483355b..4ca028a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no ## Contents + - [Requirements](#requirements) - [Install & setup](#install--setup) - [Utilities](#utilities) @@ -195,7 +196,7 @@ export default defineConfig({ #### Notes - **Usage-driven extraction.** Panda only emits CSS for properties it finds in scanned source. If you want every `squircle*` variant in the output regardless of usage, opt them in via Panda's [`staticCss`](https://panda-css.com/docs/guides/static-css) config. -- **Optional peer.** `@pandacss/dev` is an *optional* peer dependency on `@klinking/squircle` — installing the package without Panda doesn't pull Panda in. +- **Optional peer.** `@pandacss/dev` is an _optional_ peer dependency on `@klinking/squircle` — installing the package without Panda doesn't pull Panda in. ### Path D: StyleX @@ -206,7 +207,7 @@ npm install @stylexjs/stylex @klinking/squircle npm install -D @stylexjs/babel-plugin ``` -Wire `@stylexjs/babel-plugin` into your bundler the standard way ([Vite](https://stylexjs.com/docs/learn/installation/#using-vite), [Next.js](https://stylexjs.com/docs/learn/installation/#using-nextjs), etc.). One detail specific to consuming this package: `@klinking/squircle/stylex` ships a pre-compiled `dist/stylex/index.mjs` that *also* contains a `stylex.create({ … })` call, so the babel plugin must run on it too. +Wire `@stylexjs/babel-plugin` into your bundler the standard way ([Vite](https://stylexjs.com/docs/learn/installation/#using-vite), [Next.js](https://stylexjs.com/docs/learn/installation/#using-nextjs), etc.). One detail specific to consuming this package: `@klinking/squircle/stylex` ships a pre-compiled `dist/stylex/index.mjs` that _also_ contains a `stylex.create({ … })` call, so the babel plugin must run on it too. For a Vite project, that means excluding the package from `optimizeDeps` and either `noExternal`-ing it (Vite SSR mode) or running babel on it via a small custom transform: @@ -278,7 +279,7 @@ import { squircle } from "@klinking/squircle/stylex"; ``` - `radius` — any value valid for `border-radius` (rem, px, %, a `var(--…)` reference, or a number which StyleX converts to px). -- `amt` — the superellipse exponent. **Defaults to `2`.** Unlike the Tailwind and Panda integrations, this preset does *not* read `--squircle-amt` from the cascade — pass `amt` explicitly per call site to tune it. +- `amt` — the superellipse exponent. **Defaults to `2`.** Unlike the Tailwind and Panda integrations, this preset does _not_ read `--squircle-amt` from the cascade — pass `amt` explicitly per call site to tune it. Browsers without `corner-shape` support fall back to a plain `border-radius` at the same size (the `@supports` block silently drops out). @@ -322,7 +323,7 @@ import { squircle } from "@klinking/squircle/stylex"; - **No CSS-variable knobs.** The Tailwind and Panda integrations expose `amtVar` / `rVar` because they emit static `@supports` blocks the cascade can override. StyleX's preset is per-call parametric instead — there's nothing to rename. - **Static analysis.** The 15-variant table is a single statically-analyzable `stylex.create({ … })` literal, so your StyleX bundler picks it up the same way it picks up your own create calls. The literal is generated from a template — see `package/scripts/generate-stylex.ts`. -- **Optional peer.** `@stylexjs/stylex` is an *optional* peer dependency on `@klinking/squircle` — installing the package without StyleX doesn't pull it in. +- **Optional peer.** `@stylexjs/stylex` is an _optional_ peer dependency on `@klinking/squircle` — installing the package without StyleX doesn't pull it in. ## Utilities @@ -591,6 +592,7 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tailwind/utils.css — the Tailwind utilities + ```css /* ── Squircle utilities ─────────────────────────────────────── */ /* squircle-amt-[n] sets the superellipse amount (default 2) */ @@ -750,6 +752,7 @@ If you'd rather not add a dependency, copy the source directly. Click to expand } } ``` + @@ -758,7 +761,8 @@ If you'd rather not add a dependency, copy the source directly. Click to expand tailwind/index.mjs — the Tailwind plugin and tailwind-merge config -```js + +````js import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries } from "../variants-CUhqvLRq.mjs"; import plugin from "tailwindcss/plugin"; //#region src/tailwind.ts From 30169b2358eb05c200e39cbcd58efada42b76b4f Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 16:01:57 -0700 Subject: [PATCH 13/15] chore: infer node version from .node-version + use real panda types - Replace hardcoded `node-version: "22"` with `node-version-file: ".node-version"` in all four GitHub Actions workflows - Replace hand-rolled Panda type stubs with `definePreset` and `PropertyConfig` from `@pandacss/dev` - Add `@pandacss/dev` as a devDependency for build-time type checking Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 2 +- .github/workflows/deploy-site.yml | 2 +- .github/workflows/sync-readme.yml | 2 +- .github/workflows/sync-stylex.yml | 2 +- package/package.json | 1 + package/src/panda.test.ts | 58 +++++++++++++------------------ package/src/panda.ts | 39 +++++---------------- pnpm-lock.yaml | 6 ++-- 8 files changed, 40 insertions(+), 72 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd7135a..ca4248f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - uses: voidzero-dev/setup-vp@v1 with: - node-version: "22" + node-version-file: ".node-version" cache: true - run: vp install diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml index 00524fc..ab1d42c 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/deploy-site.yml @@ -22,7 +22,7 @@ jobs: - uses: voidzero-dev/setup-vp@v1 with: - node-version: "22" + node-version-file: ".node-version" cache: true - run: vp install diff --git a/.github/workflows/sync-readme.yml b/.github/workflows/sync-readme.yml index fc8a88d..9dcb827 100644 --- a/.github/workflows/sync-readme.yml +++ b/.github/workflows/sync-readme.yml @@ -26,7 +26,7 @@ jobs: - uses: voidzero-dev/setup-vp@v1 with: - node-version: "22" + node-version-file: ".node-version" cache: true - run: vp install diff --git a/.github/workflows/sync-stylex.yml b/.github/workflows/sync-stylex.yml index 70b440e..9a1068c 100644 --- a/.github/workflows/sync-stylex.yml +++ b/.github/workflows/sync-stylex.yml @@ -24,7 +24,7 @@ jobs: - uses: voidzero-dev/setup-vp@v1 with: - node-version: "22" + node-version-file: ".node-version" cache: true - run: vp install diff --git a/package/package.json b/package/package.json index e278d09..99cac38 100644 --- a/package/package.json +++ b/package/package.json @@ -42,6 +42,7 @@ "devDependencies": { "@babel/core": "^7.29.0", "@babel/preset-typescript": "^7.28.0", + "@pandacss/dev": "^1.11.0", "@stylexjs/babel-plugin": "^0.18.3", "@stylexjs/stylex": "^0.18.3", "@tailwindcss/vite": "^4.2.2", diff --git a/package/src/panda.test.ts b/package/src/panda.test.ts index f1b8691..9fed014 100644 --- a/package/src/panda.test.ts +++ b/package/src/panda.test.ts @@ -10,13 +10,13 @@ describe("panda preset shape", () => { }); it("registers the squircleSupported condition", () => { - expect(preset.conditions.extend["squircleSupported"]).toBe( + expect(preset.conditions!.extend!["squircleSupported"]).toBe( "@supports (corner-shape: superellipse(2))", ); }); it("registers a utility for every CAMEL_VARIANTS entry plus squircleAmount", () => { - const keys = Object.keys(preset.utilities.extend).sort(); + const keys = Object.keys(preset.utilities!.extend!).sort(); const expected = [ ...CAMEL_VARIANTS.map((v) => v.property), "squircleAmount", @@ -26,7 +26,7 @@ describe("panda preset shape", () => { it("uses Panda's built-in `radii` token category for radius utilities", () => { for (const variant of CAMEL_VARIANTS) { - const u = preset.utilities.extend[variant.property]; + const u = preset.utilities!.extend![variant.property]; if (!u) throw new Error(`missing utility for ${variant.property}`); expect(u.values).toBe("radii"); expect(u.shorthand).toBe(variant.shorthand); @@ -34,7 +34,7 @@ describe("panda preset shape", () => { }); it("squircleAmount accepts numeric values via shorthand squircleAmt", () => { - const u = preset.utilities.extend["squircleAmount"]!; + const u = preset.utilities!.extend!["squircleAmount"]!; expect(u.shorthand).toBe("squircleAmt"); expect(u.values).toEqual({ type: "number" }); }); @@ -43,11 +43,13 @@ describe("panda preset shape", () => { describe("panda preset transform output", () => { const preset = squirclePandaPreset(); const radiusToken = "var(--radii-md)"; // Panda passes the resolved CSS variable string + const mockToken = Object.assign(() => radiusToken, { raw: () => undefined }) as any; it("squircleRadius (all corners) emits camelCase keys with @supports block", () => { - const out = preset.utilities.extend["squircleRadius"]!.transform!(radiusToken, { - token: () => radiusToken, + const out = preset.utilities!.extend!["squircleRadius"]!.transform!(radiusToken, { + token: mockToken, raw: "md", + utils: { colorMix: () => ({ invalid: true, value: "" }) }, }); expect(out).toMatchInlineSnapshot(` { @@ -62,9 +64,10 @@ describe("panda preset transform output", () => { }); it("squircleTopLeftRadius (single corner) inlines calc without --squircle-r", () => { - const out = preset.utilities.extend["squircleTopLeftRadius"]!.transform!(radiusToken, { - token: () => radiusToken, + const out = preset.utilities!.extend!["squircleTopLeftRadius"]!.transform!(radiusToken, { + token: mockToken, raw: "md", + utils: { colorMix: () => ({ invalid: true, value: "" }) }, }); expect(out).toMatchInlineSnapshot(` { @@ -78,9 +81,10 @@ describe("panda preset transform output", () => { }); it("squircleTopRadius (multi-prop side) shares --squircle-r across both corners", () => { - const out = preset.utilities.extend["squircleTopRadius"]!.transform!(radiusToken, { - token: () => radiusToken, + const out = preset.utilities!.extend!["squircleTopRadius"]!.transform!(radiusToken, { + token: mockToken, raw: "md", + utils: { colorMix: () => ({ invalid: true, value: "" }) }, }); expect(out).toMatchInlineSnapshot(` { @@ -97,9 +101,10 @@ describe("panda preset transform output", () => { }); it("squircleAmount sets the variable and gates corner-shape", () => { - const out = preset.utilities.extend["squircleAmount"]!.transform!("3", { - token: () => "3", + const out = preset.utilities!.extend!["squircleAmount"]!.transform!("3", { + token: mockToken, raw: "3", + utils: { colorMix: () => ({ invalid: true, value: "" }) }, }); expect(out).toMatchInlineSnapshot(` { @@ -113,44 +118,33 @@ describe("panda preset transform output", () => { }); describe("panda preset options", () => { + const mockToken = Object.assign(() => "1rem", { raw: () => undefined }) as any; + const mockArgs = (raw: string) => ({ token: mockToken, raw, utils: { colorMix: () => ({ invalid: true, value: "" }) } }); + it("custom amtVar lands in every place the default --squircle-amt does", () => { const preset = squirclePandaPreset({ amtVar: "--my-amt" }); - // 1. radius transform — @supports calc references the custom var, and - // cornerShape uses it as the superellipse argument. - const radiusOut = preset.utilities.extend["squircleRadius"]!.transform!("1rem", { - token: () => "1rem", - raw: "1rem", - }) as Record; + const radiusOut = preset.utilities!.extend!["squircleRadius"]!.transform!("1rem", mockArgs("1rem")) as Record; const radiusSupports = radiusOut[ "@supports (corner-shape: superellipse(2))" ] as Record; expect(radiusSupports["--squircle-r"]).toContain("var(--my-amt, 2)"); expect(radiusSupports["cornerShape"]).toBe("superellipse(var(--my-amt, 2))"); - // 2. squircleAmount transform — writes the custom var and the @supports - // block reads it back. - const amtOut = preset.utilities.extend["squircleAmount"]!.transform!("3", { - token: () => "3", - raw: "3", - }) as Record; + const amtOut = preset.utilities!.extend!["squircleAmount"]!.transform!("3", mockArgs("3")) as Record; expect(amtOut["--my-amt"]).toBe("3"); const amtSupports = amtOut[ "@supports (corner-shape: superellipse(2))" ] as Record; expect(amtSupports["cornerShape"]).toBe("superellipse(var(--my-amt))"); - // 3. The default name does not appear anywhere when overridden. const allOutput = JSON.stringify({ radiusOut, amtOut }); expect(allOutput).not.toContain("--squircle-amt"); }); it("custom rVar threads through multi-prop side transforms", () => { const preset = squirclePandaPreset({ rVar: "--my-r" }); - const out = preset.utilities.extend["squircleTopRadius"]!.transform!("1rem", { - token: () => "1rem", - raw: "1rem", - }) as Record; + const out = preset.utilities!.extend!["squircleTopRadius"]!.transform!("1rem", mockArgs("1rem")) as Record; const supports = out["@supports (corner-shape: superellipse(2))"] as Record< string, string @@ -158,16 +152,12 @@ describe("panda preset options", () => { expect(supports["--my-r"]).toContain("calc(1rem"); expect(supports["borderTopLeftRadius"]).toBe("var(--my-r)"); expect(supports["borderTopRightRadius"]).toBe("var(--my-r)"); - // And the default --squircle-r is gone. expect(JSON.stringify(out)).not.toContain("--squircle-r"); }); it("amtVar and rVar can both be overridden together", () => { const preset = squirclePandaPreset({ amtVar: "--a", rVar: "--r" }); - const out = preset.utilities.extend["squircleRadius"]!.transform!("1rem", { - token: () => "1rem", - raw: "1rem", - }) as Record; + const out = preset.utilities!.extend!["squircleRadius"]!.transform!("1rem", mockArgs("1rem")) as Record; const supports = out["@supports (corner-shape: superellipse(2))"] as Record< string, string diff --git a/package/src/panda.ts b/package/src/panda.ts index 03e0449..6e3e764 100644 --- a/package/src/panda.ts +++ b/package/src/panda.ts @@ -1,3 +1,4 @@ +import { definePreset, type PropertyConfig } from "@pandacss/dev"; import { CAMEL_VARIANTS, DEFAULT_AMOUNT_VAR_NAME, @@ -6,21 +7,6 @@ import { variantEntries, } from "./variants"; -/** - * Panda CSS utility entry shape (subset). We do not depend on `@pandacss/dev` - * at runtime — the preset is a plain object literal and the consumer's Panda - * install loads it. Typing the public surface manually keeps `@pandacss/dev` - * an *optional* peer dependency and avoids versioning entanglement. - */ -type PandaUtility = { - shorthand?: string | string[]; - values?: string | string[] | Record | { type: string }; - transform?: ( - value: string, - helpers: { token: (path: string) => string; raw: string }, - ) => Record; -}; - export interface SquirclePandaPresetOptions { /** CSS custom property name for the superellipse amount (default: "--squircle-amt"). */ amtVar?: string; @@ -28,12 +14,6 @@ export interface SquirclePandaPresetOptions { rVar?: string; } -export interface SquirclePandaPreset { - name: string; - utilities: { extend: Record }; - conditions: { extend: Record }; -} - /** * Build the Panda preset object. Pass directly to `presets:` in `panda.config.ts`: * @@ -53,11 +33,11 @@ export interface SquirclePandaPreset { */ export function squirclePandaPreset( options: SquirclePandaPresetOptions = {}, -): SquirclePandaPreset { +) { const amtVar = options.amtVar ?? DEFAULT_AMOUNT_VAR_NAME; const rVar = options.rVar ?? "--squircle-r"; - const utilities: Record = {}; + const utilities: Record = {}; const variantBySuffix = new Map(variantEntries()); @@ -68,18 +48,15 @@ export function squirclePandaPreset( utilities[variant.property] = { shorthand: variant.shorthand, values: "radii", - transform: (value: string) => - squircleCssObj(props, value, { amtVar, rVar, case: "camel" }) as Record< - string, - unknown - >, + transform: (value) => + squircleCssObj(props, value, { amtVar, rVar, case: "camel" }) as any, }; } utilities["squircleAmount"] = { shorthand: "squircleAmt", values: { type: "number" }, - transform: (value: string) => ({ + transform: (value) => ({ [amtVar]: value, [SUPPORTS_RULE]: { cornerShape: `superellipse(var(${amtVar}))`, @@ -87,7 +64,7 @@ export function squirclePandaPreset( }), }; - return { + return definePreset({ name: "@klinking/squircle", utilities: { extend: utilities }, conditions: { @@ -95,7 +72,7 @@ export function squirclePandaPreset( squircleSupported: SUPPORTS_RULE, }, }, - }; + }); } export default squirclePandaPreset; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a734c7a..e8a643b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,9 +66,6 @@ importers: package: dependencies: - '@pandacss/dev': - specifier: '>=0.40.0' - version: 1.11.0(typescript@6.0.2) tailwind-merge: specifier: '>=2.0.0' version: 3.5.0 @@ -82,6 +79,9 @@ importers: '@babel/preset-typescript': specifier: ^7.28.0 version: 7.28.5(@babel/core@7.29.0) + '@pandacss/dev': + specifier: ^1.11.0 + version: 1.11.0(typescript@6.0.2) '@stylexjs/babel-plugin': specifier: ^0.18.3 version: 0.18.3 From 2936ffd5b783e1955427efcd4234ba6017b7c3d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 4 May 2026 23:02:36 +0000 Subject: [PATCH 14/15] docs: sync README code blocks --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4ca028a..15e7e96 100644 --- a/README.md +++ b/README.md @@ -840,6 +840,7 @@ export { squircle as default, squircleMergeConfig }; ```js import { a as squircleCssObj, i as SUPPORTS_RULE, o as variantEntries, t as CAMEL_VARIANTS } from "../variants-CUhqvLRq.mjs"; +import { definePreset } from "@pandacss/dev"; //#region src/panda.ts /** * Build the Panda preset object. Pass directly to `presets:` in `panda.config.ts`: @@ -884,11 +885,11 @@ function squirclePandaPreset(options = {}) { [SUPPORTS_RULE]: { cornerShape: `superellipse(var(${amtVar}))` } }) }; - return { + return definePreset({ name: "@klinking/squircle", utilities: { extend: utilities }, conditions: { extend: { squircleSupported: SUPPORTS_RULE } } - }; + }); } //#endregion export { squirclePandaPreset as default, squirclePandaPreset }; From 73c6546851e08be7a2acc7f01b079d8d91d4cf26 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 4 May 2026 16:25:28 -0700 Subject: [PATCH 15/15] chore: trigger CI