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

5.9 KiB

Eidos TextFocus

<TextFocus> difumina todas las palabras de una frase salvo la activa, y un marco de esquinas viaja hasta ella — avance automático con cadencia, o manualMode para enfocar la palabra bajo el cursor.

Familia text-effects (TextGradient / TextBlur / TextCircular / TextScramble) — diseño de familia: docs/decisions/design-text-effects.md.

Superficie

<TextFocus sentence="True Focus" />
<TextFocus sentence="Pick a word by hovering" manualMode blurAmount={8} />
<TextFocus sentence="Slow travel" animationDuration={1.2} pauseBetweenAnimations={2} />
<TextFocus sentence="Tinted" borderColor="--color-affirm-solid" />

Props clave

Prop Tipo Default Notas
sentence string 'True Focus' La frase.
separator string ' ' Separador de palabras.
manualMode boolean false Hover enfoca; sin auto-avance.
blurAmount number (px) 5 Blur de las palabras inactivas.
borderColor / glowColor color o token tokens de la receta '--color-*' se interpola como var().
animationDuration number (s) 0.5 Transición de foco/marco.
pauseBetweenAnimations number (s) 1 Reposo del marco (auto).

Tokens públicos

--text-focus-border-color · --text-focus-glow-color · --text-focus-word-size · --text-focus-word-weight · --text-focus-gap.

Baseline

Port limpio del seed web/routes/demos/animations/text/focus/focus.svelte (colección intacta como referencia — provenance en docs/architecture/packs.md). El seed ya traía el auto-avance, el modo manual y el RO de re-alineado; sus déficits: setInterval/RO/getBoundingClientRect crudos, colores green/rgba fijos y — el peor — role="button" + tabindex="0" en cada palabra sin acción activable detrás.

Comparativa

Capacidad Eidos react-bits TrueFocus CSS-only (:hover blur) GSAP Flip
Marco que viaja con física de layout real Sí Sí No Sí
Palabras sin falsos roles interactivos Sí No (role heredado) Sí N/A
Lecturas de layout coalescidas post-layout (dom.measure) Sí No N/A No
Timers/RO del ecosistema (cancelables) Sí No N/A No
Reduced motion (marco quieto + sin transiciones) Sí No Manual Manual

Referencias externas: react-bits TrueFocus (https://reactbits.dev/text-animations/true-focus) · GSAP Flip (https://gsap.com/docs/v3/Plugins/Flip/) · MDN filter: blur() (https://developer.mozilla.org/docs/Web/CSS/filter-function/blur).

Decisiones

  • A11y fix sobre el seed: fuera role="button"/tabindex de las palabras — eran botones falsos sin acción (trampa de tabulación). La frase se lee como texto normal; el hover del modo manual no necesita rol.
  • getBoundingClientRect → eidos.dom.measure (lectura coalescida post-layout — la regla dura de layout reads del repo); cadencia → eidos.timers.interval; re-alineado → eidos.dom.observeResize.
  • Reduced motion — upgrade sobre el seed: sin auto-avance (el marco se queda en la palabra inicial) y las transiciones inline se anulan en la receta (única regla !important, anotada — el estilo inline no se puede vencer de otro modo).
  • Colores por tokens con default --color-primary-solid (el seed: green + rgba fijos); los props aceptan tokens (--x → var()).
  • data-active en la palabra activa — hook de receta/consumidor.
  • No emite eventos sema: el foco viajero es ambiental; el hover manual elige, no compromete.

Talla y tema

Guard R-5.4 (npm run theming:sentinel -- text-focus <url>): 8/8 tokens mueven un computed en vivo, sin una sola excepción. Corrido 2026-08-22.

Contrato en lib/recipes/base.ts > text-focus (8 claves, entrada NUEVA). Alcance del censo: 100 % (era 63 %).

Ya consumía cinco públicos «de facto» con fallback y sin declarar ninguno; los otros tres faltaban, y están todos en la ESQUINA del marco de foco.

La esquina es una escuadra dibujada con bordes: 1rem × 1rem con dos de sus cuatro lados a 0 según la posición (tl, tr, bl, br). El tamaño es un knob, el grosor del trazo otro y el radio el tercero. Los desplazamientos -0.625rem no son knobs: colocan la escuadra justo fuera del marco y se derivan del tamaño y el trazo.

border-fg y glow-fg son el mismo acento en dos capas —el trazo y su resplandor vía drop-shadow— y se declaran por separado a propósito: un tema puede querer el halo de otro tono que el borde.

⚠ --radius-xs no existe, y esta receta lo referenciaba

La escala de radios del sistema es sm | md | lg | xl | xxl, sin xs. El CSS escribía var(--radius-xs, 3px) y pintaba el fallback, así que nadie lo notó. Tokenizarlo tal cual dejó la variable vacía, la declaración inválida y las cuatro esquinas CUADRADAS — 48 diffs, que es exactamente para lo que sirve el gate. El contrato guarda 3px verbatim, el valor que de verdad pintaba. Registrado en next-features.md §13 junto con la pregunta que abre: cuántos var(--fantasma, fallback) más hay en el catálogo.

Gaps

  • Navegación por teclado del foco (flechas): diferir — exigiría un contrato interactivo real (morfo con keyboard + roving focus); si un consumidor lo pide, sube de clase (deja de ser pasivo).
  • Callback onFocusChange(index): implementar cuando haya consumidor.
  • Pausar el auto-avance al hover (sin manualMode): diferir.

Passive justification

Pasivo por diseño: loop ambiental de lectura sobre texto real. El hover en modo manual solo selecciona qué palabra está nítida — sin commit, sin emerge, sin activación ni teclado (los falsos roles del seed se retiraron precisamente por eso).

Referencias

  • Seed portado: web/routes/demos/animations/text/focus/focus.svelte.
  • Regla de layout reads: CLAUDE.md §Key Conventions (dom.measure).

Powered by TurnKey Linux.