Skip to content

fix(bulma-ui): fire the pickers' onOpen and onClose once under StrictMode - #896

Merged
allxsmith merged 3 commits into
mainfrom
fix/picker-open-callbacks
Oct 5, 2026
Merged

allxsmith merged 3 commits into
mainfrom
fix/picker-open-callbacks

Conversation

@allxsmith

@allxsmith allxsmith commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

DateInput, DateTimeInput and TimeInput called onOpen and onClose from inside a state updater, and React may run an updater twice, so under StrictMode each fired twice in development. A deep review on #884 noted it.

The callbacks now fire from each picker's open setter instead. A ref keeps the input and the popover from both reporting one Escape as two closes.

A StrictMode open-and-close test in all three pickers failed before, and a double-Escape test guards the ref.

pnpm all passes locally.

Summary by CodeRabbit

  • Bug Fixes
    • Date, time, and date-time pickers now avoid duplicate open and close callbacks, including when Escape is handled by both the input and popover.
    • Picker state remains reliable when callbacks refocus the input or run in React Strict Mode.

DateInput, DateTimeInput and TimeInput called onOpen and onClose from inside their open-state
updater. StrictMode calls an updater twice in development, so each opening and closing reported
itself twice there. The callbacks now fire from the setter itself. A ref holds the state the last
request asked for, so the input and the popover both answering one Escape still close it, and
report it, once.
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 16 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: allxsmith/bestax/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0bf46fd2-3af0-4ecf-8283-ec793cc8c7f0
📥 Commits

Reviewing files that changed from the base of the PR and between 29dd2a4 and a09cfaa.

📒 Files selected for processing (6)
  • bulma-ui/src/form/DateInputBase.tsx
  • bulma-ui/src/form/DateTimeInputBase.tsx
  • bulma-ui/src/form/TimeInputBase.tsx
  • bulma-ui/src/form/__tests__/DateInput.test.tsx
  • bulma-ui/src/form/__tests__/DateTimeInput.test.tsx
  • bulma-ui/src/form/__tests__/TimeInput.test.tsx

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: allxsmith/bestax/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7c87af16-f882-4f44-bc63-6695b819d1fd
📥 Commits

Reviewing files that changed from the base of the PR and between 34a03e4 and 29dd2a4.

📒 Files selected for processing (6)
  • bulma-ui/src/form/DateInputBase.tsx
  • bulma-ui/src/form/DateTimeInputBase.tsx
  • bulma-ui/src/form/TimeInputBase.tsx
  • bulma-ui/src/form/__tests__/DateInput.test.tsx
  • bulma-ui/src/form/__tests__/DateTimeInput.test.tsx
  • bulma-ui/src/form/__tests__/TimeInput.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

Date, date-time, and time inputs now track requested popover state in refs, suppress repeated open-state requests, and invoke callbacks outside React state updaters. Tests cover callback counts under StrictMode, reopening during close callbacks, and Escape handling.

Changes

Popover state and callbacks

Layer / File(s) Summary
Requested state and callback updates
bulma-ui/src/form/DateInputBase.tsx, bulma-ui/src/form/DateTimeInputBase.tsx, bulma-ui/src/form/TimeInputBase.tsx
Each input uses a ref to deduplicate open-state requests. Each invokes the corresponding callback outside the state updater. Date-time and time inputs retain their existing value snapshots when opening.
Callback behavior tests
bulma-ui/src/form/__tests__/DateInput.test.tsx, bulma-ui/src/form/__tests__/DateTimeInput.test.tsx, bulma-ui/src/form/__tests__/TimeInput.test.tsx
Tests check callback counts under StrictMode, reopening when onClose focuses the input, and single onClose calls when Escape is handled by both the input and popover.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 29dd2

This change stops open and close callbacks from firing twice in development StrictMode for the date, date-time and time inputs. No merge-blocking risk was identified, and tests cover the main reopen and Escape cases.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to 29dd2

The change keeps picker state locally owned and preserves existing interaction guards. The reviewed paths introduce no material security risk or additional callback authority.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated exposure is local picker interaction and existing application-supplied callbacks. The changed setter does not establish a new cross-service entrypoint, credential capability, or privileged sink; application-specific callback effects remain outside the inspected scope.

Trust Boundaries and Controls

  • observed — The inspected date-time and time trigger paths still require a popover and an enabled, non-read-only component before opening. Input handlers receive the corresponding interaction flags. These are existing UI guards, not server-side authorization controls, and the setter change does not replace them.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the callback issue, the fix, and the tests, but it omits most of the repository template, including the package selection, related issues, type of change, and checklist. Add the template sections and fill in the applicable package, related-issue, type-of-change, and checklist items. Include screenshots or additional context only if applicable.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: ensuring the pickers’ onOpen and onClose callbacks fire once under StrictMode.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 6…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

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

@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 — 0 blocking · 2 advisory

No Severity Area Finding Location
1 🔵 Advisory Robustness requestedOpenRef is only ever written by setOpen, so a re-entrant setOpen from inside a consumer onOpen / onClose (the one reachable shape: an onClose that synchronously focuses the input of the picker itself while openOnFocus is on) leaves the ref ahead of the committed state — and from then on setOpen(true) early-returns forever, so the picker can never be reopened. Pre-change this misbehaved too (it reopened, state consistent), so this sharpens an existing edge rather than adding a path. A post-commit resync — useEffect(() => { requestedOpenRef.current = open; }, [open]) — heals it without weakening the same-event de-dupe bulma-ui/src/form/DateInputBase.tsx:341
2 🔵 Advisory Coverage The second test per picker (the input and the popover both take Escape) passes on the pre-change code as well — the old updater guard deduped the second setOpen(false) against prev exactly as the ref does — so it guards the ref against removal rather than reproducing the bug being fixed. That is what the PR body claims for it; recorded only so nobody reads it as a regression test for the StrictMode defect bulma-ui/src/form/__tests__/DateInput.test.tsx:2017

Overall: The diagnosis and the fix are both right, and this is the textbook remedy: React double-invokes useState updaters under StrictMode in development, so a consumer callback fired inside one is reported twice — moving onOpen and onClose into the setter and carrying the de-dupe in a ref restores exactly the semantics the updater chain had. I walked the multi-call-per-batch orderings and the callback sequence is identical before and after, because the ref mirrors the prev chain. The ref is load-bearing rather than decorative: PickerPopover registers its Escape handler on document (PickerPopover.tsx:82), so an Escape typed in the input really does reach both the React handler on the input and the one on the popover, and without the guard the setter-based form would fire onClose twice. The riskiest part is row 1 — the ref is now the sole source of truth for what the last request asked for, with nothing that ever re-reads the committed state — and that is where a human should look first; the rest is mechanical.

Residual risk:

  • Other StrictMode double-fires in the same class — refuted by search: a grep for a consumer callback (on[A-Z]...?.()) inside any setX(prev => ...) updater across all of bulma-ui/src now returns nothing, so these three were the last instances library-wide. The only updaters left in the picker stack are setFocusedDate(prev => clampDate(...)) (DateInputBase.tsx:300, DateTimeInputBase.tsx:289), which are pure.
  • Ref / state divergence without consumer re-entrancy — refuted: setOpenState has exactly one caller in each base (DateInputBase.tsx:345, DateTimeInputBase.tsx:380, TimeInputBase.tsx:321), always immediately after the matching ref write, and open starts false in all three alongside useRef(false); there is no defaultOpen or controlled open prop that could seed them differently.
  • The launcher toggle reading a stale open — refuted. setOpen(!open) (DateInputBase.tsx:619, DateTimeInputBase.tsx:693, TimeInputBase.tsx:605) cannot race the outside-click close, because the pointerdown handler in PickerPopover returns early when the composed path contains the anchor (PickerPopover.tsx:67), and the container — launcher included — is the anchor. Where two calls do land in one batch, the ref yields the same end state the prev guard did.
  • The openOnFocus handback guard — refuted as unaffected: closingRef keys off the isOpen state transition in a layout effect (useSegmentedEntry.ts:184-196), which this diff does not touch. Note the ordering it now implies, though: onClose fires before the closing commit, that is, before closingRef is set, which is precisely the window row 1 describes.
  • React 18 — open, but low: nothing here is version-specific (a ref plus a plain setter), and updater double-invocation under StrictMode exists on both majors, so the new tests should fail pre-change and pass post-change on 18 too. Only React 19.3.0 is installed in this sandbox, so I did not execute the 18 leg; the React 18/19 matrix in CI does.
  • The claim that these tests failed before — unverified by execution rather than refuted. This sandbox denied every file write and every git checkout, so I could not restore the pre-change setters and re-run the tests against them. I checked it by mechanism instead (a callback inside a double-invoked updater is called twice) and by reading the superseded code at HEAD~1.
  • The native-mobile path — unchanged and still silent: when useNative is true the component returns an <input type="date"> before any setOpen call site, so neither callback ever fires there. Pre-existing, and outside the class this PR addresses.

