|
|
|
|
[data-slider] {
|
|
|
|
|
--_slider-track-size: var(--slider-track-size-md);
|
|
|
|
|
--_slider-thumb-size: var(--slider-thumb-size-md);
|
|
|
|
|
--_slider-hit-size: var(--slider-hit-size-md);
|
|
|
|
|
--_slider-tick-size: var(--slider-tick-size-md);
|
|
|
|
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
eidos: theming fixes + size/variant parity batch + docs
- theme: add surface.muted + content.muted to color contract (neutral-3
+ neutral-10). Plugs 17 broken --color-content-muted and 3 broken
--color-surface-muted references in recipes/components.
- form.css: fix --color-neutral-element-hover typo → --color-neutral-hover.
- archetypes.css + events.css: replace raw hsl/rgba indigo with
color-mix(var(--color-primary-solid) …) — no raw colors left in eidos.
- combobox dark scrollbar: unscope ::-webkit-scrollbar rules in uix.css
and duplicate --uix-line on :root + :root[data-mode='dark'] so portaled
overlays (Combobox listbox, Popover, Dialog, Drawer) inherit the theme.
- sizes: 20 components expand from sm/md/lg to xs..xl (form controls,
text inputs, progress/meter, field/form) or xs..lg (nav controls:
breadcrumb, pagination, tag-group, toolbar). Composite panels keep
sm/md/lg deliberately.
- variants: field + toolbar drop arbitrary ControlVariant narrowings;
both expose all 3 (surface | outline | ghost) with new outline CSS.
- pagination demo: disambiguate siblingCount/boundaryCount as "per side"
in label + API table (Radix/MUI convention).
- docs: CHECKLIST §C-2.6 (contract token presence) + §D-7.4 (chip parity)
+ §D-7.5 (size category) added. DEMO_AUTHORING §12.7 (chip parity) +
§12.8 (size category cheatsheet) added. eidos/README +
active_architecture.md sync texts/migration nomenclature.
- PENDIENTES.md: normas N-1..N-5 implantadas en esta sesión.
Verification: 88/88 eidos tests, 0 type errors, 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
[data-slider][data-size='xs'] {
|
|
|
|
|
--_slider-track-size: var(--slider-track-size-xs);
|
|
|
|
|
--_slider-thumb-size: var(--slider-thumb-size-xs);
|
|
|
|
|
--_slider-hit-size: var(--slider-hit-size-xs);
|
|
|
|
|
--_slider-tick-size: var(--slider-tick-size-xs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider][data-size='sm'] {
|
|
|
|
|
--_slider-track-size: var(--slider-track-size-sm);
|
|
|
|
|
--_slider-thumb-size: var(--slider-thumb-size-sm);
|
|
|
|
|
--_slider-hit-size: var(--slider-hit-size-sm);
|
|
|
|
|
--_slider-tick-size: var(--slider-tick-size-sm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider][data-size='lg'] {
|
|
|
|
|
--_slider-track-size: var(--slider-track-size-lg);
|
|
|
|
|
--_slider-thumb-size: var(--slider-thumb-size-lg);
|
|
|
|
|
--_slider-hit-size: var(--slider-hit-size-lg);
|
|
|
|
|
--_slider-tick-size: var(--slider-tick-size-lg);
|
|
|
|
|
}
|
|
|
|
|
|
eidos: theming fixes + size/variant parity batch + docs
- theme: add surface.muted + content.muted to color contract (neutral-3
+ neutral-10). Plugs 17 broken --color-content-muted and 3 broken
--color-surface-muted references in recipes/components.
- form.css: fix --color-neutral-element-hover typo → --color-neutral-hover.
- archetypes.css + events.css: replace raw hsl/rgba indigo with
color-mix(var(--color-primary-solid) …) — no raw colors left in eidos.
- combobox dark scrollbar: unscope ::-webkit-scrollbar rules in uix.css
and duplicate --uix-line on :root + :root[data-mode='dark'] so portaled
overlays (Combobox listbox, Popover, Dialog, Drawer) inherit the theme.
- sizes: 20 components expand from sm/md/lg to xs..xl (form controls,
text inputs, progress/meter, field/form) or xs..lg (nav controls:
breadcrumb, pagination, tag-group, toolbar). Composite panels keep
sm/md/lg deliberately.
- variants: field + toolbar drop arbitrary ControlVariant narrowings;
both expose all 3 (surface | outline | ghost) with new outline CSS.
- pagination demo: disambiguate siblingCount/boundaryCount as "per side"
in label + API table (Radix/MUI convention).
- docs: CHECKLIST §C-2.6 (contract token presence) + §D-7.4 (chip parity)
+ §D-7.5 (size category) added. DEMO_AUTHORING §12.7 (chip parity) +
§12.8 (size category cheatsheet) added. eidos/README +
active_architecture.md sync texts/migration nomenclature.
- PENDIENTES.md: normas N-1..N-5 implantadas en esta sesión.
Verification: 88/88 eidos tests, 0 type errors, 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
[data-slider][data-size='xl'] {
|
|
|
|
|
--_slider-track-size: var(--slider-track-size-xl);
|
|
|
|
|
--_slider-thumb-size: var(--slider-thumb-size-xl);
|
|
|
|
|
--_slider-hit-size: var(--slider-hit-size-xl);
|
|
|
|
|
--_slider-tick-size: var(--slider-tick-size-xl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider][data-disabled] {
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
opacity: var(--slider-disabled-opacity);
|
|
|
|
|
}
|
|
|
|
|
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
/* Readonly — value visible, thumb stays focusable, NOT dimmed (distinct from
|
|
|
|
|
disabled). Just drops the grab/edit cursor; the value lock lives in soma. */
|
|
|
|
|
[data-slider][data-readonly] {
|
|
|
|
|
cursor: default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-thumb][data-readonly],
|
|
|
|
|
[data-slider-thumb][data-readonly]:active {
|
|
|
|
|
cursor: default;
|
|
|
|
|
scale: 1;
|
|
|
|
|
}
|
|
|
|
|
|
fix(slider,media-player): el anillo del commit no enmarca contenedores, y saltar al final no es completar
Cuatro defectos que solo aparecieron cuando el usuario MIRO la pagina.
1) EL BORDE DE LOS SLIDERS ("se viene arrastrando desde el principio").
No era del arquetipo ni del slider: es la firma GLOBAL de la familia
commit. BUILTIN_SIGNATURES.commit monta commit-settle, cuyo 30% pinta
box-shadow 0 0 0 3px. El commit-set del Slider apunta al PROVIDER, asi que
cada paso de flecha y cada release dibujaban un aro alrededor de la caja
entera (medido en vivo: 544x40). Un aro lee como feedback en un boton y
como borde parasito en un rail ancho y transparente. Exencion acotada en
slider.css — el patron que gradient-builder.css ya practicaba. Alcanza a
todo slider embebido (waveform, media-player, color-picker, time-picker)
porque todos llevan [data-slider]. `animation` es la palanca, no
`box-shadow`: las declaraciones de keyframe ganan a las normales, asi que
solo reiniciar el NOMBRE de la animacion detiene la pintura.
2) EL MISMO ANILLO EN EL PLAYER: commit-complete / commit-fail apuntan al
provider -> borde alrededor de los ~700px del reproductor. Misma exencion
en media-player.css. Los botones conservan su aro pequeno (20x36), que es
donde el feedback pertenece.
3) SALTAR AL FINAL ANUNCIABA UNA COMPLECION FALSA. Los botones de salto no
tienen evento propio: seek() delega a proposito (D-AP2.13, "el release del
scrubber ya ES el commit-set del Slider") — cierto para el scrubber y
VACIO para los botones, que no tienen Slider detras. Al saltar mas alla del
final el elemento dispara `ended` -> commit-complete en el provider ->
sonido (es audible por D-AP2.7) + anillo, mientras el boton de retroceso
quedaba mudo. Saltar al final no es completar: es abandonar la obra en el
final. seek()/scrubTo() marcan el salto que aterriza en el final y `ended`
no anuncia; un `play` posterior limpia la marca, asi que el final natural
se sigue anunciando. Los dos botones quedan simetricos y mudos, que es la
doctrina del transporte.
4) MEDIASESSION SIN OVERLAY DEL SO: el modo audio YA funcionaba (metadata
completa, medida en vivo); el roto era VIDEO, el modo por defecto de la
demo. <AudioPlayer> deriva metadata de title/artist/artwork; el
<MediaPlayer> compositivo no puede leer su hijo Title sin volverse
data-driven, asi que la declara el consumidor — y la demo no lo hacia.
El arreglo es de la demo; el art se comporta como D-SR.6/D-AP2.5 lo firmo.
Guard nuevo (no anunciar compleccion al saltar al final; si al final
natural) VISTO EN ROJO antes de darlo por bueno.
Nota de doctrina, tras leer el corpus a peticion del usuario: la exencion
acotada en la receta ES la puerta, no un olor. motion.md §4 fija que la
firma es generica por decision estructural ("un commit asienta igual en
todo el sistema"), eidos es el UNICO dueno del canal visual, los packs de
sema solo transportan sound/haptic, y el VisualChannel no consulta
activeChannels — no hay palanca declarativa para callar solo lo visual.
Queda anotado, menor: commit-settle escribe 3px a pelo donde sus hermanos
announce-pulse-* usan var(--focus-ring-width).
Verificado: check 75 = baseline, 0 propios; 11/11 media-player;
motion.test.ts verde (la firma global intacta); sonda en Chrome vivo —
slider real -> animation none, elemento no-slider con el mismo sello ->
sigue commit-settle, aro de foco intacto.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
/* The global `commit` firma pulses a 3px primary box-shadow RING on whatever the
|
|
|
|
|
commit event targets. Our `commit-set` targets the PROVIDER, so every arrow
|
|
|
|
|
step and every drag release drew a border around the WHOLE control — a ring
|
|
|
|
|
reads as feedback on a small box, as a stray border on a wide thin rail. Kill
|
|
|
|
|
the VISUAL ring here (the sound/haptic firma is unaffected — it runs in JS,
|
|
|
|
|
not CSS); the value change is itself the visible confirmation. Same opt-out as
|
|
|
|
|
gradient-builder.css, and it reaches every embedded slider (media-player,
|
|
|
|
|
waveform, color-picker, time-picker…) because they all carry [data-slider].
|
|
|
|
|
`animation` is the lever, not `box-shadow`: keyframed declarations outrank
|
|
|
|
|
normal ones, so only resetting the animation NAME stops the paint. */
|
|
|
|
|
[data-slider][data-event-family='commit'][data-event-phase='active'] {
|
|
|
|
|
animation: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider][data-orientation='horizontal'] {
|
uix(slider): temable — 97 % → 100 %, y con un solo valor el tick ACTIVO no existe
CERO claves acuñadas. El componente llegaba con `global` a cero, `private` a
cero —sus cuatro privados son la escala por talla, que ya deriva de públicos— y
treinta y nueve claves cubriendo su cromo entero; lo único fuera de alcance era
UN literal. Este commit lo firma, adjudica sus siete silenciosas y escribe los
artefactos que le faltaban.
QUÉ ENTRA
- **El literal se firma como identidad**: `inline-size: 100%` en
`[data-slider][data-orientation='horizontal']` — un rail ocupa su contenedor.
El knob de verdad ya existe y es su SUELO: `min-inline-size`. Mismo
precedente que `separator.css:26`, cerrado el mismo día también sin acuñar.
- **Siete adjudicaciones en el ledger**, todas MEDIDAS sobre los nodos reales,
con `transition` congelada salvo donde el token ES la transición:
- `min-block-size` — sólo la lee `[data-orientation='vertical']` y el
escenario arranca horizontal. Con el chip de orientación: 160px -> 1234px.
- `active-thumb-scale` / `active-thumb-shadow` — el pickup vive en
`[data-slider-thumb]:active`, que pide el puntero MANTENIDO, y el pase
estático del guard lo aparca. Con `mouse.down()` real sobre el thumb real:
scale 1.15 -> 4.56, y la sombra sigue al centinela.
- `active-tick-bg` — un tick lleva `data-active` sólo mientras su valor cae
DENTRO de [min(valores), max(valores)] (soma, `SliderTickProvider.isActive`),
así que un pulgar único en 40 con ticks en 0/50/100 deja los tres inactivos:
la marca activa no es un estado del tick, es una RELACIÓN CON EL RANGO. Con
el chip `multiple` (20–80) el tick 50 se activa y el token alcanza.
- `disabled-opacity` — el escenario arranca habilitado; con su interruptor,
0.4 -> 0.123.
- `transition-duration` / `transition-ease` — SON la transición que el guard
congela; medidos sin congelar, 0.12s -> 11.5s y steps(4).
- README con su sección «Talla y tema» (39 claves por grupo, con la distinción
`hit-size-{k}` = agarre vs `track-size-{k}` = pintura) y veredicto §5 de la
ficha con las cifras.
QUÉ NO SE TOCA
- **Nada se retira ni se renombra**, y no es prudencia: este contrato lo COMPONEN
otros SIETE componentes que re-tiñen o re-dimensionan estas mismas claves sobre
su Slider embebido — `media-player`, `skin-media-player`, `waveform` (su
playhead ES este thumb), `color-picker`, `gradient-builder`,
`image-adjustments` y `time-range-picker`. `min-block-size`, que el centinela
leía muerta, es justo la que `media-player` escribe para su volumen vertical.
- `base.ts` y `generated/base.css`: sin cambio de contrato no hay nada que
regenerar. 39 -> 39 claves.
ARTEFACTOS
- Censo: 97 % (33 knobs · 31 públicos · 1 literal · 1 sistema) -> **100 %**
(32 · 31 · 0 literal · 1 excepción · 1 sistema). Global 68 %, no baja.
- Sonda antes/después: **0 diffs sobre 1.376 valores computados**, 7 estados,
7 nodos (raíz · secondary-range · range · thumb · 3 ticks).
- Captura 2× antes y después: idénticas.
- Centinela R-5.4: **32/39**, las 7 restantes adjudicadas -> verde.
- component-audit PASS · eidos-lint 25 morfo-backed / 5 eidos-only / **0
invalid** · `vitest run src/uix/eidos` 35/36 ficheros (el rojo conocido es
`skin-media-player`) · rtl:check 0 · docs:check 0.
- `npm run check`: UN error en `web/routes/uix/components/slider/+page.svelte`
(`Property 'keyboard' does not exist`, línea del `sliderMorfo.parts[2]`),
**PREEXISTENTE** desde `1857c7854` y ajeno a este commit; ningún otro error en
ficheros de slider.
- Prettier: los hunks de deriva del fichero son los MISMOS que en HEAD (2 en el
README, 0 en el CSS); mi bloque no añade ninguno.
NOTA DE CONCURRENCIA: la pestaña `Tokens` de su demo (paso 11 del protocolo) la
escribí yo, pero entró en HEAD por `9fc38b19a` + `c88b2f861` de otra sesión, que
la arrastró con un `git add` derivado y lo declaró. No se re-commitea aquí.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
inline-size: 100%; /* literal: a rail spans its container — identity; its floor is `min-inline-size` */
|
|
|
|
|
block-size: var(--_slider-hit-size);
|
|
|
|
|
min-inline-size: var(--slider-min-inline-size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider][data-orientation='vertical'] {
|
|
|
|
|
inline-size: var(--_slider-hit-size);
|
|
|
|
|
block-size: var(--slider-min-block-size);
|
|
|
|
|
min-block-size: var(--slider-min-block-size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider]::before {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
border-radius: var(--slider-track-radius);
|
|
|
|
|
background: var(--slider-track-bg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider][data-orientation='horizontal']::before {
|
|
|
|
|
inset-inline: 0;
|
|
|
|
|
inset-block-start: 50%;
|
|
|
|
|
block-size: var(--_slider-track-size);
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
}
|
|
|
|
|
|
fix(direction): getDir() no era reactivo, y 33 componentes estampaban su valor congelado
El slider no respondia al cambio rtl/ltr. Resultaron ser dos defectos
independientes, y el segundo era del ecosistema entero.
1) EL SLIDER. slider.css emparejaba un inset LOGICO con un transform
FISICO en las tres reglas verticales (inset-inline-start: 50% +
translateX(-50%)). Los transforms no se voltean, asi que en RTL el rail y
el relleno quedaban fuera de eje un ancho entero. Medido en Chrome:
raiz/pulgar/ticks en x=961, rail y relleno en x=955. El Tick se libraba
porque ya usaba margin-inline-start — ese era el idioma correcto del
propio fichero y es el que aplico. Mismo defecto en accordion.css:
text-align: left en el trigger, que era el UNICO text-align fisico de
todo eidos; ahora quedan cero.
2) LA RAIZ. makeDimension().get() leia engine.snapshot() esquivando la
celda $state, asi que prefs.<dim>.get() — y con ella el
soma.prefs.getDir() que la guia manda usar — era una lectura sin
tracking. Los ~64 componentes que resuelven su direccion desde prefs la
congelaban al montarse. La proyeccion DOM se salvaba porque usa
onChange: misma dimension, dos caminos de lectura, solo uno reactivo.
Arreglado con un contador de cambios POR dimension, bombeado desde el
effectiveDiff que el motor ya calcula, de modo que cubre tambien el
cambio por DERIVACION (direction siguiendo a language) y no solo el
intent. Un contador por clave y no una celda global: con una sola celda,
tocar motion despertaria las 64 derivaciones de direccion. El test
negativo lo clava.
3) VALOR NO ES AFIRMACION. 33 de 37 componentes estampaban dir en su raiz
con un valor siempre concreto, asi que una app que ponga html dir=rtl sin
registrar la preferencia se encontraba 33 islas volteadas del reves.
Investigadas las cinco librerias de referencia: MUI y react-aria no
estampan nunca, Radix estampa siempre (sus mantenedores arrastran
discussions/1405 por esto), y Zag estampa prop("dir") — presente si
alguien lo pidio, ausente si no. Adoptado el modelo de Zag pero uniforme:
el atributo NUNCA tiene defecto. La herencia la hace el navegador por
AUSENCIA de atributo, sin ninguna lectura del DOM, asi que la cadena
prop -> prefs -> 'ltr' se queda intacta.
4) HOMOGENEIDAD. Habia DIEZ formas distintas de resolver lo mismo en los
wrappers y CINCO de declarar el tipo, con un cuarto escalon semantico
—heredar del menu padre— enterrado en dos expresiones sueltas.
Normalizado a activeDir(getter, soma) en los 36, un solo tipo
Direction | undefined, y el escalon de los submenus declarado en la
llamada, donde se ve.
5) LA SHELL. El toggle de direccion pasa de 2 a 3 estados: auto hace
clearIntent, que es lo unico que deja ganar al derive. Y entra el arabe
en el catalogo de idiomas, porque sin un idioma RTL la derivacion no era
disparable. Con las dos cosas, elegir arabe voltea la direccion sin tocar
el control — la cadena documentada funcionando de punta a punta por
primera vez.
Verificado: check 74 = linea base exacta, cero nuevos. 602/602 tests en
101 ficheros. En Chrome real: el topbar mueve al slider y al accordion en
vivo, y el arabe voltea por derivacion.
QUEDA: 48 demos siguen clavando dir='ltr'; el interrogante desplazado del
accordion necesita dir="ltr" lang="en" en el contenedor de la demo (no es
un fallo nuestro, es bidi correcto sobre texto ingles en parrafo RTL);
html lang no sigue al idioma; smoke y perm:check sin ejecutar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
/* Centring on the inline axis is a LOGICAL offset (`margin-inline-start`), never
|
|
|
|
|
`translateX(-50%)`: transforms are physical, so pairing one with
|
|
|
|
|
`inset-inline-start` centres in LTR and lands a full track-width off-axis in
|
|
|
|
|
RTL. Same idiom the Tick already used below. */
|
|
|
|
|
[data-slider][data-orientation='vertical']::before {
|
|
|
|
|
inset-block: 0;
|
|
|
|
|
inset-inline-start: 50%;
|
|
|
|
|
inline-size: var(--_slider-track-size);
|
fix(direction): getDir() no era reactivo, y 33 componentes estampaban su valor congelado
El slider no respondia al cambio rtl/ltr. Resultaron ser dos defectos
independientes, y el segundo era del ecosistema entero.
1) EL SLIDER. slider.css emparejaba un inset LOGICO con un transform
FISICO en las tres reglas verticales (inset-inline-start: 50% +
translateX(-50%)). Los transforms no se voltean, asi que en RTL el rail y
el relleno quedaban fuera de eje un ancho entero. Medido en Chrome:
raiz/pulgar/ticks en x=961, rail y relleno en x=955. El Tick se libraba
porque ya usaba margin-inline-start — ese era el idioma correcto del
propio fichero y es el que aplico. Mismo defecto en accordion.css:
text-align: left en el trigger, que era el UNICO text-align fisico de
todo eidos; ahora quedan cero.
2) LA RAIZ. makeDimension().get() leia engine.snapshot() esquivando la
celda $state, asi que prefs.<dim>.get() — y con ella el
soma.prefs.getDir() que la guia manda usar — era una lectura sin
tracking. Los ~64 componentes que resuelven su direccion desde prefs la
congelaban al montarse. La proyeccion DOM se salvaba porque usa
onChange: misma dimension, dos caminos de lectura, solo uno reactivo.
Arreglado con un contador de cambios POR dimension, bombeado desde el
effectiveDiff que el motor ya calcula, de modo que cubre tambien el
cambio por DERIVACION (direction siguiendo a language) y no solo el
intent. Un contador por clave y no una celda global: con una sola celda,
tocar motion despertaria las 64 derivaciones de direccion. El test
negativo lo clava.
3) VALOR NO ES AFIRMACION. 33 de 37 componentes estampaban dir en su raiz
con un valor siempre concreto, asi que una app que ponga html dir=rtl sin
registrar la preferencia se encontraba 33 islas volteadas del reves.
Investigadas las cinco librerias de referencia: MUI y react-aria no
estampan nunca, Radix estampa siempre (sus mantenedores arrastran
discussions/1405 por esto), y Zag estampa prop("dir") — presente si
alguien lo pidio, ausente si no. Adoptado el modelo de Zag pero uniforme:
el atributo NUNCA tiene defecto. La herencia la hace el navegador por
AUSENCIA de atributo, sin ninguna lectura del DOM, asi que la cadena
prop -> prefs -> 'ltr' se queda intacta.
4) HOMOGENEIDAD. Habia DIEZ formas distintas de resolver lo mismo en los
wrappers y CINCO de declarar el tipo, con un cuarto escalon semantico
—heredar del menu padre— enterrado en dos expresiones sueltas.
Normalizado a activeDir(getter, soma) en los 36, un solo tipo
Direction | undefined, y el escalon de los submenus declarado en la
llamada, donde se ve.
5) LA SHELL. El toggle de direccion pasa de 2 a 3 estados: auto hace
clearIntent, que es lo unico que deja ganar al derive. Y entra el arabe
en el catalogo de idiomas, porque sin un idioma RTL la derivacion no era
disparable. Con las dos cosas, elegir arabe voltea la direccion sin tocar
el control — la cadena documentada funcionando de punta a punta por
primera vez.
Verificado: check 74 = linea base exacta, cero nuevos. 602/602 tests en
101 ficheros. En Chrome real: el topbar mueve al slider y al accordion en
vivo, y el arabe voltea por derivacion.
QUEDA: 48 demos siguen clavando dir='ltr'; el interrogante desplazado del
accordion necesita dir="ltr" lang="en" en el contenedor de la demo (no es
un fallo nuestro, es bidi correcto sobre texto ingles en parrafo RTL);
html lang no sigue al idioma; smoke y perm:check sin ejecutar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
margin-inline-start: calc(var(--_slider-track-size) / -2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-range] {
|
|
|
|
|
border-radius: var(--slider-track-radius);
|
|
|
|
|
background: var(--slider-range-bg);
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-range][data-orientation='horizontal'] {
|
|
|
|
|
inset-block-start: 50%;
|
|
|
|
|
block-size: var(--_slider-track-size);
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-range][data-orientation='vertical'] {
|
|
|
|
|
inset-inline-start: 50%;
|
|
|
|
|
inline-size: var(--_slider-track-size);
|
fix(direction): getDir() no era reactivo, y 33 componentes estampaban su valor congelado
El slider no respondia al cambio rtl/ltr. Resultaron ser dos defectos
independientes, y el segundo era del ecosistema entero.
1) EL SLIDER. slider.css emparejaba un inset LOGICO con un transform
FISICO en las tres reglas verticales (inset-inline-start: 50% +
translateX(-50%)). Los transforms no se voltean, asi que en RTL el rail y
el relleno quedaban fuera de eje un ancho entero. Medido en Chrome:
raiz/pulgar/ticks en x=961, rail y relleno en x=955. El Tick se libraba
porque ya usaba margin-inline-start — ese era el idioma correcto del
propio fichero y es el que aplico. Mismo defecto en accordion.css:
text-align: left en el trigger, que era el UNICO text-align fisico de
todo eidos; ahora quedan cero.
2) LA RAIZ. makeDimension().get() leia engine.snapshot() esquivando la
celda $state, asi que prefs.<dim>.get() — y con ella el
soma.prefs.getDir() que la guia manda usar — era una lectura sin
tracking. Los ~64 componentes que resuelven su direccion desde prefs la
congelaban al montarse. La proyeccion DOM se salvaba porque usa
onChange: misma dimension, dos caminos de lectura, solo uno reactivo.
Arreglado con un contador de cambios POR dimension, bombeado desde el
effectiveDiff que el motor ya calcula, de modo que cubre tambien el
cambio por DERIVACION (direction siguiendo a language) y no solo el
intent. Un contador por clave y no una celda global: con una sola celda,
tocar motion despertaria las 64 derivaciones de direccion. El test
negativo lo clava.
3) VALOR NO ES AFIRMACION. 33 de 37 componentes estampaban dir en su raiz
con un valor siempre concreto, asi que una app que ponga html dir=rtl sin
registrar la preferencia se encontraba 33 islas volteadas del reves.
Investigadas las cinco librerias de referencia: MUI y react-aria no
estampan nunca, Radix estampa siempre (sus mantenedores arrastran
discussions/1405 por esto), y Zag estampa prop("dir") — presente si
alguien lo pidio, ausente si no. Adoptado el modelo de Zag pero uniforme:
el atributo NUNCA tiene defecto. La herencia la hace el navegador por
AUSENCIA de atributo, sin ninguna lectura del DOM, asi que la cadena
prop -> prefs -> 'ltr' se queda intacta.
4) HOMOGENEIDAD. Habia DIEZ formas distintas de resolver lo mismo en los
wrappers y CINCO de declarar el tipo, con un cuarto escalon semantico
—heredar del menu padre— enterrado en dos expresiones sueltas.
Normalizado a activeDir(getter, soma) en los 36, un solo tipo
Direction | undefined, y el escalon de los submenus declarado en la
llamada, donde se ve.
5) LA SHELL. El toggle de direccion pasa de 2 a 3 estados: auto hace
clearIntent, que es lo unico que deja ganar al derive. Y entra el arabe
en el catalogo de idiomas, porque sin un idioma RTL la derivacion no era
disparable. Con las dos cosas, elegir arabe voltea la direccion sin tocar
el control — la cadena documentada funcionando de punta a punta por
primera vez.
Verificado: check 74 = linea base exacta, cero nuevos. 602/602 tests en
101 ficheros. En Chrome real: el topbar mueve al slider y al accordion en
vivo, y el arabe voltea por derivacion.
QUEDA: 48 demos siguen clavando dir='ltr'; el interrogante desplazado del
accordion necesita dir="ltr" lang="en" en el contenedor de la demo (no es
un fallo nuestro, es bidi correcto sobre texto ingles en parrafo RTL);
html lang no sigue al idioma; smoke y perm:check sin ejecutar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
margin-inline-start: calc(var(--_slider-track-size) / -2);
|
|
|
|
|
}
|
|
|
|
|
|
feat(sound): $sound orquestador (buses+voces+media) y player v2 F1-F3 sobre el servicio
Rediseno clean-room del sonido (gate D-SR.1-12 firmado; la doctrina "la voz
es del art" de PLAN-sound-engine s16.1 queda revocada):
- Mezcla: master -> buses ui/content (gain/mute/duck refcount, gana la mas
fuerte; politica pre-contexto). prefs de UI jamas tocan la obra.
- Voces registradas: la calibracion es DATO del consumidor (sema registra
'sema'; el default conserva la calibracion historica - cero cambio audible,
A/B del usuario: "suena igual").
- Ciudadania de media: sound.media(el) PROVEE el transporte (la forma exacta
del puerto MediaProvider) + foco mixed/exclusive/duck PERSISTENTE (estado
derivado; el ducker mas reciente retiene la palabra) + duckUiWhileContent +
MediaSession de la fuente activa (play/pause/seekto + posicion, liberacion
y promocion) + visibilidad content-aware + attach() opt-in (irreversible,
CORS declarado). Re-registro idempotente por elemento.
- diagnostics.ts con catalogo tipado (contrato de arts) y guards post-dispose
(ningun camino abre un contexto huerfano). Auditoria AU-1..9 resuelta;
bundle medido: 16,2 KB min / 5,6 KB gz.
Player v2 (gate D-AP2.1-13 firmado) F1-F3:
- F1 gaps de framework: aria-valuetext en Slider (valueText por thumb) +
parte SecondaryRange con token --slider-secondary-bg (buffer/clip/capitulos)
+ formatDuration en $libs/days + fix del selector del pack (H-1: la regla
de play/pause construia sobre provider y el stamp aterriza en play-button).
- F2 morfo: 6 partes audio-only (artwork/artist/identity/transport/
rate-button/live-indicator), commit-set-rate, commit-set-time RETIRADO
(D-AP2.13: el scrubber delega en el commit-set del Slider compuesto),
sustain-loading cableado (H-9), teclado j/l, </> y 0-9 (con guard de
modificadores para no pisar atajos del navegador).
- F3 la migracion: el transporte default es uix.sound.media(el, {metadata})
(pineado con el motor real); nativeMediaProvider RETIRADO (media-provider.ts
queda como contrato puro del puerto, sin shim); G-5: los commits de
play/mute/rate cabalgan el evento de RESULTADO (play/pause saltando el
pause de ended, volumechange con transicion de muted, ratechange);
formatTime -> formatDuration; sub-providers + wrappers + exports de las 6
partes; prop metadata publica (captura al registrar, documentado).
Verificacion: 45 suites / 458 tests verdes en el alcance (sound, sema,
active-uix, active-app, morfo, slider, media-player, days) - check 74 =
baseline de la rama, 0 propios - docs:check 0 - invariante de UN AudioContext
intacta (e2e sin tocar). Planes de proceso y handoff al dia
(PLAN-sound-redesign, PLAN-audio-player-v2, CONTINUE-sound-engine).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
/* Secondary track (buffer / preloaded region) — same geometry as the range,
|
|
|
|
|
layered UNDER it (source order: the range is painted after and on top). */
|
|
|
|
|
[data-slider-secondary-range] {
|
|
|
|
|
border-radius: var(--slider-track-radius);
|
|
|
|
|
background: var(--slider-secondary-bg);
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-secondary-range][data-orientation='horizontal'] {
|
|
|
|
|
inset-block-start: 50%;
|
|
|
|
|
block-size: var(--_slider-track-size);
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-secondary-range][data-orientation='vertical'] {
|
|
|
|
|
inset-inline-start: 50%;
|
|
|
|
|
inline-size: var(--_slider-track-size);
|
fix(direction): getDir() no era reactivo, y 33 componentes estampaban su valor congelado
El slider no respondia al cambio rtl/ltr. Resultaron ser dos defectos
independientes, y el segundo era del ecosistema entero.
1) EL SLIDER. slider.css emparejaba un inset LOGICO con un transform
FISICO en las tres reglas verticales (inset-inline-start: 50% +
translateX(-50%)). Los transforms no se voltean, asi que en RTL el rail y
el relleno quedaban fuera de eje un ancho entero. Medido en Chrome:
raiz/pulgar/ticks en x=961, rail y relleno en x=955. El Tick se libraba
porque ya usaba margin-inline-start — ese era el idioma correcto del
propio fichero y es el que aplico. Mismo defecto en accordion.css:
text-align: left en el trigger, que era el UNICO text-align fisico de
todo eidos; ahora quedan cero.
2) LA RAIZ. makeDimension().get() leia engine.snapshot() esquivando la
celda $state, asi que prefs.<dim>.get() — y con ella el
soma.prefs.getDir() que la guia manda usar — era una lectura sin
tracking. Los ~64 componentes que resuelven su direccion desde prefs la
congelaban al montarse. La proyeccion DOM se salvaba porque usa
onChange: misma dimension, dos caminos de lectura, solo uno reactivo.
Arreglado con un contador de cambios POR dimension, bombeado desde el
effectiveDiff que el motor ya calcula, de modo que cubre tambien el
cambio por DERIVACION (direction siguiendo a language) y no solo el
intent. Un contador por clave y no una celda global: con una sola celda,
tocar motion despertaria las 64 derivaciones de direccion. El test
negativo lo clava.
3) VALOR NO ES AFIRMACION. 33 de 37 componentes estampaban dir en su raiz
con un valor siempre concreto, asi que una app que ponga html dir=rtl sin
registrar la preferencia se encontraba 33 islas volteadas del reves.
Investigadas las cinco librerias de referencia: MUI y react-aria no
estampan nunca, Radix estampa siempre (sus mantenedores arrastran
discussions/1405 por esto), y Zag estampa prop("dir") — presente si
alguien lo pidio, ausente si no. Adoptado el modelo de Zag pero uniforme:
el atributo NUNCA tiene defecto. La herencia la hace el navegador por
AUSENCIA de atributo, sin ninguna lectura del DOM, asi que la cadena
prop -> prefs -> 'ltr' se queda intacta.
4) HOMOGENEIDAD. Habia DIEZ formas distintas de resolver lo mismo en los
wrappers y CINCO de declarar el tipo, con un cuarto escalon semantico
—heredar del menu padre— enterrado en dos expresiones sueltas.
Normalizado a activeDir(getter, soma) en los 36, un solo tipo
Direction | undefined, y el escalon de los submenus declarado en la
llamada, donde se ve.
5) LA SHELL. El toggle de direccion pasa de 2 a 3 estados: auto hace
clearIntent, que es lo unico que deja ganar al derive. Y entra el arabe
en el catalogo de idiomas, porque sin un idioma RTL la derivacion no era
disparable. Con las dos cosas, elegir arabe voltea la direccion sin tocar
el control — la cadena documentada funcionando de punta a punta por
primera vez.
Verificado: check 74 = linea base exacta, cero nuevos. 602/602 tests en
101 ficheros. En Chrome real: el topbar mueve al slider y al accordion en
vivo, y el arabe voltea por derivacion.
QUEDA: 48 demos siguen clavando dir='ltr'; el interrogante desplazado del
accordion necesita dir="ltr" lang="en" en el contenedor de la demo (no es
un fallo nuestro, es bidi correcto sobre texto ingles en parrafo RTL);
html lang no sigue al idioma; smoke y perm:check sin ejecutar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
margin-inline-start: calc(var(--_slider-track-size) / -2);
|
feat(sound): $sound orquestador (buses+voces+media) y player v2 F1-F3 sobre el servicio
Rediseno clean-room del sonido (gate D-SR.1-12 firmado; la doctrina "la voz
es del art" de PLAN-sound-engine s16.1 queda revocada):
- Mezcla: master -> buses ui/content (gain/mute/duck refcount, gana la mas
fuerte; politica pre-contexto). prefs de UI jamas tocan la obra.
- Voces registradas: la calibracion es DATO del consumidor (sema registra
'sema'; el default conserva la calibracion historica - cero cambio audible,
A/B del usuario: "suena igual").
- Ciudadania de media: sound.media(el) PROVEE el transporte (la forma exacta
del puerto MediaProvider) + foco mixed/exclusive/duck PERSISTENTE (estado
derivado; el ducker mas reciente retiene la palabra) + duckUiWhileContent +
MediaSession de la fuente activa (play/pause/seekto + posicion, liberacion
y promocion) + visibilidad content-aware + attach() opt-in (irreversible,
CORS declarado). Re-registro idempotente por elemento.
- diagnostics.ts con catalogo tipado (contrato de arts) y guards post-dispose
(ningun camino abre un contexto huerfano). Auditoria AU-1..9 resuelta;
bundle medido: 16,2 KB min / 5,6 KB gz.
Player v2 (gate D-AP2.1-13 firmado) F1-F3:
- F1 gaps de framework: aria-valuetext en Slider (valueText por thumb) +
parte SecondaryRange con token --slider-secondary-bg (buffer/clip/capitulos)
+ formatDuration en $libs/days + fix del selector del pack (H-1: la regla
de play/pause construia sobre provider y el stamp aterriza en play-button).
- F2 morfo: 6 partes audio-only (artwork/artist/identity/transport/
rate-button/live-indicator), commit-set-rate, commit-set-time RETIRADO
(D-AP2.13: el scrubber delega en el commit-set del Slider compuesto),
sustain-loading cableado (H-9), teclado j/l, </> y 0-9 (con guard de
modificadores para no pisar atajos del navegador).
- F3 la migracion: el transporte default es uix.sound.media(el, {metadata})
(pineado con el motor real); nativeMediaProvider RETIRADO (media-provider.ts
queda como contrato puro del puerto, sin shim); G-5: los commits de
play/mute/rate cabalgan el evento de RESULTADO (play/pause saltando el
pause de ended, volumechange con transicion de muted, ratechange);
formatTime -> formatDuration; sub-providers + wrappers + exports de las 6
partes; prop metadata publica (captura al registrar, documentado).
Verificacion: 45 suites / 458 tests verdes en el alcance (sound, sema,
active-uix, active-app, morfo, slider, media-player, days) - check 74 =
baseline de la rama, 0 propios - docs:check 0 - invariante de UN AudioContext
intacta (e2e sin tocar). Planes de proceso y handoff al dia
(PLAN-sound-redesign, PLAN-audio-player-v2, CONTINUE-sound-engine).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-thumb] {
|
|
|
|
|
inline-size: var(--_slider-thumb-size);
|
|
|
|
|
block-size: var(--_slider-thumb-size);
|
|
|
|
|
border: var(--slider-thumb-border-width) solid var(--slider-thumb-border);
|
|
|
|
|
border-radius: var(--slider-thumb-radius);
|
|
|
|
|
background: var(--slider-thumb-bg);
|
|
|
|
|
box-shadow: var(--slider-thumb-shadow);
|
|
|
|
|
cursor: grab;
|
|
|
|
|
outline: none;
|
feat(uix): cropper, image-picker, image-adjustments + reusable zoom-pan layer
Three new components across all 4 layers (morfo/soma/sema/eidos) + demos + langs + READMEs:
- ImageAdjustments — reusable image-filter sliders subcomponent.
- ImagePicker — composes file-upload + image + image-adjustments (fill modes, rotation).
- Cropper — Ark image-cropper anatomy: normalized 0-1 crop rect, rect + round shapes,
8 resize handles, fixedSize move-only (avatar), canvas Blob output (5-arg drawImage
for SVG safety), wheel/pan zoom, two-zone gesture (selection moves the area, the
background pans to set focus; img draggable=false guards native DnD per zag).
New reusable soma/layers/zoom-pan: cursor-centered zoom, clamped pan, transform +
viewport-frac-to-content-frac mapping. Image-viewer / diagram-pan / map can reuse it.
sema: add 'zoom' verb to the handle family (direct manipulation, documented extension).
slider: track visible at zero (gray, not white), thumb lifts on drag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 months ago
|
|
|
/* `scale` is its own property, independent of the `transform: translate()`
|
|
|
|
|
the soma uses to centre the thumb — they compose, so the lift scales the
|
|
|
|
|
thumb in place. */
|
|
|
|
|
transition:
|
|
|
|
|
background var(--slider-transition-duration) var(--slider-transition-ease),
|
|
|
|
|
border-color var(--slider-transition-duration) var(--slider-transition-ease),
|
feat(uix): cropper, image-picker, image-adjustments + reusable zoom-pan layer
Three new components across all 4 layers (morfo/soma/sema/eidos) + demos + langs + READMEs:
- ImageAdjustments — reusable image-filter sliders subcomponent.
- ImagePicker — composes file-upload + image + image-adjustments (fill modes, rotation).
- Cropper — Ark image-cropper anatomy: normalized 0-1 crop rect, rect + round shapes,
8 resize handles, fixedSize move-only (avatar), canvas Blob output (5-arg drawImage
for SVG safety), wheel/pan zoom, two-zone gesture (selection moves the area, the
background pans to set focus; img draggable=false guards native DnD per zag).
New reusable soma/layers/zoom-pan: cursor-centered zoom, clamped pan, transform +
viewport-frac-to-content-frac mapping. Image-viewer / diagram-pan / map can reuse it.
sema: add 'zoom' verb to the handle family (direct manipulation, documented extension).
slider: track visible at zero (gray, not white), thumb lifts on drag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 months ago
|
|
|
scale var(--slider-transition-duration) var(--slider-transition-ease),
|
|
|
|
|
box-shadow var(--slider-transition-duration) var(--slider-transition-ease);
|
|
|
|
|
}
|
|
|
|
|
|
feat(uix): cropper, image-picker, image-adjustments + reusable zoom-pan layer
Three new components across all 4 layers (morfo/soma/sema/eidos) + demos + langs + READMEs:
- ImageAdjustments — reusable image-filter sliders subcomponent.
- ImagePicker — composes file-upload + image + image-adjustments (fill modes, rotation).
- Cropper — Ark image-cropper anatomy: normalized 0-1 crop rect, rect + round shapes,
8 resize handles, fixedSize move-only (avatar), canvas Blob output (5-arg drawImage
for SVG safety), wheel/pan zoom, two-zone gesture (selection moves the area, the
background pans to set focus; img draggable=false guards native DnD per zag).
New reusable soma/layers/zoom-pan: cursor-centered zoom, clamped pan, transform +
viewport-frac-to-content-frac mapping. Image-viewer / diagram-pan / map can reuse it.
sema: add 'zoom' verb to the handle family (direct manipulation, documented extension).
slider: track visible at zero (gray, not white), thumb lifts on drag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 months ago
|
|
|
/* Pickup lift on grab: scale toward the viewer + a higher shadow. */
|
|
|
|
|
[data-slider-thumb]:active {
|
|
|
|
|
cursor: grabbing;
|
refactor(eidos): el catálogo habla un idioma — 269 claves al vocabulario firmado
D-TH.6, ejecutada. El slot de tinta pasa a `fg` y el modificador interactivo
se pone delante, que es lo que theming §6.7 r7 documentaba sin guard desde
que se escribió. Value-preserving: renombra la clave en `recipes/base.ts` y
sus 793 referencias en 101 ficheros; no toca un solo valor.
claves renombradas 269 en 66 componentes
referencias 793 en 101 ficheros
censo antes/después 162 recetas · 5.203 knobs · 1.841 públicos (37 %) · 56
sin contrato — IDÉNTICO, como debe ser un rename
--names antes/después 269 desviadas → 0
Qué NO entra, y por qué:
47 `{rol}-{slot-de-rol}` canónicas: COLOR_ROLE_SLOTS pone el modificador
detrás POR CONSTRUCCIÓN (`primary-solid-hover`)
13 exentas firmadas `--focus-ring-*` es familia del sistema; el color
de `aura` es un sustantivo; `stop-color` ES una
parte de gradient-builder
47 hovers neutros por VALOR: migran a la capa de estado
(§38 + R-4.3), no se renombran — firma 3
6 ocurrencias en historia changelog, errores-toxico, PLAN-affix/background:
reescribir un registro fechado lo vuelve mentira
El clasificador vive en el censo (`--names`), no en un script suelto, para que
el guard R-5.3 consuma la MISMA gramática que el codemod. Su muta-prueba
(`__names-mutatest.ts`, 27 casos) es lo que hizo el trabajo: cazó que yo
promovía al frente CUALQUIER valor declarado por el morfo, y así
`--sidebar-width-icon` (la anchura del raíl colapsado) se convertía en
`--sidebar-icon-width` (la anchura de un icono), que es otra cosa. La firma
dice «delante lo interactivo, detrás lo dimensional y contextual»: ahora sólo
promociona el vocabulario interactivo cerrado, y lo contextual —`below`,
`loaded`, `vertical`, `icon`— se queda donde estaba. Los cinco casos de
regresión están en la muta-prueba.
También cazó que `dropdown-menu.item-bg-hover` lee `var(--color-primary-element)`:
es un hover CON VALENCIA (el palette swap de recipe-contract §2), no el hover
bespoke que §38 deprecó. Clasificar por el nombre lo habría metido en una
migración que no le toca; se clasifica por el VALOR.
Verificación (§7.4, artefacto por paso):
diff de generated/ 269 renombres 1:1 · 0 cambios de valor · 22 privados
reapuntados a los nombres nuevos (`__names-verify-diff`)
computed tag-group · field · tabs: 6.467 valores en 23 estados,
0 diffs — y comprobado en el navegador que sirve el CSS
nuevo, para que ese 0 no sea el de una copia cacheada
huérfanos 0 en código
suite eidos 434 pasan · 1 rojo, el conocido (`skin-media-player`).
`recipe-css-contract` verde: es el guard que caza el
`var()` sin fallback a un nombre que ya no se emite,
o sea el fallo exacto de un rename a medias
component:audit 163 PASS · 3 NEEDS-WORK, los tres SIN TOCAR por esto
check 0 errores en ficheros tocados (los 73 globales son de
otras sesiones de la rama; se atribuye por fichero)
rtl:check 0 · docs:check 0
formato el renombrado no alarga ninguna línea: ningún fichero
tiene más líneas de 100 chars que antes, así que no se
pasa prettier — hacerlo reformateaba 300 ficheros de
deriva ajena
Entra aquí la corrección del repaso de los 7 ya hechos:
`gradient-builder.checker-color` → `checker-fg` (el damero de transparencia;
ahí `color` era slot). Sus `stop-color-*` no se tocan.
Queda para el paso siguiente: R-5.3 no puede graduar a `error` directo
mientras los 47 hovers neutros sigan hablando el idioma viejo — o migran
antes (firma 3, ya firmada), o el guard necesita una exención greppable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
scale: var(--slider-active-thumb-scale);
|
|
|
|
|
box-shadow: var(--slider-active-thumb-shadow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-thumb]:focus-visible {
|
|
|
|
|
/* Keep the thumb's own drop shadow; the focus ring is a flush outline (no gap)
|
|
|
|
|
so it survives forced-colors. */
|
|
|
|
|
box-shadow: var(--slider-thumb-shadow);
|
|
|
|
|
outline: var(--focus-ring-width) solid var(--focus-ring-color);
|
|
|
|
|
outline-offset: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-thumb][data-disabled] {
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-tick] {
|
|
|
|
|
inline-size: var(--_slider-tick-size);
|
|
|
|
|
block-size: var(--_slider-tick-size);
|
|
|
|
|
border-radius: var(--slider-tick-radius);
|
|
|
|
|
background: var(--slider-tick-bg);
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-tick][data-orientation='horizontal'] {
|
|
|
|
|
inset-block-start: 50%;
|
|
|
|
|
margin-block-start: calc(var(--_slider-tick-size) / -2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-tick][data-orientation='vertical'] {
|
|
|
|
|
inset-inline-start: 50%;
|
|
|
|
|
margin-inline-start: calc(var(--_slider-tick-size) / -2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-slider-tick][data-active] {
|
refactor(eidos): el catálogo habla un idioma — 269 claves al vocabulario firmado
D-TH.6, ejecutada. El slot de tinta pasa a `fg` y el modificador interactivo
se pone delante, que es lo que theming §6.7 r7 documentaba sin guard desde
que se escribió. Value-preserving: renombra la clave en `recipes/base.ts` y
sus 793 referencias en 101 ficheros; no toca un solo valor.
claves renombradas 269 en 66 componentes
referencias 793 en 101 ficheros
censo antes/después 162 recetas · 5.203 knobs · 1.841 públicos (37 %) · 56
sin contrato — IDÉNTICO, como debe ser un rename
--names antes/después 269 desviadas → 0
Qué NO entra, y por qué:
47 `{rol}-{slot-de-rol}` canónicas: COLOR_ROLE_SLOTS pone el modificador
detrás POR CONSTRUCCIÓN (`primary-solid-hover`)
13 exentas firmadas `--focus-ring-*` es familia del sistema; el color
de `aura` es un sustantivo; `stop-color` ES una
parte de gradient-builder
47 hovers neutros por VALOR: migran a la capa de estado
(§38 + R-4.3), no se renombran — firma 3
6 ocurrencias en historia changelog, errores-toxico, PLAN-affix/background:
reescribir un registro fechado lo vuelve mentira
El clasificador vive en el censo (`--names`), no en un script suelto, para que
el guard R-5.3 consuma la MISMA gramática que el codemod. Su muta-prueba
(`__names-mutatest.ts`, 27 casos) es lo que hizo el trabajo: cazó que yo
promovía al frente CUALQUIER valor declarado por el morfo, y así
`--sidebar-width-icon` (la anchura del raíl colapsado) se convertía en
`--sidebar-icon-width` (la anchura de un icono), que es otra cosa. La firma
dice «delante lo interactivo, detrás lo dimensional y contextual»: ahora sólo
promociona el vocabulario interactivo cerrado, y lo contextual —`below`,
`loaded`, `vertical`, `icon`— se queda donde estaba. Los cinco casos de
regresión están en la muta-prueba.
También cazó que `dropdown-menu.item-bg-hover` lee `var(--color-primary-element)`:
es un hover CON VALENCIA (el palette swap de recipe-contract §2), no el hover
bespoke que §38 deprecó. Clasificar por el nombre lo habría metido en una
migración que no le toca; se clasifica por el VALOR.
Verificación (§7.4, artefacto por paso):
diff de generated/ 269 renombres 1:1 · 0 cambios de valor · 22 privados
reapuntados a los nombres nuevos (`__names-verify-diff`)
computed tag-group · field · tabs: 6.467 valores en 23 estados,
0 diffs — y comprobado en el navegador que sirve el CSS
nuevo, para que ese 0 no sea el de una copia cacheada
huérfanos 0 en código
suite eidos 434 pasan · 1 rojo, el conocido (`skin-media-player`).
`recipe-css-contract` verde: es el guard que caza el
`var()` sin fallback a un nombre que ya no se emite,
o sea el fallo exacto de un rename a medias
component:audit 163 PASS · 3 NEEDS-WORK, los tres SIN TOCAR por esto
check 0 errores en ficheros tocados (los 73 globales son de
otras sesiones de la rama; se atribuye por fichero)
rtl:check 0 · docs:check 0
formato el renombrado no alarga ninguna línea: ningún fichero
tiene más líneas de 100 chars que antes, así que no se
pasa prettier — hacerlo reformateaba 300 ficheros de
deriva ajena
Entra aquí la corrección del repaso de los 7 ya hechos:
`gradient-builder.checker-color` → `checker-fg` (el damero de transparencia;
ahí `color` era slot). Sus `stop-color-*` no se tocan.
Queda para el paso siguiente: R-5.3 no puede graduar a `error` directo
mientras los 47 hovers neutros sigan hablando el idioma viejo — o migran
antes (firma 3, ya firmada), o el guard necesita una exención greppable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
background: var(--slider-active-tick-bg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
|
|
[data-slider-thumb] {
|
|
|
|
|
transition: none;
|
|
|
|
|
}
|
feat(uix): cropper, image-picker, image-adjustments + reusable zoom-pan layer
Three new components across all 4 layers (morfo/soma/sema/eidos) + demos + langs + READMEs:
- ImageAdjustments — reusable image-filter sliders subcomponent.
- ImagePicker — composes file-upload + image + image-adjustments (fill modes, rotation).
- Cropper — Ark image-cropper anatomy: normalized 0-1 crop rect, rect + round shapes,
8 resize handles, fixedSize move-only (avatar), canvas Blob output (5-arg drawImage
for SVG safety), wheel/pan zoom, two-zone gesture (selection moves the area, the
background pans to set focus; img draggable=false guards native DnD per zag).
New reusable soma/layers/zoom-pan: cursor-centered zoom, clamped pan, transform +
viewport-frac-to-content-frac mapping. Image-viewer / diagram-pan / map can reuse it.
sema: add 'zoom' verb to the handle family (direct manipulation, documented extension).
slider: track visible at zero (gray, not white), thumb lifts on drag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 months ago
|
|
|
/* No pickup zoom under reduced motion — the raised shadow still conveys grab. */
|
|
|
|
|
[data-slider-thumb]:active {
|
|
|
|
|
scale: 1;
|
|
|
|
|
}
|
|
|
|
|
}
|