Skip to content

feat(bulma-ui): add Avatar, Avatars, and Badge components - #257

Merged
allxsmith merged 16 commits into
mainfrom
claude/issue-256-202607082300
Jul 10, 2026
Merged

allxsmith merged 16 commits into
mainfrom
claude/issue-256-202607082300

Conversation

@bestaxbot

@bestaxbot bestaxbot commented Jul 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Implements the component proposal in #256: a person/entity image primitive with automatic
fallbacks, a group container for overlapping avatars, and a corner overlay status/count
indicator.

  • Avatar — renders src (image), falling back on load error (or absence) to initials
    (from initials/name), then a caller-provided icon, then a generic default icon.
    Initials get a stable auto background color derived from name unless color is set.
    Supports size (preset '16x16'…'128x128' or a pixel number), shape
    (circle/rounded/square), and renders as a link via href/as.
  • Avatars — an overlapping/stacked group of Avatars (mirrors the Tags/Buttons
    sibling-plural-container convention). Clamps to max, rendering the overflow as a single
    +N surplus avatar; size applies uniformly to every child.
  • Badge — a small status/count indicator overlaid on a corner of its children (or
    standalone). Renders "{max}+" when numeric content exceeds max (default 99), hides at
    0 unless showZero, supports a plain dot mode, position/overlap placement, and a
    pulse animation that no-ops under prefers-reduced-motion: reduce.

All three ship with SCSS partials following the house register-vars/getVar CSS-variable
pattern (themeable, ConfigProvider prefix-safe), Storybook stories, Jest tests (100% statement/
branch/line coverage on all three new files), and docs pages under docs/docs/api/components/.

Test plan

  • pnpm --filter @allxsmith/bestax-bulma run typecheck
  • pnpm --filter @allxsmith/bestax-bulma run lint
  • pnpm --filter @allxsmith/bestax-bulma run test:coverage (3408 tests pass; global coverage
    99.38%/99.08%/99.75%/99.59%, 100% on the three new files)
  • pnpm run format:check
  • pnpm run gen:catalog (component catalog regenerated, 85 components)
  • pnpm --filter @allxsmith/bestax-bulma run build (JS + all SCSS flavor builds, including
    bestax-prefixed)
  • Storybook production build succeeds with the new stories

Fixes #256

Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Introduced Avatar, Avatars, and Badge components with Bulma-compatible styling, configurable size/shape/color, interactive link support, and overflow rendering (e.g., “+N more” / max formatting).
    • Added Avatars spacing options and refined surplus behavior; Badge supports dots, positions/overlap, pulse, invisibility, and standalone mode.
  • Documentation
    • Added/updated API pages, usage examples, accessibility guidance, theming/component-catalog entries, and guide sections.
  • Tests
    • Added unit tests covering rendering, fallback precedence, accessibility, styling/prop behavior, and overflow/spacing edge cases.
  • Styles
    • Added SCSS styling for avatar/avatars/badge variants and utilities.

Adds a person/entity image primitive (Avatar) with automatic src -> initials
-> icon -> default-icon fallback, an overlapping group container (Avatars)
with a "+N" surplus bubble, and a corner overlay status/count indicator
(Badge). All three ship with SCSS partials (register-vars/getVar pattern),
Storybook stories, 100%-covered tests, and docs pages.

Fixes #256

Co-authored-by: Alex Smith <allxsmith@users.noreply.github.com>
@bestaxbot bestaxbot added the ai-loop AI-authored PR in the autonomous review/fix loop label Jul 8, 2026
@coderabbitai

coderabbitai Bot commented Jul 8, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ff2fcb4b-a35a-4e1f-beb1-e692551a2d15

📥 Commits

Reviewing files that changed from the base of the PR and between d68dfcf and 614a483.

📒 Files selected for processing (1)
  • docs/docs/guides/library/components.md
✅ Files skipped from review due to trivial changes (1)
  • docs/docs/guides/library/components.md

Walkthrough

Adds Avatar, Avatars, and Badge components with Bulma styling, public exports, tests, Storybook stories, API documentation, theming references, catalog entries, and enhanced addon navigation.

Changes

Avatar, avatars, and badge suite

