Skip to content

feat: StyleX + Panda support, demos, and reorganized package exports - #29

Merged
dogmar merged 15 commits into
mainfrom
feat/stylex-support
May 4, 2026
Merged

dogmar merged 15 commits into
mainfrom
feat/stylex-support

Conversation

@dogmar

@dogmar dogmar commented May 3, 2026

Copy link
Copy Markdown
Collaborator

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:

  1. New StyleX integration (@klinking/squircle/stylex) — squircle utilities authored as a single stylex.create({ … }) literal of dynamic-style functions. Each variant takes (radius, amt) and emits a borderRadius + cornerShape pair gated on @supports (corner-shape: superellipse(2)). amt falls back to var(--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.

  2. Reorganized package exports under per-system folders (breaking).

    Old New
    @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
    (new) @klinking/squircle/stylex

    The Tailwind plugin and tailwind-merge config now ship from a single file (dist/tailwind/index.mjs) per request — plugin is the default export, squircleMergeConfig is named.

  3. 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 standalone website/examples/<system>/ project. Semantic color tokens — demoPlain / demoSquircle / demoAmount / demoCorner — are defined natively in each system (Tailwind @theme, StyleX defineVars, Panda semanticTokens) so the same logical concept produces the same color across all three.

What's not in this PR

  • The package version bump is left for a follow-up; consumers will see the new layout once published.
  • The StackBlitz iframes pull from dogmar/squircle@main, so they'll start populating after merge.

Test plan

  • vp run build produces the new dist/tailwind/, dist/panda/, dist/stylex/ layout
  • vp run test — 183 tests pass (incl. 9 stylex-compile, 11 panda-preset, 77 tailwind plugin, 83 css extraction, 3 radius-css)
  • astro build succeeds for all five website pages
  • astro dev renders all three demo pages with the squircle effect applied via each integration's native API

🤖 Generated with Claude Code

dogmar and others added 6 commits May 3, 2026 13:35
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
dogmar force-pushed the feat/stylex-support branch from c417c8b to bd093cc Compare May 4, 2026 22:06
@dogmar dogmar changed the title WIP: StyleX support investigation (#27) feat: StyleX + Panda support, demos, and reorganized package exports May 4, 2026
@dogmar
dogmar marked this pull request as ready for review May 4, 2026 22:14
dogmar and others added 8 commits May 4, 2026 15:22
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>
@dogmar
dogmar merged commit 86668b2 into main May 4, 2026
4 checks passed
@dogmar
dogmar deleted the feat/stylex-support branch May 4, 2026 23:38
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 0.9.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant