palabras(docs): UI de F4 cerrada — tracker + handoff 2026-07-19

- PLAN-EJECUCION.md: F4.3 / F4.4 / F4.7 pasan ◐→✅ (UI cableada esta sesión;
  merge/split + listas start/numeración + barra de estado count/TOC + resize de
  columna v1). Notas de alcance: resize filas+snap = v1.1; `at` explícito del
  motor; `cell.width` string.
- continuar-palabras.md: nueva sección de bitácora 2026-07-19 (las 4 piezas +
  commits + gotchas: selección perdida→`at`, `cell.width` string `"{n}px"`,
  `blockFoot` oculto para celdas→`cellFoot`; deuda: langs diferidos por
  entanglement, v1.1 del resize; próximo del mapa «qué queda»).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
alpha-0.1-sec-dom
dev 3 months ago
parent f0de4faf75
commit 98589d60d3

@ -496,11 +496,11 @@ dark/densidad), no a ojo.
|---|---|---|
| F4.1 ✅ | **Upload adapter** (D-5): opción `onUploadImage?` en el provider (File → Promise<url>); data-URL SOLO como fallback documentado; `imageStatus` pending/error ya existe. **Hecho 2026-07-14** (`31d49c88`): `uploadImage(file, apply)` en el snippet + picker de palabras ruteado | insertar imagen con adapter simulado → el JSON guarda URL, no base64 ✅ (test provider) |
| F4.2 ✅ | **Paste Word/GDocs**: pre-filtro en `parse-html` (mso-*, `<o:p>`, sopa de spans, listas de Word) + fixtures reales de Word/GDocs en tests. **Hecho 2026-07-14** (`8444dd58`) | pegar fixture → estructura limpia, sin basura ✅ (tests + navegador) |
| F4.3 ◐ | **Tablas**: comandos `mergeCells`/`splitCell` (los types ya llevan colspan/rowspan sin consumidor) + resize de columna por arrastre (tiradores espaciales, spec Fase 3) + UI en panel de tabla. **Motor hecho 2026-07-14** (`bdb8971b`: merge/split span-aware + parse de spans); resize + UI = post-FD | tests de table-ops ✅ + navegador (spans render) ✅; UI pendiente |
| F4.4 ◐ | **Listas** (DG-7): `start` + tipo de numeración; panel de lista los expone. **Motor hecho 2026-07-14** (`a025681d`: modelo+validate+render+serialize+parse); el panel = F3.1 post-FD | test ✅ + navegador ✅; panel pendiente |
| F4.3 ✅ | **Tablas**: `mergeCells`/`splitCell` (motor `bdb8971b`) + resize de columna por arrastre. **UI HECHA 2026-07-19**: merge/split en **menú Editar + pie del panel** (`b4666336a`; el `blockFoot` se oculta para celdas structural → fila `cellFoot` propia; **ajuste motor `at:[block,row,cell]` explícito** porque el chrome pierde `state.selection` al abrirse fuera del editor + test `selection:null`; merge sin multi-selección = derecha `cols:2`/abajo `rows:2`). **Resize v1 SOLO columnas** (`86a3386fc`, `palabras-table-resize.svelte`: tiradores en el borde superior al hover, drag con feedback CSS en vivo + commit `cell.width` **STRING `"{n}px"`** al soltar, doble-clic=auto). **Filas + snap a fracciones = v1.1.** | table-ops ✅ (test `at`) + Playwright (merge colspan=2, drag 234→314, doble-clic auto) ✅ |
| F4.4 ✅ | **Listas** (DG-7): `start` + tipo de numeración; panel de lista los expone. **Motor hecho 2026-07-14** (`a025681d`). **PANEL HECHO 2026-07-19** (`85d6a4858`): los campos ya existían desde F3.1 (`5411becb5`, escriben por `updateBlockAtPath`) — faltaba **gatearlos a `ordered`** (`kinds:['ordered']`; salían en viñetas/tareas) | test ✅ + navegador (`<ol start="3" type="i">`→`lower-roman`) ✅ |
| F4.5 ✅ | **Bloque embed/vídeo** (DG-9) **como plugin** — prueba de fuego del API (`PalabrasBlockMap` merging + registry): iframe saneado con allowlist. **Hecho 2026-07-14** (`b9f76740`: hook `fromPastedUrl` + fix normalize-plugin-blocks; allowlist configurable, DG-9 default) | plugin registrado SIN tocar el core ✅; paste de URL de YouTube crea embed ✅ (test + navegador) |
| F4.6 | **Menciones @ / emoji :** como segundo plugin (reutiliza la maquinaria del slash menu). **Pospuesta ENTERA a después de FD**: el popup es superficie de interacción nueva (pariente del slash en la spec) — no se improvisa sin firma | popup filtra, inserta inline, exporta |
| F4.7 ◐ | **Word/char count** en `Status` (deriva de `plainText`) + **TOC** generado de headings (el ancla ya existe en el panel). **Motor hecho 2026-07-14** (`4264f7f8`: wordCount/charCount/tableOfContents en snippet + fix plainText-columnas); widget visual = F3 post-FD | derivados vivos ✅ (test reactivo); TOC navega = UI pendiente |
| F4.7 ✅ | **Word/char count** + **TOC** de headings. **Motor hecho 2026-07-14** (`4264f7f8`). **WIDGET HECHO 2026-07-19** (`a97d8db74`, `palabras-status.svelte`): barra de estado al pie (3 modos) con «N palabras · M caracteres» + botón «Índice» → `<Popover>` de encabezados (sangrado por `level`, clic → `scrollIntoView`). Decisión del usuario: affordance PROPIA, NO el panel de propiedades | derivados ✅ + Playwright (45 palabras, 2 encabezados niveles 1/2, salto) + screenshot ✅ |
| F4.8 ✅ | **Alineación lógica** (DG-8): el render traduce left/right → start/end bajo RTL. **Hecho 2026-07-14** (`5b1e228a`: proyección en `blockStyle`, único punto render+export; DG-8 registrada) | demo RTL: aligns coherentes ✅ (geometría en navegador: end voltea bajo dir=rtl) |
| F4.9 | **Demos v2 + guards** (DG-10): demo palabras a plantilla v2 (9 tabs); adopción de recipe-contract → audit por lotes (la demo de words murió en FW) | `component:audit --only palabras` sin errores nuevos del lote adoptado |
| F4.10 | **Touch/móvil de la spec FD.2**: drawer inferior pulido, targets ≥44 px (`pointer: coarse`), grip anclado sin hover, drag táctil de bloques, panel usable a una mano | viewport móvil real: recorrido de edición COMPLETO sin ratón ni teclado, contra la columna touch de la spec |

