Repository navigation
fix(bulma-ui): read picker bounds and months in years 0 to 99 as written - #890
Conversation
The picker's day and month boundaries built dates with the multi-argument `Date` constructor, which reads years 0 to 99 as 1900 to 1999. A `min` or `max` in those years was misread wherever it passed through `startOfDay` or `endOfDay`, so a month picker ruled out a month a year-19 `min` only cut partway through, and a year-19 `max` failed to rule out the months after it. `startOfMonth` had the same flaw, and the day grid is built from it, so a calendar showing a year-19 month laid out the 1919 one and disabled every day against a year-19 range. `startOfDay`, `endOfDay`, `startOfMonth` and `endOfMonth` now build on the setter-based `makeDate` that the month and year grids already use, and so does the month-length clamp in `addMonths`, which read February of year 0 as the non-leap 1900. New tests pin a year-19 bound in the boundary helpers, in `isPeriodUnselectable`, on the day grid and on the month grid, plus the year-0 clamp. Each fails on the constructor-based helpers.
|
Warning Review limit reachedYou'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 41 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (11)
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. Comment |
Preview DeploymentPreview URL: https://454e0fd7.bestax.pages.dev |
There was a problem hiding this comment.
Deep review — 2 blocking · 3 advisory
| # | Severity | Area | Finding | Location |
|---|---|---|---|---|
| 1 | 🟠 Major | Correctness | Native day picker's ISO read-back still remaps years 0–99 (new Date(19, …) → 1919), while the 'month' branch beside it already uses makeDate; min/max reach the same input through the padded toIsoValue, so the bound fix is undone one layer up |
bulma-ui/src/form/DateInputBase.tsx:68 |
| 2 | 🟡 Minor | Correctness | The month-length clamp this PR fixed in addMonths has a byte-for-byte twin in segmented keyboard entry, feeding five clamps; 29 February year 0 clamps to the 28th |
bulma-ui/src/form/_pickerInternals/segmentMap.ts:156 |
| 3 | 🔵 Advisory | Correctness | parseDate is still constructor-based. The PR body's reasoning is right — the round-trip check nulls any year below 100 rather than misreading it — but the consequence is that a year-0–99 bound or value can only ever be set programmatically, never typed, so the day/month grids this PR fixes are reachable with such a year only from props |
bulma-ui/src/form/_pickerInternals/formatters.ts:144 |
| 4 | 🔵 Advisory | Robustness | toIsoDateTime does not pad the year (DateInputBase.toIsoValue does), so DateTimeInput's native round trip for a year below 1000 fails the \d{4} regex on read-back instead of misreading it. Pre-existing and outside this PR's stated scope — on the record because it is why finding 1's twin at DateTimeInputBase.tsx:62 is harder to reach |
bulma-ui/src/form/DateTimeInputBase.tsx:41 |
| 5 | 🔵 Advisory | API | The new free-floating comment scopes the change to min/max, but startOfMonth also lays out the day grid — which the commit message says and this comment does not. Imprecise rather than false; deleting the "a min or max" clause so it reads "…so a date in years 0–99 keeps its year" would cover both |
bulma-ui/src/form/_pickerInternals/dateUtils.ts:35 |
Overall: The core change is sound and well-targeted — swapping the four boundary helpers and the addMonths clamp onto the setter-based makeDate is semantically identical for years ≥ 100 (both paths go through MakeDay/MakeTime), endOfMonth's makeDate(y, m + 1, 0) handles the December wrap correctly via setFullYear's month-overflow rule, and Invalid Date / negative / out-of-range years behave exactly as before. Every new test is a genuine regression test: each one's assertion is falsified by the pre-fix expression (startOfDay → 1919-02-20, the day grid built from 1919-06-01, isPeriodUnselectable comparing a year-19 June against a 1919 min, and the year-0 February clamp returning 28). The riskiest part is not what the diff changed but what it did not: the same constructor remains in two adjacent executable paths that the fixed helpers hand off to, and finding 1 is the only place left where an early year produces a silently wrong value rather than a wrong-looking grid. Look at that one first.
Residual risk:
- Refuted — the four rewritten helpers for ordinary years.
makeDateseeds fromnew Date(2000, 0, 1), soTimeWithinDayis 0 andsetFullYear(y, m, d)reduces to the sameMakeDay/local-offset computation the constructor performs;endOfDay/endOfMonth's addedsetHours(23, 59, 59, 999)is the sameMakeTimethe old literal arguments produced. All 38src/formsuites (1636 tests) pass on the branch. - Refuted —
endOfMonthon December.makeDate(y, 12, 0)relies onMakeDay'sym = y + floor(m / 12): month 12 resolves to January ofy + 1, day 0 steps back to 31 December ofy. The pre-existingendOfMonthtests (including the non-leap February case) still pass. - Refuted —
parseDate.formatters.ts:145-152re-readsgetFullYear()/getMonth()/getDate()off the constructed date and returnsnullon any mismatch, so a parsed year below 100 is rejected, never misread. The PR body's claim checks out. - Refuted — no other remaining sites in picker source. A grep for multi-argument
new Date(across non-testbulma-ui/srcleaves only the three findings above plusformatters.ts:317,334, which build fixed 2021 reference dates to harvest weekday/month names and never see a caller's year. - Open (posted as finding 1) —
DateInputBase.fromIsoValue, day granularity: the native<input type="date">round trip. This is the one that matters, becausetoIsoValuedeliberately pads the year to four digits, so our own serialization does feed it000Y-MM-DD. - Open (posted as finding 2) —
segmentMap.daysInMonth, the twin of the clamp the diff fixed. Narrow: among years 0–99 only year 0's February length differs from its19xxremap, so the visible defect is confined to 29 February year 0. - Open (bullet, not posted) —
DateTimeInputBase.fromIsoDateTimeat line 62 carries finding 1's exact expression, but its serializer does not zero-pad the year, so reaching it needs a nativedatetime-localto hand back a000Y-…string on its own rather than echoing ours. Same one-word fix if finding 1 is taken.
Note on anchoring: both blocking findings live in files this PR does not touch, so GitHub rejects a line comment there. They are anchored on the nearest diff line in dateUtils.ts (the new boundary comment and the fixed addMonths clamp) and each names its real file and line in the body.
🏄 Clean little set-and-forget, dude — the gnarly 1900-year rip in the bounds is patched, and every new test actually wipes out on the old code, which is how you know they're real. Just two spots downstream still paddling the old board; grab
fromIsoValuebefore you call it glassy.
Review of the early-year bounds fix found two more places that build dates with the multi-argument constructor and so read years 0 to 99 as 1900 to 1999. The native day picker read its ISO value back that way, so picking 4 March 0019 committed 4 March 1919, even with a year-19 `min` and `max` reaching the input through the padded `toIsoValue`. The month branch beside it already used `makeDate`. The day branch now does too, and so does DateTimeInput's `datetime-local` read-back, which then sets the time with `setHours`. Segmented entry clamps the day with its own month-length helper, a twin of the one in `addMonths`. It read February of year 0 as February 1900, so typing 29 clamped to the 28th and a year typed on the way to four digits pulled 29 February back a day. It now builds on `makeDate` as well. The boundary comment in dateUtils no longer limits the change to `min` and `max`, since `startOfMonth` also lays out the day grid. New tests cover both read-backs and both segment clamps, and each fails on the previous head.
Preview DeploymentPreview URL: https://569946de.bestax.pages.dev |
There was a problem hiding this comment.
Deep review (verify) — 2 resolved · 0 open
| # | Severity | Area | Finding | Location |
|---|---|---|---|---|
| 1 | 🟠 Major | Correctness | Native day/datetime read-back remapped years 0–99 — fixed, resolved | bulma-ui/src/form/DateInputBase.tsx:68 |
| 2 | 🟡 Minor | Correctness | The daysInMonth twin in segmentMap was left on the multi-arg constructor — fixed, resolved |
bulma-ui/src/form/_pickerInternals/segmentMap.ts:159 |
What I checked
- #1 — the day branch of
fromIsoValue(DateInputBase.tsx:68) now callsmakeDate, matching themonthbranch beside it.DateTimeInputBase.fromIsoDateTime(DateTimeInputBase.tsx:61-62) was converted too, splitting the old 7-argument constructor intomakeDate(...)plussetHours(h, m, s, 0)— behaviourally equivalent, and the explicit0keeps milliseconds pinned, which the new assertion checks alongside the dropped-fractional-seconds path. New tests commit0019-03-04and0019-03-04T14:30:55back as year 19, and the first also assertsnative.min === "0019-01-01", so the paddedtoIsoValue→ read-back round trip is closed end to end. - #2 —
segmentMap.ts:159-160builds on the now-importedmakeDate(line 15), so all five consumers — the month increment (189), the day-increment wrap modulus (194), and theyear/month/daydigit writes (260, 272, 283) — see February of year 0 as 29 days. The three new assertions pin the increment (28 Feb year 0 → the 29th), the day write (29holds), and a year-0 digit write off 29 Feb 2024.
Tests run: the four date suites (DateInput, DateTimeInput, segmentMap, dateUtils) — 314 passed; -t "year below 100" — 13 passed. I could not re-run the suites against the pre-fix source (reverting the three files was not permitted in this sandbox), so the "fails on previous head" claim rests on the ECMAScript semantics the findings cited (new Date(19, …) → 1919; 1900 is not a leap year while year 0 is) plus the year-0 and year-19 assertions in the tests themselves, which cannot pass through the old constructor.
Overall: this pass settled the two open threads and reviewed no commits. Both findings are genuinely fixed at the sites named, with tests that pin the exact boundaries, and the only non-mechanical edit — the fromIsoDateTime split — preserves the time-of-day and millisecond behaviour the surrounding tests already cover. Nothing is left open; a human reviewing this should focus on whether the deliberate parseDate exemption (a year below 100 becomes null), called out in the PR body, is the behaviour they want for typed text input.
Residual risk: verify-pass scope — the ways the early-year class could still occur were enumerated in the residual-risk section of the prior review and are not re-opened here. Of what that pass flagged, both executable gaps are now closed; the one remaining acknowledged path is the round-trip check in parseDate, which fails closed to null rather than misreading, and is documented as intentional in the PR body.
🏄 Two gnarly little 1900-year riptides got patched clean, brah — every early-year date now rides its own wave from the native input all the way through segment typing. Threads closed, tests green, this one is good to paddle out.
📸 Story screenshots at handoff —
|
`parseDate` was the last picker path still building dates with the multi-argument constructor. Its round-trip check turned a year below 100 into null rather than misreading it, but the `YYYY` token displays year 19 as `0019`, so the text the field shows for such a value could not be parsed back, and typing it free-form was refused. It now builds on `makeDate` and sets the time with `setHours`, keeping the round-trip check that rejects dates like 30 February. DateTimeInput's `toIsoDateTime` did not pad the year, unlike DateInput's `toIsoValue`, so a year below 1000 gave the native `datetime-local` input an invalid value, min and max, and it showed nothing. It now pads to four digits, which the inline form value shares. Both new tests fail on the previous head.
Preview DeploymentPreview URL: https://c30b9850.bestax.pages.dev |
|
Every finding from the reviews, fixed or answered:
Both new tests fail on 306589c. |
|
deep-review: fresh The advisories from the last review are fixed or answered in the comment above; this reviews 5bfaf3c. |
There was a problem hiding this comment.
Deep review — 0 blocking · 3 advisory
| # | Severity | Area | Finding | Location |
|---|---|---|---|---|
| 1 | 🔵 Advisory | Robustness | Year 0 still cannot reach the native inputs: both ISO builders now emit 0000-01-01…, and the HTML valid-date grammar requires year > 0, so a year-0 value/min/max is silently dropped by <input type="date"> / datetime-local. Not a regression (the unpadded 0-01-01… was invalid too), and year 0 is only ever transient in segmented typing, which does not render the native input — but the helper-level tests in this PR pin year 0, so the asymmetry is worth recording |
bulma-ui/src/form/DateTimeInputBase.tsx:43 |
| 2 | 🔵 Advisory | Robustness | Years above 9999 are the mirror hole: padStart(4, "0") does not truncate, so toIsoDateTime/toIsoValue emit a 5-digit year that the anchored ^(\d{4})- read-back regexes cannot match, and a native pick in such a year commits null. Pre-existing on both sides of the round trip and untouched here |
bulma-ui/src/form/DateTimeInputBase.tsx:54 |
| 3 | 🔵 Advisory | Robustness | Negative (BCE) years: String(-5).padStart(4, "0") → 00-5, an invalid native value, so the bound is ignored rather than enforced — again the same outcome as before the padding. Adjacent to this: with an early focused year and no min, the default year window in Calendar is windowYear - 100, so a year-19 picker lists years down to -81, and makeDate builds them happily. Untouched file, and the no-min/max case only |
bulma-ui/src/form/_pickerInternals/Calendar.tsx:429 |
Overall: Sound, and now complete for the failure class it names. Every date-bearing construction in bulma-ui/src/form is off the multi-argument Date constructor: a grep of the tree leaves only parseTime, TimeInputBase.fromIsoTime (both anchored on the current year, so the 0–99 remap is unreachable), the fixed 2021 anchors in getDayNames/getMonthNames, and the new Date(2000, 0, 1) base inside makeDate. The two non-mechanical edits are the riskiest part and both check out: splitting parseDate into makeDate(...) + setHours(h, m, s, 0) is behaviourally identical to the old 7-argument call for every year ≥ 100 — including the day-overflow (2024-02-30 → null), spring-forward (2024-03-10 02:30 → 03:30) and whole-day-skip (Pacific/Apia 2011-12-30 → null) cases, because the round-trip guard is unchanged and both paths resolve the same local time — and endOfMonth with makeDate(y, m + 1, 0) wraps December correctly through the month-overflow rule of setFullYear (setFullYear(19, 12, 0) → 31 Dec year 19). A human should look first at advisory 1: the helper tests here treat year 0 as in scope, while the native input path can still only represent years 1–9999.
Residual risk:
- Other picker paths that lay out early years — refuted.
buildMonthGridgoes throughstartOfMonth/addDays(setters), the month grid throughmakeDate(focusedYear, m), the year grid throughmakeDate(year)andsetFullYear, and the header step throughaddMonths/addYears, whose clamp this PR moved ontomakeDate. TheprevDisabled/nextDisabledcomparisons inCalendarare made againststartOfDay(min)/startOfDay(max), so they are fixed by the same diff. - Segmented keyboard entry through an early year — refuted. The
yeardigit write usesnext.setFullYear(yr), and themonth/day/increment clamps all route through the now-fixeddaysInMonth; the three newsegmentMapassertions pin February of year 0 at 29 days for the increment, the day write and a year-0 digit write. - A displayed early-year value that cannot be typed back — refuted.
YYYYrenders year 19 as0019andparseDate("0019-03-04 14:30", …)now returns year 19, whileparseDate("0019-02-29")still returnsnull(19 is not a leap year), so the round-trip guard is intact.YYis unaffected — it maps into the 2000s before any date is built. - Native round trip for years 1–999 — refuted end to end:
native.min === "0019-01-01"plus a0019-03-04change event committing year 19 forDateInput, and"0019-03-04T14:30"withnative.min === "0019-01-01T09:00"forDateTimeInput. - Open: years 0, above 9999, and negative years on the native path (advisories 1–3). All three are limits of the HTML value grammar or of the fixed-width read-back regexes rather than year remapping, and none is a regression from this diff.
- Verification note: the three source files could not be reverted in this sandbox, so the claim that the new tests fail on main rests on the ECMAScript semantics those tests encode (
new Date(19, …)→ 1919; year 0 is a leap year while 1900 is not; an unpadded19-03-04T14:30is not a validdatetime-localvalue) plus assertions that cannot hold through the old constructor. Run here on the PR head: the six date suites — 462 passed; the wholesrc/formtree with coverage — 1642 passed, withdateUtils.tsandsegmentMap.tsat 100% statements and branches andsrc/formoverall at 99.73% / 99.35%;typecheck:testsclean; prettier clean on all eleven changed files. No public API moved —parseDateis internal — so no docs, story orskills/update is owed.
🏄 Three commits of patient paddling and the early-year swell is fully ridden — every
new Date(19, …)trap in the picker is off the reef, the new tests actually bite, and the only water left is the year-0 and five-digit shorebreak that HTML itself will not let you surf. Clean ride, good to go.
|
On the latest review's findings, all answered with no code change:
|
|
deep-review: fresh Main is merged in, so this review posts every finding, advisory included, as its own thread. It reviews ddaa7e6. |
Preview DeploymentPreview URL: https://19ce7e49.bestax.pages.dev |
There was a problem hiding this comment.
Deep review — 1 blocking · 2 advisory
| # | Severity | Area | Finding | Location |
|---|---|---|---|---|
| 1 | 🟡 Minor | Correctness | PR body describes only the first of three commits, and its parseDate paragraph is now the opposite of the code: a year below 100 typed into the field parses rather than becoming null |
bulma-ui/src/form/DateInputBase.tsx:68 (PR body — no line of its own) |
| 2 | 🔵 Advisory | Robustness | Year 0 cannot reach either native input: 0000-… fails HTML's "year > 0" rule, while the helpers this PR tests pin year 0 |
bulma-ui/src/form/DateTimeInputBase.tsx:43 |
| 3 | 🔵 Advisory | Robustness | The mirror hole — a 5-digit year serializes fine but the \d{4} read-back rejects it (native pick commits null); a negative year emits 00-5 and the bound is ignored |
bulma-ui/src/form/DateTimeInputBase.tsx:62 |
Overall: the change is sound and, as of the third commit, complete for the failure class it names. Every date-bearing construction in bulma-ui/src/form is now off the multi-argument Date constructor — a grep of non-test source leaves only parseTime / TimeInputBase.fromIsoTime (anchored on the current year, so the 0–99 remap is unreachable), the fixed 2021 anchors in getDayNames/getMonthNames, and makeDate's own new Date(2000, 0, 1) seed. The two non-mechanical edits both check out: splitting parseDate and fromIsoDateTime into makeDate(…) + setHours(h, m, s, 0) is behaviourally identical to the old 7-argument calls for every year ≥ 100, because makeDate seeds at local midnight so TimeWithinDay is 0 and setFullYear reduces to the same MakeDay, and the explicit trailing 0 keeps milliseconds pinned; endOfMonth's makeDate(y, m + 1, 0) wraps December through setFullYear's month-overflow rule. The riskiest thing left is not in the code — it is that the PR body now tells a reviewer the one public behaviour change (free-text entry of 0019-03-04 committing year 19 instead of null) did not happen. Look at finding 1 first and decide that change on purpose.
Empirically verified here on ddaa7e68: all 38 src/form suites, 1678 tests passed; with coverage, dateUtils.ts and segmentMap.ts at 100% statements/branches/functions/lines, DateTimeInputBase.tsx 100% statements, formatters.ts 99.4%, DateInputBase.tsx 100% lines — no coverage gap in any of the new code. No public export moved (parseDate, makeDate and daysInMonth are all internal; src/index.ts is untouched), so no story, API page or skills/ update is owed.
Residual risk:
- Native day and datetime round trip for years 1–999 — refuted end to end, not just by reading.
DateInput:native.min === "0019-01-01"and a0019-03-04change event commits year 19.DateTimeInput:native.value === "0019-03-04T14:30",native.min === "0019-01-01T09:00", and0019-03-04T14:30:55commits[19, 2, 4, 14, 30, 55, 0]. yeargranularity on the native path — refuted as unreachable, which is whyfromIsoValue's missingyearbranch is not a finding.DateInputBase.tsx:323-325gateshasNativeInputonisDayGranularity || (granularity === 'month' && …), so a year picker never renders a native control howevermobileNativeis set, and the existing test atDateInput.test.tsx:1667asserts exactly that.- Grid layout and keyboard navigation in an early year — refuted.
buildMonthGridgoes through the now-fixedstartOfMonth+addDays, the month grid throughmakeDate(focusedYear, m), the year grid throughmakeDate(year)/setFullYear, the header step throughaddMonths/addYears(whose clamp this PR moved ontomakeDate), andprevDisabled/nextDisabledcompare againststartOfDay(min)/startOfDay(max). The newCalendartests pin a year-19 day grid (10…20 enabled) and a year-19 month grid. - Segmented keyboard entry passing through an early year — refuted. The
yearwrite issetFullYear, and the month/day/increment clamps all route through the fixeddaysInMonth; three new assertions pin February of year 0 at 29 days for the increment, the day write and a year-0 digit write. - DST-sensitive paths through the new
makeDate+setHourssplit — refuted by the ECMAScriptUTC(t)disambiguation rule: for a skipped local time the pre-transition offset is used, which moves the result forward, somakeDatecan never land on the previous local day andsetHourscan never write the time onto the wrong date. The existing spring-forward, fall-back and skipped-day cases informatters.test.tsanddateUtils.test.tsstill pass. - Open, not posted as a finding:
makeDateseeds fromnew Date(2000, 0, 1)and never callssetHours(0, 0, 0, 0), so it is correct only while that seed is exactly local midnight. I could find no IANA zone that skips 2000-01-01T00:00, andmakeDatepredates this PR (#866) — but this PR routesstartOfDay,startOfMonth,endOfDay,endOfMonthandparseDatethrough it, which is what makes the seed load-bearing for the library's normalization primitives rather than for two grid builders. A one-lined.setHours(0, 0, 0, 0)would remove the assumption. - Open (findings 2 and 3): years 0, above 9999, and negative years on the native path. All three are limits of the HTML value grammar or of the fixed-width read-back regexes rather than year remapping, and none is a regression from this diff.
- Verification note: reverting the five source files to
836e20b5to re-run the new tests against pre-fix code was not permitted in this sandbox, so the "each fails on main" claim rests on the ECMAScript semantics those tests encode (new Date(19, …)→ 1919; year 0 is a leap year while 1900 is not; an unpadded19-03-04T14:30is not a validdatetime-localvalue) — assertions that cannot hold through the old constructor.
🏄 Three commits deep and the early-year swell is fully ridden, brah — every
new Date(19, …)reef break in the picker is cleared, coverage is glassy at 100% on both helper files, and the new tests actually bite. Only thing out of trim is the write-up on the back of the board: it still says you never paddled out forparseDate, and you did. Tidy that caption and this one is good to go.
HTML allows a date, month or datetime-local value a year of four or more digits, and toIsoValue and toIsoDateTime pad without truncating, so they write year 10000 as 10000-01-01. The read-back patterns took exactly four digits, so a native pick in such a year committed null instead of the date. They now take four or more.
|
deep-review: verify Every open thread has a reply: fixed, with the commit, or refuted with a reason. This settles them on e4e0466. |
Preview DeploymentPreview URL: https://c1bdf6ea.bestax.pages.dev |
There was a problem hiding this comment.
Deep review (verify) — 3 resolved · 0 open
| # | Thread | Outcome | Location |
|---|---|---|---|
| 1 | PR body contradicted the code it described | ✅ Verified fixed | bulma-ui/src/form/DateInputBase.tsx:71 (body finding, no line of its own) |
| 2 | Year 0 cannot reach either native input (🔵 Advisory) | ✅ Reason accepted | bulma-ui/src/form/DateTimeInputBase.tsx:43 |
| 3 | Years outside 1–9999 fall out of the native round trip (🔵 Advisory) | ✅ Verified fixed + reason accepted | bulma-ui/src/form/DateTimeInputBase.tsx:63 |
What I checked
- Thread 1 — the rewritten body no longer says
parseDatewas left alone; it namesparseDateas the one user-visible change to free-text entry, and lists the sites the later commits touched (daysInMonth, both native read-backs with their four-or-more-digit years, and thetoIsoDateTimepadding). - Thread 2 — refuted by the PR author (live role
admin): the HTML date grammar admits no year at or below zero, so there is no alternative value the serializer could write, and the behaviour choice is tracked in #902. That issue exists, is open, and names exactly this. The reason holds. - Thread 3 — the five-digit half is genuinely fixed in
e4e04660:fromIsoDateTime(DateTimeInputBase.tsx:59) and bothfromIsoValuebranches (DateInputBase.tsx:66,69) now match a year of four or more digits, with tests round-tripping a year-10000 native pick through the date, month anddatetime-localinputs. The negative-year row and the untouchedCalendardefault year window are accepted as the same product decision tracked in #902. - Ran the picker suites —
DateInput,DateInput.styles,DateTimeInput,dateUtils,formatters,segmentMap: 453 tests, all passing.
Overall: this pass settled threads and reviewed no commits. All three open threads are now resolved — one PR-body fix, one code fix verified against its tests, and two advisory limitations accepted as a deliberate product decision tracked in #902. Nothing of mine is left open; a reader who wants the current code reviewed afresh should ask for a fresh pass.
Residual risk: out of scope for a verify pass — no new findings were sought or raised. The one risk the settled threads leave standing is already on the record in #902: years at or below zero still cannot be carried by the native inputs, and the Calendar default year list and the YYYY token have no defined behaviour there.
🏄 Three threads paddled in clean — one patched, one coded, two waved through with a real reason and an issue number to back it. No chop left on the water; this one is good to go.
## [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))
|
🎉 This PR is included in version 5.26.3 🎉 The release is available on: Your semantic-release bot 📦🚀 |
# [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))
|
🎉 This PR is included in version 2.25.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
## [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))
|
🎉 This PR is included in version 4.2.13 🎉 The release is available on: Your semantic-release bot 📦🚀 |
## [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))
|
🎉 This PR is included in version 1.14.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
The picker's date helpers built dates with the multi-argument
Dateconstructor, which reads years 0 to 99 as 1900 to 1999. #866 added a setter-basedmakeDatefor the month and year grids; this moves the sites below onto it.startOfDayandendOfDay, which normalizeminandmax, so a bound in those years was misread.startOfMonthandendOfMonth, the same bug in the same file:startOfMonthlays out the day grid, so a year-19 month drew 1919 and disabled every day, and month keyboard navigation compares against it.addMonths, which read February of year 0 as February 1900, not a leap year, and its twindaysInMonthin segmented typing.fromIsoValueandfromIsoDateTime, so a native date pick in year 19 committed 1919. They also take a year of four or more digits now, as HTML allows, so a pick past 9999 commits that date instead ofnull.toIsoDateTime, which didn't pad the year, so a year below 1000 gavedatetime-localan invalid value,min, andmax. It pads to four digits now, astoIsoValuealready did.parseDate, the pickers' defaultparse. The field shows year 19 as0019, and the old round-trip check turned that intonull, so the field couldn't read its own text back. This is the one change a user sees in free-text entry: a typed year below 100 now parses to that year, and dates like 30 February are still rejected.New tests cover each of these. Year 0 and earlier still don't fit the native inputs, which is a product decision tracked in #902.
pnpm allpasses locally.