@ktortu/aaa 0.9.0 → 0.9.1

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.
@@ -250,19 +250,13 @@ type KtDialogPresentation = 'centered' | 'fullscreen' | 'sheet' | 'centered-full
250
250
  declare function resolveKtDialogPanelClass(presentation?: KtDialogPresentation, compact?: boolean): string[];
251
251
 
252
252
  /**
253
- * Sucre typé pour récupérer les données injectées dans un composant de dialogue (`DIALOG_DATA`).
254
- * À appeler en contexte d'injection (ex. initialiseur de champ).
255
- *
256
- * @example
257
- * ```ts
258
- * interface RenameData { currentName: string; }
253
+ * ⚠️ API BAS-NIVEAU n'utilisez PAS ceci par défaut. Pour implémenter un dialog, passez par
254
+ * {@link defineKtDialog} et son `injectData()` (qui lie le type des données à l'ouvreur).
259
255
  *
260
- * @Component({ … })
261
- * export class RenameDialog {
262
- * protected readonly data = injectKtDialogData<RenameData>();
263
- * // this.data.currentName → string
264
- * }
265
- * ```
256
+ * Sucre typé pour récupérer les données injectées dans un composant de dialogue (`DIALOG_DATA`).
257
+ * Le type `T` est affirmé ICI indépendamment de l'ouvreur : rien ne garantit qu'il corresponde au
258
+ * type passé à `injectKtDialogOpener` → risque de divergence silencieuse. À réserver à un cas où
259
+ * `defineKtDialog` ne convient pas.
266
260
  */
267
261
  declare function injectKtDialogData<T>(): T;
268
262
  /** Config d'ouverture sans le champ `data` (fourni séparément, typé), enrichie de `presentation`. */
@@ -273,29 +267,97 @@ type KtDialogOpenerConfig<D, R, C> = Omit<DialogConfig<D, DialogRef<R, C>>, 'dat
273
267
  presentation?: KtDialogPresentation;
274
268
  };
275
269
  /**
276
- * Crée un ouvreur de dialog **typé et centralisé**, en contexte d'injection.
277
- * Le contrat (composant + type de `data` + type de résultat + config par défaut) est défini
278
- * UNE fois ; l'ouvreur renvoyé est une closure appelable ensuite n'importe dans la classe
279
- * (handlers compris), 100 % typée, sans nouvel `inject`.
270
+ * ⚠️ API BAS-NIVEAU n'utilisez PAS ceci par défaut. Pour implémenter un dialog, passez par
271
+ * {@link defineKtDialog} puis son `injectOpener(...)` : il fixe données + résultat une seule fois et
272
+ * les partage avec `injectData()`/`injectRef()`. N'appelez `injectKtDialogOpener` directement que
273
+ * dans un cas avancé le contrat groupé de `defineKtDialog` ne convient pas.
274
+ *
275
+ * Crée un ouvreur de dialog typé en contexte d'injection : le contrat (composant + type de `data` +
276
+ * type de résultat + config par défaut) est figé via les génériques `<Composant, Data, Résultat>`
277
+ * (qu'il faut répéter — d'où la préférence pour `defineKtDialog`). L'ouvreur renvoyé est une closure
278
+ * appelable n'importe où dans la classe, 100 % typée, sans nouvel `inject`.
280
279
  *
281
280
  * Conserve le `ViewContainerRef` du contexte appelant (le dialog hérite donc de l'arbre logique
282
281
  * d'injection), reste testable (TestBed fournit `Dialog`) et sans état global (SSR-safe).
283
282
  *
284
- * @example
285
- * // co-localisé avec le composant
286
- * export const injectRenameDialog = () =>
287
- * injectKtDialogOpener<RenameDialog, RenameData, string>(RenameDialog, { autoFocus: '[ktDialogFocusInitial]' });
288
- *
289
- * // dans un composant/service consommateur
290
- * private readonly openRename = injectRenameDialog();
291
- * rename() { this.openRename({ currentName: 'X' }).closed.subscribe(n => { n: string | undefined }); }
292
- *
293
283
  * @param component Composant à monter dans le dialog.
294
284
  * @param baseConfig Config d'ouverture par défaut (sans `data`), enrichie de `presentation` ; fusionnée à chaque ouverture.
295
285
  * @returns Une closure d'ouverture typée : `() => DialogRef` (sans data) ou `(data, config?) => DialogRef` (avec data).
286
+ * @see {@link defineKtDialog} — la façon recommandée d'obtenir cet ouvreur.
296
287
  */
297
288
  declare function injectKtDialogOpener<C, R = unknown>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<void, R, C>): () => DialogRef<R, C>;
298
289
  declare function injectKtDialogOpener<C, D, R = unknown>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<D, R, C>): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;
