You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/components/date-range-picker/date-range-picker-year-view...

111 lines
3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script lang="ts">
import { DateRangePickerProvider } from '$soma/components/date-range-picker';
import { CalendarDate } from '$libs/days';
import type { HTMLAttributes } from 'svelte/elements';
// Year-grid range view (kind='year'). 3×4 decade grid + decade nav.
//
// Selection state machine (mirrors the day-grid range selection):
// - Empty (neither start nor end set): click sets startValue (and
// clears endValue).
// - Pending (start set, no end): click sets endValue. If the clicked
// year is before startValue, swap them so start <= end.
// - Complete (both set): click resets to a fresh start + clears end.
//
// Year endpoints normalise to Jan 1 for start, Dec 31 for end.
interface YearRangeViewProps extends HTMLAttributes<HTMLDivElement> {}
const { ...rest }: YearRangeViewProps = $props();
const provider = DateRangePickerProvider.require();
const startVal = $derived(provider.opts.startValue.current);
const endVal = $derived(provider.opts.endValue.current);
const placeholder = $derived(provider.opts.placeholder.current);
// Decade window: anchor on startValue or placeholder, snap to decade.
const anchorYear = $derived(startVal?.year ?? placeholder.year);
const decadeStart = $derived(anchorYear - (anchorYear % 10));
const years = $derived(Array.from({ length: 12 }, (_, i) => decadeStart + i));
function selectYear(year: number) {
const s = startVal;
const e = endVal;
const isComplete = s !== undefined && e !== undefined;
if (!s || isComplete) {
// Fresh start.
provider.opts.startValue.current = new CalendarDate(year, 1, 1);
provider.opts.endValue.current = undefined;
provider.opts.placeholder.current = new CalendarDate(year, 1, 1);
return;
}
// Pending end: set the second endpoint, swap if reversed.
const startYear = s.year;
if (year < startYear) {
provider.opts.endValue.current = new CalendarDate(startYear, 12, 31);
provider.opts.startValue.current = new CalendarDate(year, 1, 1);
} else {
provider.opts.endValue.current = new CalendarDate(year, 12, 31);
}
provider.handleRangeSelect();
}
function stepDecade(direction: -1 | 1) {
const p = placeholder;
provider.opts.placeholder.current = new CalendarDate(p.year + direction * 10, p.month, p.day);
}
function classFor(year: number): { start: boolean; end: boolean; inRange: boolean } {
const sy = startVal?.year;
const ey = endVal?.year;
if (sy === undefined) return { start: false, end: false, inRange: false };
const start = year === sy;
const end = ey !== undefined && year === ey;
const inRange =
ey !== undefined && year > Math.min(sy, ey) && year < Math.max(sy, ey);
return { start, end, inRange };
}
</script>
<div data-date-range-picker-year-view role="grid" aria-label="Select year range" {...rest}>
<div data-date-range-picker-year-view-header>
<button
type="button"
data-date-range-picker-year-view-prev
aria-label="Previous decade"
onclick={() => stepDecade(-1)}
>
‹
</button>
<span data-date-range-picker-year-view-heading>
{decadeStart} – {decadeStart + 11}
</span>
<button
type="button"
data-date-range-picker-year-view-next
aria-label="Next decade"
onclick={() => stepDecade(1)}
>
›
</button>
</div>
<div data-date-range-picker-year-view-grid>
{#each years as year (year)}
{@const c = classFor(year)}
<button
type="button"
data-date-range-picker-year-view-cell
data-range-start={c.start ? '' : undefined}
data-range-end={c.end ? '' : undefined}
data-in-range={c.inRange ? '' : undefined}
aria-pressed={c.start || c.end}
onclick={() => selectYear(year)}
>
{year}
</button>
{/each}
</div>
</div>

Powered by TurnKey Linux.