From fb47f0475b976f90595f262df1e6dbafacf3ca8e Mon Sep 17 00:00:00 2001 From: dev Date: Wed, 20 May 2026 22:23:21 +0200 Subject: [PATCH] =?UTF-8?q?date-field:=20opt=20out=20of=20value=E2=86=92pl?= =?UTF-8?q?aceholder=20sync=20in=20range=20pickers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause of date-range-picker incidencia 2026-05-20 #1 (auto-paging to next month when the popup opens with a complete range): both endpoint inputs of a DateRangeField create their own DateFieldProvider sharing a single placeholder. Each provider has a `$effect` that mirrors value → placeholder so the calendar jumps to the value's month. With two endpoints, the END field's effect overrides the START's on every render and the popup auto-pages to the end's month. Fix: add an explicit `syncPlaceholderToValue?: boolean` opt on `DateFieldOpts` (default `true` — preserves single-field UX). The DateRangeField endpoint Input passes `false`; range placeholder coordination stays with the range provider. Verified in browser: value `{ start: 2026-05-31, end: 2026-06-09 }` with `placeholder = 2026-05-31` now keeps the calendar on "May 2026 – June 2026" instead of jumping to "June – July". Both endpoints render correctly with the start/end stripes. The earlier `reanchorInitialSelection` removal handled the same symptom inside the range-calendar provider for fresh selections; this commit handles the OTHER source — the field provider auto-sync on already-set values. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../date-field/date-field-provider.svelte.ts | 37 +++++++++++++++---- .../components/date-range-field-input.svelte | 5 +++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/uix/soma/components/date-field/date-field-provider.svelte.ts b/src/uix/soma/components/date-field/date-field-provider.svelte.ts index 4032bbade..061385544 100644 --- a/src/uix/soma/components/date-field/date-field-provider.svelte.ts +++ b/src/uix/soma/components/date-field/date-field-provider.svelte.ts @@ -168,7 +168,21 @@ export interface DateFieldOpts hideTimeZone: boolean; required: boolean; errorMessageId: string | undefined; - }> {} + }> { + /** + * When `true` (default) the field mirrors any `value` change back into + * `placeholder` so the calendar (or any sibling that consumes + * `placeholder`) jumps to the month of the entered value. Standalone + * date fields and single-date pickers want this. + * + * Range pickers MUST pass `false` for their two endpoint fields, because + * both fields share a single `placeholder` and would fight: the END + * field would override the START field on every render, auto-paging the + * popup to the END's month (incidencia 2026-05-20 #1). Range placeholder + * coordination lives in the range provider. + */ + syncPlaceholderToValue?: boolean; +} export class DateFieldProvider { readonly opts: DateFieldOpts; @@ -266,13 +280,20 @@ export class DateFieldProvider { target: opts.ref?.current }); } - const placeholder = untrack(() => this.opts.placeholder.current); - if (this.opts.value.current && placeholder !== this.opts.value.current) { - untrack(() => { - if (this.opts.value.current) { - this.opts.placeholder.current = this.opts.value.current; - } - }); + // Mirror value → placeholder for single-field cases. Range pickers + // opt out via `syncPlaceholderToValue: false` (incidencia 2026-05-20 + // #1) because their two endpoint fields share one placeholder and + // would fight: the end input would auto-page the popup to its own + // month on every render. + if (this.opts.syncPlaceholderToValue !== false) { + const placeholder = untrack(() => this.opts.placeholder.current); + if (this.opts.value.current && placeholder !== this.opts.value.current) { + untrack(() => { + if (this.opts.value.current) { + this.opts.placeholder.current = this.opts.value.current; + } + }); + } } }); diff --git a/src/uix/soma/components/date-range-field/components/date-range-field-input.svelte b/src/uix/soma/components/date-range-field/components/date-range-field-input.svelte index 11a36d7aa..fd579d320 100644 --- a/src/uix/soma/components/date-range-field/components/date-range-field-input.svelte +++ b/src/uix/soma/components/date-range-field/components/date-range-field-input.svelte @@ -59,6 +59,11 @@ } ), placeholder: provider.opts.placeholder, + // Range endpoints share a single placeholder owned by the range + // provider; do NOT let each endpoint mirror its own value back into + // placeholder. Otherwise the end input continuously overrides the + // start input's anchor and the popup auto-pages to the end month. + syncPlaceholderToValue: false, validate: readableActive(() => undefined), // Range-level validation lives on the parent onInvalid: readableActive(() => undefined), minValue: provider.opts.minValue,