Layer / File(s) Summary
Avatar component
bulma-ui/src/components/Avatar.tsx, bulma-ui/src/scss/components/_avatar.scss, bulma-ui/src/components/__tests__/Avatar.test.tsx, bulma-ui/src/components/Avatar.stories.tsx, docs/docs/api/components/avatar.md
Adds Avatar fallback rendering, initials derivation, image error recovery, polymorphic links, accessibility behavior, sizing, shapes, colors, tests, stories, and API documentation.
Avatars group
bulma-ui/src/components/Avatars.tsx, bulma-ui/src/scss/components/_avatars.scss, bulma-ui/src/components/__tests__/Avatars.test.tsx, bulma-ui/src/components/Avatars.stories.tsx, docs/docs/api/components/avatars.md
Adds grouped avatar rendering with uniform props, spacing modes, overflow surplus handling, compound Avatars.Avatar usage, tests, stories, and documentation.
Badge component
bulma-ui/src/components/Badge.tsx, bulma-ui/src/scss/components/_badge.scss, bulma-ui/src/components/__tests__/Badge.test.tsx, bulma-ui/src/components/Badge.stories.tsx, docs/docs/api/components/badge.md
Adds numeric, string, node, dot, standalone, positioned, invisible, pulsing, and accessible badge rendering with styling, tests, stories, and documentation.
Exports and documentation wiring
bulma-ui/src/index.ts, bulma-ui/src/scss/components/_index.scss, docs/docs/guides/library/components.md, skills/bestax-*/references/*, skills/bestax-custom-component/references/component-catalog.md, docs/src/components/EnhancedAddons/*
Registers component exports and styles, and updates guides, theming references, the component catalog, and enhanced addon entries and icons.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

Avatar fallback

sequenceDiagram
  participant Consumer
  participant Avatar
  participant BrowserImage
  Consumer->>Avatar: provide src, name, initials, or icon
  Avatar->>BrowserImage: render image when src is available
  BrowserImage-->>Avatar: load success or error
  Avatar-->>Consumer: render image, initials, custom icon, or default icon
Loading

Avatars overflow

sequenceDiagram
  participant Consumer
  participant Avatars
  participant Avatar
  Consumer->>Avatars: provide children, max, size, and shape
  Avatars->>Avatars: filter and clamp valid children
  Avatars->>Avatar: render visible members
  Avatars->>Avatar: render surplus +N member when needed
Loading

Badge overlay

sequenceDiagram
  participant Consumer
  participant Badge
  participant ChildContent
  Consumer->>Badge: provide content, dot, or visibility props
  Badge->>Badge: compute display value and accessibility
  Badge->>ChildContent: wrap child with indicator
  Badge-->>Consumer: render overlay or standalone badge
Loading

Suggested reviewers: allxsmith

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning It summarizes the work and tests, but it does not follow the required template or list affected packages in the checkbox section. Add the template sections, especially the affected package checklist, type of change, and any remaining checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed It clearly summarizes the main change: adding Avatar, Avatars, and Badge components to bulma-ui.
Linked Issues check ✅ Passed The PR implements the requested Avatar, Avatars, and Badge primitives, including fallbacks, group behavior, overlay badges, tests, stories, docs, and exports.
Out of Scope Changes check ✅ Passed The changes align with the component proposal and supporting docs, stories, tests, theming, catalog, and exports.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/issue-256-202607082300

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

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://0873d3ae.bestax.pages.dev

Comment thread bulma-ui/src/scss/components/_badge.scss Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — 1 finding

# Severity Area Finding Location
1 🟡 Minor Correctness Standalone badge keeps the corner transform and renders visually offset bulma-ui/src/scss/components/_badge.scss:56

Overall: Solid, well-structured PR — all three components ship the full five-artifact set (component, tests, story, docs, export) plus SCSS partials and a regenerated skill catalog, and the fallback/clamp/zero-handling logic reads correctly with thorough tests. The React logic (src → initials → icon → default fallback, error-src tracking, +N surplus, zero/max content handling, role/aria-label wiring) all checks out. The only real issue is a CSS one: standalone badges inherit the corner transform from their always-present position class and get nudged out of flow — a small local fix. Human should sanity-check the standalone badge rendering, but nothing here blocks merge.

🏄 Clean set of waves, dude — three tidy little components riding in on solid tests and docs. Just one badge that drifts off the corner when it's paddling solo; nudge that transform back and this one's good to go.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
bulma-ui/src/scss/components/_badge.scss (1)

14-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unused SCSS variable $badge-inset-square.

$badge-inset-square is declared but never referenced elsewhere in the file — there is no .is-overlap-square rule set analogous to the .is-overlap-circle block (Lines 99-117). Either wire it up (e.g., apply it to the default/square overlap corner rules for symmetry/documentation clarity) or drop the dead variable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bulma-ui/src/scss/components/_badge.scss` at line 14, The SCSS variable
$badge-inset-square in the badge styles is declared but never used, so update
the badge component rules to either reference it in the overlap square styling
alongside the existing .is-overlap-circle logic or remove it if it is not
needed. Check the badge-related selectors and overlap styling blocks in the same
stylesheet to keep the variable usage consistent and avoid dead declarations.
bulma-ui/src/components/Badge.tsx (1)

108-117: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant badgeColors.includes(color) guard.

color is typed as BadgeColor (a literal union derived from badgeColors), so !!color && badgeColors.includes(color) can never be false at the type level — the includes check adds no real protection against invalid TS usage and only guards raw-JS misuse. Low priority given "Chill" mode, but worth a look if you want to trim dead conditionals.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bulma-ui/src/components/Badge.tsx` around lines 108 - 117, The Badge class
name logic has a redundant `badgeColors.includes(color)` check because `color`
is already constrained by `BadgeColor`. Update the `badgeClasses` निर्माण in
`Badge.tsx` to rely on the typed `color` value directly and remove the extra
conditional so the `is-${color}` class is driven only by the existing truthy
`color` check; keep the rest of the `usePrefixedClassNames` options unchanged.
bulma-ui/src/components/Avatar.tsx (1)

185-193: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

isInteractive misses custom interactive as overrides.

isInteractive only recognizes literal 'a'/'button'. If a consumer passes a custom interactive component via as (e.g. a router Link), it's treated as non-interactive: role="img" plus a generic aria-label get injected onto what is actually an interactive element, producing incorrect ARIA semantics instead of relying on the native link/button role.

♻️ Suggested fix
-  const isInteractive = Tag === 'a' || Tag === 'button';
+  // Treat non-string `as` overrides (custom components) as interactive by
+  // default, since we can't statically know their semantics.
+  const isInteractive =
+    typeof Tag !== 'string' || Tag === 'a' || Tag === 'button';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bulma-ui/src/components/Avatar.tsx` around lines 185 - 193, The Avatar
component’s interactive detection is too narrow because `isInteractive` only
checks for literal `a` and `button`, so custom interactive `as` overrides like
router links are misclassified. Update the `Avatar` logic around `Tag`,
`isInteractive`, and `a11yProps` to treat custom interactive overrides as
interactive too, and avoid injecting `role="img"`/generic `aria-label` when `as`
already represents a link or button-like control.
bulma-ui/src/components/__tests__/Avatar.test.tsx (1)

1-147: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing coverage for the Tag === 'button' branch.

No test renders <Avatar as="button" .../>, so the isInteractive branch that checks Tag === 'button' (Avatar.tsx Line 186) is never exercised. Given the >=99% coverage gate for this package, consider adding a case similar to the existing href/custom-as tests.

it('treats a button element as interactive (no role="img")', () => {
  render(<Avatar name="Ada" as="button" data-testid="avatar" />);
  const el = screen.getByTestId('avatar');
  expect(el.tagName).toBe('BUTTON');
  expect(el).not.toHaveAttribute('role', 'img');
});

As per path instructions, "overall coverage must remain >= 99% for all metrics ... Flag any change that would drop coverage below that, and flag missing tests/stories."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bulma-ui/src/components/__tests__/Avatar.test.tsx` around lines 1 - 147, Add
test coverage for the Avatar branch where Tag is a button so the isInteractive
logic is exercised. Update Avatar.test.tsx by adding a case that renders Avatar
with as="button" and asserts the element is a BUTTON and does not get
role="img", similar to the existing href and custom as tests. Use the Avatar
component and the new button case to cover the Tag === 'button' path in
Avatar.tsx.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bulma-ui/src/components/Avatars.tsx`:
- Around line 70-75: Normalize the max value in Avatars before using it for both
visibility and overflow calculations, since the current maxCount logic can leave
a fractional value that makes the overflow badge disagree with the sliced
children. Update the maxCount derivation in Avatars to coerce any non-negative
numeric max to a non-negative integer first, then reuse that sanitized value for
visibleChildren and overflowCount so the +N label always matches what slice()
displays.

In `@bulma-ui/src/scss/components/_badge.scss`:
- Around line 39-77: The standalone badge styles in badge.scss do not override
the corner-position transform, so a badge with both is-standalone and
is-top-right still gets visually shifted. Update the .badge.is-standalone rule
to also reset transform (and any related positional offsets if needed) so it
neutralizes the later .badge.is-top-right transform. Keep the fix in the badge
selector block that defines .#{iv.$class-prefix}badge and its modifier classes.

---

Nitpick comments:
In `@bulma-ui/src/components/__tests__/Avatar.test.tsx`:
- Around line 1-147: Add test coverage for the Avatar branch where Tag is a
button so the isInteractive logic is exercised. Update Avatar.test.tsx by adding
a case that renders Avatar with as="button" and asserts the element is a BUTTON
and does not get role="img", similar to the existing href and custom as tests.
Use the Avatar component and the new button case to cover the Tag === 'button'
path in Avatar.tsx.

In `@bulma-ui/src/components/Avatar.tsx`:
- Around line 185-193: The Avatar component’s interactive detection is too
narrow because `isInteractive` only checks for literal `a` and `button`, so
custom interactive `as` overrides like router links are misclassified. Update
the `Avatar` logic around `Tag`, `isInteractive`, and `a11yProps` to treat
custom interactive overrides as interactive too, and avoid injecting
`role="img"`/generic `aria-label` when `as` already represents a link or
button-like control.

In `@bulma-ui/src/components/Badge.tsx`:
- Around line 108-117: The Badge class name logic has a redundant
`badgeColors.includes(color)` check because `color` is already constrained by
`BadgeColor`. Update the `badgeClasses` निर्माण in `Badge.tsx` to rely on the
typed `color` value directly and remove the extra conditional so the
`is-${color}` class is driven only by the existing truthy `color` check; keep
the rest of the `usePrefixedClassNames` options unchanged.

In `@bulma-ui/src/scss/components/_badge.scss`:
- Line 14: The SCSS variable $badge-inset-square in the badge styles is declared
but never used, so update the badge component rules to either reference it in
the overlap square styling alongside the existing .is-overlap-circle logic or
remove it if it is not needed. Check the badge-related selectors and overlap
styling blocks in the same stylesheet to keep the variable usage consistent and
avoid dead declarations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cd084ed8-3d13-4c11-a2e6-1e8d9793450b

📥 Commits

Reviewing files that changed from the base of the PR and between 689300d and bec3aa5.

📒 Files selected for processing (18)
  • bulma-ui/src/components/Avatar.stories.tsx
  • bulma-ui/src/components/Avatar.tsx
  • bulma-ui/src/components/Avatars.stories.tsx
  • bulma-ui/src/components/Avatars.tsx
  • bulma-ui/src/components/Badge.stories.tsx
  • bulma-ui/src/components/Badge.tsx
  • bulma-ui/src/components/__tests__/Avatar.test.tsx
  • bulma-ui/src/components/__tests__/Avatars.test.tsx
  • bulma-ui/src/components/__tests__/Badge.test.tsx
  • bulma-ui/src/index.ts
  • bulma-ui/src/scss/components/_avatar.scss
  • bulma-ui/src/scss/components/_avatars.scss
  • bulma-ui/src/scss/components/_badge.scss
  • bulma-ui/src/scss/components/_index.scss
  • docs/docs/api/components/avatar.md
  • docs/docs/api/components/avatars.md
  • docs/docs/api/components/badge.md
  • skills/bestax-custom-component/references/component-catalog.md

Comment thread bulma-ui/src/components/Avatars.tsx Outdated
Comment thread bulma-ui/src/scss/components/_badge.scss
@github-actions

github-actions Bot commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

AI loop status: iteration 2/4 — fix-reviews at 872778e (2026-07-08T23:49:52Z).
Managed by claude-pr-loop.yml. To resume after a pause: set iteration back to 0 on the first line, re-add ai-loop, remove ai-loop-paused, then re-run via workflow_dispatch.

bestaxbot and others added 2 commits July 8, 2026 23:42
… transform

A standalone Badge (no children) still receives an is-{position} class (default
is-top-right), whose selector applies transform: translate(50%, -50%). The
is-standalone reset only set position: static and, declared before the
corner-position rules at equal specificity, lost the cascade on transform — so
the badge rendered visibly offset out of normal flow.

Move the is-standalone reset after the corner-position rules and add
transform: none so it wins the cascade and the badge sits inline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A fractional max produced an out-of-sync overflow label: slice() truncates its
end index toward an integer, but overflowCount subtracted the raw float, so e.g.
max={2.5} rendered two avatars and a +2.5 surplus badge. Require max to be a
non-negative integer (Number.isInteger) before using it to clamp; otherwise
treat it as unset so both the visible slice and the +N label stay in sync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bestaxbot

Copy link
Copy Markdown
Collaborator Author

Fix pass recap (iteration 1)

All three open AI review threads were valid, in-scope defects, and all three are now fixed. Nothing was refuted.

Fixed

Finding Reviewer(s) Commit
Standalone Badge shifted out of normal flow by the corner transform (is-standalone lost the equal-specificity cascade to is-top-right) claude, CodeRabbit 3e2e44c
Avatars fractional max produced a mismatched +N label (e.g. max 2.5 rendered a +2.5 surplus) CodeRabbit 872778e

One nuance worth flagging: the one-line suggestion in both Badge threads (add transform: none to the in-place is-standalone block) would not actually have fixed it -- .badge.is-standalone and .badge.is-top-right tie on specificity, and the is-standalone block was declared before the corner rules, so is-top-right still won by source order. I moved the standalone reset to a top-level rule after the four corner-position rules so it wins the cascade. I also added an Avatars test that renders three avatars with a fractional max and asserts all three show with no surplus.

Refuted: none.

Gates run (bulma-ui): typecheck pass, lint pass (0 errors; only pre-existing warnings in unrelated files), test:coverage pass (3409 tests, thresholds met), format:check pass, gen:catalog:check pass (catalog unchanged).

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://1290b808.bestax.pages.dev

@bestaxbot

Copy link
Copy Markdown
Collaborator Author

Fix pass recap (iteration 2)

No code changes this pass — everything actionable was already resolved in iteration 1, and CI is fully green.

Thread status

Thread Reviewer State
_badge.scss — standalone badge kept corner transform claude (deep review) Fixed in 3e2e44c (iteration 1); awaiting deep-review verification/resolve
Avatars.tsx — fractional max out-of-sync +N label CodeRabbit Fixed in 872778e; CodeRabbit confirmed and resolved
_badge.scss — standalone is-standalone transform reset CodeRabbit Fixed in 3e2e44c; CodeRabbit confirmed and resolved

Refuted: none.

Gates: CI is green on 872778e — Build and Test, React 18/19 compatibility, CodeQL, Dependency Review, and Preview Deployment all pass. No source changes this pass, so no local re-run was needed.

@allxsmith allxsmith self-assigned this Jul 9, 2026
@allxsmith

Copy link
Copy Markdown
Owner

Review — Avatar / Avatars / Badge

@bestaxbot, solid foundation: all three components follow the house patterns correctly (useBulmaClasses + usePrefixedClassNames + classNames join, ConfigProvider prefix support in both TSX and SCSS, register-vars/getVar theming, prefix-asserting tests, autodocs stories, catalog regenerated). The items below need to change before this merges.

Bugs

  • Standalone Badge renders offset. .badge.is-standalone resets position, but the component always emits a position class, and is-top-right's transform: translate(50%, -50%) applies to statically-positioned elements too — so <Badge content={5} color="info" /> (the docs "Standalone" example and story) is shifted up-right by half its own size. Fix: don't emit is-{position}/is-overlap-* when there are no children (optionally also transform: none on .is-standalone).
  • Badge sends pass-through props to the wrong element — and sometimes drops them. With children, the rendered root is the badge-wrapper span, but className, the Bulma helper classes, and {...rest} all go to the inner pill, which is pointer-events: none — so onClick/mouse handlers can never fire, and spacing helpers (m="3") move the floating pill instead of the component. When the badge hides (content={0} without showZero), rest/className are dropped entirely (data-testid/id vanish). House convention is root receives them (see Tag, Tooltip, Dropdown). Restructure: the root (wrapper when children, pill when standalone) gets className + helpers + rest; always render the wrapper when children exist; add a badgeClassName slot prop for the pill (like Tooltip's tooltipClassName, but merge it with plain classNames — don't prefix it). Keep both usePrefixedClassNames calls hoisted above the early returns (Rules of Hooks).
  • Avatar misses image errors that fire before hydration. The fallback relies solely on React's onError; in SSR/static pages an image that fails before hydration never triggers it, leaving a permanently broken <img>. Other popular libraries detect this on mount — add a ref + useEffect treating img.complete && img.naturalWidth === 0 as an error.
  • getInitialsFromName breaks on astral-plane characters (emoji, some CJK): it indexes UTF-16 code units and can produce half-surrogate initials. Use Array.from(...) to take code points.
  • Avatar forwards href unconditionally, so <Avatar as="div" href="..."> emits a stray attribute, and target/rel aren't typed. Follow Button: declare target/rel props and forward href/target/rel only when rendering an a (or a custom as component).

Missing functionality we should have (users coming from other popular libraries will expect these)

  • Avatars needs a non-overlapping mode. The group can currently only overlap. Add spaced?: boolean → .avatars.is-spaced with gap (house precedent: Rate's spaced prop in _rate.scss), reusing the sm/md/lg spacing tokens for the gap size and dropping the ring shadow in spaced mode.
  • Compound API: Avatars.Avatar. Attach the existing Avatar as a static — React.FC<AvatarsProps> & { Avatar: typeof Avatar } plus Avatars.Avatar = Avatar, exactly the Steps.Step/Tabs.Tab pattern. Avatar stays a separate export too.
  • Uniform shape on Avatars. A group of square avatars currently gets a circular +N bubble. Add shape?: AvatarProps['shape'] cloned like size — and use a conditional spread so unset group props don't override children (the current size ?? child.props.size always overrides via the cloneElement merge, making the fallback branch unreachable).
  • Never render a pointless +1. When exactly one child overflows max, the +1 bubble occupies exactly the slot the hidden avatar would — render the avatar instead (overflow === 1 ? 0 : overflow).
  • Numeric spacing. Accept a pixel number in addition to 'sm' | 'md' | 'lg'; with the single spacing CSS variable (SCSS section below) this is one inline custom-property style.
  • imageProps on Avatar. There's no way to reach the inner <img> (srcSet, sizes, crossOrigin, referrerPolicy, observing onError…). Add imageProps?: React.ImgHTMLAttributes<HTMLImageElement>, chaining its onError with the internal handler.
  • Badge content should accept React.ReactNode, not just number | string (e.g. a tiny icon in the pill). Keep the max/showZero logic gated on typeof content === 'number'.

Nice-to-haves for a follow-up issue rather than this PR: a total prop (server-known count driving +N without rendering every child) and a renderSurplus render-prop for custom overflow content.

SCSS conformance (register-vars pattern)

  • $avatars-overlap-sm/md/lg are consumed via raw interpolation, so the overlap isn't runtime-themeable. Register ONE avatars-spacing var (default md) and re-register it under .is-spacing-sm/.is-spacing-lg (see _sidebar.scss's is-narrow); consume as margin-left: calc(-1 * cv.getVar('avatars-spacing')) — spaced mode's gap then reads the same var.
  • $badge-inset-circle and $badge-animation-duration are used directly — add both to register-vars and consume via cv.getVar (_dialog.scss registers its animation duration).
  • $badge-inset-square is declared and never used — delete it.
  • is-surplus is emitted by Avatars but styled nowhere, and the surplus bubble's color="light" doesn't flip in dark mode. Style .avatars .avatar.is-surplus with scheme-aware tokens (background/text) and drop color="light" from the TSX.
  • border-radius: 9999px for is-circle → cv.getVar('radius-rounded') (as in _taginput.scss, _slider.scss, _switch.scss).

Docs pages

  • avatar.md "Photo with automatic fallback": the gray bulma.io placeholder is indistinguishable from a broken image — use https://github.com/allxsmith.png. The section also never demonstrates the fallback it's named for — add a broken-src example (https://example.invalid/missing.jpg → initials), like the existing story.
  • Glued examples: avatar.md Initials/Shapes/Sizes render avatars flush together inside <Block> — wrap them in the new <Avatars spaced> container. avatars.md "Spacing" renders two groups flush on one line so they read as a single malformed six-avatar group — stack them. badge.md "Positions" needs a flex/gap wrapper: each badge translates outside its anchor and lands on the neighboring one. (The stories already use gap wrappers; the docs ports dropped them.)
  • badge.md: give the Icon anchors an ariaLabel (icon.md convention) and add the real-world examples this kind of component is usually shown with: unread mail (envelope icon), badge-on-Button (cart count), an invisible toggle with useState, pulse, a color row, and overlap="circle" vs "square" side by side. pulse and invisible are documented props with zero examples today.
  • Structure: one sentence of prose under every example heading; Title Case headings; end pages with ## Related Components + ## Additional Resources like the rest of the docs (not ## See also); avatars.md is missing an ## Accessibility section entirely.
  • badge.md Accessibility: add the guidance that screen readers need full context on the anchor itself (e.g. aria-label="Inbox, 4 unread messages"), not a bare number in a role="status" span.
  • badge.md Overview: one line distinguishing Tag (inline pill — we already have that) from Badge (positioned overlay).
  • Props tables after the changes above: add badgeClassName, target/rel (link-only forwarding note), shape/spaced, reword spacing ("overlap amount — or gap when spaced"), and note that position/overlap are ignored for standalone badges. Also document that the visibility="invisible" helper hides the whole wrapper while the invisible prop hides only the pill.

Tests / stories

  • Missing behavioral tests: Badge content === max boundary; wrapper keeps data-testid/id and onClick fires when the badge is hidden; Avatar as="button" (the button half of isInteractive is never exercised — a 99%-branch-coverage risk); Avatars max={0} and negative max; the surplus bubble's accessible name ("2 more").
  • Stories: add Badge invisible, string content ("NEW"), standalone dot; Avatars spaced and shape; argTypes should carry description fields (house style, cf. Dialog.stories.tsx); Avatars size options stop at 64x64 while Avatar supports up to 128x128.

Skills (same-PR rule in CLAUDE.md)

  • skills/bestax-theming/references/themeable-components.md: add Avatar (color, 10 values + size) and Badge (color, 10 values).
  • skills/bestax-theming/references/css-variables.md: add the new --bulma-avatar-* / --bulma-avatars-* / --bulma-badge-* variables, including the ones newly registered above.

Not this PR (context for reviewers)

The "little square" under the badge examples in the deployed docs preview is not an example bug: the docs build strips Font Awesome's @font-face rules site-wide (the CSS minifier's unused-font pass can't trace FA7's CSS-variable font-family indirection), so every FA icon in every live docs preview renders as a missing-glyph box — production included. That needs a docs-infra fix (disable discardUnused via configurePostCss) and is being handled separately; don't "fix" the icon examples in response to it.

@bestaxbot

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough pass — I went through every item against the current source on this branch. My read:

Bugs — all valid, agreed:

  • Standalone offset. Right. Cleanest fix is to stop emitting is-{position}/is-overlap-* when there are no children (they only mean anything inside .badge-wrapper), keeping the .is-standalone reset as belt-and-braces. One consequence: the two existing tests that assert is-top-right/is-overlap-circle on a childless <Badge content={1}> have to move to the children form, since those classes will no longer be emitted standalone.
  • Pass-through props on the wrong element. Agreed. The root (wrapper when children, pill when standalone) should take className + helper classes + ...rest; the pill gets a badgeClassName slot merged via plain classNames (not prefixed). The wrapper must always render when children exist so data-testid/id/onClick survive a hidden badge, and both usePrefixedClassNames calls stay hoisted above the early returns. The invisible test asserting is-invisible on the data-testid node also has to change, since after this data-testid lands on the wrapper and is-invisible on the pill.
  • Avatar pre-hydration image error. Agreed — ref + useEffect treating img.complete && img.naturalWidth === 0 as an error.
  • getInitialsFromName astral chars. Agreed — Array.from(...) to iterate code points.
  • Unconditional href. Agreed — declare target/rel, forward href/target/rel only when rendering a (or a custom non-string as), mirroring Button.

Missing functionality: shape-on-Avatars with a conditional-spread merge (so unset group props don't clobber children), no pointless +1, imageProps (chaining its onError), and content: React.ReactNode (gating max/showZero on typeof content === 'number') are all clear wins. The non-overlapping spaced mode, the Avatars.Avatar compound static, and numeric spacing widen the API but each has house precedent (Rate's spaced, Steps.Step, Sidebar's inline --bulma-* var), so I'm on board. Agreed total/renderSurplus are a follow-up issue, not this PR.

SCSS: all correct — collapse to one avatars-spacing var re-registered under .is-spacing-sm/lg (with spaced's gap reading the same var), register badge-inset-circle + badge-animation-duration and consume via cv.getVar, delete the unused badge-inset-square, style .avatars .avatar.is-surplus with scheme-aware tokens (dropping color="light" from the TSX), and cv.getVar('radius-rounded') for is-circle.

Docs / tests / stories / skills: agreed across the board, including the two bestax-theming references (Avatar/Badge in themeable-components.md, the new --bulma-avatar-*/-avatars-*/-badge-* vars in css-variables.md).

