diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5514b91..400ada6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,24 @@ Le format suit [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et le pr
## [Unreleased]
+### Added
+
+- **Alignement vertical réglable sur les rangées icône/titre + action** (FSHSP-214).
+ `ui-alert`, `ui-toast` et les en-têtes de `ui-modal`, `ui-drawer` et `ui-bottom-sheet`
+ figeaient `align-items: flex-start`. C'est le bon réglage quand le texte passe sur
+ plusieurs lignes (l'icône reste sur la première) et le mauvais quand il tient sur une
+ seule, où la hauteur minimale laisse du vide sous le texte : aucune valeur statique ne
+ convient aux deux, et les projets en étaient réduits à une surcharge globale sur les
+ classes internes. Treize poignées, à chaque fois la rangée puis ses enfants, lesquels
+ valent `auto` (donc suivent la rangée) par défaut : `--ui-alert-align`,
+ `--ui-alert-icon-align`, `--ui-alert-close-align`, `--ui-toast-align`,
+ `--ui-toast-icon-align`, `--ui-toast-close-align`, `--ui-toast-icon-padding-top`,
+ `--ui-modal-header-align`, `--ui-modal-header-actions-align`, `--ui-drawer-header-align`,
+ `--ui-drawer-action-align`, `--ui-bottom-sheet-header-align` et
+ `--ui-bottom-sheet-action-align`. Aucun défaut ne change. Le calage optique de l'icône
+ (`--ui-{alert,toast}-icon-padding-top`) ne sert qu'en alignement haut : à remettre à `0`
+ quand on centre.
+
### Changed
- **`ui-input-date` : bouton d'ouverture aligné sur `ui-datepicker`** (FSHSP-214). Le champ
diff --git a/figma/README.md b/figma/README.md
index 22765ca..224dde1 100644
--- a/figma/README.md
+++ b/figma/README.md
@@ -10,7 +10,7 @@ The components' `--ui-*` variables, in the same DTCG shape as
one too. Generated by `pnpm docs:config`; `docs:config:check` fails if it is stale.
**These are not design tokens.** A token belongs to the system (`--units-sm`); a
-component variable belongs to one component, and 1261 of the 1418 entries merely _alias_ a
+component variable belongs to one component, and 1262 of the 1419 entries merely _alias_ a
token. Hence a **dedicated collection** (`$extensions.com.4sh.ui-kit.figmaCollection`)
rather than adding them to `semantics` or `metrics`.
@@ -38,9 +38,9 @@ rather than adding them to `semantics` or `metrics`.
variables are `remote`, hence read-only (see `CLAUDE.md`).
- Keep the aliases as aliases: that is what preserves brand, light/dark and responsive.
- Literal values are in `px` (converted from `rem`, base 16), like the token files.
-- `$extensions.com.4sh.ui-kit.skipped` lists 66 entries with nothing to create: `calc()`
+- `$extensions.com.4sh.ui-kit.skipped` lists 78 entries with nothing to create: `calc()`
expressions, multi-value CSS shorthands, relative units (`em`, `ch`, `%`), duration /
- easing / cursor / z-index, and internal plumbing.
+ easing / cursor / z-index / alignment, and internal plumbing.
## Two flags worth reading
diff --git a/figma/component-vars.json b/figma/component-vars.json
index 5c68290..d42fe50 100644
--- a/figma/component-vars.json
+++ b/figma/component-vars.json
@@ -10,10 +10,10 @@
"Mode 1"
],
"counts": {
- "tokens": 1418,
- "alias": 1261,
+ "tokens": 1419,
+ "alias": 1262,
"literal": 157,
- "skipped": 66,
+ "skipped": 78,
"derivedDescriptions": 223
},
"aliasTargets": [
@@ -24,6 +24,21 @@
"typography"
],
"skipped": [
+ {
+ "cssVar": "--ui-alert-align",
+ "component": "ui-alert",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
+ {
+ "cssVar": "--ui-alert-close-align",
+ "component": "ui-alert",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
+ {
+ "cssVar": "--ui-alert-icon-align",
+ "component": "ui-alert",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
{
"cssVar": "--ui-autocomplete-panel-max-width",
"component": "ui-autocomplete",
@@ -44,6 +59,16 @@
"component": "ui-avatar",
"reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
},
+ {
+ "cssVar": "--ui-bottom-sheet-action-align",
+ "component": "ui-bottom-sheet",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
+ {
+ "cssVar": "--ui-bottom-sheet-header-align",
+ "component": "ui-bottom-sheet",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
{
"cssVar": "--ui-bottom-sheet-shadow",
"component": "ui-bottom-sheet",
@@ -89,6 +114,16 @@
"component": "ui-datepicker",
"reason": "`--shadow-default-md` n'est pas un token du pipeline : rien à aliaser."
},
+ {
+ "cssVar": "--ui-drawer-action-align",
+ "component": "ui-drawer",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
+ {
+ "cssVar": "--ui-drawer-header-align",
+ "component": "ui-drawer",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
{
"cssVar": "--ui-drawer-z-index",
"component": "ui-drawer",
@@ -219,6 +254,16 @@
"component": "ui-link",
"reason": "unité relative `em` : sa valeur dépend du contexte de rendu, une variable Figma ne peut pas la porter."
},
+ {
+ "cssVar": "--ui-modal-header-actions-align",
+ "component": "ui-modal",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
+ {
+ "cssVar": "--ui-modal-header-align",
+ "component": "ui-modal",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
{
"cssVar": "--ui-modal-z-index",
"component": "ui-modal",
@@ -349,6 +394,21 @@
"component": "ui-textarea",
"reason": "expression calc() : une variable Figma ne porte pas de calcul."
},
+ {
+ "cssVar": "--ui-toast-align",
+ "component": "ui-toast",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
+ {
+ "cssVar": "--ui-toast-close-align",
+ "component": "ui-toast",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
+ {
+ "cssVar": "--ui-toast-icon-align",
+ "component": "ui-toast",
+ "reason": "sans équivalent variable Figma (durée, easing, curseur, plan d’empilement, ratio)."
+ },
{
"cssVar": "--ui-toast-z-index",
"component": "ui-toast-container",
@@ -1002,7 +1062,7 @@
"padding-top": {
"$value": "{metrics.units.2xs}",
"$type": "dimension",
- "$description": "Décalage vertical de l'icône, pour l'aligner sur la première ligne de texte.",
+ "$description": "Décalage vertical de l'icône, pour l'aligner sur la première ligne de texte ; à remettre à `0` en alignement centré.",
"$extensions": {
"com.figma": {
"resolvedType": "FLOAT",
@@ -30113,6 +30173,30 @@
}
}
},
+ "icon": {
+ "padding-top": {
+ "$value": "{metrics.units.2xs}",
+ "$type": "dimension",
+ "$description": "Décalage vertical de l'icône, pour l'aligner sur la première ligne de texte ; à remettre à `0` en alignement centré.",
+ "$extensions": {
+ "com.figma": {
+ "resolvedType": "FLOAT",
+ "scopes": [
+ "GAP"
+ ],
+ "codeSyntax": {
+ "WEB": "var(--ui-toast-icon-padding-top)"
+ }
+ },
+ "com.4sh.ui-kit": {
+ "cssVar": "--ui-toast-icon-padding-top",
+ "component": "ui-toast",
+ "entryPoint": "@4sh/ui-kit/informative/ui-toast",
+ "descriptionSource": "scss"
+ }
+ }
+ }
+ },
"stack": {
"gap": {
"$value": "{metrics.units.sm}",
diff --git a/projects/ui-kit/informative/ui-alert/src/lib/ui-alert.scss b/projects/ui-kit/informative/ui-alert/src/lib/ui-alert.scss
index 1ad7700..381e120 100644
--- a/projects/ui-kit/informative/ui-alert/src/lib/ui-alert.scss
+++ b/projects/ui-kit/informative/ui-alert/src/lib/ui-alert.scss
@@ -21,7 +21,11 @@ $padding-x: var(--ui-alert-padding-x, var(--units-md)); /// Inset ho
$radius: var(--ui-alert-radius, var(--radius-default)); /// Rayon des coins.
$stroke-width: var(--ui-alert-stroke-width, var(--stroke-default)); /// Épaisseur de la bordure.
-$icon-padding-top: var(--ui-alert-icon-padding-top, var(--units-2xs)); /// Décalage vertical de l'icône, pour l'aligner sur la première ligne de texte.
+$align: var(--ui-alert-align, flex-start); /// Alignement vertical de la rangée (icône, contenu, fermeture) ; le mode titre seul reste centré.
+$icon-align: var(--ui-alert-icon-align, auto); /// Alignement vertical de l'icône seule ; `auto` suit l'alignement de la rangée.
+$close-align: var(--ui-alert-close-align, auto);/// Alignement vertical de la fermeture seule ; `auto` suit l'alignement de la rangée.
+
+$icon-padding-top: var(--ui-alert-icon-padding-top, var(--units-2xs)); /// Décalage vertical de l'icône, pour l'aligner sur la première ligne de texte ; à remettre à `0` en alignement centré.
$content-gap: var(--ui-alert-content-gap, var(--units-2xs)); /// Espacement titre ↔ message.
$content-padding-right: var(--ui-alert-content-padding-right, var(--units-sm)); /// Réserve à droite du contenu, avant la fermeture.
@@ -62,7 +66,7 @@ $focus-ring-offset: var(--ui-alert-focus-ring-offset, #{utils.rem-calc(2)});
.ui-alert {
// --- Base ----------------------------------------------------------
display: flex;
- align-items: flex-start;
+ align-items: $align;
gap: $gap;
box-sizing: border-box;
width: 100%;
@@ -80,6 +84,7 @@ $focus-ring-offset: var(--ui-alert-focus-ring-offset, #{utils.rem-calc(2)});
flex: 0 0 auto;
display: flex;
align-items: center;
+ align-self: $icon-align;
padding-top: $icon-padding-top;
line-height: 0;
}
@@ -112,6 +117,7 @@ $focus-ring-offset: var(--ui-alert-focus-ring-offset, #{utils.rem-calc(2)});
flex: 0 0 auto;
display: inline-flex;
align-items: center;
+ align-self: $close-align;
justify-content: center;
padding: 0;
border: 0;
diff --git a/projects/ui-kit/informative/ui-alert/ui-alert.mdx b/projects/ui-kit/informative/ui-alert/ui-alert.mdx
index 465fd07..db24664 100644
--- a/projects/ui-kit/informative/ui-alert/ui-alert.mdx
+++ b/projects/ui-kit/informative/ui-alert/ui-alert.mdx
@@ -127,6 +127,40 @@ Les erreurs de validation d'un formulaire s'affichent en sévérité `error`.
+## Alignement vertical
+
+La rangée `icône | contenu | fermeture` est calée en haut, parce que c'est le seul réglage
+juste quand le texte passe sur plusieurs lignes : l'icône doit rester sur la première. Sur un
+message court, la hauteur minimale laisse alors du vide sous le texte, et c'est là qu'un
+projet veut centrer. Aucun réglage statique ne convient aux deux cas, d'où trois poignées, de
+la plus large à la plus fine :
+
+| Variable | Porte sur |
+| --- | --- |
+| `--ui-alert-align` | toute la rangée |
+| `--ui-alert-icon-align` | l'icône seule (`auto` = suit la rangée) |
+| `--ui-alert-close-align` | la fermeture seule (`auto` = suit la rangée) |
+
+```css
+/* tout centrer */
+ui-alert {
+ --ui-alert-align: center;
+ --ui-alert-icon-padding-top: 0; /* le calage optique ne sert qu'en haut */
+}
+
+/* contenu centré, icône et fermeture posées sur la première ligne */
+ui-alert {
+ --ui-alert-align: center;
+ --ui-alert-icon-align: flex-start;
+ --ui-alert-close-align: flex-start;
+}
+```
+
+Le mode titre seul reste centré par construction : une seule ligne, rien à décaler. Les mêmes
+poignées existent sur [`ui-toast`](?path=/docs/components-ui-informative-ui-toast--docs), et
+sur les en-têtes de `ui-modal`, `ui-drawer` et `ui-bottom-sheet`.
+
+
## Theming
diff --git a/projects/ui-kit/informative/ui-toast/src/lib/ui-toast.scss b/projects/ui-kit/informative/ui-toast/src/lib/ui-toast.scss
index b6055ec..ab398c2 100644
--- a/projects/ui-kit/informative/ui-toast/src/lib/ui-toast.scss
+++ b/projects/ui-kit/informative/ui-toast/src/lib/ui-toast.scss
@@ -15,13 +15,19 @@
$levels: default, highlight, success, warning, error; /// Niveaux sémantiques générant les modifiers `._`.
$sublevels: high, low; /// Intensités générant les modifiers `._`.
+$align: var(--ui-toast-align, flex-start); /// Alignement vertical de la rangée (icône, contenu, fermeture).
+$icon-align: var(--ui-toast-icon-align, auto); /// Alignement vertical de l'icône seule ; `auto` suit l'alignement de la rangée.
+$close-align: var(--ui-toast-close-align, auto); /// Alignement vertical de la fermeture seule ; `auto` suit l'alignement de la rangée.
+
+$icon-padding-top: var(--ui-toast-icon-padding-top, var(--units-2xs)); /// Décalage vertical de l'icône, pour l'aligner sur la première ligne de texte ; à remettre à `0` en alignement centré.
+
// Reused structural constant (kit-wide focus ring). Local alias, never copied.
$focus-ring-width: var(--ui-toast-focus-ring-width, #{utils.$focus-ring-width}); /// Épaisseur de l'anneau de focus.
.ui-toast {
// --- Base ----------------------------------------------------------
display: inline-flex;
- align-items: flex-start;
+ align-items: $align;
gap: var(--units-sm);
box-sizing: border-box;
width: auto;
@@ -45,8 +51,9 @@ $focus-ring-width: var(--ui-toast-focus-ring-width, #{utils.$focus-ring-width});
flex: 0 0 auto;
display: flex;
align-items: center;
+ align-self: $icon-align;
// Nudge the icon down so it lines up with the title cap-height.
- padding-top: var(--units-2xs);
+ padding-top: $icon-padding-top;
line-height: 0;
}
@@ -80,6 +87,7 @@ $focus-ring-width: var(--ui-toast-focus-ring-width, #{utils.$focus-ring-width});
flex: 0 0 auto;
display: inline-flex;
align-items: center;
+ align-self: $close-align;
justify-content: center;
padding: 0;
border: 0;
diff --git a/projects/ui-kit/informative/ui-toast/ui-toast.mdx b/projects/ui-kit/informative/ui-toast/ui-toast.mdx
index 3c2cfb7..cba20d8 100644
--- a/projects/ui-kit/informative/ui-toast/ui-toast.mdx
+++ b/projects/ui-kit/informative/ui-toast/ui-toast.mdx
@@ -149,6 +149,26 @@ respectés automatiquement.
+## Alignement vertical
+
+Même contrat que sur [`ui-alert`](?path=/docs/components-ui-informative-ui-alert--docs) : la
+rangée `icône | contenu | fermeture` est calée en haut, ce qui est juste sur un texte qui
+passe à la ligne et laisse du vide sur un texte court.
+
+| Variable | Porte sur |
+| --- | --- |
+| `--ui-toast-align` | toute la rangée |
+| `--ui-toast-icon-align` | l'icône seule (`auto` = suit la rangée) |
+| `--ui-toast-close-align` | la fermeture seule (`auto` = suit la rangée) |
+
+```css
+ui-toast {
+ --ui-toast-align: center;
+ --ui-toast-icon-padding-top: 0; /* le calage optique ne sert qu'en haut */
+}
+```
+
+
## Theming
Constantes locales à `ui-toast-container.scss` (structurelles, jamais de couleur : les couleurs
diff --git a/projects/ui-kit/layout/ui-bottom-sheet/src/lib/ui-bottom-sheet.scss b/projects/ui-kit/layout/ui-bottom-sheet/src/lib/ui-bottom-sheet.scss
index 1f6f43d..b83c1e9 100644
--- a/projects/ui-kit/layout/ui-bottom-sheet/src/lib/ui-bottom-sheet.scss
+++ b/projects/ui-kit/layout/ui-bottom-sheet/src/lib/ui-bottom-sheet.scss
@@ -32,6 +32,8 @@ $safe-area: var(--ui-bottom-sheet-safe-area-offset, env(safe-area-inset-bottom,
$panel-padding: var(--ui-bottom-sheet-padding, var(--units-default)); /// Inset horizontal du panneau et inset haut du corps.
$panel-padding-bottom: var(--ui-bottom-sheet-padding-bottom, var(--units-lg)); /// Inset bas de la dernière zone du panneau.
$header-gap: var(--ui-bottom-sheet-header-gap, var(--units-sm)); /// Espacement entre le titre et le bouton de fermeture.
+$header-align: var(--ui-bottom-sheet-header-align, flex-start); /// Alignement vertical de l'en-tête (titre, fermeture).
+$action-align: var(--ui-bottom-sheet-action-align, auto); /// Alignement vertical de la fermeture seule ; `auto` suit l'alignement de l'en-tête.
$footer-gap: var(--ui-bottom-sheet-footer-gap, var(--units-default)); /// Espacement entre les actions du pied.
$footer-padding-top: var(--ui-bottom-sheet-footer-padding-top, var(--units-sm)); /// Inset haut du pied.
$action-size: var(--ui-bottom-sheet-action-size, #{utils.rem-calc(32)}); /// Taille de la cible tactile du bouton de fermeture.
@@ -225,7 +227,7 @@ $focus-ring-width: var(--ui-bottom-sheet-focus-ring-width, #{utils.$focus-ring-w
&-header {
flex: 0 0 auto;
display: flex;
- align-items: flex-start;
+ align-items: $header-align;
gap: $header-gap;
padding-top: $grab-padding-y;
}
@@ -251,6 +253,7 @@ $focus-ring-width: var(--ui-bottom-sheet-focus-ring-width, #{utils.$focus-ring-w
flex: 0 0 auto;
display: inline-flex;
align-items: center;
+ align-self: $action-align;
justify-content: center;
box-sizing: border-box;
width: $action-size;
diff --git a/projects/ui-kit/layout/ui-bottom-sheet/ui-bottom-sheet.mdx b/projects/ui-kit/layout/ui-bottom-sheet/ui-bottom-sheet.mdx
index a13d7d4..4261104 100644
--- a/projects/ui-kit/layout/ui-bottom-sheet/ui-bottom-sheet.mdx
+++ b/projects/ui-kit/layout/ui-bottom-sheet/ui-bottom-sheet.mdx
@@ -275,6 +275,23 @@ Trois écarts assumés, notés ici pour qu'ils ne passent pas pour des oublis :
+## Alignement vertical de l'en-tête
+
+L'en-tête (titre et bouton de fermeture) est calé en haut, ce qui est juste quand le titre passe sur deux lignes
+et laisse du vide quand il tient sur une. Deux poignées plutôt qu'une surcharge globale :
+
+| Variable | Porte sur |
+| --- | --- |
+| `--ui-bottom-sheet-header-align` | toute la rangée |
+| `--ui-bottom-sheet-action-align` | la fermeture seule (`auto` = suit la rangée) |
+
+```css
+ui-bottom-sheet {
+ --ui-bottom-sheet-header-align: center;
+}
+```
+
+
## Theming
Variables locales en tête de `ui-bottom-sheet.scss`. Voir le
diff --git a/projects/ui-kit/layout/ui-drawer/src/lib/ui-drawer.scss b/projects/ui-kit/layout/ui-drawer/src/lib/ui-drawer.scss
index 0704f27..bda8882 100644
--- a/projects/ui-kit/layout/ui-drawer/src/lib/ui-drawer.scss
+++ b/projects/ui-kit/layout/ui-drawer/src/lib/ui-drawer.scss
@@ -17,6 +17,8 @@ $drawer-z-index: var(--ui-drawer-z-index, 1100);
$stroke-width: var(--ui-drawer-stroke-width, var(--stroke-sm)); /// Épaisseur de bordure du panneau.
$panel-padding: var(--ui-drawer-panel-padding, var(--units-lg)); /// Inset du panneau.
$header-gap: var(--ui-drawer-header-gap, var(--units-sm)); /// Espacement entre les éléments de l'en-tête.
+$header-align: var(--ui-drawer-header-align, flex-start); /// Alignement vertical de l'en-tête (titre, fermeture).
+$action-align: var(--ui-drawer-action-align, auto); /// Alignement vertical de la fermeture seule ; `auto` suit l'alignement de l'en-tête.
$action-size: var(--ui-drawer-action-size, #{utils.rem-calc(32)}); /// Taille de la cible tactile du bouton de fermeture.
$focus-ring-width: var(--ui-drawer-focus-ring-width, #{utils.$focus-ring-width}); /// Épaisseur de l'anneau de focus du bouton de fermeture
$mask-background: var(--ui-drawer-mask-background, var(--primitives-black-50)); /// Assombrissement du masque.
@@ -116,7 +118,7 @@ $size-edge: var(--ui-drawer-size-edge, #{utils.rem-calc(160)});
&-header {
flex: 0 0 auto;
display: flex;
- align-items: flex-start;
+ align-items: $header-align;
gap: $header-gap;
padding: $panel-padding $panel-padding var(--units-sm);
}
@@ -136,6 +138,7 @@ $size-edge: var(--ui-drawer-size-edge, #{utils.rem-calc(160)});
flex: 0 0 auto;
display: inline-flex;
align-items: center;
+ align-self: $action-align;
justify-content: center;
width: $action-size;
height: $action-size;
diff --git a/projects/ui-kit/layout/ui-drawer/ui-drawer.mdx b/projects/ui-kit/layout/ui-drawer/ui-drawer.mdx
index ce96ac1..a717f18 100644
--- a/projects/ui-kit/layout/ui-drawer/ui-drawer.mdx
+++ b/projects/ui-kit/layout/ui-drawer/ui-drawer.mdx
@@ -135,6 +135,23 @@ un conteneur borné (panneau, aperçu). Le conteneur parent doit être positionn
+## Alignement vertical de l'en-tête
+
+L'en-tête (titre et bouton de fermeture) est calé en haut, ce qui est juste quand le titre passe sur deux lignes
+et laisse du vide quand il tient sur une. Deux poignées plutôt qu'une surcharge globale :
+
+| Variable | Porte sur |
+| --- | --- |
+| `--ui-drawer-header-align` | toute la rangée |
+| `--ui-drawer-action-align` | la fermeture seule (`auto` = suit la rangée) |
+
+```css
+ui-drawer {
+ --ui-drawer-header-align: center;
+}
+```
+
+
## Theming
Variables locales en tête de `ui-drawer.scss`. Voir le
diff --git a/projects/ui-kit/layout/ui-modal/src/lib/ui-modal.scss b/projects/ui-kit/layout/ui-modal/src/lib/ui-modal.scss
index 8890fab..9d99bae 100644
--- a/projects/ui-kit/layout/ui-modal/src/lib/ui-modal.scss
+++ b/projects/ui-kit/layout/ui-modal/src/lib/ui-modal.scss
@@ -13,6 +13,8 @@ $mask-padding: var(--ui-modal-mask-padding, var(--units-lg));
$dialog-radius: var(--ui-modal-dialog-radius, var(--radius-md)); /// Rayon du dialogue.
$dialog-padding: var(--ui-modal-dialog-padding, var(--units-lg)); /// Inset du dialogue.
$header-gap: var(--ui-modal-header-gap, var(--units-sm)); /// Espacement entre les éléments de l'en-tête.
+$header-align: var(--ui-modal-header-align, flex-start); /// Alignement vertical de l'en-tête (titre, actions).
+$header-actions-align: var(--ui-modal-header-actions-align, auto); /// Alignement vertical des actions seules ; `auto` suit l'alignement de l'en-tête.
$stroke-width: var(--ui-modal-stroke-width, var(--stroke-sm)); /// Épaisseur de bordure du dialogue.
$action-size: var(--ui-modal-action-size, #{utils.rem-calc(32)}); /// Taille de la cible tactile du bouton de fermeture.
$resize-handle-size: var(--ui-modal-resize-handle-size, 16px); /// Taille de la poignée de redimensionnement.
@@ -93,7 +95,7 @@ $mask-background: var(--ui-modal-mask-background, var(--primitives-black-50));
&-header {
flex: 0 0 auto;
display: flex;
- align-items: flex-start;
+ align-items: $header-align;
gap: $header-gap;
padding: $dialog-padding $dialog-padding var(--units-sm);
@@ -118,6 +120,7 @@ $mask-background: var(--ui-modal-mask-background, var(--primitives-black-50));
flex: 0 0 auto;
display: inline-flex;
align-items: center;
+ align-self: $header-actions-align;
gap: var(--units-2xs);
}
diff --git a/projects/ui-kit/layout/ui-modal/ui-modal.mdx b/projects/ui-kit/layout/ui-modal/ui-modal.mdx
index 6996f4d..fa812b3 100644
--- a/projects/ui-kit/layout/ui-modal/ui-modal.mdx
+++ b/projects/ui-kit/layout/ui-modal/ui-modal.mdx
@@ -156,6 +156,23 @@ reste **interactif et scrollable** (`blockScroll` peut tout de même figer le sc
+## Alignement vertical de l'en-tête
+
+L'en-tête (titre et actions) est calé en haut, ce qui est juste quand le titre passe sur deux lignes
+et laisse du vide quand il tient sur une. Deux poignées plutôt qu'une surcharge globale :
+
+| Variable | Porte sur |
+| --- | --- |
+| `--ui-modal-header-align` | toute la rangée |
+| `--ui-modal-header-actions-align` | les actions seules (`auto` = suit la rangée) |
+
+```css
+ui-modal {
+ --ui-modal-header-align: center;
+}
+```
+
+
## Theming
Variables locales en tête de `ui-modal.scss`. Voir le
diff --git a/projects/ui-kit/styles/component-vars.scss b/projects/ui-kit/styles/component-vars.scss
index c4a6cf5..16144d0 100644
--- a/projects/ui-kit/styles/component-vars.scss
+++ b/projects/ui-kit/styles/component-vars.scss
@@ -11,7 +11,7 @@
// design token instead — it follows brand, light/dark and viewport.
//
// Generated by `pnpm docs:config`, values read from the compiled CSS — do not
-// edit here. 1356 variables; 128 more exist whose value depends on the
+// edit here. 1369 variables; 128 more exist whose value depends on the
// rendered variant, listed in each component’s “Theming” section in Storybook.
// =====================================================================
@@ -1068,7 +1068,10 @@
--ui-alert-title-font-size-large: var(--size-typography-title-md);
--ui-alert-title-weight: var(--weight-bold);
// Divers
+ --ui-alert-align: flex-start;
+ --ui-alert-close-align: auto;
--ui-alert-close-opacity: 0.7;
+ --ui-alert-icon-align: auto;
// ── ui-avatar ──
// Dimensions
@@ -1280,6 +1283,8 @@
--ui-tag-weight: var(--weight-regular);
// ── ui-toast ──
+ // Espacements
+ --ui-toast-icon-padding-top: var(--units-2xs);
// Bordures & rayons
--ui-toast-focus-ring-width: var(--ui-focus-ring-width, var(--units-2xs));
// Typographie
@@ -1287,6 +1292,10 @@
--ui-toast-text-weight: var(--weight-light);
--ui-toast-title-font-family: var(--fontfamily-title);
--ui-toast-title-weight: var(--weight-bold);
+ // Divers
+ --ui-toast-align: flex-start;
+ --ui-toast-close-align: auto;
+ --ui-toast-icon-align: auto;
// ── ui-toast-container ──
// Dimensions
@@ -1361,6 +1370,8 @@
--ui-bottom-sheet-mask-background: var(--primitives-black-50);
--ui-bottom-sheet-surface: var(--global-background-default);
// Divers
+ --ui-bottom-sheet-action-align: auto;
+ --ui-bottom-sheet-header-align: flex-start;
--ui-bottom-sheet-shadow: var(--shadow-default-lg);
--ui-bottom-sheet-z-index: 1100;
@@ -1410,6 +1421,8 @@
--ui-drawer-stroke: var(--global-border-subtle);
--ui-drawer-surface: var(--global-background-default);
// Divers
+ --ui-drawer-action-align: auto;
+ --ui-drawer-header-align: flex-start;
--ui-drawer-z-index: 1100;
// ── ui-modal ──
@@ -1439,6 +1452,8 @@
--ui-modal-stroke: var(--global-border-subtle);
--ui-modal-surface: var(--global-background-default);
// Divers
+ --ui-modal-header-actions-align: auto;
+ --ui-modal-header-align: flex-start;
--ui-modal-z-index: 1100;
// ── ui-popover ──
diff --git a/scripts/component-vars.build.mjs b/scripts/component-vars.build.mjs
index a8feafc..015487e 100644
--- a/scripts/component-vars.build.mjs
+++ b/scripts/component-vars.build.mjs
@@ -280,6 +280,13 @@ const PROPERTIES = {
bindable: false,
},
cursor: { fr: 'Curseur', group: 'misc', type: 'STRING', scopes: ['ALL_SCOPES'], bindable: false },
+ align: {
+ fr: 'Alignement',
+ group: 'misc',
+ type: 'STRING',
+ scopes: ['ALL_SCOPES'],
+ bindable: false,
+ },
'object-fit': {
fr: 'Cadrage du média',
group: 'misc',