Verified locally: src/form is green (38 suites, 1673 tests); the three bases measure 100% lines and 100% functions with only pre-existing partial branches left (DateInputBase.tsx:382,619, DateTimeInputBase.tsx:693, TimeInputBase.tsx:605), so the new early-return branch is covered; typecheck:tests is clean; eslint and prettier pass on all six changed files.

🏄 Clean three-line re-entry — took the callbacks out of the churn where React makes you ride every wave twice, and parked the de-dupe in a ref that paddles ahead of the render. Nothing in this lineup worth bailing for; just remember that the ref never looks back at the board it is standing on.

@github-actions github-actions Bot added the review-converged Deep review converged: no blocking findings, all review threads resolved, checks green label Oct 4, 2026
The open setter recorded each request before calling onOpen or onClose and set the state after.
A request made from inside the callback, such as an onClose that focuses the picker's own input
under openOnFocus, then recorded open while the outer call's close was set last. The popover
ended closed with the record saying open, so every later request to open was dropped. The
setter now sets the state before calling back, so a request a callback makes is the last one
both recorded and set, and the callbacks report the state the picker ends in.
@github-actions github-actions Bot removed the review-converged Deep review converged: no blocking findings, all review threads resolved, checks green label Oct 4, 2026
@allxsmith

Copy link
Copy Markdown
Owner Author

Every finding from the review, fixed or answered, in 29dd2a4:

  1. A re-entrant setOpen left the ref ahead of the state: fixed, a little differently from the suggested resync. The setter now queues the state update before calling onOpen or onClose, so a request made from inside the callback is the last one both recorded and set, and the callbacks always match the state the picker ends in. A resync after commit would unstick the ref but could leave the popover closed after onOpen had reported it open. A test in all three pickers, "still opens after an onClose that focuses the input", failed before.
  2. The double-Escape test passes on the old code too: refuted. It isn't meant to reproduce the StrictMode bug; the StrictMode test does that, and fails on the old code. This one guards the ref the PR adds: with the callbacks moved out of the updater, the input's handler and the popover's document listener both answering one Escape would each fire onClose, and this test catches that. A guard against a regression the change could introduce passes before and after it by design.

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

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

@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: fresh

Main is merged in, so this review posts every finding, advisory included, as its own thread. It reviews a09cfaa.

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://4c62e136.bestax.pages.dev

Comment thread bulma-ui/src/form/DateInputBase.tsx
Comment thread bulma-ui/src/form/__tests__/DateInput.test.tsx

@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 — 0 blocking · 2 advisory

# Severity Area Finding Location
1 🔵 Advisory Robustness A consumer onClose that refocuses the input defeats Escape under openOnFocus — the close is undone by the reopen the focus requests, which the new test asserts. Not a regression (pre-change reopened too), so on the record rather than requested bulma-ui/src/form/DateInputBase.tsx:346
2 🔵 Advisory Coverage The double-Escape test passes against the removed updater too (its prev === next guard deduped identically, and the test runs outside StrictMode), so it guards the new ref rather than reproducing either fixed defect bulma-ui/src/form/__tests__/DateInput.test.tsx:2049

Overall: Both the diagnosis and the fix are correct, and the merge of main brings in the second commit that repairs the re-entrancy hole the earlier review flagged — setOpenState now runs before the callbacks, so a request a callback makes is the last one both recorded and set, and requestedOpenRef can no longer be left ahead of the committed state. I confirmed the root cause from the installed React rather than from the PR body: react-dom-client.development.js:8426-8430 invokes the updater an extra, result-discarded time whenever shouldDoubleInvokeUserFnsInHooksDEV is set, with the pre-update state, so the old prev === next guard did not stop it and both callbacks fired twice under StrictMode. The riskiest part is that the ref is still the sole record of the requested state with nothing re-reading open, and the invariant that keeps them in step is positional — setOpenState(next) must stay the statement immediately before the callbacks. That is worth a human's eye first, though the still opens after an onClose that focuses the input test does fail if it is reordered, which is exactly how the first commit broke.

Residual risk:

  • Other instances of the same StrictMode class library-wide — refuted by an exhaustive sweep of src/components, src/form (incl. _pickerInternals), src/elements, src/helpers, src/layout, src/columns, src/grid: no consumer callback prop is invoked from inside any state updater or useMemo body, and there is no useReducer in the package at all. Navbar.tsx:783-796 already uses this PR's shape (compute next, set, then onActiveChange?.(next)).
  • Ref / state divergence without consumer re-entrancy — refuted. setOpenState has exactly one caller in each base (DateInputBase.tsx:344, DateTimeInputBase.tsx:375, TimeInputBase.tsx:316), always the statement after the matching ref write; useState(false) and useRef(false) are seeded alike; and there is no controlled open or defaultOpen prop that could seed them differently. The re-entrant orderings (an onClose that opens, an onOpen that closes, and two independent setOpen(false) calls in one event with a reopen between them) all end with the ref and the state agreeing.
  • onChange / onClose ordering flipped by firing in the handler instead of in render — refuted by reading every call site. Each one commits first and closes second: DateInputBase.tsx:384-386, useSegmentedEntry.ts:508-511, TimeInputBase.tsx:491-499 / 508-509 / 522-523, DateTimeInputBase.tsx:617. onChange still precedes onClose.
  • valueAtOpenRef captured after setOpenState(true) — refuted as unobservable: it is read only from click handlers (DateTimeInputBase.tsx:617, TimeInputBase.tsx:508,522), never during render or a layout effect, and React batches the update so no render intervenes between the two statements.
  • Escape reaching both the input's React handler and the popover's document listener — refuted as the de-dupe path it is meant to be: PickerPopover.tsx:76-84 registers on document, so React's handler on the input runs first and stopPropagation cannot retract it; the ref makes the second call a no-op. Verified by the third test in each picker.
  • The openOnFocus handback guard — refuted as untouched: closingRef keys off the isOpen transition in a layout effect (useSegmentedEntry.ts:184-196), which this diff does not reach. The one behaviour it does not cover is finding 1.
  • An impure updater of the same family still in the picker stack — TimeWheels.tsx:371-384 writes positionRef.current from inside its setPosition updater, so StrictMode invokes that write twice. Outside this diff, and benign: the write is idempotent for a given prevPos, and no consumer callback is reachable from it (onCommit / onChange fire from commitPosition, outside the updater). Named here rather than posted, since it is not a path the diff touches.
  • The PR's claim that the new tests failed before the change — verified by mechanism, not by execution. This sandbox blocked every file write, every git worktree/checkout and node --eval, so I could not restore the pre-change setters and re-run. Instead I read the double-invocation out of the installed React (above) and traced the first commit's ordering against the second test, which it fails. Treat the "failed before" claim as strongly supported rather than reproduced.
  • React 18 — open, but low: a ref plus a plain setter is not version-specific, and the dev double-invocation of updaters exists on both majors. Only React 19 is installed here, so I did not run the 18 leg; CI's React 18/19 matrix does.
  • The native-mobile path — unchanged and still silent: with useNative true the component returns <input type="date"> before any setOpen call site, so neither callback ever fires there. Pre-existing and outside this failure class.

Verified locally: src/form green (38 suites, 1676 tests); the three bases at 100% lines and 100% functions with only pre-existing partial branches left (DateInputBase.tsx:383,620, DateTimeInputBase.tsx:694, TimeInputBase.tsx:606 — all canOpen / isWithin guards), so the new early-return branch is covered; tsc -p tsconfig.test.json clean; eslint and prettier clean on all six changed files. No API change, so the generated docs pages and skills/ need no update.

🏄 Second wave cleaned up what the first one churned — callbacks out of the updater, state set before the callback so a re-entry rides in last, and the whole lineup still glassy at 1676 tests. Good to go; just know the ref and the setter have to keep paddling in that exact order.

@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: verify

Both open threads have a reply refuting them with a reason. This settles them on a09cfaa.

