@ktortu/aaa 0.9.4 → 0.9.6

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 (39) hide show
  1. package/README.md +25 -1
  2. package/button/button-tokens.css +3 -1
  3. package/button/button.css +3 -3
  4. package/card/card-tokens.css +2 -1
  5. package/cdk/styles/foundation.css +19 -10
  6. package/dialog/dialog.css +58 -4
  7. package/fesm2022/ktortu-aaa-dialog.mjs +28 -14
  8. package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
  9. package/fesm2022/ktortu-aaa-forms.mjs +402 -36
  10. package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
  11. package/fesm2022/ktortu-aaa-layout.mjs +286 -0
  12. package/fesm2022/ktortu-aaa-layout.mjs.map +1 -0
  13. package/fesm2022/ktortu-aaa.mjs +1 -0
  14. package/fesm2022/ktortu-aaa.mjs.map +1 -1
  15. package/forms/chips/chip-listbox.css +56 -0
  16. package/forms/chips/chip.css +47 -0
  17. package/forms/chips/tokens.css +5 -0
  18. package/forms/field/field.css +3 -1
  19. package/forms/styles/select-panel.css +3 -3
  20. package/package.json +5 -1
  21. package/styles/layout.css +140 -0
  22. package/styles/styles.css +1 -0
  23. package/themes/theme-ant.css +21 -16
  24. package/themes/theme-architecte.css +28 -28
  25. package/themes/theme-aurora.css +23 -23
  26. package/themes/theme-bootstrap.css +19 -19
  27. package/themes/theme-carbon.css +18 -18
  28. package/themes/theme-catppuccin.css +27 -27
  29. package/themes/theme-cyberpunk.css +28 -28
  30. package/themes/theme-fluent.css +32 -19
  31. package/themes/theme-material-you.css +78 -27
  32. package/themes/theme-material.css +28 -19
  33. package/themes/theme-primer.css +24 -18
  34. package/themes/theme-vegetal.css +21 -21
  35. package/tooltip/tooltip.css +1 -0
  36. package/types/ktortu-aaa-dialog.d.ts +23 -1
  37. package/types/ktortu-aaa-forms.d.ts +118 -6
  38. package/types/ktortu-aaa-layout.d.ts +117 -0
  39. package/types/ktortu-aaa.d.ts +1 -0
@@ -0,0 +1,286 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, signal, computed, Injectable, input, effect, Component, Directive } from '@angular/core';
3
+ import { KtViewport } from '@ktortu/aaa/cdk';
4
+ import * as i1 from '@angular/cdk/a11y';
5
+ import { CdkTrapFocus } from '@angular/cdk/a11y';
6
+
7
+ const KT_LAYOUT_DEFAULT_STATE = new InjectionToken('KT_LAYOUT_DEFAULT_STATE', {
8
+ providedIn: 'root',
9
+ factory: () => 'expanded',
10
+ });
11
+ /**
12
+ * Service global de gestion de la mise en page (Layout).
13
+ * Gère l'état d'ouverture/fermeture de la barre latérale sur mobile et bureau,
14
+ * ainsi que le comportement spécifique de "rail" sur bureau.
15
+ *
16
+ * NOTE: Ce service n'est pas "providedIn: 'root'". Le développeur doit le fournir
17
+ * (via le tableau providers d'un composant parent ou de l'application) pour
18
+ * maîtriser le scope (ex: avoir plusieurs layouts indépendants).
19
+ */
20
+ class KtLayoutService {
21
+ viewport = inject(KtViewport);
22
+ defaultState = inject(KT_LAYOUT_DEFAULT_STATE);
23
+ /**
24
+ * Comportement actif lors de la fermeture sur ordinateur (écran non mobile).
25
+ * Renseigné généralement par le composant racine `KtLayoutComponent`.
26
+ */
27
+ desktopCloseBehavior = signal('hidden', /* @ts-ignore */
28
+ ...(ngDevMode ? [{ debugName: "desktopCloseBehavior" }] : /* istanbul ignore next */ []));
29
+ _isDesktopOpen = signal(this.defaultState !== 'rail' && this.defaultState !== 'hidden', /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "_isDesktopOpen" }] : /* istanbul ignore next */ []));
31
+ _isMobileOpen = signal(false, /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "_isMobileOpen" }] : /* istanbul ignore next */ []));
33
+ isMobile = this.viewport.isMobile;
34
+ isRail = computed(() => !this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'rail', /* @ts-ignore */
35
+ ...(ngDevMode ? [{ debugName: "isRail" }] : /* istanbul ignore next */ []));
36
+ isExpanded = computed(() => !this.isMobile() && this._isDesktopOpen(), /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "isExpanded" }] : /* istanbul ignore next */ []));
38
+ isHidden = computed(() => (this.isMobile() && !this._isMobileOpen()) ||
39
+ (!this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'hidden'), /* @ts-ignore */
40
+ ...(ngDevMode ? [{ debugName: "isHidden" }] : /* istanbul ignore next */ []));
41
+ isMobileOpen = computed(() => this.isMobile() && this._isMobileOpen(), /* @ts-ignore */
42
+ ...(ngDevMode ? [{ debugName: "isMobileOpen" }] : /* istanbul ignore next */ []));
43
+ toggle() {
44
+ if (this.isMobile()) {
45
+ this._isMobileOpen.update((v) => !v);
46
+ }
47
+ else {
48
+ this._isDesktopOpen.update((v) => !v);
49
+ }
50
+ }
51
+ open() {
52
+ if (this.isMobile()) {
53
+ this._isMobileOpen.set(true);
54
+ }
55
+ else {
56
+ this._isDesktopOpen.set(true);
57
+ }
58
+ }
59
+ close() {
60
+ if (this.isMobile()) {
61
+ this._isMobileOpen.set(false);
62
+ }
63
+ else {
64
+ this._isDesktopOpen.set(false);
65
+ }
66
+ }
67
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtLayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
68
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtLayoutService });
69
+ }
70
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtLayoutService, decorators: [{
71
+ type: Injectable
72
+ }] });
73
+
74
+ /**
75
+ * Composant racine de l'application qui gère la structure de base (Sidebar, Toolbar, Contenu).
76
+ * Configure dynamiquement le comportement du layout.
77
+ */
78
+ class KtLayoutComponent {
79
+ /**
80
+ * Définit le comportement de la navigation latérale lors de sa fermeture sur bureau (écran large).
81
+ * - `'hidden'` (défaut) : le menu est complètement masqué et retiré du flux visuel/a11y.
82
+ * - `'rail'` : le menu est réduit à une fine barre verticale (mini-sidebar), permettant
83
+ * d'afficher uniquement les icônes. Idéal si les liens possèdent des icônes explicites.
84
+ */
85
+ desktopCloseBehavior = input('hidden', /* @ts-ignore */
86
+ ...(ngDevMode ? [{ debugName: "desktopCloseBehavior" }] : /* istanbul ignore next */ []));
87
+ layout = inject(KtLayoutService);
88
+ constructor() {
89
+ effect(() => {
90
+ this.layout.desktopCloseBehavior.set(this.desktopCloseBehavior());
91
+ }, { allowSignalWrites: true });
92
+ effect(() => {
93
+ // Clean up mobile state when switching back to desktop
94
+ if (!this.layout.isMobile() && this.layout.isMobileOpen()) {
95
+ this.layout.close();
96
+ }
97
+ }, { allowSignalWrites: true });
98
+ }
99
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
100
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.1", type: KtLayoutComponent, isStandalone: true, selector: "kt-layout", inputs: { desktopCloseBehavior: { classPropertyName: "desktopCloseBehavior", publicName: "desktopCloseBehavior", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "kt-layout-container" }, ngImport: i0, template: `
101
+ <ng-content select="kt-sidenav"></ng-content>
102
+ <div class="kt-layout-main-wrapper">
103
+ <ng-content select="kt-toolbar"></ng-content>
104
+ <main class="kt-layout-main" [attr.aria-hidden]="layout.isMobileOpen()">
105
+ <ng-content></ng-content>
106
+ </main>
107
+ </div>
108
+ <div
109
+ class="kt-layout-backdrop"
110
+ [class.is-visible]="layout.isMobileOpen()"
111
+ aria-hidden="true"
112
+ (click)="layout.close()"
113
+ ></div>
114
+ `, isInline: true });
115
+ }
116
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtLayoutComponent, decorators: [{
117
+ type: Component,
118
+ args: [{
119
+ selector: 'kt-layout',
120
+ standalone: true,
121
+ host: {
122
+ class: 'kt-layout-container',
123
+ },
124
+ template: `
125
+ <ng-content select="kt-sidenav"></ng-content>
126
+ <div class="kt-layout-main-wrapper">
127
+ <ng-content select="kt-toolbar"></ng-content>
128
+ <main class="kt-layout-main" [attr.aria-hidden]="layout.isMobileOpen()">
129
+ <ng-content></ng-content>
130
+ </main>
131
+ </div>
132
+ <div
133
+ class="kt-layout-backdrop"
134
+ [class.is-visible]="layout.isMobileOpen()"
135
+ aria-hidden="true"
136
+ (click)="layout.close()"
137
+ ></div>
138
+ `,
139
+ }]
140
+ }], ctorParameters: () => [], propDecorators: { desktopCloseBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "desktopCloseBehavior", required: false }] }] } });
141
+
142
+ /**
143
+ * Composant représentant le panneau latéral de navigation.
144
+ * Se comporte comme un tiroir (drawer) superposé sur mobile, et comme un
145
+ * menu latéral persistant (réductible ou masquable) sur ordinateur.
146
+ */
147
+ class KtSidenavComponent {
148
+ layout = inject(KtLayoutService);
149
+ isHidden = computed(() => this.layout.isHidden(), /* @ts-ignore */
150
+ ...(ngDevMode ? [{ debugName: "isHidden" }] : /* istanbul ignore next */ []));
151
+ trapFocus = inject(CdkTrapFocus);
152
+ constructor() {
153
+ effect(() => {
154
+ this.trapFocus.autoCapture = this.layout.isMobileOpen();
155
+ this.trapFocus.enabled = this.layout.isMobileOpen();
156
+ });
157
+ }
158
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSidenavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
159
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.1", type: KtSidenavComponent, isStandalone: true, selector: "kt-sidenav", host: { attributes: { "role": "navigation" }, properties: { "class.is-hidden": "isHidden()", "class.is-rail": "layout.isRail()", "class.is-mobile-open": "layout.isMobileOpen()", "attr.aria-expanded": "layout.isExpanded()", "attr.aria-hidden": "isHidden()" }, classAttribute: "kt-sidenav" }, hostDirectives: [{ directive: i1.CdkTrapFocus }], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true });
160
+ }
161
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSidenavComponent, decorators: [{
162
+ type: Component,
163
+ args: [{
164
+ selector: 'kt-sidenav',
165
+ standalone: true,
166
+ imports: [CdkTrapFocus],
167
+ host: {
168
+ class: 'kt-sidenav',
169
+ '[class.is-hidden]': 'isHidden()',
170
+ '[class.is-rail]': 'layout.isRail()',
171
+ '[class.is-mobile-open]': 'layout.isMobileOpen()',
172
+ '[attr.aria-expanded]': 'layout.isExpanded()',
173
+ '[attr.aria-hidden]': 'isHidden()',
174
+ role: 'navigation',
175
+ },
176
+ hostDirectives: [CdkTrapFocus],
177
+ template: `<ng-content></ng-content>`,
178
+ }]
179
+ }], ctorParameters: () => [] });
180
+
181
+ /**
182
+ * Barre d'outils supérieure (Toolbar / Top app bar).
183
+ * Se place généralement dans un `kt-layout`.
184
+ */
185
+ class KtToolbarComponent {
186
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
187
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.1", type: KtToolbarComponent, isStandalone: true, selector: "kt-toolbar", host: { attributes: { "role": "banner" }, classAttribute: "kt-toolbar" }, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true });
188
+ }
189
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtToolbarComponent, decorators: [{
190
+ type: Component,
191
+ args: [{
192
+ selector: 'kt-toolbar',
193
+ standalone: true,
194
+ host: {
195
+ class: 'kt-toolbar',
196
+ role: 'banner',
197
+ },
198
+ template: `<ng-content></ng-content>`,
199
+ }]
200
+ }] });
201
+
202
+ class KtNavItemComponent {
203
+ label = input.required(/* @ts-ignore */
204
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
205
+ layout = inject(KtLayoutService);
206
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtNavItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
207
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.1", type: KtNavItemComponent, isStandalone: true, selector: "kt-nav-item", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "kt-nav-item" }, ngImport: i0, template: `
208
+ <div class="kt-nav-item-icon">
209
+ <ng-content select="[kt-icon]"></ng-content>
210
+ </div>
211
+ <div class="kt-nav-item-label">
212
+ {{ label() }}
213
+ <ng-content></ng-content>
214
+ </div>
215
+ <!-- TODO: Add Tooltip component injection here conditionally based on layout.isRail() -->
216
+ `, isInline: true });
217
+ }
218
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtNavItemComponent, decorators: [{
219
+ type: Component,
220
+ args: [{
221
+ selector: 'kt-nav-item',
222
+ standalone: true,
223
+ host: {
224
+ class: 'kt-nav-item',
225
+ },
226
+ template: `
227
+ <div class="kt-nav-item-icon">
228
+ <ng-content select="[kt-icon]"></ng-content>
229
+ </div>
230
+ <div class="kt-nav-item-label">
231
+ {{ label() }}
232
+ <ng-content></ng-content>
233
+ </div>
234
+ <!-- TODO: Add Tooltip component injection here conditionally based on layout.isRail() -->
235
+ `,
236
+ }]
237
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }] } });
238
+
239
+ /**
240
+ * Directive applicable sur n'importe quel élément (souvent un bouton) pour basculer
241
+ * l'état d'ouverture du panneau latéral (Sidenav).
242
+ *
243
+ * Expose l'état du layout pour des utilisations dynamiques dans le template
244
+ * (ex: changer l'icône selon l'état).
245
+ *
246
+ * @example
247
+ * ```html
248
+ * <button ktSidenavToggle #btn="ktSidenavToggle" [icon]="btn.isRail() ? 'right' : 'left'">
249
+ * ```
250
+ */
251
+ class KtSidenavToggleDirective {
252
+ layout = inject(KtLayoutService);
253
+ /** Indique si le menu est actuellement réduit en mode rail. */
254
+ isRail = this.layout.isRail;
255
+ /** Indique si le menu est actuellement complètement étendu sur bureau. */
256
+ isExpanded = this.layout.isExpanded;
257
+ /** Indique si le menu est totalement masqué. */
258
+ isHidden = this.layout.isHidden;
259
+ /** Indique si le tiroir est actuellement ouvert par-dessus le contenu (mobile). */
260
+ isMobileOpen = this.layout.isMobileOpen;
261
+ /** Indique si l'écran actuel est de taille compacte (mobile). */
262
+ isMobile = this.layout.isMobile;
263
+ onClick() {
264
+ this.layout.toggle();
265
+ }
266
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSidenavToggleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
267
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: KtSidenavToggleDirective, isStandalone: true, selector: "[ktSidenavToggle]", host: { listeners: { "click": "onClick()" } }, exportAs: ["ktSidenavToggle"], ngImport: i0 });
268
+ }
269
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSidenavToggleDirective, decorators: [{
270
+ type: Directive,
271
+ args: [{
272
+ selector: '[ktSidenavToggle]',
273
+ exportAs: 'ktSidenavToggle',
274
+ standalone: true,
275
+ host: {
276
+ '(click)': 'onClick()',
277
+ },
278
+ }]
279
+ }] });
280
+
281
+ /**
282
+ * Generated bundle index. Do not edit.
283
+ */
284
+
285
+ export { KT_LAYOUT_DEFAULT_STATE, KtLayoutComponent, KtLayoutService, KtNavItemComponent, KtSidenavComponent, KtSidenavToggleDirective, KtToolbarComponent };
286
+ //# sourceMappingURL=ktortu-aaa-layout.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ktortu-aaa-layout.mjs","sources":["../../../../projects/ktortu/aaa/layout/layout.service.ts","../../../../projects/ktortu/aaa/layout/layout.component.ts","../../../../projects/ktortu/aaa/layout/sidenav.component.ts","../../../../projects/ktortu/aaa/layout/toolbar.component.ts","../../../../projects/ktortu/aaa/layout/nav-item.component.ts","../../../../projects/ktortu/aaa/layout/sidenav-toggle.directive.ts","../../../../projects/ktortu/aaa/layout/ktortu-aaa-layout.ts"],"sourcesContent":["import { Injectable, computed, inject, InjectionToken, signal } from '@angular/core';\nimport { KtViewport } from '@ktortu/aaa/cdk';\n\n/** Mode d'état de la navigation latérale. */\nexport type KtSidenavState = 'expanded' | 'rail' | 'hidden';\n\nexport const KT_LAYOUT_DEFAULT_STATE = new InjectionToken<KtSidenavState>('KT_LAYOUT_DEFAULT_STATE', {\n providedIn: 'root',\n factory: () => 'expanded',\n});\n\n/**\n * Service global de gestion de la mise en page (Layout).\n * Gère l'état d'ouverture/fermeture de la barre latérale sur mobile et bureau,\n * ainsi que le comportement spécifique de \"rail\" sur bureau.\n *\n * NOTE: Ce service n'est pas \"providedIn: 'root'\". Le développeur doit le fournir\n * (via le tableau providers d'un composant parent ou de l'application) pour\n * maîtriser le scope (ex: avoir plusieurs layouts indépendants).\n */\n@Injectable()\nexport class KtLayoutService {\n private readonly viewport = inject(KtViewport);\n private readonly defaultState = inject(KT_LAYOUT_DEFAULT_STATE);\n\n /**\n * Comportement actif lors de la fermeture sur ordinateur (écran non mobile).\n * Renseigné généralement par le composant racine `KtLayoutComponent`.\n */\n readonly desktopCloseBehavior = signal<'hidden' | 'rail'>('hidden');\n\n private readonly _isDesktopOpen = signal<boolean>(this.defaultState !== 'rail' && this.defaultState !== 'hidden');\n private readonly _isMobileOpen = signal<boolean>(false);\n\n readonly isMobile = this.viewport.isMobile;\n readonly isRail = computed(\n () => !this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'rail',\n );\n readonly isExpanded = computed(() => !this.isMobile() && this._isDesktopOpen());\n readonly isHidden = computed(\n () =>\n (this.isMobile() && !this._isMobileOpen()) ||\n (!this.isMobile() && !this._isDesktopOpen() && this.desktopCloseBehavior() === 'hidden'),\n );\n readonly isMobileOpen = computed(() => this.isMobile() && this._isMobileOpen());\n\n toggle() {\n if (this.isMobile()) {\n this._isMobileOpen.update((v) => !v);\n } else {\n this._isDesktopOpen.update((v) => !v);\n }\n }\n\n open() {\n if (this.isMobile()) {\n this._isMobileOpen.set(true);\n } else {\n this._isDesktopOpen.set(true);\n }\n }\n\n close() {\n if (this.isMobile()) {\n this._isMobileOpen.set(false);\n } else {\n this._isDesktopOpen.set(false);\n }\n }\n}\n","import { Component, inject, effect, input } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Composant racine de l'application qui gère la structure de base (Sidebar, Toolbar, Contenu).\n * Configure dynamiquement le comportement du layout.\n */\n@Component({\n selector: 'kt-layout',\n standalone: true,\n host: {\n class: 'kt-layout-container',\n },\n template: `\n <ng-content select=\"kt-sidenav\"></ng-content>\n <div class=\"kt-layout-main-wrapper\">\n <ng-content select=\"kt-toolbar\"></ng-content>\n <main class=\"kt-layout-main\" [attr.aria-hidden]=\"layout.isMobileOpen()\">\n <ng-content></ng-content>\n </main>\n </div>\n <div\n class=\"kt-layout-backdrop\"\n [class.is-visible]=\"layout.isMobileOpen()\"\n aria-hidden=\"true\"\n (click)=\"layout.close()\"\n ></div>\n `,\n})\nexport class KtLayoutComponent {\n /**\n * Définit le comportement de la navigation latérale lors de sa fermeture sur bureau (écran large).\n * - `'hidden'` (défaut) : le menu est complètement masqué et retiré du flux visuel/a11y.\n * - `'rail'` : le menu est réduit à une fine barre verticale (mini-sidebar), permettant\n * d'afficher uniquement les icônes. Idéal si les liens possèdent des icônes explicites.\n */\n readonly desktopCloseBehavior = input<'hidden' | 'rail'>('hidden');\n protected readonly layout = inject(KtLayoutService);\n\n constructor() {\n effect(\n () => {\n this.layout.desktopCloseBehavior.set(this.desktopCloseBehavior());\n },\n { allowSignalWrites: true },\n );\n\n effect(\n () => {\n // Clean up mobile state when switching back to desktop\n if (!this.layout.isMobile() && this.layout.isMobileOpen()) {\n this.layout.close();\n }\n },\n { allowSignalWrites: true },\n );\n }\n}\n","import { Component, inject, computed, effect } from '@angular/core';\nimport { CdkTrapFocus } from '@angular/cdk/a11y';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Composant représentant le panneau latéral de navigation.\n * Se comporte comme un tiroir (drawer) superposé sur mobile, et comme un\n * menu latéral persistant (réductible ou masquable) sur ordinateur.\n */\n@Component({\n selector: 'kt-sidenav',\n standalone: true,\n imports: [CdkTrapFocus],\n host: {\n class: 'kt-sidenav',\n '[class.is-hidden]': 'isHidden()',\n '[class.is-rail]': 'layout.isRail()',\n '[class.is-mobile-open]': 'layout.isMobileOpen()',\n '[attr.aria-expanded]': 'layout.isExpanded()',\n '[attr.aria-hidden]': 'isHidden()',\n role: 'navigation',\n },\n hostDirectives: [CdkTrapFocus],\n template: `<ng-content></ng-content>`,\n})\nexport class KtSidenavComponent {\n protected readonly layout = inject(KtLayoutService);\n protected readonly isHidden = computed(() => this.layout.isHidden());\n private readonly trapFocus = inject(CdkTrapFocus);\n\n constructor() {\n effect(() => {\n this.trapFocus.autoCapture = this.layout.isMobileOpen();\n this.trapFocus.enabled = this.layout.isMobileOpen();\n });\n }\n}\n","import { Component } from '@angular/core';\n\n/**\n * Barre d'outils supérieure (Toolbar / Top app bar).\n * Se place généralement dans un `kt-layout`.\n */\n@Component({\n selector: 'kt-toolbar',\n standalone: true,\n host: {\n class: 'kt-toolbar',\n role: 'banner',\n },\n template: `<ng-content></ng-content>`,\n})\nexport class KtToolbarComponent {}\n","import { Component, input, inject } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n@Component({\n selector: 'kt-nav-item',\n standalone: true,\n host: {\n class: 'kt-nav-item',\n },\n template: `\n <div class=\"kt-nav-item-icon\">\n <ng-content select=\"[kt-icon]\"></ng-content>\n </div>\n <div class=\"kt-nav-item-label\">\n {{ label() }}\n <ng-content></ng-content>\n </div>\n <!-- TODO: Add Tooltip component injection here conditionally based on layout.isRail() -->\n `,\n})\nexport class KtNavItemComponent {\n label = input.required<string>();\n protected readonly layout = inject(KtLayoutService);\n}\n","import { Directive, inject } from '@angular/core';\nimport { KtLayoutService } from './layout.service';\n\n/**\n * Directive applicable sur n'importe quel élément (souvent un bouton) pour basculer\n * l'état d'ouverture du panneau latéral (Sidenav).\n *\n * Expose l'état du layout pour des utilisations dynamiques dans le template\n * (ex: changer l'icône selon l'état).\n *\n * @example\n * ```html\n * <button ktSidenavToggle #btn=\"ktSidenavToggle\" [icon]=\"btn.isRail() ? 'right' : 'left'\">\n * ```\n */\n@Directive({\n selector: '[ktSidenavToggle]',\n exportAs: 'ktSidenavToggle',\n standalone: true,\n host: {\n '(click)': 'onClick()',\n },\n})\nexport class KtSidenavToggleDirective {\n private readonly layout = inject(KtLayoutService);\n\n /** Indique si le menu est actuellement réduit en mode rail. */\n readonly isRail = this.layout.isRail;\n\n /** Indique si le menu est actuellement complètement étendu sur bureau. */\n readonly isExpanded = this.layout.isExpanded;\n\n /** Indique si le menu est totalement masqué. */\n readonly isHidden = this.layout.isHidden;\n\n /** Indique si le tiroir est actuellement ouvert par-dessus le contenu (mobile). */\n readonly isMobileOpen = this.layout.isMobileOpen;\n\n /** Indique si l'écran actuel est de taille compacte (mobile). */\n readonly isMobile = this.layout.isMobile;\n\n onClick() {\n this.layout.toggle();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;MAMa,uBAAuB,GAAG,IAAI,cAAc,CAAiB,yBAAyB,EAAE;AACnG,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,UAAU;AAC1B,CAAA;AAED;;;;;;;;AAQG;MAEU,eAAe,CAAA;AACT,IAAA,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC;AAC7B,IAAA,YAAY,GAAG,MAAM,CAAC,uBAAuB,CAAC;AAE/D;;;AAGG;IACM,oBAAoB,GAAG,MAAM,CAAoB,QAAQ;6FAAC;AAElD,IAAA,cAAc,GAAG,MAAM,CAAU,IAAI,CAAC,YAAY,KAAK,MAAM,IAAI,IAAI,CAAC,YAAY,KAAK,QAAQ;uFAAC;IAChG,aAAa,GAAG,MAAM,CAAU,KAAK;sFAAC;AAE9C,IAAA,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ;IACjC,MAAM,GAAG,QAAQ,CACxB,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,IAAI,CAAC,oBAAoB,EAAE,KAAK,MAAM;+EAC3F;AACQ,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE;mFAAC;AACtE,IAAA,QAAQ,GAAG,QAAQ,CAC1B,MACE,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACzC,SAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,IAAI,CAAC,oBAAoB,EAAE,KAAK,QAAQ,CAAC;iFAC3F;AACQ,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,aAAa,EAAE;qFAAC;IAE/E,MAAM,GAAA;AACJ,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC;aAAO;AACL,YAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC;IACF;IAEA,IAAI,GAAA;AACF,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;QAC9B;aAAO;AACL,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;QAC/B;IACF;IAEA,KAAK,GAAA;AACH,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;QAC/B;aAAO;AACL,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;QAChC;IACF;uGA/CW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAf,eAAe,EAAA,CAAA;;2FAAf,eAAe,EAAA,UAAA,EAAA,CAAA;kBAD3B;;;ACjBD;;;AAGG;MAuBU,iBAAiB,CAAA;AAC5B;;;;;AAKG;IACM,oBAAoB,GAAG,KAAK,CAAoB,QAAQ;6FAAC;AAC/C,IAAA,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;AAEnD,IAAA,WAAA,GAAA;QACE,MAAM,CACJ,MAAK;AACH,YAAA,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;AACnE,QAAA,CAAC,EACD,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAC5B;QAED,MAAM,CACJ,MAAK;;AAEH,YAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE;AACzD,gBAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;YACrB;AACF,QAAA,CAAC,EACD,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAC5B;IACH;uGA3BW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAjB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,EAAA,oBAAA,EAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,qBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhBlB;;;;;;;;;;;;;;AAcT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAEU,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAtB7B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,WAAW;AACrB,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,qBAAqB;AAC7B,qBAAA;AACD,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;AAcT,EAAA,CAAA;AACF,iBAAA;;;ACxBD;;;;AAIG;MAiBU,kBAAkB,CAAA;AACV,IAAA,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;IAChC,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;iFAAC;AACnD,IAAA,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;AAEjD,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YACvD,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;AACrD,QAAA,CAAC,CAAC;IACJ;uGAVW,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,kBAAkB,2ZAFnB,CAAA,yBAAA,CAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAE1B,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAhB9B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,YAAY;AACtB,oBAAA,UAAU,EAAE,IAAI;oBAChB,OAAO,EAAE,CAAC,YAAY,CAAC;AACvB,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,YAAY;AACnB,wBAAA,mBAAmB,EAAE,YAAY;AACjC,wBAAA,iBAAiB,EAAE,iBAAiB;AACpC,wBAAA,wBAAwB,EAAE,uBAAuB;AACjD,wBAAA,sBAAsB,EAAE,qBAAqB;AAC7C,wBAAA,oBAAoB,EAAE,YAAY;AAClC,wBAAA,IAAI,EAAE,YAAY;AACnB,qBAAA;oBACD,cAAc,EAAE,CAAC,YAAY,CAAC;AAC9B,oBAAA,QAAQ,EAAE,CAAA,yBAAA,CAA2B;AACtC,iBAAA;;;ACtBD;;;AAGG;MAUU,kBAAkB,CAAA;uGAAlB,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,kBAAkB,gJAFnB,CAAA,yBAAA,CAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAE1B,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAT9B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,YAAY;AACtB,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,YAAY;AACnB,wBAAA,IAAI,EAAE,QAAQ;AACf,qBAAA;AACD,oBAAA,QAAQ,EAAE,CAAA,yBAAA,CAA2B;AACtC,iBAAA;;;MCMY,kBAAkB,CAAA;IAC7B,KAAK,GAAG,KAAK,CAAC,QAAQ;8EAAU;AACb,IAAA,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;uGAFxC,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,aAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAXnB;;;;;;;;;AAST,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAEU,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAjB9B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,aAAa;AACvB,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,aAAa;AACrB,qBAAA;AACD,oBAAA,QAAQ,EAAE;;;;;;;;;AAST,EAAA,CAAA;AACF,iBAAA;;;AChBD;;;;;;;;;;;AAWG;MASU,wBAAwB,CAAA;AAClB,IAAA,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;;AAGxC,IAAA,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM;;AAG3B,IAAA,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU;;AAGnC,IAAA,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ;;AAG/B,IAAA,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;;AAGvC,IAAA,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ;IAExC,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;IACtB;uGApBW,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAxB,wBAAwB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAxB,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBARpC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,QAAQ,EAAE,iBAAiB;AAC3B,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACvB,qBAAA;AACF,iBAAA;;;ACtBD;;AAEG;;;;"}
@@ -10,6 +10,7 @@ export * from '@ktortu/aaa/snackbar';
10
10
  export * from '@ktortu/aaa/tabs';
11
11
  export * from '@ktortu/aaa/tooltip';
12
12
  export * from '@ktortu/aaa/progress-bar';
13
+ export * from '@ktortu/aaa/layout';
13
14
 
14
15
  /*
15
16
  * Public API Surface of @ktortu/aaa
@@ -1 +1 @@
1
- {"version":3,"file":"ktortu-aaa.mjs","sources":["../../../../projects/ktortu/aaa/src/public-api.ts","../../../../projects/ktortu/aaa/src/ktortu-aaa.ts"],"sourcesContent":["/*\n * Public API Surface of @ktortu/aaa\n */\nexport * from '@ktortu/aaa/button';\nexport * from '@ktortu/aaa/card';\nexport * from '@ktortu/aaa/cdk';\nexport * from '@ktortu/aaa/dialog';\nexport * from '@ktortu/aaa/disclosure';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/i18n';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/snackbar';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\nexport * from '@ktortu/aaa/progress-bar';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
1
+ {"version":3,"file":"ktortu-aaa.mjs","sources":["../../../../projects/ktortu/aaa/src/public-api.ts","../../../../projects/ktortu/aaa/src/ktortu-aaa.ts"],"sourcesContent":["/*\n * Public API Surface of @ktortu/aaa\n */\nexport * from '@ktortu/aaa/button';\nexport * from '@ktortu/aaa/card';\nexport * from '@ktortu/aaa/cdk';\nexport * from '@ktortu/aaa/dialog';\nexport * from '@ktortu/aaa/disclosure';\nexport * from '@ktortu/aaa/forms';\nexport * from '@ktortu/aaa/i18n';\nexport * from '@ktortu/aaa/menu';\nexport * from '@ktortu/aaa/snackbar';\nexport * from '@ktortu/aaa/tabs';\nexport * from '@ktortu/aaa/tooltip';\nexport * from '@ktortu/aaa/progress-bar';\nexport * from '@ktortu/aaa/layout';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA;;AAEG;;ACFH;;AAEG"}
@@ -0,0 +1,56 @@
1
+ @layer kt-aaa.components {
2
+ .kt-chip-listbox-field {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 0.5rem;
6
+ }
7
+
8
+ .kt-chip-listbox__legend {
9
+ font-size: 0.875rem;
10
+ font-weight: 500;
11
+ color: var(--field-label-color, currentColor);
12
+ }
13
+
14
+ .kt-chip-listbox__required {
15
+ color: var(--kt-danger);
16
+ margin-inline-start: 0.125rem;
17
+ }
18
+
19
+ .kt-chip-listbox__options {
20
+ display: flex;
21
+ flex-wrap: wrap;
22
+ gap: 0.5rem;
23
+ outline: none;
24
+ }
25
+
26
+ .kt-chip-listbox__hint {
27
+ font-size: 0.75rem;
28
+ color: var(--field-hint-color);
29
+ margin: 0;
30
+ }
31
+
32
+ .kt-chip-listbox__error {
33
+ font-size: 0.75rem;
34
+ color: var(--field-error-color);
35
+ min-block-size: 1.25rem;
36
+ }
37
+
38
+ .kt-chip-listbox__error-message {
39
+ display: block;
40
+ }
41
+
42
+ .kt-chip-listbox__legend--visually-hidden,
43
+ .kt-chip-listbox__error--visually-hidden {
44
+ position: absolute;
45
+ inset-block-start: 0;
46
+ inset-inline-start: 0;
47
+ inline-size: 1px;
48
+ block-size: 1px;
49
+ min-block-size: 0;
50
+ padding: 0;
51
+ margin: -1px;
52
+ overflow: hidden;
53
+ clip-path: inset(50%);
54
+ white-space: nowrap;
55
+ }
56
+ }
@@ -89,4 +89,51 @@
89
89
  inset: -8px;
90
90
  }
