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/docs/audit/theming/chat-message.md

13 KiB

chat-message — alcance de tema: análisis y propuesta

Generado por node --import tsx/esm scripts/theming-census.ts --report. Lo medido y la propuesta se regeneran; el Veredicto (§5) se conserva. Vista de conjunto: README · método y protocolo: PLAN-theming.md §1, §2, §7.

  • Medido: 2026-08-25 · Alcance: 100% — 71 de 71 knobs por token público
  • Knobs de apariencia: 78 — público 71 · privado 0 · global 0 · literal 0 · sistema 7 · excepción 4 · estructural 0 · puente 0 · canal 0 (los cinco últimos, fuera del ratio)
  • Contrato hoy (lib/recipes/base.ts): 81 pública(s) — gap, row-gap-run, row-gap-group, focus-radius, gutter-inline-size, bubble-padding-inline-sm, bubble-padding-inline-md, bubble-padding-inline-lg, bubble-padding-block-sm, bubble-padding-block-md, bubble-padding-block-lg, bubble-radius, bubble-radius-run, bubble-tail-radius, bubble-max-inline-size, bubble-font-size-sm, bubble-font-size-md, bubble-font-size-lg, bubble-line-height, bubble-bg-in, bubble-fg-in, bubble-bg-out, bubble-fg-out, bubble-shadow, header-gap, header-font-size, header-font-weight, header-fg, meta-gap, meta-font-size, meta-fg, status-size, status-fg, read-status-fg, failed-status-fg, read-by-gap, read-by-font-size, read-by-fg, read-by-margin, emphasize-bg, emphasize-radius, emphasize-duration, reply-padding-inline, reply-padding-block, reply-accent-size, reply-radius, reply-bg, reply-fg, reply-accent, reply-font-size, reaction-gap, reaction-inner-gap, reaction-height, reaction-padding-inline, reaction-radius, reaction-font-size, reaction-bg, reaction-fg, reaction-border, reaction-shadow, reaction-overlap, reaction-pressed-bg, reaction-pressed-border, reaction-pressed-fg, quick-react-gap, quick-react-pad, quick-react-size, quick-react-radius, quick-react-emoji-size, quick-react-hover-bg, quick-react-hover-scale, actions-bg, actions-border, actions-shadow, actions-radius, actions-padding, mentioned-bg, mentioned-fg, mentioned-accent, actions-gap, actions-offset
  • Eje size: sí · ficheros: chat-message.css

1. Knobs fuera de alcance

1.1 Directo a primitivo global (0)

Ninguno.

1.2 A través de un privado (0)

Ninguno.

1.3 Literales (0)

Ninguno.

1.4 Excepciones firmadas (4) — fuera del ratio

Literales que llevan su anotación /* literal: <razón> */ en la propia declaración: la válvula de recipe-contract §3, la misma que honra component-audit. Una desviación firmada no es deuda — se listan para que la razón se lea, no para acuñarlas.

# fichero:línea selector propiedad valor
1 chat-message.css:371 [data-popover-content][data-chat-message-quick-reactions] inline-size max-content
2 chat-message.css:401 [data-chat-message-quick-react] line-height 1
3 chat-message.css:470 [data-chat-message]:hover [data-chat-message-actions], [data-chat-message]:focus-within [data-chat-message-actions] opacity 1
4 chat-message.css:476 [data-chat-message-actions] opacity 1

2. Sistema transversal (7) — informativo, fuera del ratio

Un tema los alcanza a nivel de sistema, por diseño (recipe-contract §2).

# fichero:línea selector propiedad valor
1 chat-message.css:36 [data-chat-message]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)
2 chat-message.css:270 [data-chat-message][data-delivery='sending'] [data-chat-message-bubble] opacity var(--opacity-muted)
3 chat-message.css:296 [data-chat-message-reply]:hover background-image linear-gradient(var(--state-hover), var(--state-hover))
4 chat-message.css:300 [data-chat-message-reply]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)
5 chat-message.css:342 [data-chat-message-reaction]:hover, [data-chat-message-reaction-add]:hover background-image linear-gradient(var(--state-hover), var(--state-hover))
6 chat-message.css:347 [data-chat-message-reaction]:focus-visible, [data-chat-message-reaction-add]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)
7 chat-message.css:416 [data-chat-message-quick-react]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)

