From 7a85ea59c2a3168965905204e3972e4678510582 Mon Sep 17 00:00:00 2001 From: dev Date: Sat, 16 May 2026 13:40:00 +0200 Subject: [PATCH] Align Soma public wrappers with providers --- continue.md | 30 ++++++++++++-- src/uix/contracts.test.ts | 40 +++++++++++++++++++ .../color-picker-provider.svelte.test.ts | 35 +++++++++++++++- .../color-picker-provider.svelte.ts | 16 ++++++-- .../components/color-picker-area.svelte | 11 +++-- .../date-field/components/date-field.svelte | 15 +++++-- .../date-field-provider.svelte.test.ts | 1 + .../date-field/date-field-provider.svelte.ts | 18 ++++++--- .../date-picker/components/date-picker.svelte | 12 ++---- src/uix/soma/components/date-picker/types.ts | 6 +-- .../components/date-range-field-input.svelte | 1 + .../components/date-range-picker.svelte | 11 ++--- .../components/date-range-picker/types.ts | 6 +-- .../time-field/components/time-field.svelte | 19 +++++++-- .../time-picker/components/time-picker.svelte | 11 ++--- src/uix/soma/components/time-picker/types.ts | 9 +++-- .../components/time-range-picker.svelte | 11 ++--- .../components/time-range-picker/types.ts | 7 ++-- 18 files changed, 188 insertions(+), 71 deletions(-) diff --git a/continue.md b/continue.md index 5dc1f58b5..a16afde9f 100644 --- a/continue.md +++ b/continue.md @@ -25,11 +25,14 @@ Arranque rapido para mañana: - Sema queda protegido contra listeners globales nativos y `console.*`. - `ScrollLock` de Soma inyecta `ActiveDom` hacia `BodyScrollLock`. - Lo primero para continuar: - 1. Hacer un barrido de wrappers publicos `.svelte` frente a providers para - detectar props no reenviadas, bindables incompletos, snippets mal - tipados o defaults divergentes. + 1. Cerrado el primer barrido de wrappers publicos `.svelte` frente a + providers. Si se retoma esta linea, continuar con validacion navegador + de rutas `/uix/components/*`, no repetir el barrido estatico salvo que + cambien wrappers. 2. Decidir si el directorio vacio `src/uix/soma/components/avatar/` se borra o se deja como placeholder documentado. Hoy Avatar es `eidos` scope. + Decidido: no hay accion versionable; solo existe un directorio local + vacio (`components/`) y Git no lo registra. No crear placeholder Soma. 3. Si se sigue con Sium: abordar P0 de integridad (`isPlainObjectRecord`, `email`, `regex` con flags mutables, doc de `ctx.rootValue`). 4. Mantener fuera de commits los logs sueltos (`.codex-vite-*`, @@ -37,6 +40,27 @@ Arranque rapido para mañana: Actualizacion 2026-05-16: +- Barrido de wrappers publicos Soma frente a providers cerrado: + - `DateField.Provider` y `TimeField.Provider` vuelven a materializar su + root publico por defecto (`
`) y aceptan `ref` / + `restProps`, coherente con su morfo (`kind: public`, + `defaultElement: 'div'`). + - `DateField` ya respeta la prop `dir`; la direccion efectiva se pasa al + provider y a la navegacion de segmentos en vez de ignorarse y leer solo + `soma.prefs`. + - `DatePicker`, `DateRangePicker`, `TimePicker` y `TimeRangePicker` + mantienen root virtual: sus props root ya no anuncian `PrimitiveDivAttrs` + ni `child` con `props: {}`. + - `ColorPicker.Area` ya aplica de verdad los overrides locales + `xChannel` / `yChannel`; antes los tipos los exponian pero el wrapper los + descartaba. + - Guardias nuevas en `src/uix/contracts.test.ts` para roots publicos + Date/Time Field y roots virtuales picker. + - Validado: `npx vitest run src/uix/contracts.test.ts` + tests focales de + date/time pickers/fields -> 52 tests OK; `color-picker-provider` -> 5 + tests OK; `npm run check` -> 0 errores / 0 warnings; `npm run test` -> + 233 archivos, 2251 tests OK. + - Soma queda en estado funcionalmente cubierto a nivel provider/runtime: `npm run check` -> 0 errores / 0 warnings, `npm run test` -> 233 archivos, 2242 tests OK, y la guardia de `*-provider.svelte.ts` sin test directo diff --git a/src/uix/contracts.test.ts b/src/uix/contracts.test.ts index c7931a306..7debf8eb1 100644 --- a/src/uix/contracts.test.ts +++ b/src/uix/contracts.test.ts @@ -347,6 +347,46 @@ describe('UIX layer contracts', () => { expect(violations).toEqual([]); }); + it('guards Date/Time field roots from swallowing provider DOM attrs', () => { + for (const dir of ['date-field', 'time-field']) { + const source = readFileSync( + join(HERE, 'soma', 'components', dir, 'components', `${dir}.svelte`), + 'utf8' + ); + + expect(source, dir).toContain('ref = $bindable(null)'); + expect(source, dir).toContain('...restProps'); + expect(source, dir).toContain('const mergedProps'); + expect(source, dir).toContain('
'); + expect(source, dir).not.toContain('child({ props: {} })'); + } + }); + + it('guards virtual picker roots from advertising DOM attrs', () => { + const roots = [ + ['date-picker', 'DatePickerProviderProps'], + ['date-range-picker', 'DateRangePickerProviderProps'], + ['time-picker', 'TimePickerProviderProps'], + ['time-range-picker', 'TimeRangePickerProviderProps'] + ] as const; + + for (const [dir, typeName] of roots) { + const types = readFileSync(join(HERE, 'soma', 'components', dir, 'types.ts'), 'utf8'); + const wrapper = readFileSync( + join(HERE, 'soma', 'components', dir, 'components', `${dir}.svelte`), + 'utf8' + ); + const rootType = + new RegExp(`export type ${typeName}\\s*=\\s*\\{[\\s\\S]*?\\};`).exec(types)?.[0] ?? ''; + + expect(rootType, dir).toContain('children?: Snippet;'); + expect(rootType, dir).not.toContain('WithChild'); + expect(rootType, dir).not.toContain('PrimitiveDivAttributes'); + expect(wrapper, dir).toContain('{@render children?.()}'); + expect(wrapper, dir).not.toContain('child({ props: {} })'); + } + }); + it('guards Soma public barrels from provider implementation filenames', () => { const violations = collectPublicSomaComponentDirs() .map((dir) => join(HERE, 'soma', 'components', dir, 'exports.ts')) diff --git a/src/uix/soma/components/color-picker/color-picker-provider.svelte.test.ts b/src/uix/soma/components/color-picker/color-picker-provider.svelte.test.ts index 178613bd6..1eba83663 100644 --- a/src/uix/soma/components/color-picker/color-picker-provider.svelte.test.ts +++ b/src/uix/soma/components/color-picker/color-picker-provider.svelte.test.ts @@ -196,7 +196,9 @@ describe('ColorPickerProvider', () => { vi.spyOn(ColorPickerProvider.ctx, 'get').mockReturnValue(provider); const area = ColorPickerAreaProvider.create({ id: state('color-picker-area'), - ref: state(document.createElement('div')) + ref: state(document.createElement('div')), + xChannel: state(undefined), + yChannel: state(undefined) }); vi.spyOn(ColorPickerAreaProvider.ctx, 'get').mockReturnValue(area); const thumb = ColorPickerAreaThumbProvider.create({ @@ -227,6 +229,37 @@ describe('ColorPickerProvider', () => { dom.dispose(); }); + it('lets each area override the root channel mapping', () => { + const { dom } = installSomaHarness(); + const opts = createColorPickerOpts(); + opts.value.current = colorValueFromRgb({ r: 10, g: 20, b: 30, a: 1 }); + + const { result, cleanup } = withEffectRoot(() => { + const provider = ColorPickerProvider.create(opts); + vi.spyOn(ColorPickerProvider.ctx, 'get').mockReturnValue(provider); + const area = ColorPickerAreaProvider.create({ + id: state('color-picker-area'), + ref: state(document.createElement('div')), + xChannel: state('red'), + yChannel: state('green') + }); + return { area }; + }); + + expect(result.area.props).toMatchObject({ + 'data-x-channel': 'red', + 'data-y-channel': 'green' + }); + + result.area.handlePointerMove(128, 128, rect(0, 0, 255, 255)); + + expect(Math.round(opts.value.current?.rgb.r ?? 0)).toBe(128); + expect(Math.round(opts.value.current?.rgb.g ?? 0)).toBe(127); + + cleanup(); + dom.dispose(); + }); + it('drives a channel slider by pointer and keyboard and commits on pointerup', () => { const { dom } = installSomaHarness(); const opts = createColorPickerOpts(); diff --git a/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts b/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts index 6cad16583..95e4a6458 100644 --- a/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts +++ b/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts @@ -528,7 +528,13 @@ import { KEYS } from '../../keyboard'; // ── Area ──────────────────────────────────────────────────────────────────── -export interface ColorPickerAreaOpts extends WithRefOpts {} +export interface ColorPickerAreaOpts + extends + WithRefOpts, + ActiveProps<{ + xChannel: ColorChannel | undefined; + yChannel: ColorChannel | undefined; + }> {} export class ColorPickerAreaProvider { readonly opts: ColorPickerAreaOpts; @@ -562,8 +568,12 @@ export class ColorPickerAreaProvider { }); } - readonly xChannel: ColorChannel = $derived.by(() => this.provider.opts.areaChannels.current.x); - readonly yChannel: ColorChannel = $derived.by(() => this.provider.opts.areaChannels.current.y); + readonly xChannel: ColorChannel = $derived.by( + () => this.opts.xChannel.current ?? this.provider.opts.areaChannels.current.x + ); + readonly yChannel: ColorChannel = $derived.by( + () => this.opts.yChannel.current ?? this.provider.opts.areaChannels.current.y + ); /** * The `(xChannel, yChannel)` normalized progress (0..1) for the current diff --git a/src/uix/soma/components/color-picker/components/color-picker-area.svelte b/src/uix/soma/components/color-picker/components/color-picker-area.svelte index c2e4f2c59..c831d6cba 100644 --- a/src/uix/soma/components/color-picker/components/color-picker-area.svelte +++ b/src/uix/soma/components/color-picker/components/color-picker-area.svelte @@ -13,22 +13,21 @@ let { ref = $bindable(null), id = createId(uid, 'color-picker-area'), - xChannel: _x, - yChannel: _y, + xChannel, + yChannel, children, child, ...restProps }: ColorPickerAreaProps = $props(); - // Per-instance axis override is not implemented yet — the provider reads - // from root `areaChannels`. Destructured (as `_x` / `_y`) to keep them out - // of `restProps` so they don't leak onto the DOM; kept for forward compat. const area = ColorPickerAreaProvider.create({ id: readableActive(() => id), ref: writableActive( () => ref, (v) => (ref = v) - ) + ), + xChannel: readableActive(() => xChannel), + yChannel: readableActive(() => yChannel) }); const mergedProps = $derived(mergeProps(restProps, area.props)); diff --git a/src/uix/soma/components/date-field/components/date-field.svelte b/src/uix/soma/components/date-field/components/date-field.svelte index 2827d021e..ab479292d 100644 --- a/src/uix/soma/components/date-field/components/date-field.svelte +++ b/src/uix/soma/components/date-field/components/date-field.svelte @@ -20,6 +20,7 @@ const soma = Soma.get(); let { + ref = $bindable(null), id = createId(uid, 'date-field'), value = $bindable(), onValueChange = () => {}, @@ -37,9 +38,6 @@ required = false, errorMessageId, locale, - // `dir` is consumed by sub-parts through soma.prefs.getDir(); - // destructured (as `_dir`) only to keep it out of `restProps`. - // eslint-disable-next-line @typescript-eslint/no-unused-vars dir: _dir, hourCycle, children, @@ -72,6 +70,10 @@ const state = DateFieldProvider.create({ id: readableActive(() => id), + ref: writableActive( + () => ref, + (v) => (ref = v) + ), value: writableActive( () => value, (v) => { @@ -97,6 +99,9 @@ hideTimeZone: readableActive(() => hideTimeZone), hourCycle: readableActive(() => hourCycle), locale: readableActive(() => locale ?? soma?.langs.getLocale() ?? ''), + dir: readableActive<'ltr' | 'rtl'>( + () => (_dir ?? soma?.prefs.getDir() ?? 'ltr') as 'ltr' | 'rtl' + ), minValue: readableActive(() => minValue), maxValue: readableActive(() => maxValue), validate: readableActive(() => validate), @@ -113,5 +118,7 @@ {#if child} {@render child({ props: mergedProps })} {:else} - {@render children?.()} +
+ {@render children?.()} +
{/if} diff --git a/src/uix/soma/components/date-field/date-field-provider.svelte.test.ts b/src/uix/soma/components/date-field/date-field-provider.svelte.test.ts index 551b77822..c6e04e179 100644 --- a/src/uix/soma/components/date-field/date-field-provider.svelte.test.ts +++ b/src/uix/soma/components/date-field/date-field-provider.svelte.test.ts @@ -103,6 +103,7 @@ function createDateFieldOpts() { granularity: state(undefined), hourCycle: state(undefined), locale: state('en-US'), + dir: state<'ltr' | 'rtl'>('ltr'), hideTimeZone: state(false), required: state(false), errorMessageId: state(undefined) 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 b1fd08218..4db5392f3 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 @@ -12,7 +12,13 @@ import { type ActiveProps, type StateProps } from '$libs/reactive'; -import type { SomaFocusEvent, SomaKeyboardEvent, SomaMouseEvent, OnChangeFn } from '../../types'; +import type { + SomaFocusEvent, + SomaKeyboardEvent, + SomaMouseEvent, + OnChangeFn, + Direction +} from '../../types'; import { KEYS, getDirectionalKeys } from '../../keyboard'; import { isNumberString } from '../../types/guards'; import { useId } from '../../id'; @@ -158,6 +164,7 @@ export interface DateFieldOpts granularity: Granularity | undefined; hourCycle: HourCycle | undefined; locale: string; + dir: Direction; hideTimeZone: boolean; required: boolean; errorMessageId: string | undefined; @@ -711,7 +718,8 @@ export class DateFieldProvider { readonly props = $derived.by(() => this.runtimePart.assert({ - ...this.runtimePart.props + ...this.runtimePart.props, + dir: this.opts.dir.current } as const) ); } @@ -918,7 +926,7 @@ abstract class BaseNumericSegmentProvider { } get directionalKeys() { - return getDirectionalKeys(this.provider.soma?.prefs.getDir() ?? 'ltr', 'horizontal'); + return getDirectionalKeys(this.provider.opts.dir.current, 'horizontal'); } /** @@ -1378,7 +1386,7 @@ class DateFieldDayPeriodSegmentProvider { } get directionalKeys() { - return getDirectionalKeys(this.provider.soma?.prefs.getDir() ?? 'ltr', 'horizontal'); + return getDirectionalKeys(this.provider.opts.dir.current, 'horizontal'); } onkeydown = (e: SomaKeyboardEvent) => { @@ -1498,7 +1506,7 @@ class DateFieldTimeZoneSegmentProvider { } get directionalKeys() { - return getDirectionalKeys(this.provider.soma?.prefs.getDir() ?? 'ltr', 'horizontal'); + return getDirectionalKeys(this.provider.opts.dir.current, 'horizontal'); } onkeydown = (e: SomaKeyboardEvent) => { diff --git a/src/uix/soma/components/date-picker/components/date-picker.svelte b/src/uix/soma/components/date-picker/components/date-picker.svelte index 67476e31c..312813b4e 100644 --- a/src/uix/soma/components/date-picker/components/date-picker.svelte +++ b/src/uix/soma/components/date-picker/components/date-picker.svelte @@ -61,8 +61,7 @@ isDateHoliday, announceNavigation = true, errorMessageId, - children, - child + children }: DatePickerProviderProps = $props(); /** Today-based default when the consumer doesn't supply a placeholder. */ @@ -137,7 +136,7 @@ granularity: readableActive(() => granularity), hideTimeZone: readableActive(() => hideTimeZone), hourCycle: readableActive(() => hourCycle), - locale: readableActive(() => locale), + locale: resolvedLocale, dir: resolvedDir, pagedNavigation: readableActive(() => pagedNavigation), weekStartsOn: readableActive(() => weekStartsOn), @@ -183,12 +182,9 @@ hideTimeZone: readableActive(() => hideTimeZone), hourCycle: readableActive(() => hourCycle), locale: resolvedLocale, + dir: resolvedDir, errorMessageId: readableActive(() => errorMessageId) }); -{#if child} - {@render child({ props: {} })} -{:else} - {@render children?.()} -{/if} +{@render children?.()} diff --git a/src/uix/soma/components/date-picker/types.ts b/src/uix/soma/components/date-picker/types.ts index c2bf75b6b..b8e0f8ad1 100644 --- a/src/uix/soma/components/date-picker/types.ts +++ b/src/uix/soma/components/date-picker/types.ts @@ -24,7 +24,7 @@ export type DatePickerCalendarSnippetProps = { // ── Root provider ────────────────────────────────────────────────────────── /** Props for the root `DatePicker.Provider`. */ -export type DatePickerProviderProps = WithChild<{ +export type DatePickerProviderProps = { /** DOM id. Auto-generated when omitted. */ id?: string; @@ -129,8 +129,8 @@ export type DatePickerProviderProps = WithChild<{ // ── ARIA ── /** External element id holding the error message (for aria-describedby). */ errorMessageId?: string; -}> & - Omit; + children?: Snippet; +}; // ── Trigger ──────────────────────────────────────────────────────────────── 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 99874bcbc..11a36d7aa 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 @@ -75,6 +75,7 @@ hideTimeZone: provider.opts.hideTimeZone, hourCycle: provider.opts.hourCycle, locale: readableActive(() => provider.opts.locale.current ?? ''), + dir: provider.opts.dir, errorMessageId: provider.opts.errorMessageId }); diff --git a/src/uix/soma/components/date-range-picker/components/date-range-picker.svelte b/src/uix/soma/components/date-range-picker/components/date-range-picker.svelte index d7987ff85..72cefa784 100644 --- a/src/uix/soma/components/date-range-picker/components/date-range-picker.svelte +++ b/src/uix/soma/components/date-range-picker/components/date-range-picker.svelte @@ -71,8 +71,7 @@ weekNumberFormat = 'iso', announceNavigation = true, errorMessageId, - children, - child + children }: DateRangePickerProviderProps = $props(); /** Today-based default placeholder. */ @@ -196,7 +195,7 @@ granularity: readableActive(() => granularity), hideTimeZone: readableActive(() => hideTimeZone), hourCycle: readableActive(() => hourCycle), - locale: readableActive(() => locale), + locale: readableActive(() => locale ?? soma?.langs.getLocale() ?? ''), dir: resolvedDir, pagedNavigation: readableActive(() => pagedNavigation), weekStartsOn: readableActive(() => weekStartsOn), @@ -253,8 +252,4 @@ }); -{#if child} - {@render child({ props: {} })} -{:else} - {@render children?.()} -{/if} +{@render children?.()} diff --git a/src/uix/soma/components/date-range-picker/types.ts b/src/uix/soma/components/date-range-picker/types.ts index 7c21d55fd..0a77187d8 100644 --- a/src/uix/soma/components/date-range-picker/types.ts +++ b/src/uix/soma/components/date-range-picker/types.ts @@ -23,7 +23,7 @@ export type DateRangePickerCalendarSnippetProps = { }; /** Props for the root `DateRangePicker.Provider`. */ -export type DateRangePickerProviderProps = WithChild<{ +export type DateRangePickerProviderProps = { id?: string; // ── Value ── @@ -109,8 +109,8 @@ export type DateRangePickerProviderProps = WithChild<{ // ── ARIA ── errorMessageId?: string; -}> & - Omit; + children?: Snippet; +}; /** Props for `DateRangePicker.Trigger`. */ export type DateRangePickerTriggerProps = WithChild<{ diff --git a/src/uix/soma/components/time-field/components/time-field.svelte b/src/uix/soma/components/time-field/components/time-field.svelte index 213d705c4..e30d07991 100644 --- a/src/uix/soma/components/time-field/components/time-field.svelte +++ b/src/uix/soma/components/time-field/components/time-field.svelte @@ -4,6 +4,7 @@ readableActive, writableActive } from '$libs/reactive'; + import { mergeProps } from '../../../props'; import { createId } from '../../../id'; import { Soma } from '../../../core/soma.svelte'; import { @@ -19,6 +20,7 @@ const soma = Soma.get(); let { + ref = $bindable(null), id = createId(uid, 'time-field'), value = $bindable(), onValueChange = () => {}, @@ -39,7 +41,8 @@ dir: _dir, hourCycle, children, - child + child, + ...restProps }: TimeFieldProviderProps = $props(); /** Default placeholder = current wall-clock time (minute precision). */ @@ -59,8 +62,12 @@ } ); - TimeFieldProvider.create({ + const state = TimeFieldProvider.create({ id: readableActive(() => id), + ref: writableActive( + () => ref, + (v) => (ref = v) + ), value: writableActive( () => value, (v) => { @@ -96,10 +103,14 @@ ), hourCycle: readableActive(() => hourCycle) }); + + const mergedProps = $derived(mergeProps(restProps, state.props)); {#if child} - {@render child({ props: {} })} + {@render child({ props: mergedProps })} {:else} - {@render children?.()} +
+ {@render children?.()} +
{/if} diff --git a/src/uix/soma/components/time-picker/components/time-picker.svelte b/src/uix/soma/components/time-picker/components/time-picker.svelte index 52a463bc4..0b0540d83 100644 --- a/src/uix/soma/components/time-picker/components/time-picker.svelte +++ b/src/uix/soma/components/time-picker/components/time-picker.svelte @@ -41,8 +41,7 @@ minuteStep = 1, secondStep = 1, errorMessageId, - children, - child + children }: TimePickerProviderProps = $props(); function defaultPlaceholder(): TimeValue { @@ -106,7 +105,7 @@ granularity: readableActive(() => granularity), hideTimeZone: readableActive(() => hideTimeZone), hourCycle: readableActive(() => hourCycle), - locale: readableActive(() => locale), + locale: readableActive(() => locale ?? soma?.langs.getLocale() ?? ''), dir: resolvedDir, hourStep: readableActive(() => hourStep), minuteStep: readableActive(() => minuteStep), @@ -143,8 +142,4 @@ }); -{#if child} - {@render child({ props: {} })} -{:else} - {@render children?.()} -{/if} +{@render children?.()} diff --git a/src/uix/soma/components/time-picker/types.ts b/src/uix/soma/components/time-picker/types.ts index 76cef9272..19c57cc26 100644 --- a/src/uix/soma/components/time-picker/types.ts +++ b/src/uix/soma/components/time-picker/types.ts @@ -1,5 +1,6 @@ +import type { Snippet } from 'svelte'; import type { WithChild, Without, OnChangeFn, Direction } from '../../types'; -import type { PrimitiveDivAttributes, PrimitiveButtonAttributes } from '../../types'; +import type { PrimitiveButtonAttributes } from '../../types'; import type { TimeValue, TimeValidator, @@ -10,7 +11,7 @@ import type { } from '$libs/days'; /** Props for the root `TimePicker.Provider`. */ -export type TimePickerProviderProps = WithChild<{ +export type TimePickerProviderProps = { id?: string; // ── Value ── @@ -54,8 +55,8 @@ export type TimePickerProviderProps = WithChild<{ // ── ARIA ── errorMessageId?: string; -}> & - Omit; + children?: Snippet; +}; /** Props for `TimePicker.Trigger`. */ export type TimePickerTriggerProps = WithChild<{ diff --git a/src/uix/soma/components/time-range-picker/components/time-range-picker.svelte b/src/uix/soma/components/time-range-picker/components/time-range-picker.svelte index 49c115cac..c8ce99d62 100644 --- a/src/uix/soma/components/time-range-picker/components/time-range-picker.svelte +++ b/src/uix/soma/components/time-range-picker/components/time-range-picker.svelte @@ -46,8 +46,7 @@ minuteStep = 1, secondStep = 1, errorMessageId, - children, - child + children }: TimeRangePickerProviderProps = $props(); /** Default placeholder = current wall-clock time (minute precision). */ @@ -147,7 +146,7 @@ granularity: readableActive(() => granularity), hideTimeZone: readableActive(() => hideTimeZone), hourCycle: readableActive(() => hourCycle), - locale: readableActive(() => locale), + locale: readableActive(() => locale ?? soma?.langs.getLocale() ?? ''), dir: resolvedDir, hourStep: readableActive(() => hourStep), minuteStep: readableActive(() => minuteStep), @@ -193,8 +192,4 @@ }); -{#if child} - {@render child({ props: {} })} -{:else} - {@render children?.()} -{/if} +{@render children?.()} diff --git a/src/uix/soma/components/time-range-picker/types.ts b/src/uix/soma/components/time-range-picker/types.ts index 0da8a029d..787679b8e 100644 --- a/src/uix/soma/components/time-range-picker/types.ts +++ b/src/uix/soma/components/time-range-picker/types.ts @@ -1,3 +1,4 @@ +import type { Snippet } from 'svelte'; import type { WithChild, Without, OnChangeFn, Direction } from '../../types'; import type { PrimitiveDivAttributes, PrimitiveButtonAttributes } from '../../types'; import type { @@ -14,7 +15,7 @@ import type { export type TimeRangeEndpoint = 'start' | 'end'; /** Props for the root `TimeRangePicker.Provider`. */ -export type TimeRangePickerProviderProps = WithChild<{ +export type TimeRangePickerProviderProps = { id?: string; // ── Value ── @@ -81,8 +82,8 @@ export type TimeRangePickerProviderProps = WithChild<{ // ── ARIA ── errorMessageId?: string; -}> & - Omit; + children?: Snippet; +}; /** Props for `TimeRangePicker.Trigger`. */ export type TimeRangePickerTriggerProps = WithChild<{