@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 (verify) — 2 resolved · 0 open

Thread Outcome Location
1 — 🔵 Advisory · Robustness — a consumer onClose that refocuses the input defeats Escape under openOnFocus Resolved — refutation accepted (deliberate, and matches the documented contract) bulma-ui/src/form/DateInputBase.tsx:346
2 — 🔵 Advisory · Coverage — the double-Escape test passes against the old updater too Resolved — refutation accepted (the test is a guard for the ref, and is presented as one) bulma-ui/src/form/__tests__/DateInput.test.tsx:2049

Overall: This pass settled threads and reviewed no commits. Both of my open threads were 🔵 Advisory, and both carried a reasoned reply from allxsmith — the PR author, and admin by a live role check. I judged each against the current code on a09cfaa5 and accepted both, so nothing of mine is left open and there is nothing here for a human to arbitrate. A reader who wants the code at a09cfaa5 reviewed afresh should ask for one with a deep-review: fresh steer comment.

What I checked before accepting each

Thread 1 — the reopen is the documented contract, not a defect. The three load-bearing facts in the reply all hold:

  • The openOnFocus TSDoc scopes the closed-on-focus exception specifically to focus a closing popover hands back (DateInputBase.tsx:174-177), which is also exactly what closingRef / handedBackRef implement (_pickerInternals/useSegmentedEntry.ts:168-182, 325-329). A focus the picker did not hand back therefore opens by design.
  • Every picker already hands focus back itself: restoreFocusRef={inputRef} at DateInputBase.tsx:641, DateTimeInputBase.tsx:715, TimeInputBase.tsx:627.
  • The reopen predates this PR — the finding itself recorded it as "not a regression" and requested no change.

A reasoned deliberate choice, so accepted rather than re-raised.

Thread 2 — no claim to correct. The reply concedes the facts and says the test exists to guard the ref. The PR body says "a double-Escape test guards the ref", never presenting it as a reproduction, so the thing the finding guarded against — the suite being read as three regression tests per picker — is not asserted anywhere. The test at DateInput.test.tsx:2049 is fires onClose once when the input and the popover both take Escape.

Test run (one run covers both threads, same package):

pnpm --filter @allxsmith/bestax-bulma exec jest src/form/__tests__/DateInput.test.tsx src/form/__tests__/DateTimeInput.test.tsx src/form/__tests__/TimeInput.test.tsx

Test Suites: 3 passed, 3 total
Tests:       341 passed, 341 total

I could not run the counterfactual both replies cite — restoring the pre-PR updaters and watching only the StrictMode tests fail — because file writes were not permitted in this session. It would not have changed either outcome: thread 1 rests on the documented contract, which I read directly, and the thread 2 finding asked for no change.

Residual risk: out of scope for a verify pass — this pass raised no findings and reviewed no commits, so there is no new failure class to enumerate. The one limitation worth leaving on the record is in the details above: the counterfactual test run the replies cite is accepted on the documented contract and the passing suite rather than re-executed here.

🏄 Two mellow advisories, two straight answers from the author, and the whole 341-test set rolls in clean — nothing left bobbing out back. Board is waxed, threads are closed, this one is good to go.

@github-actions github-actions Bot added the review-converged Deep review converged: no blocking findings, all review threads resolved, checks green label Oct 5, 2026
@allxsmith allxsmith added the needs-human-review Loop converged (or contested): awaiting owner review + manual merge label Oct 5, 2026
@github-actions github-actions Bot removed the review-converged Deep review converged: no blocking findings, all review threads resolved, checks green label Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

📸 Story screenshots at handoff — a09cfaa

No Storybook stories map to this PR's changed files — nothing to screenshot. (workflow run)

@github-actions github-actions Bot added the review-converged Deep review converged: no blocking findings, all review threads resolved, checks green label Oct 5, 2026
@allxsmith
allxsmith merged commit 20b51ed into main Oct 5, 2026
114 checks passed
@allxsmith
allxsmith deleted the fix/picker-open-callbacks branch October 5, 2026 11:43
bestax-release-bot Bot pushed a commit that referenced this pull request Oct 5, 2026
## [5.26.3](https://github.com/allxsmith/bestax/compare/@allxsmith/bestax-bulma@5.26.2...@allxsmith/bestax-bulma@5.26.3) (2026-10-05)

### Bug Fixes