91
91
  }
92
+
93
+ :host(.kt-chip--selected) {
94
+ background: var(--chip-selected-bg, var(--chip-bg-hover));
95
+ border-color: var(--chip-selected-border, var(--chip-focus-ring));
96
+ color: var(--chip-selected-color, var(--chip-color));
97
+ }
98
+
99
+ .kt-chip__selected-icon {
100
+ font-family: 'Material Symbols Outlined';
101
+ font-feature-settings: 'liga';
102
+ font-size: 1rem;
103
+ line-height: 1;
104
+ -webkit-font-smoothing: antialiased;
105
+ margin-inline-end: 0.125rem;
106
+ }
107
+
108
+ /* --- Styles pour les puces sélectionnables (role="option") --- */
109
+ :host([role='option']) {
110
+ transition:
111
+ background-color 0.15s ease,
112
+ border-color 0.15s ease,
113
+ color 0.15s ease,
114
+ box-shadow 0.15s ease;
115
+ }
116
+
117
+ :host([role='option']:not([aria-disabled='true'])) {
118
+ cursor: pointer;
119
+ }
120
+
121
+ :host([role='option']:not([aria-disabled='true']):hover) {
122
+ background-color: var(--chip-bg-hover);
123
+ box-shadow: var(--chip-shadow-hover, var(--chip-shadow, none));
124
+ }
125
+
126
+ :host([role='option'].kt-chip--selected:not([aria-disabled='true']):hover) {
127
+ background-color: color-mix(in srgb, var(--chip-selected-bg) 85%, var(--kt-primary));
128
+ }
129
+
130
+ :host([role='option']:focus-visible) {
131
+ outline: 2px solid var(--chip-focus-ring);
132
+ outline-offset: 2px;
133
+ }
134
+
135
+ :host([role='option'][aria-disabled='true']) {
136
+ cursor: not-allowed;
137
+ opacity: 0.5;
138
+ }
92
139
  }
