diff --git a/continue.md b/continue.md index 7e03e8043..1a9649de1 100644 --- a/continue.md +++ b/continue.md @@ -14,6 +14,7 @@ component CSS` pasa. ### Lo cerrado y verificado este sprint **Ronda 1 — 7 ítems (todos DONE + verificados):** + 1. Quitado el dropdown "Add block" del panel de BLOQUE Columns (vive solo en el inspector específico de columna). `dropdownsInColumnsBlockPanel: 0`. 2. Validación de ancho de columna (`isValidColumnWidth` + `commitColumnWidth` @@ -23,13 +24,14 @@ component CSS` pasa. barrel `soma/components/words/exports.ts`): `javascript:` rechazado. 4. Shift+Enter soft break: ya funcionaba (`\n` + `white-space: pre-wrap`); verificado con keystrokes reales `MARKA⇧⏎MARKB` → mismo bloque. -5+7. Rediseño cabecera inspector: mark de acento por profundidad + 5+7. Rediseño cabecera inspector: mark de acento por profundidad (primary/affirm/loss/risk) + wash + divisor + breadcrumb estilado (`[data-words-inspector-breadcrumb]`, single-row scroll). -6. Botones add/delete normalizados a icon-only (Trash2 delete, flechas +5. Botones add/delete normalizados a icon-only (Trash2 delete, flechas Arrow{Up,Down,Left,Right} para table-ops, Plus para add). **Ronda 2 — chrome systémico (DONE + verificado):** + - Inputs unificados: un solo frame bordeado (text inputs + NumberFields), un solo focus-ring de acento (NO más `outline` inset sobre el texto, NO más mezcla ghost/borde-negro). Specificity `[data-number-field][data-size]` @@ -45,20 +47,21 @@ component CSS` pasa. del popover). **Ronda 3 — defectos de controles (DONE + verificado):** + - ToggleGroups con **valor por defecto seleccionado** (uno siempre activo): Fuente=`default`, Grosor=`400`/Normal, Alinear=`left`, Borde=`none`. El default se almacena como `undefined` en el modelo (limpio). Verificado: `Predeterminada/Normal/Izquierda/Ninguno` seleccionados al activar bloque. - Borde gana opción **`none`** (chip que limpia `border: undefined`). Nuevo type `BorderChipValue = 'none' | BorderStyleValue`. Langs `BORDER_NONE` - + bundle `border.none` ({en:'None', es:'Ninguno'}). + - bundle `border.none` ({en:'None', es:'Ninguno'}). - Image "Ancho total" → **Switch** (era Toggle con texto on/off). - **Bug del radio de esquina arreglado**: el ring de selección era un `outline`/`box-shadow` que HEREDA el `border-radius` del bloque, así que redondear el bloque a 40px redondeaba el ring. Ahora el ring es un **pseudo-elemento `::after`** con radio FIJO (4px), `inset: -3px`, `pointer-events: none`. Verificado: `blockRadius=40px, ringRadius=4px, - decoupled=true`. +decoupled=true`. - **Slider-only** para "Grosor del borde" + "Radio de esquina": nuevo prop `sliderOnly` en `WordsNumRow` que oculta el NumberField y muestra un chip de valor read-only (el slider + input era redundante). Verificado: @@ -108,8 +111,8 @@ Fecha de corte: **2026-05-29**. Rama: `active-uix`. **V1 del editor Words ELIMINADO. V2 es ahora el único motor.** La sesión arrancó con una auditoría del componente Words -(`codex-full-audit.md` en la raíz) y la pregunta del usuario: *"elimina -v1 y continua v2, ¿qué sentido tiene v1?"*. Decisión firmada y +(`codex-full-audit.md` en la raíz) y la pregunta del usuario: _"elimina +v1 y continua v2, ¿qué sentido tiene v1?"_. Decisión firmada y ejecutada de cabo a rabo (F1 → F6). Ya no hay coexistencia V1/V2 ni migrador: el modelo de documento público es `WordsDocumentV2` y punto. @@ -173,28 +176,35 @@ inverso fiel). El import sólo acepta **JSON** (`JSON.parse` + - **Tabla**: `{ type:'table', rows, headerRow?, headerCol? }`; fila `{ cells, visual? }`; celda `{ children, align?, verticalAlign?, - colspan?, rowspan?, visual? }`. **Celda usa `align`**, no `textAlign`. +colspan?, rowspan?, visual? }`. **Celda usa `align`**, no `textAlign`. - **Lista**: `{ type:'list', kind, items }`; item `{ children, checked?, - indent? }`. **`items`**, no `children`. Sin `type:'list-item'`. +indent? }`. **`items`**, no `children`. Sin `type:'list-item'`. - **Bloques con alineación**: paragraph/heading/quote llevan `textAlign?` (a nivel bloque). -## ⚠️ Decisión consecuente NO firmada — export HTML +## ✅ Decisión FIRMADA (2026-06-02) — export-only (no roundtrip) -`serializeHtmlV2` emite **HTML semántico limpio**, no un formato -roundtrip-lossless. Como V2 no tiene parser HTML, HTML y Markdown son -export-only. Si el usuario quería export HTML roundtrip-friendly (re- -importable), es un encargo aparte. **Pendiente de confirmar con él.** +`serializeHtml` / `serializeMarkdown` emiten proyecciones de export (HTML +semántico limpio / GFM), **no** un formato re-importable, y así se queda: +**JSON es el formato canónico lossless; HTML/MD son export-only.** Misma +postura que TipTap/ProseMirror, Lexical, Slate y Notion — el modelo JSON +persiste, HTML/MD son proyecciones. El import acepta sólo JSON (vía +`validateWordsDocument`) + texto plano (`parseWordsPlainText`). Si en el +futuro se necesita _pegar_ HTML externo, se añade un `parseHtml` por-bloque +(patrón `parseDOM`/`importDOM` de ProseMirror/Lexical) como interop +best-effort de portapapeles — **nunca** como persistencia; markdown import no +merece la pena (es lo más lossy). Doctrina completa + tabla de formatos en +`src/uix/soma/components/words/README.md` → "Serializacion e intercambio". ## Verificación al cierre (todo verde) -| Gate | Status | Notas | -|---|---|---| -| `npm run check` | **0 errors** / 5168 files | 26 warnings pre-existentes, ninguno en archivos tocados | -| `npx vitest run src/uix/soma/components/words` | **455/456** | el único fallo es el flake de `sema-parity` por timeout 5s bajo carga paralela | -| `sema-parity` aislado | **6/6 en 362ms** | confirma que el flake es de infra, no regresión | -| `npm run morfo:vocabulary` | **exit 0** | sólo WARN suaves (vocabularios noveles legítimos) | -| Browser smoke `/uix/components/words` | **OK** | mount limpio, 0 console errors | +| Gate | Status | Notas | +| ---------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------ | +| `npm run check` | **0 errors** / 5168 files | 26 warnings pre-existentes, ninguno en archivos tocados | +| `npx vitest run src/uix/soma/components/words` | **455/456** | el único fallo es el flake de `sema-parity` por timeout 5s bajo carga paralela | +| `sema-parity` aislado | **6/6 en 362ms** | confirma que el flake es de infra, no regresión | +| `npm run morfo:vocabulary` | **exit 0** | sólo WARN suaves (vocabularios noveles legítimos) | +| Browser smoke `/uix/components/words` | **OK** | mount limpio, 0 console errors | **Smoke detallado**: el doc sample V2 renderiza (tabla 2×2 con `headerRow`, 4 list-items incl. el indentado); export markdown emite @@ -231,7 +241,7 @@ Borrados los selectores CSS muertos de `words.css` los `[data-words-cell-header]` huérfanos — los headers se renderizan como `