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,