Skip to content

chore: never hard-wrap markdown, update @tenphi/tasty to 3.3.1 - #1345

Merged
tenphi merged 5 commits into
mainfrom
chore/tasty-3.2.0
Aug 24, 2026
Merged

chore: never hard-wrap markdown, update @tenphi/tasty to 3.3.1#1345
tenphi merged 5 commits into
mainfrom
chore/tasty-3.2.0

Conversation

@tenphi

@tenphi tenphi commented Aug 24, 2026

Copy link
Copy Markdown
Member

Markdown is never hard-wrapped

One paragraph is one line, in every .md and .mdx file — docs, AGENTS.md, specs, changesets. Hard wrapping is what made these files awkward to edit and to review: a one-word change reflows the paragraph, so the diff reads as a full rewrite and every editor disagrees about where the breaks belong.

Enforced rather than asked for:

  • proseWrap: 'never' in .prettierrc.cjs, with embeddedLanguageFormatting: 'off' for *.md/*.mdx — code fences in docs are illustrative snippets, not source files, and formatting them would rewrite deliberate pseudo-code.
  • *.{md,mdx} added to the prettier / prettier:fix scripts (so pnpm lint and CI check it) and to .lintstagedrc (so a commit fixes it).
  • New .prettierignore keeps generated output out: CHANGELOG.md (changesets owns it), dist, storybook builds, the lockfile.
  • The rule itself is written down in docs/rules/coding.md, pointed at from AGENTS.md, CONTRIBUTING.md and the add-changeset command.

97 Markdown files are unwrapped in this pass. pnpm build-docs builds clean, so every reformatted .docs.mdx still compiles.

One file needed a manual touch: a bullet in Board.docs.mdx mixing inline JSX with wrapped prose made Prettier oscillate between two indentations — check and write disagreeing forever. Joining it into one line settles it, and the condition needs already-wrapped source to reproduce.

A latent bug the unwrap surfaced

no-redundant-default-prop's registry is parsed line by line out of *.docs.mdx, and a prop only becomes a candidate when its bullet carries the (default: …) annotation on the same line as the prop name. A hard-wrapped bullet hid its own default. Three come back — ItemTable's size and summary, and Pagination's summary — each proven against the component it belongs to by the usual generator, not just parsed. defaults.generated.ts is regenerated; the note in docs/rules/eslint-plugin.md now says why wrapping breaks it.

Tasty 3.3.1

Straight from 3.1.0 to 3.3.1, and two of the three changes reach this repo.

Color tokens no longer emit a decomposed companion variable, and colorSpace is deprecated. A #name token used to declare --name-color plus a companion — --name-color-rgb here, since Root configured colorSpace: 'rgb' — and the companion is what's gone; --name-color is emitted exactly as authored. Opacity has used relative color syntax since 3.1.0, so nothing inside Tasty still needed the channels. Two things had to change here: Root stops setting colorSpace (it now warns in dev and does nothing), and the two rgb(var(--primary-color-rgb) / .2) selection rules in GlobalStyles become oklch(from var(--primary-color) l c h / .2). Left alone they would have silently stopped resolving — the PrismCode selection highlight would just have gone transparent. The replacement is the same pattern Tasty itself emits (--scrollbar-thumb-color), so it adds no browser floor. This is why the changeset is minor: a consumer reading a companion in their own CSS is broken the same way. Computed colors also serialize in the space the token was authored in now, so getComputedStyle(el).backgroundColor returns oklch(…) where it returned rgb(…) — same color, but any test parsing those strings by hand has to stop assuming sRGB syntax. That is what broke the DataTable browser tests below.

The inherited color is readable as a color through $current-color. #current stays the currentcolor keyword, so it still resolves against the element reading it — 3.3.0 briefly made it var(--current-color), which broke the current.primary disabled chip (the fill stopped inheriting the fade its own color applies and rendered at full strength); 3.3.1 restores the keyword and publishes the variable alongside instead, for the cases the keyword cannot serve. Verified on 3.3.1: the disabled chip measures oklab(0.571 0.0173617 -0.0955352 / 0.4), byte for byte its 3.1.0 value. Nothing in the kit had to change.

Opt-in batched injection (from 3.2.0): configure({ batchInjection: true }) + <TastyBatchProvider> collapse a commit's stylesheet writes into one flush, for trees that measure layout during render. Off unless an app turns it on.

Size, both sides rebuilt locally against 3.1.0: All 509.94 → 508.53 kB (−1.41 kB), Button-only 124.03 → 121.76 kB (−2.27 kB). 3.2.0's batching cost 0.68 kB on the Button entry; 3.3.0 then gave back 2.96 kB by deleting the color-space decomposition. Both budgets are unchanged at 515 kB and 125 kB, with the readings and the reasoning recorded in .size-limit.cjs as that file asks.

Verification

  • pnpm test — 2093 passed, 1 skipped, 0 failed
  • pnpm test:browser — 123 passed (the DataTable color helpers now resolve any color syntax through a canvas instead of parsing rgb(...) by hand)
  • pnpm lint — clean
  • pnpm build-docs — clean
  • pnpm size — 508.53 / 515 kB and 121.76 / 125 kB
  • Rebased on main (3e5e3fee); the Tooltip docs it brought in are unwrapped too

🤖 Generated with Claude Code


Note

Medium Risk
The Tasty minor upgrade changes emitted CSS variables and computed color serialization, which can break consumer styles and tests that assumed -rgb companions or rgb(...) strings; the in-repo migration is small but the dependency bump is library-wide.

Overview
Markdown prose is enforced as single-line paragraphs across the repo: Prettier gets proseWrap: 'never', MD/MDX overrides, .prettierignore, lint-staged + pnpm lint coverage, and documented rules in CONTRIBUTING / docs/rules/coding.md. ~97 .md/.mdx files are reformatted to match.

@tenphi/tasty moves from 3.1.0 to 3.3.1 (minor changeset). The kit drops configure({ colorSpace: 'rgb' }) in Root and rewrites Prism selection highlights in GlobalStyles from rgb(var(--primary-color-rgb) / …) to relative oklch(from var(--primary-color) …) so they keep working now that tokens no longer emit -rgb companions. Consumers who still reference companion variables in custom CSS need the same migration; computed color strings may serialize as oklch/oklab instead of rgb.

Docs unwrap fixes the ESLint defaults registry: line-based parsing of (default: …) in *.docs.mdx regains ItemTable size/summary and Pagination summary; defaults.generated.ts is regenerated and docs/rules/eslint-plugin.md explains the coupling.

Tooling-only follow-ups: size-limit comment updates for the Tasty bundle delta, changeset/agent guidelines to write unwrapped summaries, and widespread .docs.mdx whitespace/formatting with no API changes beyond the Tasty/CSS items above.

Reviewed by Cursor Bugbot for commit 1035d18. Bugbot is set up for automated code reviews on this repo. Configure here.

@changeset-bot

changeset-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1035d18

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cube-dev/ui-kit Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cube-ui-kit Ready Ready Preview Aug 24, 2026 4:25pm

Request Review

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

📦 NPM canary release

Deployed canary version 0.0.0-canary-20121c0.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

🧪 Storybook is successfully deployed!

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

🏋️ Size limit report

Name Size Passed?
All 497.02 KB (-0.29% 🔽👏) Yes 🎉
Tree shaking (just a Button) 118.91 KB (-1.84% 🔽👏) Yes 🎉

Compared against main at 3755065run 32750166384, 2026-08-24T16:19:32Z.

To see which modules changed, download the size-limit-statoscope-report artifact from this run and open report.html.

@tenphi
tenphi force-pushed the chore/tasty-3.2.0 branch from 920f98b to b84229c Compare August 24, 2026 14:53
@tenphi tenphi changed the title chore: never hard-wrap markdown, update @tenphi/tasty to 3.2.0 chore: never hard-wrap markdown, update @tenphi/tasty to 3.3.0 Aug 24, 2026
@tenphi tenphi changed the title chore: never hard-wrap markdown, update @tenphi/tasty to 3.3.0 chore: never hard-wrap markdown, update @tenphi/tasty to 3.3.1 Aug 24, 2026
tenphi and others added 5 commits August 24, 2026 18:20
Prose in Markdown is now unwrapped everywhere: one paragraph is one line, in
every .md and .mdx file. Hard wrapping is what made these files awkward to edit
and to review — a one-word change reflows the paragraph, so the diff reads as a
full rewrite.

Enforced by Prettier: `proseWrap: 'never'`, `*.{md,mdx}` added to the prettier
scripts and to lint-staged, plus a .prettierignore for generated output
(CHANGELOG.md, dist, storybook builds). Code fences are left alone
(`embeddedLanguageFormatting: 'off'`) — they are illustrative snippets, not
source files.

The unwrap also fixed a latent bug: the eslint-plugin defaults registry is
parsed line by line out of *.docs.mdx, so a `(default: ...)` annotation that had
been wrapped onto the next line was invisible to it. Three defaults come back —
ItemTable's `size` and `summary`, and Pagination's `summary`.

Tasty 3.2.0 adds opt-in batched style injection (`batchInjection`,
`TastyBatchProvider`, `flushStyles`). +0.69 kB gzipped on `All` and +0.68 kB on
the Button-only entry, both sides rebuilt locally; the Button budget goes to
126 kB since 290 B of headroom is thinner than the note there allows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two things in 3.3.0 reach this repo.

Color tokens no longer emit a decomposed companion variable, and
`configure({ colorSpace })` is deprecated — it warns in development and does
nothing. `Root` no longer sets it, and the two `rgb(var(--primary-color-rgb) /
.2)` selection rules in `GlobalStyles` are rewritten as
`oklch(from var(--primary-color) l c h / .2)`: the companion they read is gone,
so they would have silently stopped resolving. Same pattern Tasty itself now
emits, so no new browser floor.

`#current` resolves through `var(--current-color)` rather than the
`currentcolor` keyword, which is what lets a token defined as `#current` be
faded from Safari 16.4 instead of 18. Nothing here had to change for it.

Size, both sides rebuilt locally against 3.1.0: All 509.94 -> 508.53 kB
(-1.41 kB), Button-only 124.03 -> 121.75 kB (-2.28 kB). 3.2.0's batching cost
0.68 kB and 3.3.0 gave back 2.96 kB with the color-space machinery, so the
Button budget stays at its original 125 kB.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`current.primary` fills with the color it inherits and punches the label out of
it with `#current-fill`, and its disabled state is expressed once, in `color`:
the fill resolved `currentcolor` against the element's own faded color, so the
chip came along for free.

Tasty 3.3.0 compiles a bare `#current` to `var(--current-color)`. Every `color`
publishes that variable except one that reads the inherited color itself — a
self-reference — which is exactly what this flavour's disabled `#current.4` is.
The fill kept reading the ancestor's unfaded color, so a disabled chip rendered
at full strength: measured `oklch(0.571 0.0971 280.3)` against 3.2.0's
`oklab(0.571 0.0173617 -0.0955352 / 0.4)`.

Writing the three fill layers as the `currentcolor` keyword restores the old
resolution exactly (both computed values now match 3.2.0 byte for byte). Only
this flavour was affected: every other `current` step is a `#current.N` fade,
which still compiles to a `color-mix()` against the keyword in every property.

The DataTable column-color browser tests were reading `getComputedStyle`
colors by hand as `rgb(...)`. Tokens now serialize in the space they were
authored in — OKLCH — so the helper parsed lightness/chroma/hue as 0-255
channels and every legible pair measured a contrast of 1.0. Both helpers now
resolve a color through a canvas, whatever its syntax.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.3.1 restores `#current` to the `currentcolor` keyword, so it resolves against
the element that reads it again — which is what lets a ramp express its disabled
state once, in `color`, and have everything painted from `#current` below it
fade along. The kit-side workaround for 3.3.0 (writing `current.primary`'s fill
layers as the literal keyword) is reverted; the disabled chip measures
`oklab(0.571 0.0173617 -0.0955352 / 0.4)`, byte for byte what it was on 3.1.0.

The inherited color stays readable as a color through `$current-color` for the
cases the keyword cannot serve — published beside every `color`, and
deliberately not published by a value that already reads what it inherits.

Size, both sides rebuilt locally against 3.1.0: All 509.94 -> 508.53 kB,
Button-only 124.03 -> 121.76 kB. Both budgets unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`main`'s cols x rows matrix docs arrived hard-wrapped, which is what CI caught:
the PR is tested on the merge commit, so new wrapped prose fails
`prettier --check` even when both sides pass on their own. Also records the
post-merge size reading, which moves by that feature's 0.42 kB and not the
dependency's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tenphi
tenphi force-pushed the chore/tasty-3.2.0 branch from 0d82ec7 to 1035d18 Compare August 24, 2026 16:24
@tenphi
tenphi merged commit 8fdee38 into main Aug 24, 2026
16 checks passed
@tenphi
tenphi deleted the chore/tasty-3.2.0 branch August 24, 2026 16:58
@tenphi tenphi mentioned this pull request Aug 24, 2026
tenphi added a commit that referenced this pull request Aug 25, 2026
Resolves the conflicts from main's tasty 3.3.1 upgrade (#1345):

- package.json / pnpm-lock.yaml: drop this branch's exact 3.2.0 pin in
  favour of main's `^3.3.1`. The StrictMode window-leak fix this branch
  pinned for shipped in 3.2.0, so 3.3.1 carries it.
- Root.tsx `configure()`: keep main's removal of `colorSpace: 'rgb'`
  alongside this branch's `batchInjection: true`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tenphi added a commit that referenced this pull request Aug 25, 2026
Conflicts were the markdown unwrap (#1345) meeting the `scheme` → `schema`
rename: took main's unwrapped docs and re-applied the rename, then
re-added the two new doc sections unwrapped.

Also dedupes the watcher: `resolve.ts` (#1351) had grown its own
appearance store over the same two attributes and two media queries, so
it now subscribes through `subscribeSchema()`, which owns the definition.
Its stricter guards (no `matchMedia`, no `MutationObserver`) moved into
that module with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant