@ktortu/aaa 0.10.2 → 0.11.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ktortu-aaa-dialog.mjs","sources":["../../../../projects/ktortu/aaa/dialog/dialog-title.directive.ts","../../../../projects/ktortu/aaa/dialog/dialog-description.directive.ts","../../../../projects/ktortu/aaa/dialog/dialog-close.directive.ts","../../../../projects/ktortu/aaa/dialog/dialog-structure.ts","../../../../projects/ktortu/aaa/dialog/dialog-config.ts","../../../../projects/ktortu/aaa/dialog/dialog-container.ts","../../../../projects/ktortu/aaa/dialog/dialog-opener.ts","../../../../projects/ktortu/aaa/dialog/dialog-imports.ts","../../../../projects/ktortu/aaa/dialog/dialog-helpers.ts","../../../../projects/ktortu/aaa/dialog/ktortu-aaa-dialog.ts"],"sourcesContent":["import { DialogRef } from '@angular/cdk/dialog';\nimport { Directive, ElementRef, Renderer2, afterNextRender, inject } from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\n/**\n * À poser sur le titre VISIBLE (idéalement un `<h2>`) du contenu d'un CDK Dialog.\n * Câble `aria-labelledby` du conteneur de dialogue.\n *\n * Pourquoi écrire l'attribut directement (Renderer2) plutôt que seulement `_addAriaLabelledBy` :\n * sous change detection ZONELESS (cas par défaut moderne), le `markForCheck()` interne du\n * conteneur ne rafraîchit pas ses host bindings à l'ouverture, donc l'attribut n'apparaîtrait\n * jamais. On écrit donc l'attribut nous-mêmes (fiable, indépendant de la CD) ET on alimente la\n * file CDK pour rester cohérent si un cycle de CD survient ensuite.\n *\n * @example\n * ```html\n * <h2 ktDialogTitle>Renommer le fichier</h2>\n * ```\n */\n@Directive({\n selector: '[ktDialogTitle]',\n host: { '[id]': 'id' },\n})\nexport class KtDialogTitle {\n private readonly dialogRef = inject<DialogRef<unknown>>(DialogRef, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly renderer = inject(Renderer2);\n private readonly idGen = inject(KtIdGenerator);\n\n /**\n * Id de l'hôte câblé en `aria-labelledby` : préserve un id fourni par le consommateur, sinon en génère un.\n * @default `host.id` ?? `dialogRef.config.ariaLabelledBy` ?? `kt-dialog-title-<généré>`\n */\n readonly id =\n this.host.id || this.dialogRef?.config.ariaLabelledBy || `kt-dialog-title-${this.idGen.generateId('dialog')}`;\n\n constructor() {\n const preConfigured = this.dialogRef?.config.ariaLabelledBy;\n if (!preConfigured) {\n if (this.dialogRef) {\n this.dialogRef.config.ariaLabelledBy = this.id;\n }\n afterNextRender(() => {\n const container = this.host.closest('.cdk-dialog-container');\n if (container) this.renderer.setAttribute(container, 'aria-labelledby', this.id);\n });\n }\n }\n}\n","import { DialogRef } from '@angular/cdk/dialog';\nimport { Directive, ElementRef, OnDestroy, OnInit, Renderer2, afterNextRender, inject } from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\n/**\n * À poser sur le paragraphe descriptif COURT du dialog : câble `aria-describedby` du conteneur\n * (texte lu par le lecteur d'écran juste après le titre, à l'ouverture).\n *\n * ⚠️ Ne JAMAIS appliquer sur un formulaire ou un long contenu : `aria-describedby` concatène\n * tout le texte du nœud et serait lu d'un bloc à l'ouverture. Réserver à une phrase de contexte.\n *\n * Écriture directe de l'attribut (Renderer2) pour la même raison que `ktDialogTitle` :\n * fiabilité sous change detection zoneless. La config est tenue à jour pour cohérence CDK.\n *\n * @example\n * ```html\n * <p ktDialogDescription>Cette action est définitive.</p>\n * ```\n */\n@Directive({\n selector: '[ktDialogDescription]',\n host: { '[id]': 'id' },\n})\nexport class KtDialogDescription implements OnInit, OnDestroy {\n private readonly dialogRef = inject<DialogRef<unknown>>(DialogRef, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly renderer = inject(Renderer2);\n private readonly idGen = inject(KtIdGenerator);\n\n /**\n * Id de l'hôte câblé en `aria-describedby` : préserve un id fourni par le consommateur, sinon en génère un.\n * @default `host.id` ?? `dialogRef.config.ariaDescribedBy` ?? `kt-dialog-desc-<généré>`\n */\n readonly id =\n this.host.id || this.dialogRef?.config.ariaDescribedBy || `kt-dialog-desc-${this.idGen.generateId('dialog')}`;\n\n constructor() {\n const preConfigured = this.dialogRef?.config.ariaDescribedBy;\n if (!preConfigured) {\n if (this.dialogRef) {\n this.dialogRef.config.ariaDescribedBy = this.id;\n }\n afterNextRender(() => {\n const container = this.host.closest('.cdk-dialog-container');\n if (container) this.renderer.setAttribute(container, 'aria-describedby', this.id);\n });\n }\n }\n\n ngOnInit(): void {\n // Asymétrie ASSUMÉE avec `ktDialogTitle` : la description peut porter un `id` d'hôte fourni par\n // le consommateur ; on aligne alors `config.ariaDescribedBy` dessus (le host binding live du\n // conteneur reflète la valeur). Un titre est posé une fois et n'a pas ce besoin.\n if (this.dialogRef && this.dialogRef.config.ariaDescribedBy !== this.id) {\n this.dialogRef.config.ariaDescribedBy = this.id;\n }\n }\n\n ngOnDestroy(): void {\n if (this.dialogRef?.config.ariaDescribedBy === this.id) {\n this.dialogRef.config.ariaDescribedBy = null;\n }\n }\n}\n","import { DialogRef } from '@angular/cdk/dialog';\nimport { Directive, ElementRef, afterNextRender, inject, input, isDevMode } from '@angular/core';\n\n/**\n * Ferme le CDK Dialog au clic, avec un résultat optionnel renvoyé à l'ouvreur via\n * `DialogRef.close(result)`. Se compose avec `[ktButton]` sur le même `<button>`.\n *\n * Réservé au DISMISS simple (Annuler / Fermer). Pour valider un formulaire, injectez\n * `DialogRef` dans votre composant et appelez `close(valeur)` après validation.\n *\n * @example\n * ```html\n * <button ktButton ktDialogClose>Annuler</button>\n * <button ktButton [ktDialogClose]=\"'confirm'\">Confirmer</button>\n * ```\n */\n@Directive({\n selector: '[ktDialogClose]',\n host: {\n '[attr.type]': 'buttonType',\n '(click)': 'close()',\n },\n})\nexport class KtDialogClose {\n private readonly dialogRef = inject<DialogRef<unknown>>(DialogRef, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n /**\n * Valeur renvoyée à l'ouvreur via `DialogRef.close(result)`. Liée par l'alias `ktDialogClose`\n * (= nom du sélecteur), d'où l'usage `[ktDialogClose]=\"'confirm'\"`. @default undefined\n */\n readonly dialogResult = input<unknown>(undefined, { alias: 'ktDialogClose' });\n\n // Force type=\"button\" sur un <button> (évite le submit implicite dans un <form>).\n protected readonly buttonType = this.host.tagName === 'BUTTON' ? 'button' : null;\n\n constructor() {\n // Garde-fou a11y (dev) : un bouton de fermeture doit avoir un nom accessible (WCAG 4.1.2).\n afterNextRender(() => {\n if (!isDevMode()) return;\n\n const named =\n (this.host.textContent ?? '').trim().length > 0 ||\n this.host.hasAttribute('aria-label') ||\n this.host.hasAttribute('aria-labelledby');\n if (!named) {\n console.warn(\n '[ktDialogClose] Bouton de fermeture sans nom accessible (WCAG 4.1.2) : ' +\n 'ajoutez du texte visible, aria-label ou aria-labelledby.',\n );\n }\n });\n }\n\n protected close(): void {\n this.dialogRef?.close(this.dialogResult());\n }\n}\n","import { Directive, isDevMode } from '@angular/core';\n\n/**\n * En-tête RICHE et OPTIONNEL du dialog : rangée flex pour composer une icône, le titre et/ou un\n * bouton de fermeture. Marqueur structurel sans logique — la mise en forme (flex, padding de\n * région, reset du padding du [ktDialogTitle] qu'il enveloppe) vit dans `dialog.css`.\n *\n * Sépare le LAYOUT (cette région) de l'ÉTIQUETTE ACCESSIBLE ([ktDialogTitle], qui garde\n * aria-labelledby). En usage simple — titre nu sans header — [ktDialogTitle] conserve son propre\n * padding : ce header n'est à utiliser que pour les en-têtes composés (icône, close top-right…).\n *\n * ⚠️ Ne rend RIEN par lui-même — pas de bouton de fermeture implicite : c'est vous qui posez la\n * croix (cf. exemple). En présentation `sheet`, l'option `sheetCloseButton` en rend une\n * automatiquement, hors flux ; les deux ensemble feraient doublon (le conteneur avertit en dev).\n *\n * @example\n * ```html\n * <header ktDialogHeader>\n * <h2 ktDialogTitle>Titre</h2>\n * <button ktButton ktDialogClose aria-label=\"Fermer\">✕</button>\n * </header>\n * ```\n */\n@Directive({ selector: '[ktDialogHeader]' })\nexport class KtDialogHeader {}\n\n/**\n * Zone de contenu du dialog. Marqueur structurel sans logique : la mise en forme\n * (rythme vertical) vit dans `dialog.css` via le sélecteur `[ktDialogContent]`.\n *\n * @example\n * ```html\n * <div ktDialogContent>…</div>\n * ```\n */\n@Directive({ selector: '[ktDialogContent]' })\nexport class KtDialogContent {}\n\n/**\n * Barre d'actions du dialog (rangée de boutons). Marqueur structurel sans logique :\n * la mise en forme (flex, gap, sticky bas pour le Reflow AAA) vit dans `dialog.css`\n * via le sélecteur `[ktDialogActions]`.\n *\n * @example\n * ```html\n * <footer ktDialogActions>\n * <button ktButton ktDialogClose>Annuler</button>\n * <button ktButton [ktDialogClose]=\"'ok'\">Valider</button>\n * </footer>\n * ```\n */\n@Directive({ selector: '[ktDialogActions]' })\nexport class KtDialogActions {}\n\n/**\n * Marque l'élément à focaliser à l'ouverture. À coupler avec la config CDK\n * `autoFocus: '[ktDialogFocusInitial]'` (incluse dans `provideKtDialogDefaults`).\n * Permet d'éviter que le focus initial tombe sur une action destructrice.\n *\n * @example\n * ```html\n * <input ktDialogFocusInitial type=\"text\" />\n * ```\n */\n@Directive({ selector: '[ktDialogFocusInitial]' })\nexport class KtDialogFocusInitial {}\n\n/**\n * @deprecated ADR-0005 — la poignée est désormais RENDUE AUTOMATIQUEMENT par `KtDialogContainer`\n * en présentation `sheet` (opt-out : option typée `sheetHandle: false`), et le\n * drag-to-dismiss s'attrape sur TOUTE la surface de la sheet (scroll-snap natif). Cette\n * directive est INERTE et son hôte est masqué (évite une double poignée) : retirez-la de vos\n * templates. Sera supprimée dans une prochaine version majeure.\n */\n@Directive({\n selector: '[ktDialogSheetHandle]',\n host: {\n 'aria-hidden': 'true',\n style: 'display: none',\n },\n})\nexport class KtDialogSheetHandle {\n constructor() {\n if (isDevMode()) {\n console.warn(\n '[ktDialogSheetHandle] déprécié (ADR-0005) : la poignée est rendue automatiquement en ' +\n 'présentation sheet et le drag s’attrape partout — retirez la directive de votre template.',\n );\n }\n }\n}\n","import { DEFAULT_DIALOG_CONFIG, DialogConfig } from '@angular/cdk/dialog';\nimport { InjectionToken, Provider } from '@angular/core';\n\n/**\n * Valeurs par défaut orientées AAA pour `@angular/cdk/dialog`.\n * - `ariaModal: true` : explicite (le CDK le laisse OFF par défaut).\n * - `restoreFocus: true` : rend le focus au déclencheur à la fermeture.\n * - `panelClass` / `backdropClass` : crochets de style consommés par `dialog.css`.\n *\n * Pour focaliser un élément précis à l'ouverture (ex. éviter un bouton destructeur),\n * passez `autoFocus: '[ktDialogFocusInitial]'` dans la config d'ouverture et posez la\n * directive `ktDialogFocusInitial` sur la cible.\n *\n * @example\n * ```ts\n * // valeur de base, généralement consommée via provideKtDialogDefaults()\n * provideKtDialogDefaults({ ...KT_DIALOG_AAA_DEFAULTS });\n * ```\n */\nexport const KT_DIALOG_AAA_DEFAULTS: DialogConfig = {\n role: 'dialog',\n ariaModal: true,\n autoFocus: '[ktDialogFocusInitial]',\n restoreFocus: true,\n hasBackdrop: true,\n panelClass: 'kt-dialog',\n backdropClass: 'kt-dialog__backdrop',\n /* Plafond de largeur posé en STYLE INLINE sur le pane par l'overlay (canal prévu par le CDK).\n Indispensable : le CDK injecte à l'exécution `.cdk-overlay-pane { max-width: 100% }` HORS\n layer, qui bat toute règle de la lib importée via layer() — seul un style inline gagne.\n La custom property garde la thémisation ; `--fullscreen`/`--sheet` la retunent sur leur\n pane (cf. dialog.css). */\n maxWidth: 'var(--dialog-max-width)',\n};\n\n/**\n * Enregistre les valeurs par défaut AAA du dialog au niveau application.\n * À ajouter aux `providers` de `app.config.ts`. `overrides` permet d'ajuster sans\n * tout réécrire (ex. `provideKtDialogDefaults({ maxWidth: '40rem' })`).\n *\n * @example\n * ```ts\n * // app.config.ts\n * export const appConfig: ApplicationConfig = {\n * providers: [provideKtDialogDefaults({ maxWidth: '40rem' })],\n * };\n * ```\n * @param overrides Surcharges partielles fusionnées par-dessus `KT_DIALOG_AAA_DEFAULTS`.\n * @returns Un `Provider` pour le token `DEFAULT_DIALOG_CONFIG`.\n */\nexport function provideKtDialogDefaults(overrides?: Partial<DialogConfig>): Provider {\n return {\n provide: DEFAULT_DIALOG_CONFIG,\n useValue: { ...KT_DIALOG_AAA_DEFAULTS, ...overrides },\n };\n}\n\n/**\n * Options MAISON du dialog (≠ {@link KT_DIALOG_AAA_DEFAULTS}, qui porte la config du CDK).\n * Conforme à l'ADR-0003 : un token `KT_*_CONFIG` par entry-point, défauts anglais neutres,\n * cascade `option d'ouverture ?? token ?? défaut`.\n *\n * Toutes les clés actuelles ne concernent que la présentation `sheet` (préfixe `sheet*`) : sur les\n * présentations `centered` / `fullscreen`, la place d'un bouton de fermeture est un\n * `[ktDialogHeader]`, où on le POSE soi-même, dans le flux. Un usage hors sheet déclenche un\n * avertissement en mode dev.\n */\nexport interface KtDialogConfig {\n /**\n * Bouton de fermeture AUTO-RENDU en haut de la carte, en présentation `sheet`.\n *\n * Désactivé par défaut, pour une raison de COMPATIBILITÉ, pas d'ergonomie : `[ktDialogHeader]`\n * ne rend aucune croix (c'est une simple rangée flex), mais un dialog qui en compose un y place\n * généralement la sienne à la main. Activer l'option par défaut ferait donc apparaître une\n * DEUXIÈME croix chez ces consommateurs-là sans qu'ils aient rien changé.\n *\n * Recommandé sur toute sheet qui ne pose pas déjà son propre bouton de fermeture en tête.\n * @default false\n */\n sheetCloseButton: boolean;\n /** Nom accessible du bouton de fermeture auto-rendu (WCAG 4.1.2). @default 'Close' */\n sheetCloseLabel: string;\n /** Poignée décorative auto-rendue en présentation `sheet` (ADR-0005). @default true */\n sheetHandle: boolean;\n}\n\n/**\n * Défauts effectifs des options maison du dialog. Objet `Required` figé : c'est la SOURCE des\n * valeurs de repli, lue à la fois par l'ouvreur (résolution) et par le conteneur (fusion\n * idempotente), et énumérée par la garde de complétude i18n.\n */\nexport const DEFAULT_KT_DIALOG_CONFIG: Required<KtDialogConfig> = {\n sheetCloseButton: false,\n sheetCloseLabel: 'Close',\n sheetHandle: true,\n};\n\n/**\n * Token des options maison du dialog. Deux usages, un seul chemin de résolution :\n * - **application** : fourni via {@link provideKtDialog} (valeur partielle) ;\n * - **par ouverture** : `injectKtDialogOpener` REFOURNIT ce même token, déjà RÉSOLU, dans\n * l'injecteur du conteneur (canal `container.providers` du CDK). Le conteneur fusionne\n * toujours par-dessus {@link DEFAULT_KT_DIALOG_CONFIG} : l'opération est idempotente sur une\n * valeur déjà résolue, et reste correcte si le conteneur est monté sans passer par l'ouvreur.\n */\nexport const KT_DIALOG_CONFIG = new InjectionToken<Partial<KtDialogConfig>>('KT_DIALOG_CONFIG');\n\n/**\n * Enregistre les options maison du dialog pour l'application (ou un sous-arbre).\n * Complémentaire de {@link provideKtDialogDefaults}, qui porte la config du CDK : les deux\n * coexistent et ne se recouvrent pas.\n *\n * @example\n * ```ts\n * // app.config.ts — bouton de fermeture sur toutes les bottom-sheets\n * providers: [provideKtDialog({ sheetCloseButton: true })];\n * ```\n * @param config Options partielles fusionnées par-dessus `DEFAULT_KT_DIALOG_CONFIG`.\n * @returns Un `Provider` pour le token `KT_DIALOG_CONFIG`.\n */\nexport function provideKtDialog(config: Partial<KtDialogConfig>): Provider {\n return { provide: KT_DIALOG_CONFIG, useValue: config };\n}\n\n/**\n * Présentation du dialog, CHOISIE EXPLICITEMENT PAR LE DÉVELOPPEUR à l'ouverture (option\n * `presentation` de `injectKtDialogOpener`). Aucune bascule CSS automatique : le dev décide.\n * - `centered` : toujours centré (ex. confirmation) — DÉFAUT ;\n * - `fullscreen` : toujours plein écran (desktop compris) ;\n * - `sheet` : toujours bottom-sheet (desktop compris) ;\n * - `centered-fullscreen` : centré sur desktop, plein écran sur téléphone compact ;\n * - `centered-sheet` : centré sur desktop, bottom-sheet sur téléphone compact.\n * Les variantes `centered-*` sont résolues EN JS à l'ouverture (signal `KtViewport.isCompact()`), pas par le CSS —\n * la classe CSS finale est donc toujours une présentation CONCRÈTE (centered/fullscreen/sheet).\n */\nexport type KtDialogPresentation = 'centered' | 'fullscreen' | 'sheet' | 'centered-fullscreen' | 'centered-sheet';\n\n/** panelClass d'une présentation CONCRÈTE (sans variante responsive). */\nfunction concreteDialogPanelClass(p: 'centered' | 'fullscreen' | 'sheet'): string[] {\n if (p === 'fullscreen') return ['kt-dialog', 'kt-dialog--fullscreen'];\n if (p === 'sheet') return ['kt-dialog', 'kt-dialog--sheet'];\n return ['kt-dialog', 'kt-dialog--centered'];\n}\n\n/**\n * Résout une `KtDialogPresentation` (responsive comprise) en panelClass concret. Pour les variantes\n * `centered-*`, l'appelant fournit `compact` (= `KtViewport.isCompact()`, largeur seule) — centré\n * sur desktop, plein écran / sheet sur écran compact. Fonction pure (testable sans DOM).\n * Appelée par `injectKtDialogOpener` à chaque ouverture ; exportée pour un usage direct éventuel.\n *\n * @example\n * ```ts\n * resolveKtDialogPanelClass('sheet'); // ['kt-dialog', 'kt-dialog--sheet']\n * resolveKtDialogPanelClass('centered-sheet', true); // bottom-sheet sur écran compact\n * ```\n * @param presentation Présentation choisie par le dev (responsive comprise). Défaut `'centered'`.\n * @param compact `true` quand l'écran est compact (= `KtViewport.isCompact()`), pour résoudre les variantes `centered-*`. Défaut `false`.\n * @returns La liste des classes CSS de la présentation concrète résolue.\n */\nexport function resolveKtDialogPanelClass(presentation: KtDialogPresentation = 'centered', compact = false): string[] {\n if (presentation === 'centered' || presentation === 'fullscreen' || presentation === 'sheet') {\n return concreteDialogPanelClass(presentation);\n }\n if (presentation === 'centered-fullscreen') {\n return concreteDialogPanelClass(compact ? 'fullscreen' : 'centered');\n }\n return concreteDialogPanelClass(compact ? 'sheet' : 'centered'); // 'centered-sheet'\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n afterNextRender,\n isDevMode,\n signal,\n inject,\n PLATFORM_ID,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { CdkDialogContainer, DialogRef } from '@angular/cdk/dialog';\nimport { PortalModule } from '@angular/cdk/portal';\nimport { KtBodyScrollLock } from '@ktortu/aaa/cdk';\n\nimport { DEFAULT_KT_DIALOG_CONFIG, KT_DIALOG_CONFIG, KtDialogConfig } from './dialog-config';\n\n/** panelClass d'opt-out historique de la poignée, conservé comme repli DÉPRÉCIÉ (cf. `sheetHandle`). */\nconst LEGACY_NO_HANDLE_CLASS = 'kt-dialog--no-handle';\n\n@Component({\n selector: 'kt-dialog-container',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [PortalModule],\n host: {\n class: 'cdk-dialog-container kt-dialog-container',\n tabindex: '-1',\n '[attr.id]': '_config.id || null',\n '[attr.role]': '_config.role',\n '[attr.aria-modal]': '_config.ariaModal',\n '[attr.aria-labelledby]': '_config.ariaLabel ? null : ariaLabelledBy',\n '[attr.aria-label]': '_config.ariaLabel',\n '[attr.aria-describedby]': '_config.ariaDescribedBy || null',\n '[class.kt-dialog-container--sheet]': 'isSheet()',\n '[class.kt-dialog-container--closing]': 'isClosing()',\n },\n template: `\n <!-- Sheet scroll-snap (ADR-0005) : le conteneur est le SCROLLER, le spacer porte le snap\n « fermé » (un écran) et la carte (layout) le snap « ouvert ». -->\n @if (isSheet()) {\n <!-- Spacer = zone de tap-extérieur (ferme, comme un backdrop) ET surface de drag (scroll natif).\n Le conteneur capte le tactile (pointer-events auto) : le clic ne traverse plus vers le\n backdrop CDK, la fermeture au tap est donc portée ici (disableClose respecté). -->\n <div class=\"kt-dialog-container__spacer\" aria-hidden=\"true\" (click)=\"onScrimClick()\"></div>\n }\n <div class=\"kt-dialog-container__layout\" [class.kt-dialog-container__layout--closable]=\"showSheetClose()\">\n @if (showSheetClose()) {\n <!-- Bouton de fermeture AUTO-RENDU (opt-in 'sheetCloseButton'). Placé en TÊTE du document\n pour ouvrir l'ordre de tabulation, mais ancré en absolu sur la carte (cf. dialog.css) :\n il ne consomme pas de place dans la colonne. Aucun touch-action ici — le geste de\n glissement doit rester saisissable au travers du bouton (ADR-0005). -->\n <button\n type=\"button\"\n class=\"kt-dialog-container__sheet-close\"\n [attr.aria-label]=\"ktConfig.sheetCloseLabel\"\n (click)=\"onSheetCloseClick()\"\n >\n <span class=\"kt-dialog-container__sheet-close-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n @if (isSheet() && showSheetHandle()) {\n <!-- Poignée DÉCORATIVE auto-rendue : la sheet s'attrape partout (opt-out : 'sheetHandle'). -->\n <div class=\"kt-dialog-container__sheet-handle\" aria-hidden=\"true\"></div>\n }\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n `,\n})\nexport class KtDialogContainer extends CdkDialogContainer {\n private readonly dialogRef = inject(DialogRef);\n private readonly elementRef = inject(ElementRef);\n private readonly host = this.elementRef.nativeElement as HTMLElement;\n private readonly platformId = inject(PLATFORM_ID);\n private readonly destroyRef = inject(DestroyRef);\n private readonly bodyScrollLock = inject(KtBodyScrollLock);\n\n /** Options maison RÉSOLUES. `injectKtDialogOpener` refournit `KT_DIALOG_CONFIG` déjà résolu dans\n l'injecteur du conteneur : la fusion ci-dessous est alors un no-op. Elle reste indispensable\n quand le conteneur est monté sans l'ouvreur (`dialog.open` brut), où le token remonte à\n l'application et n'est que partiel. Un seul chemin de code, idempotent. */\n protected readonly ktConfig: Required<KtDialogConfig> = {\n ...DEFAULT_KT_DIALOG_CONFIG,\n ...(inject(KT_DIALOG_CONFIG, { optional: true }) ?? {}),\n };\n\n protected readonly isClosing = signal(false);\n\n // --- Sheet scroll-snap (ADR-0005) : détection du snap « fermé » + fermeture différée ---\n /** Armé quand l'ouverture a dépassé 50px : un repos à ~0 est alors forcément le snap « fermé ». */\n private sheetArmed = false;\n /** Fermeture réelle en attente du repos au snap « fermé » (sortie programmatique animée). */\n private pendingSheetClose: (() => void) | null = null;\n private sheetCloseTimer: ReturnType<typeof setTimeout> | undefined;\n\n /** Premier id de la file `aria-labelledby` exposée par `CdkDialogContainer`. Le membre\n `_ariaLabelledByQueue` est interne au CDK (préfixe `_`) : on l'encapsule ICI, gardé, pour que\n le binding de template ne lise jamais l'interne directement. Si une montée du CDK retire ou\n renomme ce membre, on dégrade proprement vers `null` au lieu de casser le rendu du conteneur. */\n protected get ariaLabelledBy(): string | null {\n const queue = (this as unknown as { _ariaLabelledByQueue?: readonly string[] })._ariaLabelledByQueue;\n return queue?.[0] ?? null;\n }\n\n constructor() {\n super();\n // CDK Dialog n'expose AUCUN hook « avant fermeture ». Pour jouer l'animation de SORTIE sur\n // TOUTE fermeture, on intercepte la méthode publique `close` de la réf : c'est le point de\n // passage unique. Échap et clic backdrop sont gérés NATIVEMENT par le CDK, qui appelle lui aussi\n // `dialogRef.close()` → ils transitent donc par cette interception (inutile de les réimplémenter).\n const originalClose = this.dialogRef.close.bind(this.dialogRef);\n this.dialogRef.close = (result?: unknown) => {\n this.animateAndClose(result, originalClose);\n };\n\n // L'ouvreur pré-réserve des ids titre/description ; les directives [ktDialogTitle]/[ktDialogDescription]\n // les adoptent. En leur absence, ces ids pointent dans le vide. Au rendu (navigateur) :\n // - aria-describedby orphelin → on RETIRE l'attribut (pas de description fournie) ;\n // - aucun nom accessible (ni titre ni aria-label) → warn dev (WCAG 4.1.2).\n afterNextRender(() => {\n if (this.isSheet()) this.initSheetGesture();\n\n const doc = this.host.ownerDocument;\n\n const describedBy = this.host.getAttribute('aria-describedby');\n if (describedBy && !doc.getElementById(describedBy)) {\n this.host.removeAttribute('aria-describedby');\n }\n\n if (!isDevMode()) return;\n const labelledBy = this.host.getAttribute('aria-labelledby');\n const hasName = !!this.host.getAttribute('aria-label') || (!!labelledBy && !!doc.getElementById(labelledBy));\n if (!hasName) {\n console.warn(\n '[ktDialog] dialog sans nom accessible : ajoutez un [ktDialogTitle] (ou `aria-label` via la config d’ouverture) — WCAG 4.1.2.',\n );\n }\n this.warnOnConfigMisuse();\n });\n\n // Repli de FOCUS INITIAL. La config par défaut de la lib vise un SÉLECTEUR\n // (`autoFocus: '[ktDialogFocusInitial]'`) ; quand aucun élément ne le porte, le CDK ne focalise\n // RIEN (son repli sur le conteneur n'existe que pour les modes `first-tabbable`/`dialog`/false).\n // Le focus reste alors sur le déclencheur, HORS du dialog, et Tab promène l'utilisateur dans la\n // page derrière. On rattrape ici sur le conteneur (tabindex -1) — jamais sur un bouton :\n // atterrir d'emblée sur « Fermer » est un anti-pattern lecteur d'écran (WCAG 2.4.3).\n // `preventScroll` : en présentation sheet le conteneur EST le scroller à snap, focaliser ne doit\n // pas perturber le scroll d'entrée en cours.\n this._focusTrapped.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n if (this.host.contains(this.host.ownerDocument.activeElement)) return;\n this.host.focus({ preventScroll: true });\n });\n }\n\n /** Garde-fous dev sur la config maison : usage hors sheet, double bouton de fermeture, opt-out\n déprécié de la poignée. On AVERTIT sans jamais corriger en silence — un masquage automatique\n dépendrait de l'ordre de rendu du portail et serait indébogable. */\n private warnOnConfigMisuse(): void {\n if (this.hasLegacyNoHandleClass()) {\n console.warn(\n `[ktDialog] panelClass '${LEGACY_NO_HANDLE_CLASS}' déprécié : utilisez l’option typée ` +\n '`sheetHandle: false` (à l’ouverture ou via provideKtDialog).',\n );\n }\n\n if (this.ktConfig.sheetCloseButton && !this.isSheet()) {\n console.warn(\n '[ktDialog] `sheetCloseButton` ne s’applique qu’à la présentation `sheet` et reste sans effet ' +\n 'ici : en centré / plein écran, posez le bouton dans un [ktDialogHeader].',\n );\n }\n\n // Collision visuelle recherchée : une croix posée en TÊTE (typiquement dans un [ktDialogHeader]),\n // qui doublerait celle du conteneur. Un [ktDialogClose] dans la barre d'ACTIONS est légitime\n // (« Annuler », ou une action qui ferme au passage) et ne collisionne pas : on l'exclut.\n // Heuristique volontairement partielle par ailleurs : elle voit la forme ATTRIBUT `ktDialogClose`,\n // pas la forme liée `[ktDialogClose]=\"x\"` (un binding de propriété ne reflète aucun attribut).\n const strayClose =\n this.showSheetClose() &&\n [...this.host.querySelectorAll('[ktDialogClose]')].some((el) => !el.closest('[ktDialogActions]'));\n if (strayClose) {\n console.warn(\n '[ktDialog] double bouton de fermeture : `sheetCloseButton` est actif alors que le contenu ' +\n 'porte déjà un [ktDialogClose] hors barre d’actions (en-tête ?). Gardez l’un OU l’autre.',\n );\n }\n }\n\n protected isSheet(): boolean {\n return this._config.panelClass?.includes('kt-dialog--sheet') ?? false;\n }\n\n /** panelClass d'opt-out historique de la poignée — repli DÉPRÉCIÉ, remplacé par `sheetHandle`. */\n private hasLegacyNoHandleClass(): boolean {\n return this._config.panelClass?.includes(LEGACY_NO_HANDLE_CLASS) ?? false;\n }\n\n /** Poignée décorative auto-rendue en présentation sheet (ADR-0005). Opt-out : option `sheetHandle`\n (le panelClass historique reste honoré, en déprécié). */\n protected showSheetHandle(): boolean {\n if (this.hasLegacyNoHandleClass()) return false;\n return this.ktConfig.sheetHandle;\n }\n\n /** Bouton de fermeture auto-rendu : opt-in `sheetCloseButton`, et UNIQUEMENT en présentation sheet\n (ailleurs, la croix se pose à la main dans un `[ktDialogHeader]` — cf. `KtDialogConfig`). */\n protected showSheetClose(): boolean {\n return this.isSheet() && this.ktConfig.sheetCloseButton;\n }\n\n /** Clic sur le bouton de fermeture auto-rendu. Ne consulte VOLONTAIREMENT pas `disableClose` :\n contrairement au tap-extérieur et à Échap (fermetures « par inadvertance » que `disableClose`\n protège), ce bouton est une sortie EXPLICITEMENT demandée par le dev via `sheetCloseButton` —\n le combiner à `disableClose` est le patron « une seule sortie contrôlée ». Le drapeau\n `isClosing` garde l'idempotence face à un geste de glissement simultané. */\n protected onSheetCloseClick(): void {\n if (this.isClosing()) return;\n this.dialogRef.close();\n }\n\n /** Tap sur le spacer (zone extérieure à la carte) = fermeture, façon backdrop. Le conteneur\n captant désormais le tactile (pointer-events auto, requis pour le drag iOS), le clic ne\n traverse plus vers le backdrop CDK : on porte donc ICI la fermeture au tap-extérieur, en\n respectant `disableClose` (comme le faisait le backdropClick natif). Un drag n'émet pas de\n `click` (le navigateur le supprime après un scroll) : seul un vrai tap ferme. */\n protected onScrimClick(): void {\n if (this._config.disableClose || this.isClosing()) return;\n this.dialogRef.close();\n }\n\n /** Sheet scroll-snap : écouteurs (détection du repos + garde molette) et scroll d'ENTRÉE\n programmatique vers le snap « ouvert ». Appelé au premier rendu, en présentation sheet. */\n private initSheetGesture(): void {\n const host = this.host;\n host.addEventListener('scroll', this.onSheetScroll);\n host.addEventListener('wheel', this.onSheetWheel, { passive: false });\n // Verrou de scroll du fond (compteur partagé) : sans lui, le fond défile SOUS la sheet et,\n // sur iOS, le geste de dismiss déclenche le pull-to-refresh de la page. La stratégie `block`\n // du CDK ne suffit pas ici (non appliquée / non fiable sur iOS) — même approche que le Select.\n this.bodyScrollLock.lock();\n this.destroyRef.onDestroy(() => {\n clearTimeout(this.sheetCloseTimer);\n host.removeEventListener('scroll', this.onSheetScroll);\n host.removeEventListener('wheel', this.onSheetWheel);\n this.bodyScrollLock.unlock();\n });\n host.scrollTop = 0;\n requestAnimationFrame(() => {\n host.scrollTo?.({\n top: host.scrollHeight - host.clientHeight,\n behavior: this.prefersReducedMotion() ? 'auto' : 'smooth',\n });\n });\n }\n\n private prefersReducedMotion(): boolean {\n return this.host.ownerDocument.defaultView?.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n }\n\n /** Détection du snap « fermé » par position de scroll (ni scrollsnapchange ni scrollend — cf.\n ADR-0005). Un repos à ~0 finalise la fermeture en attente, ou EST une fermeture par geste. */\n private readonly onSheetScroll = (): void => {\n const top = this.host.scrollTop;\n if (top > 50) this.sheetArmed = true;\n if (!this.sheetArmed || top > 1) return;\n const pending = this.pendingSheetClose;\n if (pending) {\n this.pendingSheetClose = null;\n clearTimeout(this.sheetCloseTimer);\n pending();\n return;\n }\n // Dismissal par geste : transite par le close intercepté (animation déjà « jouée » par le doigt).\n if (!this.isClosing()) this.dialogRef.close();\n };\n\n /** La molette ne ferme JAMAIS la sheet (pas de geste souris — ADR-0005) : seuls les scrollers\n INTERNES peuvent consommer, dans leurs bornes (générique : un dialog peut imbriquer\n plusieurs zones scrollables). */\n private readonly onSheetWheel = (event: WheelEvent): void => {\n let el = event.target as HTMLElement | null;\n while (el && el !== this.host) {\n if (el.scrollHeight > el.clientHeight + 1) {\n const canScrollDown = el.scrollTop + el.clientHeight < el.scrollHeight - 1;\n const canScrollUp = el.scrollTop > 0;\n if ((event.deltaY > 0 && canScrollDown) || (event.deltaY < 0 && canScrollUp)) return;\n }\n el = el.parentElement;\n }\n event.preventDefault();\n };\n\n private animateAndClose(result: unknown, originalCloseFn: (r?: unknown) => void): void {\n if (this.isClosing()) return;\n this.isClosing.set(true);\n\n if (!isPlatformBrowser(this.platformId)) {\n originalCloseFn(result);\n return;\n }\n\n // Sheet scroll-snap : la sortie est un scroll programmatique vers le snap « fermé » ;\n // onSheetScroll finalise au repos. Déjà en bas (geste abouti, jsdom, reduced-motion) :\n // fermeture immédiate. Fallback : timeout (scroll lisse interrompu).\n if (this.isSheet()) {\n if (this.host.scrollTop <= 1) {\n originalCloseFn(result);\n return;\n }\n this.sheetArmed = true;\n this.pendingSheetClose = () => originalCloseFn(result);\n this.host.scrollTo?.({ top: 0, behavior: this.prefersReducedMotion() ? 'auto' : 'smooth' });\n clearTimeout(this.sheetCloseTimer);\n this.sheetCloseTimer = setTimeout(() => {\n const pending = this.pendingSheetClose;\n this.pendingSheetClose = null;\n pending?.();\n }, 400);\n return;\n }\n\n // Récupérer la durée de transition configurée en CSS (ex: \"150ms\" ou \"0.2s\"). Vue lue via\n // ownerDocument.defaultView (pas le global `window`) : cohérent avec prefersReducedMotion() et\n // sûr indépendamment du garde de plateforme — si la vue manque, durée 0 → fermeture immédiate.\n const durationStr = this.host.ownerDocument.defaultView?.getComputedStyle(this.host).transitionDuration || '0s';\n const durationMs = parseFloat(durationStr) * (durationStr.includes('ms') ? 1 : 1000);\n\n if (durationMs === 0) {\n originalCloseFn(result);\n return;\n }\n\n // Écouter la fin de la transition (opacity pour le dialog classique, translate pour la sheet)\n const onTransitionEnd = (event: TransitionEvent) => {\n if (event.target === this.host && (event.propertyName === 'translate' || event.propertyName === 'opacity')) {\n this.host.removeEventListener('transitionend', onTransitionEnd);\n originalCloseFn(result);\n }\n };\n this.host.addEventListener('transitionend', onTransitionEnd);\n\n // Sécurité (au cas où la transition n'aboutirait pas)\n setTimeout(() => {\n this.host.removeEventListener('transitionend', onTransitionEnd);\n originalCloseFn(result);\n }, durationMs + 50);\n }\n}\n","import { DIALOG_DATA, Dialog, DialogConfig, DialogRef } from '@angular/cdk/dialog';\nimport { ComponentType } from '@angular/cdk/portal';\nimport { ViewContainerRef, inject } from '@angular/core';\nimport { KtViewport, KtIdGenerator } from '@ktortu/aaa/cdk';\n\nimport {\n DEFAULT_KT_DIALOG_CONFIG,\n KT_DIALOG_AAA_DEFAULTS,\n KT_DIALOG_CONFIG,\n KtDialogConfig,\n KtDialogPresentation,\n resolveKtDialogPanelClass,\n} from './dialog-config';\nimport { KtDialogContainer } from './dialog-container';\n\n/**\n * Config d'ouverture sans le champ `data` (fourni séparément, typé), enrichie de `presentation` et\n * des options maison de {@link KtDialogConfig} (surcharge par ouverture de `KT_DIALOG_CONFIG`).\n */\nexport type KtDialogOpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> &\n Partial<KtDialogConfig> & {\n /** Présentation du dialog (cf. `KtDialogPresentation`) — choisie par le dev. Résolue à CHAQUE\n ouverture : les variantes responsive lisent le signal d'écran compact. Défaut : `'centered'`.\n Combinée à un éventuel `panelClass` additionnel. */\n presentation?: KtDialogPresentation;\n };\n\n/** Retire les clés à `undefined` : une option NON fournie à l'ouverture ne doit pas écraser\n la valeur du token global (une clé absente et une clé à `undefined` sont équivalentes ici). */\nfunction definedOnly<T extends object>(source: T): Partial<T> {\n return Object.fromEntries(Object.entries(source).filter(([, value]) => value !== undefined)) as Partial<T>;\n}\n\n/**\n * ⚠️ API BAS-NIVEAU — n'utilisez PAS ceci par défaut. Pour implémenter un dialog, passez par\n * {@link defineKtDialog} puis son `injectOpener(...)` : il fixe données + résultat une seule fois et\n * les partage avec `injectData()`/`injectRef()`. N'appelez `injectKtDialogOpener` directement que\n * dans un cas avancé où le contrat groupé de `defineKtDialog` ne convient pas.\n *\n * Crée un ouvreur de dialog typé en contexte d'injection : le contrat (composant + type de `data` +\n * type de résultat + config par défaut) est figé via les génériques `<Composant, Data, Résultat>`\n * (qu'il faut répéter — d'où la préférence pour `defineKtDialog`). L'ouvreur renvoyé est une closure\n * appelable n'importe où dans la classe, 100 % typée, sans nouvel `inject`.\n *\n * Conserve le `ViewContainerRef` du contexte appelant (le dialog hérite donc de l'arbre logique\n * d'injection), reste testable (TestBed fournit `Dialog`) et sans état global (SSR-safe).\n *\n * @param component Composant à monter dans le dialog.\n * @param baseConfig Config d'ouverture par défaut (sans `data`), enrichie de `presentation` ; fusionnée à chaque ouverture.\n * @returns Une closure d'ouverture typée : `() => DialogRef` (sans data) ou `(data, config?) => DialogRef` (avec data).\n * @see {@link defineKtDialog} — la façon recommandée d'obtenir cet ouvreur.\n */\n// Surcharge sans data (D = void) : l'ouvreur ne prend aucun argument (la config par défaut suffit).\nexport function injectKtDialogOpener<C, R = unknown>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<void, R, C>,\n): () => DialogRef<R, C>;\n// Surcharge avec data typée.\nexport function injectKtDialogOpener<C, D, R = unknown>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<D, R, C>,\n): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;\n\nexport function injectKtDialogOpener<C, D, R = unknown>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<D, R, C>,\n) {\n const dialog = inject(Dialog);\n const viewport = inject(KtViewport);\n // Optionnel : hors d'un arbre de vue (ex. service root), il n'y a pas de ViewContainerRef.\n const viewContainerRef = inject(ViewContainerRef, { optional: true }) ?? undefined;\n const idGen = inject(KtIdGenerator);\n // Options maison au niveau application (partielles) : socle de la cascade résolue ci-dessous.\n const appKtConfig = inject(KT_DIALOG_CONFIG, { optional: true });\n\n return (data?: D, config?: KtDialogOpenerConfig<D, R, C>): DialogRef<R, C> => {\n // La présentation (choisie par le dev) est résolue ICI, à l'ouverture : les variantes\n // responsive lisent le signal d'écran compact. Le panelClass final = présentation concrète + extras.\n const { presentation, panelClass, sheetCloseButton, sheetCloseLabel, sheetHandle, ...rest } = {\n ...baseConfig,\n ...config,\n };\n const extra = panelClass ? (Array.isArray(panelClass) ? panelClass : [panelClass]) : [];\n\n // Cascade des options maison, résolue UNE SEULE FOIS ici (ADR-0003) : défaut → token\n // application → option d'ouverture. Le conteneur ne relit JAMAIS le token de son côté ; il\n // reçoit cette valeur déjà résolue par le canal `container.providers` du CDK (les\n // `providers` de la config générale, eux, n'atteignent QUE le portail de contenu).\n const ktConfig: Required<KtDialogConfig> = {\n ...DEFAULT_KT_DIALOG_CONFIG,\n ...definedOnly(appKtConfig ?? {}),\n ...definedOnly({ sheetCloseButton, sheetCloseLabel, sheetHandle }),\n };\n // Dédoublonné : une classe déjà fournie par la présentation (ex. `kt-dialog`) et repassée\n // en `panelClass` par le consommateur ne doit pas apparaître deux fois.\n const merged = [...new Set([...resolveKtDialogPanelClass(presentation, viewport.isCompact()), ...extra])];\n\n const uid = idGen.generateId('dialog');\n const titleId = `kt-dialog-title-${uid}`;\n const descId = `kt-dialog-desc-${uid}`;\n\n return dialog.open<R, D, C>(component, {\n // Plancher a11y garanti par l'opener (ariaModal/role/restoreFocus/autoFocus…), même si le\n // consommateur n'a pas câblé provideKtDialogDefaults(). `...rest` (config par appel) prime.\n ...KT_DIALOG_AAA_DEFAULTS,\n viewContainerRef,\n // Canal TYPÉ vers le conteneur : ces providers-là atterrissent bien dans SON injecteur.\n container: {\n type: KtDialogContainer,\n providers: () => [{ provide: KT_DIALOG_CONFIG, useValue: ktConfig }],\n },\n ariaLabelledBy: titleId,\n ariaDescribedBy: descId,\n ...rest,\n panelClass: merged,\n data,\n } as DialogConfig<D, DialogRef<R, C>>);\n };\n}\n\n/**\n * Contrat de dialog typé renvoyé par `defineKtDialog` : les trois accès (données, référence,\n * ouvreur) dérivent des MÊMES génériques `D`/`R`, déclarés une seule fois — impossible donc que\n * le type des données ou du résultat diverge entre le composant et l'ouvreur.\n *\n * @template D Type des données injectées (`void` si aucune).\n * @template R Type du résultat renvoyé à la fermeture.\n */\nexport interface KtDialogContract<D, R> {\n /** Données injectées (à appeler en contexte d'injection DANS le composant de dialog). */\n injectData(): D;\n /** Référence typée du dialog : `close()` n'accepte QUE le résultat `R` (sûreté de fermeture). */\n injectRef(): DialogRef<R>;\n /** Ouvreur typé CO-LOCALISÉ pour ce composant (cf. `injectKtDialogOpener`). */\n injectOpener<C>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<D, R, C>,\n ): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;\n}\n\n/**\n * ✅ STRATÉGIE PAR DÉFAUT pour implémenter un dialog `@ktortu/aaa`. Toute nouvelle dialog DOIT être\n * écrite ainsi. N'utilisez `injectKtDialogData` / `injectKtDialogOpener` directement QUE dans un cas\n * avancé non couvert ici.\n *\n * Définit le contrat typé du dialog (données `D` + résultat `R`) en UN SEUL endroit, co-localisé avec\n * le composant. Renvoie trois accès liés aux mêmes types — `injectData()` (données), `injectRef()`\n * (référence dont `close()` n'accepte que `R`) et `injectOpener()` (ouvreur) — d'où l'impossibilité\n * d'une divergence de type entre composant et ouvreur.\n *\n * Recette à copier pour CHAQUE dialog :\n * 1. `interface XxxData { … }` (ou `void` si aucune donnée) ;\n * 2. `const xxxDialog = defineKtDialog<XxxData, Résultat>();` ;\n * 3. dans le composant : `injectData()` pour lire la donnée, `injectRef()` pour fermer avec résultat ;\n * 4. `export const injectXxxDialog = () => xxxDialog.injectOpener(XxxDialog);` (co-localisé) ;\n * 5. côté consommateur : `private readonly openXxx = injectXxxDialog();` (initialiseur de champ).\n *\n * Convention de fermeture : annuler / fermer SANS résultat via la directive `[ktDialogClose]`\n * (→ `undefined`) ; renvoyer un résultat via `ref.close(résultat)` (typé `R`). Passer un résultat par\n * `[ktDialogClose]=\"x\"` reste possible mais N'EST PAS typé (la directive ignore `R`).\n *\n * @example\n * ```ts\n * // ─── rename-dialog.ts : composant + contrat + ouvreur, co-localisés ───\n * export interface RenameData { currentName: string; }\n *\n * const renameDialog = defineKtDialog<RenameData, string>(); // D et R déclarés UNE seule fois\n *\n * @Component({\n * imports: [KtButton, KtDialogImports],\n * template: `\n * <h2 ktDialogTitle>Renommer</h2>\n * <footer ktDialogActions>\n * <button ktButton ktDialogClose>Annuler</button> // ferme sans résultat (undefined)\n * <button ktButton (click)=\"submit()\">Renommer</button> // ferme avec résultat typé\n * </footer>`,\n * })\n * export class RenameDialog {\n * protected readonly data = renameDialog.injectData(); // RenameData garanti\n * private readonly ref = renameDialog.injectRef(); // DialogRef<string>\n * protected submit() { this.ref.close('nouveau-nom'); } // close(result?: string) — typé\n * }\n *\n * export const injectRenameDialog = () => renameDialog.injectOpener(RenameDialog);\n *\n * // ─── consommateur ───\n * private readonly openRename = injectRenameDialog(); // initialiseur de champ = contexte d'injection\n * rename() {\n * this.openRename({ currentName: 'X' }).closed.subscribe(name => {\n * // name: string | undefined\n * });\n * }\n * ```\n */\nexport function defineKtDialog<D = void, R = unknown>(): KtDialogContract<D, R> {\n return {\n injectData: () => inject<D>(DIALOG_DATA),\n injectRef: () => inject(DialogRef) as DialogRef<R>,\n injectOpener: <C>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<D, R, C>) =>\n injectKtDialogOpener<C, D, R>(component, baseConfig) as (\n data: D,\n config?: KtDialogOpenerConfig<D, R, C>,\n ) => DialogRef<R, C>,\n };\n}\n","import { KtDialogTitle } from './dialog-title.directive';\nimport { KtDialogDescription } from './dialog-description.directive';\nimport { KtDialogClose } from './dialog-close.directive';\nimport {\n KtDialogHeader,\n KtDialogContent,\n KtDialogActions,\n KtDialogFocusInitial,\n KtDialogSheetHandle,\n} from './dialog-structure';\n\n/**\n * Import ergonomique de toute la famille dialog en une fois :\n * `imports: [KtDialogImports]` au lieu d'énumérer chaque directive structurelle.\n */\nexport const KtDialogImports = [\n KtDialogHeader,\n KtDialogTitle,\n KtDialogDescription,\n KtDialogContent,\n KtDialogActions,\n KtDialogClose,\n KtDialogFocusInitial,\n KtDialogSheetHandle,\n] as const;\n","import { ChangeDetectionStrategy, Component, Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { DialogRef } from '@angular/cdk/dialog';\nimport { KtButton, KtButtonColor } from '@ktortu/aaa/button';\n\nimport { defineKtDialog } from './dialog-opener';\nimport { KtDialogImports } from './dialog-imports';\n\n/** Option de variante visuelle pour le dialogue d'alerte. */\nexport type KtAlertDialogVariant = 'neutral' | 'info' | 'success' | 'warning' | 'error';\n\n/**\n * Options pour l'ouverture d'une boîte de dialogue d'alerte.\n */\nexport interface KtAlertOptions {\n /** Libellé du bouton de fermeture. Par défaut: 'Fermer'. */\n closeLabel?: string;\n /** Variante sémantique (apparence : icône + accent). Par défaut: 'neutral'. */\n variant?: KtAlertDialogVariant;\n}\n\n/**\n * Configuration pour l'ouverture d'une boîte de dialogue d'alerte simple.\n */\nexport interface KtAlertData {\n /** Titre de la boîte de dialogue. */\n title: string;\n /**\n * Message explicatif. Peut être une simple chaîne de caractères\n * ou un tableau de chaînes pour composer plusieurs paragraphes.\n * Supporte le HTML (balises sécurisées) désinfecté à l'affichage.\n */\n message: string | string[];\n /** Libellé du bouton de fermeture. Par défaut: 'Fermer'. */\n closeLabel?: string;\n /** Variante sémantique (apparence : icône + accent). Par défaut: 'neutral'. */\n variant?: KtAlertDialogVariant;\n}\n\nconst alertDialog = defineKtDialog<KtAlertData, void>();\n\n/**\n * Composant interne d'alerte générique.\n * Affiche un titre, un message (simple ou multiligne HTML) et un bouton de fermeture.\n */\n@Component({\n selector: 'kt-alert-dialog',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [KtButton, KtDialogImports],\n host: {\n class: 'kt-alert-dialog',\n '[attr.data-variant]': \"data.variant || 'neutral'\",\n },\n template: `\n <h2 ktDialogTitle>\n @if (data.variant && data.variant !== 'neutral') {\n <span class=\"kt-alert-dialog__icon\" aria-hidden=\"true\"></span>\n }\n <span>{{ data.title }}</span>\n </h2>\n <div ktDialogDescription>\n @if (isMessageArray()) {\n @for (line of messageArray(); track line) {\n <p [innerHTML]=\"line\"></p>\n }\n } @else {\n <p [innerHTML]=\"messageString()\"></p>\n }\n </div>\n <footer ktDialogActions>\n <button ktButton ktDialogFocusInitial ktDialogClose>\n {{ data.closeLabel || 'Fermer' }}\n </button>\n </footer>\n `,\n})\nexport class KtAlertDialog {\n protected readonly data = alertDialog.injectData();\n\n protected isMessageArray(): boolean {\n return Array.isArray(this.data.message);\n }\n\n protected messageArray(): string[] {\n return Array.isArray(this.data.message) ? this.data.message : [];\n }\n\n protected messageString(): string {\n return typeof this.data.message === 'string' ? this.data.message : '';\n }\n}\n\n/** Ouvreur co-localisé officiel pour l'alerte. Utilise la présentation responsive par défaut. */\nexport const injectAlertDialog = () => alertDialog.injectOpener(KtAlertDialog, { presentation: 'centered-sheet' });\n\n/** Option de variante visuelle pour le bouton d'action principal. */\nexport type KtDialogColor = KtButtonColor;\n\n/**\n * Configuration pour l'ouverture d'une boîte de dialogue de confirmation binaire (Oui/Non).\n */\nexport interface KtConfirmConfig {\n /** Titre de la boîte de dialogue. */\n title: string;\n /**\n * Message explicatif. Peut être une simple chaîne ou un tableau\n * de chaînes de caractères pour composer plusieurs paragraphes.\n * Supporte le HTML désinfecté à l'affichage.\n */\n message: string | string[];\n /** Libellé du bouton de validation. Par défaut: 'Oui'. */\n confirmLabel?: string;\n /** Libellé du bouton de rejet. Par défaut: 'Non'. */\n rejectLabel?: string;\n /**\n * Variante de couleur du bouton principal.\n * Utile pour marquer une action destructive ou critique.\n * Par défaut: 'primary'.\n */\n color?: KtDialogColor;\n}\n\n/**\n * Configuration pour une décision ternaire (inclut obligatoirement un bouton d'annulation).\n */\nexport interface KtDecideConfig extends KtConfirmConfig {\n /** Libellé du bouton d'annulation. Requis. */\n cancelLabel: string;\n}\n\n/**\n * Type de retour d'une boîte de dialogue de confirmation ou de décision.\n * - 'confirm' : Choix de validation (Oui / Enregistrer)\n * - 'reject' : Choix de rejet (Non / Ignorer)\n * - 'cancel' : Choix d'annulation (Annuler)\n */\nexport type KtConfirmResult = 'confirm' | 'reject' | 'cancel';\n\nconst confirmDialog = defineKtDialog<KtDecideConfig, KtConfirmResult>();\n\n/**\n * Composant interne de confirmation/décision générique.\n * Supporte le mode binaire (Oui/Non) et le mode ternaire (Oui/Non/Annuler).\n * Gère l'empilement vertical des boutons et les messages HTML multi-lignes.\n */\n@Component({\n selector: 'kt-confirm-dialog',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [KtButton, KtDialogImports],\n template: `\n <h2 ktDialogTitle>{{ data.title }}</h2>\n <div ktDialogDescription>\n @if (isMessageArray()) {\n @for (line of messageArray(); track line) {\n <p [innerHTML]=\"line\"></p>\n }\n } @else {\n <p [innerHTML]=\"messageString()\"></p>\n }\n </div>\n <footer ktDialogActions>\n @if (data.cancelLabel) {\n <button ktButton mode=\"text\" ktDialogFocusInitial (click)=\"cancel()\">\n {{ data.cancelLabel }}\n </button>\n <button ktButton mode=\"text\" (click)=\"reject()\">\n {{ data.rejectLabel || 'Non' }}\n </button>\n } @else {\n <button ktButton mode=\"text\" ktDialogFocusInitial (click)=\"reject()\">\n {{ data.rejectLabel || 'Non' }}\n </button>\n }\n <button ktButton [color]=\"data.color || 'primary'\" (click)=\"confirm()\">\n {{ data.confirmLabel || 'Oui' }}\n </button>\n </footer>\n `,\n})\nexport class KtConfirmDialog {\n protected readonly data = confirmDialog.injectData();\n private readonly ref = confirmDialog.injectRef();\n\n protected isMessageArray(): boolean {\n return Array.isArray(this.data.message);\n }\n\n protected messageArray(): string[] {\n return Array.isArray(this.data.message) ? this.data.message : [];\n }\n\n protected messageString(): string {\n return typeof this.data.message === 'string' ? this.data.message : '';\n }\n\n protected confirm(): void {\n this.ref.close('confirm');\n }\n\n protected reject(): void {\n this.ref.close('reject');\n }\n\n protected cancel(): void {\n this.ref.close('cancel');\n }\n}\n\n/** Ouvreur co-localisé officiel pour la confirmation/décision. Utilise la présentation responsive par défaut. */\nexport const injectConfirmDialog = () =>\n confirmDialog.injectOpener(KtConfirmDialog, { presentation: 'centered-sheet' });\n\n/**\n * Service d'aide global pour l'ouverture simplifiée de boîtes de dialogue d'alerte et de confirmation.\n * S'appuie sur les ouvreurs de dialogues officiels co-localisés.\n * Propose une présentation adaptative (centrée sur grand écran, bottom-sheet sur mobile).\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class KtQuickDialog {\n private readonly openAlert = injectAlertDialog();\n private readonly openConfirm = injectConfirmDialog();\n\n /**\n * Ouvre une boîte de dialogue d'alerte simple.\n *\n * @param title Titre de l'alerte.\n * @param message Message d'explication (string simple ou tableau de strings pour du multi-lignes HTML).\n * @param closeLabel Libellé du bouton de fermeture.\n * @returns La référence DialogRef de la modale ouverte.\n */\n alert(title: string, message: string | string[], closeLabel?: string): DialogRef<void, KtAlertDialog>;\n /**\n * Ouvre une boîte de dialogue d'alerte simple.\n *\n * @param title Titre de l'alerte.\n * @param message Message d'explication (string simple ou tableau de strings pour du multi-lignes HTML).\n * @param options Options d'ouverture de l'alerte (libellé de fermeture, variante).\n * @returns La référence DialogRef de la modale ouverte.\n */\n alert(title: string, message: string | string[], options?: KtAlertOptions): DialogRef<void, KtAlertDialog>;\n alert(\n title: string,\n message: string | string[],\n closeLabelOrOptions?: string | KtAlertOptions,\n ): DialogRef<void, KtAlertDialog> {\n const data: KtAlertData = { title, message };\n\n if (typeof closeLabelOrOptions === 'string') {\n data.closeLabel = closeLabelOrOptions;\n } else if (closeLabelOrOptions) {\n data.closeLabel = closeLabelOrOptions.closeLabel;\n data.variant = closeLabelOrOptions.variant;\n }\n\n return this.openAlert(data);\n }\n\n /**\n * Ouvre une boîte de dialogue de confirmation binaire (Oui/Non).\n *\n * @param config Options de configuration (titre, message, libellés de boutons, couleur).\n * @returns Un Observable émettant true si l'utilisateur valide (Oui),\n * false s'il rejette (Non), et undefined si la boîte est fermée en cliquant en dehors ou via Échap.\n */\n confirm(config: KtConfirmConfig): Observable<boolean | undefined> {\n const dialogRef = this.openConfirm({\n ...config,\n cancelLabel: '', // Pas de bouton d'annulation en mode binaire\n });\n\n return dialogRef.closed.pipe(\n map((result) => {\n if (result === 'confirm') return true;\n if (result === 'reject') return false;\n return undefined;\n }),\n );\n }\n\n /**\n * Ouvre une boîte de dialogue de décision ternaire (Oui/Non/Annuler).\n *\n * @param config Options de configuration (titre, message, libellés de boutons dont cancelLabel obligatoire).\n * @returns Un Observable émettant 'confirm', 'reject', 'cancel' ou undefined si fermeture externe.\n */\n decide(config: KtDecideConfig): Observable<KtConfirmResult | undefined> {\n const dialogRef = this.openConfirm(config);\n return dialogRef.closed;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.KtDialogTitle","i2.KtDialogDescription","i3.KtDialogActions","i4.KtDialogClose","i3.KtDialogFocusInitial"],"mappings":"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"}
1
+ {"version":3,"file":"ktortu-aaa-dialog.mjs","sources":["../../../../projects/ktortu/aaa/dialog/dialog-title.directive.ts","../../../../projects/ktortu/aaa/dialog/dialog-description.directive.ts","../../../../projects/ktortu/aaa/dialog/dialog-close.directive.ts","../../../../projects/ktortu/aaa/dialog/dialog-structure.ts","../../../../projects/ktortu/aaa/dialog/dialog-config.ts","../../../../projects/ktortu/aaa/dialog/dialog-container.ts","../../../../projects/ktortu/aaa/dialog/dialog-opener.ts","../../../../projects/ktortu/aaa/dialog/dialog-imports.ts","../../../../projects/ktortu/aaa/dialog/dialog-helpers.ts","../../../../projects/ktortu/aaa/dialog/ktortu-aaa-dialog.ts"],"sourcesContent":["import { DialogRef } from '@angular/cdk/dialog';\nimport { Directive, ElementRef, Renderer2, afterNextRender, inject } from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\n/**\n * À poser sur le titre VISIBLE (idéalement un `<h2>`) du contenu d'un CDK Dialog.\n * Câble `aria-labelledby` du conteneur de dialogue.\n *\n * Pourquoi écrire l'attribut directement (Renderer2) plutôt que seulement `_addAriaLabelledBy` :\n * sous change detection ZONELESS (cas par défaut moderne), le `markForCheck()` interne du\n * conteneur ne rafraîchit pas ses host bindings à l'ouverture, donc l'attribut n'apparaîtrait\n * jamais. On écrit donc l'attribut nous-mêmes (fiable, indépendant de la CD) ET on alimente la\n * file CDK pour rester cohérent si un cycle de CD survient ensuite.\n *\n * @example\n * ```html\n * <h2 ktDialogTitle>Renommer le fichier</h2>\n * ```\n */\n@Directive({\n selector: '[ktDialogTitle]',\n host: { '[id]': 'id' },\n})\nexport class KtDialogTitle {\n private readonly dialogRef = inject<DialogRef<unknown>>(DialogRef, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly renderer = inject(Renderer2);\n private readonly idGen = inject(KtIdGenerator);\n\n /**\n * Id de l'hôte câblé en `aria-labelledby` : préserve un id fourni par le consommateur, sinon en génère un.\n * @default `host.id` ?? `dialogRef.config.ariaLabelledBy` ?? `kt-dialog-title-<généré>`\n */\n readonly id =\n this.host.id || this.dialogRef?.config.ariaLabelledBy || `kt-dialog-title-${this.idGen.generateId('dialog')}`;\n\n constructor() {\n const preConfigured = this.dialogRef?.config.ariaLabelledBy;\n if (!preConfigured) {\n if (this.dialogRef) {\n this.dialogRef.config.ariaLabelledBy = this.id;\n }\n afterNextRender(() => {\n const container = this.host.closest('.cdk-dialog-container');\n if (container) this.renderer.setAttribute(container, 'aria-labelledby', this.id);\n });\n }\n }\n}\n","import { DialogRef } from '@angular/cdk/dialog';\nimport { Directive, ElementRef, OnDestroy, OnInit, Renderer2, afterNextRender, inject } from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\n/**\n * À poser sur le paragraphe descriptif COURT du dialog : câble `aria-describedby` du conteneur\n * (texte lu par le lecteur d'écran juste après le titre, à l'ouverture).\n *\n * ⚠️ Ne JAMAIS appliquer sur un formulaire ou un long contenu : `aria-describedby` concatène\n * tout le texte du nœud et serait lu d'un bloc à l'ouverture. Réserver à une phrase de contexte.\n *\n * Écriture directe de l'attribut (Renderer2) pour la même raison que `ktDialogTitle` :\n * fiabilité sous change detection zoneless. La config est tenue à jour pour cohérence CDK.\n *\n * @example\n * ```html\n * <p ktDialogDescription>Cette action est définitive.</p>\n * ```\n */\n@Directive({\n selector: '[ktDialogDescription]',\n host: { '[id]': 'id' },\n})\nexport class KtDialogDescription implements OnInit, OnDestroy {\n private readonly dialogRef = inject<DialogRef<unknown>>(DialogRef, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly renderer = inject(Renderer2);\n private readonly idGen = inject(KtIdGenerator);\n\n /**\n * Id de l'hôte câblé en `aria-describedby` : préserve un id fourni par le consommateur, sinon en génère un.\n * @default `host.id` ?? `dialogRef.config.ariaDescribedBy` ?? `kt-dialog-desc-<généré>`\n */\n readonly id =\n this.host.id || this.dialogRef?.config.ariaDescribedBy || `kt-dialog-desc-${this.idGen.generateId('dialog')}`;\n\n constructor() {\n const preConfigured = this.dialogRef?.config.ariaDescribedBy;\n if (!preConfigured) {\n if (this.dialogRef) {\n this.dialogRef.config.ariaDescribedBy = this.id;\n }\n afterNextRender(() => {\n const container = this.host.closest('.cdk-dialog-container');\n if (container) this.renderer.setAttribute(container, 'aria-describedby', this.id);\n });\n }\n }\n\n ngOnInit(): void {\n // Asymétrie ASSUMÉE avec `ktDialogTitle` : la description peut porter un `id` d'hôte fourni par\n // le consommateur ; on aligne alors `config.ariaDescribedBy` dessus (le host binding live du\n // conteneur reflète la valeur). Un titre est posé une fois et n'a pas ce besoin.\n if (this.dialogRef && this.dialogRef.config.ariaDescribedBy !== this.id) {\n this.dialogRef.config.ariaDescribedBy = this.id;\n }\n }\n\n ngOnDestroy(): void {\n if (this.dialogRef?.config.ariaDescribedBy === this.id) {\n this.dialogRef.config.ariaDescribedBy = null;\n }\n const container = this.host.closest('.cdk-dialog-container');\n if (container && container.getAttribute('aria-describedby') === this.id) {\n this.renderer.removeAttribute(container, 'aria-describedby');\n }\n }\n}\n","import { DialogRef } from '@angular/cdk/dialog';\nimport { Directive, ElementRef, afterNextRender, inject, input, isDevMode } from '@angular/core';\n\n/**\n * Ferme le CDK Dialog au clic, avec un résultat optionnel renvoyé à l'ouvreur via\n * `DialogRef.close(result)`. Se compose avec `[ktButton]` sur le même `<button>`.\n *\n * Réservé au DISMISS simple (Annuler / Fermer). Pour valider un formulaire, injectez\n * `DialogRef` dans votre composant et appelez `close(valeur)` après validation.\n *\n * @example\n * ```html\n * <button ktButton ktDialogClose>Annuler</button>\n * <button ktButton [ktDialogClose]=\"'confirm'\">Confirmer</button>\n * ```\n */\n@Directive({\n selector: '[ktDialogClose]',\n host: {\n '[attr.type]': 'buttonType',\n '(click)': 'close()',\n },\n})\nexport class KtDialogClose {\n private readonly dialogRef = inject<DialogRef<unknown>>(DialogRef, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n /**\n * Valeur renvoyée à l'ouvreur via `DialogRef.close(result)`. Liée par l'alias `ktDialogClose`\n * (= nom du sélecteur), d'où l'usage `[ktDialogClose]=\"'confirm'\"`. @default undefined\n */\n readonly dialogResult = input<unknown>(undefined, { alias: 'ktDialogClose' });\n\n // Force type=\"button\" sur un <button> (évite le submit implicite dans un <form>).\n protected readonly buttonType = this.host.tagName === 'BUTTON' ? 'button' : null;\n\n constructor() {\n // Garde-fou a11y (dev) : un bouton de fermeture doit avoir un nom accessible (WCAG 4.1.2).\n afterNextRender(() => {\n if (!isDevMode()) return;\n\n const named =\n (this.host.textContent ?? '').trim().length > 0 ||\n this.host.hasAttribute('aria-label') ||\n this.host.hasAttribute('aria-labelledby');\n if (!named) {\n console.warn(\n '[ktDialogClose] Bouton de fermeture sans nom accessible (WCAG 4.1.2) : ' +\n 'ajoutez du texte visible, aria-label ou aria-labelledby.',\n );\n }\n });\n }\n\n protected close(): void {\n this.dialogRef?.close(this.dialogResult());\n }\n}\n","import { Directive, isDevMode } from '@angular/core';\n\n/**\n * En-tête RICHE et OPTIONNEL du dialog : rangée flex pour composer une icône, le titre et/ou un\n * bouton de fermeture. Marqueur structurel sans logique — la mise en forme (flex, padding de\n * région, reset du padding du [ktDialogTitle] qu'il enveloppe) vit dans `dialog.css`.\n *\n * Sépare le LAYOUT (cette région) de l'ÉTIQUETTE ACCESSIBLE ([ktDialogTitle], qui garde\n * aria-labelledby). En usage simple — titre nu sans header — [ktDialogTitle] conserve son propre\n * padding : ce header n'est à utiliser que pour les en-têtes composés (icône, close top-right…).\n *\n * ⚠️ Ne rend RIEN par lui-même — pas de bouton de fermeture implicite : c'est vous qui posez la\n * croix (cf. exemple). En présentation `sheet`, l'option `sheetCloseButton` en rend une\n * automatiquement, hors flux ; les deux ensemble feraient doublon (le conteneur avertit en dev).\n *\n * @example\n * ```html\n * <header ktDialogHeader>\n * <h2 ktDialogTitle>Titre</h2>\n * <button ktButton ktDialogClose aria-label=\"Fermer\">✕</button>\n * </header>\n * ```\n */\n@Directive({ selector: '[ktDialogHeader]' })\nexport class KtDialogHeader {}\n\n/**\n * Zone de contenu du dialog. Marqueur structurel sans logique : la mise en forme\n * (rythme vertical) vit dans `dialog.css` via le sélecteur `[ktDialogContent]`.\n *\n * @example\n * ```html\n * <div ktDialogContent>…</div>\n * ```\n */\n@Directive({ selector: '[ktDialogContent]' })\nexport class KtDialogContent {}\n\n/**\n * Barre d'actions du dialog (rangée de boutons). Marqueur structurel sans logique :\n * la mise en forme (flex, gap, sticky bas pour le Reflow AAA) vit dans `dialog.css`\n * via le sélecteur `[ktDialogActions]`.\n *\n * @example\n * ```html\n * <footer ktDialogActions>\n * <button ktButton ktDialogClose>Annuler</button>\n * <button ktButton [ktDialogClose]=\"'ok'\">Valider</button>\n * </footer>\n * ```\n */\n@Directive({ selector: '[ktDialogActions]' })\nexport class KtDialogActions {}\n\n/**\n * Marque l'élément à focaliser à l'ouverture. À coupler avec la config CDK\n * `autoFocus: '[ktDialogFocusInitial]'` (incluse dans `provideKtDialogDefaults`).\n * Permet d'éviter que le focus initial tombe sur une action destructrice.\n *\n * @example\n * ```html\n * <input ktDialogFocusInitial type=\"text\" />\n * ```\n */\n@Directive({ selector: '[ktDialogFocusInitial]' })\nexport class KtDialogFocusInitial {}\n\n/**\n * @deprecated ADR-0005 — la poignée est désormais RENDUE AUTOMATIQUEMENT par `KtDialogContainer`\n * en présentation `sheet` (opt-out : option typée `sheetHandle: false`), et le\n * drag-to-dismiss s'attrape sur TOUTE la surface de la sheet (scroll-snap natif). Cette\n * directive est INERTE et son hôte est masqué (évite une double poignée) : retirez-la de vos\n * templates. Sera supprimée dans une prochaine version majeure.\n */\n@Directive({\n selector: '[ktDialogSheetHandle]',\n host: {\n 'aria-hidden': 'true',\n style: 'display: none',\n },\n})\nexport class KtDialogSheetHandle {\n constructor() {\n if (isDevMode()) {\n console.warn(\n '[ktDialogSheetHandle] déprécié (ADR-0005) : la poignée est rendue automatiquement en ' +\n 'présentation sheet et le drag s’attrape partout — retirez la directive de votre template.',\n );\n }\n }\n}\n","import { DEFAULT_DIALOG_CONFIG, DialogConfig } from '@angular/cdk/dialog';\nimport { InjectionToken, Provider } from '@angular/core';\n\n/**\n * Valeurs par défaut orientées AAA pour `@angular/cdk/dialog`.\n * - `ariaModal: true` : explicite (le CDK le laisse OFF par défaut).\n * - `restoreFocus: true` : rend le focus au déclencheur à la fermeture.\n * - `panelClass` / `backdropClass` : crochets de style consommés par `dialog.css`.\n *\n * Pour focaliser un élément précis à l'ouverture (ex. éviter un bouton destructeur),\n * passez `autoFocus: '[ktDialogFocusInitial]'` dans la config d'ouverture et posez la\n * directive `ktDialogFocusInitial` sur la cible.\n *\n * @example\n * ```ts\n * // valeur de base, généralement consommée via provideKtDialogDefaults()\n * provideKtDialogDefaults({ ...KT_DIALOG_AAA_DEFAULTS });\n * ```\n */\nexport const KT_DIALOG_AAA_DEFAULTS: DialogConfig = {\n role: 'dialog',\n ariaModal: true,\n autoFocus: '[ktDialogFocusInitial]',\n restoreFocus: true,\n hasBackdrop: true,\n panelClass: 'kt-dialog',\n backdropClass: 'kt-dialog__backdrop',\n /* Plafond de largeur posé en STYLE INLINE sur le pane par l'overlay (canal prévu par le CDK).\n Indispensable : le CDK injecte à l'exécution `.cdk-overlay-pane { max-width: 100% }` HORS\n layer, qui bat toute règle de la lib importée via layer() — seul un style inline gagne.\n La custom property garde la thémisation ; `--fullscreen`/`--sheet` la retunent sur leur\n pane (cf. dialog.css). */\n maxWidth: 'var(--dialog-max-width)',\n};\n\n/**\n * Enregistre les valeurs par défaut AAA du dialog au niveau application.\n * À ajouter aux `providers` de `app.config.ts`. `overrides` permet d'ajuster sans\n * tout réécrire (ex. `provideKtDialogDefaults({ maxWidth: '40rem' })`).\n *\n * @example\n * ```ts\n * // app.config.ts\n * export const appConfig: ApplicationConfig = {\n * providers: [provideKtDialogDefaults({ maxWidth: '40rem' })],\n * };\n * ```\n * @param overrides Surcharges partielles fusionnées par-dessus `KT_DIALOG_AAA_DEFAULTS`.\n * @returns Un `Provider` pour le token `DEFAULT_DIALOG_CONFIG`.\n */\nexport function provideKtDialogDefaults(overrides?: Partial<DialogConfig>): Provider {\n return {\n provide: DEFAULT_DIALOG_CONFIG,\n useValue: { ...KT_DIALOG_AAA_DEFAULTS, ...overrides },\n };\n}\n\n/**\n * Options MAISON du dialog (≠ {@link KT_DIALOG_AAA_DEFAULTS}, qui porte la config du CDK).\n * Conforme à l'ADR-0003 : un token `KT_*_CONFIG` par entry-point, défauts anglais neutres,\n * cascade `option d'ouverture ?? token ?? défaut`.\n *\n * Toutes les clés actuelles ne concernent que la présentation `sheet` (préfixe `sheet*`) : sur les\n * présentations `centered` / `fullscreen`, la place d'un bouton de fermeture est un\n * `[ktDialogHeader]`, où on le POSE soi-même, dans le flux. Un usage hors sheet déclenche un\n * avertissement en mode dev.\n */\nexport interface KtDialogConfig {\n /**\n * Bouton de fermeture AUTO-RENDU en haut de la carte, en présentation `sheet`.\n *\n * Désactivé par défaut, pour une raison de COMPATIBILITÉ, pas d'ergonomie : `[ktDialogHeader]`\n * ne rend aucune croix (c'est une simple rangée flex), mais un dialog qui en compose un y place\n * généralement la sienne à la main. Activer l'option par défaut ferait donc apparaître une\n * DEUXIÈME croix chez ces consommateurs-là sans qu'ils aient rien changé.\n *\n * Recommandé sur toute sheet qui ne pose pas déjà son propre bouton de fermeture en tête.\n * @default false\n */\n sheetCloseButton: boolean;\n /** Nom accessible du bouton de fermeture auto-rendu (WCAG 4.1.2). @default 'Close' */\n sheetCloseLabel: string;\n /** Poignée décorative auto-rendue en présentation `sheet` (ADR-0005). @default true */\n sheetHandle: boolean;\n}\n\n/**\n * Défauts effectifs des options maison du dialog. Objet `Required` figé : c'est la SOURCE des\n * valeurs de repli, lue à la fois par l'ouvreur (résolution) et par le conteneur (fusion\n * idempotente), et énumérée par la garde de complétude i18n.\n */\nexport const DEFAULT_KT_DIALOG_CONFIG: Required<KtDialogConfig> = {\n sheetCloseButton: false,\n sheetCloseLabel: 'Close',\n sheetHandle: true,\n};\n\n/**\n * Token des options maison du dialog. Deux usages, un seul chemin de résolution :\n * - **application** : fourni via {@link provideKtDialog} (valeur partielle) ;\n * - **par ouverture** : `injectKtDialogOpener` REFOURNIT ce même token, déjà RÉSOLU, dans\n * l'injecteur du conteneur (canal `container.providers` du CDK). Le conteneur fusionne\n * toujours par-dessus {@link DEFAULT_KT_DIALOG_CONFIG} : l'opération est idempotente sur une\n * valeur déjà résolue, et reste correcte si le conteneur est monté sans passer par l'ouvreur.\n */\nexport const KT_DIALOG_CONFIG = new InjectionToken<Partial<KtDialogConfig>>('KT_DIALOG_CONFIG');\n\n/**\n * Enregistre les options maison du dialog pour l'application (ou un sous-arbre).\n * Complémentaire de {@link provideKtDialogDefaults}, qui porte la config du CDK : les deux\n * coexistent et ne se recouvrent pas.\n *\n * @example\n * ```ts\n * // app.config.ts — bouton de fermeture sur toutes les bottom-sheets\n * providers: [provideKtDialog({ sheetCloseButton: true })];\n * ```\n * @param config Options partielles fusionnées par-dessus `DEFAULT_KT_DIALOG_CONFIG`.\n * @returns Un `Provider` pour le token `KT_DIALOG_CONFIG`.\n */\nexport function provideKtDialog(config: Partial<KtDialogConfig>): Provider {\n return { provide: KT_DIALOG_CONFIG, useValue: config };\n}\n\n/**\n * Présentation du dialog, CHOISIE EXPLICITEMENT PAR LE DÉVELOPPEUR à l'ouverture (option\n * `presentation` de `injectKtDialogOpener`). Aucune bascule CSS automatique : le dev décide.\n * - `centered` : toujours centré (ex. confirmation) — DÉFAUT ;\n * - `fullscreen` : toujours plein écran (desktop compris) ;\n * - `sheet` : toujours bottom-sheet (desktop compris) ;\n * - `centered-fullscreen` : centré sur desktop, plein écran sur téléphone compact ;\n * - `centered-sheet` : centré sur desktop, bottom-sheet sur téléphone compact.\n * Les variantes `centered-*` sont résolues EN JS à l'ouverture (signal `KtViewport.isCompact()`), pas par le CSS —\n * la classe CSS finale est donc toujours une présentation CONCRÈTE (centered/fullscreen/sheet).\n */\nexport type KtDialogPresentation = 'centered' | 'fullscreen' | 'sheet' | 'centered-fullscreen' | 'centered-sheet';\n\n/** panelClass d'une présentation CONCRÈTE (sans variante responsive). */\nfunction concreteDialogPanelClass(p: 'centered' | 'fullscreen' | 'sheet'): string[] {\n if (p === 'fullscreen') return ['kt-dialog', 'kt-dialog--fullscreen'];\n if (p === 'sheet') return ['kt-dialog', 'kt-dialog--sheet'];\n return ['kt-dialog', 'kt-dialog--centered'];\n}\n\n/**\n * Résout une `KtDialogPresentation` (responsive comprise) en panelClass concret. Pour les variantes\n * `centered-*`, l'appelant fournit `compact` (= `KtViewport.isCompact()`, largeur seule) — centré\n * sur desktop, plein écran / sheet sur écran compact. Fonction pure (testable sans DOM).\n * Appelée par `injectKtDialogOpener` à chaque ouverture ; exportée pour un usage direct éventuel.\n *\n * @example\n * ```ts\n * resolveKtDialogPanelClass('sheet'); // ['kt-dialog', 'kt-dialog--sheet']\n * resolveKtDialogPanelClass('centered-sheet', true); // bottom-sheet sur écran compact\n * ```\n * @param presentation Présentation choisie par le dev (responsive comprise). Défaut `'centered'`.\n * @param compact `true` quand l'écran est compact (= `KtViewport.isCompact()`), pour résoudre les variantes `centered-*`. Défaut `false`.\n * @returns La liste des classes CSS de la présentation concrète résolue.\n */\nexport function resolveKtDialogPanelClass(presentation: KtDialogPresentation = 'centered', compact = false): string[] {\n if (presentation === 'centered' || presentation === 'fullscreen' || presentation === 'sheet') {\n return concreteDialogPanelClass(presentation);\n }\n if (presentation === 'centered-fullscreen') {\n return concreteDialogPanelClass(compact ? 'fullscreen' : 'centered');\n }\n return concreteDialogPanelClass(compact ? 'sheet' : 'centered'); // 'centered-sheet'\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n afterNextRender,\n isDevMode,\n signal,\n inject,\n PLATFORM_ID,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { CdkDialogContainer, DialogRef } from '@angular/cdk/dialog';\nimport { PortalModule } from '@angular/cdk/portal';\nimport { KtBodyScrollLock } from '@ktortu/aaa/cdk';\n\nimport { DEFAULT_KT_DIALOG_CONFIG, KT_DIALOG_CONFIG, KtDialogConfig } from './dialog-config';\n\n/** panelClass d'opt-out historique de la poignée, conservé comme repli DÉPRÉCIÉ (cf. `sheetHandle`). */\nconst LEGACY_NO_HANDLE_CLASS = 'kt-dialog--no-handle';\n\n@Component({\n selector: 'kt-dialog-container',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [PortalModule],\n host: {\n class: 'cdk-dialog-container kt-dialog-container',\n tabindex: '-1',\n '[attr.id]': '_config.id || null',\n '[attr.role]': '_config.role',\n '[attr.aria-modal]': '_config.ariaModal',\n '[attr.aria-labelledby]': '_config.ariaLabel ? null : ariaLabelledBy',\n '[attr.aria-label]': '_config.ariaLabel',\n '[attr.aria-describedby]': '_config.ariaDescribedBy || null',\n '[class.kt-dialog-container--sheet]': 'isSheet()',\n '[class.kt-dialog-container--closing]': 'isClosing()',\n },\n template: `\n <!-- Sheet scroll-snap (ADR-0005) : le conteneur est le SCROLLER, le spacer porte le snap\n « fermé » (un écran) et la carte (layout) le snap « ouvert ». -->\n @if (isSheet()) {\n <!-- Spacer = zone de tap-extérieur (ferme, comme un backdrop) ET surface de drag (scroll natif).\n Le conteneur capte le tactile (pointer-events auto) : le clic ne traverse plus vers le\n backdrop CDK, la fermeture au tap est donc portée ici (disableClose respecté). -->\n <div class=\"kt-dialog-container__spacer\" aria-hidden=\"true\" (click)=\"onScrimClick()\"></div>\n }\n <div class=\"kt-dialog-container__layout\" [class.kt-dialog-container__layout--closable]=\"showSheetClose()\">\n @if (showSheetClose()) {\n <!-- Bouton de fermeture AUTO-RENDU (opt-in 'sheetCloseButton'). Placé en TÊTE du document\n pour ouvrir l'ordre de tabulation, mais ancré en absolu sur la carte (cf. dialog.css) :\n il ne consomme pas de place dans la colonne. Aucun touch-action ici — le geste de\n glissement doit rester saisissable au travers du bouton (ADR-0005). -->\n <button\n type=\"button\"\n class=\"kt-dialog-container__sheet-close\"\n [attr.aria-label]=\"ktConfig.sheetCloseLabel\"\n (click)=\"onSheetCloseClick()\"\n >\n <span class=\"kt-dialog-container__sheet-close-icon\" aria-hidden=\"true\"></span>\n </button>\n }\n @if (isSheet() && showSheetHandle()) {\n <!-- Poignée DÉCORATIVE auto-rendue : la sheet s'attrape partout (opt-out : 'sheetHandle'). -->\n <div class=\"kt-dialog-container__sheet-handle\" aria-hidden=\"true\"></div>\n }\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n `,\n})\nexport class KtDialogContainer extends CdkDialogContainer {\n private readonly dialogRef = inject(DialogRef);\n private readonly elementRef = inject(ElementRef);\n private readonly host = this.elementRef.nativeElement as HTMLElement;\n private readonly platformId = inject(PLATFORM_ID);\n private readonly destroyRef = inject(DestroyRef);\n private readonly bodyScrollLock = inject(KtBodyScrollLock);\n\n /** Options maison RÉSOLUES. `injectKtDialogOpener` refournit `KT_DIALOG_CONFIG` déjà résolu dans\n l'injecteur du conteneur : la fusion ci-dessous est alors un no-op. Elle reste indispensable\n quand le conteneur est monté sans l'ouvreur (`dialog.open` brut), où le token remonte à\n l'application et n'est que partiel. Un seul chemin de code, idempotent. */\n protected readonly ktConfig: Required<KtDialogConfig> = {\n ...DEFAULT_KT_DIALOG_CONFIG,\n ...(inject(KT_DIALOG_CONFIG, { optional: true }) ?? {}),\n };\n\n protected readonly isClosing = signal(false);\n\n // --- Sheet scroll-snap (ADR-0005) : détection du snap « fermé » + fermeture différée ---\n /** Armé quand l'ouverture a dépassé 50px : un repos à ~0 est alors forcément le snap « fermé ». */\n private sheetArmed = false;\n /** Fermeture réelle en attente du repos au snap « fermé » (sortie programmatique animée). */\n private pendingSheetClose: (() => void) | null = null;\n private sheetCloseTimer: ReturnType<typeof setTimeout> | undefined;\n\n /** Premier id de la file `aria-labelledby` exposée par `CdkDialogContainer`. Le membre\n `_ariaLabelledByQueue` est interne au CDK (préfixe `_`) : on l'encapsule ICI, gardé, pour que\n le binding de template ne lise jamais l'interne directement. Si une montée du CDK retire ou\n renomme ce membre, on dégrade proprement vers `null` au lieu de casser le rendu du conteneur. */\n protected get ariaLabelledBy(): string | null {\n const queue = (this as unknown as { _ariaLabelledByQueue?: readonly string[] })._ariaLabelledByQueue;\n return queue?.[0] ?? null;\n }\n\n constructor() {\n super();\n // CDK Dialog n'expose AUCUN hook « avant fermeture ». Pour jouer l'animation de SORTIE sur\n // TOUTE fermeture, on intercepte la méthode publique `close` de la réf : c'est le point de\n // passage unique. Échap et clic backdrop sont gérés NATIVEMENT par le CDK, qui appelle lui aussi\n // `dialogRef.close()` → ils transitent donc par cette interception (inutile de les réimplémenter).\n const originalClose = this.dialogRef.close.bind(this.dialogRef);\n this.dialogRef.close = (result?: unknown) => {\n this.animateAndClose(result, originalClose);\n };\n\n // L'ouvreur pré-réserve des ids titre/description ; les directives [ktDialogTitle]/[ktDialogDescription]\n // les adoptent. En leur absence, ces ids pointent dans le vide. Au rendu (navigateur) :\n // - aria-describedby orphelin → on RETIRE l'attribut (pas de description fournie) ;\n // - aucun nom accessible (ni titre ni aria-label) → warn dev (WCAG 4.1.2).\n afterNextRender(() => {\n if (this.isSheet()) this.initSheetGesture();\n\n const doc = this.host.ownerDocument;\n\n const describedBy = this.host.getAttribute('aria-describedby');\n if (describedBy && !doc.getElementById(describedBy)) {\n this.host.removeAttribute('aria-describedby');\n }\n\n if (!isDevMode()) return;\n const labelledBy = this.host.getAttribute('aria-labelledby');\n const hasName = !!this.host.getAttribute('aria-label') || (!!labelledBy && !!doc.getElementById(labelledBy));\n if (!hasName) {\n console.warn(\n '[ktDialog] dialog sans nom accessible : ajoutez un [ktDialogTitle] (ou `aria-label` via la config d’ouverture) — WCAG 4.1.2.',\n );\n }\n this.warnOnConfigMisuse();\n });\n\n // Repli de FOCUS INITIAL. La config par défaut de la lib vise un SÉLECTEUR\n // (`autoFocus: '[ktDialogFocusInitial]'`) ; quand aucun élément ne le porte, le CDK ne focalise\n // RIEN (son repli sur le conteneur n'existe que pour les modes `first-tabbable`/`dialog`/false).\n // Le focus reste alors sur le déclencheur, HORS du dialog, et Tab promène l'utilisateur dans la\n // page derrière. On rattrape ici sur le conteneur (tabindex -1) — jamais sur un bouton :\n // atterrir d'emblée sur « Fermer » est un anti-pattern lecteur d'écran (WCAG 2.4.3).\n // `preventScroll` : en présentation sheet le conteneur EST le scroller à snap, focaliser ne doit\n // pas perturber le scroll d'entrée en cours.\n this._focusTrapped.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n if (this.host.contains(this.host.ownerDocument.activeElement)) return;\n this.host.focus({ preventScroll: true });\n });\n }\n\n /** Garde-fous dev sur la config maison : usage hors sheet, double bouton de fermeture, opt-out\n déprécié de la poignée. On AVERTIT sans jamais corriger en silence — un masquage automatique\n dépendrait de l'ordre de rendu du portail et serait indébogable. */\n private warnOnConfigMisuse(): void {\n if (this.hasLegacyNoHandleClass()) {\n console.warn(\n `[ktDialog] panelClass '${LEGACY_NO_HANDLE_CLASS}' déprécié : utilisez l’option typée ` +\n '`sheetHandle: false` (à l’ouverture ou via provideKtDialog).',\n );\n }\n\n if (this.ktConfig.sheetCloseButton && !this.isSheet()) {\n console.warn(\n '[ktDialog] `sheetCloseButton` ne s’applique qu’à la présentation `sheet` et reste sans effet ' +\n 'ici : en centré / plein écran, posez le bouton dans un [ktDialogHeader].',\n );\n }\n\n // Collision visuelle recherchée : une croix posée en TÊTE (typiquement dans un [ktDialogHeader]),\n // qui doublerait celle du conteneur. Un [ktDialogClose] dans la barre d'ACTIONS est légitime\n // (« Annuler », ou une action qui ferme au passage) et ne collisionne pas : on l'exclut.\n // Heuristique volontairement partielle par ailleurs : elle voit la forme ATTRIBUT `ktDialogClose`,\n // pas la forme liée `[ktDialogClose]=\"x\"` (un binding de propriété ne reflète aucun attribut).\n const strayClose =\n this.showSheetClose() &&\n [...this.host.querySelectorAll('[ktDialogClose]')].some((el) => !el.closest('[ktDialogActions]'));\n if (strayClose) {\n console.warn(\n '[ktDialog] double bouton de fermeture : `sheetCloseButton` est actif alors que le contenu ' +\n 'porte déjà un [ktDialogClose] hors barre d’actions (en-tête ?). Gardez l’un OU l’autre.',\n );\n }\n }\n\n protected isSheet(): boolean {\n return this._config.panelClass?.includes('kt-dialog--sheet') ?? false;\n }\n\n /** panelClass d'opt-out historique de la poignée — repli DÉPRÉCIÉ, remplacé par `sheetHandle`. */\n private hasLegacyNoHandleClass(): boolean {\n return this._config.panelClass?.includes(LEGACY_NO_HANDLE_CLASS) ?? false;\n }\n\n /** Poignée décorative auto-rendue en présentation sheet (ADR-0005). Opt-out : option `sheetHandle`\n (le panelClass historique reste honoré, en déprécié). */\n protected showSheetHandle(): boolean {\n if (this.hasLegacyNoHandleClass()) return false;\n return this.ktConfig.sheetHandle;\n }\n\n /** Bouton de fermeture auto-rendu : opt-in `sheetCloseButton`, et UNIQUEMENT en présentation sheet\n (ailleurs, la croix se pose à la main dans un `[ktDialogHeader]` — cf. `KtDialogConfig`). */\n protected showSheetClose(): boolean {\n return this.isSheet() && this.ktConfig.sheetCloseButton;\n }\n\n /** Clic sur le bouton de fermeture auto-rendu. Ne consulte VOLONTAIREMENT pas `disableClose` :\n contrairement au tap-extérieur et à Échap (fermetures « par inadvertance » que `disableClose`\n protège), ce bouton est une sortie EXPLICITEMENT demandée par le dev via `sheetCloseButton` —\n le combiner à `disableClose` est le patron « une seule sortie contrôlée ». Le drapeau\n `isClosing` garde l'idempotence face à un geste de glissement simultané. */\n protected onSheetCloseClick(): void {\n if (this.isClosing()) return;\n this.dialogRef.close();\n }\n\n /** Tap sur le spacer (zone extérieure à la carte) = fermeture, façon backdrop. Le conteneur\n captant désormais le tactile (pointer-events auto, requis pour le drag iOS), le clic ne\n traverse plus vers le backdrop CDK : on porte donc ICI la fermeture au tap-extérieur, en\n respectant `disableClose` (comme le faisait le backdropClick natif). Un drag n'émet pas de\n `click` (le navigateur le supprime après un scroll) : seul un vrai tap ferme. */\n protected onScrimClick(): void {\n if (this._config.disableClose || this.isClosing()) return;\n this.dialogRef.close();\n }\n\n /** Sheet scroll-snap : écouteurs (détection du repos + garde molette) et scroll d'ENTRÉE\n programmatique vers le snap « ouvert ». Appelé au premier rendu, en présentation sheet. */\n private initSheetGesture(): void {\n const host = this.host;\n host.addEventListener('scroll', this.onSheetScroll);\n host.addEventListener('wheel', this.onSheetWheel, { passive: false });\n // Verrou de scroll du fond (compteur partagé) : sans lui, le fond défile SOUS la sheet et,\n // sur iOS, le geste de dismiss déclenche le pull-to-refresh de la page. La stratégie `block`\n // du CDK ne suffit pas ici (non appliquée / non fiable sur iOS) — même approche que le Select.\n this.bodyScrollLock.lock();\n this.destroyRef.onDestroy(() => {\n clearTimeout(this.sheetCloseTimer);\n host.removeEventListener('scroll', this.onSheetScroll);\n host.removeEventListener('wheel', this.onSheetWheel);\n this.bodyScrollLock.unlock();\n });\n host.scrollTop = 0;\n requestAnimationFrame(() => {\n host.scrollTo?.({\n top: host.scrollHeight - host.clientHeight,\n behavior: this.prefersReducedMotion() ? 'auto' : 'smooth',\n });\n });\n }\n\n private prefersReducedMotion(): boolean {\n return this.host.ownerDocument.defaultView?.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n }\n\n /** Détection du snap « fermé » par position de scroll (ni scrollsnapchange ni scrollend — cf.\n ADR-0005). Un repos à ~0 finalise la fermeture en attente, ou EST une fermeture par geste. */\n private readonly onSheetScroll = (): void => {\n const top = this.host.scrollTop;\n if (top > 50) this.sheetArmed = true;\n if (!this.sheetArmed || top > 1) return;\n const pending = this.pendingSheetClose;\n if (pending) {\n this.pendingSheetClose = null;\n clearTimeout(this.sheetCloseTimer);\n pending();\n return;\n }\n // Dismissal par geste : transite par le close intercepté (animation déjà « jouée » par le doigt).\n if (!this.isClosing()) this.dialogRef.close();\n };\n\n /** La molette ne ferme JAMAIS la sheet (pas de geste souris — ADR-0005) : seuls les scrollers\n INTERNES peuvent consommer, dans leurs bornes (générique : un dialog peut imbriquer\n plusieurs zones scrollables). */\n private readonly onSheetWheel = (event: WheelEvent): void => {\n let el = event.target as HTMLElement | null;\n while (el && el !== this.host) {\n if (el.scrollHeight > el.clientHeight + 1) {\n const canScrollDown = el.scrollTop + el.clientHeight < el.scrollHeight - 1;\n const canScrollUp = el.scrollTop > 0;\n if ((event.deltaY > 0 && canScrollDown) || (event.deltaY < 0 && canScrollUp)) return;\n }\n el = el.parentElement;\n }\n event.preventDefault();\n };\n\n private animateAndClose(result: unknown, originalCloseFn: (r?: unknown) => void): void {\n if (this.isClosing()) return;\n this.isClosing.set(true);\n\n if (!isPlatformBrowser(this.platformId)) {\n originalCloseFn(result);\n return;\n }\n\n // Sheet scroll-snap : la sortie est un scroll programmatique vers le snap « fermé » ;\n // onSheetScroll finalise au repos. Déjà en bas (geste abouti, jsdom, reduced-motion) :\n // fermeture immédiate. Fallback : timeout (scroll lisse interrompu).\n if (this.isSheet()) {\n if (this.host.scrollTop <= 1) {\n originalCloseFn(result);\n return;\n }\n this.sheetArmed = true;\n this.pendingSheetClose = () => originalCloseFn(result);\n this.host.scrollTo?.({ top: 0, behavior: this.prefersReducedMotion() ? 'auto' : 'smooth' });\n clearTimeout(this.sheetCloseTimer);\n this.sheetCloseTimer = setTimeout(() => {\n const pending = this.pendingSheetClose;\n this.pendingSheetClose = null;\n pending?.();\n }, 400);\n return;\n }\n\n // Récupérer la durée de transition configurée en CSS (ex: \"150ms\" ou \"0.2s\"). Vue lue via\n // ownerDocument.defaultView (pas le global `window`) : cohérent avec prefersReducedMotion() et\n // sûr indépendamment du garde de plateforme — si la vue manque, durée 0 → fermeture immédiate.\n const durationStr = this.host.ownerDocument.defaultView?.getComputedStyle(this.host).transitionDuration || '0s';\n const durationMs = parseFloat(durationStr) * (durationStr.includes('ms') ? 1 : 1000);\n\n if (durationMs === 0) {\n originalCloseFn(result);\n return;\n }\n\n // Écouter la fin de la transition (opacity pour le dialog classique, translate pour la sheet)\n const onTransitionEnd = (event: TransitionEvent) => {\n if (event.target === this.host && (event.propertyName === 'translate' || event.propertyName === 'opacity')) {\n this.host.removeEventListener('transitionend', onTransitionEnd);\n originalCloseFn(result);\n }\n };\n this.host.addEventListener('transitionend', onTransitionEnd);\n\n // Sécurité (au cas où la transition n'aboutirait pas)\n setTimeout(() => {\n this.host.removeEventListener('transitionend', onTransitionEnd);\n originalCloseFn(result);\n }, durationMs + 50);\n }\n}\n","import { DIALOG_DATA, Dialog, DialogConfig, DialogRef } from '@angular/cdk/dialog';\nimport { ComponentType } from '@angular/cdk/portal';\nimport { ViewContainerRef, inject } from '@angular/core';\nimport { KtViewport, KtIdGenerator } from '@ktortu/aaa/cdk';\n\nimport {\n DEFAULT_KT_DIALOG_CONFIG,\n KT_DIALOG_AAA_DEFAULTS,\n KT_DIALOG_CONFIG,\n KtDialogConfig,\n KtDialogPresentation,\n resolveKtDialogPanelClass,\n} from './dialog-config';\nimport { KtDialogContainer } from './dialog-container';\n\n/**\n * Config d'ouverture sans le champ `data` (fourni séparément, typé), enrichie de `presentation` et\n * des options maison de {@link KtDialogConfig} (surcharge par ouverture de `KT_DIALOG_CONFIG`).\n */\nexport type KtDialogOpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'data'> &\n Partial<KtDialogConfig> & {\n /** Présentation du dialog (cf. `KtDialogPresentation`) — choisie par le dev. Résolue à CHAQUE\n ouverture : les variantes responsive lisent le signal d'écran compact. Défaut : `'centered'`.\n Combinée à un éventuel `panelClass` additionnel. */\n presentation?: KtDialogPresentation;\n };\n\n/** Retire les clés à `undefined` : une option NON fournie à l'ouverture ne doit pas écraser\n la valeur du token global (une clé absente et une clé à `undefined` sont équivalentes ici). */\nfunction definedOnly<T extends object>(source: T): Partial<T> {\n return Object.fromEntries(Object.entries(source).filter(([, value]) => value !== undefined)) as Partial<T>;\n}\n\n/**\n * ⚠️ API BAS-NIVEAU — n'utilisez PAS ceci par défaut. Pour implémenter un dialog, passez par\n * {@link defineKtDialog} puis son `injectOpener(...)` : il fixe données + résultat une seule fois et\n * les partage avec `injectData()`/`injectRef()`. N'appelez `injectKtDialogOpener` directement que\n * dans un cas avancé où le contrat groupé de `defineKtDialog` ne convient pas.\n *\n * Crée un ouvreur de dialog typé en contexte d'injection : le contrat (composant + type de `data` +\n * type de résultat + config par défaut) est figé via les génériques `<Composant, Data, Résultat>`\n * (qu'il faut répéter — d'où la préférence pour `defineKtDialog`). L'ouvreur renvoyé est une closure\n * appelable n'importe où dans la classe, 100 % typée, sans nouvel `inject`.\n *\n * Conserve le `ViewContainerRef` du contexte appelant (le dialog hérite donc de l'arbre logique\n * d'injection), reste testable (TestBed fournit `Dialog`) et sans état global (SSR-safe).\n *\n * @param component Composant à monter dans le dialog.\n * @param baseConfig Config d'ouverture par défaut (sans `data`), enrichie de `presentation` ; fusionnée à chaque ouverture.\n * @returns Une closure d'ouverture typée : `() => DialogRef` (sans data) ou `(data, config?) => DialogRef` (avec data).\n * @see {@link defineKtDialog} — la façon recommandée d'obtenir cet ouvreur.\n */\n// Surcharge sans data (D = void) : l'ouvreur ne prend aucun argument (la config par défaut suffit).\nexport function injectKtDialogOpener<C, R = unknown>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<void, R, C>,\n): () => DialogRef<R, C>;\n// Surcharge avec data typée.\nexport function injectKtDialogOpener<C, D, R = unknown>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<D, R, C>,\n): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;\n\nexport function injectKtDialogOpener<C, D, R = unknown>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<D, R, C>,\n) {\n const dialog = inject(Dialog);\n const viewport = inject(KtViewport);\n // Optionnel : hors d'un arbre de vue (ex. service root), il n'y a pas de ViewContainerRef.\n const viewContainerRef = inject(ViewContainerRef, { optional: true }) ?? undefined;\n const idGen = inject(KtIdGenerator);\n // Options maison au niveau application (partielles) : socle de la cascade résolue ci-dessous.\n const appKtConfig = inject(KT_DIALOG_CONFIG, { optional: true });\n\n return (data?: D, config?: KtDialogOpenerConfig<D, R, C>): DialogRef<R, C> => {\n // La présentation (choisie par le dev) est résolue ICI, à l'ouverture : les variantes\n // responsive lisent le signal d'écran compact. Le panelClass final = présentation concrète + extras.\n const { presentation, panelClass, sheetCloseButton, sheetCloseLabel, sheetHandle, ...rest } = {\n ...baseConfig,\n ...config,\n };\n const extra = panelClass ? (Array.isArray(panelClass) ? panelClass : [panelClass]) : [];\n\n // Cascade des options maison, résolue UNE SEULE FOIS ici (ADR-0003) : défaut → token\n // application → option d'ouverture. Le conteneur ne relit JAMAIS le token de son côté ; il\n // reçoit cette valeur déjà résolue par le canal `container.providers` du CDK (les\n // `providers` de la config générale, eux, n'atteignent QUE le portail de contenu).\n const ktConfig: Required<KtDialogConfig> = {\n ...DEFAULT_KT_DIALOG_CONFIG,\n ...definedOnly(appKtConfig ?? {}),\n ...definedOnly({ sheetCloseButton, sheetCloseLabel, sheetHandle }),\n };\n // Dédoublonné : une classe déjà fournie par la présentation (ex. `kt-dialog`) et repassée\n // en `panelClass` par le consommateur ne doit pas apparaître deux fois.\n const merged = [...new Set([...resolveKtDialogPanelClass(presentation, viewport.isCompact()), ...extra])];\n\n const uid = idGen.generateId('dialog');\n const titleId = `kt-dialog-title-${uid}`;\n\n return dialog.open<R, D, C>(component, {\n // Plancher a11y garanti par l'opener (ariaModal/role/restoreFocus/autoFocus…), même si le\n // consommateur n'a pas câblé provideKtDialogDefaults(). `...rest` (config par appel) prime.\n ...KT_DIALOG_AAA_DEFAULTS,\n viewContainerRef,\n // Canal TYPÉ vers le conteneur : ces providers-là atterrissent bien dans SON injecteur.\n container: {\n type: KtDialogContainer,\n providers: () => [{ provide: KT_DIALOG_CONFIG, useValue: ktConfig }],\n },\n ariaLabelledBy: titleId,\n ...rest,\n panelClass: merged,\n data,\n } as DialogConfig<D, DialogRef<R, C>>);\n };\n}\n\n/**\n * Contrat de dialog typé renvoyé par `defineKtDialog` : les trois accès (données, référence,\n * ouvreur) dérivent des MÊMES génériques `D`/`R`, déclarés une seule fois — impossible donc que\n * le type des données ou du résultat diverge entre le composant et l'ouvreur.\n *\n * @template D Type des données injectées (`void` si aucune).\n * @template R Type du résultat renvoyé à la fermeture.\n */\nexport interface KtDialogContract<D, R> {\n /** Données injectées (à appeler en contexte d'injection DANS le composant de dialog). */\n injectData(): D;\n /** Référence typée du dialog : `close()` n'accepte QUE le résultat `R` (sûreté de fermeture). */\n injectRef(): DialogRef<R>;\n /** Ouvreur typé CO-LOCALISÉ pour ce composant (cf. `injectKtDialogOpener`). */\n injectOpener<C>(\n component: ComponentType<C>,\n baseConfig?: KtDialogOpenerConfig<D, R, C>,\n ): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;\n}\n\n/**\n * ✅ STRATÉGIE PAR DÉFAUT pour implémenter un dialog `@ktortu/aaa`. Toute nouvelle dialog DOIT être\n * écrite ainsi. N'utilisez `injectKtDialogData` / `injectKtDialogOpener` directement QUE dans un cas\n * avancé non couvert ici.\n *\n * Définit le contrat typé du dialog (données `D` + résultat `R`) en UN SEUL endroit, co-localisé avec\n * le composant. Renvoie trois accès liés aux mêmes types — `injectData()` (données), `injectRef()`\n * (référence dont `close()` n'accepte que `R`) et `injectOpener()` (ouvreur) — d'où l'impossibilité\n * d'une divergence de type entre composant et ouvreur.\n *\n * Recette à copier pour CHAQUE dialog :\n * 1. `interface XxxData { … }` (ou `void` si aucune donnée) ;\n * 2. `const xxxDialog = defineKtDialog<XxxData, Résultat>();` ;\n * 3. dans le composant : `injectData()` pour lire la donnée, `injectRef()` pour fermer avec résultat ;\n * 4. `export const injectXxxDialog = () => xxxDialog.injectOpener(XxxDialog);` (co-localisé) ;\n * 5. côté consommateur : `private readonly openXxx = injectXxxDialog();` (initialiseur de champ).\n *\n * Convention de fermeture : annuler / fermer SANS résultat via la directive `[ktDialogClose]`\n * (→ `undefined`) ; renvoyer un résultat via `ref.close(résultat)` (typé `R`). Passer un résultat par\n * `[ktDialogClose]=\"x\"` reste possible mais N'EST PAS typé (la directive ignore `R`).\n *\n * @example\n * ```ts\n * // ─── rename-dialog.ts : composant + contrat + ouvreur, co-localisés ───\n * export interface RenameData { currentName: string; }\n *\n * const renameDialog = defineKtDialog<RenameData, string>(); // D et R déclarés UNE seule fois\n *\n * @Component({\n * imports: [KtButton, KtDialogImports],\n * template: `\n * <h2 ktDialogTitle>Renommer</h2>\n * <footer ktDialogActions>\n * <button ktButton ktDialogClose>Annuler</button> // ferme sans résultat (undefined)\n * <button ktButton (click)=\"submit()\">Renommer</button> // ferme avec résultat typé\n * </footer>`,\n * })\n * export class RenameDialog {\n * protected readonly data = renameDialog.injectData(); // RenameData garanti\n * private readonly ref = renameDialog.injectRef(); // DialogRef<string>\n * protected submit() { this.ref.close('nouveau-nom'); } // close(result?: string) — typé\n * }\n *\n * export const injectRenameDialog = () => renameDialog.injectOpener(RenameDialog);\n *\n * // ─── consommateur ───\n * private readonly openRename = injectRenameDialog(); // initialiseur de champ = contexte d'injection\n * rename() {\n * this.openRename({ currentName: 'X' }).closed.subscribe(name => {\n * // name: string | undefined\n * });\n * }\n * ```\n */\nexport function defineKtDialog<D = void, R = unknown>(): KtDialogContract<D, R> {\n return {\n injectData: () => inject<D>(DIALOG_DATA),\n injectRef: () => inject(DialogRef) as DialogRef<R>,\n injectOpener: <C>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<D, R, C>) =>\n injectKtDialogOpener<C, D, R>(component, baseConfig) as (\n data: D,\n config?: KtDialogOpenerConfig<D, R, C>,\n ) => DialogRef<R, C>,\n };\n}\n","import { KtDialogTitle } from './dialog-title.directive';\nimport { KtDialogDescription } from './dialog-description.directive';\nimport { KtDialogClose } from './dialog-close.directive';\nimport {\n KtDialogHeader,\n KtDialogContent,\n KtDialogActions,\n KtDialogFocusInitial,\n KtDialogSheetHandle,\n} from './dialog-structure';\n\n/**\n * Import ergonomique de toute la famille dialog en une fois :\n * `imports: [KtDialogImports]` au lieu d'énumérer chaque directive structurelle.\n */\nexport const KtDialogImports = [\n KtDialogHeader,\n KtDialogTitle,\n KtDialogDescription,\n KtDialogContent,\n KtDialogActions,\n KtDialogClose,\n KtDialogFocusInitial,\n KtDialogSheetHandle,\n] as const;\n","import { ChangeDetectionStrategy, Component, Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { DialogRef } from '@angular/cdk/dialog';\nimport { KtButton, KtButtonColor } from '@ktortu/aaa/button';\n\nimport { defineKtDialog } from './dialog-opener';\nimport { KtDialogImports } from './dialog-imports';\n\n/** Option de variante visuelle pour le dialogue d'alerte. */\nexport type KtAlertDialogVariant = 'neutral' | 'info' | 'success' | 'warning' | 'error';\n\n/**\n * Options pour l'ouverture d'une boîte de dialogue d'alerte.\n */\nexport interface KtAlertOptions {\n /** Libellé du bouton de fermeture. Par défaut: 'Fermer'. */\n closeLabel?: string;\n /** Variante sémantique (apparence : icône + accent). Par défaut: 'neutral'. */\n variant?: KtAlertDialogVariant;\n}\n\n/**\n * Configuration pour l'ouverture d'une boîte de dialogue d'alerte simple.\n */\nexport interface KtAlertData {\n /** Titre de la boîte de dialogue. */\n title: string;\n /**\n * Message explicatif. Peut être une simple chaîne de caractères\n * ou un tableau de chaînes pour composer plusieurs paragraphes.\n * Supporte le HTML (balises sécurisées) désinfecté à l'affichage.\n */\n message: string | string[];\n /** Libellé du bouton de fermeture. Par défaut: 'Fermer'. */\n closeLabel?: string;\n /** Variante sémantique (apparence : icône + accent). Par défaut: 'neutral'. */\n variant?: KtAlertDialogVariant;\n}\n\nconst alertDialog = defineKtDialog<KtAlertData, void>();\n\n/**\n * Composant interne d'alerte générique.\n * Affiche un titre, un message (simple ou multiligne HTML) et un bouton de fermeture.\n */\n@Component({\n selector: 'kt-alert-dialog',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [KtButton, KtDialogImports],\n host: {\n class: 'kt-alert-dialog',\n '[attr.data-variant]': \"data.variant || 'neutral'\",\n },\n template: `\n <h2 ktDialogTitle>\n @if (data.variant && data.variant !== 'neutral') {\n <span class=\"kt-alert-dialog__icon\" aria-hidden=\"true\"></span>\n }\n <span>{{ data.title }}</span>\n </h2>\n <div ktDialogDescription>\n @if (isMessageArray()) {\n @for (line of messageArray(); track line) {\n <p [innerHTML]=\"line\"></p>\n }\n } @else {\n <p [innerHTML]=\"messageString()\"></p>\n }\n </div>\n <footer ktDialogActions>\n <button ktButton ktDialogFocusInitial ktDialogClose>\n {{ data.closeLabel || 'Fermer' }}\n </button>\n </footer>\n `,\n})\nexport class KtAlertDialog {\n protected readonly data = alertDialog.injectData();\n\n protected isMessageArray(): boolean {\n return Array.isArray(this.data.message);\n }\n\n protected messageArray(): string[] {\n return Array.isArray(this.data.message) ? this.data.message : [];\n }\n\n protected messageString(): string {\n return typeof this.data.message === 'string' ? this.data.message : '';\n }\n}\n\n/** Ouvreur co-localisé officiel pour l'alerte. Utilise la présentation responsive par défaut. */\nexport const injectAlertDialog = () => alertDialog.injectOpener(KtAlertDialog, { presentation: 'centered-sheet' });\n\n/** Option de variante visuelle pour le bouton d'action principal. */\nexport type KtDialogColor = KtButtonColor;\n\n/**\n * Configuration pour l'ouverture d'une boîte de dialogue de confirmation binaire (Oui/Non).\n */\nexport interface KtConfirmConfig {\n /** Titre de la boîte de dialogue. */\n title: string;\n /**\n * Message explicatif. Peut être une simple chaîne ou un tableau\n * de chaînes de caractères pour composer plusieurs paragraphes.\n * Supporte le HTML désinfecté à l'affichage.\n */\n message: string | string[];\n /** Libellé du bouton de validation. Par défaut: 'Oui'. */\n confirmLabel?: string;\n /** Libellé du bouton de rejet. Par défaut: 'Non'. */\n rejectLabel?: string;\n /**\n * Variante de couleur du bouton principal.\n * Utile pour marquer une action destructive ou critique.\n * Par défaut: 'primary'.\n */\n color?: KtDialogColor;\n}\n\n/**\n * Configuration pour une décision ternaire (inclut obligatoirement un bouton d'annulation).\n */\nexport interface KtDecideConfig extends KtConfirmConfig {\n /** Libellé du bouton d'annulation. Requis. */\n cancelLabel: string;\n}\n\n/**\n * Type de retour d'une boîte de dialogue de confirmation ou de décision.\n * - 'confirm' : Choix de validation (Oui / Enregistrer)\n * - 'reject' : Choix de rejet (Non / Ignorer)\n * - 'cancel' : Choix d'annulation (Annuler)\n */\nexport type KtConfirmResult = 'confirm' | 'reject' | 'cancel';\n\nconst confirmDialog = defineKtDialog<KtDecideConfig, KtConfirmResult>();\n\n/**\n * Composant interne de confirmation/décision générique.\n * Supporte le mode binaire (Oui/Non) et le mode ternaire (Oui/Non/Annuler).\n * Gère l'empilement vertical des boutons et les messages HTML multi-lignes.\n */\n@Component({\n selector: 'kt-confirm-dialog',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [KtButton, KtDialogImports],\n template: `\n <h2 ktDialogTitle>{{ data.title }}</h2>\n <div ktDialogDescription>\n @if (isMessageArray()) {\n @for (line of messageArray(); track line) {\n <p [innerHTML]=\"line\"></p>\n }\n } @else {\n <p [innerHTML]=\"messageString()\"></p>\n }\n </div>\n <footer ktDialogActions>\n @if (data.cancelLabel) {\n <button ktButton mode=\"text\" ktDialogFocusInitial (click)=\"cancel()\">\n {{ data.cancelLabel }}\n </button>\n <button ktButton mode=\"text\" (click)=\"reject()\">\n {{ data.rejectLabel || 'Non' }}\n </button>\n } @else {\n <button ktButton mode=\"text\" ktDialogFocusInitial (click)=\"reject()\">\n {{ data.rejectLabel || 'Non' }}\n </button>\n }\n <button ktButton [color]=\"data.color || 'primary'\" (click)=\"confirm()\">\n {{ data.confirmLabel || 'Oui' }}\n </button>\n </footer>\n `,\n})\nexport class KtConfirmDialog {\n protected readonly data = confirmDialog.injectData();\n private readonly ref = confirmDialog.injectRef();\n\n protected isMessageArray(): boolean {\n return Array.isArray(this.data.message);\n }\n\n protected messageArray(): string[] {\n return Array.isArray(this.data.message) ? this.data.message : [];\n }\n\n protected messageString(): string {\n return typeof this.data.message === 'string' ? this.data.message : '';\n }\n\n protected confirm(): void {\n this.ref.close('confirm');\n }\n\n protected reject(): void {\n this.ref.close('reject');\n }\n\n protected cancel(): void {\n this.ref.close('cancel');\n }\n}\n\n/** Ouvreur co-localisé officiel pour la confirmation/décision. Utilise la présentation responsive par défaut. */\nexport const injectConfirmDialog = () =>\n confirmDialog.injectOpener(KtConfirmDialog, { presentation: 'centered-sheet' });\n\n/**\n * Service d'aide global pour l'ouverture simplifiée de boîtes de dialogue d'alerte et de confirmation.\n * S'appuie sur les ouvreurs de dialogues officiels co-localisés.\n * Propose une présentation adaptative (centrée sur grand écran, bottom-sheet sur mobile).\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class KtQuickDialog {\n private readonly openAlert = injectAlertDialog();\n private readonly openConfirm = injectConfirmDialog();\n\n /**\n * Ouvre une boîte de dialogue d'alerte simple.\n *\n * @param title Titre de l'alerte.\n * @param message Message d'explication (string simple ou tableau de strings pour du multi-lignes HTML).\n * @param closeLabel Libellé du bouton de fermeture.\n * @returns La référence DialogRef de la modale ouverte.\n */\n alert(title: string, message: string | string[], closeLabel?: string): DialogRef<void, KtAlertDialog>;\n /**\n * Ouvre une boîte de dialogue d'alerte simple.\n *\n * @param title Titre de l'alerte.\n * @param message Message d'explication (string simple ou tableau de strings pour du multi-lignes HTML).\n * @param options Options d'ouverture de l'alerte (libellé de fermeture, variante).\n * @returns La référence DialogRef de la modale ouverte.\n */\n alert(title: string, message: string | string[], options?: KtAlertOptions): DialogRef<void, KtAlertDialog>;\n alert(\n title: string,\n message: string | string[],\n closeLabelOrOptions?: string | KtAlertOptions,\n ): DialogRef<void, KtAlertDialog> {\n const data: KtAlertData = { title, message };\n\n if (typeof closeLabelOrOptions === 'string') {\n data.closeLabel = closeLabelOrOptions;\n } else if (closeLabelOrOptions) {\n data.closeLabel = closeLabelOrOptions.closeLabel;\n data.variant = closeLabelOrOptions.variant;\n }\n\n return this.openAlert(data);\n }\n\n /**\n * Ouvre une boîte de dialogue de confirmation binaire (Oui/Non).\n *\n * @param config Options de configuration (titre, message, libellés de boutons, couleur).\n * @returns Un Observable émettant true si l'utilisateur valide (Oui),\n * false s'il rejette (Non), et undefined si la boîte est fermée en cliquant en dehors ou via Échap.\n */\n confirm(config: KtConfirmConfig): Observable<boolean | undefined> {\n const dialogRef = this.openConfirm({\n ...config,\n cancelLabel: '', // Pas de bouton d'annulation en mode binaire\n });\n\n return dialogRef.closed.pipe(\n map((result) => {\n if (result === 'confirm') return true;\n if (result === 'reject') return false;\n return undefined;\n }),\n );\n }\n\n /**\n * Ouvre une boîte de dialogue de décision ternaire (Oui/Non/Annuler).\n *\n * @param config Options de configuration (titre, message, libellés de boutons dont cancelLabel obligatoire).\n * @returns Un Observable émettant 'confirm', 'reject', 'cancel' ou undefined si fermeture externe.\n */\n decide(config: KtDecideConfig): Observable<KtConfirmResult | undefined> {\n const dialogRef = this.openConfirm(config);\n return dialogRef.closed;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.KtDialogTitle","i2.KtDialogDescription","i3.KtDialogActions","i4.KtDialogClose","i3.KtDialogFocusInitial"],"mappings":"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"}
@@ -3682,7 +3682,10 @@ class KtMultiSelect extends KtBaseSelect {
3682
3682
  listboxValue = computed(() => this.selectedOptions().map((o) => this.keyOf(o)), /* @ts-ignore */
3683
3683
  ...(ngDevMode ? [{ debugName: "listboxValue" }] : /* istanbul ignore next */ []));
3684
3684
  // --- Tout effacer depuis le champ (clearable) ---
3685
- showClear = computed(() => this.clearable() && !this.disabled() && !this.readonly() && this.selectedOptions().length > 0, /* @ts-ignore */
3685
+ /** Affiche le bouton « effacer » (×) sur le champ dès qu'une valeur est présente (`clearable`).
3686
+ Basé sur `value()` et non `selectedOptions()` : des clés orphelines (options retirées des données)
3687
+ restent effaçables (aligné sur `KtSelect`). */
3688
+ showClear = computed(() => this.clearable() && !this.disabled() && !this.readonly() && (this.value()?.length ?? 0) > 0, /* @ts-ignore */
3686
3689
  ...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
3687
3690
  /** Le popup utilise la structure « panneau dialog » (champ de filtre et/ou barre d'actions). */
3688
3691
  dialogMode = computed(() => this.filterable() || this.selectionActions(), /* @ts-ignore */