290
+ /**
291
+ * Contrat de dialog typé renvoyé par `defineKtDialog` : les trois accès (données, référence,
292
+ * ouvreur) dérivent des MÊMES génériques `D`/`R`, déclarés une seule fois — impossible donc que
293
+ * le type des données ou du résultat diverge entre le composant et l'ouvreur.
294
+ *
295
+ * @template D Type des données injectées (`void` si aucune).
296
+ * @template R Type du résultat renvoyé à la fermeture.
297
+ */
298
+ interface KtDialogContract<D, R> {
299
+ /** Données injectées (à appeler en contexte d'injection DANS le composant de dialog). */
300
+ injectData(): D;
301
+ /** Référence typée du dialog : `close()` n'accepte QUE le résultat `R` (sûreté de fermeture). */
302
+ injectRef(): DialogRef<R>;
303
+ /** Ouvreur typé CO-LOCALISÉ pour ce composant (cf. `injectKtDialogOpener`). */
304
+ injectOpener<C>(component: ComponentType<C>, baseConfig?: KtDialogOpenerConfig<D, R, C>): (data: D, config?: KtDialogOpenerConfig<D, R, C>) => DialogRef<R, C>;
305
+ }
306
+ /**
307
+ * ✅ STRATÉGIE PAR DÉFAUT pour implémenter un dialog `@ktortu/aaa`. Toute nouvelle dialog DOIT être
308
+ * écrite ainsi. N'utilisez `injectKtDialogData` / `injectKtDialogOpener` directement QUE dans un cas
309
+ * avancé non couvert ici.
310
+ *
311
+ * Définit le contrat typé du dialog (données `D` + résultat `R`) en UN SEUL endroit, co-localisé avec
312
+ * le composant. Renvoie trois accès liés aux mêmes types — `injectData()` (données), `injectRef()`
313
+ * (référence dont `close()` n'accepte que `R`) et `injectOpener()` (ouvreur) — d'où l'impossibilité
314
+ * d'une divergence de type entre composant et ouvreur.
315
+ *
316
+ * Recette à copier pour CHAQUE dialog :
317
+ * 1. `interface XxxData { … }` (ou `void` si aucune donnée) ;
318
+ * 2. `const xxxDialog = defineKtDialog<XxxData, Résultat>();` ;
319
+ * 3. dans le composant : `injectData()` pour lire la donnée, `injectRef()` pour fermer avec résultat ;
320
+ * 4. `export const injectXxxDialog = () => xxxDialog.injectOpener(XxxDialog);` (co-localisé) ;
321
+ * 5. côté consommateur : `private readonly openXxx = injectXxxDialog();` (initialiseur de champ).
322
+ *
323
+ * Convention de fermeture : annuler / fermer SANS résultat via la directive `[ktDialogClose]`
324
+ * (→ `undefined`) ; renvoyer un résultat via `ref.close(résultat)` (typé `R`). Passer un résultat par
325
+ * `[ktDialogClose]="x"` reste possible mais N'EST PAS typé (la directive ignore `R`).
326
+ *
327
+ * @example
328
+ * ```ts
329
+ * // ─── rename-dialog.ts : composant + contrat + ouvreur, co-localisés ───
330
+ * export interface RenameData { currentName: string; }
331
+ *
332
+ * const renameDialog = defineKtDialog<RenameData, string>(); // D et R déclarés UNE seule fois
333
+ *
334
+ * @Component({
335
+ * imports: [KtButton, KtDialogImports],
336
+ * template: `
337
+ * <h2 ktDialogTitle>Renommer</h2>
338
+ * <footer ktDialogActions>
339
+ * <button ktButton ktDialogClose>Annuler</button> // ferme sans résultat (undefined)
340
+ * <button ktButton (click)="submit()">Renommer</button> // ferme avec résultat typé
341
+ * </footer>`,
342
+ * })
343
+ * export class RenameDialog {
344
+ * protected readonly data = renameDialog.injectData(); // RenameData garanti
345
+ * private readonly ref = renameDialog.injectRef(); // DialogRef<string>
346
+ * protected submit() { this.ref.close('nouveau-nom'); } // close(result?: string) — typé
347
+ * }
348
+ *
349
+ * export const injectRenameDialog = () => renameDialog.injectOpener(RenameDialog);
350
+ *
351
+ * // ─── consommateur ───
352
+ * private readonly openRename = injectRenameDialog(); // initialiseur de champ = contexte d'injection
353
+ * rename() {
354
+ * this.openRename({ currentName: 'X' }).closed.subscribe(name => {
355
+ * // name: string | undefined
356
+ * });
357
+ * }
358
+ * ```
359
+ */
360
+ declare function defineKtDialog<D = void, R = unknown>(): KtDialogContract<D, R>;
299
361
 
300
362
  declare class KtDialogContainer extends CdkDialogContainer implements OnInit {
301
363
  private readonly dialogRef;
@@ -318,5 +380,5 @@ declare class KtDialogContainer extends CdkDialogContainer implements OnInit {
318
380
  */
319
381
  declare const KtDialogImports: readonly [typeof KtDialogHeader, typeof KtDialogTitle, typeof KtDialogDescription, typeof KtDialogContent, typeof KtDialogActions, typeof KtDialogClose, typeof KtDialogFocusInitial, typeof KtDialogSheetHandle];
320
382
 
321
- export { KT_DIALOG_AAA_DEFAULTS, KtDialogActions, KtDialogClose, KtDialogContainer, KtDialogContent, KtDialogDescription, KtDialogFocusInitial, KtDialogHeader, KtDialogImports, KtDialogSheetHandle, KtDialogTitle, injectKtDialogData, injectKtDialogOpener, provideKtDialogDefaults, resolveKtDialogPanelClass };
322
- export type { KtDialogOpenerConfig, KtDialogPresentation };
383
+ export { KT_DIALOG_AAA_DEFAULTS, KtDialogActions, KtDialogClose, KtDialogContainer, KtDialogContent, KtDialogDescription, KtDialogFocusInitial, KtDialogHeader, KtDialogImports, KtDialogSheetHandle, KtDialogTitle, defineKtDialog, injectKtDialogData, injectKtDialogOpener, provideKtDialogDefaults, resolveKtDialogPanelClass };
384
+ export type { KtDialogContract, KtDialogOpenerConfig, KtDialogPresentation };