Skip to content

feat!: attributes only (BON-26) - #58

Merged
hunterbecton merged 18 commits into
mainfrom
hunter/bon-26-attributes-only-drop-the-js-helpers-one-stylesheet-with-data
Aug 30, 2026
Merged

feat!: attributes only (BON-26)#58
hunterbecton merged 18 commits into
mainfrom
hunter/bon-26-attributes-only-drop-the-js-helpers-one-stylesheet-with-data

Conversation

@hunterbecton

@hunterbecton hunterbecton commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

The stylesheet is now the whole rendering API. Under aria-busy="true" (on or above an element), every leaf paints as a bar and every image or control as a box; data-bones-type, data-bones-lines, data-bones-auto, and data-bones-animate adjust that and are inert otherwise. Inferred rules live in @layer bones-auto; explicit rules are unlayered. data-bones-lines="N" paints N bars in one element (enumerated 2–8 everywhere, any integer where advanced attr() exists). An img with no src gets a box and a transparent pixel.

Removed: createBones, forceBones, readPromise, minMax, isMinMax, resolveLength, boneAttributes, TRANSPARENT_PIXEL, the React BonesBoundary wrapper, the /react and /element entries, and the React peer dependency. import "@camp.dev/bones" registers <bones-boundary>; exports are ., ./server, ./css. The demo, docs, vanilla sandbox, and stream app use the aria-busy pattern. One minor changeset.

Linear: BON-26. Absorbs BON-12 (selector collapse and scope-selector pinning). Spec and plan are local docs under docs/superpowers/.

Verified: root vp check (apart from the pre-existing stale worktree under .claude/worktrees/); package unit and browser projects (175 tests); demo check, tests (111), and build; docs check and build; stream check and tests; vanilla check, tests, and build. Cross-engine check of packages/bones/sandbox/auto.html in Safari and Firefox: pending (only Chromium is installed locally).

The visual job fails on the first run: Linux baselines for the new fixtures (explicit-force, lines-16, lines-24, block-div, img-no-src) do not exist yet and react-force was removed. They get regenerated with the temporary --update commit and artifact harvest.

hunterbecton and others added 16 commits August 29, 2026 14:19
…ON-26)

Inferred rules stay in @layer bones-auto; explicit data-bones-type and
data-bones-lines rules are unlayered. data-bones-lines paints N bars in one
element with a masked ::before. An img with no src gets a box and a
transparent pixel. Old data-bone* names are gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Renames the overlay's animate attribute to data-bones-animate and moves
every browser test to the new attributes. visual.test.tsx drops React and
gains fixtures for data-bones-lines, a block on a div, and an img with no
src.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ON-26)

The rewrite dropped the rule that keeps data-bones-auto="off" subtrees
visible under a measured boundary's shadow-side visibility: hidden.
Restored as the last rule in @layer bones-auto, comment included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t data (BON-26)

Adds Await (use() behind a Suspense boundary) and TRANSPARENT_PIXEL for
next/image. Components take data, forward rest props to their root, and
get aria-busy from the caller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
React 19 requires awaited act scope when Suspense suspends during render.
Split test into pending and resolved cases with proper async act handling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drops createBones, forceBones, minMax, repeat, and lines from every demo
component. Static labels carry data-bones-auto="off", stat fills are
explicit blocks, paragraphs carry data-bones-lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four "no data" shell tests never asserted aria-busy reached the root, so a
dropped {...rest} spread would have passed unnoticed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…BON-26)

Pages wrap promises in Await and render each fallback as the same
component with aria-busy and no data. Showcase sections and the compare
mirrors follow. The body carries data-bones-animate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…up (BON-26)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (BON-26)

createBones, forceBones, readPromise, minMax, isMinMax, resolveLength,
boneAttributes, TRANSPARENT_PIXEL, the React BonesBoundary wrapper, and the
/react and /element entries are gone. import "@camp.dev/bones" registers
<bones-boundary>. No React dependency remains.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The React IntrinsicElements augmentation for <bones-boundary> was missing
onbones:show/onbones:hide, so the snippet above it that uses onbones:hide
didn't typecheck. The Animations example rendered nothing because it still
used the promise-era `user={fetchUser()}` prop instead of aria-busy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round out the review's demo and test fixes: drop a vacuous moves-panel
assertion, refresh the stale layout metadata, make Forced Skeletons put
the same loaded cards behind aria-busy instead of an empty grid (and
update its test for the real names/img count that follows), document why
MovesInteractive is the one component that sets its own aria-busy, and add
computed-style browser coverage for the data-bones-lines and no-src img
shapes the visual baselines cover.