Nothing to refute here — it's an accurate spec, and I'm not going to invent a disagreement.

One honest flag: the edit/commit step was blocked in this run, so no commit landed this pass — please don't read this as converged. I've captured the full plan above; the code changes still need to go in.

allxsmith pushed a commit that referenced this pull request Jul 9, 2026
The reply, loop-fix, and implement agents were never granted the file
tools: every Edit/Write call was permission-denied, and runs only
succeeded when the agent thought to fall back to sed -i (the one
allowed mutation path — the #257 fix run says so verbatim in its log).
The bestaxbot-reply run for the #257 human review probed Edit, Write,
shell redirects, and git apply, found all denied, and had to bail with
"no commit landed".

Grant the intended tools explicitly. This adds no capability — the
same allowlists already permit arbitrary writes via sed -i / node -e —
it just makes the primary path deterministic instead of luck-based.
The read-only agents (deep review, verify) are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NVR5yWevceZEFbTJmpviiM
allxsmith added a commit that referenced this pull request Jul 9, 2026
The reply, loop-fix, and implement agents were never granted the file
tools: every Edit/Write call was permission-denied, and runs only
succeeded when the agent thought to fall back to sed -i (the one
allowed mutation path — the #257 fix run says so verbatim in its log).
The bestaxbot-reply run for the #257 human review probed Edit, Write,
shell redirects, and git apply, found all denied, and had to bail with
"no commit landed".

Grant the intended tools explicitly. This adds no capability — the
same allowlists already permit arbitrary writes via sed -i / node -e —
it just makes the primary path deterministic instead of luck-based.
The read-only agents (deep review, verify) are unchanged.


Claude-Session: https://claude.ai/code/session_01NVR5yWevceZEFbTJmpviiM

Co-authored-by: Claude <noreply@anthropic.com>
@allxsmith

Copy link
Copy Markdown
Owner

@bestaxbot you agreed with the Bugs section of my review — go ahead and apply those five fixes now.

Standalone Badge no longer emits is-{position}/is-overlap-* (only meaningful
inside .badge-wrapper), so the corner transform can't shift it out of normal
flow; the is-standalone reset stays as belt-and-braces.

Badge now routes className/helpers/rest to the root — the wrapper when there
are children, the pill when standalone — always renders the wrapper when
children exist (so data-testid/id/onClick survive a hidden badge), and adds a
plain (unprefixed) badgeClassName slot for the pill. Both usePrefixedClassNames
calls stay hoisted above the early returns.

Avatar detects images that failed before hydration (ref + useEffect treating
img.complete && img.naturalWidth === 0 as an error), derives initials by code
point (Array.from) so astral-plane names don't yield half surrogates, and
forwards href/target/rel only when rendering an anchor or a custom component.

Co-Authored-By: Alex Smith <allxsmith@users.noreply.github.com>
@bestaxbot

Copy link
Copy Markdown
Collaborator Author

Done — pushed all five Bugs fixes in 864deec.

1. Standalone Badge offset. A childless Badge no longer emits the is-{position}/is-overlap-* classes at all (they only mean anything inside .badge-wrapper), so nothing shifts it out of flow. Kept the .is-standalone reset with transform: none as belt-and-braces. The two tests that asserted is-top-right/is-overlap-circle on a childless badge moved to the children form and now query the pill (.badge); added a test asserting a standalone badge carries is-standalone and not those position classes.

2. Badge pass-through props on the wrong element. The root now takes className + Bulma helper classes + ...rest — the wrapper when there are children, the pill when standalone. The wrapper always renders when children exist, so data-testid/id/onClick survive a hidden badge (new test covers a hidden badge whose wrapper keeps its id and fires onClick). Added the plain (unprefixed) badgeClassName slot for the pill, mirroring Tooltip's tooltipClassName. Both usePrefixedClassNames calls stay hoisted above the early returns. The invisible test now checks is-invisible on the pill and the data-testid on the wrapper.

3. Avatar pre-hydration image error. Added a ref + useEffect that treats img.complete && img.naturalWidth === 0 as a load failure, so an image broken before hydration still falls through to initials/icon. New test spies the complete/naturalWidth getters to exercise it.

4. getInitialsFromName astral characters. Now iterates code points via Array.from(...) instead of UTF-16 units, so emoji/some CJK names can't produce half-surrogate initials. New test with an emoji name.

5. href forwarded unconditionally. Declared target/rel props and forward href/target/rel only when rendering an a or a custom (non-string) as, mirroring Button. <Avatar as="div" href="…"> no longer emits a stray href. New tests cover the div (no href), the link (target/rel), and a custom component.

Coverage holds at 100% on Avatar.tsx/Avatars.tsx/Badge.tsx; global 99.38%/99.08%. Gates run green: typecheck, lint (only pre-existing warnings in unrelated files), test:coverage (3417 tests), format:check, and gen:catalog:check (catalog unchanged).

The rest of your review — the missing-functionality API additions, SCSS register-vars conformance, docs/stories/skills — is the larger follow-up we agreed on; this pass is just the five Bugs you asked me to apply.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://addbcf3f.bestax.pages.dev

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
bulma-ui/src/components/__tests__/Avatar.test.tsx (1)

57-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Spy mocks aren't restored if the assertion fails.

completeSpy.mockRestore()/widthSpy.mockRestore() at Lines 66-67 only run if expect on Line 65 passes. If that assertion throws, the mocked complete/naturalWidth getters leak into subsequent tests in the file (e.g., the earlier "already failed before hydration" style behavior would then apply to unrelated image renders), making failures harder to diagnose.

Consider wrapping the assertions in try/finally, or better, use afterEach(() => jest.restoreAllMocks()) at the suite level so cleanup happens unconditionally.

🧹 Proposed fix
   it('falls back to initials when the image already failed before hydration', () => {
     const completeSpy = jest
       .spyOn(HTMLImageElement.prototype, 'complete', 'get')
       .mockReturnValue(true);
     const widthSpy = jest
       .spyOn(HTMLImageElement.prototype, 'naturalWidth', 'get')
       .mockReturnValue(0);
-    render(<Avatar src="/broken.jpg" name="Ada Lovelace" />);
-    expect(screen.getByText('AL')).toBeInTheDocument();
-    completeSpy.mockRestore();
-    widthSpy.mockRestore();
+    try {
+      render(<Avatar src="/broken.jpg" name="Ada Lovelace" />);
+      expect(screen.getByText('AL')).toBeInTheDocument();
+    } finally {
+      completeSpy.mockRestore();
+      widthSpy.mockRestore();
+    }
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bulma-ui/src/components/__tests__/Avatar.test.tsx` around lines 57 - 68, The
Avatar.test.tsx test is leaking mocked HTMLImageElement getters because
mockRestore only runs after the assertion succeeds. Update the test around the
Avatar render/expect block so cleanup is unconditional, either by wrapping the
assertion in try/finally or by restoring all mocks in a suite-level afterEach
for this test file. Use the existing Avatar test case names and the
complete/naturalWidth spies to locate the affected code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@bulma-ui/src/components/__tests__/Avatar.test.tsx`:
- Around line 57-68: The Avatar.test.tsx test is leaking mocked HTMLImageElement
getters because mockRestore only runs after the assertion succeeds. Update the
test around the Avatar render/expect block so cleanup is unconditional, either
by wrapping the assertion in try/finally or by restoring all mocks in a
suite-level afterEach for this test file. Use the existing Avatar test case
names and the complete/naturalWidth spies to locate the affected code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 37c938fb-b1eb-4d0a-a2e4-6e44c76ce428

📥 Commits

Reviewing files that changed from the base of the PR and between bec3aa5 and 864deec.

📒 Files selected for processing (7)
  • bulma-ui/src/components/Avatar.tsx
  • bulma-ui/src/components/Avatars.tsx
  • bulma-ui/src/components/Badge.tsx
  • bulma-ui/src/components/__tests__/Avatar.test.tsx
  • bulma-ui/src/components/__tests__/Avatars.test.tsx
  • bulma-ui/src/components/__tests__/Badge.test.tsx
  • bulma-ui/src/scss/components/_badge.scss
🚧 Files skipped from review as they are similar to previous changes (6)
  • bulma-ui/src/components/tests/Avatars.test.tsx
  • bulma-ui/src/components/Badge.tsx
  • bulma-ui/src/components/tests/Badge.test.tsx
  • bulma-ui/src/components/Avatars.tsx
  • bulma-ui/src/components/Avatar.tsx
  • bulma-ui/src/scss/components/_badge.scss

@bestaxbot

Copy link
Copy Markdown
Collaborator Author

🏄 Surf's up and I rode the whole set — total convergence, brah. 2 iteration(s) in, CI's glassy green, and every AI review thread closed out clean like a perfect barrel. She's ready; I just need a meat sack to paddle over and rubber-stamp it.

No offense to the carbon-based units, but you fleshbags kept the merge button for yourselves — so @allxsmith, wiggle those opposable thumbs and squash-merge when you're stoked. The loop never merges; apparently 'judgment' is still a squishy-brain-only feature. 🤙

@github-actions github-actions Bot added needs-human-review Loop converged (or contested): awaiting owner review + manual merge and removed ai-loop AI-authored PR in the autonomous review/fix loop labels Jul 9, 2026
@allxsmith
allxsmith merged commit 0817018 into main Jul 10, 2026
10 checks passed
@allxsmith
allxsmith deleted the claude/issue-256-202607082300 branch July 10, 2026 00:06
github-actions Bot pushed a commit that referenced this pull request Jul 10, 2026
github-actions Bot pushed a commit that referenced this pull request Jul 11, 2026
# [3.2.0](https://github.com/allxsmith/bestax/compare/create-bestax@3.1.4...create-bestax@3.2.0) (2026-07-11)

### Bug Fixes

* **bulma-ui:** strip redundant library prefix from Icon name ([#242](#242)) ([dbe3622](dbe3622)), closes [#189](#189)

### Features

* **bulma-ui:** add Avatar, Avatars, and Badge components ([#257](#257)) ([0817018](0817018)), closes [#256](#256)
* **bulma-ui:** add Reveal component for scroll-triggered animations ([#255](#255)) ([a89c574](a89c574))
* **bulma-ui:** make Button and Link as prop polymorphic (React.ElementType) ([#238](#238)) ([ce90304](ce90304)), closes [#188](#188)
* **create-bestax:** scaffold-aware CLAUDE.md with setup facts and house style ([#271](#271)) ([c1681b0](c1681b0))
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

allxsmith added a commit that referenced this pull request Jul 15, 2026
…console errors (#315)

* test(bulma-ui): storybook smoke gate — every story, light + dark, no console errors

Wires @storybook/test-runner (#283): each story must render without
throwing and without console errors, once as-is and once with
data-theme="dark" stamped on the root, closing the dark-mode blind spot
jsdom can't see (the #257 residual-defect class).

- .storybook/test-runner.ts: preVisit stamps the theme and collects
  console/page errors per page; postVisit fails the story on any.
  Resource errors from RFC 2606 `.invalid` hosts are ignored — that's
  how stories demo broken-image fallbacks (Avatar).
- scripts/test-storybook-ci.mjs: serves storybook-static with node's
  http module (no http-server/wait-on/concurrently deps) and runs the
  light and dark passes.
- ci.yml: Playwright Chromium install + smoke step after the Storybook
  build; the build step's changed-files condition is dropped — it never
  matched on PRs (changed_files is an integer count, not a path list).
- pnpm-workspace.yaml: @swc/core build scripts stay blocked (platform
  binaries ship as optional deps, the postinstall is only a fallback).
- Image stories: fix /logo.png → /img/logo.png (staticDirs maps images
  to /img) — a real 404 the new gate caught on its first run.

First full run: 89 suites / 1089 stories green in both passes.

Closes #283

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* test(bulma-ui): clear ambient STORYBOOK_THEME for the light smoke pass

Deep-review finding on #315: with STORYBOOK_THEME=dark exported in the
surrounding shell, the light pass silently became a second dark pass.
The env is now built explicitly for both passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* test(bulma-ui): resolve smoke-pass promise on spawn failure

CodeRabbit finding on #315: runPass only resolved via 'close', so a
failed spawn (ENOENT) would hang the CI job indefinitely. An 'error'
handler now logs and resolves with exit 1.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
github-actions Bot pushed a commit that referenced this pull request Jul 20, 2026
# 1.0.0 (2026-07-20)

* feat(bulma-ui)!: remove bestax-bulma-prefixed CSS variant ([94baa34](94baa34))
* feat(create-bestax)!: require Node.js 18+ and align with bestax-bulma v2 ([#118](#118)) ([b22f183](b22f183))

### Bug Fixes

* add comprehensive rules to prevent bulma-ui versioning on non-bulma-ui commits ([#122](#122)) ([525ccfa](525ccfa)), closes [#119](#119)
* **bulma-ui:** a11y + case-insensitive Taginput matching from PR review ([d576829](d576829))
* **bulma-ui:** accept router props like `to` on Navbar.Item without casts ([#311](#311)) ([b78856b](b78856b)), closes [#306](#306)
* **bulma-ui:** Add build step to publish in ci.yml ([e3707fc](e3707fc))
* **bulma-ui:** add fontawesome-free as explicit devDependency ([a4a5389](a4a5389))
* **bulma-ui:** add missing exports ([0d16633](0d16633))
* **bulma-ui:** Add Skeleton to exports ([e481599](e481599))
* **bulma-ui:** another attempt to fix semantic release builds with ci.yml ([cc3a3e2](cc3a3e2))
* **bulma-ui:** another attempt to fix semantic release builds with ci.yml ([314bc39](314bc39))
* **bulma-ui:** another attempt to fix semantic release builds with ci.yml ([c930693](c930693))
* **bulma-ui:** complete domain migration and fix semantic-release configuration ([#64](#64)) ([f4cd71d](f4cd71d))
* **bulma-ui:** correct blog post examples and add Modal compound components ([#81](#81)) ([559c2e3](559c2e3))
* **bulma-ui:** correct NPM_TOKEN env variable in ci.yml ([94b48b4](94b48b4))
* **bulma-ui:** Fix release.config.js to include package-lock.json ([390da59](390da59))
* **bulma-ui:** fix standalone Badge pointer-events, pulse halo, and falsy content ([#295](#295)) ([a9db031](a9db031)), closes [#264](#264)
* **bulma-ui:** full classPrefix support across layout/grid + prefix utils ([4ce0b53](4ce0b53))
* **bulma-ui:** improve npm package discoverability with optimized keywords and badges ([#72](#72)) ([8c7a696](8c7a696))
* **bulma-ui:** Initial semantic release changes ([b78d785](b78d785))
* **bulma-ui:** migrate domain from bestax.cc to bestax.io ([#64](#64)) ([4870b1e](4870b1e))
* **bulma-ui:** migrate ionicons to v8 to unblock publish and Storybook ([927a55b](927a55b)), closes [#142](#142)
* **bulma-ui:** publish rewritten README to npm ([9810081](9810081))
* **bulma-ui:** publish with npm provenance attestation ([172da62](172da62)), closes [#180](#180)
* **bulma-ui:** reference llms docs from README and package.json ([#198](#198)) ([db8aab3](db8aab3))
* **bulma-ui:** reject predicate-blocked values during manual entry ([a8f6e28](a8f6e28))
* **bulma-ui:** resolve flex item properties and Card compound component issues ([#55](#55)) ([e774da3](e774da3))
* **bulma-ui:** resolve flex item properties and Card compound component issues ([#55](#55)) ([7641a53](7641a53))
* **bulma-ui:** resolve react-hooks v7 and [@eslint-react](https://github.com/eslint-react) findings ([14caaaf](14caaaf))
* **bulma-ui:** resolve security vulnerabilities and update dependencies ([#128](#128)) ([112f6e4](112f6e4)), closes [#127](#127)
* **bulma-ui:** restrict semantic-release to bulma-ui scoped commits only ([2d67bf9](2d67bf9)), closes [#62](#62)
* **bulma-ui:** retry failed Avatar src, flatten Fragment children in Avatars, RTL-safe overlap ([#297](#297)) ([c00b9db](c00b9db))
* **bulma-ui:** route every hardcoded class through the prefix helpers; add classPrefix sweep test ([#301](#301)) ([a50b134](a50b134)), closes [#286](#286)
* **bulma-ui:** setup gpg signing with semantic-release ([3e24722](3e24722))
* **bulma-ui:** strip redundant library prefix from Icon name ([#242](#242)) ([dbe3622](dbe3622)), closes [#189](#189)
* **bulma-ui:** trigger release to publish via OIDC trusted publishing ([e2d09c5](e2d09c5))
* **bulma-ui:** update bundle size claims to accurate 21KB gzipped ([#66](#66)) ([6e381bd](6e381bd))
* **bulma-ui:** update package-lock.json ([853d585](853d585))
* **bulma-ui:** update package.json for better seo, exports, types, engines, funding, etc ([98cbc56](98cbc56))
* **bulma-ui:** use createRequire for ESM compatibility in Storybook 10 ([#130](#130)) ([b27e60e](b27e60e)), closes [#129](#129)
* **ci:** collect screenshots as artifacts and commit in single batch to avoid conflicts ([27b259d](27b259d))
* **ci:** ensure npm install uses fresh downloads with --prefer-online ([1f2e15d](1f2e15d))
* **ci:** properly extract base path for recursive file search ([e0330ff](e0330ff))
* **ci:** use find command instead of glob module in verified-commit action ([0e2d159](0e2d159))
* **ci:** use npm ci for scaffolded app dependencies ([35652c8](35652c8))
* **create-bestax:** correct browser title to prioritize Bestax branding ([#106](#106)) ([23aa535](23aa535)), closes [#105](#105)
* **create-bestax:** correct template path resolution from ../../ to ../ ([65b4493](65b4493)), closes [#78](#78)
* **create-bestax:** dark-mode contrast rules in theming/layout skills and docs ([#303](#303)) ([490bf21](490bf21)), closes [#194](#194) [#195](#195)
* **create-bestax:** exclude templates directory from linting and typecheck ([18fec0b](18fec0b))
* **create-bestax:** fail fast with guidance instead of hanging when stdin is not a TTY ([#293](#293)) ([46a172d](46a172d)), closes [#192](#192)
* **create-bestax:** move templates into package directory and update docs ([195bf01](195bf01)), closes [#78](#78)
* **create-bestax:** point scaffolded CLAUDE.md at llms docs; document skills ([#198](#198)) ([b2e0514](b2e0514))
* **create-bestax:** publish with npm provenance attestation ([21ffe8f](21ffe8f)), closes [#180](#180)
* **create-bestax:** read version from package.json instead of hardcoded value ([#109](#109)) ([8605699](8605699))
* **create-bestax:** refresh README and bump scaffolded bestax-bulma to ^5 ([4e19e86](4e19e86))
* **create-bestax:** reject dot-only project names, pin icon versions, bundle bestax-icons skill ([#310](#310)) ([ddff8e5](ddff8e5))
* **create-bestax:** scaffold @allxsmith/bestax-bulma ^4.0.0 ([1d3b802](1d3b802))
* **create-bestax:** scaffold bundled bestax CSS flavors, not stock Bulma ([43621dc](43621dc))
* **create-bestax:** ship improved bundled skills + component catalog ([#199](#199)) ([a1515c2](a1515c2))
* **create-bestax:** skills-sync conformance gate + theming skill reference backfill ([#326](#326)) ([9584133](9584133)), closes [#285](#285)
* **create-bestax:** synchronize version with bestax-bulma to 2.4.0 ([623ee79](623ee79)), closes [#96](#96)
* **create-bestax:** update template dependency to ^2.4.0 ([200971d](200971d))
* **create-bestax:** use scenario-specific screenshot directories to prevent overwrites ([#108](#108)) ([c675957](c675957)), closes [#107](#107)
* **docs:** correct Content Signals syntax in robots.txt ([#134](#134)) ([85dd9de](85dd9de))
* **docs:** emit per-page markdown so llms.txt links resolve ([#200](#200)) ([7877083](7877083))
* **docs:** escape apostrophe in QuickStart notification text ([25d6d72](25d6d72))
* **docs:** generate llms.txt so the advertised homepage link resolves ([9fae464](9fae464)), closes [#177](#177)
* **docs:** improve homepage hero layout and button spacing ([5f7a5a7](5f7a5a7))
* **docs:** move robots.txt to correct deployment location ([#90](#90)) ([1e2aeee](1e2aeee))
* **docs:** rebrand and reorganize Storybook ([#83](#83)) ([dfb9937](dfb9937))
* **docs:** remove Google Analytics and add robots.txt ([94776f7](94776f7))
* **docs:** update Storybook logo path to /img/logo.svg for deployed site ([bf59758](bf59758))
* **e2e:** correct notification CSS selectors to use contains instead of ends-with ([182acc1](182acc1))
* implement independent package versioning strategy ([#111](#111)) ([7819c73](7819c73)), closes [#110](#110)
* prevent bulma-ui from versioning on create-bestax commits ([#120](#120)) ([4dfaf9c](4dfaf9c)), closes [#119](#119)
* resolve React Hooks violations and ESLint configuration issues ([32d2931](32d2931))
* upgrade Turbo, Storybook, and Docusaurus dependencies ([5b4ebdd](5b4ebdd)), closes [#98](#98)

### Documentation

* fix stale versioning and coverage docs; drop CLAUDE.md stale-docs flags ([71c4583](71c4583))

### Features

* add theme system and config provider with comprehensive test coverage ([f3ca7f0](f3ca7f0))
* **bestax-migrate:** react-bulma-components → bestax-bulma codemod CLI, skill, and docs ([#333](#333)) ([e04a12b](e04a12b)), closes [#1e6b99](https://github.com/allxsmith/bestax/issues/1e6b99)
* **bulma-ui:** add Avatar, Avatars, and Badge components ([#257](#257)) ([0817018](0817018)), closes [#256](#256)
* **bulma-ui:** add colorMode dark-mode prop to Theme ([4acc41e](4acc41e)), closes [#174](#174)
* **bulma-ui:** add consistent gap prop to Columns, aliasing gapSize ([#300](#300)) ([6c36455](6c36455)), closes [#282](#282)
* **bulma-ui:** add cursor helper, closeDelay prop, and polish Tooltip stories ([37945b5](37945b5))
* **bulma-ui:** add extra components, form elements, and SCSS styles ([59daf28](59daf28))
* **bulma-ui:** add HTML element wrapper components ([#135](#135)) ([#136](#136)) ([20fb16d](20fb16d))
* **bulma-ui:** add manual-entry stories for format, bounds, and blocked-value variations ([e93d51c](e93d51c))
* **bulma-ui:** add Reveal component for scroll-triggered animations ([#255](#255)) ([a89c574](a89c574))
* **bulma-ui:** Add skeletons ([6c46e4b](6c46e4b))
* **bulma-ui:** add themed Checkbox/Radio, convenience Field components, and Autocomplete cleanup ([3c57a5a](3c57a5a))
* **bulma-ui:** add typing-first story variants for all picker property variations ([078433f](078433f))
* **bulma-ui:** avatar/badge a11y batch — decorative alt, accessible names, live region, button type, surplus i18n, focus ring ([#298](#298)) ([508477f](508477f)), closes [#266](#266) [#266](#266)
* **bulma-ui:** change the default primary color to [#1](#1 ([8872620](8872620)), closes [#1e6b99](https://github.com/allxsmith/bestax/issues/1e6b99) [#1e6b99](https://github.com/allxsmith/bestax/issues/1e6b99)
* **bulma-ui:** compound (dot-notation) sub-components for all parent/child families via shared withSubComponents helper ([#331](#331)) ([07516c5](07516c5))
* **bulma-ui:** dim and blur the calendar behind the Datetimepicker time wheels ([3d90619](3d90619))
* **bulma-ui:** finalize the 3.0 component set ([87ccc0e](87ccc0e))
* **bulma-ui:** make Button and Link as prop polymorphic (React.ElementType) ([#238](#238)) ([ce90304](ce90304)), closes [#188](#188)
* **bulma-ui:** require React 18 as the minimum supported version ([c7251b0](c7251b0))
* **ci:** add verified-commit action for GPG-signed commits ([d078dfa](d078dfa))
* **create-bestax:** add bestax-optimize skill for shrinking built CSS ([#329](#329)) ([f597b9f](f597b9f))
* **create-bestax:** add CLI tool with Vite templates and automated publishing ([9748c3d](9748c3d))
* **create-bestax:** add cross-platform emoji support with figures ([#103](#103)) ([15567d9](15567d9))
* **create-bestax:** add README with templates location note ([8ddc73d](8ddc73d))
* **create-bestax:** add visual regression testing and synchronized versioning ([17e1e22](17e1e22)), closes [#94](#94)
* **create-bestax:** bestax-icons skill — teach agents the icon system ([#302](#302)) ([61c8ef2](61c8ef2)), closes [#287](#287)
* **create-bestax:** improve favicon visibility and add distinct branding ([621590d](621590d)), closes [#100](#100)
* **create-bestax:** modernize templates (Vite 8, ESLint 10, TS 6) + add working lint config ([4537629](4537629)), closes [#167](#167)
* **create-bestax:** offer to install the bestax AI skills when scaffolding ([625b7bf](625b7bf)), closes [#174](#174)
* **create-bestax:** scaffold-aware CLAUDE.md with setup facts and house style ([#271](#271)) ([c1681b0](c1681b0))
* **docs:** add Google Analytics tracking for usage insights ([#68](#68)) ([90ab951](90ab951))
* **docs:** add pronunciation guide and dark mode support ([#58](#58)) ([48a8916](48a8916))
* **docs:** migrate from GitHub Pages to Cloudflare Pages ([#132](#132)) ([2154672](2154672)), closes [#131](#131)
* **form:** add Datepicker, Timepicker, and Datetimepicker components ([c6684e6](c6684e6))

### BREAKING CHANGES

* footer requirement, and the commitlint scope rule
- CONTRIBUTING.md: replace the type-less commit example with a
  commitlint-valid conventional format (verified against commitlint);
  correct all four coverage mentions to the real jest thresholds
  (bulma-ui 99%, create-bestax 95%/78% branches); fix the npm package
  name (@allxsmith/bestax-bulma, plus create-bestax) and link VERSIONING.md
- CLAUDE.md: remove the stale-docs warning and asides now that the
  underlying docs are correct; point at VERSIONING.md again

Closes #206.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131uD6QKmAij7Byk3SByyLh
* the @allxsmith/bestax-bulma/versions/bestax-bulma-prefixed.css
export is removed. Use versions/bestax-prefixed.css with classPrefix="bestax-".
* **bulma-ui:** React 16 and 17 are no longer supported; the minimum
supported React version is now 18.
* **bulma-ui:** Snackbar has been removed and merged into Toast; use Toast
with its positioning and queue props instead.
* **bulma-ui:** form controls now auto-wrap in Field/Control, and Checkbox
and Radio ship new themed visuals. See the 2.x -> 3.x migration guide.
* This version requires Node.js 18.0.0 or higher. The CLI now enforces this requirement and will exit with an error message if running on older Node.js versions. This aligns create-bestax with the bestax-bulma v2.x ecosystem.

* fix(create-bestax): correct Prettier formatting in index.ts
* None - all changes are additive and backward compatible
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

bestax-release-bot Bot pushed a commit that referenced this pull request Aug 12, 2026
# 1.0.0 (2026-08-12)

* feat(bulma-ui)!: remove bestax-bulma-prefixed CSS variant ([94baa34](94baa34))
* feat(create-bestax)!: require Node.js 18+ and align with bestax-bulma v2 ([#118](#118)) ([b22f183](b22f183))

### Bug Fixes

* add comprehensive rules to prevent bulma-ui versioning on non-bulma-ui commits ([#122](#122)) ([525ccfa](525ccfa)), closes [#119](#119)
* **bestax-mcp:** derive the near-miss guidance from the skill, and only when it helps ([1141cca](1141cca))
* **bestax-mcp:** do not split a helper-prop table cell on an escaped pipe ([bdac820](bdac820))
* **bestax-mcp:** lead get_helper_props with the inline-style prohibition ([ffc627a](ffc627a))
* **bestax-mcp:** make list_components point at the next step ([8ddb2fd](8ddb2fd))
* **bestax-mcp:** make tests and cached builds work from a clean checkout ([6e63820](6e63820)), closes [bestax-mcp#build](https://github.com/bestax-mcp/issues/build)
* **bestax-mcp:** name list_components as the entry point, not search_bestax ([206380b](206380b))
* **bestax-mcp:** name the three near-miss components in the list_components footer ([1c7af67](1c7af67))
* **bestax-mcp:** route helper questions to the tool that answers them ([cd6ce12](cd6ce12))
* **bestax-mcp:** validate the one input that is not ours, and bound the rest ([3e1adc9](3e1adc9))
* **bestax-migrate:** give the kitchen-sink e2e a per-process scratch dir ([2211ea5](2211ea5))
* **bestax-migrate:** reject pnpm's workspace alias form instead of unwrapping it ([de6a900](de6a900))
* **bestax-migrate:** require the pack script to exist, not just be named ([5315efe](5315efe))
* **bestax-migrate:** resolve bare workspace: and guard the catalog: protocol ([7fda9db](7fda9db)), closes [#417](#417) [#412](#412)
* **bestax-migrate:** resolve workspace: specifiers before publishing ([782829a](782829a)), closes [bestax-migrate#test](https://github.com/bestax-migrate/issues/test) [#412](#412)
* **bestax-migrate:** stop the pack hooks excusing a catalog: devDependency ([4127ead](4127ead)), closes [#412-shaped](#412)
* **bulma-ui:** a11y + case-insensitive Taginput matching from PR review ([d576829](d576829))
* **bulma-ui:** accept router props like `to` on Navbar.Item without casts ([#311](#311)) ([b78856b](b78856b)), closes [#306](#306)
* **bulma-ui:** Add build step to publish in ci.yml ([e3707fc](e3707fc))
* **bulma-ui:** add fontawesome-free as explicit devDependency ([a4a5389](a4a5389))
* **bulma-ui:** add missing exports ([0d16633](0d16633))
* **bulma-ui:** Add Skeleton to exports ([e481599](e481599))
* **bulma-ui:** another attempt to fix semantic release builds with ci.yml ([cc3a3e2](cc3a3e2))
* **bulma-ui:** another attempt to fix semantic release builds with ci.yml ([314bc39](314bc39))
* **bulma-ui:** another attempt to fix semantic release builds with ci.yml ([c930693](c930693))
* **bulma-ui:** associate Autocomplete and Taginput labels with their inner inputs ([7ae37d4](7ae37d4))
* **bulma-ui:** associate Autocomplete and Taginput labels with their inner inputs ([384bd38](384bd38))
* **bulma-ui:** associate the form label prop with its control via a generated id ([e6686af](e6686af))
* **bulma-ui:** complete domain migration and fix semantic-release configuration ([#64](#64)) ([f4cd71d](f4cd71d))
* **bulma-ui:** correct blog post examples and add Modal compound components ([#81](#81)) ([559c2e3](559c2e3))
* **bulma-ui:** correct NPM_TOKEN env variable in ci.yml ([94b48b4](94b48b4))
* **bulma-ui:** cover horizontal-layout group label association ([ef3ca9f](ef3ca9f))
* **bulma-ui:** deprecate CSS-less color values, warn in dev, fix has-text fall-through ([fb111eb](fb111eb))
* **bulma-ui:** fail closed on missing process and scope color guidance to real props ([117c0c0](117c0c0))
* **bulma-ui:** Fix release.config.js to include package-lock.json ([390da59](390da59))
* **bulma-ui:** fix standalone Badge pointer-events, pulse halo, and falsy content ([#295](#295)) ([a9db031](a9db031)), closes [#264](#264)
* **bulma-ui:** full classPrefix support across layout/grid + prefix utils ([4ce0b53](4ce0b53))
* **bulma-ui:** honor the htmlFor opt-out in the convenience hook and tighten the association docs ([92aa622](92aa622))
* **bulma-ui:** improve npm package discoverability with optimized keywords and badges ([#72](#72)) ([8c7a696](8c7a696))
* **bulma-ui:** Initial semantic release changes ([b78d785](b78d785))
* **bulma-ui:** keep Taginput's fallback name unless the label targets its input ([73cec33](73cec33))
* **bulma-ui:** keep Taginput's fallback name unless the label targets its input ([ca5996a](ca5996a))
* **bulma-ui:** migrate domain from bestax.cc to bestax.io ([#64](#64)) ([4870b1e](4870b1e))
* **bulma-ui:** migrate ionicons to v8 to unblock publish and Storybook ([927a55b](927a55b)), closes [#142](#142)
* **bulma-ui:** name Rate, Checkboxes, and Radios groups from their labels via aria-labelledby ([dce0ee7](dce0ee7))
* **bulma-ui:** name Rate, Checkboxes, and Radios groups from their labels via aria-labelledby ([#497](#497)) ([5c4222e](5c4222e))
* **bulma-ui:** name the three near-miss components in AGENTS.md ([c63f491](c63f491)), closes [#344](#344)
* **bulma-ui:** never let labelProps.htmlFor wire a group label to a control ([3b3aaaf](3b3aaaf))
* **bulma-ui:** publish rewritten README to npm ([9810081](9810081))
* **bulma-ui:** publish with npm provenance attestation ([172da62](172da62)), closes [#180](#180)
* **bulma-ui:** reference llms docs from README and package.json ([#198](#198)) ([db8aab3](db8aab3))
* **bulma-ui:** reject predicate-blocked values during manual entry ([a8f6e28](a8f6e28))
* **bulma-ui:** resolve flex item properties and Card compound component issues ([#55](#55)) ([e774da3](e774da3))
* **bulma-ui:** resolve flex item properties and Card compound component issues ([#55](#55)) ([7641a53](7641a53))
* **bulma-ui:** resolve react-hooks v7 and [@eslint-react](https://github.com/eslint-react) findings ([14caaaf](14caaaf))
* **bulma-ui:** resolve security vulnerabilities and update dependencies ([#128](#128)) ([112f6e4](112f6e4)), closes [#127](#127)
* **bulma-ui:** restrict semantic-release to bulma-ui scoped commits only ([2d67bf9](2d67bf9)), closes [#62](#62)
* **bulma-ui:** retry failed Avatar src, flatten Fragment children in Avatars, RTL-safe overlap ([#297](#297)) ([c00b9db](c00b9db))
* **bulma-ui:** route every hardcoded class through the prefix helpers; add classPrefix sweep test ([#301](#301)) ([a50b134](a50b134)), closes [#286](#286)
* **bulma-ui:** setup gpg signing with semantic-release ([3e24722](3e24722))
* **bulma-ui:** strip redundant library prefix from Icon name ([#242](#242)) ([dbe3622](dbe3622)), closes [#189](#189)
* **bulma-ui:** trigger release to publish via OIDC trusted publishing ([e2d09c5](e2d09c5))
* **bulma-ui:** update bundle size claims to accurate 21KB gzipped ([#66](#66)) ([6e381bd](6e381bd))
* **bulma-ui:** update package-lock.json ([853d585](853d585))
* **bulma-ui:** update package.json for better seo, exports, types, engines, funding, etc ([98cbc56](98cbc56))
* **bulma-ui:** use createRequire for ESM compatibility in Storybook 10 ([#130](#130)) ([b27e60e](b27e60e)), closes [#129](#129)
* **ci:** collect screenshots as artifacts and commit in single batch to avoid conflicts ([27b259d](27b259d))
* **ci:** ensure npm install uses fresh downloads with --prefer-online ([1f2e15d](1f2e15d))
* **ci:** properly extract base path for recursive file search ([e0330ff](e0330ff))
* **ci:** use find command instead of glob module in verified-commit action ([0e2d159](0e2d159))
* **ci:** use npm ci for scaffolded app dependencies ([35652c8](35652c8))
* **create-bestax:** concrete inline-style → helper-prop mapping for the never-inline rule ([#357](#357)) ([5f72a90](5f72a90)), closes [#350](#350) [#350](#350)
* **create-bestax:** correct browser title to prioritize Bestax branding ([#106](#106)) ([23aa535](23aa535)), closes [#105](#105)
* **create-bestax:** correct template path resolution from ../../ to ../ ([65b4493](65b4493)), closes [#78](#78)
* **create-bestax:** dark-mode contrast rules in theming/layout skills and docs ([#303](#303)) ([490bf21](490bf21)), closes [#194](#194) [#195](#195)
* **create-bestax:** exclude templates directory from linting and typecheck ([18fec0b](18fec0b))
* **create-bestax:** fail fast with guidance instead of hanging when stdin is not a TTY ([#293](#293)) ([46a172d](46a172d)), closes [#192](#192)
* **create-bestax:** move templates into package directory and update docs ([195bf01](195bf01)), closes [#78](#78)
* **create-bestax:** point scaffolded CLAUDE.md at llms docs; document skills ([#198](#198)) ([b2e0514](b2e0514))
* **create-bestax:** publish with npm provenance attestation ([21ffe8f](21ffe8f)), closes [#180](#180)
* **create-bestax:** put the near-miss guidance where every session sees it ([6db49f3](6db49f3))
* **create-bestax:** read version from package.json instead of hardcoded value ([#109](#109)) ([8605699](8605699))
* **create-bestax:** refresh README and bump scaffolded bestax-bulma to ^5 ([4e19e86](4e19e86))
* **create-bestax:** reject dot-only project names, pin icon versions, bundle bestax-icons skill ([#310](#310)) ([ddff8e5](ddff8e5))
* **create-bestax:** scaffold @allxsmith/bestax-bulma ^4.0.0 ([1d3b802](1d3b802))
* **create-bestax:** scaffold bundled bestax CSS flavors, not stock Bulma ([43621dc](43621dc))
* **create-bestax:** ship improved bundled skills + component catalog ([#199](#199)) ([a1515c2](a1515c2))
* **create-bestax:** shrink the near-miss block and pin the copies together ([d582da5](d582da5))
* **create-bestax:** skills-sync conformance gate + theming skill reference backfill ([#326](#326)) ([9584133](9584133)), closes [#285](#285)
* **create-bestax:** stop the skills teaching a Theme call that does not compile ([2935bb2](2935bb2))
* **create-bestax:** synchronize version with bestax-bulma to 2.4.0 ([623ee79](623ee79)), closes [#96](#96)
* **create-bestax:** teach the skills the three components Bulma hides ([22dcff7](22dcff7))
* **create-bestax:** update template dependency to ^2.4.0 ([200971d](200971d))
* **create-bestax:** use scenario-specific screenshot directories to prevent overwrites ([#108](#108)) ([c675957](c675957)), closes [#107](#107)
* **create-bestax:** validate at submit in the bestax-form signup example ([0b9518f](0b9518f))
* **create-bestax:** wire labeled controls in the skill showcase story ([af49a16](af49a16))
* **docs:** announce the hero copy, and stop remounting the icons ([98e2cb0](98e2cb0)), closes [#434](#434)
* **docs:** correct Content Signals syntax in robots.txt ([#134](#134)) ([85dd9de](85dd9de))
* **docs:** correct the frozen-install translation and reject leaked fences ([1883de3](1883de3))
* **docs:** drop dead nomodule ionicons fallback ([82be3e4](82be3e4))
* **docs:** emit per-page markdown so llms.txt links resolve ([#200](#200)) ([7877083](7877083))
* **docs:** escape apostrophe in QuickStart notification text ([25d6d72](25d6d72))
* **docs:** generate llms.txt so the advertised homepage link resolves ([9fae464](9fae464)), closes [#177](#177)
* **docs:** give every batch run its own port — slot reuse was corrupting runs ([6ef1755](6ef1755))
* **docs:** harden PackageManagerTabs and document how to author it ([5b0d3e6](5b0d3e6)), closes [#434](#434)
* **docs:** harden the hero copy button and share the tab storage key ([9e16cd7](9e16cd7))
* **docs:** improve homepage hero layout and button spacing ([5f7a5a7](5f7a5a7))
* **docs:** make the eval batch resumable after a container restart ([d56229e](d56229e))
* **docs:** make the hero package-manager switcher a real radiogroup ([aa14ff2](aa14ff2)), closes [#434](#434)
* **docs:** move robots.txt to correct deployment location ([#90](#90)) ([1e2aeee](1e2aeee))
* **docs:** rebrand and reorganize Storybook ([#83](#83)) ([dfb9937](dfb9937))
* **docs:** remove Google Analytics and add robots.txt ([94776f7](94776f7))
* **docs:** stop cssnano stripping Font Awesome [@font-face](https://github.com/font-face), add [#3](#3) CSS framework blog post ([#401](#401)) ([5d114e1](5d114e1)), closes [#400](#400)
* **docs:** update Storybook logo path to /img/logo.svg for deployed site ([bf59758](bf59758))
* **e2e:** correct notification CSS selectors to use contains instead of ends-with ([182acc1](182acc1))
* implement independent package versioning strategy ([#111](#111)) ([7819c73](7819c73)), closes [#110](#110)
* prevent bulma-ui from versioning on create-bestax commits ([#120](#120)) ([4dfaf9c](4dfaf9c)), closes [#119](#119)
* resolve React Hooks violations and ESLint configuration issues ([32d2931](32d2931))
* upgrade Turbo, Storybook, and Docusaurus dependencies ([5b4ebdd](5b4ebdd)), closes [#98](#98)

### chore

* **deps:** consolidate the dependabot backlog, require Node 22 in both CLIs ([#447](#447)) ([e68148c](e68148c)), closes [#427](#427) [#428](#428) [#431](#431) [#432](#432) [#440](#440) [#393](#393)

### Documentation

* fix stale versioning and coverage docs; drop CLAUDE.md stale-docs flags ([71c4583](71c4583))

### Features

* add theme system and config provider with comprehensive test coverage ([f3ca7f0](f3ca7f0))
* **bestax-mcp:** serve component docs, props, examples and skills over MCP ([c2abcc4](c2abcc4))
* **bestax-migrate:** react-bulma-components → bestax-bulma codemod CLI, skill, and docs ([#333](#333)) ([e04a12b](e04a12b)), closes [#1e6b99](https://github.com/allxsmith/bestax/issues/1e6b99)
* **bestax-migrate:** require Node 22 and take chalk 6 ([#449](#449)) ([4c0e1e2](4c0e1e2)), closes [#447](#447)
* **bulma-ui:** add Avatar, Avatars, and Badge components ([#257](#257)) ([0817018](0817018)), closes [#256](#256)
* **bulma-ui:** add colorMode dark-mode prop to Theme ([4acc41e](4acc41e)), closes [#174](#174)
* **bulma-ui:** add consistent gap prop to Columns, aliasing gapSize ([#300](#300)) ([6c36455](6c36455)), closes [#282](#282)
* **bulma-ui:** add cursor helper, closeDelay prop, and polish Tooltip stories ([37945b5](37945b5))
* **bulma-ui:** add extra components, form elements, and SCSS styles ([59daf28](59daf28))
* **bulma-ui:** add HTML element wrapper components ([#135](#135)) ([#136](#136)) ([20fb16d](20fb16d))
* **bulma-ui:** add manual-entry stories for format, bounds, and blocked-value variations ([e93d51c](e93d51c))
* **bulma-ui:** add Reveal component for scroll-triggered animations ([#255](#255)) ([a89c574](a89c574))
* **bulma-ui:** Add skeletons ([6c46e4b](6c46e4b))
* **bulma-ui:** add themed Checkbox/Radio, convenience Field components, and Autocomplete cleanup ([3c57a5a](3c57a5a))
* **bulma-ui:** add typing-first story variants for all picker property variations ([078433f](078433f))
* **bulma-ui:** associate Field's label with a composed base control ([219f631](219f631))
* **bulma-ui:** avatar/badge a11y batch — decorative alt, accessible names, live region, button type, surplus i18n, focus ring ([#298](#298)) ([508477f](508477f)), closes [#266](#266) [#266](#266)
* **bulma-ui:** change the default primary color to [#1](#1 ([8872620](8872620)), closes [#1e6b99](https://github.com/allxsmith/bestax/issues/1e6b99) [#1e6b99](https://github.com/allxsmith/bestax/issues/1e6b99)
* **bulma-ui:** compound (dot-notation) sub-components for all parent/child families via shared withSubComponents helper ([#331](#331)) ([07516c5](07516c5))
* **bulma-ui:** dim and blur the calendar behind the Datetimepicker time wheels ([3d90619](3d90619))
* **bulma-ui:** finalize the 3.0 component set ([87ccc0e](87ccc0e))
* **bulma-ui:** make Button and Link as prop polymorphic (React.ElementType) ([#238](#238)) ([ce90304](ce90304)), closes [#188](#188)
* **bulma-ui:** require React 18 as the minimum supported version ([c7251b0](c7251b0))
* **bulma-ui:** ship agent-discovery files in the npm tarball ([#345](#345)) ([4b58739](4b58739)), closes [#344](#344) [#344](#344) [#344](#344)
* **ci:** add verified-commit action for GPG-signed commits ([d078dfa](d078dfa))
* **create-bestax:** add bestax-optimize skill for shrinking built CSS ([#329](#329)) ([f597b9f](f597b9f))
* **create-bestax:** add CLI tool with Vite templates and automated publishing ([9748c3d](9748c3d))
* **create-bestax:** add controlled-Burger Navbar to the landing archetype ([#355](#355)) ([36d4d09](36d4d09)), closes [#348](#348)
* **create-bestax:** add cross-platform emoji support with figures ([#103](#103)) ([15567d9](15567d9))
* **create-bestax:** add README with templates location note ([8ddc73d](8ddc73d))
* **create-bestax:** add visual regression testing and synchronized versioning ([17e1e22](17e1e22)), closes [#94](#94)
* **create-bestax:** agent-validated guidance for skills, scaffold CLAUDE.md, and catalog ([#365](#365)) ([6fd06ae](6fd06ae)), closes [#2](#2)
* **create-bestax:** bestax-icons skill — teach agents the icon system ([#302](#302)) ([61c8ef2](61c8ef2)), closes [#287](#287)
* **create-bestax:** improve favicon visibility and add distinct branding ([621590d](621590d)), closes [#100](#100)
* **create-bestax:** modernize templates (Vite 8, ESLint 10, TS 6) + add working lint config ([4537629](4537629)), closes [#167](#167)
* **create-bestax:** offer to install the bestax AI skills when scaffolding ([625b7bf](625b7bf)), closes [#174](#174)
* **create-bestax:** require Node 22 and take chalk 6 ([#448](#448)) ([90fced2](90fced2)), closes [#447](#447)
* **create-bestax:** scaffold .claude/launch.json with the AI skills opt-in ([#343](#343)) ([189135a](189135a))
* **create-bestax:** scaffold-aware CLAUDE.md with setup facts and house style ([#271](#271)) ([c1681b0](c1681b0))
* **create-bestax:** set scaffolded index.html title to the project name ([#356](#356)) ([3bfbea3](3bfbea3)), closes [#349](#349) [#349](#349)
* **docs:** add Google Analytics tracking for usage insights ([#68](#68)) ([90ab951](90ab951))
* **docs:** add package-manager switches to the homepage hero ([374caf8](374caf8))
* **docs:** add PackageManagerTabs and register it globally ([23c9989](23c9989))
* **docs:** add pronunciation guide and dark mode support ([#58](#58)) ([48a8916](48a8916))
* **docs:** aggregate-runs.mjs — distribution stats across a runs directory ([5de9c07](5de9c07))
* **docs:** batch runner for the eval harness, with the concurrency fixes it needed ([f8e268c](f8e268c))
* **docs:** migrate from GitHub Pages to Cloudflare Pages ([#132](#132)) ([2154672](2154672)), closes [#131](#131)
* **docs:** rubric v2 and a brief that demands the components beyond Bulma ([e6047be](e6047be))
* **docs:** show all posts in the blog sidebar ([d29e9c6](d29e9c6))
* **form:** add Datepicker, Timepicker, and Datetimepicker components ([c6684e6](c6684e6))

### Performance Improvements

* **bestax-mcp:** stop get_helper_props costing half the session ([b865651](b865651))
* **docs:** defer live previews until they scroll into view ([d6bf87b](d6bf87b))
* **docs:** share one parsed stylesheet set across every live preview ([feb993a](feb993a))

### BREAKING CHANGES

* **bestax-migrate:** bestax-migrate now requires Node.js 22 or newer. Node 18 and
20 are both past end-of-life. Running it on an older runtime prints an explicit
upgrade message and exits 1. This applies to the runtime the codemod executes
on, not to the app being migrated.

Claude-Session: https://claude.ai/code/session_01TGA6sFTUGsJ6oXhfpjKEnh
* **create-bestax:** create-bestax now requires Node.js 22 or newer. Node 18 and 20
are both past end-of-life. Running it on an older runtime prints an explicit
upgrade message and exits 1.

Claude-Session: https://claude.ai/code/session_01TGA6sFTUGsJ6oXhfpjKEnh
* **deps:** create-bestax now requires Node.js 22 or newer. Node 18 and 20
are both past end-of-life. Running it on an older runtime prints an explicit
upgrade message and exits 1.

Claude-Session: https://claude.ai/code/session_01TGA6sFTUGsJ6oXhfpjKEnh

* feat(bestax-migrate): require Node 22 and take chalk 6

chalk 6 drops support for Node below 22. The API surface this package uses is
unchanged, so no calling code changes.

The version guard in src/index.ts moves ahead of every import and no longer
depends on anything: import declarations are hoisted and evaluated before any
statement in the module, and chalk 6 itself requires Node >= 22, so a static
import would fail to load on exactly the runtimes the guard exists to catch.
./cli.js is now imported dynamically for the same reason.

@babel/parser deliberately stays on 7.x. Babel 8 removes the
`deprecatedImportAssert` plugin with no replacement, and this package parses
the legacy `import x from 'y' assert { type: 'json' }` form on purpose — a
codemod that migrates older codebases must not crash on the syntax those
codebases still contain. There is a regression test for it ("parses the legacy
import-assert syntax"), which Babel 8 fails outright. jscodeshift 17 bundles
its own Babel 7 regardless, so staying on 7 also keeps a single parser in the
tree rather than two.
* **deps:** bestax-migrate now requires Node.js 22 or newer. Node 18 and
20 are both past end-of-life. Running it on an older runtime prints an explicit
upgrade message and exits 1.

Claude-Session: https://claude.ai/code/session_01TGA6sFTUGsJ6oXhfpjKEnh
* footer requirement, and the commitlint scope rule
- CONTRIBUTING.md: replace the type-less commit example with a
  commitlint-valid conventional format (verified against commitlint);
  correct all four coverage mentions to the real jest thresholds
  (bulma-ui 99%, create-bestax 95%/78% branches); fix the npm package
  name (@allxsmith/bestax-bulma, plus create-bestax) and link VERSIONING.md
- CLAUDE.md: remove the stale-docs warning and asides now that the
  underlying docs are correct; point at VERSIONING.md again

Closes #206.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0131uD6QKmAij7Byk3SByyLh
* the @allxsmith/bestax-bulma/versions/bestax-bulma-prefixed.css
export is removed. Use versions/bestax-prefixed.css with classPrefix="bestax-".
* **bulma-ui:** React 16 and 17 are no longer supported; the minimum
supported React version is now 18.
* **bulma-ui:** Snackbar has been removed and merged into Toast; use Toast
with its positioning and queue props instead.
* **bulma-ui:** form controls now auto-wrap in Field/Control, and Checkbox
and Radio ship new themed visuals. See the 2.x -> 3.x migration guide.
* This version requires Node.js 18.0.0 or higher. The CLI now enforces this requirement and will exit with an error message if running on older Node.js versions. This aligns create-bestax with the bestax-bulma v2.x ecosystem.

* fix(create-bestax): correct Prettier formatting in index.ts
* None - all changes are additive and backward compatible
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 1.0.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

needs-human-review Loop converged (or contested): awaiting owner review + manual merge released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Component Proposal] Avatar / Badge — user images, initials, status dots &amp; counts

2 participants