From 546aa8d0eefdb2e31964b551b37010cc65fae1b9 Mon Sep 17 00:00:00 2001 From: dev Date: Mon, 25 May 2026 13:25:52 +0200 Subject: [PATCH] =?UTF-8?q?fix(soma/eidos):=20close=20last=205=20check=20e?= =?UTF-8?q?rrors=20=E2=80=94=20PassthroughProps=20helper=20+=20floating/sh?= =?UTF-8?q?ell=20cast?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `npm run check`: 5 errors → 0 errors. floating/shell.ts (Phase 1 — local fix): - `buildFloatingShellWrapperProps` returned a type where TS couldn't prove `transform` stayed required after the conditional-object spread. Runtime preserves the key; we cast at the return boundary so consumers downstream keep the strict shape. soma/types/html.ts (Phase 2 — canonical pattern): - Nuevo `PassthroughProps` helper para resolver el drift Eidos→Soma estructuralmente. Es `Omit, 'style' | 'id' | 'children' | 'dir' | 'value' | 'placeholder'>`. Las keys excluidas son las que Soma narrowa en sus Provider types — incluirlas en Eidos wrappers (via el plain `HTMLAttributes`) producía "Expression produces a union type that is too complex to represent" y errores de incompatibilidad al hacer spread. - Exportado por `soma/types/index.ts`. eidos picker views (Phase 3 — adopción): - `date-picker-year-view.svelte` y `date-picker-month-view.svelte` tipados como `Props = PassthroughProps` en lugar del plain `HTMLAttributes`. Conserva data-*, aria-*, class, role, tabindex etc. — solo dropea las keys conflictivas. Pattern reusable: cualquier futuro Eidos wrapper que envuelva un Soma Provider via `{...props}` debe usar `PassthroughProps` en vez de `HTMLAttributes`. Documentado en el JSDoc del helper con ejemplo. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../date-picker/date-picker-month-view.svelte | 6 ++-- .../date-picker/date-picker-year-view.svelte | 8 +++-- src/uix/soma/layers/floating/shell.ts | 7 +++- src/uix/soma/types/html.ts | 32 +++++++++++++++++++ src/uix/soma/types/index.ts | 3 +- 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/uix/eidos/components/date-picker/date-picker-month-view.svelte b/src/uix/eidos/components/date-picker/date-picker-month-view.svelte index 94f3d3400..2f4949616 100644 --- a/src/uix/eidos/components/date-picker/date-picker-month-view.svelte +++ b/src/uix/eidos/components/date-picker/date-picker-month-view.svelte @@ -6,11 +6,13 @@ * `size` from the visual context and forwards it. */ import * as DatePicker from '$soma/components/date-picker'; + import type { PassthroughProps } from '$soma/types'; import type { MonthGridSize } from '../month-grid'; import { getDatePickerVisualContext } from './context.svelte'; - import type { HTMLAttributes } from 'svelte/elements'; - type Props = HTMLAttributes; + // See `date-picker-year-view.svelte` for the rationale on + // `PassthroughProps` — same pattern, same boundary. + type Props = PassthroughProps; const props: Props = $props(); diff --git a/src/uix/eidos/components/date-picker/date-picker-year-view.svelte b/src/uix/eidos/components/date-picker/date-picker-year-view.svelte index 08a3b1fe6..c5c5f38ef 100644 --- a/src/uix/eidos/components/date-picker/date-picker-year-view.svelte +++ b/src/uix/eidos/components/date-picker/date-picker-year-view.svelte @@ -6,11 +6,15 @@ * `size` from the visual context and forwards it. */ import * as DatePicker from '$soma/components/date-picker'; + import type { PassthroughProps } from '$soma/types'; import type { YearGridSize } from '../year-grid'; import { getDatePickerVisualContext } from './context.svelte'; - import type { HTMLAttributes } from 'svelte/elements'; - type Props = HTMLAttributes; + // `PassthroughProps` drops the HTML keys that Soma's + // YearGrid narrows (`dir`, `value`, `placeholder`). See + // `soma/types/html.ts` — pattern adopted to avoid the "union too + // complex" / type-incompat errors at the Eidos→Soma boundary. + type Props = PassthroughProps; const props: Props = $props(); diff --git a/src/uix/soma/layers/floating/shell.ts b/src/uix/soma/layers/floating/shell.ts index 59e1c73c9..8b5595968 100644 --- a/src/uix/soma/layers/floating/shell.ts +++ b/src/uix/soma/layers/floating/shell.ts @@ -87,11 +87,16 @@ export function buildFloatingShellWrapperProps( pointerEvents: 'auto' | 'none' = 'auto' ): FloatingContent['wrapperProps'] & { style: Record } { const baseStyle = floating.wrapperProps.style; + // The spread + conditional object widens the inferred type beyond + // what the floating wrapperProps contract narrows (e.g. `transform` + // goes from required-string to optional). At runtime the keys are + // always present — we cast at the boundary so consumers downstream + // keep the strict shape. return { ...floating.wrapperProps, style: { ...(typeof baseStyle === 'object' && baseStyle !== null ? baseStyle : {}), 'pointer-events': pointerEvents } - }; + } as FloatingContent['wrapperProps'] & { style: Record }; } diff --git a/src/uix/soma/types/html.ts b/src/uix/soma/types/html.ts index c169af6a6..021e2fa89 100644 --- a/src/uix/soma/types/html.ts +++ b/src/uix/soma/types/html.ts @@ -15,6 +15,38 @@ import type { // Primitive attribute types — omit style, id, children (handled by WithChild/mergeProps) type OmitManaged = Omit; +/** + * Canonical "safe" HTML attribute subset for Eidos→Soma passthrough. + * + * Use this in **Eidos wrapper components** that type their props as + * `HTMLAttributes` and forward via `{...props}` into a Soma + * Provider. The naive `HTMLAttributes` clashes with Soma's + * narrowing of certain attributes (`dir`, `value`, `placeholder`) — + * the intersection produces "Expression produces a union type that is + * too complex to represent" errors or property incompatibility on the + * Eidos→Soma boundary. + * + * `PassthroughProps` drops every key Soma is allowed to narrow. + * Anything the wrapper still wants to expose at the Eidos surface + * (typically `class`, `role`, `data-*`, `aria-*` — all included) flows + * through cleanly. If a wrapper needs to accept a narrowed key (e.g. + * `dir: 'ltr' | 'rtl'`) it extends explicitly: + * + * ```ts + * type Props = PassthroughProps & { + * dir?: 'ltr' | 'rtl'; + * }; + * ``` + * + * Pattern adopted in the 2026-05-25 audit-codex cleanup after the + * picker-view drift (`date-picker-year-view` / `month-view`) surfaced + * the same shape repeatedly across Eidos wrappers. + */ +export type PassthroughProps = Omit< + OmitManaged>, + 'dir' | 'value' | 'placeholder' +>; + export type PrimitiveDivAttributes = OmitManaged>; export type PrimitiveButtonAttributes = OmitManaged; export type PrimitiveInputAttributes = OmitManaged; diff --git a/src/uix/soma/types/index.ts b/src/uix/soma/types/index.ts index 6023f9f49..69e7650ba 100644 --- a/src/uix/soma/types/index.ts +++ b/src/uix/soma/types/index.ts @@ -43,5 +43,6 @@ export type { PrimitiveTRAttributes, PrimitiveTHAttributes, PrimitiveTDAttributes, - PrimitiveCaptionAttributes + PrimitiveCaptionAttributes, + PassthroughProps } from './html';