Skip to content

refactor(ui): move Tabs and Table into the kit, and start policing it - #786

Open
markhayden wants to merge 1 commit into
mainfrom
feat/kit-tabs-table-relocation
Open

refactor(ui): move Tabs and Table into the kit, and start policing it#786
markhayden wants to merge 1 commit into
mainfrom
feat/kit-tabs-table-relocation

Conversation

@markhayden

Copy link
Copy Markdown
Owner

Came out of the PR 4 host-chrome audit. The styling migration follows separately — this is the structural finding that audit surfaced.

The finding

Tabs* and Table* — two public kit component families — had their real implementations in root src/components/ui/ while every peer lived in packages/ui. The SDK published them with export *, which is how their structural sub-parts (TableCaption, TabsContent, …) ended up in the public surface undocumented. The other seven files there are thin re-export shims, untouched.

  • Both move to packages/ui/src/primitives/, switching to the kit's own cn.
  • export * becomes an explicit list — deliberately not narrowed. The public API freeze is byte-identical at 300 values / 404 types, so the surface becomes intentional without breaking a single consumer.

The coupled problem it exposed

packages/ui was the one browser surface the legacy-styles ratchet never scanned. Relocating these files would have silently erased 25 tracked units and orphaned an approved exception — the ledger would have reported a 25-unit improvement for work nobody did.

ui:legacy-styles:generate refused to run. That's #783's check doing exactly its job.

So the scanner now covers packages/ui/src. Two refinements keep the baseline honest rather than noisy:

Token applications aren't magic numbers. An arbitrary value resolving a --bakin-* property is the token system working — and sometimes the only correct spelling. text-[length:var(--bakin-typography-size-meta)] exists precisely because the shorthand shares the text-* merge group with colour and gets silently dropped. Counting those as debt flagged the prescribed pattern — including the primitive added in #782 — as a violation, which teaches people to ignore the ratchet. Literal values (w-[240px]) still count. Kit arbitrary-size: 244 → 55, and it's a fleet-wide correction.

Generated artifacts are excluded. The token files define the palette in hex because that is their job; you fix the generator, not the output. That's 60 of the 64 raw-palette hits.

What the numbers mean

before after
paths 106 174
units 982 1135

Every one of those +153 is pre-existing code becoming visible — zero lines of product code changed. The naive version of this would have recorded +402, most of it false.

This also closes the gap I've flagged twice: the kit being unpoliced is what let the WorkspacePage font-size drop ship unnoticed.

Census

102 → 100, because the census never tracked packages/ui at all. Button, Card, and Badge are uncensused too — Tabs and Table are joining their peers, not losing coverage.

Verification

typecheck ✅ · lint ✅ (0 errors) · bun test tests/ui/ tests/components/ tests/architecture/ tests/scripts/1326 pass, 0 fail

Gates: public-api (byte-identical), census, kit-coverage, performance, legacy-styles, check-cycles — all green. Vendor chunks consolidated 36 → 35 because the SDK no longer reaches across into root src/.

🤖 Generated with Claude Code

Two public kit component families had their real implementations in the
root `src/components/ui/` tree while every peer lived in `packages/ui`,
and the SDK published them with `export *` — which is how their
structural sub-parts (TableCaption, TabsContent, …) ended up in the
public surface undocumented. The other seven files there are thin
re-export shims and are untouched.

- Both implementations move to `packages/ui/src/primitives/`, switching
  from the app's `@/lib/utils` cn to the kit's own.
- `export *` becomes an explicit list. Deliberately NOT narrowed: the
  public API freeze is byte-identical at 300 values / 404 types, so this
  makes the surface intentional without breaking a single consumer.

The move exposed a coupled problem. `packages/ui` was the ONE browser
surface the legacy-styles ratchet never scanned, so relocating these
files would have silently erased 25 tracked units and orphaned an
approved exception — the ledger would have reported a 25-unit
improvement for work nobody did. `ui:legacy-styles:generate` refused to
run, which is the check from #783 doing its job.

So the scanner now covers `packages/ui/src`. Two refinements keep that
baseline honest rather than noisy:

- An arbitrary value that resolves a `--bakin-*` custom property is the
  token system being applied, not a magic number. Sometimes it is the
  ONLY correct spelling: `text-[length:var(--bakin-typography-size-meta)]`
  exists because the shorthand shares the `text-*` merge group with
  colour and gets silently dropped. Counting those as debt flagged the
  prescribed pattern — including the primitive added in #782 — as a
  violation. Literal values (`w-[240px]`) still count. This drops the
  kit's arbitrary-size from 244 to 55 and is a fleet-wide correction.
- Generated artifacts are excluded. The token files define the palette in
  hex because that is their job; you fix the generator, not the output.
  That is 60 of the 64 raw-palette hits.

Net: 106 -> 174 paths, 982 -> 1135 units. Every one of those +153 is
pre-existing code becoming visible — zero lines of product code changed.
The naive version of this would have recorded +402.

Census drops 102 -> 100 because it never tracked `packages/ui` at all;
Button, Card, and Badge are uncensused too, so Tabs and Table are simply
joining their peers.

Co-Authored-By: Claude Opus 5 (1M context) <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