* **bulma-ui:** fire the pickers' onOpen and onClose once under StrictMode ([#896](#896)) ([20b51ed](20b51ed))
* **bulma-ui:** let focus follow the keys in an inline calendar, and skip disabled days for the tab stop ([#885](#885)) ([f55af27](f55af27))
* **bulma-ui:** make Theme colorMode switch the scheme under the prefixed builds ([#894](#894)) ([2bd6ec2](2bd6ec2))
* **bulma-ui:** place a portaled picker panel by its coordinates alone ([#886](#886)) ([040299b](040299b))
* **bulma-ui:** read picker bounds and months in years 0 to 99 as written ([#890](#890)) ([02fb619](02fb619))
* **bulma-ui:** start a date picker's focus on the focused cell ([#897](#897)) ([6a55714](6a55714))
* **bulma-ui:** stop the indeterminate progress bar and skeleton pulse under reduced motion ([bcf5407](bcf5407))
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 5.26.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

bestax-release-bot Bot pushed a commit that referenced this pull request Oct 7, 2026
# [2.25.0](https://github.com/allxsmith/bestax/compare/bestax-migrate@2.24.0...bestax-migrate@2.25.0) (2026-10-07)

### Bug Fixes

* **bulma-ui:** announce polite notifications through a status region kept from mount ([#835](#835)) ([c93478d](c93478d))
* **bulma-ui:** answer the granularity review on native input and blur ([7a17486](7a17486))
* **bulma-ui:** attach useFocusTrap to a container that mounts after it turns on ([17a944d](17a944d))
* **bulma-ui:** bring File and Taginput under the bare-Control Field rule ([cdaa6c2](cdaa6c2))
* **bulma-ui:** clear a picker's unused seed whenever its popover closes ([cbe86c5](cbe86c5))
* **bulma-ui:** color the calendar from the color prop and read TimeInput's wheel variables ([2251e67](2251e67)), closes [#832](#832)
* **bulma-ui:** commit nothing when a picker popover is dismissed ([0a46209](0a46209))
* **bulma-ui:** commit nothing when Enter confirms untouched picker text ([773e146](773e146))
* **bulma-ui:** commit nothing when focus leaves a picker untouched ([30b4849](30b4849))
* **bulma-ui:** draw the time wheel focus ring where the wheel's mask shows it ([e1d8c9f](e1d8c9f)), closes [#832](#832)
* **bulma-ui:** fall back when useFocusTrap's initialFocusRef can't take focus ([c191931](c191931))
* **bulma-ui:** fire the pickers' onOpen and onClose once under StrictMode ([#896](#896)) ([20b51ed](20b51ed))
* **bulma-ui:** give the selected calendar cell a ring that shows on its fill ([b3eecc6](b3eecc6))
* **bulma-ui:** hide a picker's launcher for a loading Control it sits in ([9a3888e](9a3888e))
* **bulma-ui:** hide a picker's launcher only for the spinner it draws ([7a28a0e](7a28a0e))
* **bulma-ui:** hold Portal to looking a selector up on each render ([8fe02ce](8fe02ce))
* **bulma-ui:** hold the year-1 floor under a max before it ([4f6eb18](4f6eb18))
* **bulma-ui:** judge image map areas by their image in useFocusTrap ([af7bc59](af7bc59))
* **bulma-ui:** keep a tab stop in the year list when the year falls outside it ([fe028c1](fe028c1))
* **bulma-ui:** keep an empty picker's seed while a portaled popover is open ([1e66528](1e66528))
* **bulma-ui:** keep an inline date picker's calendar on its released id ([c26da07](c26da07)), closes [#897](#897) [#897](#897)
* **bulma-ui:** keep button defaults through a spread, and type the buttons that had none ([#853](#853)) ([0810482](0810482))
* **bulma-ui:** keep button types and Avatar's accessible name through a spread ([#826](#826)) ([dc798d4](dc798d4))
* **bulma-ui:** keep the Field for horizontal and fieldClassName in a bare Control ([e4dc513](e4dc513))
* **bulma-ui:** keep the picker focus rings visible in every color ([612aa09](612aa09))
* **bulma-ui:** let focus follow the keys in an inline calendar, and skip disabled days for the tab stop ([#885](#885)) ([f55af27](f55af27))
* **bulma-ui:** let the picker bases give way to a loading Control too ([66e803a](66e803a))
* **bulma-ui:** let useFocusTrap go of a container that leaves while it is on ([8c56d7a](8c56d7a))
* **bulma-ui:** make auto leave room for an in-place picker panel's themed offset ([8c534bd](8c534bd)), closes [#904](#904)
* **bulma-ui:** make Theme colorMode switch the scheme under the prefixed builds ([#894](#894)) ([2bd6ec2](2bd6ec2))
* **bulma-ui:** make useFocusTrap follow radio groups and initialFocusRef past the trap ([d6219d4](d6219d4))
* **bulma-ui:** match a picker's opening focus only inside its calendar ([e3c22ed](e3c22ed))
* **bulma-ui:** place a portaled picker panel by its coordinates alone ([#886](#886)) ([040299b](040299b))
* **bulma-ui:** place toasts and notifications at the position they were shown with ([#834](#834)) ([62feab9](62feab9))
* **bulma-ui:** read clicks and focus inside a shadow root ([474f2cc](474f2cc))
* **bulma-ui:** read picker bounds and months in years 0 to 99 as written ([#890](#890)) ([02fb619](02fb619))
* **bulma-ui:** restore a portaled Modal's focus to an opener in a shadow root ([c564bd3](c564bd3))
* **bulma-ui:** return focus to the input when a date picker closes ([b741264](b741264))
* **bulma-ui:** settle Popover's deep review findings ([feadaf4](feadaf4))
* **bulma-ui:** start a date picker's focus on the focused cell ([#897](#897)) ([6a55714](6a55714))
* **bulma-ui:** stop Bulma's spinners under reduced motion in every stylesheet ([b234712](b234712)), closes [#770](#770)
* **bulma-ui:** stop form wrappers nesting a Field in a bare Control ([2c6d295](2c6d295))
* **bulma-ui:** stop the date pickers at year 1 ([853142a](853142a))
* **bulma-ui:** stop the indeterminate progress bar and skeleton pulse under reduced motion ([bcf5407](bcf5407))
* **bulma-ui:** stop the Rate pop and DateTimeInput scrim under reduced motion ([3a59129](3a59129))
* **bulma-ui:** stop TimeInput reopening on the focus its popover hands back ([1c87c15](1c87c15))
* **bulma-ui:** warn when a root Theme drops its className and helpers ([05c10e0](05c10e0))
* **eslint-plugin:** judge Columns' gap by its own steps, and lengths as lengths ([4786c8d](4786c8d))

### Features

* **bestax-mcp:** publish to the official MCP Registry ([74efc7f](74efc7f))
* **bestax-migrate:** convert the gap, position, overflow, radius and aspect-ratio helpers ([13dcf63](13dcf63))
* **bulma-ui:** add Bulma's gap helper props to every component ([#877](#877)) ([1bd4abc](1bd4abc))
* **bulma-ui:** add Bulma's position, overflow, radius and aspect-ratio helper props ([#845](#845)) ([64fb91c](64fb91c))
* **bulma-ui:** add Collapses, an accordion group for Collapse ([#849](#849)) ([a12c823](a12c823))
* **bulma-ui:** add Loader, Bulma's inline spinner ([c5e9eb0](c5e9eb0)), closes [#770](#770)
* **bulma-ui:** add month and year pickers to DateInput through granularity ([c4cfc2b](c4cfc2b)), closes [#773](#773)
* **bulma-ui:** add Popover ([2e17fac](2e17fac)), closes [#776](#776)
* **bulma-ui:** export ClientOnly and useIsHydrated ([2c0c1e6](2c0c1e6))
* **bulma-ui:** export Portal ([346d8c2](346d8c2))
* **bulma-ui:** export useFocusTrap, counting the stops the browser's Tab visits ([c304fef](c304fef)), closes [#772](#772)
* **bulma-ui:** make columnGap the column gap helper on Theme ([eb2c611](eb2c611)), closes [#694](#694)
* **eslint-plugin:** check the gap helper props ([b53a749](b53a749))
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 2.25.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

bestax-release-bot Bot pushed a commit that referenced this pull request Oct 8, 2026
## [4.2.13](https://github.com/allxsmith/bestax/compare/create-bestax@4.2.12...create-bestax@4.2.13) (2026-10-08)

### Bug Fixes

* **bestax-mcp:** give .image's ratios their reason in the lookup ([3ea4d0c](3ea4d0c))
* **bestax-mcp:** say an .image converts around elements written out, not an expression ([49bb27b](49bb27b))
* **bestax-migrate:** convert an .image around its children only when they're elements ([ff99907](ff99907))
* **bestax-migrate:** flag react-bulma-components Pagination's delta={0} rather than renaming it ([e339ff1](e339ff1))
* **bestax-migrate:** keep a .menu-list around a bestax Menu.List as markup ([2119c3f](2119c3f))
* **bestax-migrate:** keep a Modal part as markup inside an existing bestax Modal ([cfd5f15](cfd5f15))
* **bestax-migrate:** keep a named anchor as markup instead of saying its name does nothing ([74dc360](74dc360)), closes [#fragment](https://github.com/allxsmith/bestax/issues/fragment)
* **bestax-migrate:** keep a page link as markup when its li is a component's only child ([0e72683](0e72683))
* **bestax-migrate:** know a bestax part imported under its flat export ([7a325ee](7a325ee))
* **bestax-migrate:** leave a wrapper tag alone when none of its classes would become a prop ([2397b9d](2397b9d))
* **bestax-migrate:** leave a wrapper tag with no helper class alone, TODOs and all ([1167a29](1167a29))
* **bestax-migrate:** map react-bulma-components Pagination onto the props it now renders from ([6cd4b51](6cd4b51))
* **bestax-migrate:** rename rbx innerRef to ref on a plain Navbar.Item too ([bb6ace0](bb6ace0)), closes [#734](#734)
* **bestax-migrate:** say why .image's ratios stay classes ([2fbfbd5](2fbfbd5))
* **bestax-migrate:** write a File text with a backslash as a string ([212831e](212831e))
* **bestax-migrate:** write a tabIndex string as a number on every root ([546bf8a](546bf8a)), closes [#814](#814)
* **bestax-migrate:** write isFullwidth from react-bulma-components too ([01da047](01da047))
* **bestax-migrate:** write isFullwidth rather than its deprecated alias from bloomer ([c2a1d22](c2a1d22)), closes [#680](#680)
* **bulma-ui:** announce polite notifications through a status region kept from mount ([#835](#835)) ([c93478d](c93478d))
* **bulma-ui:** answer the granularity review on native input and blur ([7a17486](7a17486))
* **bulma-ui:** apply textColor helper class on Navbar Menu, Start, End, and Burger ([#792](#792)) ([feb83c8](feb83c8))
* **bulma-ui:** attach useFocusTrap to a container that mounts after it turns on ([17a944d](17a944d))
* **bulma-ui:** avoid empty class attribute on several components ([#793](#793)) ([7c5c316](7c5c316))
* **bulma-ui:** bring File and Taginput under the bare-Control Field rule ([cdaa6c2](cdaa6c2))
* **bulma-ui:** clear a picker's unused seed whenever its popover closes ([cbe86c5](cbe86c5))
* **bulma-ui:** close a picker's popover on Alt+ArrowUp from inside it ([b6da4ef](b6da4ef))
* **bulma-ui:** color the calendar from the color prop and read TimeInput's wheel variables ([2251e67](2251e67)), closes [#832](#832)
* **bulma-ui:** color TimeInput's wheels from the color prop ([#832](#832)) ([ad370c9](ad370c9))
* **bulma-ui:** commit nothing when a picker popover is dismissed ([0a46209](0a46209))
* **bulma-ui:** commit nothing when Enter confirms untouched picker text ([773e146](773e146))
* **bulma-ui:** commit nothing when focus leaves a picker untouched ([30b4849](30b4849))
* **bulma-ui:** document the checkbox, radio and switch color and size tuples ([bd39ff3](bd39ff3))
* **bulma-ui:** draw the time wheel focus ring where the wheel's mask shows it ([e1d8c9f](e1d8c9f)), closes [#832](#832)
* **bulma-ui:** drop the openOnFocus TSDoc reason that only holds for segments ([efde0d9](efde0d9))
* **bulma-ui:** Dropdown items withhold attributes by tag and answer Enter and Space ([#827](#827)) ([f6aeb2d](f6aeb2d))
* **bulma-ui:** fall back when useFocusTrap's initialFocusRef can't take focus ([c191931](c191931))
* **bulma-ui:** fire the pickers' onOpen and onClose once under StrictMode ([#896](#896)) ([20b51ed](20b51ed))
* **bulma-ui:** give the calendar's day grid rows of a week ([971a196](971a196)), closes [#774](#774)
* **bulma-ui:** give the selected calendar cell a ring that shows on its fill ([b3eecc6](b3eecc6))
* **bulma-ui:** hide a picker's launcher for a loading Control it sits in ([9a3888e](9a3888e))
* **bulma-ui:** hide a picker's launcher only for the spinner it draws ([7a28a0e](7a28a0e))
* **bulma-ui:** hold Portal to looking a selector up on each render ([8fe02ce](8fe02ce))
* **bulma-ui:** hold the year-1 floor under a max before it ([4f6eb18](4f6eb18))
* **bulma-ui:** judge image map areas by their image in useFocusTrap ([af7bc59](af7bc59))
* **bulma-ui:** keep a range's end while the start's digits are coming ([8d1f862](8d1f862))
* **bulma-ui:** keep a read-only date or time picker closed on ArrowDown ([ba74bf7](ba74bf7))
* **bulma-ui:** keep a tab stop in the year list when the year falls outside it ([fe028c1](fe028c1))
* **bulma-ui:** keep an empty picker's seed while a portaled popover is open ([1e66528](1e66528))
* **bulma-ui:** keep an inline date picker's calendar on its released id ([c26da07](c26da07)), closes [#897](#897) [#897](#897)
* **bulma-ui:** keep button defaults through a spread, and type the buttons that had none ([#853](#853)) ([0810482](0810482))
* **bulma-ui:** keep button types and Avatar's accessible name through a spread ([#826](#826)) ([dc798d4](dc798d4))
* **bulma-ui:** keep menuitemcheckbox and menuitemradio items in Dropdown's arrow-key order ([#786](#786)) ([064155a](064155a))
* **bulma-ui:** keep Numberinput's buttons in a row inside Field > Control ([4dff84c](4dff84c))
* **bulma-ui:** keep Numberinput's Field examples in a row and labelled ([c937c88](c937c88))
* **bulma-ui:** keep radiusless zeroing the radius inside a Theme ([07db6a3](07db6a3)), closes [#829](#829) [#694](#694)
* **bulma-ui:** keep the calendar behind DateTimeInput's time wheels out of reach ([c7f674c](c7f674c))
* **bulma-ui:** keep the clock's seconds out of a picked date and time ([0af2e71](0af2e71))
* **bulma-ui:** keep the Field for horizontal and fieldClassName in a bare Control ([e4dc513](e4dc513))
* **bulma-ui:** keep the picker focus rings visible in every color ([612aa09](612aa09))
* **bulma-ui:** keep the range band under the pointer in the calendar ([c1f2008](c1f2008))
* **bulma-ui:** key the Avatar link warning on the element and attributes ([e628eba](e628eba)), closes [#733](#733) [#733](#733)
* **bulma-ui:** key the Control-level warning by its advice ([24cda3d](24cda3d))
* **bulma-ui:** leave keys on a control inside a tab to that control ([4a9f7b6](4a9f7b6))
* **bulma-ui:** leave rel out of the Avatar link attribute warning ([b059476](b059476)), closes [#733](#733) [#733](#733)
* **bulma-ui:** let Autocomplete's clear button give way to a loading spinner ([5c11fb2](5c11fb2))
* **bulma-ui:** let Escape in a popover's year dropdown go back to the grid ([a8b1dbf](a8b1dbf)), closes [#901](#901)
* **bulma-ui:** let File's picked-files count be reworded, and document its name in the label ([e86545c](e86545c))
* **bulma-ui:** let focus follow the keys in an inline calendar, and skip disabled days for the tab stop ([#885](#885)) ([f55af27](f55af27))
* **bulma-ui:** let several isRoot Themes share the :root style element ([04f399f](04f399f)), closes [#736](#736)
* **bulma-ui:** let the arrow keys move through the calendar's year dropdown ([6abc329](6abc329)), closes [#901](#901)
* **bulma-ui:** let the picker bases give way to a loading Control too ([66e803a](66e803a))
* **bulma-ui:** let useFocusTrap go of a container that leaves while it is on ([8c56d7a](8c56d7a))
* **bulma-ui:** let warnOnce decide when the Avatar link warning fires ([1a5965c](1a5965c)), closes [#733](#733)
* **bulma-ui:** make ArrowUp raise a time wheel's value ([c27c310](c27c310))
* **bulma-ui:** make auto leave room for an in-place picker panel's themed offset ([8c534bd](8c534bd)), closes [#904](#904)
* **bulma-ui:** make Tabs keyboard operable with the WAI-ARIA tabs pattern ([fe0e7ef](fe0e7ef))
* **bulma-ui:** make Theme colorMode switch the scheme under the prefixed builds ([#894](#894)) ([2bd6ec2](2bd6ec2))
* **bulma-ui:** make Theme's radius the helper it is typed as ([36c73d3](36c73d3)), closes [#694](#694)
* **bulma-ui:** make useFocusTrap follow radio groups and initialFocusRef past the trap ([d6219d4](d6219d4))
* **bulma-ui:** match a picker's opening focus only inside its calendar ([e3c22ed](e3c22ed))
* **bulma-ui:** merge className into Navbar.Divider instead of overwriting it ([#791](#791)) ([fcc0d51](fcc0d51))
* **bulma-ui:** move focus into DateTimeInput's time wheels as they open ([adfa9db](adfa9db))
* **bulma-ui:** move the year dropdown's tab stop with the arrow keys ([f56daf5](f56daf5))
* **bulma-ui:** name a picker's default icon when its icon size or column moves ([6f6de39](6f6de39))
* **bulma-ui:** name custom elements among the targets that get Avatar's target and rel ([a962259](a962259)), closes [#733](#733)
* **bulma-ui:** name DateRangeInput's default icon in its Control-level warning ([15cbbb8](15cbbb8)), closes [#952](#952)
* **bulma-ui:** name DateRangeInput's default icon in its Control-level warning ([9cbe7ca](9cbe7ca)), closes [#952](#952)
* **bulma-ui:** name Pagination's page links, and read a count that's no number as its default ([0a1cf06](0a1cf06))
* **bulma-ui:** open DateRangeInput's popover on Alt+ArrowDown, as the other pickers ([c0e22ec](c0e22ec))
* **bulma-ui:** open the date and time popovers on Alt+ArrowDown ([6db22cc](6db22cc))
* **bulma-ui:** order the Tabs fallback stop by index and style disabled tabs ([eefd283](eefd283))
* **bulma-ui:** pick a DateInput day at midnight by key as by click ([92c27ca](92c27ca))
* **bulma-ui:** place a portaled picker panel by its coordinates alone ([#886](#886)) ([040299b](040299b))
* **bulma-ui:** place toasts and notifications at the position they were shown with ([#834](#834)) ([62feab9](62feab9))
* **bulma-ui:** prefix the is-current and is-disabled classes on Pagination's parts ([c9a5fae](c9a5fae))
* **bulma-ui:** reach Taginput's delete buttons and Autocomplete's clear button ([21a064b](21a064b))
* **bulma-ui:** read a Pagination current page that's no number as the first ([68e963b](68e963b))
* **bulma-ui:** read clicks and focus inside a shadow root ([474f2cc](474f2cc))
* **bulma-ui:** read picker bounds and months in years 0 to 99 as written ([#890](#890)) ([02fb619](02fb619))
* **bulma-ui:** render the four burger spans Bulma v1 positions ([#785](#785)) ([8e4e1e6](8e4e1e6))
* **bulma-ui:** restore a portaled Modal's focus to an opener in a shadow root ([c564bd3](c564bd3))
* **bulma-ui:** return focus to the input when a date picker closes ([b741264](b741264))
* **bulma-ui:** say a picked DateTimeInput day keeps milliseconds and meets the bounds ([3536467](3536467))
* **bulma-ui:** say Tab reaches DateRangeInput's end input only when typing ([d2d3d1a](d2d3d1a))
* **bulma-ui:** say where Numberinput goes bare and test bare={false} in a Field ([0461631](0461631))
* **bulma-ui:** send a press on DateRangeInput's field to the nearer input ([f06b2b0](f06b2b0))
* **bulma-ui:** settle Popover's deep review findings ([feadaf4](feadaf4))
* **bulma-ui:** show the picked file with File's hasName and add a keyboard focus ring ([7881db4](7881db4))
* **bulma-ui:** show toasts, notifications and dialogs raised before their container mounts ([#828](#828)) ([2ab4493](2ab4493))
* **bulma-ui:** skip the Avatar target warning on elements with their own target ([27b58f4](27b58f4)), closes [#733](#733)
* **bulma-ui:** start a date picker's focus on the focused cell ([#897](#897)) ([6a55714](6a55714))
* **bulma-ui:** stop Bulma's spinners under reduced motion in every stylesheet ([b234712](b234712)), closes [#770](#770)
* **bulma-ui:** stop form wrappers nesting a Field in a bare Control ([2c6d295](2c6d295))
* **bulma-ui:** stop shipping test-only exports, and document notification() ([#781](#781)) ([5f95398](5f95398))
* **bulma-ui:** stop the date pickers at year 1 ([853142a](853142a))
* **bulma-ui:** stop the indeterminate progress bar and skeleton pulse under reduced motion ([bcf5407](bcf5407))
* **bulma-ui:** stop the Rate pop and DateTimeInput scrim under reduced motion ([3a59129](3a59129))
* **bulma-ui:** stop TimeInput reopening on the focus its popover hands back ([1c87c15](1c87c15))
* **bulma-ui:** strip the Avatar link warning from production builds ([a243fa5](a243fa5)), closes [#733](#733)
* **bulma-ui:** warn about a dropped Avatar href only for an as the caller wrote ([c93b27c](c93b27c)), closes [#733](#733)
* **bulma-ui:** warn in development when Avatar drops an href on a non-link as ([c76e632](c76e632)), closes [#733](#733)
* **bulma-ui:** warn when a root Theme drops its className and helpers ([05c10e0](05c10e0))
* **bulma-ui:** warn when a wrapper inside a Control drops its Control-level props ([cbf434b](cbf434b)), closes [#921](#921)
* **bulma-ui:** warn when an inline picker drops its Control-level props ([f0494bd](f0494bd)), closes [#921](#921)
* **bulma-ui:** warn when Avatar drops a target or rel on a non-link as ([50c385e](50c385e)), closes [#733](#733) [#733](#733)
* **create-bestax:** check the react ranges fit the library's peers, not equal them ([8ae5a0c](8ae5a0c)), closes [#950](#950)
* **create-bestax:** import the icon CSS for every Bulma flavor, not only complete ([a712b91](a712b91)), closes [#946](#946)
* **create-bestax:** install react and react-dom so Yarn 1 reports no unmet peers ([9c9814c](9c9814c)), closes [#644](#644) [#950](#950)
* **create-bestax:** name the files the overwrite prompt removes, and stop on a file path ([39b6232](39b6232)), closes [#945](#945)
* **create-bestax:** never empty a non-empty folder under -y, and validate flags first ([917f195](917f195)), closes [#950](#950) [#945](#945) [#950](#950)
* **create-bestax:** warn when the icon CSS import has nowhere to go ([f7f0b64](f7f0b64)), closes [#946](#946) [#946](#946)
* **eslint-plugin:** judge Columns' gap by its own steps, and lengths as lengths ([4786c8d](4786c8d))
* **eslint-plugin:** report .file as a class the codemod converts ([72a32c9](72a32c9))
* **eslint-plugin:** report .image with the message for a class the codemod converts ([d27c19b](d27c19b))
* **eslint-plugin:** report .menu, .menu-label and .menu-list with the converts message ([8ffaccc](8ffaccc))
* **eslint-plugin:** report .select and .breadcrumb as converted ([a9d8082](a9d8082))
* **eslint-plugin:** report Bulma form markup as classes the codemod converts ([128e832](128e832))
* **eslint-plugin:** report Bulma skeletons as converted ([04ca4ee](04ca4ee))
* **eslint-plugin:** report Modal's parts with the message for a class the codemod converts ([87f3c08](87f3c08))
* **eslint-plugin:** report Pagination's converting parts with the converts message ([6b94f14](6b94f14))
* **eslint-plugin:** report the pagination links and ellipsis as classes the codemod converts ([54ba0b3](54ba0b3))
* **eslint-plugin:** report Theme's deprecated radius route accurately ([5605816](5605816)), closes [#694](#694)
* **eslint-plugin:** suggest radiusless for a near miss on Theme ([21aa9a7](21aa9a7)), closes [#694](#694)

### Features

* **bestax-mcp:** look up .image as Image, with the props it takes from its <img> ([3e63230](3e63230))
* **bestax-mcp:** look up .menu and its label and list as Menu's parts ([f9fe7cd](f9fe7cd))
* **bestax-mcp:** look up Card's title and footer items on the tags their as takes ([ba8193e](ba8193e))
* **bestax-mcp:** look up Modal's parts as components ([b71583a](b71583a))
* **bestax-mcp:** look up Pagination, its list and its previous and next links as components ([f1298df](f1298df))
* **bestax-mcp:** look up the bestax component and props for a Bulma class string ([4a4b246](4a4b246)), closes [#744](#744)
* **bestax-mcp:** publish to the official MCP Registry ([74efc7f](74efc7f))
* **bestax-mcp:** say a Bulma field wraps its children only when horizontal ([929bc82](929bc82))
* **bestax-mcp:** say an .image converts around anything but a bare <img> ([60e9219](60e9219))
* **bestax-mcp:** say Menu.List renders .menu-list only at the top level ([dcce74f](dcce74f))
* **bestax-mcp:** say when a component renders the children from a count ([b60c295](b60c295))
* **bestax-mcp:** say when a component renders the element inside it ([4ced25c](4ced25c))
* **bestax-mcp:** say when a component renders the li around its element, or its own text ([8fd3faf](8fd3faf))
* **bestax-mcp:** say when a component renders the whole .file tree from props ([976d8a3](976d8a3))
* **bestax-migrate:** convert .file inside a Field, building its tree from props ([724dff5](724dff5)), closes [#809](#809)
* **bestax-migrate:** convert .icon-text, building its icons from props ([#823](#823)) ([933868f](933868f))
* **bestax-migrate:** convert .menu, its labels and its top-level lists ([02f4db6](02f4db6))
* **bestax-migrate:** convert .select and .breadcrumb with the element inside them ([d76c569](d76c569))
* **bestax-migrate:** convert .tabs and .icon around their children ([#815](#815)) ([3967a80](3967a80))
* **bestax-migrate:** convert a menu list's items to Menu.Item ([#816](#816)) ([b385687](b385687))
* **bestax-migrate:** convert an .image and its <img> to Image ([d4f3673](d4f3673)), closes [#793](#793)
* **bestax-migrate:** convert an .image around anything but a bare <img> ([0a31c5b](0a31c5b)), closes [#801](#801)
* **bestax-migrate:** convert Bulma cards built from their parts ([#752](#752)) ([1b08e17](1b08e17))
* **bestax-migrate:** convert Bulma form fields, controls, inputs and textareas ([3da788d](3da788d)), closes [#743](#743)
* **bestax-migrate:** convert Bulma grids and cells ([#760](#760)) ([22adc7c](22adc7c)), closes [#743](#743)
* **bestax-migrate:** convert Bulma navbars ([#754](#754)) ([02fdd72](02fdd72))
* **bestax-migrate:** convert Bulma skeletons ([2574ace](2574ace))
* **bestax-migrate:** convert Card's title and footer items on the tags their as takes ([20bc0c6](20bc0c6)), closes [#794](#794)
* **bestax-migrate:** convert conditional classes in clsx and classnames calls ([8948cce](8948cce))
* **bestax-migrate:** convert Modal's parts element by element ([4d41ad2](4d41ad2)), closes [#805](#805)
* **bestax-migrate:** convert navbar dividers with classes, and navbar text colors ([#796](#796)) ([c97c7e9](c97c7e9))
* **bestax-migrate:** convert Pagination, its list and its previous and next links ([d75bc70](d75bc70)), closes [#807](#807)
* **bestax-migrate:** convert Pagination's page links and ellipsis in their li's place ([ae720fa](ae720fa)), closes [#809](#809)
* **bestax-migrate:** convert Panel and its heading, tabs and blocks ([#811](#811)) ([0694e54](0694e54))
* **bestax-migrate:** convert the gap, position, overflow, radius and aspect-ratio helpers ([13dcf63](13dcf63))
* **bestax-migrate:** fold .table-container and .fixed-grid into the component inside ([#761](#761)) ([72504f5](72504f5)), closes [#743](#743)
* **bulma-ui:** add Bulma's gap helper props to every component ([#877](#877)) ([1bd4abc](1bd4abc))
* **bulma-ui:** add Bulma's position, overflow, radius and aspect-ratio helper props ([#845](#845)) ([64fb91c](64fb91c))
* **bulma-ui:** add Collapses, an accordion group for Collapse ([#849](#849)) ([a12c823](a12c823))
* **bulma-ui:** add DateRangeInput ([50fcba7](50fcba7)), closes [#774](#774)
* **bulma-ui:** add Loader, Bulma's inline spinner ([c5e9eb0](c5e9eb0)), closes [#770](#770)
* **bulma-ui:** add month and year pickers to DateInput through granularity ([c4cfc2b](c4cfc2b)), closes [#773](#773)
* **bulma-ui:** add Popover ([2e17fac](2e17fac)), closes [#776](#776)
* **bulma-ui:** export ClientOnly and useIsHydrated ([2c0c1e6](2c0c1e6))
* **bulma-ui:** export Portal ([346d8c2](346d8c2))
* **bulma-ui:** export useFocusTrap, counting the stops the browser's Tab visits ([c304fef](c304fef)), closes [#772](#772)
* **bulma-ui:** let Card.Header.Title and Card.FooterItem render Bulma's own tags ([#794](#794)) ([47ecdb6](47ecdb6))
* **bulma-ui:** make columnGap the column gap helper on Theme ([eb2c611](eb2c611)), closes [#694](#694)
* **bulma-ui:** render Pagination from total, current and onPageChange ([f7ddf04](f7ddf04)), closes [#813](#813)
* **eslint-plugin:** add an opt-in rule for plain elements styled with a Bulma component class ([#750](#750)) ([0bb4d80](0bb4d80))
* **eslint-plugin:** check the gap helper props ([b53a749](b53a749))
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 4.2.13 🎉

The release is available on:

Your semantic-release bot 📦🚀

bestax-release-bot Bot pushed a commit that referenced this pull request Oct 9, 2026
## [1.14.1](https://github.com/allxsmith/bestax/compare/bestax-mcp@1.14.0...bestax-mcp@1.14.1) (2026-10-09)

### Bug Fixes

* **bestax-mcp:** describe a built icon's attributes as the codemod writes them ([d2f341b](d2f341b)), closes [#942](#942)
* **bestax-mcp:** hold every docs Storybook link to a real story, and floor the index's ([3a6df21](3a6df21))
* **bestax-mcp:** keep a described or named component first in a sentence-shaped search ([2e2a1ef](2e2a1ef))
* **bestax-mcp:** name every component that declares a CSS variable, its owner first ([8bf01e3](8bf01e3))
* **bestax-mcp:** point the index's Storybook links at stories that exist ([0852de4](0852de4))
* **bestax-mcp:** rank the component a search is about above passing mentions ([cc952c2](cc952c2))
* **bestax-mcp:** read self-closing names, explain Theme on every query, advertise dot-paths ([62a4a3a](62a4a3a))
* **bestax-mcp:** release the skill examples that compile in a vite-ts scaffold ([3a7f222](3a7f222))
* **bestax-mcp:** smooth the rough edges a smoke test found ([b6ed21a](b6ed21a))
* **bestax-mcp:** stop the search comment claiming every variable has an owner ([4f1d102](4f1d102))
* **bestax-migrate:** convert a .icon to Icon by the attributes Icon now writes ([a3795fb](a3795fb)), closes [#942](#942)
* **bestax-migrate:** convert an unnamed .icon with a role of its own without aria-hidden ([7c5ff91](7c5ff91)), closes [#942](#942)
* **bestax-migrate:** convert an unnamed .icon with a tabIndex of its own without aria-hidden ([df24c06](df24c06)), closes [#942](#942)
* **bulma-ui:** attach useFocusTrap to a container that mounts after it turns on ([17a944d](17a944d))
* **bulma-ui:** bring File and Taginput under the bare-Control Field rule ([cdaa6c2](cdaa6c2))
* **bulma-ui:** carry Rate's value on its checked star, not the radiogroup ([84f86d8](84f86d8)), closes [#942](#942)
* **bulma-ui:** check initializers for import-time work and stop overstating namespace imports ([20ef350](20ef350))
* **bulma-ui:** clear a picker's unused seed whenever its popover closes ([cbe86c5](cbe86c5))
* **bulma-ui:** close a picker's popover on Alt+ArrowUp from inside it ([b6da4ef](b6da4ef))
* **bulma-ui:** collapse an inline DateTimeInput's wheels on Enter ([ff44aa3](ff44aa3))
* **bulma-ui:** commit nothing when a picker popover is dismissed ([0a46209](0a46209))
* **bulma-ui:** commit nothing when Enter confirms untouched picker text ([773e146](773e146))
* **bulma-ui:** commit nothing when focus leaves a picker untouched ([30b4849](30b4849))
* **bulma-ui:** commit the time on Enter from the seconds wheel too ([d2c0920](d2c0920))
* **bulma-ui:** drop the openOnFocus TSDoc reason that only holds for segments ([efde0d9](efde0d9))
* **bulma-ui:** emit the ESM build one file per module so unused components shake out ([2893197](2893197))
* **bulma-ui:** fire the pickers' onOpen and onClose once under StrictMode ([#896](#896)) ([20b51ed](20b51ed))
* **bulma-ui:** give the calendar's day grid rows of a week ([971a196](971a196)), closes [#774](#774)
* **bulma-ui:** give TimeInput's wheels an id apart from the popover's ([40824cc](40824cc))
* **bulma-ui:** hide a picker's launcher for a loading Control it sits in ([9a3888e](9a3888e))
* **bulma-ui:** hide a picker's launcher only for the spinner it draws ([7a28a0e](7a28a0e))
* **bulma-ui:** hide an unnamed Icon and make a named one an image ([f9de39c](f9de39c)), closes [#942](#942)
* **bulma-ui:** hold the year-1 floor under a max before it ([4f6eb18](4f6eb18))
* **bulma-ui:** keep a press on a time wheel item from focusing the hidden item ([c57836a](c57836a)), closes [#942](#942)
* **bulma-ui:** keep a range's end while the start's digits are coming ([8d1f862](8d1f862))
* **bulma-ui:** keep a read-only date or time picker closed on ArrowDown ([ba74bf7](ba74bf7))
* **bulma-ui:** keep a tab stop in the year list when the year falls outside it ([fe028c1](fe028c1))
* **bulma-ui:** keep an empty picker's seed while a portaled popover is open ([1e66528](1e66528))
* **bulma-ui:** keep an inline date picker's calendar on its released id ([c26da07](c26da07)), closes [#897](#897) [#897](#897)
* **bulma-ui:** keep each Rate star's name its own at a value a hair off a whole number ([eed3d99](eed3d99)), closes [#942](#942)
* **bulma-ui:** keep Numberinput's buttons in a row inside Field > Control ([4dff84c](4dff84c))
* **bulma-ui:** keep Numberinput's Field examples in a row and labelled ([c937c88](c937c88))
* **bulma-ui:** keep the calendar behind DateTimeInput's time wheels out of reach ([c7f674c](c7f674c))
* **bulma-ui:** keep the clock's seconds out of a picked date and time ([0af2e71](0af2e71))
* **bulma-ui:** keep the Field for horizontal and fieldClassName in a bare Control ([e4dc513](e4dc513))
* **bulma-ui:** keep the range band under the pointer in the calendar ([c1f2008](c1f2008))
* **bulma-ui:** keep the time wheels' items out of their spinbutton ([6a02615](6a02615)), closes [#942](#942)
* **bulma-ui:** key the Control-level warning by its advice ([24cda3d](24cda3d))
* **bulma-ui:** leave an unnamed Icon with a role of its own visible ([b1e85f5](b1e85f5)), closes [#942](#942)
* **bulma-ui:** leave an unnamed Icon with a tabIndex of its own visible ([a41d131](a41d131)), closes [#942](#942)
* **bulma-ui:** leave Dropdown's menu nothing focusable but its items ([c1ec016](c1ec016)), closes [#942](#942)
* **bulma-ui:** leave keys on a control inside a tab to that control ([4a9f7b6](4a9f7b6))
* **bulma-ui:** let Autocomplete's clear button give way to a loading spinner ([5c11fb2](5c11fb2))
* **bulma-ui:** let Escape in a popover's year dropdown go back to the grid ([a8b1dbf](a8b1dbf)), closes [#901](#901)
* **bulma-ui:** let File's picked-files count be reworded, and document its name in the label ([e86545c](e86545c))
* **bulma-ui:** let focus follow the keys in an inline calendar, and skip disabled days for the tab stop ([#885](#885)) ([f55af27](f55af27))
* **bulma-ui:** let the arrow keys move through the calendar's year dropdown ([6abc329](6abc329)), closes [#901](#901)
* **bulma-ui:** let the picker bases give way to a loading Control too ([66e803a](66e803a))
* **bulma-ui:** let useFocusTrap go of a container that leaves while it is on ([8c56d7a](8c56d7a))
* **bulma-ui:** make ArrowUp raise a time wheel's value ([c27c310](c27c310))
* **bulma-ui:** make auto leave room for an in-place picker panel's themed offset ([8c534bd](8c534bd)), closes [#904](#904)
* **bulma-ui:** make Tabs keyboard operable with the WAI-ARIA tabs pattern ([fe0e7ef](fe0e7ef))
* **bulma-ui:** make Theme colorMode switch the scheme under the prefixed builds ([#894](#894)) ([2bd6ec2](2bd6ec2))
* **bulma-ui:** match a picker's opening focus only inside its calendar ([e3c22ed](e3c22ed))
* **bulma-ui:** move focus into DateTimeInput's time wheels as they open ([adfa9db](adfa9db))
* **bulma-ui:** move the year dropdown's tab stop with the arrow keys ([f56daf5](f56daf5))
* **bulma-ui:** name a picker's default icon when its icon size or column moves ([6f6de39](6f6de39))
* **bulma-ui:** name DateRangeInput's default icon in its Control-level warning ([51fc017](51fc017)), closes [#952](#952)
* **bulma-ui:** name DateRangeInput's default icon in its Control-level warning ([633f5dc](633f5dc)), closes [#952](#952)
* **bulma-ui:** name DateRangeInput's default icon in its Control-level warning ([15cbbb8](15cbbb8)), closes [#952](#952)
* **bulma-ui:** name DateRangeInput's default icon in its Control-level warning ([9cbe7ca](9cbe7ca)), closes [#952](#952)
* **bulma-ui:** name DateRangeInput's default icon in its Control-level warning ([25b7a0b](25b7a0b)), closes [#952](#952)
* **bulma-ui:** open DateRangeInput's popover on Alt+ArrowDown, as the other pickers ([c0e22ec](c0e22ec))
* **bulma-ui:** open the date and time popovers on Alt+ArrowDown ([6db22cc](6db22cc))
* **bulma-ui:** order the Tabs fallback stop by index and style disabled tabs ([eefd283](eefd283))
* **bulma-ui:** pick a DateInput day at midnight by key as by click ([92c27ca](92c27ca))
* **bulma-ui:** place a portaled picker panel by its coordinates alone ([#886](#886)) ([040299b](040299b))
* **bulma-ui:** point Autocomplete's aria-controls at its list only while the list is on screen ([8a16115](8a16115)), closes [#942](#942)
* **bulma-ui:** reach Taginput's delete buttons and Autocomplete's clear button ([21a064b](21a064b))
* **bulma-ui:** read a day that is both today and a nearby month the same inside a range band ([4164c3b](4164c3b)), closes [#983](#983)
* **bulma-ui:** read DateTimeInput's footer time row at 4.5:1 in both schemes ([585aa3b](585aa3b)), closes [#976](#976)
* **bulma-ui:** read every calendar day at 4.5:1 in both schemes ([876fe60](876fe60)), closes [#983](#983)
* **bulma-ui:** read picker bounds and months in years 0 to 99 as written ([#890](#890)) ([02fb619](02fb619))
* **bulma-ui:** render the time wheels' inert calendar through inertProps ([f023f25](f023f25))
* **bulma-ui:** return focus to the input when a date picker closes ([b741264](b741264))
* **bulma-ui:** say a picked DateTimeInput day keeps milliseconds and meets the bounds ([3536467](3536467))
* **bulma-ui:** say Alt+ArrowUp closes DateTimeInput's popover from the wheels ([f994d7d](f994d7d))
* **bulma-ui:** say Tab reaches DateRangeInput's end input only when typing ([d2d3d1a](d2d3d1a))
* **bulma-ui:** say where Numberinput goes bare and test bare={false} in a Field ([0461631](0461631))
* **bulma-ui:** send a press on DateRangeInput's field to the nearer input ([f06b2b0](f06b2b0))
* **bulma-ui:** show the picked file with File's hasName and add a keyboard focus ring ([7881db4](7881db4))
* **bulma-ui:** start a date picker's focus on the focused cell ([#897](#897)) ([6a55714](6a55714))
* **bulma-ui:** stop form wrappers nesting a Field in a bare Control ([2c6d295](2c6d295))
* **bulma-ui:** stop the date pickers at year 1 ([853142a](853142a))
* **bulma-ui:** stop the indeterminate progress bar and skeleton pulse under reduced motion ([bcf5407](bcf5407))
* **bulma-ui:** stop the picker popover partial warning about global nth() ([0b34d84](0b34d84))
* **bulma-ui:** stop the Rate pop and DateTimeInput scrim under reduced motion ([3a59129](3a59129))
* **bulma-ui:** tie DateTimeInput's Time button to the wheels it opens ([889fc7e](889fc7e))
* **bulma-ui:** warn when a root Theme drops its className and helpers ([05c10e0](05c10e0))
* **bulma-ui:** warn when a wrapper inside a Control drops its Control-level props ([cbf434b](cbf434b)), closes [#921](#921)
* **bulma-ui:** warn when an inline picker drops its Control-level props ([f0494bd](f0494bd)), closes [#921](#921)
* **bulma-ui:** wire Autocomplete's combobox to a named listbox ([213f648](213f648)), closes [#942](#942)
* **create-bestax:** check the react ranges fit the library's peers, not equal them ([8ae5a0c](8ae5a0c)), closes [#950](#950)
* **create-bestax:** have the optimize skill install with the project's package manager ([e0ba314](e0ba314)), closes [#597](#597)
* **create-bestax:** import the icon CSS for every Bulma flavor, not only complete ([a712b91](a712b91)), closes [#946](#946)
* **create-bestax:** install react and react-dom so Yarn 1 reports no unmet peers ([9c9814c](9c9814c)), closes [#644](#644) [#950](#950)
* **create-bestax:** make every skill example compile in a vite-ts scaffold ([6cc5fec](6cc5fec))
* **create-bestax:** name the files the overwrite prompt removes, and stop on a file path ([39b6232](39b6232)), closes [#945](#945)
* **create-bestax:** never empty a non-empty folder under -y, and validate flags first ([917f195](917f195)), closes [#950](#950) [#945](#945) [#950](#950)
* **create-bestax:** read the flags after a `--` that pnpm or bun forwards ([82112a2](82112a2)), closes [#950](#950)
* **create-bestax:** tell the optimize skill's modular build to install bulma ([4289d0a](4289d0a)), closes [#597](#597)
* **create-bestax:** warn when the icon CSS import has nowhere to go ([f7f0b64](f7f0b64)), closes [#946](#946) [#946](#946)
* **eslint-plugin:** judge Columns' gap by its own steps, and lengths as lengths ([4786c8d](4786c8d))

### Features

* **bestax-migrate:** convert the gap, position, overflow, radius and aspect-ratio helpers ([13dcf63](13dcf63))
* **bulma-ui:** add Bulma's gap helper props to every component ([#877](#877)) ([1bd4abc](1bd4abc))
* **bulma-ui:** add DateRangeInput ([50fcba7](50fcba7)), closes [#774](#774)
* **bulma-ui:** make columnGap the column gap helper on Theme ([eb2c611](eb2c611)), closes [#694](#694)
* **eslint-plugin:** check the gap helper props ([b53a749](b53a749))
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 1.14.1 🎉

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

deep-review needs-human-review Loop converged (or contested): awaiting owner review + manual merge released review-converged Deep review converged: no blocking findings, all review threads resolved, checks green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant