@mesgflow/ui-kit 0.6.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 (230) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +200 -0
  3. package/fesm2022/mesgflow-ui-kit-accordion.mjs +75 -0
  4. package/fesm2022/mesgflow-ui-kit-accordion.mjs.map +1 -0
  5. package/fesm2022/mesgflow-ui-kit-alert.mjs +165 -0
  6. package/fesm2022/mesgflow-ui-kit-alert.mjs.map +1 -0
  7. package/fesm2022/mesgflow-ui-kit-avatar-group.mjs +88 -0
  8. package/fesm2022/mesgflow-ui-kit-avatar-group.mjs.map +1 -0
  9. package/fesm2022/mesgflow-ui-kit-avatar.mjs +123 -0
  10. package/fesm2022/mesgflow-ui-kit-avatar.mjs.map +1 -0
  11. package/fesm2022/mesgflow-ui-kit-badge.mjs +68 -0
  12. package/fesm2022/mesgflow-ui-kit-badge.mjs.map +1 -0
  13. package/fesm2022/mesgflow-ui-kit-banner.mjs +111 -0
  14. package/fesm2022/mesgflow-ui-kit-banner.mjs.map +1 -0
  15. package/fesm2022/mesgflow-ui-kit-box-input.mjs +78 -0
  16. package/fesm2022/mesgflow-ui-kit-box-input.mjs.map +1 -0
  17. package/fesm2022/mesgflow-ui-kit-brand.mjs +120 -0
  18. package/fesm2022/mesgflow-ui-kit-brand.mjs.map +1 -0
  19. package/fesm2022/mesgflow-ui-kit-breadcrumb.mjs +84 -0
  20. package/fesm2022/mesgflow-ui-kit-breadcrumb.mjs.map +1 -0
  21. package/fesm2022/mesgflow-ui-kit-button-group.mjs +37 -0
  22. package/fesm2022/mesgflow-ui-kit-button-group.mjs.map +1 -0
  23. package/fesm2022/mesgflow-ui-kit-button.mjs +359 -0
  24. package/fesm2022/mesgflow-ui-kit-button.mjs.map +1 -0
  25. package/fesm2022/mesgflow-ui-kit-card.mjs +128 -0
  26. package/fesm2022/mesgflow-ui-kit-card.mjs.map +1 -0
  27. package/fesm2022/mesgflow-ui-kit-chart.mjs +538 -0
  28. package/fesm2022/mesgflow-ui-kit-chart.mjs.map +1 -0
  29. package/fesm2022/mesgflow-ui-kit-checkbox.mjs +45 -0
  30. package/fesm2022/mesgflow-ui-kit-checkbox.mjs.map +1 -0
  31. package/fesm2022/mesgflow-ui-kit-chip.mjs +123 -0
  32. package/fesm2022/mesgflow-ui-kit-chip.mjs.map +1 -0
  33. package/fesm2022/mesgflow-ui-kit-code-block.mjs +71 -0
  34. package/fesm2022/mesgflow-ui-kit-code-block.mjs.map +1 -0
  35. package/fesm2022/mesgflow-ui-kit-collapsible.mjs +89 -0
  36. package/fesm2022/mesgflow-ui-kit-collapsible.mjs.map +1 -0
  37. package/fesm2022/mesgflow-ui-kit-color-picker.mjs +210 -0
  38. package/fesm2022/mesgflow-ui-kit-color-picker.mjs.map +1 -0
  39. package/fesm2022/mesgflow-ui-kit-combobox.mjs +181 -0
  40. package/fesm2022/mesgflow-ui-kit-combobox.mjs.map +1 -0
  41. package/fesm2022/mesgflow-ui-kit-command.mjs +491 -0
  42. package/fesm2022/mesgflow-ui-kit-command.mjs.map +1 -0
  43. package/fesm2022/mesgflow-ui-kit-context-menu.mjs +92 -0
  44. package/fesm2022/mesgflow-ui-kit-context-menu.mjs.map +1 -0
  45. package/fesm2022/mesgflow-ui-kit-copy-button.mjs +167 -0
  46. package/fesm2022/mesgflow-ui-kit-copy-button.mjs.map +1 -0
  47. package/fesm2022/mesgflow-ui-kit-core.mjs +624 -0
  48. package/fesm2022/mesgflow-ui-kit-core.mjs.map +1 -0
  49. package/fesm2022/mesgflow-ui-kit-date-picker.mjs +643 -0
  50. package/fesm2022/mesgflow-ui-kit-date-picker.mjs.map +1 -0
  51. package/fesm2022/mesgflow-ui-kit-description-list.mjs +76 -0
  52. package/fesm2022/mesgflow-ui-kit-description-list.mjs.map +1 -0
  53. package/fesm2022/mesgflow-ui-kit-dialog.mjs +700 -0
  54. package/fesm2022/mesgflow-ui-kit-dialog.mjs.map +1 -0
  55. package/fesm2022/mesgflow-ui-kit-divider.mjs +62 -0
  56. package/fesm2022/mesgflow-ui-kit-divider.mjs.map +1 -0
  57. package/fesm2022/mesgflow-ui-kit-dropzone.mjs +126 -0
  58. package/fesm2022/mesgflow-ui-kit-dropzone.mjs.map +1 -0
  59. package/fesm2022/mesgflow-ui-kit-empty-state.mjs +70 -0
  60. package/fesm2022/mesgflow-ui-kit-empty-state.mjs.map +1 -0
  61. package/fesm2022/mesgflow-ui-kit-field.mjs +42 -0
  62. package/fesm2022/mesgflow-ui-kit-field.mjs.map +1 -0
  63. package/fesm2022/mesgflow-ui-kit-hover-card.mjs +171 -0
  64. package/fesm2022/mesgflow-ui-kit-hover-card.mjs.map +1 -0
  65. package/fesm2022/mesgflow-ui-kit-i18n-tr.mjs +258 -0
  66. package/fesm2022/mesgflow-ui-kit-i18n-tr.mjs.map +1 -0
  67. package/fesm2022/mesgflow-ui-kit-icon.mjs +174 -0
  68. package/fesm2022/mesgflow-ui-kit-icon.mjs.map +1 -0
  69. package/fesm2022/mesgflow-ui-kit-input.mjs +448 -0
  70. package/fesm2022/mesgflow-ui-kit-input.mjs.map +1 -0
  71. package/fesm2022/mesgflow-ui-kit-kbd.mjs +24 -0
  72. package/fesm2022/mesgflow-ui-kit-kbd.mjs.map +1 -0
  73. package/fesm2022/mesgflow-ui-kit-link.mjs +48 -0
  74. package/fesm2022/mesgflow-ui-kit-link.mjs.map +1 -0
  75. package/fesm2022/mesgflow-ui-kit-menu.mjs +105 -0
  76. package/fesm2022/mesgflow-ui-kit-menu.mjs.map +1 -0
  77. package/fesm2022/mesgflow-ui-kit-number-input.mjs +153 -0
  78. package/fesm2022/mesgflow-ui-kit-number-input.mjs.map +1 -0
  79. package/fesm2022/mesgflow-ui-kit-otp-input.mjs +164 -0
  80. package/fesm2022/mesgflow-ui-kit-otp-input.mjs.map +1 -0
  81. package/fesm2022/mesgflow-ui-kit-page-header.mjs +83 -0
  82. package/fesm2022/mesgflow-ui-kit-page-header.mjs.map +1 -0
  83. package/fesm2022/mesgflow-ui-kit-pagination.mjs +99 -0
  84. package/fesm2022/mesgflow-ui-kit-pagination.mjs.map +1 -0
  85. package/fesm2022/mesgflow-ui-kit-password-input.mjs +120 -0
  86. package/fesm2022/mesgflow-ui-kit-password-input.mjs.map +1 -0
  87. package/fesm2022/mesgflow-ui-kit-popover.mjs +213 -0
  88. package/fesm2022/mesgflow-ui-kit-popover.mjs.map +1 -0
  89. package/fesm2022/mesgflow-ui-kit-progress.mjs +82 -0
  90. package/fesm2022/mesgflow-ui-kit-progress.mjs.map +1 -0
  91. package/fesm2022/mesgflow-ui-kit-radio.mjs +123 -0
  92. package/fesm2022/mesgflow-ui-kit-radio.mjs.map +1 -0
  93. package/fesm2022/mesgflow-ui-kit-rating.mjs +116 -0
  94. package/fesm2022/mesgflow-ui-kit-rating.mjs.map +1 -0
  95. package/fesm2022/mesgflow-ui-kit-scroll-area.mjs +84 -0
  96. package/fesm2022/mesgflow-ui-kit-scroll-area.mjs.map +1 -0
  97. package/fesm2022/mesgflow-ui-kit-search-input.mjs +154 -0
  98. package/fesm2022/mesgflow-ui-kit-search-input.mjs.map +1 -0
  99. package/fesm2022/mesgflow-ui-kit-segmented-control.mjs +95 -0
  100. package/fesm2022/mesgflow-ui-kit-segmented-control.mjs.map +1 -0
  101. package/fesm2022/mesgflow-ui-kit-select.mjs +227 -0
  102. package/fesm2022/mesgflow-ui-kit-select.mjs.map +1 -0
  103. package/fesm2022/mesgflow-ui-kit-sidebar.mjs +449 -0
  104. package/fesm2022/mesgflow-ui-kit-sidebar.mjs.map +1 -0
  105. package/fesm2022/mesgflow-ui-kit-skeleton.mjs +74 -0
  106. package/fesm2022/mesgflow-ui-kit-skeleton.mjs.map +1 -0
  107. package/fesm2022/mesgflow-ui-kit-slider.mjs +179 -0
  108. package/fesm2022/mesgflow-ui-kit-slider.mjs.map +1 -0
  109. package/fesm2022/mesgflow-ui-kit-spinner.mjs +67 -0
  110. package/fesm2022/mesgflow-ui-kit-spinner.mjs.map +1 -0
  111. package/fesm2022/mesgflow-ui-kit-splitter.mjs +97 -0
  112. package/fesm2022/mesgflow-ui-kit-splitter.mjs.map +1 -0
  113. package/fesm2022/mesgflow-ui-kit-stat-tile.mjs +98 -0
  114. package/fesm2022/mesgflow-ui-kit-stat-tile.mjs.map +1 -0
  115. package/fesm2022/mesgflow-ui-kit-stepper.mjs +133 -0
  116. package/fesm2022/mesgflow-ui-kit-stepper.mjs.map +1 -0
  117. package/fesm2022/mesgflow-ui-kit-switch.mjs +73 -0
  118. package/fesm2022/mesgflow-ui-kit-switch.mjs.map +1 -0
  119. package/fesm2022/mesgflow-ui-kit-table.mjs +1783 -0
  120. package/fesm2022/mesgflow-ui-kit-table.mjs.map +1 -0
  121. package/fesm2022/mesgflow-ui-kit-tabs.mjs +569 -0
  122. package/fesm2022/mesgflow-ui-kit-tabs.mjs.map +1 -0
  123. package/fesm2022/mesgflow-ui-kit-tag-input.mjs +138 -0
  124. package/fesm2022/mesgflow-ui-kit-tag-input.mjs.map +1 -0
  125. package/fesm2022/mesgflow-ui-kit-theme-switcher.mjs +53 -0
  126. package/fesm2022/mesgflow-ui-kit-theme-switcher.mjs.map +1 -0
  127. package/fesm2022/mesgflow-ui-kit-theming.mjs +1016 -0
  128. package/fesm2022/mesgflow-ui-kit-theming.mjs.map +1 -0
  129. package/fesm2022/mesgflow-ui-kit-time-picker.mjs +138 -0
  130. package/fesm2022/mesgflow-ui-kit-time-picker.mjs.map +1 -0
  131. package/fesm2022/mesgflow-ui-kit-timeline.mjs +91 -0
  132. package/fesm2022/mesgflow-ui-kit-timeline.mjs.map +1 -0
  133. package/fesm2022/mesgflow-ui-kit-toast.mjs +202 -0
  134. package/fesm2022/mesgflow-ui-kit-toast.mjs.map +1 -0
  135. package/fesm2022/mesgflow-ui-kit-toggle.mjs +243 -0
  136. package/fesm2022/mesgflow-ui-kit-toggle.mjs.map +1 -0
  137. package/fesm2022/mesgflow-ui-kit-toolbar.mjs +99 -0
  138. package/fesm2022/mesgflow-ui-kit-toolbar.mjs.map +1 -0
  139. package/fesm2022/mesgflow-ui-kit-tooltip.mjs +160 -0
  140. package/fesm2022/mesgflow-ui-kit-tooltip.mjs.map +1 -0
  141. package/fesm2022/mesgflow-ui-kit-tour.mjs +272 -0
  142. package/fesm2022/mesgflow-ui-kit-tour.mjs.map +1 -0
  143. package/fesm2022/mesgflow-ui-kit-tree-select.mjs +177 -0
  144. package/fesm2022/mesgflow-ui-kit-tree-select.mjs.map +1 -0
  145. package/fesm2022/mesgflow-ui-kit-tree.mjs +82 -0
  146. package/fesm2022/mesgflow-ui-kit-tree.mjs.map +1 -0
  147. package/fesm2022/mesgflow-ui-kit.mjs +12851 -0
  148. package/fesm2022/mesgflow-ui-kit.mjs.map +1 -0
  149. package/package.json +374 -0
  150. package/preset.css +20 -0
  151. package/tokens/color.css +693 -0
  152. package/tokens/contrast.css +68 -0
  153. package/tokens/elevation.css +68 -0
  154. package/tokens/motion.css +277 -0
  155. package/tokens/radius.css +69 -0
  156. package/tokens/typography.css +127 -0
  157. package/tokens.css +41 -0
  158. package/types/mesgflow-ui-kit-accordion.d.ts +42 -0
  159. package/types/mesgflow-ui-kit-alert.d.ts +60 -0
  160. package/types/mesgflow-ui-kit-avatar-group.d.ts +28 -0
  161. package/types/mesgflow-ui-kit-avatar.d.ts +23 -0
  162. package/types/mesgflow-ui-kit-badge.d.ts +39 -0
  163. package/types/mesgflow-ui-kit-banner.d.ts +42 -0
  164. package/types/mesgflow-ui-kit-box-input.d.ts +45 -0
  165. package/types/mesgflow-ui-kit-brand.d.ts +48 -0
  166. package/types/mesgflow-ui-kit-breadcrumb.d.ts +26 -0
  167. package/types/mesgflow-ui-kit-button-group.d.ts +17 -0
  168. package/types/mesgflow-ui-kit-button.d.ts +75 -0
  169. package/types/mesgflow-ui-kit-card.d.ts +71 -0
  170. package/types/mesgflow-ui-kit-chart.d.ts +242 -0
  171. package/types/mesgflow-ui-kit-checkbox.d.ts +17 -0
  172. package/types/mesgflow-ui-kit-chip.d.ts +46 -0
  173. package/types/mesgflow-ui-kit-code-block.d.ts +56 -0
  174. package/types/mesgflow-ui-kit-collapsible.d.ts +39 -0
  175. package/types/mesgflow-ui-kit-color-picker.d.ts +78 -0
  176. package/types/mesgflow-ui-kit-combobox.d.ts +74 -0
  177. package/types/mesgflow-ui-kit-command.d.ts +185 -0
  178. package/types/mesgflow-ui-kit-context-menu.d.ts +40 -0
  179. package/types/mesgflow-ui-kit-copy-button.d.ts +47 -0
  180. package/types/mesgflow-ui-kit-core.d.ts +508 -0
  181. package/types/mesgflow-ui-kit-date-picker.d.ts +215 -0
  182. package/types/mesgflow-ui-kit-description-list.d.ts +23 -0
  183. package/types/mesgflow-ui-kit-dialog.d.ts +342 -0
  184. package/types/mesgflow-ui-kit-divider.d.ts +23 -0
  185. package/types/mesgflow-ui-kit-dropzone.d.ts +47 -0
  186. package/types/mesgflow-ui-kit-empty-state.d.ts +18 -0
  187. package/types/mesgflow-ui-kit-field.d.ts +26 -0
  188. package/types/mesgflow-ui-kit-hover-card.d.ts +52 -0
  189. package/types/mesgflow-ui-kit-i18n-tr.d.ts +14 -0
  190. package/types/mesgflow-ui-kit-icon.d.ts +76 -0
  191. package/types/mesgflow-ui-kit-input.d.ts +186 -0
  192. package/types/mesgflow-ui-kit-kbd.d.ts +9 -0
  193. package/types/mesgflow-ui-kit-link.d.ts +20 -0
  194. package/types/mesgflow-ui-kit-menu.d.ts +53 -0
  195. package/types/mesgflow-ui-kit-number-input.d.ts +55 -0
  196. package/types/mesgflow-ui-kit-otp-input.d.ts +44 -0
  197. package/types/mesgflow-ui-kit-page-header.d.ts +31 -0
  198. package/types/mesgflow-ui-kit-pagination.d.ts +50 -0
  199. package/types/mesgflow-ui-kit-password-input.d.ts +33 -0
  200. package/types/mesgflow-ui-kit-popover.d.ts +62 -0
  201. package/types/mesgflow-ui-kit-progress.d.ts +32 -0
  202. package/types/mesgflow-ui-kit-radio.d.ts +59 -0
  203. package/types/mesgflow-ui-kit-rating.d.ts +56 -0
  204. package/types/mesgflow-ui-kit-scroll-area.d.ts +27 -0
  205. package/types/mesgflow-ui-kit-search-input.d.ts +72 -0
  206. package/types/mesgflow-ui-kit-segmented-control.d.ts +54 -0
  207. package/types/mesgflow-ui-kit-select.d.ts +89 -0
  208. package/types/mesgflow-ui-kit-sidebar.d.ts +224 -0
  209. package/types/mesgflow-ui-kit-skeleton.d.ts +29 -0
  210. package/types/mesgflow-ui-kit-slider.d.ts +40 -0
  211. package/types/mesgflow-ui-kit-spinner.d.ts +31 -0
  212. package/types/mesgflow-ui-kit-splitter.d.ts +40 -0
  213. package/types/mesgflow-ui-kit-stat-tile.d.ts +54 -0
  214. package/types/mesgflow-ui-kit-stepper.d.ts +48 -0
  215. package/types/mesgflow-ui-kit-switch.d.ts +34 -0
  216. package/types/mesgflow-ui-kit-table.d.ts +805 -0
  217. package/types/mesgflow-ui-kit-tabs.d.ts +269 -0
  218. package/types/mesgflow-ui-kit-tag-input.d.ts +33 -0
  219. package/types/mesgflow-ui-kit-theme-switcher.d.ts +27 -0
  220. package/types/mesgflow-ui-kit-theming.d.ts +745 -0
  221. package/types/mesgflow-ui-kit-time-picker.d.ts +54 -0
  222. package/types/mesgflow-ui-kit-timeline.d.ts +27 -0
  223. package/types/mesgflow-ui-kit-toast.d.ts +94 -0
  224. package/types/mesgflow-ui-kit-toggle.d.ts +110 -0
  225. package/types/mesgflow-ui-kit-toolbar.d.ts +52 -0
  226. package/types/mesgflow-ui-kit-tooltip.d.ts +55 -0
  227. package/types/mesgflow-ui-kit-tour.d.ts +66 -0
  228. package/types/mesgflow-ui-kit-tree-select.d.ts +65 -0
  229. package/types/mesgflow-ui-kit-tree.d.ts +44 -0
  230. package/types/mesgflow-ui-kit.d.ts +5444 -0
@@ -0,0 +1,700 @@
1
+ import { DIALOG_DATA, DialogRef, Dialog as Dialog$1 } from '@angular/cdk/dialog';
2
+ 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';
4
+ import { Button } from '@mesgflow/ui-kit/button';
5
+ import { glassSurface, MF_DIALOG_LABELS, cn } from '@mesgflow/ui-kit/core';
6
+ import { Icon } from '@mesgflow/ui-kit/icon';
7
+ import * as i1 from '@angular/cdk/drag-drop';
8
+ import { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
9
+ import { cva } from 'class-variance-authority';
10
+ import { BreakpointObserver } from '@angular/cdk/layout';
11
+ import { createGlobalPositionStrategy } from '@angular/cdk/overlay';
12
+
13
+ /**
14
+ * Dialog başına TEK instance — `DialogService.open()` her açılışta yeni bir
15
+ * tane üretip `options`'tan doldurur, CDK `DialogConfig.providers` ile o
16
+ * dialog'un (içerik component'inin) injector'ına verir. `Dialog` (dialog.ts)
17
+ * kendi `@Component.providers`'ında `skipSelf` ile bunu arar — bulamazsa
18
+ * (ör. overlay olmadan tek başına render edilen statik bir önizleme/demo)
19
+ * kendi yerel instance'ını üretir, hiçbir şey patlamaz.
20
+ *
21
+ * Boyut/maximize/drag/resize/sheet durumunun TAMAMI burada yaşıyor — `Dialog`
22
+ * kendi `@Input()`'larıyla DEĞİL, bu sınıfı okuyarak render ediyor. Böylece
23
+ * `DialogService.open(SomeForm, { size:'lg', maximizable:true })` gibi bir
24
+ * çağrı, `SomeForm`'un template'inde 1+ seviye iç içe olan `<mf-dialog>`'a
25
+ * DI üzerinden ulaşabiliyor (`@Input()` ile mümkün olmazdı — DialogService
26
+ * `Dialog`'u değil, `SomeForm`'u örnekliyor).
27
+ */
28
+ class DialogSurface {
29
+ size = signal('md', /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
31
+ placement = signal('center', /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
33
+ maximizable = signal(false, /* @ts-ignore */
34
+ ...(ngDevMode ? [{ debugName: "maximizable" }] : /* istanbul ignore next */ []));
35
+ draggable = signal(false, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "draggable" }] : /* istanbul ignore next */ []));
37
+ resizable = signal(false, /* @ts-ignore */
38
+ ...(ngDevMode ? [{ debugName: "resizable" }] : /* istanbul ignore next */ []));
39
+ maximized = signal(false, /* @ts-ignore */
40
+ ...(ngDevMode ? [{ debugName: "maximized" }] : /* istanbul ignore next */ []));
41
+ /** Kullanıcı kenardan boyutlandırdıysa dolu; maximize/sheet'te yok sayılır. */
42
+ customSize = signal(null, /* @ts-ignore */
43
+ ...(ngDevMode ? [{ debugName: "customSize" }] : /* istanbul ignore next */ []));
44
+ /** < 640px — `DialogService` `BreakpointObserver` ile besler. */
45
+ sheet = signal(false, /* @ts-ignore */
46
+ ...(ngDevMode ? [{ debugName: "sheet" }] : /* istanbul ignore next */ []));
47
+ /** Kapanış animasyonu oynarken `true` — bkz. `DialogService.open()` `closePredicate`. */
48
+ closing = signal(false, /* @ts-ignore */
49
+ ...(ngDevMode ? [{ debugName: "closing" }] : /* istanbul ignore next */ []));
50
+ toggleMaximize() {
51
+ this.maximized.update((value) => !value);
52
+ this.customSize.set(null);
53
+ }
54
+ dirtyCheck = null;
55
+ /** Başarılı kayıt/programatik kapanışta `true` yapılır — bir sonraki kapanışta kirli-form uyarısı SORULMAZ. */
56
+ bypassDirtyGuard = signal(false, /* @ts-ignore */
57
+ ...(ngDevMode ? [{ debugName: "bypassDirtyGuard" }] : /* istanbul ignore next */ []));
58
+ /** İçerik component'i (tüketicinin kendi form component'i) kendi "kirli mi" sorusunu buraya kaydeder — `DialogSurface` formun kendi şemasını bilmez. */
59
+ registerDirty(check) {
60
+ this.dirtyCheck = check;
61
+ }
62
+ /** `DialogService.open()`'ın `closePredicate`'i ESC/backdrop/X kapanışında bunu okur. */
63
+ isDirty() {
64
+ return !this.bypassDirtyGuard() && !!this.dirtyCheck?.();
65
+ }
66
+ /** Başarılı kayıttan hemen önce çağrılır — programatik `dialogRef.close()` kirli-form uyarısı sormasın diye. */
67
+ markClean() {
68
+ this.bypassDirtyGuard.set(true);
69
+ }
70
+ }
71
+
72
+ const MIN_WIDTH = 320;
73
+ const MIN_HEIGHT = 240;
74
+ const VIEWPORT_MARGIN = 32;
75
+ const ARROW_STEP = 16;
76
+ const ARROW_STEP_LARGE = 64;
77
+ /**
78
+ * `<button mfDialogResizeHandle [ariaLabel]="...">` — `Dialog`'un (dialog.ts)
79
+ * sağ-alt köşesinde, `DialogSurface.customSize`'ı besleyen serbest boyutlandırma
80
+ * tutamacı. Fare/dokunma İLE klavye (ok tuşları) İKİSİ de destekleniyor —
81
+ * projects/ui-kit/README.md "a11y checklist" bölümü "sadece fareyle çalışan bir
82
+ * tutamaç"ı kabul etmiyor.
83
+ */
84
+ class DialogResizeHandle {
85
+ surface = inject(DialogSurface);
86
+ host = inject(ElementRef);
87
+ ariaLabel = input.required(/* @ts-ignore */
88
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
89
+ /** `role="slider"` `aria-valuenow` zorunlu kılıyor (axe: `aria-required-attr`) — genişliği raporlar, özel boyut yoksa panelin ölçülen genişliğine, o da yoksa `MIN_WIDTH`'e düşer. */
90
+ ariaValueNow = computed(() => this.surface.customSize()?.width ?? this.panelRect()?.width ?? MIN_WIDTH, /* @ts-ignore */
91
+ ...(ngDevMode ? [{ debugName: "ariaValueNow" }] : /* istanbul ignore next */ []));
92
+ pointerId = null;
93
+ startX = 0;
94
+ startY = 0;
95
+ startWidth = 0;
96
+ startHeight = 0;
97
+ onPointerDown(event) {
98
+ if (event.button !== 0)
99
+ return;
100
+ const rect = this.panelRect();
101
+ if (!rect)
102
+ return;
103
+ this.pointerId = event.pointerId;
104
+ this.startX = event.clientX;
105
+ this.startY = event.clientY;
106
+ this.startWidth = this.surface.customSize()?.width ?? rect.width;
107
+ this.startHeight = this.surface.customSize()?.height ?? rect.height;
108
+ this.host.nativeElement.setPointerCapture(event.pointerId);
109
+ event.preventDefault();
110
+ }
111
+ onPointerMove(event) {
112
+ if (this.pointerId !== event.pointerId)
113
+ return;
114
+ this.applySize(this.startWidth + (event.clientX - this.startX), this.startHeight + (event.clientY - this.startY));
115
+ }
116
+ onPointerUp(event) {
117
+ if (this.pointerId !== event.pointerId)
118
+ return;
119
+ this.pointerId = null;
120
+ }
121
+ onKeydown(event) {
122
+ const rect = this.panelRect();
123
+ const current = this.surface.customSize() ?? {
124
+ width: rect?.width ?? MIN_WIDTH,
125
+ height: rect?.height ?? MIN_HEIGHT,
126
+ };
127
+ const step = event.shiftKey ? ARROW_STEP_LARGE : ARROW_STEP;
128
+ switch (event.key) {
129
+ case 'ArrowRight':
130
+ this.applySize(current.width + step, current.height);
131
+ break;
132
+ case 'ArrowLeft':
133
+ this.applySize(current.width - step, current.height);
134
+ break;
135
+ case 'ArrowDown':
136
+ this.applySize(current.width, current.height + step);
137
+ break;
138
+ case 'ArrowUp':
139
+ this.applySize(current.width, current.height - step);
140
+ break;
141
+ case 'Home':
142
+ this.surface.customSize.set(null);
143
+ break;
144
+ default:
145
+ return;
146
+ }
147
+ event.preventDefault();
148
+ }
149
+ panelRect() {
150
+ return (this.host.nativeElement.closest('.cdk-overlay-pane')?.getBoundingClientRect() ??
151
+ null);
152
+ }
153
+ applySize(width, height) {
154
+ const maxWidth = window.innerWidth - VIEWPORT_MARGIN;
155
+ const maxHeight = window.innerHeight - VIEWPORT_MARGIN;
156
+ this.surface.customSize.set({
157
+ width: Math.min(Math.max(width, MIN_WIDTH), maxWidth),
158
+ height: Math.min(Math.max(height, MIN_HEIGHT), maxHeight),
159
+ });
160
+ }
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 });
163
+ }
164
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: DialogResizeHandle, decorators: [{
165
+ type: Directive,
166
+ args: [{
167
+ selector: '[mfDialogResizeHandle]',
168
+ host: {
169
+ role: 'slider',
170
+ tabindex: '0',
171
+ '[attr.aria-label]': 'ariaLabel()',
172
+ '[attr.aria-valuenow]': 'ariaValueNow()',
173
+ '(pointerdown)': 'onPointerDown($event)',
174
+ '(pointermove)': 'onPointerMove($event)',
175
+ '(pointerup)': 'onPointerUp($event)',
176
+ '(pointercancel)': 'onPointerUp($event)',
177
+ '(keydown)': 'onKeydown($event)',
178
+ },
179
+ }]
180
+ }], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: true }] }] } });
181
+
182
+ /**
183
+ * Boyut ölçeği CSS `min()` ile viewport'a göre kendini sınırlıyor —
184
+ * `max-w-[560px]` gibi ayrı bir "hiçbir zaman viewport'tan taşma" class'ıyla
185
+ * `cn()`/tailwind-merge üzerinden birleştirilemezdi (ikisi aynı utility
186
+ * grubu — `max-width` — sonuncusu kazanır, ikisi birden UYGULANMAZ). Tek
187
+ * arbitrary value'da `min(N, 100vw-2rem)` ile ikisi birden garanti ediliyor.
188
+ *
189
+ * `state` (normal/maximized/sheet/drawer) boyut eksenine dik, tek-seçim bir eksen —
190
+ * `Dialog` (dialog.ts) `DialogSurface`'ten okuyup hesaplıyor, tüketici
191
+ * tarafından doğrudan set edilmiyor. `drawer` boyut ölçeğini (sm/md/lg/xl)
192
+ * `normal` ile PAYLAŞIR ama genişliği AYNI şekilde uygulamaz — aşağıdaki
193
+ * `compoundVariants`'a bak.
194
+ *
195
+ * **`drawer` neden `width` de alıyor, `max-width` yetmiyor mu**: sağa yaslı
196
+ * `GlobalPositionStrategy` (`dialog.service.ts`) overlay wrapper'a
197
+ * `align-items:flex-start` veriyor — bu, cross-axis stretch'i KAPATIYOR, yani
198
+ * `.cdk-overlay-pane` içeriğine göre daralıyor (shrink-to-fit). Böyle bir
199
+ * (genişliği belirsiz/auto) kapsayıcı içinde `mf-dialog`'un tabandaki
200
+ * `w-full`'u (`width:100%`) CSS Sizing L3'e göre `width:auto`'ya döner —
201
+ * yani panel `max-w-[min(N,...)]` TAVANINA hiç ulaşmadan, içeriğin doğal
202
+ * genişliğinde kalır. `normal` (ortada yüzen) dialog için bu doğru davranış
203
+ * (kısa bir onay kutusu tavana kadar zorla GENİŞLEMEMELİ), ama drawer için
204
+ * YANLIŞ — üç CRUD formu içerik uzunluğuna göre üç farklı genişlikte açılırdı
205
+ * (gerçek, gözlemlenen bir regresyon). Çözüm: `calc(100vw-2rem)` viewport'a
206
+ * göre DEFINITE bir uzunluk — parent'ın genişliği belirsiz olsa bile bu
207
+ * paradoksu atlıyor. `width` + `max-width` aynı ifadeyi taşıdığı için
208
+ * `max-width` drawer'da fiilen artık gereksiz ama zararsız kalıyor.
209
+ *
210
+ * **`maximized` neden kendi `max-w-none`'ını taşıyor**: `size` (sm/md/lg/xl)
211
+ * her zaman uygulanır, `state` ondan BAĞIMSIZ bir eksendir — `maximized` kendi
212
+ * `max-w-none`'ını taşımazsa, `size`'ın `max-w-[min(N,...)]`'i (aynı `max-width`
213
+ * grubu, ama `size` `state`'ten ÖNCE değerlendirildiği için `state` sonuncusu
214
+ * kazanmadıkça) tek başına kalır ve `w-screen`'i geçersiz kılar — gerçek,
215
+ * gözlemlenen bir regresyon: `maximizable:true, size:'lg'` bir dialog
216
+ * büyütüldüğünde yükseklik `h-[100dvh]`'e ulaşırken genişlik hâlâ `lg`'nin
217
+ * 720px tavanına sıkışıp kalıyordu ("kenarlar kısa, sadece boyu uzuyor").
218
+ */
219
+ /**
220
+ * Panel yüzeyi `glassSurface` (bkz. `@mesgflow/ui-kit/core` — mikro
221
+ * glassmorphism, 2026-09 Deep Emerald geçişi): arkadaki içerik `backdrop-blur`
222
+ * destekleyen tarayıcılarda hafifçe görünür kalır, backdrop
223
+ * (`.mf-dialog-backdrop`, motion.css) ayrıca karartıyor. `maximized` durumu
224
+ * TAM VIEWPORT'u kapladığı için (arkasında blur'lanacak sayfa içeriği yok,
225
+ * sadece backdrop) camı KAPATIP düz `bg-surface`'e döner — hem maliyetsiz hem
226
+ * anlamsız bir blur'dan kaçınır.
227
+ */
228
+ const dialogVariants = cva(`relative flex w-full flex-col overflow-hidden border shadow-3 ${glassSurface}`, {
229
+ variants: {
230
+ size: {
231
+ sm: 'max-w-[min(440px,calc(100vw-2rem))]',
232
+ md: 'max-w-[min(560px,calc(100vw-2rem))]',
233
+ lg: 'max-w-[min(720px,calc(100vw-2rem))]',
234
+ xl: 'max-w-[min(960px,calc(100vw-2rem))]',
235
+ full: 'max-w-none',
236
+ },
237
+ state: {
238
+ normal: 'rounded-xl max-h-[85vh]',
239
+ 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
+ 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',
242
+ },
243
+ },
244
+ 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))]' },
249
+ ],
250
+ defaultVariants: { size: 'md', state: 'normal' },
251
+ });
252
+
253
+ const DRAG_MIN_VISIBLE = 48;
254
+ /**
255
+ * `<mf-dialog [title]="..." [subtitle]="..." [icon]="'group'" (close)="onCancel()">`
256
+ * — `DialogService.open()`'ın açtığı her içerik component'i (tüketicinin kendi
257
+ * form component'i, ör. `ConfirmDialog`) kendi kök elemanı olarak bunu kullanır. CDK Dialog'un
258
+ * kendisi (bkz. dialog.service.ts) hiçbir görsel çerçeve DAYATMIYOR (backdrop hariç) —
259
+ * panel görünümü (yuvarlak köşe/gölge/header/footer/kapatma düğmesi) TAMAMEN burada,
260
+ * tek yerde yaşıyor.
261
+ *
262
+ * Boyut/placement/maximize/drag/resize/sheet durumu kendi `@Input()`'ları DEĞİL,
263
+ * `DialogSurface` (DI ile enjekte edilir) — bkz. o dosyanın doc yorumu. `title`/
264
+ * `subtitle`/`icon`/`fillBody` ise İÇERİĞE ait olduğu için normal input —
265
+ * `[dialog-header]` slot'u tamamen özel bir başlık gerektiren durumlar için (bkz.
266
+ * ConfirmDialog) kaçış kapısı olarak kalıyor.
267
+ *
268
+ * `stateVariant()` sırası (sheet → maximized → drawer → normal) bilinçli: mobil
269
+ * sheet her zaman kazanır, ardından drag/resize/mobil-sheet'in yalnızca `normal`'da
270
+ * açık olması (bkz. `dragEnabled`/`resizeHandleVisible`) drawer'da bu ikisinin
271
+ * otomatik kapalı kalmasını BEDAVA sağlıyor — ayrı bir kontrol gerekmiyor.
272
+ */
273
+ class Dialog {
274
+ title = input('', /* @ts-ignore */
275
+ ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
276
+ subtitle = input('', /* @ts-ignore */
277
+ ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
278
+ icon = input('', /* @ts-ignore */
279
+ ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
280
+ /** Sadece `DialogSurface` DI ile enjekte edilmediğinde (ör. statik bir önizleme/demo) etkili — gerçek dialog'larda `DialogService.open({ size })` kullanılır. */
281
+ size = input(undefined, /* @ts-ignore */
282
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
283
+ /**
284
+ * `true` ise gövde kendi kaydırmasını KAPATIR (`overflow:hidden`) ve kalan
285
+ * yüksekliği içeriğe `flex-1` ile devreder — içeriğin KENDİ tek scroll alanını
286
+ * kurması beklenir (ör. uzun bir liste içeren bir form). "Tek kaydırma bölgesi"
287
+ * kuralının uygulama noktası: dialog gövdesi + içerik aynı anda kaymaz.
288
+ */
289
+ fillBody = input(false, /* @ts-ignore */
290
+ ...(ngDevMode ? [{ debugName: "fillBody" }] : /* istanbul ignore next */ []));
291
+ // `close` adı native DOM `close` olayıyla çakışıyor (@angular-eslint/no-output-native);
292
+ // mevcut public API — yeniden adlandırma kırıcı, ileri bir sürümde ele alınacak.
293
+ // eslint-disable-next-line @angular-eslint/no-output-native
294
+ close = output();
295
+ surface = inject(DialogSurface);
296
+ labels = inject(MF_DIALOG_LABELS);
297
+ elementRef = inject(ElementRef);
298
+ cdkDrag = inject(CdkDrag, { self: true });
299
+ scrollBody = viewChild('scrollBody', /* @ts-ignore */
300
+ ...(ngDevMode ? [{ debugName: "scrollBody" }] : /* istanbul ignore next */ []));
301
+ scrolledFromTop = signal(false, /* @ts-ignore */
302
+ ...(ngDevMode ? [{ debugName: "scrolledFromTop" }] : /* istanbul ignore next */ []));
303
+ hasMoreBelow = signal(false, /* @ts-ignore */
304
+ ...(ngDevMode ? [{ debugName: "hasMoreBelow" }] : /* istanbul ignore next */ []));
305
+ stateVariant = computed(() => {
306
+ if (this.surface.sheet())
307
+ return 'sheet';
308
+ if (this.surface.maximized() || this.size() === 'full')
309
+ return 'maximized';
310
+ if (this.surface.placement() === 'right')
311
+ return 'drawer';
312
+ return 'normal';
313
+ }, /* @ts-ignore */
314
+ ...(ngDevMode ? [{ debugName: "stateVariant" }] : /* istanbul ignore next */ []));
315
+ dragEnabled = computed(() => this.surface.draggable() && this.stateVariant() === 'normal', /* @ts-ignore */
316
+ ...(ngDevMode ? [{ debugName: "dragEnabled" }] : /* istanbul ignore next */ []));
317
+ resizeHandleVisible = computed(() => this.surface.resizable() && this.stateVariant() === 'normal', /* @ts-ignore */
318
+ ...(ngDevMode ? [{ debugName: "resizeHandleVisible" }] : /* istanbul ignore next */ []));
319
+ /** Drawer zaten tam yükseklik — büyütme düğmesinin anlamı yok, `surface.maximizable()` `true` olsa bile gizlenir. */
320
+ maximizeVisible = computed(() => this.surface.maximizable() && this.stateVariant() !== 'drawer', /* @ts-ignore */
321
+ ...(ngDevMode ? [{ debugName: "maximizeVisible" }] : /* istanbul ignore next */ []));
322
+ hostClasses = computed(() => {
323
+ const closing = this.surface.closing();
324
+ 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'}`);
327
+ }, /* @ts-ignore */
328
+ ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
329
+ customWidth = computed(() => this.stateVariant() === 'normal' ? this.surface.customSize()?.width : undefined, /* @ts-ignore */
330
+ ...(ngDevMode ? [{ debugName: "customWidth" }] : /* istanbul ignore next */ []));
331
+ customHeight = computed(() => this.stateVariant() === 'normal' ? this.surface.customSize()?.height : undefined, /* @ts-ignore */
332
+ ...(ngDevMode ? [{ debugName: "customHeight" }] : /* istanbul ignore next */ []));
333
+ /** Kenara/tam ekrana yaslı yüzeyler (drawer, mobil sheet, maximized): bölgeler KALICI
334
+ * çizgiyle ayrılır — header/content/footer iskeleti her zaman aynı görünür. Ortada
335
+ * yüzen klasik dialog (`normal`, ör. ConfirmDialog) bugünkü kaydırma-gölgesi davranışını
336
+ * korur — kısa bir onay kutusu gereksiz çizgi kazanmaz. */
337
+ framed = computed(() => this.stateVariant() !== 'normal', /* @ts-ignore */
338
+ ...(ngDevMode ? [{ debugName: "framed" }] : /* istanbul ignore next */ []));
339
+ headerBorder = computed(() => this.framed() || this.scrolledFromTop(), /* @ts-ignore */
340
+ ...(ngDevMode ? [{ debugName: "headerBorder" }] : /* istanbul ignore next */ []));
341
+ footerBorder = computed(() => this.framed() || this.hasMoreBelow(), /* @ts-ignore */
342
+ ...(ngDevMode ? [{ debugName: "footerBorder" }] : /* istanbul ignore next */ []));
343
+ constructor() {
344
+ this.cdkDrag.rootElementSelector = '.cdk-overlay-pane';
345
+ this.cdkDrag.constrainPosition = (point, _dragRef, dimensions) => ({
346
+ x: Math.min(Math.max(point.x, DRAG_MIN_VISIBLE - dimensions.width), window.innerWidth - DRAG_MIN_VISIBLE),
347
+ y: Math.min(Math.max(point.y, 0), window.innerHeight - DRAG_MIN_VISIBLE),
348
+ });
349
+ effect(() => {
350
+ this.cdkDrag.disabled = !this.dragEnabled();
351
+ });
352
+ effect(() => {
353
+ if (this.surface.maximized() || this.surface.sheet()) {
354
+ this.cdkDrag.reset();
355
+ this.surface.customSize.set(null);
356
+ }
357
+ });
358
+ const destroyRef = inject(DestroyRef);
359
+ afterNextRender(() => {
360
+ this.updateScrollShadow();
361
+ const el = this.scrollBody()?.nativeElement;
362
+ if (!el || typeof ResizeObserver === 'undefined')
363
+ return;
364
+ const observer = new ResizeObserver(() => this.updateScrollShadow());
365
+ observer.observe(el);
366
+ destroyRef.onDestroy(() => observer.disconnect());
367
+ });
368
+ }
369
+ updateScrollShadow() {
370
+ const el = this.scrollBody()?.nativeElement;
371
+ if (!el)
372
+ return;
373
+ this.scrolledFromTop.set(el.scrollTop > 1);
374
+ this.hasMoreBelow.set(el.scrollHeight - el.clientHeight - el.scrollTop > 1);
375
+ }
376
+ /**
377
+ * Ctrl/Cmd+Enter — tek yerde çözülür, her form bedava kazanır. Kaydet düğmesi
378
+ * footer slot'unda `<form>`'un DIŞINDA yaşıyor (`form="role-form"` attribute
379
+ * ilişkilendirmesiyle çalışıyor) — bu yüzden düğmeye tıklamayı taklit etmek
380
+ * yerine doğrudan `<form>` üzerinde `requestSubmit()` çağrılıyor; bu da native
381
+ * kısıt doğrulamasını çalıştırıp mevcut `(submit)` bağlamasını tetikler.
382
+ */
383
+ requestSubmit() {
384
+ this.elementRef.nativeElement.querySelector('form')?.requestSubmit();
385
+ }
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: [
388
+ {
389
+ provide: DialogSurface,
390
+ useFactory: () => inject(DialogSurface, { optional: true, skipSelf: true }) ?? new DialogSurface(),
391
+ },
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"] }] });
393
+ }
394
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: Dialog, decorators: [{
395
+ type: Component,
396
+ args: [{ selector: 'mf-dialog', exportAs: 'mfDialog', imports: [Button, Icon, DialogResizeHandle, CdkDragHandle], hostDirectives: [CdkDrag], providers: [
397
+ {
398
+ provide: DialogSurface,
399
+ useFactory: () => inject(DialogSurface, { optional: true, skipSelf: true }) ?? new DialogSurface(),
400
+ },
401
+ ], host: {
402
+ '[class]': 'hostClasses()',
403
+ '[style.width.px]': 'customWidth()',
404
+ '[style.height.px]': 'customHeight()',
405
+ '(keydown.control.enter)': 'requestSubmit()',
406
+ '(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 }] }] } });
409
+
410
+ const TONE_ICON = {
411
+ danger: 'warning',
412
+ warning: 'warning',
413
+ info: 'info',
414
+ success: 'check_circle',
415
+ neutral: 'help',
416
+ };
417
+ /** Rozet renkleri Badge'in `badge.variants.ts`'teki tonal işaret rol token'ını (`bg-X-tint text-X-tint-fg`) birebir izliyor. */
418
+ const TONE_BADGE_CLASS = {
419
+ danger: 'bg-danger-tint text-danger-tint-fg',
420
+ warning: 'bg-warning-tint text-warning-tint-fg',
421
+ info: 'bg-info-tint text-info-tint-fg',
422
+ success: 'bg-success-tint text-success-tint-fg',
423
+ neutral: 'bg-surface-alt text-fg-muted',
424
+ };
425
+ /**
426
+ * Onay diyaloğunun içerik component'i — `DialogService.confirm()`/`confirmDelete()`/
427
+ * `alert()` (bkz. dialog.service.ts) bunu açıp `DialogRef<boolean>`'ı `Promise`'e
428
+ * çeviriyor. `Dialog`'un (dialog.ts) `[dialog-header]` kaçış kapısını kullanıyor —
429
+ * ton'a göre renkli ikon rozeti, generic `Dialog`'un kendi `[icon]` input'unun
430
+ * desteklemediği bir şey (o sadece nötr bir rozet çizer), bu yüzden kendi başlığını
431
+ * kendi çiziyor.
432
+ */
433
+ class ConfirmDialog {
434
+ data = inject(DIALOG_DATA);
435
+ dialogRef = inject((DialogRef));
436
+ labels = inject(MF_DIALOG_LABELS);
437
+ tone = computed(() => this.data.tone ?? 'neutral', /* @ts-ignore */
438
+ ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
439
+ toneIcon = computed(() => TONE_ICON[this.tone()], /* @ts-ignore */
440
+ ...(ngDevMode ? [{ debugName: "toneIcon" }] : /* istanbul ignore next */ []));
441
+ toneBadgeClass = computed(() => TONE_BADGE_CLASS[this.tone()], /* @ts-ignore */
442
+ ...(ngDevMode ? [{ debugName: "toneBadgeClass" }] : /* istanbul ignore next */ []));
443
+ /** Her ton `filled` — warning da diğer tonlarla aynı `bg-X-fill` rol deseninde dolu blok kullanıyor (bkz. button.variants.ts), eski `outlined` istisnası kaldırıldı. */
444
+ confirmTone = computed(() => {
445
+ const tone = this.tone();
446
+ if (tone === 'danger')
447
+ return 'danger';
448
+ if (tone === 'warning')
449
+ return 'warning';
450
+ return 'primary';
451
+ }, /* @ts-ignore */
452
+ ...(ngDevMode ? [{ debugName: "confirmTone" }] : /* istanbul ignore next */ []));
453
+ submitting = signal(false, /* @ts-ignore */
454
+ ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
455
+ actionError = signal(null, /* @ts-ignore */
456
+ ...(ngDevMode ? [{ debugName: "actionError" }] : /* istanbul ignore next */ []));
457
+ onCancel() {
458
+ this.dialogRef.close(false);
459
+ }
460
+ async onConfirm() {
461
+ if (!this.data.action) {
462
+ this.dialogRef.close(true);
463
+ return;
464
+ }
465
+ this.submitting.set(true);
466
+ this.actionError.set(null);
467
+ this.dialogRef.disableClose = true;
468
+ try {
469
+ await this.data.action();
470
+ this.dialogRef.close(true);
471
+ }
472
+ catch {
473
+ this.actionError.set(this.labels().errorGeneric);
474
+ }
475
+ finally {
476
+ this.submitting.set(false);
477
+ this.dialogRef.disableClose = false;
478
+ }
479
+ }
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"] }] });
482
+ }
483
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ConfirmDialog, decorators: [{
484
+ 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" }]
486
+ }] });
487
+
488
+ /** `--duration-fast` (styles.css) ile birebir — `animate-dialog-out`/`animate-sheet-out` keyframe'lerinin süresi. */
489
+ const EXIT_MS = 120;
490
+ const SHEET_QUERY = '(max-width: 639.98px)';
491
+ function normalizeClass(value) {
492
+ if (!value)
493
+ return [];
494
+ return Array.isArray(value) ? value : [value];
495
+ }
496
+ /**
497
+ * Dialog açmanın tek, merkezi noktası — `@angular/cdk/dialog`'un `Dialog`
498
+ * servisi ÜZERİNE ince bir katman (focus-trap/ESC/backdrop-click/geri-scroll-
499
+ * engelleme davranışının TAMAMI CDK'dan geliyor, burada TEKRAR YAZILMADI — bkz.
500
+ * projects/ui-kit/README.md "a11y checklist" bölümündeki "elle yazmak son çare" ilkesi).
501
+ *
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
505
+ * `DialogSurface` (bkz. o dosya) üzerinden, `providers` ile o dialog'un injector'ına
506
+ * verilir — `Dialog` (dialog.ts) bunu DI'dan okuyarak render eder.
507
+ *
508
+ * **Tek kural**: kayıt oluştur/düzenle → `openDrawer()` (sağdan, `placement:'right'`);
509
+ * onayla/bilgilendir/sil → `confirm()`/`confirmDelete()`/`alert()` (merkezi, `size:'sm'`).
510
+ * Drawer ayrı bir primitif DEĞİL — `placement` sadece konum stratejisini ve
511
+ * `Dialog.stateVariant()`'ı değiştiren bir eksen, geri kalan her şey (CDK Dialog,
512
+ * closePredicate, kirli-form koruması, mobil sheet, kaydırma gölgesi) ortak.
513
+ *
514
+ * Kapanış animasyonu: CDK'nın `DialogRef.close()`'u `overlayRef.dispose()`'u SENKRON
515
+ * çağırıyor, bir "kapanıyor" olayı/kancası yok. `closePredicate` bunun için bilinçli
516
+ * 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
518
+ * kendi reaktif `animate-dialog-out`/`animate-sheet-out`/`animate-drawer-out` class'ıyla
519
+ * görsel olarak kapanır), ikinci çağrıda (zaten `closing()===true`) gerçek `dispose()`'a
520
+ * 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 —
522
+ * AMA kirli-form kontrolünden SONRA: koruma reduced-motion kullanıcılarında da çalışmalı.
523
+ *
524
+ * **Kirli form koruması**: `surface.isDirty()` `true` dönerse kapanış iptal edilip
525
+ * `confirmDiscard()` (kendi içindeki `ConfirmDialog`, ayrı/temiz bir `DialogSurface`
526
+ * ile) açılır; kullanıcı onaylarsa `surface.markClean()` + gerçek `close()`. İçerik
527
+ * component'i `constructor()`'da `surface.registerDirty(() => ...)` ile kendi
528
+ * "değişti mi" sorusunu kaydeder.
529
+ */
530
+ class DialogService {
531
+ cdkDialog = inject(Dialog$1);
532
+ injector = inject(Injector);
533
+ breakpointObserver = inject(BreakpointObserver);
534
+ labels = inject(MF_DIALOG_LABELS);
535
+ /** `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
+ // `DialogRef<D, C>`'nin `config.providers` callback'i kendi generic'lerine yapısal
537
+ // olarak döngüsel referans veriyor (bkz. @angular/cdk/dialog) — `unknown` kullanmak
538
+ // `ref`'i somut `DialogRef<R, C>` tipiyle çağıran DIŞARIDAKİ tüketicileri (public API)
539
+ // derleme zamanında kırar. Registry nesne KİMLİĞİNE göre çalışıyor, tür parametreleri
540
+ // ilgisiz; `any` burada BİLEREK.
541
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
542
+ surfaces = new WeakMap();
543
+ open(component, options) {
544
+ const surface = new DialogSurface();
545
+ const placement = options?.placement ?? 'center';
546
+ surface.size.set(options?.size ?? 'md');
547
+ surface.placement.set(placement);
548
+ surface.maximizable.set(options?.maximizable ?? false);
549
+ surface.draggable.set(options?.draggable ?? false);
550
+ surface.resizable.set(options?.resizable ?? false);
551
+ 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;
557
+ const ref = this.cdkDialog.open(component, {
558
+ data: options?.data,
559
+ panelClass: normalizeClass(options?.panelClass),
560
+ backdropClass: 'mf-dialog-backdrop',
561
+ positionStrategy: position,
562
+ autoFocus: 'first-tabbable',
563
+ restoreFocus: true,
564
+ disableClose: options?.disableClose ?? false,
565
+ // CDK'nın kendi tarayıcı geri/ileri tuşu dinleyicisi (varsayılan `true`) —
566
+ // tüketici derin-bağlantı/URL senkronizasyonunu KENDİ route effect'i
567
+ // üzerinden yönetiyorsa (kirli-form kontrolü + confirmDiscard + URL
568
+ // senkronu dahil), CDK'nın PARALEL ve koordinasyonsuz kendi `close()`
569
+ // çağrısı (kendi closePredicate'inden geçerek KENDİ confirmDiscard'ını
570
+ // açar) tüketicininkiyle AYNI ANDA iki ayrı "Kaydedilmemiş değişiklikler"
571
+ // onayı açılmasına yol açabilir — gerçek bir kullanıcı senaryosunda
572
+ // tekrarlanan, doğrulanmış bir çakışma.
573
+ closeOnNavigation: false,
574
+ ariaLabel: options?.ariaLabel,
575
+ providers: [{ provide: DialogSurface, useValue: surface }],
576
+ closePredicate: (result) => {
577
+ // Çıkış animasyonu turu — ikinci çağrı, gerçek dispose'a izin ver.
578
+ if (surface.closing())
579
+ return true;
580
+ // Kirli form koruması `reducedMotion`'DAN ÖNCE kontrol edilir — aksi halde
581
+ // "animasyonu azalt" açık kullanıcılarda bu koruma hiç çalışmazdı.
582
+ if (surface.isDirty()) {
583
+ void this.confirmDiscard().then((discard) => {
584
+ if (!discard)
585
+ return;
586
+ surface.markClean();
587
+ ref.close(result);
588
+ });
589
+ return false;
590
+ }
591
+ if (reducedMotion)
592
+ return true;
593
+ surface.closing.set(true);
594
+ ref.overlayRef.backdropElement?.classList.add('is-closing');
595
+ setTimeout(() => ref.close(result), EXIT_MS);
596
+ return false;
597
+ },
598
+ });
599
+ this.surfaces.set(ref, surface);
600
+ const breakpointSub = this.breakpointObserver.observe(SHEET_QUERY).subscribe(({ matches }) => {
601
+ surface.sheet.set(matches);
602
+ if (matches) {
603
+ position.centerHorizontally().bottom('0');
604
+ }
605
+ else if (placement === 'right') {
606
+ position.right('0').top('0');
607
+ }
608
+ else {
609
+ position.centerHorizontally().centerVertically();
610
+ }
611
+ position.apply();
612
+ });
613
+ ref.closed.subscribe(() => breakpointSub.unsubscribe());
614
+ return ref;
615
+ }
616
+ /**
617
+ * Kayıt oluştur/düzenle formlarının TEK açılış noktası — sağdan drawer.
618
+ * `maximizable` bilerek zorla kapatılıyor: drawer zaten tam yükseklik, büyütme
619
+ * düğmesinin anlamı yok (bkz. `Dialog.maximizeVisible`).
620
+ *
621
+ * Varsayılan genişlik `md` (560px) — CRUD formları `size` GEÇMEZ, hepsi aynı
622
+ * genişlikte açılmalı. İstisna: iki sütunlu bir form (sol dikey ray + sağ
623
+ * panel gibi) `md` içine sığmazsa `xl` (960px) geçilebilir.
624
+ */
625
+ openDrawer(component, options) {
626
+ return this.open(component, { ...options, placement: 'right', maximizable: false });
627
+ }
628
+ /** `Promise<boolean>` döner — `if (await dialog.confirm(...))` çağıran taraf için `.subscribe()` zincirinden daha sade. */
629
+ confirm(data) {
630
+ const ref = this.open(ConfirmDialog, {
631
+ data,
632
+ size: 'sm',
633
+ // `data.title` her zaman görünür bir başlık taşıyor — CDK'nın dialog konteynerine
634
+ // erişilebilir ad olarak veriliyor (axe: `aria-dialog-name`); çağıran taraf
635
+ // `ConfirmDialogData`'da ayrı bir `ariaLabel` alanı sağlayamıyor zaten.
636
+ ariaLabel: data.title,
637
+ });
638
+ return new Promise((resolve) => ref.closed.subscribe((result) => resolve(!!result)));
639
+ }
640
+ /**
641
+ * Kirli-form kapanış korumasının kendi onay diyaloğu — `confirmDiscard`'ın açtığı
642
+ * `ConfirmDialog`'un `DialogSurface`'i her zaman temiz (yeni instance), bu yüzden
643
+ * özyineleme sorunsuz. `closePredicate` içinden (ESC/backdrop/X) VE tüketicinin
644
+ * kendi route senkronizasyonundan (URL değişip panel PROAKTİF kapatılmadan
645
+ * önce) iki ayrı yoldan çağrılabildiği için `public`.
646
+ *
647
+ * `tone: 'warning'` — onay butonu artık DOLU warning (bkz.
648
+ * `button.variants.ts`/`confirm-dialog.ts`, eski `outlined` istisnası
649
+ * kaldırıldı).
650
+ */
651
+ confirmDiscard() {
652
+ const t = this.labels().discard;
653
+ return this.confirm({
654
+ title: t.title,
655
+ content: t.content,
656
+ tone: 'warning',
657
+ confirmLabel: t.confirm,
658
+ cancelLabel: t.cancel,
659
+ });
660
+ }
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. */
662
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
663
+ getSurface(ref) {
664
+ return this.surfaces.get(ref);
665
+ }
666
+ /** `confirm()`'in silme kısayolu — `tone:'danger'` + varsayılan "Sil" etiketi. */
667
+ confirmDelete(data) {
668
+ const confirmLabel = data.confirmLabel ?? this.labels().confirmDelete;
669
+ return this.confirm({ ...data, tone: 'danger', confirmLabel });
670
+ }
671
+ /** Tek butonlu bilgilendirme modu — sonuç önemsiz olduğu için `Promise<void>` döner. */
672
+ alert(data) {
673
+ const ref = this.open(ConfirmDialog, {
674
+ data: { ...data, alert: true },
675
+ size: 'sm',
676
+ ariaLabel: data.title,
677
+ });
678
+ return new Promise((resolve) => ref.closed.subscribe(() => resolve()));
679
+ }
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' });
682
+ }
683
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: DialogService, decorators: [{
684
+ type: Injectable,
685
+ args: [{ providedIn: 'root' }]
686
+ }] });
687
+
688
+ // `MF_DIALOG_LABELS`/`MfDialogLabels` artık `@mesgflow/ui-kit/core`'da yaşıyor
689
+ // (bkz. `core/i18n/tokens.ts` — MF_LABELS'ın bir seçicisi) — buradan AYRICA
690
+ // re-export etmek `ng build ui-kit`'de TS2308 (ambiguous export) veriyor, çünkü
691
+ // birincil barrel zaten hem `./core`'u hem `./dialog`'u `export *` ediyor.
692
+ // Tüketici `import { MF_DIALOG_LABELS } from '@mesgflow/ui-kit'` (birincil barrel)
693
+ // veya `'@mesgflow/ui-kit/core'` kullanır.
694
+
695
+ /**
696
+ * Generated bundle index. Do not edit.
697
+ */
698
+
699
+ export { ConfirmDialog, Dialog, DialogResizeHandle, DialogService, DialogSurface, dialogVariants };
700
+ //# sourceMappingURL=mesgflow-ui-kit-dialog.mjs.map