Restaure et termine le lot tableur resté non committé. Il n'existait que dans un `git stash` (24 fichiers suivis) et en fichiers non suivis (menus.js, formula.js, color-picker.js, tests, fiches) : la 2.53.3 livrée ne le contenait donc pas. Le stash, créé avant le commit BUG-108, n'a jamais été restauré. #180 Redimensionnement au curseur (en-tête de bord miroité + classe de repaint), grille thémée sur les 15 thèmes et les modes contraste élevé / sépia, menu Fichier au niveau des onglets, barre épinglée pleine largeur. #181 Modèle de saisie Google Sheets : sélection ≠ édition (caret masqué sans quitter contenteditable, double-clic / F2 / première frappe qui remplace, Entrée contextuelle, Échap qui restaure) + inventaire priorisé des écarts. #182 Désélection fiable (clic simple sans dépendre du focus), contours de plage non empilés (sélecteur de classes sans point), couleurs texte/fond sur une plage, clic droit qui préserve la sélection multiple. #183 Panneau de couleurs façon Google Sheets : palette 8 × 10, STANDARD, PERSONNALISÉ, coche selon la luminance, sortie `#rrggbb` (une valeur HSL était rejetée par normHex). #184 Peinture de format complète (toutes propriétés, source sans format = réinitialisation), sélection multi-lignes/colonnes depuis les marges, grille étendue : colonnes A → Z d'emblée, lignes ajoutées PAR BLOCS DE 100 au défilement jusqu'à 1000 — matérialiser 1000 lignes d'un coup = ~26 000 cellules câblées par feuille, ce qui épuisait le tas de la suite JSDOM ; index de cellules `ref → td`, court-circuits formule/styles, marqueur data-wired. #185 Barre de menus : les 10 menus Google Sheets (161 entrées, 125 câblées, 36 annoncées indisponibles), ruban façon Sheets, grille unie 1 px dérivée du thème. #186 « Créer un fichier » propose .xlsx et construit un vrai classeur OPC (openpyxl) au lieu d'une charge utile texte illisible. Corrections trouvées en restaurant et en exerçant le lot : - fuite mémoire : écouteur `click` anonyme posé sur #content-area à chaque rendu, jamais retiré — sa fermeture retenait la grille précédente en entier ; - sorties Markdown / HTML / Imprimer de la barre de menus inertes (`data-xlsx-export` jamais réparti, seul `data-xlsx-action` l'était) ; - collision de classe `.xlsx-structure-menu` entre la barre de menus et le menu Structure de la barre d'outils (toute requête tombait sur un nœud masqué) ; - curseur col/row-resize absent quand le pointeur est sur la table elle-même ; - l'export emportait les lignes et colonnes vides du quadrillage (CSV, Markdown, HTML, impression) ; - clic extérieur avalé par la grâce de 250 ms du menu contextuel (destinée au seul appui long tactile) ; - une entrée indisponible laissait la barre de menus ouverte. Tests : pytest 1595 passés / 2 ignorés ; ruff et mypy 0 erreur ; bandit 0 ; 33 suites frontend vertes (xlsx-viewer 163/163, xlsx-menus 19/19, xlsx-formula 14/14) ; E2E complet 132 passés / 12 ignorés ; E2E xlsx-viewer 19/19.
108 lines
6.0 KiB
Markdown
108 lines
6.0 KiB
Markdown
# #180 — Éditeur tableur : redimensionnement au curseur, grille thémée, menu Fichier & barre épinglée
|
|
|
|
> **Statut :** ✅ livré le 2026-10-08 (v2.54.0) — ouvert le 2026-10-05 | **Effort :** 1-2 jours | **Impact :** 🟡
|
|
> **Références :** [Roadmap](../ROADMAP.md) · [Changelog](../../CHANGELOG.md) ·
|
|
> [#154](./xlsx-ui-redesign.md) · [#155](./xlsx-context-menu.md) ·
|
|
> [#179](./xlsx-menus-179.md) · [#156](./xlsx-editor-completeness.md)
|
|
|
|
## 1. Constat
|
|
|
|
Retours utilisateur après #179, quatre défauts d'ergonomie et un défaut de thème :
|
|
|
|
1. **Le curseur de redimensionnement n'apparaît pas.** Le redimensionnement
|
|
par les marges existe depuis #156-A8 (`wireResize`), mais l'indicateur est
|
|
invisible : `.xlsx-table td[contenteditable]` impose `cursor: cell` et les
|
|
en-têtes reçoivent `cursor: pointer` **en ligne** (`paintHeaders()`). Les
|
|
deux beat la règle `table.style.cursor` posée par le `mousemove`, y compris
|
|
pendant le glissement. L'utilisateur n'a aucun retour sur la zone cliquable.
|
|
2. **La grille ne suit pas le thème.** `--grid-*` n'est déclaré que pour le
|
|
thème par défaut (dark + light) dans `style.css`. Les 13 autres thèmes et
|
|
les modes générés *contraste élevé* / *sépia* n'en fournissent pas : la
|
|
grille y reste en couleurs GitHub. `themes.js` applique pourtant bien les
|
|
variables via `setProperty`, sans les jetons de grille.
|
|
3. **Les sorties de fichier sont dispersées.** Télécharger, CSV et Exporter
|
|
occupent trois commandes du ruban, à gauche du bouton Enregistrer.
|
|
4. **La barre n'est pas épinglée** et l'éditeur ne prend pas toute la largeur
|
|
du contenu quand la sidebar est masquée (contrairement aux viewers
|
|
PDF / images / Excalidraw, cf. la règle `:has(...)` de `.content-area`).
|
|
5. La pastille « Formules calculées localement » occupe une ligne entière
|
|
pour annoncer un comportement normal, pas une limite.
|
|
|
|
## 2. Livré (A1-A4)
|
|
|
|
### A1 — Curseur de redimensionnement sur les marges
|
|
|
|
`wireResize()` (viewer.js) remplace le `table.style.cursor = …` isolé par
|
|
`paintResizeCursor(kind, th)` :
|
|
|
|
- la table reçoit `.xlsx-resize-col` / `.xlsx-resize-row`, repint par le CSS
|
|
sur la table **et** ses cellules (surplus des deux curseurs concurrents) ;
|
|
- l'en-tête de bord est **miroité en ligne** (`th.style.cursor`), seul moyen
|
|
de passer devant le `cursor: pointer` inline — l'ancienne valeur est
|
|
mémorisée puis restaurée quand le pointeur quitte le bord (`mouseleave`) ;
|
|
- l'état est remis à zéro au `mouseup` global : le curseur ne reste pas
|
|
« coincé » après un glissement.
|
|
|
|
### A2 — Grille compatible tous les thèmes
|
|
|
|
- `themes.js` : `applyTheme()` dérive les jetons `--grid-bg`,
|
|
`--grid-header-bg`, `--grid-header-text`, `--grid-border` et `--grid-zebra`
|
|
des surfaces du thème actif. Le zébré passe par `color-mix(… 4%, transparent)`
|
|
pour rester subtil sur fond clair **et** sombre. Un thème importé sans ces
|
|
jetons est donc couvert automatiquement.
|
|
- `style.css` : jetons de repli (`var(--grid-bg, var(--surface))`, …) pour que
|
|
la grille reste lisible même sans `applyTheme()`, plus les deux modes
|
|
*contraste élevé* et *sépia* déclarés explicitement.
|
|
- Le fond du menu Export passe de `var(--bg, #fff)` (repli clair cassé en
|
|
thème sombre) à `var(--surface)`.
|
|
|
|
### A3 — Menu Fichier + Enregistrer au niveau des onglets
|
|
|
|
- `buildCommandBar()` renvoie un fragment `fileHtml` supplémentaire : menu
|
|
**Fichier** (`download`, `file-spreadsheet`, `file-text`, `code`,
|
|
`printer`) + bouton **Enregistrer** primary. Les trois commandes de sortie
|
|
sortent du ruban, qui ne garde que l'édition.
|
|
- La coquille (`viewer.js`) rend une barre de feuilles `.xlsx-sheetbar` :
|
|
onglets à gauche, `.xlsx-sheetbar-end` (menu + Enregistrer) à droite.
|
|
- Câblage : `trackDismissable()` (même contrat que #179), navigation clavier,
|
|
fermeture au clic sur Télécharger / CSV, `aria-haspopup` / `aria-expanded`.
|
|
- **Identifiants stables** : `#xlsx-download-btn`, `#xlsx-csv-btn`,
|
|
`#xlsx-save-btn` conservés — seuls le conteneur (`#xlsx-file-btn` /
|
|
`#xlsx-file-menu`) et la classe (`.xlsx-file-menu`) sont nouveaux.
|
|
|
|
### A4 — Retrait de la pastille + barre épinglée pleine largeur
|
|
|
|
- La pastille « Formules calculées localement » est retirée ; la barre de
|
|
statut ne subsiste que pour la pastille *lecture seule* (format `.xls` /
|
|
`.ods`), et disparaît entièrement quand elle n'a rien à afficher.
|
|
- `.xlsx-toolbar` devient `position: sticky; top: 0` avec des marges négatives
|
|
qui neutralizing le padding de `.content-area` : la barre se colle au bord
|
|
haut de la page et l'éditeur occupe la largeur totale du contenu.
|
|
- `.content-area:has(.xlsx-viewer)` rejoint les viewers plein cadre.
|
|
|
|
## 3. Tests
|
|
|
|
- `tests/frontend/xlsx-viewer.test.mjs` — 136/136 :
|
|
- barre de feuilles (onglets / menu / Enregistrer à droite, onglets sortis
|
|
du ruban), contenu exact du menu Fichier (5 icônes dans l'ordre), toggle ;
|
|
- curseur `col-resize` / `row-resize` sur les deux types de bord, classes de
|
|
repaint, restauration du curseur d'en-tête à la sortie ;
|
|
- jetons `--grid-*` pour 4 thèmes (Spotify dark, Notion light, GitHub
|
|
contrasté élevé, GitHub sépia) + zébré `color-mix` ;
|
|
- absence de pastille formules (xlsx **et** csv).
|
|
- `tests/frontend/xlsx-menus.test.mjs` — 12/12 : icônes de `fileHtml`.
|
|
- `tests/e2e/xlsx-viewer.spec.js` : le menu Fichier s'ouvre, expose les 5
|
|
entrées, se ferme au clic extérieur ; Enregistrer présent dans
|
|
`.xlsx-sheetbar-end`.
|
|
- 8 tests préexistants réalignés sur la sémantique « écriture verrouillée
|
|
puis application locale » (le viewer n'est plus re-lu après une écriture
|
|
structure / mise en forme) : le second appel PUT n'a plus lieu, les
|
|
assertions portent sur la grille peinte en place.
|
|
|
|
## 4. Points d'attention
|
|
|
|
- La copie des cellules vers le presse-papiers système et l'export sont
|
|
inchangés : seul le **point d'entrée** des sorties de fichier a bougé.
|
|
- `viewer.js` reste le propriétaire du câblage ; `command-bar.js` reste un
|
|
constructeur de chaînes pur, donc testable sans DOM.
|