Skip to content

feat(DateTimePicker): a date-and-time picker with presets - #578

Merged
IgorShevchik merged 19 commits into
mainfrom
feat/date-time-picker
Sep 15, 2026
Merged

IgorShevchik merged 19 commits into
mainfrom
feat/date-time-picker

Conversation

@IgorShevchik

@IgorShevchik IgorShevchik commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Linked issue

Rebuilds what #55 attempted. That branch was opened before main was re-rooted, so it shares no merge base with it — git merge-base exits 1 — and could neither rebase nor merge. It was closed and used here as a specification rather than as a base.

Follow-ups filed from this PR: #582 (native review of thirteen locales), #583 (nothing catches an empty API section).

Type of change

  • Documentation (updates to the documentation or readme)
  • Bug fix (a non-breaking change that fixes an issue)
  • Enhancement (improving an existing functionality)
  • New feature (a non-breaking change that adds functionality)
  • Chore (updates to the build process or auxiliary tools and libraries)
  • Revert (undoing a merged change — retitle this PR revert(Scope): ...)
  • Breaking change (fix or feature that would cause existing functionality to change)

Description

B24DateTimePicker picks a date and a time in one control: a calendar, then a time grid, with a preset column beside them. It renders in a B24Popover on pointer-sized screens and a B24Drawer on small ones, through the existing useDevice composable.

Public surface

  • Props: modelValue, defaultValue, open, defaultOpen, dateOnly, minuteStep, locale, placeholder, presets, hidePresets, format, color, size, disabled, icon, timeIcon, plus pass-through objects popover, drawer, calendar, input.
  • Emits: update:modelValue, change, update:open.
  • Slots: default (replaces the trigger), presets, preset, time-header.
  • Theme src/theme/date-time-picker.ts: 20 slots, color (5 values) and size (xs/sm/md/lg) variants, defaults md / air-primary.

Decisions worth a reviewer's attention

The trigger is a B24Input, not a wrapper around one. The first version wrapped a readonly input in a clickable div. axe rejected it twice: aria-allowed-attr, because aria-expanded sat on a role-less element; then nested-interactive, once a role="button" was added and the real <input> was still inside it. B24Input forwards fall-through attributes onto its <input>, so the popover's aria-haspopup / aria-expanded land on a genuine control and the wrapper is gone.

shallowRef for the value, not ref. Vue's deep unwrapping widens the DateValue union of class instances into a structural object that no longer matches the type. Measured: swapping the one word and running pnpm typecheck produces seven TS2322/TS2345 errors in this file. Date values are immutable, so there is nothing to track deeply anyway. The component carries no as any and no as unknown as DateValue.

minuteStep is clamped, not trusted. 1…30, with a non-finite value falling back to the default rather than rendering an empty or unbounded grid. Covered at five values, not one — undefined, 15, 90, 0, NaN — because a guard checked at one value is not a guard checked.

Presets resolve once per render. A preset's value may be a function so that "today" stays today across a long session; resolvedPresets calls it a single time and the test asserts the call count, so rendering and applying cannot disagree.

dateOnly drops the time rather than zeroing it. The value stays a CalendarDate, so it carries no time at all instead of an implied 00:00, and applying a preset under dateOnly discards the preset's time too.

Documentationdocs/content/docs/2.components/date-time-picker.md with five runnable examples, both playgrounds, and the page registered in docs/nuxt.config.ts and in the skill index. The scaffolder's Nuxt UI and reka-ui front-matter links were removed: reka-ui has no such component and the generated URL returns 404.

What the review found

A five-reviewer panel ran over the first four commits. Every finding below was reproduced before being acted on, and the fixes are in 02fe7e09 and bddc6ae3.

The end-of-week preset resolved to the wrong day. It was derived from startOfWeek(…).add({ days: 4 }), which reads as Friday only where the week starts on Monday. Measured: Thursday under en — this repository's own default locale — and Wednesday under ar, where it could resolve to the current day and the button would do nothing. The wrong day was already sitting in the committed snapshot, accepted because nothing asserted the weekday. The index is now anchored to en-US, so Friday is 5 everywhere.

