diff --git a/.github/workflows/sync-readme.yml b/.github/workflows/sync-readme.yml index 9dcb827..0ce8ab5 100644 --- a/.github/workflows/sync-readme.yml +++ b/.github/workflows/sync-readme.yml @@ -35,13 +35,33 @@ jobs: run: vp run sync-readme - name: Commit and push if changed + id: sync run: | - git diff --quiet README.md && exit 0 + if git diff --quiet README.md; then + echo "pushed=false" >> "$GITHUB_OUTPUT" + exit 0 + fi git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add README.md git commit -m "docs: sync README code blocks" - git push || { + if ! git push; then echo "::error::README is out of sync and could not push fix to branch" exit 1 - } + fi + echo "pushed=true" >> "$GITHUB_OUTPUT" + + # GitHub's anti-loop policy: pushes made with the default GITHUB_TOKEN + # don't fire `pull_request`/`push` events, so the synced commit would + # land on the PR with no CI run. Re-dispatch CI manually so the new HEAD + # gets validated. (For a "proper" fix that fires the synchronize event, + # plumb a PAT/App token through the checkout step's `token:` input.) + - name: Re-trigger CI on synced commit + if: steps.sync.outputs.pushed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: ${{ github.head_ref }} + run: | + gh workflow run ci.yml --ref "$BRANCH" + gh workflow run sync-readme.yml --ref "$BRANCH" + gh workflow run pr-title.yml --ref "$BRANCH" diff --git a/README.md b/README.md index 15e7e96..cd54174 100644 --- a/README.md +++ b/README.md @@ -540,50 +540,80 @@ Both are first-class. The copy/paste block is right below, and it's honestly may ## FAQ -### Does this work in Safari/Firefox/Chrome today? +
+Does this work in Safari/Firefox/Chrome today? Partially, at time of writing — recent Chrome ships `corner-shape`, Safari and Firefox are still catching up. Check [caniuse](https://caniuse.com/?search=corner-shape) for the current state. Either way you're fine: in a browser without support, you get a plain `border-radius` at the pre-correction value, which visually matches `rounded-*`. No broken layouts, no visible fallback weirdness. -### Does it work with Tailwind v3? +
+ +
+Does it work with Tailwind 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). -### Why do my corners look smaller with `corner-shape: superellipse` without this? +
+ +
+Why do my corners look smaller with corner-shape: superellipse without this? At the same `border-radius`, a squircle pokes further into the corner, so less of the box edge is rounded off. The fix is to scale the radius up so the visual roundness matches `rounded-*` — see [How the radius correction works](#how-the-radius-correction-works). -### Does this add runtime JS? +
+ +
+Does this add runtime JS? No. Everything is static CSS — the Tailwind utilities expand at build time into declarations with a native `calc()` the browser evaluates. The JS plugin also runs at build time only. Zero JS ships to the browser. -### What happens once `corner-shape` is universal? +
+ +
+What happens once corner-shape is universal? Nothing you need to do. The correction lives inside `@supports (corner-shape: superellipse(2))`, so it activates exactly when the shape does. Once the browser ships support, the shape applies _and_ the compensated radius applies, at the same moment. Your layout is identical before and after. -### Do I need `tailwind-merge`? +
+ +
+Do I need tailwind-merge? Only if your project already uses it. The extra config (`squircleMergeConfig`) exists so `rounded-lg squircle-md` de-duplicates the way you'd expect — otherwise tailwind-merge doesn't know `squircle-*` and `rounded-*` occupy the same slot. -### What's the difference between the utilities and the `squircle-radius()` function? +
+ +
+What's the difference between the utilities and the squircle-radius() function? The utilities expand to inline `calc()` at build time — they work in any browser that supports `calc()` + `pow()` (most current ones) and degrade to plain `border-radius` where `corner-shape` isn't supported. The `@function` form runs the same math at CSS runtime via CSS Values 5's `@function` — which is [experimental](https://caniuse.com/?search=%40function) (Chrome behind a flag, nothing else yet). Use the utilities unless you're specifically building for a non-Tailwind setup. -### Can I use a different `squircle-amt` for each corner? +
+ +
+Can I use a different squircle-amt for each corner? No. `corner-shape` is declared once per element, so all four corners share the same K. You can still mix per-corner _radii_ (`squircle-tl-lg squircle-br-sm`), but the squircle-ness is uniform across the element. -### Why is the tone of this README all over the place? +
+ +
+Why is the tone of this README all over the place? Because I made Claude write most of it, got mad at claude, re-wrote a lot of stuff myself, then got tired and let Claude win. -### Did you just let Claude write this? +
+ +
+Did you just let Claude write this? Kinda. Honestly I wrote the basic tailwind utilities by hand using a weird cobbled together formula I just kinda eyeballed to work for most values anyone would actually want to use for the `superellipse()` param. But then I thought, hey, robots are good at math, maybe they can make the formula _actually_ **correct**. And they could! The robots _could_ make a right formula. I was so happy. I cried tears of joy for days and days. So many tears I drowned my robot. And now I'll never code again. Alas. +
+ ## Copy/paste source If you'd rather not add a dependency, copy the source directly. Click to expand each file. @@ -757,12 +787,46 @@ If you'd rather not add a dependency, copy the source directly. Click to expand +
+tailwind/radius.css — the squircle-radius() CSS function + + + +```css +/* ── squircle-radius() ──────────────────────────────────────── + * Computes the visually-corrected border-radius for use with + * corner-shape: superellipse(). A superellipse corner appears + * tighter than a circular arc at the same radius, so the radius + * must be scaled up to preserve the intended visual size. + * + * --radius The target border-radius (any ). + * --squircle-amt The superellipse exponent passed to corner-shape. + * + * Parameters are untyped to preserve standard CSS resolution of + * relative units (em, rem, etc.) — they resolve in the context + * where the function result is applied, not at call time. + * + * Usage: + * border-radius: squircle-radius(1rem, 1.5); + * corner-shape: superellipse(1.5); + * ──────────────────────────────────────────────────────────── */ +@function squircle-radius(--radius, --squircle-amt) { + result: calc( + var(--radius) * (1 - pow(2, -0.5)) / (1 - pow(2, -1 * pow(2, -1 * var(--squircle-amt)))) + ); +} +``` + + + +
+
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 @@ -829,7 +893,9 @@ const squircleMergeConfig = { extend: { //#endregion export { squircle as default, squircleMergeConfig }; -//# sourceMappingURL=index.mjs.map``` +//# sourceMappingURL=index.mjs.map +``` +
@@ -838,7 +904,8 @@ export { squircle as default, squircleMergeConfig }; panda/index.mjs — the Panda CSS preset -```js + +````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 @@ -894,7 +961,9 @@ function squirclePandaPreset(options = {}) { //#endregion export { squirclePandaPreset as default, squirclePandaPreset }; -//# sourceMappingURL=index.mjs.map``` +//# sourceMappingURL=index.mjs.map +```` + @@ -903,7 +972,8 @@ export { squirclePandaPreset as default, squirclePandaPreset }; stylex/index.mjs — the StyleX dynamic-style preset -```js + +````js import * as stylex from "@stylexjs/stylex"; //#region src/stylex.ts /** @@ -1127,7 +1197,9 @@ const squircle = stylex.create({ //#endregion export { squircle }; -//# sourceMappingURL=index.mjs.map``` +//# sourceMappingURL=index.mjs.map +```` + @@ -1141,4 +1213,3 @@ export { squircle }; ## License MIT -```` diff --git a/scripts/sync-readme.sh b/scripts/sync-readme.sh index f7f0230..7f7c830 100755 --- a/scripts/sync-readme.sh +++ b/scripts/sync-readme.sh @@ -12,11 +12,15 @@ sync_file() { local begin="" local end="" - # Build replacement: marker, fenced code block, content, closing fence + # Build replacement: marker, fenced code block, content, closing fence. + # Some bundled dist files have no trailing newline, which would glue the + # closing fence to the last source line (e.g. `//# sourceMappingURL=…```) + # and prevent the fence from closing — so force a newline before it. { echo "$begin" echo "\`\`\`$lang" cat "$src" + [ -z "$(tail -c 1 "$src")" ] || echo "" echo "\`\`\`" } > "$REPO_ROOT/.sync-block.tmp" @@ -76,6 +80,7 @@ sync_toc() { } sync_file "dist/tailwind/utils.css" "css" "package/dist/tailwind/utils.css" +sync_file "dist/tailwind/radius.css" "css" "package/dist/tailwind/radius.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"