feat: StyleX + Panda support, demos, and reorganized package exports - #29
Merged
Merged
Conversation
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
- 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) <noreply@anthropic.com>
…folders
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) <noreply@anthropic.com>
dogmar
force-pushed
the
feat/stylex-support
branch
from
May 4, 2026 22:06
c417c8b to
bd093cc
Compare
dogmar
marked this pull request as ready for review
May 4, 2026 22:14
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
- 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) <noreply@anthropic.com>
Contributor
|
🎉 This PR is included in version 0.9.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three things land together because the demos exercise both the new integrations and the reorganized exports — splitting them up would create cross-cutting churn:
New StyleX integration (
@klinking/squircle/stylex) — squircle utilities authored as a singlestylex.create({ … })literal of dynamic-style functions. Each variant takes(radius, amt)and emits aborderRadius+cornerShapepair gated on@supports (corner-shape: superellipse(2)).amtfalls back tovar(--squircle-amt, 2)via nullish-coalesce inside template literals (StyleX disallows default param values on dynamic styles). 9 compile tests pin the babel output for every variant.Reorganized package exports under per-system folders (breaking).
@klinking/squircle/tw-plugin@klinking/squircle/tailwind@klinking/squircle/tw-merge-cfg@klinking/squircle/tailwind(named export)@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/stylexThe Tailwind plugin and tailwind-merge config now ship from a single file (
dist/tailwind/index.mjs) per request — plugin is the default export,squircleMergeConfigis named.Three matching demo pages on the website (
/demos/tailwind,/demos/stylex,/demos/panda) — each shows a live in-page demo (same visual layout across all three) followed by a StackBlitz embed of a standalonewebsite/examples/<system>/project. Semantic color tokens —demoPlain/demoSquircle/demoAmount/demoCorner— are defined natively in each system (Tailwind@theme, StyleXdefineVars, PandasemanticTokens) so the same logical concept produces the same color across all three.What's not in this PR
dogmar/squircle@main, so they'll start populating after merge.Test plan
vp run buildproduces the newdist/tailwind/,dist/panda/,dist/stylex/layoutvp run test— 183 tests pass (incl. 9 stylex-compile, 11 panda-preset, 77 tailwind plugin, 83 css extraction, 3 radius-css)astro buildsucceeds for all five website pagesastro devrenders all three demo pages with the squircle effect applied via each integration's native API🤖 Generated with Claude Code