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/README.md

6.0 KiB

eidos/components/

Recipes y wrappers visuales por componente. La forma actual de un componente es un subdirectorio con cuatro archivos; los .css sueltos del nivel raíz son legacy de la fase "eidos = solo CSS" y se migran progresivamente.

Forma actual (toggle es el piloto)

toggle/
  toggle.css       → recipe CSS (selectores [data-toggle], variants, …)
  toggle.svelte    → wrapper sobre $soma/components/toggle
  types.ts         → ToggleProps (extiende SomaToggleProps)
  index.ts         → re-exports públicos
  README.md        → notas del componente (opcional, recomendado para piloto)

{name}.svelte — el wrapper

Compone sobre el provider headless del soma. Re-bindable de estado (pressed = $bindable(false)), emite los data-attrs de tokens visuales y opcionalmente añade slots (icon, checkMark):

<script lang="ts">
  import * as Toggle from '$soma/components/toggle';
  import type { ToggleProps } from './types';
  let {
    variant = 'solid',
    size = 'md',
    block = false,
    iconOnly = false,
    icon,
    checkMark = false,
    pressed = $bindable(false),
    children: bodyContent,
    ...somaProps
  }: ToggleProps = $props();
</script>

<Toggle.Provider
  {...somaProps}
  bind:pressed
  data-variant={variant}
  data-size={size}
  data-block={block ? '' : undefined}
  data-icon-only={iconOnly ? '' : undefined}
>
  {#snippet children(snippetProps)}
    {#if icon}{@render icon(snippetProps)}{/if}
    <span class="eidos-toggle-body">{@render bodyContent?.(snippetProps)}</span>
    {#if checkMark === true && snippetProps.pressed}
      <svg class="eidos-toggle-checkmark" …/>
    {/if}
  {/snippet}
</Toggle.Provider>

Patrones notables:

  • children se renombra a bodyContent dentro del wrapper porque el {#snippet children} interno shadowearía el prop y haría recursión.
  • pressed = $bindable(false) se declara explícitamente; sin esto un consumer que pase bind:pressed choca con un error de Svelte ("non-bindable property").
  • <span class="eidos-toggle-body"> envuelve el body del usuario para que [data-icon-only] .eidos-toggle-body { sr-only } lo oculte visualmente sin perder accesibilidad.

types.ts — extensión de los tipos del soma

import type { Snippet } from 'svelte';
import type { ToggleProps as SomaToggleProps } from '$soma/components/toggle/types';
import type { Size } from '$uix/eidos/lib/types';

export type ToggleVariant = 'solid' | 'outline' | 'ghost';
export type ToggleSize = Extract<Size, 'sm' | 'md' | 'lg'>;

export type ToggleProps = SomaToggleProps & {
  variant?: ToggleVariant;
  size?: ToggleSize;
  block?: boolean;
  iconOnly?: boolean;
  icon?: Snippet<[{ pressed: boolean }]>;
  checkMark?: boolean | Snippet<[{ pressed: boolean }]>;
};

Reglas:

  • Sin prefijo Eidos. El path $uix/eidos/components/{x} ya identifica la capa.
  • Subset el tipo compartido. Size global tiene 8 valores (xxs..xxl + full); el componente reduce con Extract al subset que su recipe soporta. Compile error antes que fallback silencioso.
  • El nombre del prop refleja la API doctrinal. intent y color pertenecen a soma — no se redeclaran en eidos; se heredan de SomaToggleProps.

index.ts — re-exports

export { default } from './toggle.svelte';
export { default as Provider } from './toggle.svelte';

export type {
  ToggleProps,
  ToggleProps as ProviderProps,
  ToggleVariant,
  ToggleSize
} from './types';

Doble export (default + Provider) por la doctrina de API:

Forma Cuándo
import Toggle from '$uix/eidos/components/toggle' → <Toggle> single-part components, ergonomía Chakra-style
import * as Toggle from … → <Toggle.Provider> consumers que prefieren la forma compound (Radix-style)

{name}.css — el recipe

Selectores [data-{component}], variantes por data-color, data-size, data-variant, etc.

Para el subset por componente, el CSS sólo define los tokens permitidos por el anexo del libro. Si un componente no admite loss, no aparece [data-color='loss'] en su recipe.

Convención de naming de tokens CSS

Regla: los tokens CSS llevan el nombre del componente, no de la capa. Sin prefijos de capa — ni --eidos-, ni --air-, ni --terra-, ni --soma-.

Forma Uso Ejemplo
--{component}-… tokens públicos (sobreescribibles por el consumer) --dialog-content-bg, --toggle-radius-md
--_{component}-… tokens internos del recipe (no parte del API público) --_dialog-padding, --_toggle-palette-track

Por qué bare-prefixed (sin --eidos-):

  • Los recipes son la skin oficial; el consumer interactúa con tokens por componente, no por capa.
  • Si un consumer construye un recipe alternativo a partir de soma+morfo (doctrina §13), reutiliza los mismos tokens — no debe importar de qué capa "salieron".
  • Migrar de air → eidos no debe romper override de consumer. Mantener --{component}-… hace la migración invisible (el rename air- → `` es interno).
  • El selector [data-{component}] ya identifica al componente; el token sólo necesita coincidir con ese mismo nombre.

Histórico: la baseline air/ usaba --air-{component}-…. Al migrar al wrapper eidos se hace strip del prefijo air- (no se reemplaza por eidos-).

Forma legacy (CSS-only)

Los archivos sueltos accordion.css, dialog.css, drawer.css, etc. son la fase anterior cuando eidos sólo emitía CSS. Funcionan, pero se migran a la forma actual cuando el componente entra en revisión.

Pendientes de migrar a wrapper

Componente CSS legacy Wrapper
toggle — ✅ piloto
switch — ✅
collapsible — ✅ (multi-part: flat + compound)
dialog dialog.css ⏳
drawer drawer.css ⏳
popover popover.css ⏳
toast toast.css ⏳
avatar — ✅ eidos-native
accordion accordion.css ⏳
tabs tabs.css ⏳
checkbox checkbox.css ⏳
tooltip tooltip.css ⏳

Powered by TurnKey Linux.