|
|
|
|
@ -1,97 +1,71 @@
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
import { DatePickerProvider } from '$soma/components/date-picker';
|
|
|
|
|
import { getActiveUix } from '$active-uix';
|
|
|
|
|
import { CalendarDate } from '$libs/days';
|
|
|
|
|
import { YearGrid } from '../year-grid';
|
|
|
|
|
import type { YearValue, YearPlaceholder } from '$soma/components/year-grid';
|
|
|
|
|
import type { YearGridProviderSnippetProps } from '../year-grid';
|
|
|
|
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
|
|
|
|
|
|
|
|
// Year-grid view for `kind='year'`. Renders a 3×4 decade grid centred
|
|
|
|
|
// on the placeholder year. Click on a year sets the picker's value to
|
|
|
|
|
// January 1 of that year and triggers handleDateSelect (closes the
|
|
|
|
|
// popover when closeOnDateSelect is true and mode is inline).
|
|
|
|
|
//
|
|
|
|
|
// Decade range: the anchor year's decade plus the previous and next
|
|
|
|
|
// years to fill 12 cells. Example for 2026 → 2020..2031 padded so the
|
|
|
|
|
// row starts on a decade boundary.
|
|
|
|
|
// Year-grid view for `kind='year'`. Internally renders the standalone
|
|
|
|
|
// YearGrid primitive, bridging its `{year}` value to the
|
|
|
|
|
// DatePickerProvider's CalendarDate value. Click on a year sets the
|
|
|
|
|
// picker's value to January 1 of that year and triggers handleDateSelect.
|
|
|
|
|
interface YearViewProps extends HTMLAttributes<HTMLDivElement> {}
|
|
|
|
|
|
|
|
|
|
const { ...rest }: YearViewProps = $props();
|
|
|
|
|
// View is a thin bridge that reads its state from the DatePickerProvider
|
|
|
|
|
// context. It accepts no extra props from consumers — the demo just
|
|
|
|
|
// renders `<DatePicker.YearView />` without arguments. Bind $props()
|
|
|
|
|
// to silence Svelte's mandatory props declaration check.
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
|
|
const _props: YearViewProps = $props();
|
|
|
|
|
|
|
|
|
|
const uix = getActiveUix();
|
|
|
|
|
void uix;
|
|
|
|
|
const provider = DatePickerProvider.require();
|
|
|
|
|
|
|
|
|
|
// Anchor year: the value's year if any, otherwise the placeholder's.
|
|
|
|
|
const anchorYear = $derived(
|
|
|
|
|
provider.opts.value.current?.year ?? provider.opts.placeholder.current.year
|
|
|
|
|
);
|
|
|
|
|
const anchor = $derived(provider.opts.value.current ?? provider.opts.placeholder.current);
|
|
|
|
|
|
|
|
|
|
// Decade window: 12 years starting at the previous decade boundary.
|
|
|
|
|
// E.g. anchor=2026 → start=2020 → years 2020..2031.
|
|
|
|
|
const decadeStart = $derived(anchorYear - (anchorYear % 10));
|
|
|
|
|
const years = $derived(Array.from({ length: 12 }, (_, i) => decadeStart + i));
|
|
|
|
|
const yearValue = $derived<YearValue | undefined>(
|
|
|
|
|
provider.opts.value.current ? { year: provider.opts.value.current.year } : undefined
|
|
|
|
|
);
|
|
|
|
|
const yearPlaceholder = $derived<YearPlaceholder>({ year: anchor.year });
|
|
|
|
|
|
|
|
|
|
function selectYear(year: number) {
|
|
|
|
|
const current = provider.opts.value.current ?? provider.opts.placeholder.current;
|
|
|
|
|
// For kind='year', only the year matters — keep month=1, day=1.
|
|
|
|
|
// Down-stream consumers see the value's year via `.year`.
|
|
|
|
|
const next = new CalendarDate(year, 1, 1);
|
|
|
|
|
provider.opts.value.current = next;
|
|
|
|
|
provider.opts.placeholder.current = next;
|
|
|
|
|
function onValueChange(next: YearValue | undefined): void {
|
|
|
|
|
if (!next) return;
|
|
|
|
|
// For kind='year' only the year matters — keep month=1, day=1.
|
|
|
|
|
const date = new CalendarDate(next.year, 1, 1);
|
|
|
|
|
provider.opts.value.current = date;
|
|
|
|
|
provider.opts.placeholder.current = date;
|
|
|
|
|
provider.handleDateSelect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stepDecade(direction: -1 | 1) {
|
|
|
|
|
function onPlaceholderChange(next: YearPlaceholder): void {
|
|
|
|
|
const placeholder = provider.opts.placeholder.current;
|
|
|
|
|
provider.opts.placeholder.current = new CalendarDate(
|
|
|
|
|
placeholder.year + direction * 10,
|
|
|
|
|
next.year,
|
|
|
|
|
placeholder.month,
|
|
|
|
|
placeholder.day
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isSelected(year: number): boolean {
|
|
|
|
|
return provider.opts.value.current?.year === year;
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
data-date-picker-year-view
|
|
|
|
|
role="grid"
|
|
|
|
|
aria-label="Select year"
|
|
|
|
|
{...rest}
|
|
|
|
|
<YearGrid
|
|
|
|
|
value={yearValue}
|
|
|
|
|
placeholder={yearPlaceholder}
|
|
|
|
|
{onValueChange}
|
|
|
|
|
{onPlaceholderChange}
|
|
|
|
|
locale={provider.opts.locale.current}
|
|
|
|
|
disabled={provider.opts.disabled.current}
|
|
|
|
|
readonly={provider.opts.readonly.current}
|
|
|
|
|
>
|
|
|
|
|
<div data-date-picker-year-view-header>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
data-date-picker-year-view-prev
|
|
|
|
|
aria-label="Previous decade"
|
|
|
|
|
onclick={() => stepDecade(-1)}
|
|
|
|
|
>
|
|
|
|
|
‹
|
|
|
|
|
</button>
|
|
|
|
|
<span data-date-picker-year-view-heading>
|
|
|
|
|
{decadeStart} – {decadeStart + 11}
|
|
|
|
|
</span>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
data-date-picker-year-view-next
|
|
|
|
|
aria-label="Next decade"
|
|
|
|
|
onclick={() => stepDecade(1)}
|
|
|
|
|
>
|
|
|
|
|
›
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div data-date-picker-year-view-grid>
|
|
|
|
|
{#each years as year (year)}
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
data-date-picker-year-view-cell
|
|
|
|
|
data-selected={isSelected(year) ? '' : undefined}
|
|
|
|
|
aria-pressed={isSelected(year)}
|
|
|
|
|
onclick={() => selectYear(year)}
|
|
|
|
|
>
|
|
|
|
|
{year}
|
|
|
|
|
</button>
|
|
|
|
|
{/each}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{#snippet children({ years }: YearGridProviderSnippetProps)}
|
|
|
|
|
<YearGrid.Header>
|
|
|
|
|
<YearGrid.PrevButton><</YearGrid.PrevButton>
|
|
|
|
|
<YearGrid.Heading />
|
|
|
|
|
<YearGrid.NextButton>></YearGrid.NextButton>
|
|
|
|
|
</YearGrid.Header>
|
|
|
|
|
<YearGrid.Grid>
|
|
|
|
|
{#each years as year (year)}
|
|
|
|
|
<YearGrid.Cell {year} />
|
|
|
|
|
{/each}
|
|
|
|
|
</YearGrid.Grid>
|
|
|
|
|
{/snippet}
|
|
|
|
|
</YearGrid>
|
|
|
|
|
|