@ktortu/aaa 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/button/button-tokens.css +152 -0
  4. package/button/button.css +319 -0
  5. package/card/card-tokens.css +49 -0
  6. package/card/card.css +200 -0
  7. package/cdk/styles/foundation.css +83 -0
  8. package/cdk/styles/tabs.css +276 -0
  9. package/dialog/dialog.css +350 -0
  10. package/fesm2022/ktortu-aaa-button.mjs +128 -0
  11. package/fesm2022/ktortu-aaa-button.mjs.map +1 -0
  12. package/fesm2022/ktortu-aaa-card.mjs +209 -0
  13. package/fesm2022/ktortu-aaa-card.mjs.map +1 -0
  14. package/fesm2022/ktortu-aaa-cdk.mjs +183 -0
  15. package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -0
  16. package/fesm2022/ktortu-aaa-dialog.mjs +512 -0
  17. package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -0
  18. package/fesm2022/ktortu-aaa-forms.mjs +3215 -0
  19. package/fesm2022/ktortu-aaa-forms.mjs.map +1 -0
  20. package/fesm2022/ktortu-aaa-menu.mjs +315 -0
  21. package/fesm2022/ktortu-aaa-menu.mjs.map +1 -0
  22. package/fesm2022/ktortu-aaa-tabs.mjs +79 -0
  23. package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -0
  24. package/fesm2022/ktortu-aaa-tooltip.mjs +356 -0
  25. package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -0
  26. package/fesm2022/ktortu-aaa.mjs +17 -0
  27. package/fesm2022/ktortu-aaa.mjs.map +1 -0
  28. package/forms/checkbox/checkbox-group.css +55 -0
  29. package/forms/checkbox/checkbox.css +216 -0
  30. package/forms/chips/chip-list.css +70 -0
  31. package/forms/chips/chip.css +92 -0
  32. package/forms/chips/tokens.css +102 -0
  33. package/forms/field/field.css +87 -0
  34. package/forms/multi-select/multi-select.css +136 -0
  35. package/forms/radio/radio-group.css +55 -0
  36. package/forms/radio/radio.css +165 -0
  37. package/forms/styles/field-box.css +171 -0
  38. package/forms/styles/select-panel.css +464 -0
  39. package/forms/styles/tokens.css +67 -0
  40. package/forms/switch/switch.css +188 -0
  41. package/menu/menu-tokens.css +58 -0
  42. package/menu/menu.css +224 -0
  43. package/package.json +96 -0
  44. package/styles/button.css +6 -0
  45. package/styles/card.css +6 -0
  46. package/styles/dialog.css +6 -0
  47. package/styles/forms.css +13 -0
  48. package/styles/foundation.css +7 -0
  49. package/styles/menu.css +6 -0
  50. package/styles/styles.css +24 -0
  51. package/styles/tabs.css +5 -0
  52. package/styles/tooltip.css +5 -0
  53. package/themes/theme-ant.css +44 -0
  54. package/themes/theme-architecte.css +83 -0
  55. package/themes/theme-aurora.css +97 -0
  56. package/themes/theme-bootstrap.css +46 -0
  57. package/themes/theme-carbon.css +49 -0
  58. package/themes/theme-catppuccin.css +66 -0
  59. package/themes/theme-cyberpunk.css +211 -0
  60. package/themes/theme-fluent.css +45 -0
  61. package/themes/theme-material-you.css +74 -0
  62. package/themes/theme-material.css +48 -0
  63. package/themes/theme-primer.css +46 -0
  64. package/themes/theme-vegetal.css +78 -0
  65. package/tooltip/tooltip.css +129 -0
  66. package/types/ktortu-aaa-button.d.ts +70 -0
  67. package/types/ktortu-aaa-card.d.ts +143 -0
  68. package/types/ktortu-aaa-cdk.d.ts +110 -0
  69. package/types/ktortu-aaa-dialog.d.ts +286 -0
  70. package/types/ktortu-aaa-forms.d.ts +1574 -0
  71. package/types/ktortu-aaa-menu.d.ts +171 -0
  72. package/types/ktortu-aaa-tabs.d.ts +27 -0
  73. package/types/ktortu-aaa-tooltip.d.ts +90 -0
  74. package/types/ktortu-aaa.d.ts +8 -0
