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/image-picker.md

7.6 KiB

image-picker — 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-24 · Alcance: 100% — 13 de 13 knobs por token público
  • Knobs de apariencia: 16 — público 13 · privado 0 · global 0 · literal 0 · sistema 3 · excepción 4 (los dos últimos, fuera del ratio)
  • Contrato hoy (lib/recipes/base.ts): 14 pública(s) — gap, preview-radius, preview-bg, preview-border, preview-aspect, toolbar-gap, toolbar-inset, button-size, button-bg, button-fg, button-border, button-radius, button-font-size, hover-button-bg
  • Eje size: no · ficheros: image-picker.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 image-picker.css:45 [data-image-picker-canvas] > * inline-size 100%
2 image-picker.css:46 [data-image-picker-canvas] > * block-size 100%
3 image-picker.css:79 [data-image-picker-rotate], [data-image-picker-remove] line-height 1
4 image-picker.css:109 [data-image-picker-rotate]:focus-visible, [data-image-picker-remove]:focus-visible outline-color Highlight

2. Sistema transversal (3) — 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 image-picker.css:19 [data-image-picker][data-disabled] opacity var(--opacity-disabled)
2 image-picker.css:90 [data-image-picker-rotate]:focus-visible, [data-image-picker-remove]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)
3 image-picker.css:96 [data-image-picker-rotate][disabled], [data-image-picker-remove][disabled] opacity var(--opacity-disabled)

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

La receta no declara privados propios en su CSS.

4. Propuesta de corrección

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

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 (--image-picker-…) scope TSC valor propuesto usos

4.2 Sin nombre mecánico (4)

  • ⚠ decisión: 100% 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 — 2: inline-size, block-size.
  • ⚠ 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 — 1: line-height.
  • foco: lo posee el sistema (--focus-ring-*, theming §32) — no acuñar token propio — 1: outline-color.

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-23 — 71 % → 100 %, una clave nueva y cuatro literales firmados. Diff de computed 0 sobre 1.344 valores en 7 estados (6 nodos); R-5.4 de 13/13 a 14/14 sin una sola adjudicación; capturas 2× antes/después idénticas.

El instrumento medía UN nodo. El picker arranca VACÍO —un dropzone de FileUpload— y todo lo que la receta pinta (preview, canvas, toolbar y los dos botones de icono) sólo existe en el estado ready, al que no llega ningún trigger: hay que cargar un fichero. Con el chip «Load sample image» de la demo la sonda pasa de 1 a 6 nodos. Sonda (DEMO_VARIANTS) y centinela (prepareWith) llevan ya el interruptor; el centinela además necesita openMarker para que su re-apertura por token no vuelva a pulsar el chip y remonte la vista previa a mitad de corrida.

La única clave: hover-button-bg. Era el único knob que iba a un primitivo global a pelo (--color-surface-default). La §4 lo nombraba hover-rotate-bg por el PRIMER selector de la regla, y miente dos veces: pinta rotate y remove, y el contrato de este componente ya llama button-* a ese par desde que nació. El catálogo decide — hover-{parte}-{slot} es la forma de las 60 claves hover-* de base.ts.

No es el velo del sistema, y por eso se acuña. Los dos botones flotan SOBRE la foto: su relleno de reposo es translúcido (color-mix(… 88%, transparent)) y el hover lo vuelve OPACO — un cambio de RELLENO, no una capa encima. Medido desde el píxel hacia arriba con las transiciones congeladas: el cambio cae en el <button> (el nodo con forma, radio 6 px, srgb .988/.88 → oklch(.9911 0 0)) y ningún ancestro recibe background-image, porque el arquetipo action no trae velo — archetypes.css sólo vela trigger, item y option. No se está bendiciendo un duplicado, que es lo que paró el hover-* de listbox.

Los cuatro literales se firman, no se acuñan (válvula de recipe-contract §3): el 100% doble del hijo del canvas es identidad (la <Image> ES la caja del canvas, que ya está en inset: 0), el line-height: 1 es un botón de un solo glifo, y el Highlight de forced-colors es la paleta del sistema operativo — un valor de tema ahí lo sustituiría el UA, que es justo lo que ese modo hace.

Fuera del ratio por doctrina: --opacity-disabled (×2) y el par --focus-ring-* son de la capa de sistema (theming §32).

Sin eje size y es correcto: la prop size del wrapper viaja al ImageAdjustments embebido; este cromo de orquestación no escala.

⚠ Un defecto real, ANOTADO, no arreglado: ese hover neutro es una invención por componente, y §38 / R-4.3 mandan que el hover neutro sea la capa --state-*. Migrarlo cambia el default (velo translúcido en vez de relleno opaco) y D-TH.5 lo prohíbe dentro de este eje. Queda escrito aquí y en el README del componente. Nota para quien lo firme: el arquetipo del par es action, que HOY no recibe velo del sistema, así que la migración no es sólo cambiar la receta — o action gana velo en archetypes.css (mueve píxel en todos los action del catálogo) o el par cambia de arquetipo, que es morfo.

Powered by TurnKey Linux.