range-calendar: smart heading + per-calendar title in header

Closes incidencia points D + E:

- Heading collapses the shared year when both visible months are the
  same year: "May – June 2026" instead of "May 2026 – June 2026".
  Cross-year still renders both ends explicitly ("June 2025 – July
  2026"). Implemented in `RangeCalendarProvider.headingValue`.
- date-range-picker demo: drop the per-month title that previously
  rendered BELOW each grid (duplicate of the main heading). Instead,
  render one centered title per visible calendar INSIDE the header
  bar between the prev/next buttons. The grid below now shows just
  the weeks. A `range-header-titles` grid container splits the
  available header space equally across `month-count` titles, so
  each label sits centered over its calendar grid.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
active-uix
dev 5 months ago
parent fb47f0475b
commit 3b464ee361

@ -253,13 +253,21 @@ export class RangeCalendarProvider {
readonly headingValue = $derived.by(() => { readonly headingValue = $derived.by(() => {
const first = this.visibleMonths[0]; const first = this.visibleMonths[0];
if (!first) return ''; if (!first) return '';
const month = this.formatMonth(first.month); const firstMonth = this.formatMonth(first.month);
const year = this.formatYear(first.year); const firstYear = this.formatYear(first.year);
if (this.visibleMonths.length > 1) { if (this.visibleMonths.length > 1) {
const last = this.visibleMonths[this.visibleMonths.length - 1]; const last = this.visibleMonths[this.visibleMonths.length - 1];
return `${month} ${year} – ${this.formatMonth(last.month)} ${this.formatYear(last.year)}`; const lastMonth = this.formatMonth(last.month);
const lastYear = this.formatYear(last.year);
// Collapse the year on the left side when both months share it
// ("June – July 2026"). Cross-year stays explicit on both ends
// ("June 2025 – July 2026").
if (first.year === last.year) {
return `${firstMonth} – ${lastMonth} ${lastYear}`;
}
return `${firstMonth} ${firstYear} – ${lastMonth} ${lastYear}`;
} }
return `${month} ${year}`; return `${firstMonth} ${firstYear}`;
}); });
readonly fullCalendarLabel = $derived.by(() => { readonly fullCalendarLabel = $derived.by(() => {

@ -967,8 +967,12 @@
{#snippet calendarBody({ months, weekdays, validationMessage }: DateRangePickerCalendarSnippetProps)} {#snippet calendarBody({ months, weekdays, validationMessage }: DateRangePickerCalendarSnippetProps)}
<DateRangePicker.Header> <DateRangePicker.Header>
<DateRangePicker.PrevButton aria-label="Previous month">&lt;</DateRangePicker.PrevButton> <DateRangePicker.PrevButton aria-label="Previous month">&lt;</DateRangePicker.PrevButton>
<div data-range-calendar-header-controls> <div class="range-header-titles" data-month-count={months.length}>
<DateRangePicker.Heading /> {#each months as month (`hdr-${month.value.toString()}`)}
<div class="range-month-title" id={monthHeadingId(month.value)}>
{formatMonthYear(month.value)}
</div>
{/each}
</div> </div>
<DateRangePicker.NextButton aria-label="Next month">&gt;</DateRangePicker.NextButton> <DateRangePicker.NextButton aria-label="Next month">&gt;</DateRangePicker.NextButton>
</DateRangePicker.Header> </DateRangePicker.Header>
@ -980,11 +984,6 @@
<div class="range-months" data-month-count={months.length}> <div class="range-months" data-month-count={months.length}>
{#each months as month (month.value.toString())} {#each months as month (month.value.toString())}
<div class="range-month-panel"> <div class="range-month-panel">
{#if months.length > 1}
<div class="range-month-title" id={monthHeadingId(month.value)}>
{formatMonthYear(month.value)}
</div>
{/if}
<DateRangePicker.Grid> <DateRangePicker.Grid>
<DateRangePicker.GridHead> <DateRangePicker.GridHead>
<DateRangePicker.GridRow> <DateRangePicker.GridRow>
@ -1074,6 +1073,15 @@
min-inline-size: max-content; min-inline-size: max-content;
} }
.range-header-titles {
display: grid;
grid-auto-flow: column;
grid-auto-columns: 1fr;
gap: var(--calendar-month-gap, 36px);
flex: 1 1 auto;
min-inline-size: 0;
}
.range-month-title { .range-month-title {
color: var(--calendar-heading-color); color: var(--calendar-heading-color);
font-size: var(--calendar-heading-font-size); font-size: var(--calendar-heading-font-size);

Loading…
Cancel
Save

Powered by TurnKey Linux.