@ -9,6 +9,64 @@
---
## ESTADO 2026-07-19 — UI de F4 CERRADA (listas · merge/split · count/TOC · resize)
> El usuario eligió «las tres en orden» de la **UI de F4** (el MOTOR ya estaba desde 2026-07-14).
> Cuatro piezas hechas, verificadas end-to-end y commiteadas a `gita`. **Verificación**: Playwright
> headless (frame loop real) — la barra de menús / el popover / la tabla CONGELAN en el Browser pane
> MCP (rAF suspendido) [[reference_hidden_pane_suspends_raf]]; screenshots vía Playwright.
### Lo hecho hoy (todo en `alpha-0.1-sec-dom` → `gita`)
- **F4.4 listas — `85d6a4858`**: los campos `start`/`numeración` YA existían + cableados desde F3.1
(`5411becb5`; escriben por `updateBlockAtPath` — campos NO `visual`). Solo faltaba **gatearlos a
`ordered`** (`kinds:['ordered']` en `list.contenido` de `panel-schema.ts` — salían en viñetas/tareas,
sin sentido). El filtro `kinds` es el mismo que ya gobierna marker/box. Verificado: `start:3/
numbering:'i'` → `<ol start="3" type="i">` → `lower-roman`.
- **F4.3a merge/split — `b4666336a`**: UI en **menú Editar** (barra) + **pie del panel** (flotante/
acoplado), gateada a celda top-level. Helper `tableCellActions(loc, activeEl)` en
`palabras-block-actions.ts` (inCell + `at`=`loc.path.slice(0,3)` + canMergeRight/Down/Split de la
geometría del `<td>`). **El `blockFoot` se oculta para celdas structural (`isStructural`) → las celdas
tienen fila PROPIA `cellFoot`.** **DESVIACIÓN DECLARADA de «solo UI»**: los comandos resolvían la celda
por `state.selection`, que el chrome PIERDE al abrirse fuera del editor → `mergeTableCells`/
`splitTableCell` ganan `at?:readonly number[]` explícito (fallback a la selección; consistente con
mover/eliminar por `loc.path`); test con `selection:null`. Merge sin multi-selección = derecha
(`cols:2`) / abajo (`rows:2`). Verificado Playwright ambas superficies (colspan=2 tras merge, dividir
restaura).
- **F4.7 recuento + TOC — `a97d8db74`**: decisión del usuario = **barra de estado al pie + botón
«Índice» → popover**. `palabras-status.svelte` NUEVO (montado al pie del shell, los 3 modos): «N
palabras · M caracteres» (readout) + `<Popover>` con `tableOfContents` (sangrado por `level`);
`jumpTo` = `scrollIntoView` del `[data-palabras-id]` del encabezado + cierra el popover; trigger
disabled sin encabezados. CSS en `palabras-chrome.css`. **El índice va en affordance PROPIA — NO
re-añadir al panel de propiedades** (el usuario lo quitó: es navegación, no una propiedad).
- **F4.3b resize de columna — `86a3386fc`** (v1 SOLO columnas): `palabras-table-resize.svelte` NUEVO —
overlay de tiradores en el borde superior de cada tabla top-level (mirror de `palabras-column-inserter`:
medición frame-relative `[data-palabras]`, remeasure en `api.html` + scroll/resize), solo al hover de
la tabla. Arrastre = inline `width` en la celda de la 1ª fila EN VIVO durante el drag + commit
`cell.width` en UN paso de historia al soltar; doble-clic = auto (limpia el width). **GOTCHA CLAVE (me
costó una ronda de debug): `cell.width` es una LONGITUD CSS en STRING** (el campo `length`/CssField del
panel commitea p.ej. `"314px"`) — un número crudo renderiza `width:314` inválido y el navegador lo
ignora; el commit usa `` `${w}px` ``. Restringido a top-level (path `[table,0,col]`).
### Deuda declarada de esta sesión
- **Langs es/en** de las 4 acciones nuevas (`action.merge-right`/`merge-down`/`split-cell`/`resize-column`
+ `status.words`/`chars`/`outline`/`untitled`) **DIFERIDOS**: `langs/components/palabras.ts` está ` M`
(modificado con el **merge de langs pendiente**, entangled con el track de chat) → NO lo toqué; los
`ts()` renderizan por **fallback castellano**. Al resolver el entanglement, añadir los keys (patrón
`'move-up': { es, en }` en el fichero).
- **v1.1 del resize**: tiradores de FILA (alto) + esquina + **snap a fracciones (1/2·1/3·2/3)** (§4.6) —
diferidos con el usuario.
### Próximo (del mapa «qué queda del componente», presentado al usuario)
Finos de F3 (typography.* granular DENTRO del mega-control · **aria-live announce** de acciones de bloque ·
familia efectiva del bubble) · **deuda del motor**: `copyBlock` simétrico (hoy el copiar serializa
`outerHTML`), `deleteRange` cross-callout (no-op diferido), **atasco de imágenes base64** en el modelo
(investigar) · **F4.10 táctil** (gestos long-press/drag, necesita dispositivo) · **F5** (deltas ⇒ id de
bloque obligatorio v3 · colaboración DG-11 · comentarios · export DOCX/PDF) · **puertas FD** (FD.3 mood del
chrome · FD.4 firma perceptual, requiere permiso). Y los langs diferidos + v1.1 del resize de arriba.
---
## ESTADO 2026-07-18 — capa de edición EN LÍNEA (bubble + slash + find) ✅ · menubar pulido
> ⚠️ La sección «2026-07-17 MENUBAR v4 MENÚ-NATIVO» de abajo es HISTÓRICA: ese enfoque

Loading…
Cancel
Save

Powered by TurnKey Linux.