Audit complet de mise en forme — Titre/Paragraphe (1er élément du tableau)

Nouveau module partagé document_engine/rendering/box_style.py
(padding/margin/background_color/border_radius/border par côté/height/
min-height/max-height/min-width/box-shadow/opacity/align_self) —
réutilisable tel quel par tous les kinds suivants du tableau d'audit.

Titre/Paragraphe gagnent : barré, police de caractère, taille de
police, hauteur de ligne, espacement des lettres, majuscules/
minuscules/capitales, ombre du texte, et tous les attributs de boîte
partagés ci-dessus. Interface entièrement à base de curseurs/cases à
cocher/listes déroulantes/sélecteurs de couleur natifs — plus aucun
champ de texte libre pour une valeur CSS (retour utilisateur).

Deux bugs transversaux corrigés au passage (concernent tout
l'éditeur) :
- Le panneau Propriétés n'était jamais reconstruit après un clic sur un
  bouton (gras/alignement/segments...) — il fallait recharger la page
  pour voir l'état réel. Corrigé dans forgeDocUpdateAttributes, point
  d'entrée unique de toute mise à jour d'attribut.
- Les cases à cocher et curseurs héritaient à tort le style d'un champ
  de texte (padding/bordure/fond/largeur 100%) via la règle générique
  .docField input.

Ajoute docs/plan/AUDIT_MISE_EN_FORME.md : suivi de l'audit élément par
élément (Titre/Paragraphe traité, Image ensuite).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-26 09:25:30 +02:00
co-authored by Claude Sonnet 5
parent e03bea39c5
commit 6c7675fad0
10 changed files with 942 additions and 25 deletions
+59 -6
View File
@@ -29,12 +29,24 @@ regroupement à chaque appel.
`justify-content` réels depuis `attributes`), enfants rendus
récursivement.
- **Texte** (`titre`/`paragraphe`) : `<div>` stylé selon `style` (préréglage
taille/graisse/interligne) et `bold`/`italic`/`underline`/`align`/`color`.
`max_width` (optionnel, ex. `"60ch"`, `"480px"`) ajoute `max-width` au
style inline quand non vide — pleine largeur de `.docPageContent` par
défaut, retour utilisateur du 24/09/2026 (un paragraphe doit pouvoir
rester plus étroit que la page, sans dépendre d'une rangée qui en
partagerait la largeur avec un frère).
taille/graisse/interligne) et `bold`/`italic`/`underline`/`strikethrough`/
`align`/`color`. `underline`/`strikethrough` se combinent dans un seul
`text-decoration` (`"underline line-through"` si les deux sont actifs).
`font_size`/`line_height` (vides par défaut) remplacent les valeurs du
préréglage `style` SANS toucher `font-weight` (toujours piloté par le
préréglage + `bold`). `text_transform` (`"none"` par défaut) ajoute
`text-transform` quand différent de `"none"`. `font_family`/
`letter_spacing`/`text_shadow` (vides par défaut) ajoutent leur
déclaration CSS respective quand non vides. `max_width` (optionnel, ex.
`"60ch"`, `"480px"`) ajoute `max-width` au style inline quand non vide —
pleine largeur de `.docPageContent` par défaut, retour utilisateur du
24/09/2026 (un paragraphe doit pouvoir rester plus étroit que la page,
sans dépendre d'une rangée qui en partagerait la largeur avec un frère).
Termine par `render_box_style(a)` (voir `box_style.py` ci-dessous) pour
`padding`/`margin`/`background_color`/`border_radius`/`border`/
`align_self` — attributs PARTAGÉS avec d'autres kinds, jamais dupliqués
ici (audit du 26/09/2026, réglages manquants à couvrir élément par
élément en réutilisant ce module).
- **Image** : `<img>`, ou un bloc placeholder si `src` est vide — OU, si
`attributes["svg_markup"]` est non vide (prioritaire sur `src`), un
`<div>` portant directement ce fragment SVG nettoyé par
@@ -180,6 +192,47 @@ regroupement à chaque appel.
emplacement réservé, formulaire de contenu dédié hors périmètre de
cette passe.
## `box_style.py` — attributs de "boîte" partagés entre plusieurs kinds
Audit du 26/09/2026 (réglages manquants, à couvrir élément par élément) :
padding/margin/couleur de fond/arrondi/bordure par côté/position du bloc
sont des besoins IDENTIQUES pour la plupart des kinds de contenu — un
seul jeu d'attributs et une seule fonction de rendu ici, jamais réécrits
à chaque kind (voir `_render_text` pour le premier usage réel).
### `BORDER_SIDES: tuple[str, ...]`
`("top", "right", "bottom", "left")`.
### `default_border() -> dict[str, dict[str, str]]`
Un dict à 4 clés (`BORDER_SIDES`), chacune `{"style": "none", "width":
"1px", "color": "var(--doc-border)"}`.
- **Retour** : un NOUVEAU dict à chaque appel (jamais un littéral partagé
muté par référence entre deux éléments — même précaution que
`DEFAULT_QUIZ_CONFIG` côté `labels/`).
- **Exceptions** : aucune.
### `BOX_DEFAULTS: dict[str, Any]`
`{"padding": "", "margin": "", "background_color": "", "border_radius":
"", "align_self": "stretch", "height": "", "min_height": "",
"max_height": "", "min_width": "", "box_shadow": "", "opacity": ""}` —
`border` n'y figure PAS (voir `default_border()`, à ajouter séparément
par chaque appelant pour éviter le partage par référence).
### `render_box_style(a: dict[str, Any]) -> str`
Construit les déclarations CSS inline pour `padding`/`margin`/
`background_color`/`border_radius`/`height`/`min_height`/`max_height`/
`min_width`/`box_shadow`/`opacity`/`border`/`align_self` de `a` — un
attribut absent ou à sa valeur par défaut ne produit AUCUNE déclaration
(comportement historique inchangé). `border` est un dict à 4 clés
(`BORDER_SIDES`), chacune `{"style", "width", "color"}` — un côté à
`style="none"` (ou absent) ne produit rien pour ce côté, jamais un
`border-top:none` explicite. `align-self` n'est ajouté que si différent
de `"stretch"` (déjà le comportement par défaut d'un enfant flex en
colonne).
- **Retour** : les déclarations CSS (`"propriete:valeur; ..."`), chaîne
vide si rien à ajouter.
- **Exceptions** : aucune.
## `sanitize_svg_markup.py` — nettoyage du contenu SVG inline d'une image
### `sanitize_svg_markup(markup: str) -> str`