@@ -14,6 +14,11 @@
14
14
  --chip-bg-hover: color-mix(in srgb, var(--kt-primary) 18%, transparent);
15
15
  --chip-border: color-mix(in srgb, var(--kt-primary) 20%, transparent);
16
16
 
17
+ /* État sélectionné */
18
+ --chip-selected-bg: color-mix(in srgb, var(--kt-primary) 15%, transparent);
19
+ --chip-selected-border: var(--kt-primary);
20
+ --chip-selected-color: var(--kt-primary);
21
+
17
22
  /* Texte et icônes */
18
23
  --chip-color: var(--field-color);
19
24
  --chip-remove-color: var(--field-icon-color);
@@ -74,7 +74,9 @@
74
74
  /* Copie visually-hidden du texte d'aide : présente en permanence dans l'arbre d'accessibilité
75
75
  (technique clip), contrairement à la bulle du tooltip créée à la volée → aria-describedby du
76
76
  contrôle résout toujours sa cible (pas de référence pendante pour les lecteurs d'écran). */
77
- .kt-field__help-description {
77
+ .kt-field__help-description,
78
+ .kt-field__label--visually-hidden,
79
+ .kt-field__error--visually-hidden {
78
80
  position: absolute;
79
81
  inset-block-start: 0;
80
82
  inset-inline-start: 0;
@@ -79,7 +79,7 @@
79
79
  border-style: var(--field-border-style, solid);
80
80
  border-color: var(--field-border-color, #c4c7c5);
81
81
  border-radius: var(--field-radius, 8px);
82
- background: var(--select-popup-bg, var(--kt-surface, #fff));
82
+ background: var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));
83
83
  color: var(--field-color, inherit);
84
84
  box-shadow: var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));
85
85
  /* Translucidité (verre) : bascule => aucun effet par défaut (cf. theme-liquid-glass). */
@@ -144,7 +144,7 @@
144
144
  padding: 0.375rem 0.625rem;
145
145
  border: var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);