The forced-skeletons "twelve skeleton cards" test now overrides
fetchPokemonList for just that test so the busy grid has 12 real items to
count, since the busy path renders exactly the pokemon it's given rather
than always defaulting to 12 placeholders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 104 files, which is 4 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review is too large to run within your organization's remaining usage spending cap. Raise or remove your spending cap in the billing tab, then retry.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: af1228dc-f2ea-44bc-9b96-064bdf5f5505

📥 Commits

Reviewing files that changed from the base of the PR and between a387bef and 1d0b0a0.

⛔ Files ignored due to path filters (7)
  • packages/bones/tests/browser/__screenshots__/visual.test.tsx/block-div-chromium-linux.png is excluded by !**/*.png
  • packages/bones/tests/browser/__screenshots__/visual.test.tsx/explicit-force-chromium-linux.png is excluded by !**/*.png
  • packages/bones/tests/browser/__screenshots__/visual.test.tsx/img-no-src-chromium-linux.png is excluded by !**/*.png
  • packages/bones/tests/browser/__screenshots__/visual.test.tsx/lines-16-chromium-linux.png is excluded by !**/*.png
  • packages/bones/tests/browser/__screenshots__/visual.test.tsx/lines-24-chromium-linux.png is excluded by !**/*.png
  • packages/bones/tests/browser/__screenshots__/visual.test.tsx/react-force-chromium-linux.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (104)
  • .changeset/attributes-only.md
  • README.md
  • apps/demo/app/compare/page.tsx
  • apps/demo/app/compare/pokemon/[id]/page.tsx
  • apps/demo/app/layout.tsx
  • apps/demo/app/pokemon/[id]/page.tsx
  • apps/demo/app/pokemon/[id]/tabs-section.tsx
  • apps/demo/components/animations-demo/animations-demo.test.tsx
  • apps/demo/components/animations-demo/animations-demo.tsx
  • apps/demo/components/article-preview/article-preview.test.tsx
  • apps/demo/components/article-preview/article-preview.tsx
  • apps/demo/components/base-stats-card/base-stats-card.test.tsx
  • apps/demo/components/base-stats-card/base-stats-card.tsx
  • apps/demo/components/dex-entries-panel/dex-entries-panel.test.tsx
  • apps/demo/components/dex-entries-panel/dex-entries-panel.tsx
  • apps/demo/components/evolution-chain-card/evolution-chain-card.test.tsx
  • apps/demo/components/evolution-chain-card/evolution-chain-card.tsx
  • apps/demo/components/forced-skeletons-demo/forced-skeletons-demo.test.tsx
  • apps/demo/components/forced-skeletons-demo/forced-skeletons-demo.tsx
  • apps/demo/components/hero-section/hero-section.test.tsx
  • apps/demo/components/hero-section/hero-section.tsx
  • apps/demo/components/info-card/info-card.test.tsx
  • apps/demo/components/info-card/info-card.tsx
  • apps/demo/components/locations-panel/locations-panel.tsx
  • apps/demo/components/moves-panel/moves-interactive.tsx
  • apps/demo/components/moves-panel/moves-panel.test.tsx
  • apps/demo/components/moves-panel/moves-panel.tsx
  • apps/demo/components/multi-line-text-demo/multi-line-text-demo.test.tsx
  • apps/demo/components/multi-line-text-demo/multi-line-text-demo.tsx
  • apps/demo/components/pokemon-card/pokemon-card.test.tsx
  • apps/demo/components/pokemon-card/pokemon-card.tsx
  • apps/demo/components/pokemon-detail-view/pokemon-detail-view.test.tsx
  • apps/demo/components/pokemon-detail-view/pokemon-detail-view.tsx
  • apps/demo/components/pokemon-grid/pokemon-grid.test.tsx
  • apps/demo/components/pokemon-grid/pokemon-grid.tsx
  • apps/demo/components/pokemon-hero/pokemon-hero.test.tsx
  • apps/demo/components/pokemon-hero/pokemon-hero.tsx
  • apps/demo/components/stat-bar/stat-bar.test.tsx
  • apps/demo/components/stat-bar/stat-bar.tsx
  • apps/demo/components/suspense-demo/suspense-demo.test.tsx
  • apps/demo/components/suspense-demo/suspense-demo.tsx
  • apps/demo/components/theming-demo/theming-demo.test.tsx
  • apps/demo/components/theming-demo/theming-demo.tsx
  • apps/demo/components/type-defense-card/type-defense-card.test.tsx
  • apps/demo/components/type-defense-card/type-defense-card.tsx
  • apps/demo/lib/await.test.tsx
  • apps/demo/lib/await.tsx
  • apps/demo/lib/pixel.ts
  • apps/docs/app/layout.tsx
  • apps/docs/components/demo/pokemon-card.module.css
  • apps/docs/components/demo/pokemon-card.tsx
  • apps/docs/content/docs/api/attributes.mdx
  • apps/docs/content/docs/api/bone-attributes.mdx
  • apps/docs/content/docs/api/bones-boundary.mdx
  • apps/docs/content/docs/api/create-bones.mdx
  • apps/docs/content/docs/api/force-bones.mdx
  • apps/docs/content/docs/api/meta.json
  • apps/docs/content/docs/examples.mdx
  • apps/docs/content/docs/getting-started.mdx
  • apps/docs/content/docs/index.mdx
  • apps/docs/content/docs/streaming.mdx
  • apps/docs/content/docs/styling.mdx
  • apps/stream/src/app.ts
  • apps/stream/src/page.ts
  • apps/stream/test/app.test.ts
  • apps/vanilla/index.html
  • apps/vanilla/src/apply.ts
  • apps/vanilla/src/main.ts
  • apps/vanilla/test/apply.test.ts
  • packages/bones/README.md
  • packages/bones/package.json
  • packages/bones/sandbox/auto.html
  • packages/bones/sandbox/boundary.html
  • packages/bones/sandbox/measured.html
  • packages/bones/src/core/attributes.ts
  • packages/bones/src/css/bones.css
  • packages/bones/src/element/index.ts
  • packages/bones/src/element/measure.ts
  • packages/bones/src/element/overlay.ts
  • packages/bones/src/index.ts
  • packages/bones/src/react/boundary.ts
  • packages/bones/src/react/create-bones.ts
  • packages/bones/src/react/index.ts
  • packages/bones/tests/attributes.test.ts
  • packages/bones/tests/auto-css.test.ts
  • packages/bones/tests/bones-css.test.ts
  • packages/bones/tests/boundary-react.test.tsx
  • packages/bones/tests/boundary.test.ts
  • packages/bones/tests/browser/adaptive-colors.test.ts
  • packages/bones/tests/browser/animation-scope.test.ts
  • packages/bones/tests/browser/default-animation.test.ts
  • packages/bones/tests/browser/img-occlusion.test.ts
  • packages/bones/tests/browser/measured.test.ts
  • packages/bones/tests/browser/mutation.test.ts
  • packages/bones/tests/browser/overlay-fallback.test.ts
  • packages/bones/tests/browser/shapes.test.ts
  • packages/bones/tests/browser/visual.test.tsx
  • packages/bones/tests/create-bones.test.tsx
  • packages/bones/tests/css-skeleton.test.tsx
  • packages/bones/tests/exports.test.ts
  • packages/bones/tests/read-promise.test.tsx
  • packages/bones/tests/server-bootstrap.test.ts
  • packages/bones/tsconfig.json
  • packages/bones/vite.config.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands.

hunterbecton and others added 2 commits August 29, 2026 16:53
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regenerated on CI with a temporary --update run; the workflow tweak is
reverted in this same commit. Unchanged fixtures regenerate byte-identically,
so only the new and renamed shots differ.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hunterbecton
hunterbecton merged commit ba5e27d into main Aug 30, 2026
16 checks passed
@github-actions github-actions Bot mentioned this pull request Aug 30, 2026
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