@@ -0,0 +1,216 @@
1
+ @layer kt-aaa.components {
2
+ :host {
3
+ display: block;
4
+ }
5
+
6
+ .kt-checkbox-field {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--field-gap, 0.375rem);
10
+ }
11
+
12
+ /* Surface cliquable (label) : remplit tout le host, cible tactile confortable (AAA 2.5.5) sur
13
+ toute la rangée. Rembourrage par token (`--checkbox-padding`) pour bâtir une carte/option
14
+ cliquable sans franchir l'encapsulation ; rayon hérité du host. */
15
+ .kt-checkbox {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: var(--field-control-gap, 0.5rem);
19
+ inline-size: 100%;
20
+ box-sizing: border-box;
21
+ min-block-size: var(--checkbox-target-size, 44px);
22
+ padding: var(--checkbox-padding, 0);
23
+ border-radius: inherit;
24
+ cursor: pointer;
25
+ user-select: none;
26
+ }
27
+
28
+ /* La case elle-même : input natif redessiné. Taille pilotée par UN token via `font-size`
29
+ (la box et la coche s'expriment en `em`, donc tout suit `--checkbox-size`). */
30
+ .kt-checkbox__input {
31
+ appearance: none;
32
+ -webkit-appearance: none;
33
+ margin: 0;
34
+ flex: none;
35
+ box-sizing: border-box;
36
+ display: grid;
37
+ place-content: center;
38
+ font-size: var(--checkbox-size, 1.25rem);
39
+ inline-size: 1em;
40
+ block-size: 1em;
41
+ border: var(--checkbox-border-width, 2px) solid
42
+ var(--checkbox-border-color, var(--field-border-color, var(--kt-outline, #c4c7c5)));
43
+ border-radius: var(--checkbox-radius, 0.25rem);
44
+ background-color: var(--checkbox-bg, var(--field-bg, var(--kt-surface, #ffffff)));
45
+ cursor: pointer;
46
+ /* Élévation/glow de repos : retombe sur le token de thème des champs (--field-shadow) pour que
47
+ la case « rayonne » comme les champs sous un thème (aurora, cyberpunk…). `none` par défaut. */
48
+ box-shadow: var(--checkbox-shadow, var(--field-shadow, none));
49
+ /* Token de BASCULE (cf. --switch-transition) : transitionne aussi box-shadow pour animer le glow. */
50
+ transition: var(
51
+ --checkbox-transition,
52
+ background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
53
+ border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
54
+ box-shadow 0.2s ease
55
+ );
56
+ }
57
+
58
+ /* La coche : pseudo-élément masqué par clip-path, mis à l'échelle 0 → 1.
59
+ `box-shadow: inset` remplit la forme de la couleur de coche (technique cross-browser fiable). */
60
+ .kt-checkbox__input::before {
61
+ content: '';
62
+ inline-size: 0.65em;
63
+ block-size: 0.65em;
64
+ transform: scale(0);
65
+ transform-origin: center;
66
+ box-shadow: inset 1em 1em var(--checkbox-mark-color, #ffffff);
67
+ clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
68
+ /* Décochage : repli doux vers scale(0). */
69
+ transition: var(--checkbox-mark-transition, transform 0.12s ease-in);
70
+ }
71
+
72
+ /* Cochage : « pop » avec rebond via @keyframes — fiable car déclenché à l'ENTRÉE dans l'état
73
+ `:checked` (une transition, elle, exige un diff de valeur entre deux recalculs, que la
74
+ ré-écriture de `checked` par Angular écrase → elle ne démarrait pas). */
75
+ .kt-checkbox__input:checked::before,
76
+ .kt-checkbox__input:indeterminate::before {
77
+ transform: scale(1);
78
+ animation: var(--checkbox-mark-animation, kt-checkbox-pop 0.22s cubic-bezier(0.34, 1.56, 0.64, 1));
79
+ }
80
+
81
+ /* État indéterminé : une barre horizontale au lieu de la coche. */
82
+ .kt-checkbox__input:indeterminate::before {
83
+ clip-path: inset(42% 12%);
84
+ }
85
+
86
+ @keyframes kt-checkbox-pop {
87
+ from {
88
+ transform: scale(0);
89
+ }
90
+ }
91
+
92
+ /* États COCHÉ / INDÉTERMINÉ : remplissage plein + HALO coloré dérivé du primaire du thème
93
+ (« glow » visible dans tous les thèmes ; apparaît en fondu via la transition box-shadow).
94
+ Surchargeable/désactivable par thème via --checkbox-shadow-checked. */
95
+ .kt-checkbox__input:checked,
96
+ .kt-checkbox__input:indeterminate {
97
+ background-color: var(--checkbox-bg-checked, var(--kt-primary, #0842a0));
98
+ border-color: var(--checkbox-border-color-checked, var(--checkbox-bg-checked, var(--kt-primary, #0842a0)));
99
+ box-shadow: var(
100
+ --checkbox-shadow-checked,
101
+ 0 0 8px color-mix(in srgb, var(--checkbox-bg-checked, var(--kt-primary, #0842a0)) 50%, transparent)
102
+ );
103
+ }
104
+
105
+ /* HOVER : bordure + glow de survol du thème (--field-shadow-hover). */
106
+ .kt-checkbox__input:hover:not(:disabled) {
107
+ border-color: var(
108
+ --checkbox-border-color-hover,
109
+ var(--field-border-color-hover, var(--kt-outline-strong, #5f6368))
110
+ );
111
+ box-shadow: var(
112
+ --checkbox-shadow-hover,
113
+ var(--field-shadow-hover, var(--checkbox-shadow, var(--field-shadow, none)))
114
+ );
115
+ }
116
+
117
+ .kt-checkbox__input:checked:hover:not(:disabled),
118
+ .kt-checkbox__input:indeterminate:hover:not(:disabled) {
119
+ background-color: var(--checkbox-bg-checked-hover, color-mix(in srgb, var(--kt-primary, #0842a0) 90%, black));
120
+ border-color: var(--checkbox-bg-checked-hover, color-mix(in srgb, var(--kt-primary, #0842a0) 90%, black));
121
+ }
122
+
123
+ /* FOCUS : anneau via `outline` (comme les champs → pas de conflit avec le glow box-shadow), +
124
+ glow de focus du thème (--field-shadow-focus). L'outline reste visible quel que soit le survol. */
125
+ .kt-checkbox__input:focus-visible {
126
+ outline: var(--kt-focus-ring-width, 2px) solid var(--kt-focus-ring-color, #0842a0);
127
+ outline-offset: var(--checkbox-focus-ring-offset, 2px);
128
+ box-shadow: var(--checkbox-shadow-focus, var(--field-shadow-focus, var(--field-shadow, none)));
129
+ }
130
+
131
+ /* DÉSACTIVÉ */
132
+ .kt-checkbox__input:disabled {
133
+ cursor: not-allowed;
134
+ opacity: 0.5;
135
+ }
136
+
137
+ .kt-checkbox-field--disabled .kt-checkbox {
138
+ cursor: not-allowed;
139
+ }
140
+
141
+ /* INVALIDE */
142
+ .kt-checkbox-field--invalid .kt-checkbox__input:not(:checked):not(:indeterminate) {
143
+ border-color: var(--field-error-color, var(--kt-danger, #8c1d18));
144
+ }
145
+
146
+ /* Libellé */
147
+ .kt-checkbox__label {
148
+ font-size: var(--field-label-font-size, 0.875rem);
149
+ font-weight: var(--field-label-weight, 500);
150
+ color: var(--field-label-color, inherit);
151
+ }
152
+
153
+ .kt-checkbox-field--disabled .kt-checkbox__label {
154
+ color: var(--field-hint-color, #5f6368);
155
+ opacity: 0.6;
156
+ }
157
+
158
+ .kt-checkbox__required {
159
+ margin-inline-start: 0.125rem;
160
+ color: var(--field-required-color, var(--kt-danger, #8c1d18));
161
+ }
162
+
163
+ /* Hint & erreur */
164
+ .kt-checkbox-hint {
165
+ margin: 0;
166
+ font-size: var(--field-hint-font-size, 0.8125rem);
167
+ color: var(--field-hint-color, #474747);
168
+ }
169
+
170
+ .kt-checkbox-error {
171
+ margin: 0;
172
+ display: flex;
173
+ flex-direction: column;
174
+ font-size: var(--field-hint-font-size, 0.8125rem);
175
+ color: var(--field-error-color, #8c1d18);
176
+ }
177
+
178
+ .kt-checkbox-error-message {
179
+ animation: var(--field-error-animation, none);
180
+ }
181
+
182
+ /* Mode contraste élevé (Windows) : `appearance:none` casse le rendu système → on le restaure
183
+ avec les couleurs système (obligatoire RGAA dès qu'on redessine un contrôle natif). */
184
+ @media (forced-colors: active) {
185
+ .kt-checkbox__input {
186
+ border-color: CanvasText;
187
+ background-color: Canvas;
188
+ }
189
+ .kt-checkbox__input:checked,
190
+ .kt-checkbox__input:indeterminate {
191
+ background-color: Highlight;
192
+ border-color: Highlight;
193
+ }
194
+ .kt-checkbox__input::before {
195
+ box-shadow: inset 1em 1em HighlightText;
196
+ }
197
+ .kt-checkbox__input:disabled {
198
+ border-color: GrayText;
199
+ }
200
+ .kt-checkbox__input:focus-visible {
201
+ outline: 2px solid CanvasText;
202
+ outline-offset: 2px;
203
+ }
204
+ }
205
+
206
+ @media (prefers-reduced-motion: reduce) {
207
+ .kt-checkbox__input,
208
+ .kt-checkbox__input::before {
209
+ transition: none;
210
+ animation: none;
211
+ }
212
+ .kt-checkbox-error-message {
213
+ animation: none;
214
+ }
215
+ }
216
+ }
@@ -0,0 +1,70 @@
1
+ @layer kt-aaa.components {
2
+ :host {
3
+ display: block;
4
+ }
5
+
6
+ .kt-chip-list {
7
+ display: flex;
8
+ flex-wrap: wrap;
9
+ gap: 0.5rem;
10
+ }
11
+
12
+ /* Porte le role="list" sans créer de contexte de mise en page : chips et bouton « +N more »
13
+ restent dans la même rangée flex de .kt-chip-list. */
14
+ .kt-chip-list__items {
15
+ display: contents;
16
+ }
17
+
18
+ /* Wrapper transparent : le rôle listitem est porté ici, le rendu vient du template custom
19
+ ou du bouton « +N more ». */
20
+ .kt-chip-list__item {
21
+ display: contents;
22
+ }
23
+
24
+ /* Bouton de repli/dépli : même habillage pilule que kt-chip (dupliqué : c'est un bouton,
25
+ pas un chip — il ne partage pas l'hôte du composant Chip). */
26
+ .kt-chip-list__more {
27
+ display: inline-flex;
28
+ align-items: center;
29
+ gap: var(--chip-gap);
30
+ padding: var(--chip-padding-y) var(--chip-padding-x);
31
+ border-radius: var(--chip-radius);
32
+ background: var(--chip-bg);
33
+ border: 1px solid var(--chip-border);
34
+ box-shadow: var(--chip-shadow, none);
35
+ font: inherit;
36
+ font-size: var(--chip-font-size);
37
+ color: var(--chip-color);
38
+ cursor: pointer;
39
+ min-block-size: 24px;
40
+ }
41
+
42
+ .kt-chip-list__more:hover {
43
+ background: var(--chip-bg-hover);
44
+ box-shadow: var(--chip-shadow-hover, var(--chip-shadow, none));
45
+ }
46
+
47
+ .kt-chip-list__more:focus-visible {
48
+ outline: 2px solid var(--chip-focus-ring);
49
+ outline-offset: 1px;
50
+ }
51
+
52
+ /* Texte réservé aux lecteurs d'écran (live region des retraits). */
53
+ .kt-chip-list__status {
54
+ position: absolute;
55
+ inline-size: 1px;
56
+ block-size: 1px;
57
+ padding: 0;
58
+ margin: -1px;
59
+ overflow: hidden;
60
+ clip-path: inset(50%);
61
+ white-space: nowrap;
62
+ border: 0;
63
+ }
64
+
65
+ @media (pointer: coarse) {
66
+ .kt-chip-list__more {
67
+ min-block-size: 32px;
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,92 @@
1
+ @layer kt-aaa.components {
2
+ /* Pilule. Tokens centralisés dans forms/chips/tokens.css */
3
+ :host {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ gap: var(--chip-gap);
7
+ padding: var(--chip-padding-y) var(--chip-padding-x);
8
+ border-radius: var(--chip-radius);
9
+ background: var(--chip-bg);
10
+ border: 1px solid var(--chip-border);
11
+ box-shadow: var(--chip-shadow, none);
12
+ font-size: var(--chip-font-size);
13
+ color: var(--chip-color);
14
+ }
15
+
16
+ .kt-chip__label {
17
+ max-inline-size: 12rem;
18
+ overflow: hidden;
19
+ text-overflow: ellipsis;
20
+ white-space: nowrap;
21
+ }
22
+
23
+ /* 24px visibles (WCAG 2.5.8 AA) ; cible réelle 44px via ::after transparent (AAA),
24
+ même technique que les boutons icon-only — le chip reste fin visuellement. */
25
+ .kt-chip__remove {
26
+ position: relative;
27
+ display: inline-flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ inline-size: 24px;
31
+ block-size: 24px;
32
+ padding: 0;
33
+ border: 0;
34
+ border-radius: 50%;
35
+ background: transparent;
36
+ color: var(--chip-remove-color);
37
+ cursor: pointer;
38
+ font-size: 0.75rem;
39
+ /* Token de BASCULE (non déclaré => hover actuel). Contrat : forms/chips/tokens.css. */
40
+ transition: var(--chip-remove-transition, background-color 0.15s ease);
41
+ }
42
+
43
+ .kt-chip__remove::after {
44
+ content: '';
45
+ position: absolute;
46
+ inset: -10px;
47
+ }
48
+
49
+ .kt-chip__remove:hover {
50
+ background-color: var(--chip-remove-bg-hover);
51
+ color: var(--chip-remove-color-hover);
52
+ }
53
+
54
+ :host(:hover) {
55
+ box-shadow: var(--chip-shadow-hover, var(--chip-shadow, none));
56
+ }
57
+
58
+ .kt-chip__remove:focus-visible {
59
+ outline: 2px solid var(--chip-focus-ring);
60
+ outline-offset: 1px;
61
+ }
62
+
63
+ .kt-chip__remove:disabled {
64
+ cursor: not-allowed;
65
+ opacity: 0.5;
66
+ }
67
+
68
+ .kt-chip__close-icon {
69
+ font-family: 'Material Symbols Outlined';
70
+ font-feature-settings: 'liga';
71
+ font-size: 1rem;
72
+ line-height: 1;
73
+ -webkit-font-smoothing: antialiased;
74
+ }
75
+
76
+ /* Tactile : à peine plus généreux (32px), la cible 44px vient du ::after invisible. */
77
+ @media (pointer: coarse) {
78
+ :host {
79
+ min-block-size: 32px;
80
+ }
81
+
82
+ .kt-chip__remove {
83
+ inline-size: 28px;
84
+ block-size: 28px;
85
+ font-size: 0.875rem;
86
+ }
87
+
88
+ .kt-chip__remove::after {
89
+ inset: -8px;
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,102 @@
1
+ /* Design tokens du composant Chip — contrat public de theming.
2
+ Les couleurs et géométries dérivent du socle (--kt-*) et des champs (--field-*). */
3
+ @layer kt-aaa.tokens {
4
+ :root {
5
+ /* Géométrie */
6
+ --chip-radius: 50px;
7
+ --chip-padding-y: 0.25rem;
8
+ --chip-padding-x: 0.625rem;
9
+ --chip-gap: 0.25rem;
10
+ --chip-font-size: 0.875rem;
11
+
12
+ /* Couleurs (dérivées de ds-primary) */
13
+ --chip-bg: color-mix(in srgb, var(--kt-primary) 10%, transparent);
14
+ --chip-bg-hover: color-mix(in srgb, var(--kt-primary) 18%, transparent);
15
+ --chip-border: color-mix(in srgb, var(--kt-primary) 20%, transparent);
16
+
17
+ /* Texte et icônes */
18
+ --chip-color: var(--field-color);
19
+ --chip-remove-color: var(--field-icon-color);
20
+ --chip-remove-color-hover: var(--kt-danger); /* rouge au survol du bouton × */
21
+ --chip-remove-bg-hover: color-mix(in srgb, currentColor 15%, transparent);
22
+
23
+ /* Animations d'entrée/sortie : keyframes jouées sur les PSEUDO-ÉLÉMENTS View Transition
24
+ (cf. règles ::view-transition-* plus bas), PAS sur les chips eux-mêmes — la suppression
25
+ DOM reste synchrone (indispensable : un retrait différé casse la capture de l'état
26
+ « après » et tue la transition en plein vol). Les keyframes d'un thème ne doivent animer
27
+ que transform / opacity / filter : la géométrie (largeur, position) est déjà morphée par
28
+ l'animation de groupe. Défaut : fondu équivalent à celui du navigateur. */
29
+ --chip-enter-animation: chip-vt-fade-in 0.25s ease both;
30
+ --chip-leave-animation: chip-vt-fade-out 0.25s ease both;
31
+
32
+ /* Focus */
33
+ --chip-focus-ring: var(--field-border-color-focus);
34
+
35
+ /* Token de BASCULE (NON déclaré exprès, cf. button-tokens.css) :
36
+ --chip-remove-transition — transition du bouton « retirer » au survol
37
+ (défaut : background-color 0.15s ease, posé dans chip.css). */
38
+ }
39
+
40
+ /* ============ Intégration View Transition (API document.startViewTransition) ============
41
+ Chaque chip porte un view-transition-name unique + la classe .chip-transition (cf. Chip).
42
+ Ces règles ciblent les pseudo-éléments de la transition, rattachés à la racine du document :
43
+ elles doivent vivre dans une feuille GLOBALE (les styles de composant scopés ne les
44
+ atteignent pas). Les tokens --chip-*-animation y sont résolus par héritage depuis <html>,
45
+ donc surchargeables par thème ([data-theme='…']). */
46
+
47
+ @keyframes chip-vt-fade-in {
48
+ from {
49
+ opacity: 0;
50
+ }
51
+ }
52
+
53
+ @keyframes chip-vt-fade-out {
54
+ to {
55
+ opacity: 0;
56
+ }
57
+ }
58
+
59
+ /* Chips à template custom (ktChipItem / chipTemplate) : la lib ne rend pas kt-chip,
60
+ c'est l'élément RACINE du template consommateur qui reçoit un nom automatique → il
61
+ participe aux mêmes animations (entrée/sortie/morph) que les chips standards.
62
+ Scopé à [data-vt-active] (posé par ChipList UNIQUEMENT pendant SA transition) : un nom
63
+ permanent ferait participer tous les chips de la page à chaque View Transition —
64
+ glissement individuel au moindre reflow (même principe que le gating de kt-chip).
65
+ Surcharge consommateur : redéclarer view-transition-name sur son élément —
66
+ `none` = opt-out, un nom explicite = chorégraphie maison ; ou une autre
67
+ view-transition-class pour des keyframes dédiées. Le bouton « +N » (dans le même
68
+ wrapper) n'est pas concerné : son nom est posé en style inline (prioritaire).
69
+ Navigateurs sans `view-transition-name: auto` : dégradation = pas d'animation
70
+ par chip (comportement antérieur), le reste de la transition est inchangé. */
71
+ [data-vt-active] .kt-chip-list__item > * {
72
+ /* Double déclaration volontaire : `match-element` (Chrome 140+) prime quand il est
73
+ compris, sinon retombée sur `auto` (spec antérieure) ; aucun des deux compris =
74
+ déclaration ignorée (dégradation propre). */
75
+ view-transition-name: auto;
76
+ view-transition-name: match-element;
77
+ view-transition-class: chip-transition;
78
+ }
79
+
80
+ /* Chip qui APPARAÎT (présent uniquement dans l'état « après ») : animation d'entrée. */
81
+ ::view-transition-new(.chip-transition):only-child {
82
+ animation: var(--chip-enter-animation);
83
+ }
84
+
85
+ /* Chip qui DISPARAÎT (présent uniquement dans l'état « avant ») : animation de sortie. */
86
+ ::view-transition-old(.chip-transition):only-child {
87
+ animation: var(--chip-leave-animation);
88
+ }
89
+
90
+ /* Chip qui PERSISTE (déplacement) : pas de cross-fade — l'ancienne image est masquée, la
91
+ nouvelle (rendu live) suit le morph de géométrie du groupe. Évite le scintillement
92
+ plus-lighter quand le contenu is identique mais que les ombres du thème bougent. */
93
+ ::view-transition-old(.chip-transition):not(:only-child) {
94
+ animation: none;
95
+ opacity: 0;
96
+ }
97
+
98
+ ::view-transition-new(.chip-transition):not(:only-child) {
99
+ animation: none;
100
+ opacity: 1;
101
+ }
102
+ }
@@ -0,0 +1,87 @@
1
+ @layer kt-aaa.components {
2
+ /* Field = chrome seul (empilement label / contrôle / hint / erreur).
3
+ Le visuel du contrôle (bordure, focus) appartient au composant de champ, pas ici. */
4
+ :host {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: var(--field-gap, 0.375rem);
8
+ font-size: var(--field-font-size, 1rem);
9
+ color: var(--field-color, inherit);
10
+ }
11
+
12
+ .kt-field__header {
13
+ display: flex;
14
+ align-items: center;
15
+ gap: 0.375rem;
16
+ }
17
+
18
+ .kt-field__label {
19
+ font-size: var(--field-label-font-size, 0.875rem);
20
+ font-weight: var(--field-label-weight, 500);
21
+ text-transform: var(--field-label-transform, none);
22
+ letter-spacing: var(--field-label-letter-spacing, normal);
23
+ color: var(--field-label-color, inherit);
24
+ }
25
+
26
+ .kt-field__help {
27
+ display: inline-flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ padding: 0;
31
+ border: 0;
32
+ background: transparent;
33
+ color: var(--field-icon-color, #474747);
34
+ cursor: pointer;
35
+ position: relative; /* requis pour le positionnement de ::after */
36
+ }
37
+
38
+ /* Zone de clic étendue à 44x44px (AAA 2.5.5) via un pseudo-élément transparent */
39
+ .kt-field__help::after {
40
+ content: '';
41
+ position: absolute;
42
+ inset: -12px;
43
+ }
44
+
45
+ .kt-field__help-icon {
46
+ font-family: 'Material Symbols Outlined';
47
+ font-size: 1.25rem;
48
+ line-height: 1;
49
+ font-feature-settings: 'liga';
50
+ -webkit-font-smoothing: antialiased;
51
+ }
52
+
53
+ .kt-field__required {
54
+ margin-inline-start: 0.125rem;
55
+ color: var(--field-required-color, #8c1d18);
56
+ }
57
+
58
+ .kt-field__hint {
59
+ margin: 0;
60
+ font-size: var(--field-hint-font-size, 0.8125rem);
61
+ color: var(--field-hint-color, #474747);
62
+ }
63
+
64
+ /* Pas de hauteur réservée quand vide (contre-pied du subscript fantôme de Material) ;
65
+ l'élément reste dans le DOM pour rester une région live. */
66
+ .kt-field__error {
67
+ margin: 0;
68
+ display: flex;
69
+ flex-direction: column;
70
+ font-size: var(--field-hint-font-size, 0.8125rem);
71
+ color: var(--field-error-color, #8c1d18);
72
+ }
73
+
74
+ /* Apparition d'un message d'erreur : token de BASCULE (non déclaré => aucune animation).
75
+ Sur le MESSAGE (inséré à l'invalidation) — PAS sur le conteneur, qui vit en permanence
76
+ (région live). Keyframes de thème : transform/opacity/filter seulement (les spans sont
77
+ des flex items, donc transformables). Même token consommé par kt-switch (switch.css). */
78
+ .kt-field__error-message {
79
+ animation: var(--field-error-animation, none);
80
+ }
81
+
82
+ @media (prefers-reduced-motion: reduce) {
83
+ .kt-field__error-message {
84
+ animation: none;
85
+ }
86
+ }
87
+ }
@@ -0,0 +1,136 @@
1
+ @layer kt-aaa.components {
2
+ /* Styles SPÉCIFIQUES au multi-select. Tout le panneau commun (trigger, popup, listbox, options,
3
+ filtre, bottom-sheet mobile) vient de ../styles/select-panel.css, chargé en premier via
4
+ styleUrls — ici uniquement : croix « tout effacer », barre d'actions, compteur, checkboxes
5
+ d'option et chips révocables. */
6
+
7
+ /* Réserve la place de la croix (sibling absolu) : sur le TEXTE, pas sur le padding du
8
+ trigger — la flèche reste collée au bord, la croix se glisse entre texte et flèche. */
9
+ .kt-select__trigger--clearable .kt-select__value {
10
+ margin-inline-end: 2rem;
11
+ }
12
+
13
+ /* Tout effacer : entre le texte et la flèche, disposition standard « texte … ✕ ▾ ».
14
+ 24px visibles ; cible étendue à 44px via ::after transparent (AAA). */
15
+ .kt-select__clear {
16
+ position: absolute;
17
+ inset-block-start: 50%;
18
+ inset-inline-end: 2.5rem;
19
+ translate: 0 -50%;
20
+ display: inline-flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ inline-size: 24px;
24
+ block-size: 24px;
25
+ padding: 0;
26
+ border: 0;
27
+ border-radius: 50%;
28
+ background: transparent;
29
+ color: var(--field-icon-color, #5f6368);
30
+ cursor: pointer;
31
+ }
32
+
33
+ .kt-select__clear::after {
34
+ content: '';
35
+ position: absolute;
36
+ inset: -10px;
37
+ }
38
+
39
+ .kt-select__clear:hover {
40
+ background-color: color-mix(in srgb, currentColor 12%, transparent);
41
+ color: var(--field-color, inherit);
42
+ }
43
+
44
+ .kt-select__clear:focus-visible {
45
+ outline: 2px solid var(--field-border-color-focus, #0b57d0);
46
+ outline-offset: 1px;
47
+ }
48
+
49
+ .kt-select__clear-icon {
50
+ font-family: 'Material Symbols Outlined';
51
+ font-feature-settings: 'liga';
52
+ font-size: 1.25rem;
53
+ line-height: 1;
54
+ -webkit-font-smoothing: antialiased;
55
+ }
56
+
57
+ /* Barre d'actions de masse (Tout sélectionner / Tout effacer) en tête de panneau. */
58
+ .kt-select__actions {
59
+ display: flex;
60
+ gap: 0.25rem;
61
+ flex: none;
62
+ padding: 0.25rem 0.5rem;
63
+ border-block-end: 1px solid var(--field-border-color, #c4c7c5);
64
+ }
65
+
66
+ .kt-select__action {
67
+ flex: 1;
68
+ min-block-size: 44px;
69
+ padding: 0.375rem 0.625rem;
70
+ border: 0;
71
+ border-radius: calc(var(--field-radius, 8px) * 0.75);
72
+ background: transparent;
73
+ color: var(--kt-primary, #0b57d0);
74
+ font: inherit;
75
+ font-weight: 500;
76
+ cursor: pointer;
77
+ }
78
+
79
+ .kt-select__action:hover {
80
+ background: var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent));
81
+ }
82
+
83
+ .kt-select__action:focus-visible {
84
+ outline: 2px solid var(--field-border-color-focus, #0b57d0);
85
+ outline-offset: -2px;
86
+ }
87
+
88
+ /* Compteur de sélection visible (info SR portée par la live region → aria-hidden). */
89
+ .kt-select__count {
90
+ flex: none;
91
+ padding: 0.25rem 0.75rem;
92
+ font-size: 0.8125rem;
93
+ color: var(--field-hint-color, #5f6368);
94
+ border-block-end: 1px solid var(--field-border-color, #c4c7c5);
95
+ }
96
+
97
+ /* Checkbox visuelle dans la liste */
98
+ .kt-select__checkbox {
99
+ display: inline-flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ flex: none;
103
+ margin-inline-end: 0.25rem;
104
+ user-select: none;
105
+ }
106
+
107
+ .kt-select__checkbox-icon {
108
+ font-family: 'Material Symbols Outlined';
109
+ font-feature-settings: 'liga';
110
+ font-size: 1.25rem;
111
+ line-height: 1;
112
+ color: var(--field-icon-color, #5f6368);
113
+ -webkit-font-smoothing: antialiased;
114
+ }
115
+
116
+ .kt-select__option[aria-selected='true'] .kt-select__checkbox-icon {
117
+ color: var(--kt-primary, #0b57d0);
118
+ }
119
+
120
+ .kt-select__option--multiple {
121
+ display: flex;
122
+ align-items: center;
123
+ gap: 0.5rem;
124
+ }
125
+
126
+ .kt-select__option-content {
127
+ flex: 1;
128
+ min-inline-size: 0;
129
+ }
130
+
131
+ /* Chips délégués au composant kt-chip-list (hôte toujours rendu : la marge ne
132
+ s'applique que lorsqu'il y a des chips, via l'attribut data-empty). */
133
+ kt-chip-list:not([data-empty]) {
134
+ margin-block-start: 0.5rem;
135
+ }
136
+ }