Seven locales named the weekend, not the end of the weekja, sc, tc, th, id, ms, la — which is a different day from the one the preset picks. The same class of error was fixed for de/fr/it/br/tr during #55; it came back because the preset itself had no settled meaning. Corrected here; the remaining thirteen unreviewed locales are #582, and the replacements are the author's, not a native speaker's.

open was not a controlled prop. It was mirrored into a ref that every internal handler wrote to, so picking a date closed the picker even while the parent held the prop at true. It now reads through the prop and asks to close by emitting.

A throwing preset factory took the whole component down. presets[].value may be consumer-supplied and is called during render; an exception escaped the computed the template reads. Under SSR that rejected the page render outright, and on the client it replaced the component — working calendar included — with an empty node. One bad preset now drops out of the list with a warning.

A locale string Intl rejects threw before the picker could open. The prop feeds four Intl.DateTimeFormat constructions, one of them on the always-visible trigger, so a malformed tag was fatal on first render. It falls back to en.

The spec did not pin the clock. Calendar, InputDate and InputTime all call vi.setSystemTime; this one did not, so the preset hints wrote the day it was authored into the snapshots six times. They would have gone red the next morning.

The API section on the docs page was empty. interface DateTimePickerProps {}, and the same for slots and emits, while docs:generate reported 1100 routes with no failures. The cause was not in the component: the componentMeta transformer in docs/nuxt.config.ts rewrites the b24ui slot-prop token anywhere it appears, including where it is an object key in an expression, and the result does not parse. vue-component-meta then returns nothing for the component, silently. B24Theme and B24DashboardSearchButton were being rewritten the same way, and B24EditorDragHandle's onClick slot prop was being swallowed by the same pattern crossing a brace. Bounding it to the plain <script> block and forbidding the run from crossing a brace keeps 119 of the 125 sites it hit and drops exactly the six it was damaging. That the failure is invisible at all is #583.

Nine tests added, each checked against a mutation of the code it covers: accessibility on the time step (the first check never opened it), change, update:open, the controlled open, the resolved weekday across three locales, the throwing factory, the rejected locale, a time step opened without a value, and the defaultValue / defaultOpen seeds.

Not acted on. One reviewer read the "Inside a FormField" example as decorative, on the grounds that the component does not call useFormField itself. Measured instead: inside a B24FormField, the picker's inner input receives id="reka-popover-trigger-…" with the label's for pointing at it and aria-describedby="…-description" — the association works, through B24Input's own useFormField. disabled does not propagate, but a bare B24Input in the same disabled B24FormField does not receive it either, so that is not this component's behaviour to fix. Separately, a reviewer noted that a v-bind spread placed after individual binds can overwrite them with undefined; that ordering is the established convention at every forwarding site in the kit, so changing it here alone would make this component the odd one out.

What this does not do

  • No range mode, and no top-level min-value / max-value / is-date-disabled — those reach the calendar through the calendar pass-through prop only.
  • No segmented trigger; the trigger is readonly and opens the picker rather than accepting typed input.
  • defineModel was not used; the component keeps the explicit prop/emit pair the rest of the kit uses.

Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Local gate on bddc6ae3: lint 0, typecheck 0, pnpm test 353 files / 8049 passed / 6 skipped, docs:generate from a cold cache 1100 routes with no prerender errors and the API section populated (21 props, 4 slots, 3 emits).

🤖 Generated with Claude Code

https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc

Groundwork for rebuilding `B24DateTimePicker` on current `main`. PR #55 carried
the same component but branched before `main` was re-rooted on 2026-07-10, so it
shares no ancestor and cannot be merged or rebased; it is closed, and its design
is the specification for this rebuild.

Generated with `bitrix24-ui make component DateTimePicker`, which wrote the
component, theme, spec, docs page and the nuxt playground page, and registered
the entry in `src/runtime/types/index.ts` and `src/theme/index.ts`.

Two things the scaffolder did not do, both recorded rather than worked around:

- The `ThemeDefaults` entry was skipped silently. `cli/utils.mjs:24` looks for
  the interface in `src/runtime/composables/useComponentProps.ts` and returns
  early when it does not match, but `ThemeDefaults` now lives in
  `src/runtime/types/theme.ts` with 157 entries. So every component scaffolded
  since that move has quietly missed its entry, and
  `.github/contributing/component-structure.md:476` still tells the reader the
  CLI inserts it. Added by hand here; the CLI and the doc need their own change.
- The generated component extends `DateTimePickerRootProps` from `reka-ui`,
  which does not exist — the template assumes a primitive wrapper. Replaced with
  a minimal valid stub so the branch builds; the real component follows.

`dev:prepare`, `lint` and `typecheck` are green on this commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
Written against today's `main` rather than ported from the branch behind #55,
which shares no ancestor with it. The design is that PR's: a calendar that
hands over to an hour/minute grid, a preset column beside it, `dateOnly` to
drop the time step, a `B24Drawer` on small screens and a `B24Popover`
elsewhere, and the `default` / `presets` / `preset` / `time-header` slots.

Three things are different because the tree is.

**No `as unknown as DateValue` anywhere.** The old branch carried those casts
throughout, and #56 was filed to clean them up. They were not needed: `ref()`
deep-unwraps, which widens the `DateValue` union of class instances into a
structural type that no longer matches, and `shallowRef` does not. Date values
are immutable, so nothing is lost. That one change took the file from six type
errors to one. The last of them is `B24Calendar` typing its emit for every mode
it supports — the handler takes the wide type and narrows, rather than casting.

**The preset column caps its height with `--max-height-popup-menu`**, the token
the menus use, instead of a literal `20rem`. `.sync/PORTING.md` records that
those caps are tokens; the side effect is that
`test/utils/theme-css-compiles.spec.ts` now covers this class automatically,
since it collects exactly that shape.

**One fewer string to translate.** The old design had a `pickTime` label for the
footer when no time was chosen. The footer shows a time either way, so it falls
back to `00:00` and the key is gone — 20 locale files lighter.

Every utility the theme uses was compiled through the installed engine before
being written down, and every `--ui-*` / `--b24ui-*` variable it references was
checked to still exist.

The locale strings come from the branch behind #55. Thirteen of them are
machine-translated and still want a native reader — that is #60, which stays
open and applies here unchanged.

Icons are direct imports, not dictionary roles: the dictionary has no calendar
or clock key, and `test/utils/icon-claims.spec.ts` forbids documenting one that
is not reachable. The JSDoc names the components instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
Eleven render cases and six behaviour tests. The behaviour half is the point:
the minute grid is asserted at the default step, at a divisor of 60, above the
cap, below the floor and at `NaN`; the selected hour and minute are asserted to
be the *only* cells marked pressed; a factory preset is asserted to resolve
exactly once per render; and picking a preset is asserted to keep the time in
the normal case and to drop it under `dateOnly`.

Writing them turned up three defects, all in code written earlier today.

**The component emitted `update:open` but had no `open` prop**, so
`v-model:open` could not work — a consumer could hear the picker open and never
tell it to. `open` and `defaultOpen` are now props, which is also what lets the
spec assert the popover content rather than reach into the instance.

**Two accessibility defects, both found by `axe` rather than by reading.** The
trigger was a `div` that the popover decorates with `aria-haspopup` and
`aria-expanded`; `aria-allowed-attr` rejects those on an element with no role.
Adding `role="button"` moved the failure rather than fixing it — the wrapper
contained a real `<input>`, and `nested-interactive` rejects a control inside a
control. The wrapper is gone: `B24Input` forwards fall-through attributes onto
its `<input>`, so the readonly input *is* the trigger and the popover's ARIA
lands on a real control. The `triggerInput` theme slot went with it rather than
staying as a promise nothing keeps.

