El grip pasa a ser un DropdownMenu con acciones (Propiedades, Mover
arriba/abajo, Insertar, Eliminar bloque). Arreglado el "parpadeo" del menú,
que eran CUATRO fallos compuestos (por eso cada fix suelto no lo resolvía):
- disabled reactivo (leía api.html) re-creaba el item enfocado al abrir ->
cierre/reapertura en bucle. Fix: index/count congelados en el objeto grip +
grip congelado mientras el menú está abierto.
- pointerdown sobre el grip llegaba a la capa Dismissal del menú, que lo veía
"fuera del contenido" -> cerraba, y el click reabría. Fix: stopPropagation en
el pointerdown del trigger SOLO con el menú abierto.
- preventScroll (default true) bloqueaba el scroll del body al abrir -> el
scrollbar desaparecía y la página saltaba. Fix: preventScroll={false}.
- doble animación de entrada (present-rise de sema/motion durante el hold +
dropdown-menu-enter del recipe) reiniciaba la opacidad a 0 al acabar el hold;
como el menú no está portalizado, se veían los bloques detrás. Fix: fijar una
sola animación con !important en palabras.css.
Nuevo palabras-block-actions.ts (moveBlock / insertParagraphBelow /
deleteBlockAndReanchor). words-provider: marcador genérico
data-words-external-tool en isInsideWordsTool para que abrir el menú no dispare
el bucle blur->refoco del editor. Diagnóstico completo en continuar-palabras.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`palabras.svelte` (prop `content` para `deleteBlockAndReanchor`),
`words-provider.svelte.ts` (`data-words-external-tool` en `isInsideWordsTool`).
---
## 0. REGLAS DURAS (no negociables — el usuario fue tajante)
1. **Solo componentes del framework (eidos). PROHIBIDO usar elementos nativos
@ -47,7 +131,8 @@
| `palabras-panel.svelte` | Panel de propiedades (flotante, draggable). Cabecera (dot+título+papelera), secciones del schema (colapsable propio con chevron), pie "Apariencia · heredada/personalizada" + botón "Editar". | Funciona. La sección usa un `<button>`+`<section>` NATIVO colapsable (no Accordion/Tabs) — ver punto 4. Título/labels en `<span>` nativo → deuda regla #1. |
| `palabras-appearance.svelte` | 2º popover (botón "Editar"): edita `block.visual.*`. Color de texto/Fondo (`PalabrasColorRow`), Tamaño/Interlineado (`NumberField`), Alineación (`ToggleGroup`, labels de texto). Título "Apariencia". | Funciona. Contenedores `<aside>`/`<div>`/`<span>` nativos → deuda regla #1. Muestra el valor EFECTIVO (override del bloque, o el computado/heredado). |
| `palabras-color-row.svelte` | Fila de color con nuestro `<ColorPicker>` (Control>Trigger UN swatch, Portal>Content con Area + ChannelSlider hue/alpha + ChannelInput hex/rgb + SwatchGroup de `presets`). Patrón draft+`onValueChangeEnd` como `words-color-row`. | Funciona. `presets` llega vacío hoy (la paleta del esquema se revirtió — ver punto 5). |
| `palabras-handle.svelte` | El **tirador (grip)**. Ahora es un `<Button>` del framework (re-aplicado por el usuario). Aparece en el bloque ACTIVO (touch, sin hover) + sigue al hover (desktop); `gripFor` devuelve el CENTRO vertical. Escucha en `[data-palabras-doc]` (no en content) para que no desaparezca al ir a pulsarlo. | **VERIFICAR EL PRIMERO** (ver punto 3). |
| `palabras-handle.svelte` | El **tirador (grip)** = `DropdownMenu` cuyo Trigger es un `<Button>` (ghost/xs/iconOnly) draggable. Click → **menú de acciones** (Propiedades · Mover arriba/abajo · Insertar · Eliminar). Sigue al bloque hover/activo (`gripFor` → centro vertical + `index`/`count` congelados); escucha en `[data-palabras-doc]`. Drag → reorder. | Funciona (parpadeo resuelto — ver sección 2026-06-07). |
| `palabras-block-actions.ts` | Acciones de bloque compartidas por el grip y el panel: `moveBlock`, `insertParagraphBelow`, `deleteBlockAndReanchor` (borra y re-ancla el activo leyendo el superviviente del DOM, no de `api.document` que es snapshot). | Funciona. |
| `palabras-nav.svelte` | Descarte del panel: `Esc` o pointerdown FUERA → `onClose`. Ignora clics dentro de `[data-palabras-panel-card]`, `[data-palabras-appearance]`, `[data-palabras-handle]` y **`[data-color-picker-content]`** (el picker portaliza fuera). | Funciona. |
| `palabras-breadcrumb.svelte` | Breadcrumb desde `ancestry`. Delegación de clic por `data-idpath` (funciona sea `<a>` o `<span>`): clic en miga = activar nodo + abrir panel; crumb "documento" = solo limpia. | Funciona. |
| `palabras-drag.svelte.ts` | `createDrag()` reactivo: `transform` + `down/move/up`. Lo usan panel y appearance (cada uno su estado). Botones internos no arrastran. | Funciona. |