@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,464 @@
1
+ @layer kt-aaa.components {
2
+ /* Panneau de sélection PARTAGÉ entre kt-select et kt-multi-select (référencé par les deux
3
+ composants via styleUrl(s) → compilé/scopé par composant, PAS global — contrairement à
4
+ field-box.css, pas d'entrée angular.json ni de redémarrage du dev server).
5
+ Styles SCOPÉS : le popup rend in-place dans la vue (DeferredContent), donc l'encapsulation
6
+ s'applique même en top-layer. UN SEUL Popover, deux régimes via @media : desktop = dropdown
7
+ ancré (CSS Anchor Positioning) ; téléphone tactile = bottom-sheet.
8
+ Tokens --select-* dérivés du socle --kt-* / --field-*.
9
+ Tokens de BASCULE mouvement (NON déclarés exprès, cf. button-tokens.css) :
10
+ --select-arrow-transition (défaut : transform 120ms ease — rotation du chevron),
11
+ --select-popup-enter-animation (défaut : none — entrée du dropdown desktop ; keyframes de
12
+ thème limitées à transform/opacity/filter, le popup est ancré : ne pas animer la position),
13
+ --kt-sheet-anim-duration (défaut : 120ms — glissement + scrim de la bottom-sheet mobile).
14
+ Les règles spécifiques au multi (chips, clear, actions, checkbox) vivent dans multi-select.css. */
15
+ :host {
16
+ display: block;
17
+ }
18
+
19
+ .kt-select {
20
+ position: relative;
21
+ }
22
+
23
+ /* Le trigger réutilise .kt-field-box (boîte de champ partagée) pour l'aspect/min-height/focus. */
24
+ .kt-select__trigger {
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: space-between;
28
+ gap: var(--field-control-gap, 0.5rem);
29
+ inline-size: 100%;
30
+ cursor: pointer;
31
+ text-align: start;
32
+ font: inherit;
33
+ color: var(--field-color, inherit);
34
+ }
35
+
36
+ .kt-select__trigger:disabled {
37
+ cursor: not-allowed;
38
+ background: var(--field-disabled-bg, #f1f3f4);
39
+ color: color-mix(in srgb, currentColor 50%, transparent);
40
+ }
41
+
42
+ .kt-select__value {
43
+ flex: 1;
44
+ min-inline-size: 0;
45
+ overflow: hidden;
46
+ text-overflow: ellipsis;
47
+ white-space: nowrap;
48
+ }
49
+
50
+ .kt-select__placeholder {
51
+ color: var(--field-hint-color, #5f6368);
52
+ }
53
+
54
+ /* Chevron via ligature Material Symbols (même mécanisme que Button / field-box). */
55
+ .kt-select__arrow {
56
+ flex: none;
57
+ font-family: 'Material Symbols Outlined';
58
+ font-size: 1.25em;
59
+ line-height: 1;
60
+ font-feature-settings: 'liga';
61
+ color: var(--field-icon-color, #5f6368);
62
+ transition: var(--select-arrow-transition, transform 120ms ease);
63
+ -webkit-font-smoothing: antialiased;
64
+ }
65
+
66
+ .kt-select--open .kt-select__arrow {
67
+ transform: rotate(180deg);
68
+ }
69
+
70
+ /* Conteneur popover (div). Affiché en top-layer via le Popover API.
71
+ border-box pour aligner la largeur sur le trigger. */
72
+ .kt-select__popup {
73
+ box-sizing: border-box;
74
+ display: flex;
75
+ flex-direction: column;
76
+ margin: 0;
77
+ padding: 0;
78
+ border-width: var(--select-popup-border-width, var(--field-border-width, 1px));
79
+ border-style: var(--field-border-style, solid);
80
+ border-color: var(--field-border-color, #c4c7c5);
81
+ border-radius: var(--field-radius, 8px);
82
+ background: var(--select-popup-bg, var(--kt-surface, #fff));
83
+ color: var(--field-color, inherit);
84
+ box-shadow: var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));
85
+ /* Translucidité (verre) : bascule => aucun effet par défaut (cf. theme-liquid-glass). */
86
+ backdrop-filter: var(--select-popup-backdrop-filter, none);
87
+ max-block-size: var(--select-popup-max-height, 16rem);
88
+ overflow: hidden; /* la liste interne scrolle */
89
+ }
90
+
91
+ .kt-select__sheet-card {
92
+ display: contents;
93
+ }
94
+
95
+ /* Notre `display: flex` écrase la règle UA `[popover]:not(:popover-open) { display: none }` :
96
+ sans ceci, le popup fermé par hidePopover() reste affiché (et tabbable) jusqu'à la
97
+ destruction différée de son contenu — le Tab de fermeture retomberait dedans. */
98
+ .kt-select__popup:not(:popover-open) {
99
+ display: none !important;
100
+ }
101
+
102
+ /* Entrée du dropdown desktop : token de BASCULE (non déclaré => aucune animation). Une animation
103
+ sur :popover-open rejoue à chaque ouverture, sans @starting-style ni conflit avec la règle
104
+ display:none ci-dessus — la fermeture reste volontairement instantanée. */
105
+ .kt-select__popup:popover-open {
106
+ animation: var(--select-popup-enter-animation, none);
107
+ }
108
+
109
+ @media (prefers-reduced-motion: reduce) {
110
+ .kt-select__popup:popover-open {
111
+ animation: none;
112
+ }
113
+ }
114
+
115
+ /* Liste scrollable (élément ngListbox). */
116
+ .kt-select__listbox {
117
+ flex: 1 1 auto;
118
+ min-block-size: 0;
119
+ margin: 0;
120
+ padding: 0.25rem;
121
+ list-style: none;
122
+ overflow-y: auto;
123
+ }
124
+
125
+ /* ===== Mode filtrable : panneau (widget combobox) = champ de recherche + liste ===== */
126
+ /* Le panneau reprend la colonne flex du popup pour que la liste interne reste seule à scroller. */
127
+ .kt-select__panel {
128
+ display: flex;
129
+ flex-direction: column;
130
+ flex: 1 1 auto;
131
+ min-block-size: 0;
132
+ }
133
+
134
+ .kt-select__filter {
135
+ flex: none;
136
+ padding: 0.5rem;
137
+ border-block-end: 1px solid var(--field-border-color, #c4c7c5);
138
+ }
139
+
140
+ .kt-select__filter-input {
141
+ box-sizing: border-box;
142
+ inline-size: 100%;
143
+ min-block-size: var(--field-min-height, 44px); /* cible tactile AAA 44px sur tous les écrans */
144
+ padding: 0.375rem 0.625rem;
145
+ border: var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);
146
+ border-radius: calc(var(--field-radius, 8px) * 0.75);
147
+ background: var(--select-popup-bg, var(--kt-surface, #fff));
148
+ color: var(--field-color, inherit);
149
+ font: inherit;
150
+ /* Neutralise l'aspect natif de type=search (coins en pilule sur Safari) ; le rôle implicite
151
+ `searchbox` et la touche Entrée « rechercher » du clavier mobile sont conservés. */
152
+ appearance: none;
153
+ }
154
+
155
+ .kt-select__filter-input::placeholder {
156
+ color: var(--field-hint-color, #5f6368);
157
+ }
158
+
159
+ .kt-select__filter-input:focus-visible {
160
+ outline: 2px solid var(--field-border-color-focus, #0b57d0);
161
+ outline-offset: -1px;
162
+ }
163
+
164
+ /* Bouton d'effacement (×) de type=search sur WebKit/Blink — mini « clearable » gratuit, utile sur
165
+ mobile. Redessiné en mask pour suivre la couleur d'icône du thème (le × natif est sombre, donc
166
+ invisible sur les thèmes foncés). N'apparaît que lorsque le champ contient du texte. */
167
+ .kt-select__filter-input::-webkit-search-cancel-button {
168
+ appearance: none;
169
+ inline-size: 1rem;
170
+ block-size: 1rem;
171
+ margin-inline-start: 0.375rem;
172
+ cursor: pointer;
173
+ background-color: var(--field-icon-color, #5f6368);
174
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E")
175
+ center / contain no-repeat;
176
+ }
177
+
178
+ /* Texte réservé aux lecteurs d'écran (live region du nombre de résultats). */
179
+ .kt-select__sr-only {
180
+ position: absolute;
181
+ inline-size: 1px;
182
+ block-size: 1px;
183
+ padding: 0;
184
+ margin: -1px;
185
+ overflow: hidden;
186
+ clip-path: inset(50%);
187
+ white-space: nowrap;
188
+ border: 0;
189
+ }
190
+
191
+ /* ===== DESKTOP : dropdown ancré via CSS Anchor Positioning ===== */
192
+ @supports (anchor-name: --x) {
193
+ .kt-select__popup {
194
+ position: fixed;
195
+ inset: auto;
196
+ top: anchor(bottom);
197
+ left: anchor(left);
198
+ margin-block-start: 0.25rem;
199
+ min-inline-size: anchor-size(width);
200
+ width: max-content;
201
+ max-inline-size: min(90vw, 28rem);
202
+ position-try-fallbacks:
203
+ flip-block,
204
+ flip-inline,
205
+ flip-block flip-inline;
206
+ }
207
+ }
208
+
209
+ /* Repli si l'anchor positioning n'est pas supporté (ex. iOS < 26) : bottom-sheet plein largeur,
210
+ bien plus sûr qu'un popover mal positionné en 0,0. */
211
+ @supports not (anchor-name: --x) {
212
+ .kt-select__popup {
213
+ position: fixed;
214
+ inset: auto 0 0 0;
215
+ inline-size: 100%;
216
+ max-inline-size: 100%;
217
+ border-radius: var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;
218
+ }
219
+ }
220
+
221
+ /* ===== ÉCRAN COMPACT : bottom-sheet (même Popover, restylé) =====
222
+ Pilotée par la CLASSE `kt-select__popup--sheet` posée en JS par le composant (signal
223
+ `KtViewport.isCompact()`) — et NON par un `@media` : le seuil est configurable par appli
224
+ (`provideKtBreakpoints`), source unique JS qui pilote aussi ce style. */
225
+ .kt-select__popup--sheet {
226
+ position: fixed !important;
227
+ inset: 0 !important;
228
+ inline-size: 100% !important;
229
+ max-inline-size: 100% !important;
230
+ min-inline-size: 0 !important;
231
+ width: 100% !important;
232
+ height: 100% !important;
233
+ max-block-size: none !important;
234
+ margin: 0 !important;
235
+ padding: 0 !important;
236
+ border: none !important;
237
+ background: transparent !important;
238
+ box-shadow: none !important;
239
+ border-radius: 0 !important;
240
+ overflow: visible !important;
241
+ display: flex;
242
+ flex-direction: column !important;
243
+ justify-content: flex-end !important;
244
+ }
245
+
246
+ .kt-select__popup--sheet .kt-select__sheet-card {
247
+ position: relative;
248
+ z-index: 2;
249
+ display: flex;
250
+ flex-direction: column;
251
+ background: var(--select-popup-bg, var(--kt-surface, #fff));
252
+ border-radius: var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;
253
+ box-shadow: var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));
254
+ max-block-size: var(--kt-sheet-max-block-size, 85svh);
255
+ width: 100%;
256
+ overflow: hidden;
257
+ /* Position de repos. L'entrée (glissement du bas) est jouée par la keyframe PARTAGÉE kt-sheet-in
258
+ sur :popover-open (cf. plus bas), comme le mode `sheet` du Dialog. La transition translate ne
259
+ sert qu'au snap-back du drag-to-dismiss. */
260
+ translate: 0 0;
261
+ transition: translate var(--kt-sheet-anim-duration, 120ms) ease;
262
+ }
263
+
264
+ /* Sheet FILTRABLE : hauteur STABLE (et non « au contenu plafonné »). Sans ça, filtrer raccourcit
265
+ la liste → la sheet ancrée en bas rétrécit → son haut (champ de recherche) descend derrière le
266
+ clavier virtuel. Avec une hauteur fixe, la liste rétrécit À L'INTÉRIEUR, le champ ne bouge plus. */
267
+ .kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter) {
268
+ block-size: var(--kt-sheet-max-block-size, 85svh);
269
+ max-block-size: var(--kt-sheet-max-block-size, 85svh);
270
+ }
271
+
272
+ .kt-select__popup--sheet:popover-open .kt-select__sheet-card {
273
+ translate: 0 0;
274
+ /* Entrée : glissement du bas (keyframe PARTAGÉE kt-sheet-in). */
275
+ animation: var(--select-sheet-enter-animation, kt-sheet-in var(--kt-sheet-anim-duration, 120ms) ease);
276
+ }
277
+
278
+ /* Pendant le drag : la feuille suit le doigt (translate posé en inline), sans transition. */
279
+ .kt-select__popup--sheet .kt-select__sheet-card.kt-select__popup--dragging {
280
+ transition: none;
281
+ }
282
+
283
+ /* Pendant la fermeture déclenchée par JS */
284
+ .kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-card,
285
+ .kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-card {
286
+ translate: 0 100%;
287
+ transition: translate var(--kt-sheet-exit-duration, 90ms) cubic-bezier(0.4, 0, 0.2, 1);
288
+ }
289
+
290
+ /* Masquer le backdrop popover natif car pointer-events: none y est forcé par le navigateur */
291
+ ::ng-deep .kt-select__popup--sheet::backdrop {
292
+ display: none !important;
293
+ }
294
+
295
+ /* Scrim : assombrit le fond + bloque clics arrière-plan (pointer-events: auto) + fondu. */
296
+ .kt-select__sheet-scrim {
297
+ display: none;
298
+ }
299
+
300
+ .kt-select__popup--sheet .kt-select__sheet-scrim {
301
+ display: block;
302
+ position: fixed;
303
+ inset: 0;
304
+ z-index: 1;
305
+ background: var(--kt-sheet-scrim, rgb(0 0 0 / 40%));
306
+ opacity: 0;
307
+ pointer-events: auto;
308
+ transition:
309
+ opacity var(--kt-sheet-anim-duration, 120ms) ease,
310
+ overlay var(--kt-sheet-anim-duration, 120ms) allow-discrete,
311
+ display var(--kt-sheet-anim-duration, 120ms) allow-discrete;
312
+ }
313
+
314
+ .kt-select__popup--sheet:popover-open .kt-select__sheet-scrim {
315
+ opacity: 1;
316
+ }
317
+
318
+ @starting-style {
319
+ .kt-select__popup--sheet:popover-open .kt-select__sheet-scrim {
320
+ opacity: 0;
321
+ }
322
+ }
323
+
324
+ .kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,
325
+ .kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim {
326
+ opacity: 0;
327
+ transition: opacity var(--kt-sheet-exit-duration, 90ms) ease;
328
+ }
329
+
330
+ /* Cibles tactiles ≥44px (Apple 44pt / WCAG 2.5.5). */
331
+ .kt-select__popup--sheet .kt-select__option {
332
+ --select-option-min-height: 44px;
333
+ padding-block: 0.625rem;
334
+ }
335
+
336
+ /* ≥16px : empêche le zoom automatique d'iOS au focus du champ de filtre. */
337
+ .kt-select__popup--sheet .kt-select__filter-input {
338
+ font-size: 1rem;
339
+ min-block-size: 44px;
340
+ }
341
+
342
+ @media (prefers-reduced-motion: reduce) {
343
+ .kt-select__popup--sheet .kt-select__sheet-card,
344
+ .kt-select__popup--sheet .kt-select__sheet-scrim {
345
+ transition: none;
346
+ translate: 0 0;
347
+ }
348
+ }
349
+
350
+ /* Poignée de drag (téléphone) : barre centrée, zone de préhension confortable. `touch-action: none`
351
+ pour que le geste de glissement ne déclenche pas le scroll de la page. aria-hidden (décoratif). */
352
+ .kt-select__sheet-grab {
353
+ display: flex;
354
+ align-items: center;
355
+ justify-content: center;
356
+ flex: none;
357
+ block-size: 44px; /* Cible tactile minimale WCAG 2.5.5 AAA (44px) */
358
+ cursor: grab;
359
+ touch-action: none;
360
+ }
361
+
362
+ .kt-select__sheet-grab:active {
363
+ cursor: grabbing;
364
+ }
365
+
366
+ .kt-select__sheet-grab::before {
367
+ content: '';
368
+ inline-size: 2.25rem;
369
+ block-size: 0.25rem;
370
+ border-radius: 999px;
371
+ /* Token PARTAGÉ avec le Dialog (= var(--kt-outline) par défaut, identique à --field-border-color). */
372
+ background: var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5));
373
+ }
374
+
375
+ /* En-tête de la bottom-sheet (titre + bouton Fermer), rendu seulement sur téléphone. */
376
+ .kt-select__sheet-header {
377
+ display: flex;
378
+ align-items: center;
379
+ justify-content: space-between;
380
+ gap: 0.5rem;
381
+ flex: none;
382
+ padding-block: 0.5rem;
383
+ padding-inline: 1rem 0.5rem;
384
+ border-block-end: 1px solid var(--field-border-color, #c4c7c5);
385
+ }
386
+
387
+ .kt-select__sheet-title {
388
+ font-weight: 600;
389
+ }
390
+
391
+ .kt-select__sheet-close {
392
+ display: inline-flex;
393
+ align-items: center;
394
+ justify-content: center;
395
+ flex: none;
396
+ inline-size: 44px;
397
+ block-size: 44px;
398
+ padding: 0;
399
+ border: 0;
400
+ border-radius: 50%;
401
+ background: transparent;
402
+ color: var(--field-icon-color, #5f6368);
403
+ cursor: pointer;
404
+ }
405
+
406
+ .kt-select__sheet-close:focus-visible {
407
+ outline: 2px solid var(--field-border-color-focus, #0b57d0);
408
+ outline-offset: 2px;
409
+ }
410
+
411
+ .kt-select__sheet-close-icon {
412
+ font-family: 'Material Symbols Outlined';
413
+ font-feature-settings: 'liga';
414
+ font-size: 1.5rem;
415
+ line-height: 1;
416
+ -webkit-font-smoothing: antialiased;
417
+ }
418
+
419
+ /* ===== Options ===== */
420
+ .kt-select__option {
421
+ display: flex;
422
+ align-items: center;
423
+ gap: 0.5rem;
424
+ box-sizing: border-box;
425
+ min-block-size: var(
426
+ --select-option-min-height,
427
+ 44px
428
+ ); /* cible tactile AAA 44px par défaut (y compris sur desktop) */
429
+ padding: 0.5rem 0.625rem;
430
+ border-radius: 6px;
431
+ cursor: pointer;
432
+ }
433
+
434
+ .kt-select__option[aria-selected='true'] {
435
+ background: var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));
436
+ color: var(--select-option-selected-color, inherit); /* utile si le bg sélectionné est plein */
437
+ font-weight: var(--select-option-selected-weight, 600);
438
+ }
439
+
440
+ .kt-select__option--active:not([aria-disabled='true']),
441
+ .kt-select__option:hover:not([aria-disabled='true']) {
442
+ background: var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent));
443
+ }
444
+
445
+ .kt-select__option[aria-disabled='true'] {
446
+ opacity: 0.5;
447
+ cursor: not-allowed;
448
+ }
449
+
450
+ .kt-select__empty {
451
+ padding: 0.5rem 0.625rem;
452
+ color: var(--field-hint-color, #5f6368);
453
+ }
454
+
455
+ .kt-select__truncated-info {
456
+ box-sizing: border-box;
457
+ padding: 0.5rem 0.625rem;
458
+ font-size: 0.875rem;
459
+ font-style: italic;
460
+ color: var(--field-hint-color, #5f6368);
461
+ border-block-start: 1px solid var(--field-border-color, #c4c7c5);
462
+ pointer-events: none;
463
+ }
464
+ }
@@ -0,0 +1,67 @@
1
+ /* Design tokens des champs de formulaire — contrat public de theming.
2
+ Surchargez ces variables (globalement sur :root, ou localement sur un conteneur)
3
+ pour adapter la lib à la charte graphique du projet d'accueil.
4
+
5
+ Les couleurs et la géométrie de contrôle DÉRIVENT du socle partagé (--kt-*, voir
6
+ src/app/styles/foundation.css) : rebrander --kt-primary met à jour champs ET boutons.
7
+ Surcharger un --field-* ici reste possible pour un réglage propre aux champs. */
8
+ @layer kt-aaa.tokens {
9
+ :root {
10
+ /* Couleurs (dérivées du socle) */
11
+ --field-color: var(--kt-on-surface);
12
+ --field-bg: var(--kt-surface);
13
+ --field-border-color: var(--kt-outline);
14
+ --field-border-color-hover: var(--kt-outline-strong);
15
+ --field-border-color-focus: var(--kt-primary);
16
+ --field-label-color: var(--kt-on-surface);
17
+ --field-hint-color: var(--kt-muted);
18
+ --field-error-color: var(--kt-danger);
19
+ --field-required-color: var(--kt-danger);
20
+ --field-icon-color: var(--kt-muted);
21
+ /* Dérivé (et non #f1f3f4 en dur) : reste correct quand un thème passe la surface en sombre.
22
+ En light défaut : 6% de #1f1f1f dans #fff ≈ #f2f2f2. */
23
+ --field-disabled-bg: color-mix(in srgb, var(--kt-on-surface) 6%, var(--kt-surface));
24
+
25
+ /* Géométrie */
26
+ --field-radius: var(--kt-control-radius);
27
+ --field-min-height: var(--kt-control-height); /* hauteur unifiée avec le bouton md */
28
+ /* Bordure en LONGHANDS côté consommation : width (et --field-border-style, bascule non
29
+ déclarée, défaut solid) acceptent 1 à 4 valeurs => underline (`0 0 2px 0`), styles mixtes
30
+ (`solid dashed`)… --field-border-color reste UNE couleur. Le popup du select suit
31
+ --field-border-width sauf si --select-popup-border-width est défini (utile quand les
32
+ champs passent en underline : un menu flottant garde sa bordure complète). */
33
+ --field-border-width: 1px;
34
+ --field-padding-x: 0.75rem;
35
+ --field-padding-y: 0.5rem;
36
+ --field-gap: 0.375rem;
37
+ --field-control-gap: 0.5rem;
38
+
39
+ /* Typo */
40
+ --field-font-size: var(--kt-control-font);
41
+ --field-label-font-size: 0.875rem;
42
+ --field-hint-font-size: 0.8125rem;
43
+
44
+ /* Focus */
45
+ --field-focus-ring-width: var(--kt-focus-ring-width);
46
+ /* Halo TRANSLUCIDE par défaut : le contraste du focus est porté par le BORDER opaque
47
+ (--field-border-color-focus) ; l'anneau n'est qu'un voile doux. Un thème peut le rendre
48
+ opaque (cf. win98). */
49
+ --field-focus-ring: color-mix(in srgb, var(--field-border-color-focus) 35%, transparent);
50
+
51
+ /* Ombres par état : tokens de BASCULE (NON déclarés ici exprès, même principe que
52
+ --btn-radius). Non définis => box-shadow: none (rendu actuel). Un thème les déclare
53
+ pour un glow/elevation : --field-shadow (repos), --field-shadow-hover, --field-shadow-focus
54
+ (hover/focus retombent sur --field-shadow si absents). Disabled force toujours `none`. */
55
+
56
+ /* Mouvement : --field-transition, token de BASCULE (NON déclaré) => boîte inerte par défaut.
57
+ Pas de transform sur la boîte (le trigger du select est une ancre, cf. field-box.css). */
58
+
59
+ /* Autres BASCULES non déclarées (défauts entre parenthèses) :
60
+ - Focus ring : --field-focus-ring-style (solid), --field-focus-ring-offset (1px).
61
+ - Caret : --field-caret-color (auto).
62
+ - Typo du label : --field-label-weight (500), --field-label-transform (none),
63
+ --field-label-letter-spacing (normal).
64
+ - Select : --select-option-selected-weight (600),
65
+ --select-option-selected-color (inherit — à poser si le bg sélectionné est plein). */
66
+ }
67
+ }