That last one is inherited from the design in #55, where the same wrapper stood.
It shipped no tests for the trigger, so nothing said.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
A `### Usage` walkthrough plus sections for `date-only`, presets, `minute-step`,
a custom trigger and use inside a `B24FormField`. The examples are real
components under `examples/`, so they are typechecked with the docs project.

The scaffolded front matter linked the page at Nuxt UI and reka-ui. Neither has
this component — `reka-ui.com/docs/components/date-time-picker` answers 404 —
so both links are gone rather than left to rot. The page follows the shape of
the other b24ui-only components: GitHub and Demo only.

Registration the scaffolder does not do, and that two guards in this repository
caught rather than letting through:

- `docs-component-registries.spec.ts` wants the slug in `pages` in
  `docs/nuxt.config.ts`;
- `skill-manifest.spec.ts` wants the component in the skill index. It went into
  the Form section beside `B24InputDate` and `B24InputTime` — my first attempt
  put it under Layout, because that table is grouped by purpose rather than
  sorted.

Both playground pages carry a colour × size matrix with `Date only` and
`Hide presets` switches, and are byte-identical to each other. The slug is
registered in both `useNavigation.ts` files.

Gate: `lint`, `typecheck`, `test` (353 files, 8031 passed, 6 skipped), and
`docs:generate` with the CI environment — 1474 routes, no prerender errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
The comment claimed the deep-unwrapping problem is "what forces
`as unknown as DateValue` casts elsewhere (#56)". Neither half held: no
such cast exists anywhere in `src/` today, and #56 was closed as
not planned when PR #55 was abandoned, so the reference points at a
decision not to act.

Replaced with the measurement: swapping `shallowRef` for `ref` and
running `pnpm typecheck` yields seven TS2322/TS2345 errors in this file,
all of the same widened-union shape.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
… found

The end-of-week preset resolved through `startOfWeek(…).add({ days: 4 })`,
which reads as Friday only where the week starts on Monday. Measured: it
landed on Thursday under `en` — this repo's own default — and on Wednesday
under `ar`, where it could resolve to the current day and do nothing. The
wrong day was already sitting in the committed snapshot. Anchoring the
weekday index to `en-US` makes Friday 5 for every locale.

Seven locales then said "weekend" rather than "end of week", which is a
different day from the one the preset picks: ja, sc, tc, th, id, ms, la.
Thirteen locales remain the author's approximations and are not claimed
as reviewed.

`open` was not a controlled prop. It was mirrored into a ref that every
internal handler wrote to, so picking a date closed the picker even while
the parent held the prop at `true`. It is now read through the prop, and
the component asks to close by emitting.

A preset's `value` factory is consumer code called during render, and an
exception escaped the computed the template reads: under SSR it rejected
the page, on the client it replaced the component and its working calendar
with an empty node. One bad preset now drops out of the list.

`locale` is a free string feeding four `Intl.DateTimeFormat` constructions,
one of them on the always-visible trigger, so a malformed tag threw before
the picker could be opened. It falls back to `en`.

The spec did not pin the clock, unlike Calendar, InputDate and InputTime,
so the preset hints wrote today's date into the snapshots six times and
would have gone red the next morning.

Nine tests added: accessibility on the time step, `change`, `update:open`,
the controlled `open`, the resolved weekday, the throwing factory, the
rejected locale, a time step opened without a value, and the `defaultValue`
/ `defaultOpen` seeds. Each was checked against a mutation of the code it
covers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
The transformer simplifies the `b24ui` slot-prop type for the API tables.
Its pattern was unbounded in two directions, and both were doing damage.

It ran over the whole SFC, so in `<script setup>` it rewrote the same token
where it is an object key in an expression. The result does not parse, and
`vue-component-meta` answers with empty Props, Slots and Emits for the
entire component — no error, no warning, just a blank API section on the
page. `B24DateTimePicker` was the only component with zero props of 135
extracted, which is how this surfaced; `B24Theme` and
`B24DashboardSearchButton` were being rewritten the same way.

The matched run could also cross a brace, so wherever the type was followed
by a function signature it swallowed the next slot prop with it —
`B24EditorDragHandle`'s `onClick` was being eaten.

Restricting it to the plain `<script>` block, where slot interfaces are
declared, and forbidding the run from crossing a brace keeps 119 of the 125
sites the old pattern hit across `src/runtime/components` and drops exactly
the six it was corrupting. Verified by rebuilding the documentation: the
four affected components now extract 21, 2, 34 and 40 props, and the
unaffected ones are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
claude and others added 11 commits September 15, 2026 07:26
Four visual defects, none of which any test or `axe` could see, because the
markup was correct throughout — only the styling never arrived.

The colour variant wrote `style-filled` to a `root` slot. That slot was
never rendered, and the popover and the drawer both teleport their content
out of the component, so it could not have reached the grid either way.
Measured in a browser: `--b24ui-background` resolved to an empty string
inside the popover, which left the selected hour and minute on
`rgba(0, 0, 0, 0)` and the active preset on the default grey border. It is
now `#0075ff` on a white glyph, and the variant sits on `content`, which is
the element both wrappers actually mount. The dead `root` slot is gone;
keeping it invites the same mistake.

There was no rule between the hours and the minutes, and the columns drifted
apart on a `min-w` instead. The rule now lives on the column itself, with
`first:` keeping it off the left edge.

The rule under the header, by contrast, should not have been there at all:
sitting inside the padding it rendered as a short line floating clear of
both edges. Removed — the columns below carry the separation.

The control that returns from the time step to the calendar showed a clock.
It goes back, so it is a `chevronLeft` now, with `backIcon` to override it
and a slot of its own for the hit area.

The regression test asserts the colour class is on the teleported content,
and goes red when the variant is moved back to `root`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
The time step's header showed only the date, so the value being edited was
the one thing it did not say. It now carries the formatted value, time
included, which is what the picker this copies puts there.

The control that opens the time step was laid out in a flex column and
stretched to the full width of the calendar, turning the whole bottom strip
into one click target: 252px of 276. `self-start` makes it the width of what
it contains, 75px.

The grid is always 00-23, but the trigger followed the locale, so under `en`
it read `2:30 PM` beside a cell marked 14 and nothing exposed a way to
change it. `hour12` now settles it, with a switch in both playgrounds and a
section in the documentation. Omitted, it still follows the locale.

Edge padding was 8px against the 16px of the design being followed, and the
preset column — which sets the height of the whole popover — ran 47px past
the bottom of the time grid, leaving a dead band under the minutes. Tighter
cards and a wider frame bring that to 27px at 16px edges.

The colour of the selected hour and minute was raised as a fourth item. It
was already the calendar's: both measure `rgb(0, 117, 255)` in the browser,
on the date step and on the time step. Left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
`DateValue` builds a `CalendarDate` from `[year, month, day]`, so a
component that picks a date *and* a time had no way to show a value in a
`::component-code` block at all — passing a timestamp fails the page with a
bare 500 and no indication of why.

`DateTimeValue` takes `[year, month, day, hour, minute]` and builds a
`CalendarDateTime`, mirroring the entry beside it.

It has to be added twice. The cast table exists in two copies, one in
`app/components/content/ComponentCode.vue` for the rendered page and one in
`server/utils/transformMDC.ts` for the raw markdown, and a cast present in
only one of them fails the other with the same unexplained 500 — which is
how this was found. Both copies now say so in a comment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
The two steps are the same control over different units and were styled
independently, so they disagreed on every state that matters.

The current hour and minute were a grey background pill, where the calendar
marks the current date with accent text and a heavier weight. Hover used
`--b24ui-background-hover` and applied to the selected cell as well, where
the calendar uses `--b24ui-background` and excludes anything already
selected. Focus drew an outline against the calendar's ring. The header was
sized by a raw token instead of `text-legend`, which is what the calendar's
own heading uses.

`timeCell` is now `cellTrigger` variant for variant, and the markers are
rendered only when true so both themes can use the same bare `data-selected`
variant. `data-now` keeps the bracket form: it is not one of Tailwind's
built-in boolean data variants, and written bare it compiles to nothing —
which is how it first went out with no effect at all.

The time step also gets a 252px floor of its own, rather than inheriting a
`min-w` from the shared container that the calendar step sized.

Measured in a browser: the current cell is now `rgb(0, 117, 255)` on no
background at weight 600, hover is `rgb(0, 117, 255)` on white, and the grid
is 252px.

The rendered matrix only ever reached the calendar step, so none of this was
under a snapshot. The time step now has one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
…the cascade

Five things, four of them found by looking at the rendered component rather
than at the code.

Hovering the current hour made the digit vanish. The current-cell rule
outranks the hover rule in Tailwind's variant order, so accent text was
being painted on an accent background: measured at `rgb(0, 117, 255)` on
`rgb(0, 117, 255)`. `not-hover` on the current-cell rule settles it; the
hovered cell now measures white on accent.

The grid was sized only by `text-label`, which is 16px, while the calendar
cell beside it is 14px — the two halves of one picker set in different type.
The size variants now carry the calendar's own scale for the cell, the
column titles and the header, step for step.

Cells were 28px squares. In the drawer, where this is hit with a thumb, that
is well under the 44px a touch target needs, and the component is unusable
on a phone. The base is now 44px and the compact desktop cell arrives at
`sm`; the size variants only ever narrow the `sm:` half, so no setting of
`size` can shrink the target. The back control, the preset cards and the
footer follow.

`color` and `size` stopped at the component: the inner calendar kept its own
defaults and stayed blue while the presets and the grid went green. Both now
cascade, bound after the spread so `v-bind` cannot overwrite them with an
`undefined` key, and overridable through `calendar`.

The explanatory comments in the template were rendered into the DOM — 22
nodes in every snapshot, a thing no other component in the kit does. Moved
onto the props they describe, where the documentation picks them up too.
The snapshots lose 140 lines.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
The tests read source, docs and generated files as text and match on literal
`\n` boundaries — front matter fences, `export default {` blocks, the
byte-for-byte `skills/index.json` comparison. With `core.autocrlf=true`, which
is the Windows default, a checkout rewrites the tree to CRLF and those checks
go red against files that are perfectly fine in the repository. Normalise the
whole tree to LF instead of the `skills/**` corner that already had to do it.

Two more failures are the filesystem itself, not the checkout, so they are
skipped on Windows next to the guards already there for the same reason:
symlinking a `node_modules` needs Developer Mode, and the case-collision case
cannot be written on a case-insensitive filesystem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every entry in the day scale was between 24px and 36px, and the picker
scale between 24px and 36px tall. All of it is under what a finger can
reliably hit, and this calendar renders inside a drawer on a phone — where
it is hit with a thumb, not a mouse.

The scale is now mobile-first: a 44px target on a touch screen, with the
compact desktop cell arriving at `sm:`. The `sm:` half is the scale exactly
as it was, so nothing changes on a pointer device — measured at 32x32 for
`md` before and after. The 0.5 margin moves behind the same breakpoint,
because at 44px it pushed seven columns past a phone's width; without it the
grid measures 358px inside a 390px viewport with no horizontal scroll.

The guard checks all four sizes, not one: a variant can only narrow the
`sm:` half now, and the test goes red if any size drops the base again.

This is what `B24DateTimePicker` sits on, so its calendar step was small
under the thumb while its own time grid was already 44px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
`@nuxtjs/mcp-toolkit` re-exports `completable` straight from the MCP SDK. With
the SDK left external, the dev bundle imported that module for side effects
only while keeping the name in its namespace object, so the server threw
`ReferenceError: completable is not defined` before it served a request — every
docs page came back as a 500. Inlining the SDK gives the re-export a binding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@IgorShevchik
IgorShevchik marked this pull request as ready for review September 15, 2026 14:03
@IgorShevchik
IgorShevchik merged commit 66c24cf into main Sep 15, 2026
2 checks passed
@IgorShevchik
IgorShevchik deleted the feat/date-time-picker branch September 15, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants