@mesgflow/ui-kit 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/README.md +56 -5
  2. package/fesm2022/mesgflow-ui-kit-accordion.mjs +9 -8
  3. package/fesm2022/mesgflow-ui-kit-accordion.mjs.map +1 -1
  4. package/fesm2022/mesgflow-ui-kit-agenda.mjs +208 -0
  5. package/fesm2022/mesgflow-ui-kit-agenda.mjs.map +1 -0
  6. package/fesm2022/mesgflow-ui-kit-alert.mjs +3 -3
  7. package/fesm2022/mesgflow-ui-kit-aspect-ratio.mjs +37 -0
  8. package/fesm2022/mesgflow-ui-kit-aspect-ratio.mjs.map +1 -0
  9. package/fesm2022/mesgflow-ui-kit-avatar-group.mjs +3 -3
  10. package/fesm2022/mesgflow-ui-kit-avatar.mjs +3 -3
  11. package/fesm2022/mesgflow-ui-kit-badge.mjs +3 -3
  12. package/fesm2022/mesgflow-ui-kit-banner.mjs +3 -3
  13. package/fesm2022/mesgflow-ui-kit-blocks.mjs +207 -0
  14. package/fesm2022/mesgflow-ui-kit-blocks.mjs.map +1 -0
  15. package/fesm2022/mesgflow-ui-kit-box-input.mjs +4 -4
  16. package/fesm2022/mesgflow-ui-kit-box-input.mjs.map +1 -1
  17. package/fesm2022/mesgflow-ui-kit-brand.mjs +3 -3
  18. package/fesm2022/mesgflow-ui-kit-breadcrumb.mjs +3 -3
  19. package/fesm2022/mesgflow-ui-kit-button-group.mjs +3 -3
  20. package/fesm2022/mesgflow-ui-kit-button.mjs +190 -244
  21. package/fesm2022/mesgflow-ui-kit-button.mjs.map +1 -1
  22. package/fesm2022/mesgflow-ui-kit-card.mjs +48 -27
  23. package/fesm2022/mesgflow-ui-kit-card.mjs.map +1 -1
  24. package/fesm2022/mesgflow-ui-kit-carousel.mjs +308 -0
  25. package/fesm2022/mesgflow-ui-kit-carousel.mjs.map +1 -0
  26. package/fesm2022/mesgflow-ui-kit-chart.mjs +12 -12
  27. package/fesm2022/mesgflow-ui-kit-checkbox.mjs +18 -23
  28. package/fesm2022/mesgflow-ui-kit-checkbox.mjs.map +1 -1
  29. package/fesm2022/mesgflow-ui-kit-chip.mjs +5 -5
  30. package/fesm2022/mesgflow-ui-kit-chip.mjs.map +1 -1
  31. package/fesm2022/mesgflow-ui-kit-code-block.mjs +11 -7
  32. package/fesm2022/mesgflow-ui-kit-code-block.mjs.map +1 -1
  33. package/fesm2022/mesgflow-ui-kit-collapsible.mjs +9 -9
  34. package/fesm2022/mesgflow-ui-kit-color-picker.mjs +9 -7
  35. package/fesm2022/mesgflow-ui-kit-color-picker.mjs.map +1 -1
  36. package/fesm2022/mesgflow-ui-kit-combobox.mjs +147 -67
  37. package/fesm2022/mesgflow-ui-kit-combobox.mjs.map +1 -1
  38. package/fesm2022/mesgflow-ui-kit-command.mjs +15 -16
  39. package/fesm2022/mesgflow-ui-kit-command.mjs.map +1 -1
  40. package/fesm2022/mesgflow-ui-kit-context-menu.mjs +7 -9
  41. package/fesm2022/mesgflow-ui-kit-context-menu.mjs.map +1 -1
  42. package/fesm2022/mesgflow-ui-kit-copy-button.mjs +6 -6
  43. package/fesm2022/mesgflow-ui-kit-core.mjs +446 -128
  44. package/fesm2022/mesgflow-ui-kit-core.mjs.map +1 -1
  45. package/fesm2022/mesgflow-ui-kit-countdown.mjs +149 -0
  46. package/fesm2022/mesgflow-ui-kit-countdown.mjs.map +1 -0
  47. package/fesm2022/mesgflow-ui-kit-date-picker.mjs +140 -19
  48. package/fesm2022/mesgflow-ui-kit-date-picker.mjs.map +1 -1
  49. package/fesm2022/mesgflow-ui-kit-description-list.mjs +3 -3
  50. package/fesm2022/mesgflow-ui-kit-dialog.mjs +310 -64
  51. package/fesm2022/mesgflow-ui-kit-dialog.mjs.map +1 -1
  52. package/fesm2022/mesgflow-ui-kit-divider.mjs +3 -3
  53. package/fesm2022/mesgflow-ui-kit-drawer.mjs +109 -0
  54. package/fesm2022/mesgflow-ui-kit-drawer.mjs.map +1 -0
  55. package/fesm2022/mesgflow-ui-kit-dropzone.mjs +6 -6
  56. package/fesm2022/mesgflow-ui-kit-dropzone.mjs.map +1 -1
  57. package/fesm2022/mesgflow-ui-kit-empty-state.mjs +3 -3
  58. package/fesm2022/mesgflow-ui-kit-field.mjs +55 -14
  59. package/fesm2022/mesgflow-ui-kit-field.mjs.map +1 -1
  60. package/fesm2022/mesgflow-ui-kit-file-upload.mjs +356 -0
  61. package/fesm2022/mesgflow-ui-kit-file-upload.mjs.map +1 -0
  62. package/fesm2022/mesgflow-ui-kit-hover-card.mjs +6 -6
  63. package/fesm2022/mesgflow-ui-kit-i18n-tr.mjs +135 -0
  64. package/fesm2022/mesgflow-ui-kit-i18n-tr.mjs.map +1 -1
  65. package/fesm2022/mesgflow-ui-kit-icon.mjs +8 -3
  66. package/fesm2022/mesgflow-ui-kit-icon.mjs.map +1 -1
  67. package/fesm2022/mesgflow-ui-kit-icons-lucide.mjs +371 -0
  68. package/fesm2022/mesgflow-ui-kit-icons-lucide.mjs.map +1 -0
  69. package/fesm2022/mesgflow-ui-kit-inline-edit.mjs +279 -0
  70. package/fesm2022/mesgflow-ui-kit-inline-edit.mjs.map +1 -0
  71. package/fesm2022/mesgflow-ui-kit-input.mjs +162 -19
  72. package/fesm2022/mesgflow-ui-kit-input.mjs.map +1 -1
  73. package/fesm2022/mesgflow-ui-kit-kbd.mjs +3 -3
  74. package/fesm2022/mesgflow-ui-kit-lightbox.mjs +299 -0
  75. package/fesm2022/mesgflow-ui-kit-lightbox.mjs.map +1 -0
  76. package/fesm2022/mesgflow-ui-kit-link.mjs +5 -5
  77. package/fesm2022/mesgflow-ui-kit-link.mjs.map +1 -1
  78. package/fesm2022/mesgflow-ui-kit-listbox.mjs +151 -0
  79. package/fesm2022/mesgflow-ui-kit-listbox.mjs.map +1 -0
  80. package/fesm2022/mesgflow-ui-kit-mention.mjs +283 -0
  81. package/fesm2022/mesgflow-ui-kit-mention.mjs.map +1 -0
  82. package/fesm2022/mesgflow-ui-kit-menu.mjs +178 -14
  83. package/fesm2022/mesgflow-ui-kit-menu.mjs.map +1 -1
  84. package/fesm2022/mesgflow-ui-kit-nav-menu.mjs +276 -0
  85. package/fesm2022/mesgflow-ui-kit-nav-menu.mjs.map +1 -0
  86. package/fesm2022/mesgflow-ui-kit-notification-center.mjs +281 -0
  87. package/fesm2022/mesgflow-ui-kit-notification-center.mjs.map +1 -0
  88. package/fesm2022/mesgflow-ui-kit-number-input.mjs +9 -6
  89. package/fesm2022/mesgflow-ui-kit-number-input.mjs.map +1 -1
  90. package/fesm2022/mesgflow-ui-kit-otp-input.mjs +3 -3
  91. package/fesm2022/mesgflow-ui-kit-page-header.mjs +6 -6
  92. package/fesm2022/mesgflow-ui-kit-pagination.mjs +7 -6
  93. package/fesm2022/mesgflow-ui-kit-pagination.mjs.map +1 -1
  94. package/fesm2022/mesgflow-ui-kit-password-input.mjs +38 -68
  95. package/fesm2022/mesgflow-ui-kit-password-input.mjs.map +1 -1
  96. package/fesm2022/mesgflow-ui-kit-popover.mjs +12 -52
  97. package/fesm2022/mesgflow-ui-kit-popover.mjs.map +1 -1
  98. package/fesm2022/mesgflow-ui-kit-progress.mjs +164 -23
  99. package/fesm2022/mesgflow-ui-kit-progress.mjs.map +1 -1
  100. package/fesm2022/mesgflow-ui-kit-qr-code.mjs +766 -0
  101. package/fesm2022/mesgflow-ui-kit-qr-code.mjs.map +1 -0
  102. package/fesm2022/mesgflow-ui-kit-radio.mjs +10 -12
  103. package/fesm2022/mesgflow-ui-kit-radio.mjs.map +1 -1
  104. package/fesm2022/mesgflow-ui-kit-rating.mjs +4 -4
  105. package/fesm2022/mesgflow-ui-kit-rating.mjs.map +1 -1
  106. package/fesm2022/mesgflow-ui-kit-scroll-area.mjs +3 -3
  107. package/fesm2022/mesgflow-ui-kit-search-input.mjs +11 -7
  108. package/fesm2022/mesgflow-ui-kit-search-input.mjs.map +1 -1
  109. package/fesm2022/mesgflow-ui-kit-segmented-control.mjs +15 -11
  110. package/fesm2022/mesgflow-ui-kit-segmented-control.mjs.map +1 -1
  111. package/fesm2022/mesgflow-ui-kit-select.mjs +6 -5
  112. package/fesm2022/mesgflow-ui-kit-select.mjs.map +1 -1
  113. package/fesm2022/mesgflow-ui-kit-sidebar.mjs +24 -21
  114. package/fesm2022/mesgflow-ui-kit-sidebar.mjs.map +1 -1
  115. package/fesm2022/mesgflow-ui-kit-skeleton.mjs +6 -5
  116. package/fesm2022/mesgflow-ui-kit-skeleton.mjs.map +1 -1
  117. package/fesm2022/mesgflow-ui-kit-slider.mjs +253 -6
  118. package/fesm2022/mesgflow-ui-kit-slider.mjs.map +1 -1
  119. package/fesm2022/mesgflow-ui-kit-sortable.mjs +526 -0
  120. package/fesm2022/mesgflow-ui-kit-sortable.mjs.map +1 -0
  121. package/fesm2022/mesgflow-ui-kit-spinner.mjs +44 -15
  122. package/fesm2022/mesgflow-ui-kit-spinner.mjs.map +1 -1
  123. package/fesm2022/mesgflow-ui-kit-split-button.mjs +205 -0
  124. package/fesm2022/mesgflow-ui-kit-split-button.mjs.map +1 -0
  125. package/fesm2022/mesgflow-ui-kit-splitter.mjs +213 -6
  126. package/fesm2022/mesgflow-ui-kit-splitter.mjs.map +1 -1
  127. package/fesm2022/mesgflow-ui-kit-stat-tile.mjs +13 -6
  128. package/fesm2022/mesgflow-ui-kit-stat-tile.mjs.map +1 -1
  129. package/fesm2022/mesgflow-ui-kit-stepper.mjs +171 -64
  130. package/fesm2022/mesgflow-ui-kit-stepper.mjs.map +1 -1
  131. package/fesm2022/mesgflow-ui-kit-switch.mjs +4 -4
  132. package/fesm2022/mesgflow-ui-kit-switch.mjs.map +1 -1
  133. package/fesm2022/mesgflow-ui-kit-table.mjs +34 -28
  134. package/fesm2022/mesgflow-ui-kit-table.mjs.map +1 -1
  135. package/fesm2022/mesgflow-ui-kit-tabs.mjs +421 -180
  136. package/fesm2022/mesgflow-ui-kit-tabs.mjs.map +1 -1
  137. package/fesm2022/mesgflow-ui-kit-tag-input.mjs +9 -4
  138. package/fesm2022/mesgflow-ui-kit-tag-input.mjs.map +1 -1
  139. package/fesm2022/mesgflow-ui-kit-theme-switcher.mjs +3 -3
  140. package/fesm2022/mesgflow-ui-kit-theming.mjs +7 -7
  141. package/fesm2022/mesgflow-ui-kit-theming.mjs.map +1 -1
  142. package/fesm2022/mesgflow-ui-kit-time-picker.mjs +6 -6
  143. package/fesm2022/mesgflow-ui-kit-time-picker.mjs.map +1 -1
  144. package/fesm2022/mesgflow-ui-kit-timeline.mjs +3 -3
  145. package/fesm2022/mesgflow-ui-kit-toast.mjs +118 -35
  146. package/fesm2022/mesgflow-ui-kit-toast.mjs.map +1 -1
  147. package/fesm2022/mesgflow-ui-kit-toggle.mjs +12 -11
  148. package/fesm2022/mesgflow-ui-kit-toggle.mjs.map +1 -1
  149. package/fesm2022/mesgflow-ui-kit-toolbar.mjs +13 -11
  150. package/fesm2022/mesgflow-ui-kit-toolbar.mjs.map +1 -1
  151. package/fesm2022/mesgflow-ui-kit-tooltip.mjs +76 -53
  152. package/fesm2022/mesgflow-ui-kit-tooltip.mjs.map +1 -1
  153. package/fesm2022/mesgflow-ui-kit-tour.mjs +17 -29
  154. package/fesm2022/mesgflow-ui-kit-tour.mjs.map +1 -1
  155. package/fesm2022/mesgflow-ui-kit-transfer-list.mjs +288 -0
  156. package/fesm2022/mesgflow-ui-kit-transfer-list.mjs.map +1 -0
  157. package/fesm2022/mesgflow-ui-kit-tree-select.mjs +3 -3
  158. package/fesm2022/mesgflow-ui-kit-tree.mjs +4 -4
  159. package/fesm2022/mesgflow-ui-kit-tree.mjs.map +1 -1
  160. package/fesm2022/mesgflow-ui-kit-virtual-list.mjs +109 -0
  161. package/fesm2022/mesgflow-ui-kit-virtual-list.mjs.map +1 -0
  162. package/fesm2022/mesgflow-ui-kit.mjs +93 -12836
  163. package/fesm2022/mesgflow-ui-kit.mjs.map +1 -1
  164. package/package.json +91 -3
  165. package/schematics/collection.json +10 -0
  166. package/schematics/migration.json +10 -0
  167. package/schematics/migrations/v0-7.cjs +70 -0
  168. package/schematics/ng-add/index.cjs +234 -0
  169. package/schematics/ng-add/schema.json +43 -0
  170. package/tokens/color.css +96 -0
  171. package/tokens/controls.css +145 -0
  172. package/tokens/elevation.css +62 -6
  173. package/tokens/motion.css +304 -66
  174. package/tokens/radius.css +14 -0
  175. package/tokens.css +1 -0
  176. package/tokens.json +1583 -0
  177. package/types/mesgflow-ui-kit-agenda.d.ts +49 -0
  178. package/types/mesgflow-ui-kit-aspect-ratio.d.ts +18 -0
  179. package/types/mesgflow-ui-kit-blocks.d.ts +128 -0
  180. package/types/mesgflow-ui-kit-button.d.ts +23 -38
  181. package/types/mesgflow-ui-kit-card.d.ts +26 -16
  182. package/types/mesgflow-ui-kit-carousel.d.ts +51 -0
  183. package/types/mesgflow-ui-kit-checkbox.d.ts +8 -5
  184. package/types/mesgflow-ui-kit-code-block.d.ts +4 -1
  185. package/types/mesgflow-ui-kit-combobox.d.ts +47 -22
  186. package/types/mesgflow-ui-kit-command.d.ts +2 -2
  187. package/types/mesgflow-ui-kit-core.d.ts +279 -21
  188. package/types/mesgflow-ui-kit-countdown.d.ts +47 -0
  189. package/types/mesgflow-ui-kit-date-picker.d.ts +31 -1
  190. package/types/mesgflow-ui-kit-dialog.d.ts +122 -14
  191. package/types/mesgflow-ui-kit-drawer.d.ts +45 -0
  192. package/types/mesgflow-ui-kit-field.d.ts +17 -8
  193. package/types/mesgflow-ui-kit-file-upload.d.ts +64 -0
  194. package/types/mesgflow-ui-kit-hover-card.d.ts +2 -2
  195. package/types/mesgflow-ui-kit-icons-lucide.d.ts +27 -0
  196. package/types/mesgflow-ui-kit-inline-edit.d.ts +42 -0
  197. package/types/mesgflow-ui-kit-input.d.ts +64 -2
  198. package/types/mesgflow-ui-kit-lightbox.d.ts +54 -0
  199. package/types/mesgflow-ui-kit-listbox.d.ts +30 -0
  200. package/types/mesgflow-ui-kit-mention.d.ts +59 -0
  201. package/types/mesgflow-ui-kit-menu.d.ts +41 -2
  202. package/types/mesgflow-ui-kit-nav-menu.d.ts +58 -0
  203. package/types/mesgflow-ui-kit-notification-center.d.ts +41 -0
  204. package/types/mesgflow-ui-kit-number-input.d.ts +3 -1
  205. package/types/mesgflow-ui-kit-password-input.d.ts +35 -5
  206. package/types/mesgflow-ui-kit-popover.d.ts +13 -5
  207. package/types/mesgflow-ui-kit-progress.d.ts +33 -12
  208. package/types/mesgflow-ui-kit-qr-code.d.ts +160 -0
  209. package/types/mesgflow-ui-kit-radio.d.ts +2 -2
  210. package/types/mesgflow-ui-kit-search-input.d.ts +3 -1
  211. package/types/mesgflow-ui-kit-segmented-control.d.ts +4 -0
  212. package/types/mesgflow-ui-kit-sidebar.d.ts +1 -1
  213. package/types/mesgflow-ui-kit-slider.d.ts +60 -1
  214. package/types/mesgflow-ui-kit-sortable.d.ts +103 -0
  215. package/types/mesgflow-ui-kit-spinner.d.ts +5 -8
  216. package/types/mesgflow-ui-kit-split-button.d.ts +47 -0
  217. package/types/mesgflow-ui-kit-splitter.d.ts +64 -1
  218. package/types/mesgflow-ui-kit-stat-tile.d.ts +3 -0
  219. package/types/mesgflow-ui-kit-stepper.d.ts +54 -32
  220. package/types/mesgflow-ui-kit-table.d.ts +2 -0
  221. package/types/mesgflow-ui-kit-tabs.d.ts +193 -93
  222. package/types/mesgflow-ui-kit-tag-input.d.ts +3 -1
  223. package/types/mesgflow-ui-kit-toast.d.ts +48 -22
  224. package/types/mesgflow-ui-kit-tooltip.d.ts +15 -12
  225. package/types/mesgflow-ui-kit-transfer-list.d.ts +34 -0
  226. package/types/mesgflow-ui-kit-virtual-list.d.ts +35 -0
  227. package/types/mesgflow-ui-kit.d.ts +88 -5444
@@ -1,15 +1,119 @@
1
- import { DIALOG_DATA, DialogRef, Dialog as Dialog$1 } from '@angular/cdk/dialog';
2
1
  import * as i0 from '@angular/core';
3
- import { signal, inject, ElementRef, input, computed, Directive, output, viewChild, effect, DestroyRef, afterNextRender, Component, Injector, Injectable } from '@angular/core';
2
+ import { signal, computed, inject, ElementRef, input, Directive, booleanAttribute, output, viewChild, effect, DestroyRef, afterNextRender, Component, Injector, Injectable } from '@angular/core';
4
3
  import { Button } from '@mesgflow/ui-kit/button';
5
- import { glassSurface, MF_DIALOG_LABELS, cn } from '@mesgflow/ui-kit/core';
4
+ import { glassSurface, MF_DIALOG_LABELS, nextId, cn, exitDurationMs } from '@mesgflow/ui-kit/core';
6
5
  import { Icon } from '@mesgflow/ui-kit/icon';
6
+ import { DIALOG_DATA, DialogRef, Dialog as Dialog$1 } from '@angular/cdk/dialog';
7
7
  import * as i1 from '@angular/cdk/drag-drop';
8
8
  import { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
9
9
  import { cva } from 'class-variance-authority';
10
+ import { Directionality } from '@angular/cdk/bidi';
10
11
  import { BreakpointObserver } from '@angular/cdk/layout';
11
12
  import { createGlobalPositionStrategy } from '@angular/cdk/overlay';
12
13
 
14
+ /**
15
+ * `DialogService.open()`/`openDrawer()`'ın döndürdüğü, kite ait dialog referansı.
16
+ *
17
+ * CDK `DialogRef`'in günlük kullanılan yüzeyini (`close`, `closed`,
18
+ * `componentInstance`, `disableClose`, `backdropClick`, `keydownEvents` …)
19
+ * birebir DELEGE eder — yani eski `ref.closed.subscribe(...)` kodu aynen derlenir.
20
+ * Üstüne kitin kendi dünyasını ekler:
21
+ *
22
+ * - `afterClosed()` — `await` edilebilir sonuç (çıkış animasyonu BİTTİKTEN sonra çözülür).
23
+ * - `state` — `'open' | 'closing' | 'closed'` signal'i (şablonda/`computed`'ta okunur).
24
+ * - `surface` — boyut/maximize/kirli-form durumuna tipli erişim (`setSize`, `toggleMaximize`,
25
+ * `registerDirty`, `markClean` kısayolları).
26
+ * - `cdk` — ham CDK referansı (kaçış kapısı; ör. `updatePosition()`).
27
+ *
28
+ * `close()` İDEMPOTENT'tir: çıkış animasyonu sürerken ya da kirli-form onayı
29
+ * açıkken gelen ek çağrılar yok sayılır (bkz. `dialog.service.ts` `closePredicate`).
30
+ *
31
+ * İçerik component'i içinde `injectDialogRef<Sonuç>()` ile alınır.
32
+ */
33
+ class MfDialogRef {
34
+ cdk;
35
+ surface;
36
+ closed;
37
+ backdropClick;
38
+ keydownEvents;
39
+ outsidePointerEvents;
40
+ overlayRef;
41
+ id;
42
+ isClosed = signal(false, /* @ts-ignore */
43
+ ...(ngDevMode ? [{ debugName: "isClosed" }] : /* istanbul ignore next */ []));
44
+ result;
45
+ /** Dialog'un yaşam döngüsü — `closing` çıkış animasyonu boyunca. */
46
+ state;
47
+ constructor(cdk, surface) {
48
+ this.cdk = cdk;
49
+ this.surface = surface;
50
+ this.closed = cdk.closed;
51
+ this.backdropClick = cdk.backdropClick;
52
+ this.keydownEvents = cdk.keydownEvents;
53
+ this.outsidePointerEvents = cdk.outsidePointerEvents;
54
+ this.overlayRef = cdk.overlayRef;
55
+ this.id = cdk.id;
56
+ this.state = computed(() => this.isClosed() ? 'closed' : surface.closing() ? 'closing' : 'open', /* @ts-ignore */
57
+ ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
58
+ this.result = new Promise((resolve) => cdk.closed.subscribe((value) => {
59
+ this.isClosed.set(true);
60
+ resolve(value);
61
+ }));
62
+ }
63
+ /** Açılan component örneği (şablonla açıldıysa ve kapandıktan sonra `null`). */
64
+ get componentInstance() {
65
+ return this.cdk.componentInstance;
66
+ }
67
+ get componentRef() {
68
+ return this.cdk.componentRef;
69
+ }
70
+ /** `true` iken ESC/backdrop kapatmaz; programatik `close()` yine çalışır. */
71
+ get disableClose() {
72
+ return this.cdk.disableClose;
73
+ }
74
+ set disableClose(value) {
75
+ this.cdk.disableClose = value;
76
+ }
77
+ /** Dialog'u (çıkış animasyonu + kirli-form koruması üzerinden) kapatır. İdempotent. */
78
+ close(result) {
79
+ if (this.isClosed())
80
+ return;
81
+ this.cdk.close(result);
82
+ }
83
+ /** Kapanış tamamlandığında (animasyon dahil) sonuçla çözülür; ESC/backdrop'ta `undefined`. */
84
+ afterClosed() {
85
+ return this.result;
86
+ }
87
+ /** Açıkken genişlik basamağını değiştirir (`sm`…`xl`, `full`). */
88
+ setSize(size) {
89
+ this.surface.size.set(size);
90
+ }
91
+ toggleMaximize() {
92
+ this.surface.toggleMaximize();
93
+ }
94
+ /** Kirli-form sorusunu kaydeder — ESC/backdrop/X kapanışında `true` dönerse onay sorulur. */
95
+ registerDirty(check) {
96
+ this.surface.registerDirty(check);
97
+ }
98
+ /** Başarılı kayıttan hemen önce — sonraki `close()` kirli-form onayı sormaz. */
99
+ markClean() {
100
+ this.surface.markClean();
101
+ }
102
+ }
103
+ /**
104
+ * `DIALOG_DATA`'nın kite ait adı — AYNI token nesnesi, CDK'dan ayrıca import
105
+ * etmeye gerek kalmasın diye. `inject(MF_DIALOG_DATA)` ≡ `injectDialogData()`.
106
+ */
107
+ const MF_DIALOG_DATA = DIALOG_DATA;
108
+ /** İçerik component'inde `DialogService.open(..., { data })` ile geçilen veriyi okur. */
109
+ function injectDialogData() {
110
+ return inject(DIALOG_DATA);
111
+ }
112
+ /** İçerik component'inde kendi dialog referansını alır — `ref.close(sonuç)`. */
113
+ function injectDialogRef() {
114
+ return inject(MfDialogRef);
115
+ }
116
+
13
117
  /**
14
118
  * Dialog başına TEK instance — `DialogService.open()` her açılışta yeni bir
15
119
  * tane üretip `options`'tan doldurur, CDK `DialogConfig.providers` ile o
@@ -30,6 +134,9 @@ class DialogSurface {
30
134
  ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
31
135
  placement = signal('center', /* @ts-ignore */
32
136
  ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
137
+ /** Çekmecenin fiziksel kenarı (`center`'da `null`) — `DialogService` yön bilgisiyle çözer. */
138
+ side = signal(null, /* @ts-ignore */
139
+ ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
33
140
  maximizable = signal(false, /* @ts-ignore */
34
141
  ...(ngDevMode ? [{ debugName: "maximizable" }] : /* istanbul ignore next */ []));
35
142
  draggable = signal(false, /* @ts-ignore */
@@ -158,10 +265,10 @@ class DialogResizeHandle {
158
265
  height: Math.min(Math.max(height, MIN_HEIGHT), maxHeight),
159
266
  });
160
267
  }
161
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: DialogResizeHandle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
162
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: DialogResizeHandle, isStandalone: true, selector: "[mfDialogResizeHandle]", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "slider", "tabindex": "0" }, listeners: { "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp($event)", "pointercancel": "onPointerUp($event)", "keydown": "onKeydown($event)" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-valuenow": "ariaValueNow()" } }, ngImport: i0 });
268
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: DialogResizeHandle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
269
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: DialogResizeHandle, isStandalone: true, selector: "[mfDialogResizeHandle]", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "slider", "tabindex": "0" }, listeners: { "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp($event)", "pointercancel": "onPointerUp($event)", "keydown": "onKeydown($event)" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-valuenow": "ariaValueNow()" } }, ngImport: i0 });
163
270
  }
164
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: DialogResizeHandle, decorators: [{
271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: DialogResizeHandle, decorators: [{
165
272
  type: Directive,
166
273
  args: [{
167
274
  selector: '[mfDialogResizeHandle]',
@@ -238,16 +345,52 @@ const dialogVariants = cva(`relative flex w-full flex-col overflow-hidden border
238
345
  normal: 'rounded-xl max-h-[85vh]',
239
346
  maximized: 'h-[100dvh] max-h-none w-screen max-w-none rounded-none supports-[backdrop-filter]:bg-surface supports-[backdrop-filter]:backdrop-blur-none',
240
347
  sheet: 'w-screen rounded-t-xl rounded-b-none max-h-[92dvh]',
241
- drawer: 'h-[100dvh] max-h-none rounded-l-xl rounded-r-none',
348
+ drawer: 'max-h-none',
349
+ },
350
+ /** Çekmecenin fiziksel kenarı — yalnızca `state: 'drawer'` ile anlamlı. */
351
+ side: {
352
+ none: '',
353
+ right: '',
354
+ left: '',
355
+ top: '',
356
+ bottom: '',
242
357
  },
243
358
  },
244
359
  compoundVariants: [
245
- { state: 'drawer', size: 'sm', class: 'w-[min(440px,calc(100vw-2rem))]' },
246
- { state: 'drawer', size: 'md', class: 'w-[min(560px,calc(100vw-2rem))]' },
247
- { state: 'drawer', size: 'lg', class: 'w-[min(720px,calc(100vw-2rem))]' },
248
- { state: 'drawer', size: 'xl', class: 'w-[min(960px,calc(100vw-2rem))]' },
360
+ // Yan çekmeceler: tam yükseklik, boyut ölçeği GENİŞLİK olarak.
361
+ { state: 'drawer', side: ['left', 'right'], class: 'h-[100dvh]' },
362
+ { state: 'drawer', side: 'right', class: 'rounded-l-xl rounded-r-none' },
363
+ { state: 'drawer', side: 'left', class: 'rounded-r-xl rounded-l-none' },
364
+ {
365
+ state: 'drawer',
366
+ side: ['left', 'right'],
367
+ size: 'sm',
368
+ class: 'w-[min(440px,calc(100vw-2rem))]',
369
+ },
370
+ {
371
+ state: 'drawer',
372
+ side: ['left', 'right'],
373
+ size: 'md',
374
+ class: 'w-[min(560px,calc(100vw-2rem))]',
375
+ },
376
+ {
377
+ state: 'drawer',
378
+ side: ['left', 'right'],
379
+ size: 'lg',
380
+ class: 'w-[min(720px,calc(100vw-2rem))]',
381
+ },
382
+ {
383
+ state: 'drawer',
384
+ side: ['left', 'right'],
385
+ size: 'xl',
386
+ class: 'w-[min(960px,calc(100vw-2rem))]',
387
+ },
388
+ // Üst/alt paneller: tam genişlik, içerik yüksekliğinde (en çok %85).
389
+ { state: 'drawer', side: ['top', 'bottom'], class: 'w-screen max-w-none max-h-[85dvh]' },
390
+ { state: 'drawer', side: 'top', class: 'rounded-b-xl rounded-t-none' },
391
+ { state: 'drawer', side: 'bottom', class: 'rounded-t-xl rounded-b-none' },
249
392
  ],
250
- defaultVariants: { size: 'md', state: 'normal' },
393
+ defaultVariants: { size: 'md', state: 'normal', side: 'none' },
251
394
  });
252
395
 
253
396
  const DRAG_MIN_VISIBLE = 48;
@@ -288,12 +431,23 @@ class Dialog {
288
431
  */
289
432
  fillBody = input(false, /* @ts-ignore */
290
433
  ...(ngDevMode ? [{ debugName: "fillBody" }] : /* istanbul ignore next */ []));
434
+ /**
435
+ * `true` (varsayılan): kapat (X) düğmesi `close` olayını yayınladıktan SONRA
436
+ * dialog'u kendisi de kapatır (`MfDialogRef.close()` — idempotent, tüketicinin
437
+ * `(close)` handler'ında sonuçla yaptığı kapanış önce davranır ve kazanır).
438
+ * `false`: yalnızca `close` yayınlanır — kapanışı tamamen tüketici yönetir.
439
+ */
440
+ autoClose = input(true, { ...(ngDevMode ? { debugName: "autoClose" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
291
441
  // `close` adı native DOM `close` olayıyla çakışıyor (@angular-eslint/no-output-native);
292
442
  // mevcut public API — yeniden adlandırma kırıcı, ileri bir sürümde ele alınacak.
293
443
  // eslint-disable-next-line @angular-eslint/no-output-native
294
444
  close = output();
295
445
  surface = inject(DialogSurface);
296
446
  labels = inject(MF_DIALOG_LABELS);
447
+ /** Görünür başlığın id'si — CDK konteynerinin `aria-labelledby`'ı buna bağlanır. */
448
+ titleId = nextId('mf-dialog-title');
449
+ mfRef = inject(MfDialogRef, { optional: true });
450
+ cdkRef = inject(DialogRef, { optional: true });
297
451
  elementRef = inject(ElementRef);
298
452
  cdkDrag = inject(CdkDrag, { self: true });
299
453
  scrollBody = viewChild('scrollBody', /* @ts-ignore */
@@ -307,7 +461,7 @@ class Dialog {
307
461
  return 'sheet';
308
462
  if (this.surface.maximized() || this.size() === 'full')
309
463
  return 'maximized';
310
- if (this.surface.placement() === 'right')
464
+ if (this.surface.side())
311
465
  return 'drawer';
312
466
  return 'normal';
313
467
  }, /* @ts-ignore */
@@ -322,8 +476,18 @@ class Dialog {
322
476
  hostClasses = computed(() => {
323
477
  const closing = this.surface.closing();
324
478
  const state = this.stateVariant();
325
- const animateBase = state === 'sheet' ? 'sheet' : state === 'drawer' ? 'drawer' : 'dialog';
326
- return cn(dialogVariants({ size: this.size() ?? this.surface.size(), state }), state === 'normal' && this.surface.customSize() ? 'max-w-none max-h-none' : '', `animate-${animateBase}-${closing ? 'out' : 'in'}`);
479
+ const side = state === 'drawer' ? (this.surface.side() ?? 'right') : null;
480
+ // Kenar başına FİZİKSEL kayma (host `--mf-dir: 1` sabitler — bkz. host bağlaması).
481
+ const animateBase = state === 'sheet' || side === 'bottom'
482
+ ? 'sheet'
483
+ : side === 'right'
484
+ ? 'drawer'
485
+ : side === 'left'
486
+ ? 'drawer-start'
487
+ : side === 'top'
488
+ ? 'drawer-top'
489
+ : 'dialog';
490
+ return cn(dialogVariants({ size: this.size() ?? this.surface.size(), state, side: side ?? 'none' }), state === 'normal' && this.surface.customSize() ? 'max-w-none max-h-none' : '', `animate-${animateBase}-${closing ? 'out' : 'in'}`);
327
491
  }, /* @ts-ignore */
328
492
  ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
329
493
  customWidth = computed(() => this.stateVariant() === 'normal' ? this.surface.customSize()?.width : undefined, /* @ts-ignore */
@@ -355,6 +519,17 @@ class Dialog {
355
519
  this.surface.customSize.set(null);
356
520
  }
357
521
  });
522
+ // Erişilebilir ad: `ariaLabel` verilmemiş bir dialog'da CDK konteyneri görünür
523
+ // başlığa `aria-labelledby` ile bağlanır (MatDialogTitle'ın kullandığı AYNI kanca).
524
+ // Başlık sonradan boşalırsa/değişirse effect cleanup'ı kaydı geri alır.
525
+ effect((onCleanup) => {
526
+ // `DialogRef.containerInstance` tipi bu (CdkDialogContainer'a ait) metotları taşımıyor.
527
+ const container = this.cdkRef?.containerInstance;
528
+ if (!this.title() || !container?._addAriaLabelledBy)
529
+ return;
530
+ container._addAriaLabelledBy(this.titleId);
531
+ onCleanup(() => container._removeAriaLabelledBy?.(this.titleId));
532
+ });
358
533
  const destroyRef = inject(DestroyRef);
359
534
  afterNextRender(() => {
360
535
  this.updateScrollShadow();
@@ -366,6 +541,12 @@ class Dialog {
366
541
  destroyRef.onDestroy(() => observer.disconnect());
367
542
  });
368
543
  }
544
+ /** Kapat (X): önce `close` olayı (tüketici sonuçla kapatabilsin), sonra — `autoClose` ise — ref'in kendisi. */
545
+ onDismiss() {
546
+ this.close.emit();
547
+ if (this.autoClose())
548
+ (this.mfRef ?? this.cdkRef)?.close();
549
+ }
369
550
  updateScrollShadow() {
370
551
  const el = this.scrollBody()?.nativeElement;
371
552
  if (!el)
@@ -383,15 +564,15 @@ class Dialog {
383
564
  requestSubmit() {
384
565
  this.elementRef.nativeElement.querySelector('form')?.requestSubmit();
385
566
  }
386
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: Dialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
387
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: Dialog, isStandalone: true, selector: "mf-dialog", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fillBody: { classPropertyName: "fillBody", publicName: "fillBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close" }, host: { listeners: { "keydown.control.enter": "requestSubmit()", "keydown.meta.enter": "requestSubmit()" }, properties: { "class": "hostClasses()", "style.width.px": "customWidth()", "style.height.px": "customHeight()" } }, providers: [
567
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: Dialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
568
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: Dialog, isStandalone: true, selector: "mf-dialog", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fillBody: { classPropertyName: "fillBody", publicName: "fillBody", isSignal: true, isRequired: false, transformFunction: null }, autoClose: { classPropertyName: "autoClose", publicName: "autoClose", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close" }, host: { listeners: { "keydown.control.enter": "requestSubmit()", "keydown.meta.enter": "requestSubmit()" }, properties: { "class": "hostClasses()", "style.width.px": "customWidth()", "style.height.px": "customHeight()", "style.--mf-dir": "stateVariant() === 'drawer' ? 1 : null" } }, providers: [
388
569
  {
389
570
  provide: DialogSurface,
390
571
  useFactory: () => inject(DialogSurface, { optional: true, skipSelf: true }) ?? new DialogSurface(),
391
572
  },
392
- ], viewQueries: [{ propertyName: "scrollBody", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }], exportAs: ["mfDialog"], hostDirectives: [{ directive: i1.CdkDrag }], ngImport: i0, template: "<div\r\n class=\"flex shrink-0 items-start justify-between gap-3 px-6 pt-5 pb-4\"\r\n [class.border-b]=\"headerBorder()\"\r\n [class.border-border]=\"headerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-header]\">\r\n @if (icon()) {\r\n <span\r\n class=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-surface-alt text-fg-muted\"\r\n >\r\n <span mfIcon [size]=\"20\">{{ icon() }}</span>\r\n </span>\r\n }\r\n <div\r\n cdkDragHandle\r\n class=\"min-w-0 flex-1 pt-0.5\"\r\n [class.cursor-grab]=\"dragEnabled()\"\r\n [class.active:cursor-grabbing]=\"dragEnabled()\"\r\n >\r\n @if (title()) {\r\n <h2 class=\"truncate font-display text-title text-fg\">{{ title() }}</h2>\r\n }\r\n @if (subtitle()) {\r\n <p class=\"mt-0.5 truncate text-sm text-fg-muted\">{{ subtitle() }}</p>\r\n }\r\n </div>\r\n </ng-content>\r\n\r\n <div class=\"flex shrink-0 items-center gap-1\">\r\n @if (maximizeVisible()) {\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"surface.maximized() ? labels().fullscreenExit : labels().fullscreenEnter\"\r\n (click)=\"surface.toggleMaximize()\"\r\n >\r\n <span mfIcon [size]=\"18\">{{ surface.maximized() ? 'fullscreen_exit' : 'fullscreen' }}</span>\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"labels().close\"\r\n (click)=\"close.emit()\"\r\n >\r\n <span mfIcon [size]=\"20\">close</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div\r\n #scrollBody\r\n class=\"flex-1 min-h-0 px-6\"\r\n [class.py-4]=\"framed()\"\r\n [class.overflow-y-auto]=\"!fillBody()\"\r\n [class.flex]=\"fillBody()\"\r\n [class.flex-col]=\"fillBody()\"\r\n [class.overflow-hidden]=\"fillBody()\"\r\n (scroll)=\"updateScrollShadow()\"\r\n>\r\n <ng-content />\r\n</div>\r\n\r\n<div\r\n class=\"shrink-0 px-6 py-4 [&:not(:has(*))]:hidden\"\r\n [class.border-t]=\"footerBorder()\"\r\n [class.border-border]=\"footerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-footer]\" />\r\n</div>\r\n\r\n@if (resizeHandleVisible()) {\r\n <button\r\n mfDialogResizeHandle\r\n type=\"button\"\r\n [ariaLabel]=\"labels().resize\"\r\n class=\"absolute right-1 bottom-1 flex h-4 w-4 cursor-se-resize items-center justify-center rounded-xs text-fg-subtle hover:text-fg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring\"\r\n >\r\n <span mfIcon [size]=\"14\">south_east</span>\r\n </button>\r\n}\r\n", dependencies: [{ kind: "component", type: Button, selector: "button[mfButton], a[mfButton]", inputs: ["tone", "appearance", "size", "shape", "type", "loading", "iconStart", "iconEnd"], exportAs: ["mfButton"] }, { kind: "directive", type: Icon, selector: "span[mfIcon]", inputs: ["size", "filled"] }, { kind: "directive", type: DialogResizeHandle, selector: "[mfDialogResizeHandle]", inputs: ["ariaLabel"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }] });
573
+ ], viewQueries: [{ propertyName: "scrollBody", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }], exportAs: ["mfDialog"], hostDirectives: [{ directive: i1.CdkDrag }], ngImport: i0, template: "<div\r\n class=\"flex shrink-0 items-start justify-between gap-3 px-6 pt-5 pb-4\"\r\n [class.border-b]=\"headerBorder()\"\r\n [class.border-border]=\"headerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-header]\">\r\n @if (icon()) {\r\n <span\r\n class=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-surface-alt text-fg-muted\"\r\n >\r\n <span mfIcon [size]=\"20\">{{ icon() }}</span>\r\n </span>\r\n }\r\n <div\r\n cdkDragHandle\r\n class=\"min-w-0 flex-1 pt-0.5\"\r\n [class.cursor-grab]=\"dragEnabled()\"\r\n [class.active:cursor-grabbing]=\"dragEnabled()\"\r\n >\r\n @if (title()) {\r\n <h2 [id]=\"titleId\" class=\"truncate font-display text-title text-fg\">{{ title() }}</h2>\r\n }\r\n @if (subtitle()) {\r\n <p class=\"mt-0.5 truncate text-sm text-fg-muted\">{{ subtitle() }}</p>\r\n }\r\n </div>\r\n </ng-content>\r\n\r\n <div class=\"flex shrink-0 items-center gap-1\">\r\n @if (maximizeVisible()) {\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"surface.maximized() ? labels().fullscreenExit : labels().fullscreenEnter\"\r\n (click)=\"surface.toggleMaximize()\"\r\n >\r\n <span mfIcon [size]=\"18\">{{ surface.maximized() ? 'fullscreen_exit' : 'fullscreen' }}</span>\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"labels().close\"\r\n (click)=\"onDismiss()\"\r\n >\r\n <span mfIcon [size]=\"20\">close</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div\r\n #scrollBody\r\n class=\"flex-1 min-h-0 px-6\"\r\n [class.py-4]=\"framed()\"\r\n [class.overflow-y-auto]=\"!fillBody()\"\r\n [class.flex]=\"fillBody()\"\r\n [class.flex-col]=\"fillBody()\"\r\n [class.overflow-hidden]=\"fillBody()\"\r\n (scroll)=\"updateScrollShadow()\"\r\n>\r\n <ng-content />\r\n</div>\r\n\r\n<div\r\n class=\"shrink-0 px-6 py-4 [&:not(:has(*))]:hidden\"\r\n [class.border-t]=\"footerBorder()\"\r\n [class.border-border]=\"footerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-footer]\" />\r\n</div>\r\n\r\n@if (resizeHandleVisible()) {\r\n <button\r\n mfDialogResizeHandle\r\n type=\"button\"\r\n [ariaLabel]=\"labels().resize\"\r\n class=\"absolute right-1 bottom-1 flex h-4 w-4 cursor-se-resize items-center justify-center rounded-xs text-fg-subtle hover:text-fg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring\"\r\n >\r\n <span mfIcon [size]=\"14\">south_east</span>\r\n </button>\r\n}\r\n", dependencies: [{ kind: "component", type: Button, selector: "button[mfButton], a[mfButton]", inputs: ["tone", "appearance", "size", "shape", "type", "loading", "iconStart", "iconEnd"], exportAs: ["mfButton"] }, { kind: "directive", type: Icon, selector: "span[mfIcon]", inputs: ["size", "filled"] }, { kind: "directive", type: DialogResizeHandle, selector: "[mfDialogResizeHandle]", inputs: ["ariaLabel"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }] });
393
574
  }
394
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: Dialog, decorators: [{
575
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: Dialog, decorators: [{
395
576
  type: Component,
396
577
  args: [{ selector: 'mf-dialog', exportAs: 'mfDialog', imports: [Button, Icon, DialogResizeHandle, CdkDragHandle], hostDirectives: [CdkDrag], providers: [
397
578
  {
@@ -402,10 +583,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
402
583
  '[class]': 'hostClasses()',
403
584
  '[style.width.px]': 'customWidth()',
404
585
  '[style.height.px]': 'customHeight()',
586
+ // Çekmece kenarları FİZİKSEL çözülür (`DialogService` RTL'i zaten hesaba kattı) —
587
+ // motion.css'in `--mf-dir` çevirmesi burada çift çevirme yapmasın.
588
+ '[style.--mf-dir]': "stateVariant() === 'drawer' ? 1 : null",
405
589
  '(keydown.control.enter)': 'requestSubmit()',
406
590
  '(keydown.meta.enter)': 'requestSubmit()',
407
- }, template: "<div\r\n class=\"flex shrink-0 items-start justify-between gap-3 px-6 pt-5 pb-4\"\r\n [class.border-b]=\"headerBorder()\"\r\n [class.border-border]=\"headerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-header]\">\r\n @if (icon()) {\r\n <span\r\n class=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-surface-alt text-fg-muted\"\r\n >\r\n <span mfIcon [size]=\"20\">{{ icon() }}</span>\r\n </span>\r\n }\r\n <div\r\n cdkDragHandle\r\n class=\"min-w-0 flex-1 pt-0.5\"\r\n [class.cursor-grab]=\"dragEnabled()\"\r\n [class.active:cursor-grabbing]=\"dragEnabled()\"\r\n >\r\n @if (title()) {\r\n <h2 class=\"truncate font-display text-title text-fg\">{{ title() }}</h2>\r\n }\r\n @if (subtitle()) {\r\n <p class=\"mt-0.5 truncate text-sm text-fg-muted\">{{ subtitle() }}</p>\r\n }\r\n </div>\r\n </ng-content>\r\n\r\n <div class=\"flex shrink-0 items-center gap-1\">\r\n @if (maximizeVisible()) {\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"surface.maximized() ? labels().fullscreenExit : labels().fullscreenEnter\"\r\n (click)=\"surface.toggleMaximize()\"\r\n >\r\n <span mfIcon [size]=\"18\">{{ surface.maximized() ? 'fullscreen_exit' : 'fullscreen' }}</span>\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"labels().close\"\r\n (click)=\"close.emit()\"\r\n >\r\n <span mfIcon [size]=\"20\">close</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div\r\n #scrollBody\r\n class=\"flex-1 min-h-0 px-6\"\r\n [class.py-4]=\"framed()\"\r\n [class.overflow-y-auto]=\"!fillBody()\"\r\n [class.flex]=\"fillBody()\"\r\n [class.flex-col]=\"fillBody()\"\r\n [class.overflow-hidden]=\"fillBody()\"\r\n (scroll)=\"updateScrollShadow()\"\r\n>\r\n <ng-content />\r\n</div>\r\n\r\n<div\r\n class=\"shrink-0 px-6 py-4 [&:not(:has(*))]:hidden\"\r\n [class.border-t]=\"footerBorder()\"\r\n [class.border-border]=\"footerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-footer]\" />\r\n</div>\r\n\r\n@if (resizeHandleVisible()) {\r\n <button\r\n mfDialogResizeHandle\r\n type=\"button\"\r\n [ariaLabel]=\"labels().resize\"\r\n class=\"absolute right-1 bottom-1 flex h-4 w-4 cursor-se-resize items-center justify-center rounded-xs text-fg-subtle hover:text-fg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring\"\r\n >\r\n <span mfIcon [size]=\"14\">south_east</span>\r\n </button>\r\n}\r\n" }]
408
- }], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fillBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillBody", required: false }] }], close: [{ type: i0.Output, args: ["close"] }], scrollBody: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }] } });
591
+ }, template: "<div\r\n class=\"flex shrink-0 items-start justify-between gap-3 px-6 pt-5 pb-4\"\r\n [class.border-b]=\"headerBorder()\"\r\n [class.border-border]=\"headerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-header]\">\r\n @if (icon()) {\r\n <span\r\n class=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-surface-alt text-fg-muted\"\r\n >\r\n <span mfIcon [size]=\"20\">{{ icon() }}</span>\r\n </span>\r\n }\r\n <div\r\n cdkDragHandle\r\n class=\"min-w-0 flex-1 pt-0.5\"\r\n [class.cursor-grab]=\"dragEnabled()\"\r\n [class.active:cursor-grabbing]=\"dragEnabled()\"\r\n >\r\n @if (title()) {\r\n <h2 [id]=\"titleId\" class=\"truncate font-display text-title text-fg\">{{ title() }}</h2>\r\n }\r\n @if (subtitle()) {\r\n <p class=\"mt-0.5 truncate text-sm text-fg-muted\">{{ subtitle() }}</p>\r\n }\r\n </div>\r\n </ng-content>\r\n\r\n <div class=\"flex shrink-0 items-center gap-1\">\r\n @if (maximizeVisible()) {\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"surface.maximized() ? labels().fullscreenExit : labels().fullscreenEnter\"\r\n (click)=\"surface.toggleMaximize()\"\r\n >\r\n <span mfIcon [size]=\"18\">{{ surface.maximized() ? 'fullscreen_exit' : 'fullscreen' }}</span>\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"icon\"\r\n shape=\"square\"\r\n type=\"button\"\r\n [attr.aria-label]=\"labels().close\"\r\n (click)=\"onDismiss()\"\r\n >\r\n <span mfIcon [size]=\"20\">close</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div\r\n #scrollBody\r\n class=\"flex-1 min-h-0 px-6\"\r\n [class.py-4]=\"framed()\"\r\n [class.overflow-y-auto]=\"!fillBody()\"\r\n [class.flex]=\"fillBody()\"\r\n [class.flex-col]=\"fillBody()\"\r\n [class.overflow-hidden]=\"fillBody()\"\r\n (scroll)=\"updateScrollShadow()\"\r\n>\r\n <ng-content />\r\n</div>\r\n\r\n<div\r\n class=\"shrink-0 px-6 py-4 [&:not(:has(*))]:hidden\"\r\n [class.border-t]=\"footerBorder()\"\r\n [class.border-border]=\"footerBorder()\"\r\n>\r\n <ng-content select=\"[dialog-footer]\" />\r\n</div>\r\n\r\n@if (resizeHandleVisible()) {\r\n <button\r\n mfDialogResizeHandle\r\n type=\"button\"\r\n [ariaLabel]=\"labels().resize\"\r\n class=\"absolute right-1 bottom-1 flex h-4 w-4 cursor-se-resize items-center justify-center rounded-xs text-fg-subtle hover:text-fg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring\"\r\n >\r\n <span mfIcon [size]=\"14\">south_east</span>\r\n </button>\r\n}\r\n" }]
592
+ }], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fillBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillBody", required: false }] }], autoClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClose", required: false }] }], close: [{ type: i0.Output, args: ["close"] }], scrollBody: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }] } });
409
593
 
410
594
  const TONE_ICON = {
411
595
  danger: 'warning',
@@ -431,8 +615,8 @@ const TONE_BADGE_CLASS = {
431
615
  * kendi çiziyor.
432
616
  */
433
617
  class ConfirmDialog {
434
- data = inject(DIALOG_DATA);
435
- dialogRef = inject((DialogRef));
618
+ data = injectDialogData();
619
+ dialogRef = injectDialogRef();
436
620
  labels = inject(MF_DIALOG_LABELS);
437
621
  tone = computed(() => this.data.tone ?? 'neutral', /* @ts-ignore */
438
622
  ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
@@ -477,17 +661,28 @@ class ConfirmDialog {
477
661
  this.dialogRef.disableClose = false;
478
662
  }
479
663
  }
480
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ConfirmDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
481
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ConfirmDialog, isStandalone: true, selector: "mf-confirm-dialog", host: { classAttribute: "contents" }, ngImport: i0, template: "<mf-dialog size=\"sm\" (close)=\"onCancel()\">\r\n <div dialog-header class=\"flex items-start gap-3\">\r\n <span\r\n class=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-md\"\r\n [class]=\"toneBadgeClass()\"\r\n >\r\n <span mfIcon [size]=\"22\">{{ toneIcon() }}</span>\r\n </span>\r\n <div class=\"min-w-0 flex-1 pt-1.5\">\r\n <h2 class=\"truncate font-display text-title text-fg\">{{ data.title }}</h2>\r\n </div>\r\n </div>\r\n\r\n <p class=\"text-sm text-fg-muted\">{{ data.content }}</p>\r\n\r\n @if (actionError()) {\r\n <p class=\"mt-3 text-sm text-danger\">{{ actionError() }}</p>\r\n }\r\n\r\n <div dialog-footer class=\"flex justify-end gap-2\">\r\n @if (!data.alert) {\r\n <button\r\n mfButton\r\n appearance=\"outlined\"\r\n tone=\"neutral\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n (click)=\"onCancel()\"\r\n >\r\n {{ data.cancelLabel ?? labels().confirmCancel }}\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n [tone]=\"confirmTone()\"\r\n appearance=\"filled\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n (click)=\"onConfirm()\"\r\n >\r\n @if (submitting()) {\r\n <span mfIcon [size]=\"16\" class=\"animate-spin\">progress_activity</span>\r\n }\r\n {{ data.confirmLabel ?? (data.alert ? labels().confirmOk : labels().confirmConfirm) }}\r\n </button>\r\n </div>\r\n</mf-dialog>\r\n", dependencies: [{ kind: "component", type: Dialog, selector: "mf-dialog", inputs: ["title", "subtitle", "icon", "size", "fillBody"], outputs: ["close"], exportAs: ["mfDialog"] }, { kind: "component", type: Button, selector: "button[mfButton], a[mfButton]", inputs: ["tone", "appearance", "size", "shape", "type", "loading", "iconStart", "iconEnd"], exportAs: ["mfButton"] }, { kind: "directive", type: Icon, selector: "span[mfIcon]", inputs: ["size", "filled"] }] });
664
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ConfirmDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
665
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: ConfirmDialog, isStandalone: true, selector: "mf-confirm-dialog", host: { classAttribute: "contents" }, ngImport: i0, template: "<mf-dialog size=\"sm\" (close)=\"onCancel()\">\r\n <div dialog-header class=\"flex items-start gap-3\">\r\n <span\r\n class=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-md\"\r\n [class]=\"toneBadgeClass()\"\r\n >\r\n <span mfIcon [size]=\"22\">{{ toneIcon() }}</span>\r\n </span>\r\n <div class=\"min-w-0 flex-1 pt-1.5\">\r\n <h2 class=\"truncate font-display text-title text-fg\">{{ data.title }}</h2>\r\n </div>\r\n </div>\r\n\r\n <p class=\"text-sm text-fg-muted\">{{ data.content }}</p>\r\n\r\n @if (actionError()) {\r\n <p class=\"mt-3 text-sm text-danger\">{{ actionError() }}</p>\r\n }\r\n\r\n <div dialog-footer class=\"flex justify-end gap-2\">\r\n @if (!data.alert) {\r\n <button\r\n mfButton\r\n appearance=\"outlined\"\r\n tone=\"neutral\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n (click)=\"onCancel()\"\r\n >\r\n {{ data.cancelLabel ?? labels().confirmCancel }}\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n [tone]=\"confirmTone()\"\r\n appearance=\"filled\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n [loading]=\"submitting()\"\r\n (click)=\"onConfirm()\"\r\n >\r\n {{ data.confirmLabel ?? (data.alert ? labels().confirmOk : labels().confirmConfirm) }}\r\n </button>\r\n </div>\r\n</mf-dialog>\r\n", dependencies: [{ kind: "component", type: Dialog, selector: "mf-dialog", inputs: ["title", "subtitle", "icon", "size", "fillBody", "autoClose"], outputs: ["close"], exportAs: ["mfDialog"] }, { kind: "component", type: Button, selector: "button[mfButton], a[mfButton]", inputs: ["tone", "appearance", "size", "shape", "type", "loading", "iconStart", "iconEnd"], exportAs: ["mfButton"] }, { kind: "directive", type: Icon, selector: "span[mfIcon]", inputs: ["size", "filled"] }] });
482
666
  }
483
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ConfirmDialog, decorators: [{
667
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ConfirmDialog, decorators: [{
484
668
  type: Component,
485
- args: [{ selector: 'mf-confirm-dialog', imports: [Dialog, Button, Icon], host: { class: 'contents' }, template: "<mf-dialog size=\"sm\" (close)=\"onCancel()\">\r\n <div dialog-header class=\"flex items-start gap-3\">\r\n <span\r\n class=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-md\"\r\n [class]=\"toneBadgeClass()\"\r\n >\r\n <span mfIcon [size]=\"22\">{{ toneIcon() }}</span>\r\n </span>\r\n <div class=\"min-w-0 flex-1 pt-1.5\">\r\n <h2 class=\"truncate font-display text-title text-fg\">{{ data.title }}</h2>\r\n </div>\r\n </div>\r\n\r\n <p class=\"text-sm text-fg-muted\">{{ data.content }}</p>\r\n\r\n @if (actionError()) {\r\n <p class=\"mt-3 text-sm text-danger\">{{ actionError() }}</p>\r\n }\r\n\r\n <div dialog-footer class=\"flex justify-end gap-2\">\r\n @if (!data.alert) {\r\n <button\r\n mfButton\r\n appearance=\"outlined\"\r\n tone=\"neutral\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n (click)=\"onCancel()\"\r\n >\r\n {{ data.cancelLabel ?? labels().confirmCancel }}\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n [tone]=\"confirmTone()\"\r\n appearance=\"filled\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n (click)=\"onConfirm()\"\r\n >\r\n @if (submitting()) {\r\n <span mfIcon [size]=\"16\" class=\"animate-spin\">progress_activity</span>\r\n }\r\n {{ data.confirmLabel ?? (data.alert ? labels().confirmOk : labels().confirmConfirm) }}\r\n </button>\r\n </div>\r\n</mf-dialog>\r\n" }]
669
+ args: [{ selector: 'mf-confirm-dialog', imports: [Dialog, Button, Icon], host: { class: 'contents' }, template: "<mf-dialog size=\"sm\" (close)=\"onCancel()\">\r\n <div dialog-header class=\"flex items-start gap-3\">\r\n <span\r\n class=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-md\"\r\n [class]=\"toneBadgeClass()\"\r\n >\r\n <span mfIcon [size]=\"22\">{{ toneIcon() }}</span>\r\n </span>\r\n <div class=\"min-w-0 flex-1 pt-1.5\">\r\n <h2 class=\"truncate font-display text-title text-fg\">{{ data.title }}</h2>\r\n </div>\r\n </div>\r\n\r\n <p class=\"text-sm text-fg-muted\">{{ data.content }}</p>\r\n\r\n @if (actionError()) {\r\n <p class=\"mt-3 text-sm text-danger\">{{ actionError() }}</p>\r\n }\r\n\r\n <div dialog-footer class=\"flex justify-end gap-2\">\r\n @if (!data.alert) {\r\n <button\r\n mfButton\r\n appearance=\"outlined\"\r\n tone=\"neutral\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n (click)=\"onCancel()\"\r\n >\r\n {{ data.cancelLabel ?? labels().confirmCancel }}\r\n </button>\r\n }\r\n <button\r\n mfButton\r\n [tone]=\"confirmTone()\"\r\n appearance=\"filled\"\r\n type=\"button\"\r\n [disabled]=\"submitting()\"\r\n [loading]=\"submitting()\"\r\n (click)=\"onConfirm()\"\r\n >\r\n {{ data.confirmLabel ?? (data.alert ? labels().confirmOk : labels().confirmConfirm) }}\r\n </button>\r\n </div>\r\n</mf-dialog>\r\n" }]
486
670
  }] });
487
671
 
488
- /** `--duration-fast` (styles.css) ile birebir — `animate-dialog-out`/`animate-sheet-out` keyframe'lerinin süresi. */
489
- const EXIT_MS = 120;
490
672
  const SHEET_QUERY = '(max-width: 639.98px)';
673
+ /** Mantıksal yerleşimi fiziksel kenara çevirir (`start`/`end` RTL'de yer değiştirir). */
674
+ function sideOf(placement, rtl) {
675
+ switch (placement) {
676
+ case 'center':
677
+ return null;
678
+ case 'start':
679
+ return rtl ? 'right' : 'left';
680
+ case 'end':
681
+ return rtl ? 'left' : 'right';
682
+ default:
683
+ return placement;
684
+ }
685
+ }
491
686
  function normalizeClass(value) {
492
687
  if (!value)
493
688
  return [];
@@ -499,9 +694,10 @@ function normalizeClass(value) {
499
694
  * engelleme davranışının TAMAMI CDK'dan geliyor, burada TEKRAR YAZILMADI — bkz.
500
695
  * projects/ui-kit/README.md "a11y checklist" bölümündeki "elle yazmak son çare" ilkesi).
501
696
  *
502
- * İçerik component'i (tüketicinin kendi form component'i, ör. `ConfirmDialog`) `@angular/cdk/dialog`'un
503
- * KENDİ `DIALOG_DATA`/`DialogRef` token'larını doğrudan `inject()` eder — ekstra bir
504
- * sarmalayıcı token'a gerek yok. Boyut/placement/maximize/drag/resize/sheet durumu
697
+ * `open()` kite ait `MfDialogRef` döndürür (CDK `DialogRef` yüzeyini delege eder +
698
+ * `afterClosed()`/`state`/`surface`). İçerik component'i `injectDialogRef()`/
699
+ * `injectDialogData()` (bkz. dialog-ref.ts) kullanır — CDK'nın kendi `DialogRef`/
700
+ * `DIALOG_DATA` token'larını inject etmek de çalışmaya devam eder. Boyut/placement/maximize/drag/resize/sheet durumu
505
701
  * `DialogSurface` (bkz. o dosya) üzerinden, `providers` ile o dialog'un injector'ına
506
702
  * verilir — `Dialog` (dialog.ts) bunu DI'dan okuyarak render eder.
507
703
  *
@@ -514,11 +710,13 @@ function normalizeClass(value) {
514
710
  * Kapanış animasyonu: CDK'nın `DialogRef.close()`'u `overlayRef.dispose()`'u SENKRON
515
711
  * çağırıyor, bir "kapanıyor" olayı/kancası yok. `closePredicate` bunun için bilinçli
516
712
  * bir kaçamak — `false` döndürmek kapanmayı iptal ediyor: ilk çağrıda `surface.closing`'i
517
- * `true` yapıp gerçek kapanmayı `EXIT_MS` geciktiriyoruz (panel bu sürede `Dialog`'un
713
+ * `true` yapıp gerçek kapanmayı `exitDurationMs()` kadar geciktiriyoruz (panel bu sürede `Dialog`'un
518
714
  * kendi reaktif `animate-dialog-out`/`animate-sheet-out`/`animate-drawer-out` class'ıyla
519
715
  * görsel olarak kapanır), ikinci çağrıda (zaten `closing()===true`) gerçek `dispose()`'a
520
716
  * izin veriyoruz. ESC/backdrop/programatik `dialogRef.close(...)` HEPSİ bu predicate'ten
521
- * geçtiği için davranış tekdüze. `prefers-reduced-motion` gecikmeyi tamamen atlıyor —
717
+ * geçtiği için davranış tekdüze. Animasyon sürerken gelen EK `close()` çağrıları
718
+ * yok sayılır (`disposeArmed` yalnızca zamanlayıcı tarafından kurulur) — X düğmesi +
719
+ * tüketicinin `(close)` handler'ı aynı anda kapatsa bile animasyon kesilmez. `prefers-reduced-motion` gecikmeyi tamamen atlıyor —
522
720
  * AMA kirli-form kontrolünden SONRA: koruma reduced-motion kullanıcılarında da çalışmalı.
523
721
  *
524
722
  * **Kirli form koruması**: `surface.isDirty()` `true` dönerse kapanış iptal edilip
@@ -532,6 +730,7 @@ class DialogService {
532
730
  injector = inject(Injector);
533
731
  breakpointObserver = inject(BreakpointObserver);
534
732
  labels = inject(MF_DIALOG_LABELS);
733
+ dir = inject(Directionality, { optional: true });
535
734
  /** `ref` başına `DialogSurface` — tüketicinin kendi URL senkronizasyon mantığı, kirli-form durumunu PROAKTİF sormak için kullanabilir (kendi `closePredicate`'inin async akışıyla yarışmamak için). */
536
735
  // `DialogRef<D, C>`'nin `config.providers` callback'i kendi generic'lerine yapısal
537
736
  // olarak döngüsel referans veriyor (bkz. @angular/cdk/dialog) — `unknown` kullanmak
@@ -540,20 +739,43 @@ class DialogService {
540
739
  // ilgisiz; `any` burada BİLEREK.
541
740
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
542
741
  surfaces = new WeakMap();
742
+ /**
743
+ * Bir component'i ya da bir `TemplateRef'i açar (şablon yolu `<mf-drawer>` gibi
744
+ * bildirimsel sarmalayıcılar içindir — şablonun injector'ı da `DialogSurface'i görür).
745
+ */
543
746
  open(component, options) {
544
747
  const surface = new DialogSurface();
545
748
  const placement = options?.placement ?? 'center';
546
749
  surface.size.set(options?.size ?? 'md');
547
750
  surface.placement.set(placement);
751
+ const side = sideOf(placement, this.dir?.value === 'rtl');
752
+ surface.side.set(side);
753
+ const sheetOnMobile = (options?.sheetOnMobile ?? true) && side !== 'top' && side !== 'bottom';
548
754
  surface.maximizable.set(options?.maximizable ?? false);
549
755
  surface.draggable.set(options?.draggable ?? false);
550
756
  surface.resizable.set(options?.resizable ?? false);
551
757
  const position = createGlobalPositionStrategy(this.injector);
552
- if (placement === 'right')
553
- position.right('0').top('0');
554
- else
555
- position.centerHorizontally().centerVertically();
556
- const reducedMotion = typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches;
758
+ const place = () => {
759
+ if (side === 'right')
760
+ position.right('0').top('0');
761
+ else if (side === 'left')
762
+ position.left('0').top('0');
763
+ else if (side === 'top')
764
+ position.top('0').left('0');
765
+ else if (side === 'bottom')
766
+ position.bottom('0').left('0');
767
+ else
768
+ position.centerHorizontally().centerVertically();
769
+ };
770
+ place();
771
+ // Çıkış süresi CSS token'ından (`--mf-duration-exit`); reduced-motion'da 0.
772
+ const exitMs = exitDurationMs();
773
+ // Gerçek dispose'a SADECE çıkış zamanlayıcısı izin verir — bkz. sınıf yorumu.
774
+ let disposeArmed = false;
775
+ // Kirli-form onayı açıkken ikinci bir onay yığılmasın.
776
+ let discardPending = false;
777
+ let mfRef;
778
+ // CDK iki aşırı yükü (component / şablon) çalışma zamanında ayırt eder.
557
779
  const ref = this.cdkDialog.open(component, {
558
780
  data: options?.data,
559
781
  panelClass: normalizeClass(options?.panelClass),
@@ -571,16 +793,32 @@ class DialogService {
571
793
  // onayı açılmasına yol açabilir — gerçek bir kullanıcı senaryosunda
572
794
  // tekrarlanan, doğrulanmış bir çakışma.
573
795
  closeOnNavigation: false,
796
+ // `aria-modal` — arka plan zaten `aria-hidden`, ama ekran okuyucuların sanal imleci
797
+ // için modal olduğunu açıkça söylemek WAI-ARIA dialog deseninin gereği.
798
+ ariaModal: true,
799
+ // Verilmezse CDK konteyneri `<mf-dialog>`'un görünür başlığına `aria-labelledby` ile
800
+ // bağlanır (bkz. dialog.ts — `_addAriaLabelledBy`).
574
801
  ariaLabel: options?.ariaLabel,
575
- providers: [{ provide: DialogSurface, useValue: surface }],
802
+ providers: (cdkRef) => {
803
+ mfRef = new MfDialogRef(cdkRef, surface);
804
+ return [
805
+ { provide: DialogSurface, useValue: surface },
806
+ { provide: MfDialogRef, useValue: mfRef },
807
+ ];
808
+ },
576
809
  closePredicate: (result) => {
577
- // Çıkış animasyonu turu — ikinci çağrı, gerçek dispose'a izin ver.
578
- if (surface.closing())
810
+ // Çıkış animasyonu bitti — zamanlayıcının kendi çağrısı, gerçek dispose'a izin ver.
811
+ if (disposeArmed)
579
812
  return true;
580
- // Kirli form koruması `reducedMotion`'DAN ÖNCE kontrol edilir — aksi halde
813
+ // Animasyon ya da kirli-form onayı sürerken gelen ek çağrılar yok sayılır.
814
+ if (surface.closing() || discardPending)
815
+ return false;
816
+ // Kirli form koruması reduced-motion kısa devresinden ÖNCE kontrol edilir — aksi halde
581
817
  // "animasyonu azalt" açık kullanıcılarda bu koruma hiç çalışmazdı.
582
818
  if (surface.isDirty()) {
819
+ discardPending = true;
583
820
  void this.confirmDiscard().then((discard) => {
821
+ discardPending = false;
584
822
  if (!discard)
585
823
  return;
586
824
  surface.markClean();
@@ -588,30 +826,30 @@ class DialogService {
588
826
  });
589
827
  return false;
590
828
  }
591
- if (reducedMotion)
829
+ if (exitMs === 0)
592
830
  return true;
593
831
  surface.closing.set(true);
594
832
  ref.overlayRef.backdropElement?.classList.add('is-closing');
595
- setTimeout(() => ref.close(result), EXIT_MS);
833
+ setTimeout(() => {
834
+ disposeArmed = true;
835
+ ref.close(result);
836
+ }, exitMs);
596
837
  return false;
597
838
  },
598
839
  });
599
840
  this.surfaces.set(ref, surface);
600
841
  const breakpointSub = this.breakpointObserver.observe(SHEET_QUERY).subscribe(({ matches }) => {
601
- surface.sheet.set(matches);
602
- if (matches) {
842
+ const sheet = matches && sheetOnMobile;
843
+ surface.sheet.set(sheet);
844
+ if (sheet)
603
845
  position.centerHorizontally().bottom('0');
604
- }
605
- else if (placement === 'right') {
606
- position.right('0').top('0');
607
- }
608
- else {
609
- position.centerHorizontally().centerVertically();
610
- }
846
+ else
847
+ place();
611
848
  position.apply();
612
849
  });
613
850
  ref.closed.subscribe(() => breakpointSub.unsubscribe());
614
- return ref;
851
+ // `providers` fabrikası CDK `open()` içinde SENKRON çağrılır — burada her zaman dolu.
852
+ return mfRef ?? new MfDialogRef(ref, surface);
615
853
  }
616
854
  /**
617
855
  * Kayıt oluştur/düzenle formlarının TEK açılış noktası — sağdan drawer.
@@ -623,7 +861,11 @@ class DialogService {
623
861
  * panel gibi) `md` içine sığmazsa `xl` (960px) geçilebilir.
624
862
  */
625
863
  openDrawer(component, options) {
626
- return this.open(component, { ...options, placement: 'right', maximizable: false });
864
+ return this.open(component, {
865
+ ...options,
866
+ placement: options?.placement ?? 'right',
867
+ maximizable: false,
868
+ });
627
869
  }
628
870
  /** `Promise<boolean>` döner — `if (await dialog.confirm(...))` çağıran taraf için `.subscribe()` zincirinden daha sade. */
629
871
  confirm(data) {
@@ -635,7 +877,7 @@ class DialogService {
635
877
  // `ConfirmDialogData`'da ayrı bir `ariaLabel` alanı sağlayamıyor zaten.
636
878
  ariaLabel: data.title,
637
879
  });
638
- return new Promise((resolve) => ref.closed.subscribe((result) => resolve(!!result)));
880
+ return ref.afterClosed().then((result) => !!result);
639
881
  }
640
882
  /**
641
883
  * Kirli-form kapanış korumasının kendi onay diyaloğu — `confirmDiscard`'ın açtığı
@@ -658,10 +900,14 @@ class DialogService {
658
900
  cancelLabel: t.cancel,
659
901
  });
660
902
  }
661
- /** Tüketici bir ref'i kapatmadan ÖNCE kirli mi diye sormak istiyorsa — kendi `closePredicate`'inin async akışıyla yarışmamak için `DialogSurface`'e doğrudan erişim. */
903
+ /**
904
+ * Tüketici bir ref'i kapatmadan ÖNCE kirli mi diye sormak istiyorsa — kendi `closePredicate`'inin
905
+ * async akışıyla yarışmamak için `DialogSurface`'e doğrudan erişim. `MfDialogRef` için
906
+ * `ref.surface` tercih edilir; ham CDK ref'i (ör. içerikte inject edilen) de kabul edilir.
907
+ */
662
908
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
663
909
  getSurface(ref) {
664
- return this.surfaces.get(ref);
910
+ return ref instanceof MfDialogRef ? ref.surface : this.surfaces.get(ref);
665
911
  }
666
912
  /** `confirm()`'in silme kısayolu — `tone:'danger'` + varsayılan "Sil" etiketi. */
667
913
  confirmDelete(data) {
@@ -675,12 +921,12 @@ class DialogService {
675
921
  size: 'sm',
676
922
  ariaLabel: data.title,
677
923
  });
678
- return new Promise((resolve) => ref.closed.subscribe(() => resolve()));
924
+ return ref.afterClosed().then(() => undefined);
679
925
  }
680
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: DialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
681
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: DialogService, providedIn: 'root' });
926
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: DialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
927
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: DialogService, providedIn: 'root' });
682
928
  }
683
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: DialogService, decorators: [{
929
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: DialogService, decorators: [{
684
930
  type: Injectable,
685
931
  args: [{ providedIn: 'root' }]
686
932
  }] });
@@ -696,5 +942,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
696
942
  * Generated bundle index. Do not edit.
697
943
  */
698
944
 
699
- export { ConfirmDialog, Dialog, DialogResizeHandle, DialogService, DialogSurface, dialogVariants };
945
+ export { ConfirmDialog, Dialog, DialogResizeHandle, DialogService, DialogSurface, MF_DIALOG_DATA, MfDialogRef, dialogVariants, injectDialogData, injectDialogRef };
700
946
  //# sourceMappingURL=mesgflow-ui-kit-dialog.mjs.map