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/file-upload.md

14 KiB

file-upload — 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: 83% — 45 de 54 knobs por token público
  • Knobs de apariencia: 56 — público 45 · privado 9 · global 0 · literal 0 · sistema 2 · excepción 4 (los dos últimos, fuera del ratio)
  • Contrato hoy (lib/recipes/base.ts): 98 pública(s) — gap-sm, gap-md, gap-lg, padding-sm, padding-md, padding-lg, control-height-sm, control-height-md, control-height-lg, font-size-sm, font-size-md, font-size-lg, preview-size-sm, preview-size-md, preview-size-lg, font-family, line-height, fg, label-fg, label-font-weight, dropzone-gap, dropzone-min-height, dropzone-border-width, dropzone-border, dropzone-radius, dropzone-bg, dropzone-fg, button-gap, button-padding-inline, button-border-width, button-border, hover-button-border, button-radius, button-fg, hover-button-fg, button-solid-fg, list-gap, item-gap, item-padding, item-border-width, item-border, item-radius, item-bg, item-shadow, preview-radius, preview-bg, preview-fg, item-name-fg, item-name-font-weight, item-size-fg, item-size-font-size, progress-height, progress-radius, progress-track-bg, transition-duration, transition-ease, disabled-opacity, invalid-dropzone-border, primary-solid, primary-solid-hover, primary-text, secondary-solid, secondary-solid-hover, secondary-text, neutral-solid, neutral-solid-hover, neutral-text, affirm-solid, affirm-solid-hover, affirm-text, fulfill-solid, fulfill-solid-hover, fulfill-track, fulfill-border, fulfill-text, risk-solid, risk-solid-hover, risk-text, threat-solid, threat-solid-hover, threat-text, loss-solid, loss-solid-hover, loss-track, loss-border, loss-text, primary-track, primary-border, secondary-track, secondary-border, neutral-track, neutral-border, affirm-track, affirm-border, risk-track, risk-border, threat-track, threat-border · 5 privada(s) forward — _palette-solid, _palette-solid-hover, _palette-track, _palette-border, _palette-text
  • Eje size: sí · ficheros: file-upload.css

1. Knobs fuera de alcance

1.1 Directo a primitivo global (0)

Ninguno.

1.2 A través de un privado (9)

# fichero:línea selector propiedad valor
1 file-upload.css:69 [data-file-upload-dropzone]:hover:not([data-disabled]), [data-file-upload-dropzone][data-dragging] border-color var(--_file-upload-palette-border)
2 file-upload.css:70 [data-file-upload-dropzone]:hover:not([data-disabled]), [data-file-upload-dropzone][data-dragging] background var(--_file-upload-palette-track)
3 file-upload.css:71 [data-file-upload-dropzone]:hover:not([data-disabled]), [data-file-upload-dropzone][data-dragging] color var(--_file-upload-palette-text)
4 file-upload.css:107 [data-file-upload-trigger] border-color var(--_file-upload-palette-solid)
5 file-upload.css:108 [data-file-upload-trigger] background var(--_file-upload-palette-solid)
6 file-upload.css:113 [data-file-upload-trigger]:hover:not([data-disabled]) border-color var(--_file-upload-palette-solid-hover)
7 file-upload.css:114 [data-file-upload-trigger]:hover:not([data-disabled]) background var(--_file-upload-palette-solid-hover)
8 file-upload.css:194 [data-file-upload-item-progress]::before inline-size calc(var(--_file-upload-progress-value, 0) * 1%)
9 file-upload.css:196 [data-file-upload-item-progress]::before background var(--_file-upload-palette-solid)

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 file-upload.css:10 [data-file-upload] inline-size 100%
2 file-upload.css:161 [data-file-upload-item-preview] :where(img, video) inline-size 100%
3 file-upload.css:162 [data-file-upload-item-preview] :where(img, video) block-size 100%
4 file-upload.css:183 [data-file-upload-item-progress] inline-size 100%

2. Sistema transversal (2) — 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 file-upload.css:78 [data-file-upload-dropzone]:focus-visible, [data-file-upload-trigger]:focus-visible, [data-file-upload-item-remove]:focus-visible, [data-file-upload-clear-trigger]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)
2 file-upload.css:125 [data-file-upload-item-remove]:hover:not([data-disabled]), [data-file-upload-clear-trigger]:hover:not([data-disabled]) background-image linear-gradient(var(--state-hover), var(--state-hover))

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

privado declaraciones valor(es) origen ¿deriva de un público?
--_file-upload-gap 3 var(--file-upload-gap-md), var(--file-upload-gap-sm), var(--file-upload-gap-lg) public sí
--_file-upload-padding 3 var(--file-upload-padding-md), var(--file-upload-padding-sm), var(--file-upload-padding-lg) public sí
--_file-upload-control-height 3 var(--file-upload-control-height-md), var(--file-upload-control-height-sm), var(--file-upload-control-height-lg) public sí
--_file-upload-font-size 3 var(--file-upload-font-size-md), var(--file-upload-font-size-sm), var(--file-upload-font-size-lg) public sí
--_file-upload-preview-size 3 var(--file-upload-preview-size-md), var(--file-upload-preview-size-sm), var(--file-upload-preview-size-lg) public sí

Consumidos y no declarados en el CSS (vienen de base.ts o de un estilo inline del wrapper): --_file-upload-palette-border, --_file-upload-palette-solid, --_file-upload-palette-solid-hover, --_file-upload-palette-text, --_file-upload-palette-track, --_file-upload-progress-value.

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

4.2 Sin nombre mecánico (13)

  • ⚠ 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 — 4: inline-size, block-size.
  • ⚠ decisión: el privado que alimenta este knob no se declara en el CSS (viene de base.ts o de un estilo inline) — hay que resolverlo antes de nombrarlo — 9: border-color, background, color, inline-size.

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 — 76 % → 83 %. Una clave acuñada, una retirada con su declaración muerta, cuatro literales firmados y cuarenta y cuatro adjudicaciones medidas (4 propias + 40 por patrón). Diff de computed 0 sobre 11.448 valores en 17 estados y capturas 2× idénticas byte a byte.

invalid-dropzone-border era el único knob que iba a un primitivo global a pelo (--color-risk-border). Lleva la PARTE en el nombre —y no el invalid-border que el catálogo repite seis veces— porque aquí hay TRES partes con borde (dropzone, botón, ítem) y el nombre desnudo no diría cuál tiñe. Su estado no lo alcanza esta ruta: isInvalid sale de un Field envolvente y la demo no monta ninguno, así que se mide forzando el atributo (oklch(0.8059 0.1123 59.96) → rgb(1,2,3)).

⚠ button-bg NO PINTABA, y se retira con su declaración. La regla compartida de los tres botones declaraba background: var(--file-upload-button-bg) y los tres la pisan después: el trigger con el sólido de la paleta (línea 108), ItemRemove y ClearTrigger con transparent (línea 119). Medido sobre los tres nodos, uno a uno: el sentinel no mueve NADA en ninguno (oklch(0.5556 …) y rgba(0,0,0,0) intactos). Es la clase «un token que no mueve nada es un token que miente» de F2-A, y con UNA clave la respuesta es retirar, no adjudicar: retirarla da diff 0, que es la prueba de que estaba muerta. La clave sale del contrato con ella (un público sin consumidor es un huérfano).

Cuatro literales firmados en vez de acuñados, con su anotación en la propia declaración: el 100% del campo (ocupa el ancho que le dan), los dos de la miniatura (img/video LLENAN la caja en la que se recortan) y el de la barra de progreso (ocupa la fila que le da el grid). Identidad, no knob.

⚠⚠ CUARENTA claves de tono no pintan — 8 tonos × 5 ranuras (solid, solid-hover, track, border, text), 40 de sus 98. Es la cascada de paleta: el forward emite AL FINAL un bloque genérico [data-file-upload][data-color] que resuelve desde el --palette-* global, misma especificidad (0,2,0), gana el último. Medido para los ocho tonos sobre las dos superficies que las consumen —el trigger (solid) y el dropzone en hover (track)—: ninguna se mueve, mientras --palette-solid sobre el nodo repinta. Su host es primary y la demo pasa color explícito, así que el fallback tampoco actúa. Adjudicadas por PATRÓN; incidencia de fondo en next-features.md §13.

Los nueve privados se quedan, y ninguno es deuda de valor: ocho son el puente de paleta THM-2 (--_file-upload-palette-* en el hover/arrastre del dropzone, en el trigger y en el relleno de la barra) —un público encima dejaría que un tema fijara el tono y matara el color= de cada instancia— y el noveno es el canal de valor, --_file-upload-progress-value, que file-upload-item-progress.svelte escribe INLINE por fila. Lo que el componente escribe inline no es tema. El techo honesto de este componente no es el 100 %.

Medición: sonda estándar 0 diffs (4.608 valores · 8 estados · 19 nodos, la demo arranca con dos ficheros sembrados, así que monta la superficie entera) más un barrido de estados que la ruta no arranca —3 variantes × 3 tallas, invalid, disabled y dragging— con el CSS de HEAD inyectado en la página como control (gana por orden a igual especificidad): 0 diffs sobre 6.840 valores. El instrumento pasó su muta-prueba: alterando el CSS de control acusa 19 diffs, y 1 si sólo se altera el borde inválido.

Nota 2026-08-24 — FIRMA: la receta deja de BARRER DESCENDIENTES. La regla de disabled (file-upload.css:200-218) escribía [data-file-upload][data-disabled], [data-file-upload] [data-disabled]. La segunda mitad, (0,2,0), vestía TODO nodo deshabilitado bajo el provider —los ajenos incluidos— y ganaba el empate por orden de emisión. Única ocurrencia de ese patrón en las 171 recetas del árbol. Pasa a cinco selectores por parte propia (label, dropzone, trigger, item-remove, clear-trigger), con la mitad del provider intacta y la misma especificidad.

Se pudo retirar entera porque el morfo declara data-disabled en 6 partes y soma lo escribe en esos 6 nodos exactos, siempre junto a su data-file-upload-{parte}: el barrido no alcanzaba ni un nodo propio que un selector por parte no alcance. Verificado en runtime — las 6 partes conservan opacity: 0.4 y cursor: default. Este componente NO se mueve: sonda estándar 0 diffs (4.608 valores · 8 estados) y 0 de 35 valores en el estado disabled medido aparte (la sonda compartida no tiene paso disabled). image-picker, el otro consumidor de sus partes, 0 de 15. Lo que se movió es el huésped: ver chat-composer.md. Centinela 61/98, exit 0. Detalle en §8 de PLAN-theming.md.

Powered by TurnKey Linux.