146
146
  border-radius: calc(var(--field-radius, 8px) * 0.75);
147
- background: var(--select-popup-bg, var(--kt-surface, #fff));
147
+ background: var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));
148
148
  color: var(--field-color, inherit);
149
149
  font: inherit;
150
150
  /* Neutralise l'aspect natif de type=search (coins en pilule sur Safari) ; le rôle implicite
@@ -252,7 +252,7 @@
252
252
  z-index: 2;
253
253
  display: flex;
254
254
  flex-direction: column;
255
- background: var(--select-popup-bg, var(--kt-surface, #fff));
255
+ background: var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));
256
256
  border-radius: var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;
257
257
  box-shadow: var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));
258
258
  max-block-size: var(--kt-sheet-max-block-size, 85svh);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktortu/aaa",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "Bibliothèque de composants Angular headless + thémés par tokens CSS.",
5
5
  "keywords": [
6
6
  "angular",
@@ -85,6 +85,10 @@
85
85
  "types": "./types/ktortu-aaa-i18n.d.ts",
86
86
  "default": "./fesm2022/ktortu-aaa-i18n.mjs"
87
87
  },
88
+ "./layout": {
89
+ "types": "./types/ktortu-aaa-layout.d.ts",
90
+ "default": "./fesm2022/ktortu-aaa-layout.mjs"
91
+ },
88
92
  "./menu": {
89
93
  "types": "./types/ktortu-aaa-menu.d.ts",
90
94
  "default": "./fesm2022/ktortu-aaa-menu.mjs"
@@ -0,0 +1,140 @@
1
+ /* ktortu/aaa/styles/layout.css */
2
+ :root {
3
+ --kt-sidenav-width: 280px;
4
+ --kt-sidenav-rail-width: 72px;
5
+ --kt-layout-transition: 200ms cubic-bezier(0.25, 0.8, 0.25, 1);
6
+ --kt-toolbar-height: 64px;
7
+ }
8
+
9
+ .kt-layout-container {
10
+ display: flex;
11
+ height: 100dvh;
12
+ width: 100%;
13
+ overflow: hidden;
14
+ position: relative;
15
+ background: var(--kt-surface, #f8f9fa);
16
+ color: var(--kt-on-surface, #1f1f1f);
17
+ }
18
+
19
+ .kt-sidenav {
20
+ width: var(--kt-sidenav-width);
21
+ background: var(--kt-surface, #ffffff);
22
+ border-right: 1px solid var(--kt-outline, #e0e0e0);
23
+ flex-shrink: 0;
24
+ transition:
25
+ width var(--kt-layout-transition),
26
+ transform var(--kt-layout-transition);
27
+ display: flex;
28
+ flex-direction: column;
29
+ overflow-x: hidden;
30
+ overflow-y: auto;
31
+ z-index: 10;
32
+ }
33
+
34
+ .kt-sidenav.is-rail {
35
+ width: var(--kt-sidenav-rail-width);
36
+ }
37
+
38
+ @media (min-width: 601px) {
39
+ .kt-sidenav.is-hidden {
40
+ width: 0;
41
+ border-right-color: transparent;
42
+ }
43
+ }
44
+
45
+ .kt-layout-main-wrapper {
46
+ flex: 1;
47
+ display: flex;
48
+ flex-direction: column;
49
+ min-width: 0;
50
+ overflow: hidden;
51
+ }
52
+
53
+ .kt-toolbar {
54
+ height: var(--kt-toolbar-height);
55
+ background: var(--kt-surface, #ffffff);
56
+ border-bottom: 1px solid var(--kt-outline, #e0e0e0);
57
+ display: flex;
58
+ align-items: center;
59
+ padding: 0 16px;
60
+ flex-shrink: 0;
61
+ z-index: 5;
62
+ }
63
+
64
+ .kt-layout-main {
65
+ flex: 1;
66
+ overflow-y: auto;
67
+ padding: 24px;
68
+ }
69
+
70
+ .kt-layout-backdrop {
71
+ display: none;
72
+ position: fixed;
73
+ inset: 0;
74
+ background: rgba(0, 0, 0, 0.32);
75
+ z-index: 99;
76
+ opacity: 0;
77
+ transition: opacity var(--kt-layout-transition);
78
+ }
79
+
80
+ /* Nav Item styling for truncation */
81
+ .kt-nav-item {
82
+ display: flex;
83
+ align-items: center;
84
+ gap: 16px;
85
+ width: 100%;
86
+ cursor: pointer;
87
+ white-space: nowrap;
88
+ overflow: hidden;
89
+ }
90
+
91
+ .kt-nav-item-icon {
92
+ width: 24px;
93
+ height: 24px;
94
+ flex-shrink: 0;
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ }
99
+
100
+ .kt-nav-item-label {
101
+ flex: 1;
102
+ overflow: hidden;
103
+ text-overflow: ellipsis;
104
+ opacity: 1;
105
+ transition: opacity 100ms;
106
+ }
107
+
108
+ .kt-sidenav.is-rail .kt-nav-item-label {
109
+ opacity: 0;
110
+ }
111
+
112
+ /*
113
+ Mobile Breakpoint - 600px par défaut
114
+ (A copier/éjecter si modification nécessaire)
115
+ */
116
+ @media (max-width: 600px) {
117
+ .kt-sidenav {
118
+ position: fixed;
119
+ top: 0;
120
+ bottom: 0;
121
+ left: 0;
122
+ z-index: 100;
123
+ transform: translateX(-100%);
124
+ width: 280px; /* On force la largeur étendue sur mobile */
125
+ }
126
+
127
+ .kt-sidenav.is-mobile-open {
128
+ transform: translateX(0);
129
+ }
130
+
131
+ .kt-layout-backdrop {
132
+ display: block;
133
+ pointer-events: none;
134
+ }
135
+
136
+ .kt-layout-backdrop.is-visible {
137
+ opacity: 1;
138
+ pointer-events: auto;
139
+ }
140
+ }
package/styles/styles.css CHANGED
@@ -25,3 +25,4 @@
25
25
  @import './snackbar.css';
26
26
  @import './disclosure.css';
27
27
  @import './progress-bar.css';
28
+ @import './layout.css';