3. Privados de la receta — ¿de dónde sale su valor?

privado declaraciones valor(es) origen ¿deriva de un público?
--_chat-message-bubble-bg 2 var(--chat-message-bubble-bg-in), var(--chat-message-bubble-bg-out) public sí
--_chat-message-bubble-fg 2 var(--chat-message-bubble-fg-in), var(--chat-message-bubble-fg-out) public sí

4. Propuesta de corrección

  • Tiene eje size: los tokens dimensionales van por talla ({part}-{eje}-{k}) apuntando al bundle --size-{k}-*, nunca al primitivo crudo (theming §5; el guard recipe-css-contract prohíbe el primitivo).

4.1 Tokens a declarar en lib/recipes/base.ts (1)

Valor verbatim del CSS de hoy: el default no se mueve, sólo cambia quién puede moverlo. Nombres derivados de recipe-contract §1 (ejes lógicos, talla al final) y theming §6.7 (slots de color, modificador delante). Un token con DOS valores distintos es una colisión de nombre: son dos knobs, o el nombre no distingue lo que debería — se marca ⚠.

token (--chat-message-…) scope TSC valor propuesto usos
quick-reactions-width root max-content 1

4.2 Sin nombre mecánico (3)

  • ⚠ decisión: 1 es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar — 3: line-height, opacity.

4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)

  • Privado que no deriva de un público — §3 lo marca; el privado debe leer el público o desaparecer.
  • Velo o acento en el nodo equivocado (archetype: 'item' en un envoltorio, un background en shorthand que mata la capa de estado) — se mide desde el píxel hacia arriba.
  • Doble animación al mover un sello a una superficie con animación propia — registro de animationstart/animationend.
  • Diff de computed = 0 en reposo · hover · abierto · disabled · foco, por talla, antes y después.
  • Centinela por token nuevo: valor imposible en el root → el nodo lo sigue. Si no, el token miente.

5. Veredicto

EJECUTADO 2026-08-24 — 84 % → 100 %. Contrato 75 → 81 claves; censo público 71 · global 0 · literal 0 · sistema 7 · excepción 4. Diff de computed VACÍO (4.192 valores, 8 estados, 16 nodos) y capturas 2× idénticas byte a byte, en reposo y con la barra tapback abierta. Centinela 77/81, cuatro adjudicadas. component-audit PASS · eidos-lint 0 invalid · rtl:check 0 · docs:check 0 · check sin errores del componente.

Otra vez, lo caro fue VER. El guard daba 45/75 antes de tocar una línea y las treinta «muertas» estaban las treinta VIVAS: una fila de chat es una PILA de superficies opt-in (reply citado, read-by, estado de entrega, mención) y de ejes de PRESENTACIÓN (run, direction, emphasized) que la demo arranca en su posición más pobre. Con las cuatro superficies encendidas por prepareWith y los cinco ejes barridos como producto: 71/75 antes de acuñar nada. La sonda pasó de 12 a 16 nodos en reposo y a 24 con la barra abierta.

Lo que entra (6 claves, la COSTURA de los seis globales): focus-radius, mentioned-fg, reply-fg, reaction-fg, reaction-inner-gap y quick-react-radius. El valor sigue siendo el del sistema; el knob pasa a ser del componente.

Los nombres salen del CATÁLOGO. La ficha proponía radius (colisiona con emphasize-radius, que ES la esquina en reposo de la MISMA fila: la de foco lleva su modificador delante, focus-radius), bubble-fg (el knob es de la MENCIÓN — mentioned-bg / mentioned-accent ya existen, faltaba mentioned-fg), reaction-width + reaction-height para el glifo (dos literales de una regla muerta, y reaction-height ya existe con otro sentido: la altura del CHIP) y quick-reactions-width para un max-content que es identidad.

Y el caso que obligó a decidir: reaction-gap ya existía con otro sentido. La receta la pinta en la fila reactions (el hueco ENTRE chips) mientras el knob nuevo es el ritmo INTERNO del chip — el emoji y su cuenta. Mismo valor (--space-1), dos papeles: un chip más denso no es una fila más apretada. Reusar la clave habría cambiado en silencio lo que mueve un tema que ya la usa, así que entra como reaction-inner-gap y reaction-gap se queda como está. El resto del bloque {parte}-gap de esta receta (meta-gap, read-by-gap, header-gap, actions-gap) significa «dentro de la parte»: la anómala es la vieja, y renombrarla es churn con riesgo.

Lo que SALE: una regla que no ha pintado nunca. [data-chat-message-reaction] svg, [data-chat-message-reaction-add] svg fijaba 1.1em en los dos ejes «porque un svg de sólo viewBox computa 0×0». El glifo por defecto es el Icon compuesto, que emite style="width: var(--icon-size-sm); height: …" INLINE — y un estilo en línea gana a todo selector. Medido: 16 px (el paso sm del icono), no los 15,4 px que 1.1em daría sobre los 14 px heredados. La otra mitad del selector no tiene nodo: los chips llevan un emoji de texto. Retirada: 0 diffs. Tercera vez en la familia (chat-log, chat-composer, y aquí).

Identidades firmadas (4, fuera del ratio): inline-size: max-content de la barra tapback (la barra ES su fila de emoji), line-height: 1 de la celda (la celda es la caja del glifo) y los dos opacity: 1 de la pastilla de acciones (el final del fundido 0 → 1).

Adjudicadas (4), todas límites del INSTRUMENTO y medidas a mano:

  1. bubble-tail-radius — el guard fotografía UNA esquina (borderTopLeftRadius) y la cola es la de ABAJO (border-end-start en in, border-end-end en out). Medido en las 8 combinaciones dirección × run: 4 px → 1234 px en solo y last en las dos direcciones. Su hermana bubble-radius-run lee viva porque middle aplana la esquina START, que sí está en la lista.
  2. emphasize-duration — ES la transición que el guard congela para poder medir todo lo demás. Sin congelar: 0,24 s → 4,321 s.
  3. focus-radius — la fila sólo es tabulable compuesta DENTRO de un Feed (soma fusiona la identidad de Feed.Article cuando hay un Feed ancestro) y su propia demo la monta suelta, así que :focus-visible no tiene nodo ahí. Medido en /uix/components/chat-log, donde las filas SÍ son artículos de feed (tabindex=0): reposo 6 px (la esquina de emphasize), enfocada 4 px → 1234 px, por foco programático y por recorrido real con Tab.
  4. quick-react-hover-scale — dos límites a la vez: transform no está en la lista de propiedades del guard (el punto ciego ya adjudicado en background, rating-group y card) y la celda es un botón PORTALADO con regla :hover. Con puntero real y transiciones congeladas: matrix(1.18…) → matrix(7.77…).

Defecto real encontrado y NO corregido aquí (mueve píxel): el chip de añadir reacción lleva también data-popover-trigger, y [data-popover-trigger]:not([data-archetype='field-trigger']) pesa (0,2,0) contra los (0,1,0) de [data-chat-message-reaction-add] — así que su fondo, su borde, su radio, su tinta, su altura, su padding y su tamaño de letra los pinta popover.css. Se ve en la captura: los dos chips de reacción son píldoras redondas y el de añadir es un cuadrado gris. Es la clase gradient-picker (36 de 45) / emoji-picker (3). Los reaction-* NO mienten —alcanzan sobre los chips normales—, así que no hay nada que retirar; lo que hay es una decisión de diseño pendiente. Registrado, no tocado (D-TH.5).

D-TH.5 — CERRADO 2026-08-25 por la firma «el sobre de trigger de popover es el SUELO» (changelog §55). Se resolvió donde estaba el defecto, no aquí: el sobre de popover.css bajó a :where(...) (0,0,0) —tercera aplicación de la ley de §12.9 y §53— y el bloque de esta receta gana ya sus siete propiedades. El chip mide 34×26, radio 9999px, fondo oklch(0.9911 0 0), 12px de letra, 8px de padding: la misma píldora que sus hermanas. Cero claves retiradas y cero añadidas — el número del componente no se mueve, el centinela sigue en 77/81 con las mismas cuatro adjudicadas.

Lo que queda fuera y por qué: cuatro identidades firmadas (§1.4) y siete knobs de sistema transversal (§2, anillo de foco × 4, velo de estado × 2, --opacity-muted del sending). No hay deuda: el componente está CERRADO en su número.

Powered by TurnKey Linux.