feat(Calendar): add month/year picker modes and view switching#5981
feat(Calendar): add month/year picker modes and view switching#5981
Conversation
d181f50 to
28da0df
Compare
|
@benjamincanac what do you think about this PR? Do you like the API? There are some styles I would like to improve and nail down. But I think is mostly ready :) Let me know your thoughts! Thank you! Once we decide to move forward I will ammend PR fixing CI and fixing UI issues |
|
Thanks for the PR! I do like the API with the However, it adds lots of code since there are no primitives for this in Reka UI. @J-Michalek what do you think about this? Are you aware of such thing being added in Reka UI any time soon? |
|
Well there is an issue open for 8 months unovue/reka-ui#1933 and the activity in the repo is mild at best, but I think we should rely on RekaUI to provide these inputs... Perhaps the author of this PR would be interested in implementing in RekaUI? |
|
I’m the author of the feature request in Reka UI (unovue/reka-ui#1933), and it has already gathered meaningful community interest (19+ reactions). As mentioned above, this PR adds a fair amount of code mainly because Reka UI doesn’t provide primitives for month/year picking yet. @onmax, if you’re open to it, migrating this PR to add |
|
Thanks for the feedback. I will prepare a PR for Reka UI. @benjamincanac, should I keep the behaviour shown in the video? I am not 100% this is the best ux 🤔 |
|
I think I like it yes, it avoids having to implement popover and lets us render a Calendar only for months at the same time as selecting a month for a normal calendar. |
|
Ok, i won't bother you again 😬, once reka ui is released and this pr is ready I will mark this pr ready and i will ping you. Feel free to post any feedback though. Most of the code is ready. I am just testing it throughly :) |
4d64993 to
ae0edf7
Compare
commit: |
|
Great to see work on this! I've long missed it since version 2. Just my 2c. I think a 3x4 grid looks neater as was used in v2: https://ui2.nuxt.com/components/date-picker#datepicker |
83cbfce to
dc8123d
Compare
dc8123d to
ec30460
Compare
db211f6 to
ff305e7
Compare
9833079 to
7fc753c
Compare
|
Hi Benjamin, this PR is ready for review. A few notes before you dive in:
Let me know how to proceed :) Tested playground and docs. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7fc753c86e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds two example Vue components: CalendarMonthPickerExample.vue and CalendarYearPickerExample.vue. Extends src/runtime/components/Calendar.vue to support multi-view calendars by adding exported types CalendarType and CalendarView, new props (type, view, defaultView), emits ('update:placeholder', 'update:view'), expanded slot signatures (heading, month-cell, year-cell), view resolution and navigation/placeholder synchronization, and scaffolding for month/year rendering. Updates src/theme/calendar.ts to expose month/year grid/cell/trigger slots and expands variant/size mappings and compound variants. Documentation (calendar.md) is updated with month/year picker examples. Tests (Calendar.spec.ts) are expanded to cover type/view behaviors, slots, and emission semantics. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
src/theme/calendar.ts (1)
145-176: Reduce duplication in month/year trigger variant maps.
monthCellTriggerandyearCellTriggerare repeated with identical class logic across each color/variant branch. This doubles maintenance surface and makes future style updates easy to desync.Also applies to: 206-237
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/theme/calendar.ts` around lines 145 - 176, monthCellTrigger and yearCellTrigger class strings are duplicated across each color/variant branch; extract a small helper (e.g., buildTriggerClass(color:string, variantKind:string) or buildTriggerClasses(color:string) that returns the template string) and use it for both monthCellTrigger and yearCellTrigger in the maps for variants 'solid','outline','soft','subtle' (refer to options.theme.colors usage and the monthCellTrigger/yearCellTrigger keys); apply the same refactor to the second block noted (lines ~206-237) so both triggers consume the single source of truth for the class string.src/runtime/components/Calendar.vue (1)
558-778: Consider extracting shared month/year picker panel markup.The month/year navigation and standalone branches repeat nearly the same header/grid/cell structure. Extracting shared subcomponents/helpers would significantly reduce maintenance overhead.
Also applies to: 780-962
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Calendar.vue` around lines 558 - 778, The MonthPicker and YearPicker branches duplicate the same header/grid/cell markup; extract the shared panel pieces into reusable subcomponents (e.g., PickerPanel, PickerHeader, PickerGrid, PickerCell) and use them inside both MonthPicker and YearPicker to avoid repetition. Move shared logic/props/slots (heading slot using setView/setMonth/setYear, prev/next controls, grid rows/cols rendering, getPickerColumnAlignment, formatMonthLabel/formatYearLabel, and the v-slot props like { grid, date } ) into these new components and have MonthPicker/YearPicker pass their specific props (monthGrid/yearGrid, onMonthSelectForNavigation/onYearNavigationModelValueUpdate, MonthPickerCellTriggerComp/YearPickerCellTriggerComp, MonthPickerHeadingComp/YearPickerHeadingComp, etc.) so the duplicated header and grid rendering is centralized and reused.test/components/Calendar.spec.ts (1)
112-114: Tightenupdate:placeholderassertions to catch duplicate emits.These tests currently validate presence/payload, but duplicate emissions would still pass. Prefer asserting exact count where deterministic.
🧪 Example assertion pattern
- expect(wrapper.emitted('update:placeholder')).toBeTruthy() - expect(wrapper.emitted('update:placeholder')![0]![0]).toMatchObject({ month: 6, day: 1 }) + const placeholderEvents = wrapper.emitted('update:placeholder') ?? [] + expect(placeholderEvents).toHaveLength(1) + expect(placeholderEvents[0]?.[0]).toMatchObject({ month: 6, day: 1 })Also applies to: 130-132, 313-316, 335-338, 350-353
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/components/Calendar.spec.ts` around lines 112 - 114, The test currently only checks that wrapper.emitted('update:placeholder') exists and payload matches, which won't catch duplicate emits; update each assertion (e.g., the block using wrapper.emitted('update:placeholder') and payload checks around lines with expect(...).toBeTruthy()) to assert the exact emit count (expect(wrapper.emitted('update:placeholder')).toHaveLength(1)) before inspecting the payload (then assert emitted(...)[0][0] matches the expected { month, day }); apply this pattern to all occurrences mentioned (around the other assertions at the referenced places) so duplicate emits will fail the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@docs/app/components/content/examples/calendar/CalendarMonthPickerExample.vue`:
- Around line 56-63: The two icon-only UButton controls used for year navigation
(the one calling shiftYears(-1) and the one calling shiftYears(1)) lack
accessible labels; update those UButton instances to include descriptive
accessible text (e.g., aria-label="Previous year" and aria-label="Next year" or
use a localized string) so screen readers can identify them, and ensure the
label prop (or title) is set on both the left chevron and the right chevron
buttons to match their shiftYears(-1) and shiftYears(1) behavior.
In `@docs/content/docs/2.components/calendar.md`:
- Around line 341-345: The new example blocks using the ::component-example
wrapper (name: 'calendar-month-picker-example') trigger markdownlint MD003
heading-style warnings; fix by either adjusting the block to use proper heading
markup or, more simply, add targeted markdownlint suppression comments around
each example block (e.g., insert <!-- markdownlint-disable MD003 --> immediately
before the ::component-example block and <!-- markdownlint-enable MD003 -->
immediately after) and do the same for the other occurrence referenced (lines
351-355) so the linter is satisfied without changing content.
- Line 269: Update the sentence describing calendar view transitions to
accurately reflect behavior: change the line that currently states "Selecting a
month or year navigates back to the day view" so it instead says that selecting
a month navigates to the day view, while selecting a year navigates to the month
view first (and from there selecting a month goes to the day view). Reference
the sentence in the calendar docs heading description to ensure the month vs.
year flow is clarified.
In `@src/runtime/components/Calendar.vue`:
- Around line 220-221: The template is double-emitting update:placeholder
because calendarRootProps (from useForwardPropsEmits) already forwards
update:placeholder from DayCalendar.Root; remove the explicit
`@update`:placeholder="updatePlaceholder" listener on DayCalendar.Root so only the
forwarded event is emitted. Locate DayCalendar.Root usages that spread
calendarRootProps and remove the explicit updatePlaceholder handler (also apply
the same removal for the other occurrence referenced around the second block),
leaving calendarRootProps to handle forwarding.
- Around line 215-219: The month/year labels become stale because
useDateFormatter(code.value) captures the locale at init; update the formatter
when locale changes by adding a watch on code.value that calls
formatter.setLocale(newCode) so formatMonthLabel/formatYearLabel use the current
locale; locate useDateFormatter and formatter in Calendar.vue and add a watch(()
=> code.value, (newCode) => formatter.setLocale(newCode)) (also apply the same
change where useDateFormatter is used around lines 341-352).
---
Nitpick comments:
In `@src/runtime/components/Calendar.vue`:
- Around line 558-778: The MonthPicker and YearPicker branches duplicate the
same header/grid/cell markup; extract the shared panel pieces into reusable
subcomponents (e.g., PickerPanel, PickerHeader, PickerGrid, PickerCell) and use
them inside both MonthPicker and YearPicker to avoid repetition. Move shared
logic/props/slots (heading slot using setView/setMonth/setYear, prev/next
controls, grid rows/cols rendering, getPickerColumnAlignment,
formatMonthLabel/formatYearLabel, and the v-slot props like { grid, date } )
into these new components and have MonthPicker/YearPicker pass their specific
props (monthGrid/yearGrid,
onMonthSelectForNavigation/onYearNavigationModelValueUpdate,
MonthPickerCellTriggerComp/YearPickerCellTriggerComp,
MonthPickerHeadingComp/YearPickerHeadingComp, etc.) so the duplicated header and
grid rendering is centralized and reused.
In `@src/theme/calendar.ts`:
- Around line 145-176: monthCellTrigger and yearCellTrigger class strings are
duplicated across each color/variant branch; extract a small helper (e.g.,
buildTriggerClass(color:string, variantKind:string) or
buildTriggerClasses(color:string) that returns the template string) and use it
for both monthCellTrigger and yearCellTrigger in the maps for variants
'solid','outline','soft','subtle' (refer to options.theme.colors usage and the
monthCellTrigger/yearCellTrigger keys); apply the same refactor to the second
block noted (lines ~206-237) so both triggers consume the single source of truth
for the class string.
In `@test/components/Calendar.spec.ts`:
- Around line 112-114: The test currently only checks that
wrapper.emitted('update:placeholder') exists and payload matches, which won't
catch duplicate emits; update each assertion (e.g., the block using
wrapper.emitted('update:placeholder') and payload checks around lines with
expect(...).toBeTruthy()) to assert the exact emit count
(expect(wrapper.emitted('update:placeholder')).toHaveLength(1)) before
inspecting the payload (then assert emitted(...)[0][0] matches the expected {
month, day }); apply this pattern to all occurrences mentioned (around the other
assertions at the referenced places) so duplicate emits will fail the test.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5a5e3435-b8d2-4612-9fca-d9b292cbbdd6
⛔ Files ignored due to path filters (2)
test/components/__snapshots__/Calendar-vue.spec.ts.snapis excluded by!**/*.snaptest/components/__snapshots__/Calendar.spec.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (6)
docs/app/components/content/examples/calendar/CalendarMonthPickerExample.vuedocs/app/components/content/examples/calendar/CalendarYearPickerExample.vuedocs/content/docs/2.components/calendar.mdsrc/runtime/components/Calendar.vuesrc/theme/calendar.tstest/components/Calendar.spec.ts
docs/app/components/content/examples/calendar/CalendarMonthPickerExample.vue
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
♻️ Duplicate comments (2)
src/runtime/components/Calendar.vue (2)
218-219:⚠️ Potential issue | 🟠 MajorSync formatter locale when
codechanges at runtime.
useDateFormatter(code.value)is created once, but month/year labels continue using that formatter later. If locale switches dynamically, labels can stay stale unless the formatter locale is updated.💡 Proposed fix
const formatter = useDateFormatter(code.value) +watch(() => code.value, (newCode) => { + formatter.setLocale(newCode) +})#!/bin/bash # Verify formatter initialization and whether locale sync exists rg -n "useDateFormatter\\(|setLocale\\(|watch\\(\\(\\) => code\\.value" src/runtime/components/Calendar.vue -C2Also applies to: 341-352
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Calendar.vue` around lines 218 - 219, The date formatter created with useDateFormatter(code.value) is only initialized once so when code.value (locale) changes at runtime the formatter stays stale; update the implementation around the formatter variable (the const formatter = useDateFormatter(code.value) in Calendar.vue) to react to code changes—either by watching code.value and calling formatter.setLocale(newLocale) if the formatter exposes setLocale, or by recreating the formatter inside a watch on code.value (e.g., replace the single initialization with a watch that reassigns formatter using useDateFormatter(code.value)); ensure the same approach is applied to the other affected block around lines referenced (341-352).
220-221:⚠️ Potential issue | 🟠 MajorAvoid duplicate
update:placeholderemission in day mode.
useForwardPropsEmits(..., emits)already forwards emitted updates; keeping explicit@update:placeholder="updatePlaceholder"onDayCalendar.Rootcan emit twice for one user action.💡 Proposed fix
-const calendarRootProps = useForwardPropsEmits(reactiveOmit(props, 'type', 'view', 'defaultView', 'range', 'modelValue', 'defaultValue', 'placeholder', 'color', 'variant', 'size', 'monthControls', 'yearControls', 'class', 'ui'), emits) +const _calendarRootProps = useForwardPropsEmits( + reactiveOmit(props, 'type', 'view', 'defaultView', 'range', 'modelValue', 'defaultValue', 'placeholder', 'color', 'variant', 'size', 'monthControls', 'yearControls', 'class', 'ui'), + emits +) +const calendarRootProps = computed(() => ({ + ..._calendarRootProps.value, + 'onUpdate:placeholder': updatePlaceholder +}))- `@update`:placeholder="updatePlaceholder"#!/bin/bash # Verify possible duplicate placeholder update wiring in day view rg -n "useForwardPropsEmits|@update:placeholder|updatePlaceholder\\(|'update:placeholder'" src/runtime/components/Calendar.vue -C2Also applies to: 431-432
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Calendar.vue` around lines 220 - 221, Duplicate placeholder updates occur because useForwardPropsEmits(calendarRootProps, emits) already forwards emits and DayCalendar.Root still has an explicit `@update`:placeholder="updatePlaceholder"; remove the explicit `@update`:placeholder binding from DayCalendar.Root (and the similar binding around lines ~431-432) so only useForwardPropsEmits handles the emit, keeping calendarRootProps and the emits object intact and ensuring updatePlaceholder helper (if still referenced elsewhere) is not hooked twice.
🧹 Nitpick comments (1)
src/runtime/components/Calendar.vue (1)
576-874: Consider extracting shared month/year panel structure.Month/year panel markup is duplicated across navigation and standalone branches, which increases maintenance cost and drift risk. A shared internal subcomponent/composable for header+grid rendering would simplify future changes.
Also applies to: 689-965
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Calendar.vue` around lines 576 - 874, The month/year panel header+grid markup is duplicated between the MonthPicker and YearPicker branches (see MonthPickerHeaderComp/MonthPickerGridComp/MonthPickerCellComp and YearPickerHeaderComp/YearPickerGridComp/YearPickerCellComp usage plus helpers like pickerPanelClass, pickerHeaderStyle, pickerHeaderHeadingStyle, getPickerColumnAlignment, setView, setMonth, setYear, yearControls); extract that shared structure into a single internal component or composable (e.g., CalendarPanel) that accepts props for the heading slot/value, grid rows, cell renderers, navigation controls, aria labels and emits necessary events (update:model-value, update:placeholder) so MonthPicker/YearPicker/standalone Month branches simply render <CalendarPanel :grid="..." :date="..." ...> and forward slots/props, keeping behavior (buttons, click handlers, classes, and styles) identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/runtime/components/Calendar.vue`:
- Around line 218-219: The date formatter created with
useDateFormatter(code.value) is only initialized once so when code.value
(locale) changes at runtime the formatter stays stale; update the implementation
around the formatter variable (the const formatter =
useDateFormatter(code.value) in Calendar.vue) to react to code changes—either by
watching code.value and calling formatter.setLocale(newLocale) if the formatter
exposes setLocale, or by recreating the formatter inside a watch on code.value
(e.g., replace the single initialization with a watch that reassigns formatter
using useDateFormatter(code.value)); ensure the same approach is applied to the
other affected block around lines referenced (341-352).
- Around line 220-221: Duplicate placeholder updates occur because
useForwardPropsEmits(calendarRootProps, emits) already forwards emits and
DayCalendar.Root still has an explicit `@update`:placeholder="updatePlaceholder";
remove the explicit `@update`:placeholder binding from DayCalendar.Root (and the
similar binding around lines ~431-432) so only useForwardPropsEmits handles the
emit, keeping calendarRootProps and the emits object intact and ensuring
updatePlaceholder helper (if still referenced elsewhere) is not hooked twice.
---
Nitpick comments:
In `@src/runtime/components/Calendar.vue`:
- Around line 576-874: The month/year panel header+grid markup is duplicated
between the MonthPicker and YearPicker branches (see
MonthPickerHeaderComp/MonthPickerGridComp/MonthPickerCellComp and
YearPickerHeaderComp/YearPickerGridComp/YearPickerCellComp usage plus helpers
like pickerPanelClass, pickerHeaderStyle, pickerHeaderHeadingStyle,
getPickerColumnAlignment, setView, setMonth, setYear, yearControls); extract
that shared structure into a single internal component or composable (e.g.,
CalendarPanel) that accepts props for the heading slot/value, grid rows, cell
renderers, navigation controls, aria labels and emits necessary events
(update:model-value, update:placeholder) so MonthPicker/YearPicker/standalone
Month branches simply render <CalendarPanel :grid="..." :date="..." ...> and
forward slots/props, keeping behavior (buttons, click handlers, classes, and
styles) identical.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ab468c0c-8f73-4a93-ad60-2443c92496d4
📒 Files selected for processing (1)
src/runtime/components/Calendar.vue
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/components/Calendar.vue`:
- Around line 267-281: The current effectivePlaceholder always falls back to
today(getLocalTimeZone()) which causes MonthPicker/YearPicker to open on today
even when modelValue/defaultValue are provided; change effectivePlaceholder to
derive from value when props.placeholder is not provided by computing:
localPlaceholder.value ?? props.modelValue ?? props.defaultValue ??
today(getLocalTimeZone()); keep dayViewPlaceholder behavior as-is (it already
respects explicit placeholder/localPlaceholder), and ensure the bindings to
MonthPicker and YearPicker use this updated effectivePlaceholder (references:
localPlaceholder, effectivePlaceholder, dayViewPlaceholder, props.placeholder,
props.modelValue, props.defaultValue, MonthPicker, YearPicker).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 112db6dc-50df-4a41-aef4-73caa0ce38fc
📒 Files selected for processing (5)
docs/app/components/content/examples/calendar/CalendarMonthPickerExample.vuedocs/content/docs/2.components/calendar.mdsrc/runtime/components/Calendar.vuesrc/theme/calendar.tstest/components/Calendar.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/content/docs/2.components/calendar.md
|
@onmax I think the resolved issue is wrong! |
|
fixed |
5581f82 to
cd84b16
Compare
cd84b16 to
6959644
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/runtime/components/Calendar.vue (1)
208-212: Consider usingsetLocale()instead of recreating the formatter.Reka UI's
useDateFormatterprovides asetLocale()method specifically for updating the locale. This is more efficient than recreating the formatter instance on each change:💡 Suggested refactor
-const formatter = shallowRef(useDateFormatter(code.value)) - -watch(() => code.value, (value) => { - formatter.value = useDateFormatter(value) -}) +const formatter = useDateFormatter(code.value) + +watch(() => code.value, (value) => { + formatter.setLocale(value) +})🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Calendar.vue` around lines 208 - 212, The current code recreates the date formatter on each locale change by assigning formatter.value = useDateFormatter(value); instead use the formatter's built-in updater: keep formatter as shallowRef(useDateFormatter(code.value)) and in the watch callback call formatter.value.setLocale(value) (ensure setLocale exists on the returned object) instead of replacing the whole formatter instance to improve efficiency and preserve any internal state or subscriptions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/runtime/components/Calendar.vue`:
- Around line 208-212: The current code recreates the date formatter on each
locale change by assigning formatter.value = useDateFormatter(value); instead
use the formatter's built-in updater: keep formatter as
shallowRef(useDateFormatter(code.value)) and in the watch callback call
formatter.value.setLocale(value) (ensure setLocale exists on the returned
object) instead of replacing the whole formatter instance to improve efficiency
and preserve any internal state or subscriptions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6c23c1df-28da-43ee-8187-b64d3c7ae764
⛔ Files ignored due to path filters (2)
test/components/__snapshots__/Calendar-vue.spec.ts.snapis excluded by!**/*.snaptest/components/__snapshots__/Calendar.spec.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (6)
docs/app/components/content/examples/calendar/CalendarMonthPickerExample.vuedocs/app/components/content/examples/calendar/CalendarYearPickerExample.vuedocs/content/docs/2.components/calendar.mdsrc/runtime/components/Calendar.vuesrc/theme/calendar.tstest/components/Calendar.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/app/components/content/examples/calendar/CalendarYearPickerExample.vue
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/components/Calendar.vue`:
- Around line 619-635: The inline branch that renders <component
:is="picker.root"> is dropping root-level props by passing a hand-picked set
(pickerValueProps, placeholder, locale, dir, minValue, maxValue, disabled,
readonly, class) instead of reusing the same root prop assembly used by the
day-calendar path; fix this by using the same calendarRootProps construction
(the same prop spread used for day mode) when rendering picker.root and then
explicitly override only the value/placeholder wiring and event handlers (keep
picker.onUpdate and onPickerPlaceholderUpdate) so documented root props like as
and other root-level options are preserved across type !== 'date' modes.
- Around line 241-245: The watcher currently re-applies props.defaultView after
mount, turning it into live state; change the logic so defaultView only seeds
internalView once and is not watched thereafter. Concretely: stop watching
props.defaultView (remove it from the watcher), initialize internalView from
defaultView on mount (or only when internalView is undefined), and update the
watcher to only react to props.type and props.view so that internalView is
updated when the component is controlled (props.view changes) or when props.type
changes (in which case call getDefaultView(type, defaultView) to compute a new
seed if internalView is undefined). Ensure you reference and update the existing
watcher and the initialization for internalView and use getDefaultView(type as
CalendarType, defaultView as CalendarView | undefined) where needed.
- Around line 364-379: Remove the no-op expressions causing the linter error by
deleting the stray `code.value` lines in the functions `formatMonthLabel` and
`formatYearLabel`; leave the rest of each function intact so they continue to
call `formatter.value.custom(date.toDate(getLocalTimeZone()), {...})` and fall
back to `String(date.month)` / appropriate fallback — this removes the
unused-expression warnings from `@typescript-eslint/no-unused-expressions`
without changing reactivity (the locale sync is already handled by the watcher).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ba04acfe-5bd5-4986-bc24-479bb70b5631
📒 Files selected for processing (1)
src/runtime/components/Calendar.vue

🔗 Linked issue
Resolves #5842, resolves #3652
Related #3094
❓ Type of change
📚 Description
typeproptypepropChanges:
typeprop (date|month|year) for standalone pickersview/defaultViewprops for view state controltype="date"monthGrid,monthCell,yearGrid,yearCellmonth-cell,year-cellfor custom rendering📸 Screenshots
type="month")type="year")Cap.2026-02-04.at.14.31.40.mp4
📝 Checklist