You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit c417c8b
Browse filesBrowse the repository at this point in the historyBrowse files
Panda preset: definePreset-style export with the full 15-utility radius
matrix, naming follows Panda's borderRadius / rounded convention. Tests
+ snapshots cover shape, transform output, custom amtVar/rVar options.
StyleX: helpers + factory written but parked. Real @stylexjs/babel-plugin
probes confirmed the static analyzer rejects every function call and
computed @-rule key inside stylex.create(). Boundary tests in
squircle.stylex.compile.test.ts pin the failure modes for future
re-evaluation. Vanilla CSS sidecar (dist/squircle.css) added as the
practical workaround. Full research + recommended paths forward
captured in package/docs/stylex-research.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@@ -9,7 +9,6 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no
9
9
## Contents
10
10
11
11
<!-- BEGIN:toc -->
12
-
13
12
-[Requirements](#requirements)
14
13
-[Install & setup](#install--setup)
15
14
-[Utilities](#utilities)
@@ -43,7 +42,7 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no
43
42
npm install @klinking/squircle
44
43
```
45
44
46
-
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.
45
+
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/) helpers — both produce the exact same `@supports`-gated visual correction, just wired through their respective build pipelines.
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:
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.
133
+
134
+
The preset accepts the same `amtVar` / `rVar` options as the Tailwind plugin if you need to rename the underlying CSS variables:
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).
141
+
142
+
### Path D: StyleX
143
+
144
+
For [StyleX](https://stylexjs.com/) projects, the package exposes parametric helpers and a factory — there's no baked-in radius set; you bring your own theme via `stylex.defineVars(...)`.
145
+
146
+
**Bundler setup:** add the package path to your StyleX bundler plugin's `include` config so the helpers are processed:
147
+
148
+
```ts
149
+
// vite.config.ts (or your StyleX plugin equivalent)
The full helper set mirrors the Panda table above (`squircle`, `squircleTop`, …, `squircleEndEnd`). Each one returns a StyleX style object whose `borderRadius` (or per-corner equivalent) and `cornerShape` properties carry per-property `@supports (corner-shape: superellipse(2))` conditional values, so unsupported browsers fall back to plain `border-radius`.
187
+
188
+
Override the superellipse exponent at call time by passing a second argument: `squircle("1rem", 3)` (number) or `squircle("1rem", "var(--my-amt, 2)")` (var expression). The CSS variable name read by default (`--squircle-amt`) is exported as `SQUIRCLE_AMOUNT_VAR`.
189
+
91
190
## Utilities
92
191
93
192
| Utility | Equivalent | Description |
@@ -355,7 +454,6 @@ If you'd rather not add a dependency, copy the source directly. Click to expand
355
454
<summary><strong><code>tw-utils.css</code></strong> — the Tailwind utilities</summary>
Status: **paused**, picked back up on this branch (`feat/stylex-support`). The Panda preset shipped on the parent branch; StyleX needs more design thought before merging.
4
+
5
+
## Why this is paused
6
+
7
+
StyleX's babel/swc plugin requires `stylex.create(...)` to receive a fully-static object literal. **Every "factory" or "helper that returns a style object" pattern is rejected at compile time.** Verified directly against `@stylexjs/babel-plugin@0.18.3` — see [`squircle.stylex.compile.test.ts`](../src/squircle.stylex.compile.test.ts) for the live boundary tests. Specifically:
|`stylex.create({ a: { padding: corrected('1rem') } })` (function call in value) | ❌ rejects | same as above |
16
+
17
+
The `defineSquircleVariants(stylex.defineVars(...))` API the original plan called for is therefore impossible to ship as a working StyleX-native API today. This was discovered after the JS module was already written and unit-tested in isolation — the unit tests passed because they only verified the plain-JS return shape, not the babel plugin's acceptance of those calls inside `stylex.create`.
18
+
19
+
## What ships on this branch
20
+
21
+
The work-in-progress for the StyleX entry. All files exist; the unit tests pass; the **boundary tests pass** (proving the patterns DO fail as expected); but no consumer-visible API on this branch is wired up to actually solve a real StyleX user's problem yet.
22
+
23
+
-[`package/src/squircle.stylex.ts`](../src/squircle.stylex.ts) — JS helpers (`squircle()`, `squircleTopLeft()`, …, `defineSquircleVariants()`) + constants (`SQUIRCLE_AMOUNT_VAR`, `SQUIRCLE_SUPPORTS_QUERY`) + `correctedRadiusCalc()`. Helpers return plain object literals in StyleX's per-property conditional-value shape. Module docstring **already documents** that they cannot be used inside `stylex.create()`. Useful for: (a) build-time codegen, (b) emotion / styled-components / vanilla-extract / inline styles where function calls in style values are allowed.
24
+
-[`package/src/squircle.stylex.test.ts`](../src/squircle.stylex.test.ts) — 11 unit tests on helper return shape (kept passing).
25
+
-[`package/src/squircle.stylex.compile.test.ts`](../src/squircle.stylex.compile.test.ts) — real `@stylexjs/babel-plugin` integration tests. Pin both the working "hand-written literal" pattern and the rejected boundary patterns. Resume here when StyleX ships changes.
26
+
-[`package/src/squircle-css-sidecar.test.ts`](../src/squircle-css-sidecar.test.ts) — validates the vanilla CSS sidecar.
27
+
-[`package/scripts/generate-squircle-css.ts`](../scripts/generate-squircle-css.ts) — added `generateVanillaCss()` that emits `dist/squircle.css` with plain `.squircle-md` etc. classes (no `@utility` directive). Default Tailwind-ish radii (xs/sm/md/lg/xl/2xl/3xl/4xl/full) baked in.
// <div className="squircle-md" /> alongside any stylex.props(...) styles
43
+
```
44
+
45
+
The class names are inert — they don't go through StyleX's compiler at all, so the static-analysis problem is avoided entirely. The only down-side is class-name collision risk if a consumer also defines `.squircle-md` somewhere; the radii set is fixed to a Tailwind-ish default; and it doesn't compose with `stylex.defineVars` / `stylex.createTheme` for theming.
46
+
47
+
### Option 2 — Codegen CLI (most StyleX-native)
48
+
49
+
Ship a one-shot script (e.g. `npx @klinking/squircle/codegen --radii=sm:0.25rem,md:0.375rem --side=all --out=src/squircle.stylex.ts`) that emits a literal `*.stylex.ts` file the consumer checks in. The emitted file is a hand-written `stylex.create({...})` literal so StyleX's compiler is happy.
50
+
51
+
This is the only path that lets a StyleX consumer use *their own*`defineVars` radii and still get the full StyleX-native experience (`stylex.props(squircleStyles.md)`). The cost is meaningful: we'd ship a CLI, document a "regenerate after changing your radii" workflow, and the generated file would be a new artifact in the consumer's repo.
52
+
53
+
The existing `defineSquircleVariants()` helper is *exactly* what such a CLI would call internally — that's its real reason for existing. Resume here by:
54
+
55
+
1. Add a `bin` entry in `package.json`.
56
+
2. Wrap `defineSquircleVariants` in a small CLI that JSON-stringifies the output and writes it as a `stylex.create(...)` literal source file.
57
+
3. Test the generated file by running it through `@stylexjs/babel-plugin` (the test scaffold already exists in `squircle.stylex.compile.test.ts`).
58
+
59
+
### Option 3 — Babel macro
60
+
61
+
A `babel-plugin-macros`-style import that inlines the `stylex.create({...})` literal at consumer compile time. Works around the static-analysis problem by transforming the source before StyleX sees it. Cost: depends on `babel-plugin-macros` (not universally installed), adds a runtime dependency, more complex to debug. Probably not worth it given Option 2 covers the same use case more transparently.
62
+
63
+
### Option that does **not** work — pre-baked `stylex.create`
64
+
65
+
Could ship `stylex.create({...})` calls in the package's own source, processed by `@stylexjs/babel-plugin` at our build time. Two blockers: (a) we don't know the consumer's radii, and (b) atomic class names hash with version coupling, so consumers' bundlers re-process the package source anyway. The user's earlier instruction — "no default export with tailwind radii" — also rules this out by preference.
66
+
67
+
## How to resume
68
+
69
+
```bash
70
+
git checkout feat/stylex-support
71
+
cd package
72
+
pnpm install
73
+
vp run @klinking/squircle#test:stylex-compile # runs the boundary tests
74
+
```
75
+
76
+
The boundary tests are the canary: re-run them against newer `@stylexjs/babel-plugin` versions to see if any of the rejected patterns become accepted. If they do, the factory API may become viable.
77
+
78
+
When picking a direction:
79
+
80
+
- For Option 1 (sidecar): just merge this branch as-is, write the README path, done.
81
+
- For Option 2 (codegen): keep everything on this branch, add a `bin/squircle-stylex-codegen.ts`, add CLI args parsing, generate a sample output file, snapshot-test it, run it through the babel plugin to verify, document.
82
+
- For Option 3 (macro): start a fresh branch — different dependency surface, different mental model.
83
+
84
+
## Key files
85
+
86
+
-`package/src/squircle.stylex.ts:46` — module docstring with the "do not call inside `stylex.create`" warning.
87
+
-`package/src/squircle.stylex.compile.test.ts:60` — verified working pattern (hand-written literal).
88
+
-`package/src/squircle.stylex.compile.test.ts:91` — boundary tests pinning the failure modes.
1.`vp run @klinking/squircle#build` — must produce `dist/squircle.css` and `dist/stylex.mjs`.
94
+
2.`vp run @klinking/squircle#test:sidecar` — sidecar shape.
95
+
3.`vp run @klinking/squircle#test:stylex` — JS helper unit tests.
96
+
4.`vp run @klinking/squircle#test:stylex-compile` — real babel-plugin integration.
97
+
5. Manual smoke in `website/` — add a tiny example component, check DevTools that `@supports (corner-shape: superellipse(2))` activates in supporting browsers and falls back cleanly elsewhere.
0 commit comments