@appaflytech/zeyrek-ai-mcp 0.0.18 → 0.0.20

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 (65) hide show
  1. package/README.md +13 -14
  2. package/dist/config.js +2 -0
  3. package/dist/knowledge/componentCatalog.js +204 -836
  4. package/dist/knowledge/componentEvents.js +75 -368
  5. package/dist/knowledge/mobileComponentCatalog.js +331 -0
  6. package/dist/knowledge/mobileComponentEvents.js +50 -0
  7. package/dist/knowledge/normalize.js +63 -66
  8. package/dist/knowledge/platform/lint.js +205 -0
  9. package/dist/knowledge/platform/mobile.js +78 -0
  10. package/dist/knowledge/platform/mobileRules.js +121 -0
  11. package/dist/knowledge/platform/mobileTabs.js +108 -0
  12. package/dist/knowledge/platform/profile.js +20 -0
  13. package/dist/knowledge/platform/resolve.js +122 -0
  14. package/dist/knowledge/platform/web.js +38 -0
  15. package/dist/knowledge/rules.js +6 -29
  16. package/dist/knowledge/styleResolve.js +1 -1
  17. package/dist/knowledge/styleResolveNative.js +410 -0
  18. package/dist/knowledge/themeResolve.js +3 -3
  19. package/dist/platform/capture/actions.js +333 -0
  20. package/dist/platform/capture/browser.js +1 -0
  21. package/dist/platform/{screenshot.js → capture/capture.js} +23 -509
  22. package/dist/platform/capture/index.js +10 -0
  23. package/dist/platform/capture/readiness.js +103 -0
  24. package/dist/platform/capture/summary.js +77 -0
  25. package/dist/platform/capture/target.js +5 -0
  26. package/dist/platform/capture/targets/studio-mobile.js +15 -0
  27. package/dist/platform/capture/targets/studio-web.js +5 -0
  28. package/dist/platform/domSummary.js +1 -1
  29. package/dist/platform/responses.js +1 -2
  30. package/dist/platform/strictArguments.js +2 -22
  31. package/dist/platform/writeDiff.js +31 -58
  32. package/dist/resources/examples/mobile-app-shell-drawer.json +209 -0
  33. package/dist/resources/examples/mobile-app-shell-stack.json +123 -0
  34. package/dist/resources/examples/mobile-app-shell-tab.json +174 -0
  35. package/dist/resources/examples/mobile-list-detail-form.json +656 -0
  36. package/dist/resources/guides/component.md +6 -9
  37. package/dist/resources/guides/functions.md +3 -32
  38. package/dist/resources/guides/getting-started.md +0 -35
  39. package/dist/resources/guides/layout.md +11 -7
  40. package/dist/resources/guides/mobile.md +215 -0
  41. package/dist/resources/guides/page.md +71 -49
  42. package/dist/resources/guides/translation.md +6 -5
  43. package/dist/resources/schema-fingerprint.json +2 -2
  44. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +0 -18
  45. package/dist/server.js +2 -0
  46. package/dist/tools/applications.js +60 -3
  47. package/dist/tools/components.js +50 -10
  48. package/dist/tools/designSchemaPatch.js +18 -13
  49. package/dist/tools/externalComponents.js +25 -4
  50. package/dist/tools/flows.js +51 -38
  51. package/dist/tools/functions.js +10 -20
  52. package/dist/tools/layouts.js +41 -9
  53. package/dist/tools/microservices.js +11 -39
  54. package/dist/tools/mobile.js +203 -0
  55. package/dist/tools/pages.js +127 -95
  56. package/dist/tools/platformInfo.js +2 -1
  57. package/dist/tools/profileWrite.js +45 -0
  58. package/dist/tools/schemaOps.js +2 -2
  59. package/dist/tools/screenWrite.js +2 -2
  60. package/dist/tools/screens.js +9 -3
  61. package/dist/tools/workflows.js +12 -39
  62. package/package.json +2 -7
  63. package/dist/platform/diagnostics.js +0 -85
  64. package/dist/platform/ifExists.js +0 -129
  65. package/dist/platform/writeView.js +0 -17
@@ -22,49 +22,11 @@ export const componentEventContracts = {
22
22
  mount: { payload: {}, reads: 'self.filters · self.sortField · self.sortType · self.offset · self.limit' }
23
23
  },
24
24
  button: { mount: NO_DATA, click: NO_DATA },
25
- card: {
26
- mount: NO_DATA,
27
- click: NO_DATA,
28
- buttonClick: {
29
- payload: {},
30
- reads: 'Kartın kendi butonuna (buttonText) basılınca yayılır. Kabarcığı DURDURMAZ: aynı tıklama kartın click olayını da çalıştırır — yalnız buton eylemi isteniyorsa click bağını boş bırakın.'
31
- }
32
- },
33
- compound: {
34
- mount: NO_DATA,
35
- click: {
36
- payload: {},
37
- reads: 'Düğmeye tıklanınca yayılır — href YAZILIYKEN DE yayılır, yani gezinme ile akış birlikte koşar. isDisabled ya da isLoading açıkken hiç yayılmaz.'
38
- }
39
- },
40
- image: {
41
- mount: NO_DATA,
42
- click: {
43
- payload: {},
44
- reads: 'Görsele (ya da kırık/boş kaynağın yedek kutusuna) tıklanınca yayılır. isZoomable açıkken aynı tıklama büyütülmüş önizlemeyi de açar; akış iptal edilmez.'
45
- }
46
- },
47
- qrcode: {
48
- mount: NO_DATA,
49
- click: {
50
- payload: {},
51
- reads: 'Koda tıklanınca yayılır, ama YALNIZ akışa bağlıysa ve ekranda gerçek bir kod varken (yer tutucu ve iskelet tıklanmaz). Bağlıyken düğüm <button> olur ve odak sırasına girer; bağlı değilken role="img" taşıyan salt görsel bir <div>tür.'
52
- },
53
- error: {
54
- payload: {
55
- errorText: 'string (kütüphanenin kendi mesajı, ör. "Data too long: expected 1273 but got 1600")'
56
- },
57
- reads: 'self.errorText YA DA event.data.errorText — ikisi de dolu. YALNIZ üretim başarısızlığında yayılır — pratikte tek sebebi kapasite: seçilen errorCorrectionLevel’de sığmayan data (bayt sınırı L 2953 · M 2331 · Q 1663 · H 1273). BOŞ data hata DEĞİLDİR ve bu olayı çalıştırmaz, kesikli yer tutucu çizilir. Veri düzelince hata bir sonraki çizim turunda temizlenir ve olay yeniden yayılmaz.'
58
- }
59
- },
25
+ card: { click: NO_DATA },
26
+ compound: { click: NO_DATA },
27
+ image: { click: NO_DATA },
60
28
  'qm-card': { click: NO_DATA },
61
- form: {
62
- mount: NO_DATA,
63
- submit: {
64
- payload: {},
65
- reads: "Yalnız BÜTÜN kurallar geçince yayılır (alan kuralları + formun kendi validations dizisi); kalırsa olay çalışmaz, alanlar işaretlenir. event.data BOŞ. event.source.id = formu gönderen düğmenin ADI, event.source.props = onun prop'ları (Type='submit' düğme; Enter'la gönderimde formun ilk submit düğmesi; formda hiç submit düğmesi yoksa event.source formun KENDİSİDİR) — aynı formu iki düğme gönderiyorsa ('Kaydet' / 'Kaydet ve kapat') dallanma buradan. Toplu değer self.value = { <alan adı>: değer } (Page.components.<form>.value ile de okunur), self.isValid bu anda her zaman true."
66
- }
67
- },
29
+ form: { mount: NO_DATA, submit: NO_DATA },
68
30
  container: { mount: NO_DATA },
69
31
  aibox: { mount: NO_DATA },
70
32
  box: { mount: NO_DATA },
@@ -72,8 +34,8 @@ export const componentEventContracts = {
72
34
  divider: {},
73
35
  spacer: {},
74
36
  popover: {
75
- open: { payload: { isOpen: 'boolean (true)' }, reads: 'Tetikleyici yolunda setter: self.isOpen da yazılır. Akış isOpen’ı kendisi yazınca da open çıkar (setter’sız, prop zaten yazılmış) — açılış nasıl olursa olsun tek olay. İlk çizimde çıkmaz; editörde tetikleyici çalışmaz.' },
76
- close: { payload: { isOpen: 'boolean (false)' }, reads: 'Tetikleyici, dışarı tıklama, Escape ya da hover ayrılışı: setter, self.isOpen yazılır. Akış isOpen’ı false yazınca da close çıkar (setter’sız).' }
37
+ open: { payload: { isOpen: 'boolean (true)' }, reads: 'setter: self.isOpen da yazılır — akış paneli isOpen prop’unu değiştirerek de açıp kapatabilir' },
38
+ close: { payload: { isOpen: 'boolean (false)' }, reads: 'setter: self.isOpen da yazılır' }
77
39
  },
78
40
  phoneinput: {
79
41
  mount: NO_DATA,
@@ -108,9 +70,9 @@ export const componentEventContracts = {
108
70
  payload: { text: 'string', parentId: "string (yanıtsa üst yorumun id’si, kök yorumda '')", mentions: 'string[] (metinden çözülmüş @kişi listesi)', author: 'string (currentUser)' },
109
71
  reads: 'Komponent yorumu ANINDA iyimser olarak listeye ekler (bekleyen katman); kalıcılık akışın işidir — rows tazelenmezse bekleyen satır bir sonraki içerik değişiminde kaybolur'
110
72
  },
111
- like: { payload: { id: 'string', liked: 'boolean (yeni durum)', author: 'string (currentUser — işlemi yapan)' }, reads: 'beğeni de iyimserdir; sayaç rows tazelenene kadar yerel. isDisabled/isReadonly/isViewmode açıkken yayılmaz' },
112
- edit: { payload: { id: 'string', text: 'string (yeni metin)', author: 'string (currentUser — işlemi yapan)' }, reads: 'düzenleme de iyimserdir; yeni metin "düzenlendi" işaretiyle rows tazelenene kadar yerel. Metin değişmediyse yayılmaz' },
113
- delete: { payload: { id: 'string', author: 'string (currentUser — işlemi yapan)' }, reads: 'satır (kök yorumsa yanıtlarıyla birlikte) listeden hemen gizlenir; uca yazmak akışın işidir' }
73
+ like: { payload: { id: 'string', liked: 'boolean (yeni durum)', author: 'string' }, reads: 'beğeni de iyimserdir; sayaç rows tazelenene kadar yerel' },
74
+ edit: { payload: { id: 'string', text: 'string (yeni metin)', author: 'string' } },
75
+ delete: { payload: { id: 'string', author: 'string' }, reads: 'satır listeden hemen çıkarılır; uca yazmak akışın işidir' }
114
76
  },
115
77
  'auth-layout': { mount: NO_DATA, primaryClick: NO_DATA, secondaryClick: NO_DATA },
116
78
  layout: { mount: NO_DATA, logout: NO_DATA },
@@ -151,18 +113,7 @@ export const componentEventContracts = {
151
113
  focus: NO_DATA,
152
114
  blur: NO_DATA
153
115
  },
154
- incrementalinput: {
155
- mount: NO_DATA,
156
- change: {
157
- payload: {
158
- value: "string (elle yazılan metin) YA DA { Prefix, Separator, Counter, DigitCount, FieldId } (sunucudan kod gelince: kodun METNİ DEĞİL, kodu üreten şekil)"
159
- },
160
- reads: 'setter: self.value da yazılır. Elle yazarken HER TUŞTA, otomatik kod gelince bir kez yayılır — pahalı akışı changed’e bağla'
161
- },
162
- changed: valueChange('string (alan bırakılınca kesinleşen metin; yalnız ELLE düzenlemede yayılır)'),
163
- focus: NO_DATA,
164
- blur: NO_DATA
165
- },
116
+ incrementalinput: { mount: NO_DATA, change: valueChange('string'), blur: NO_DATA },
166
117
  // Adlar 2026-09-11'de `on` önekinden kurtuldu: şema onMount/onChange diyordu, runtime
167
118
  // mount/change yayıyordu ve flow-machine eşleşmeyi ADLA yaptığı için bu bileşene bağlanan
168
119
  // hiçbir akış çalışmıyordu.
@@ -193,13 +144,6 @@ export const componentEventContracts = {
193
144
  dropdown: { mount: NO_DATA, change: { payload: { value: 'seçilen option değeri', selectedLabel: "seçilen option'ın label metni (temizlemede '')" } }, search: { payload: { searchText: 'string' } }, focus: NO_DATA, blur: NO_DATA },
194
145
  'multi-select': { mount: NO_DATA, change: { payload: { value: "seçilen değerlerin dizisi: [{ value, label, id, text }] — id/text, value/label'ın eski adlı ikizleridir" } }, search: { payload: { searchText: 'string' } }, focus: NO_DATA, blur: NO_DATA },
195
146
  'tag-input': { mount: NO_DATA, change: { payload: { value: 'etiket dizisi: [{ value, color? }] — renk verilmemiş etikette color anahtarı HİÇ bulunmaz' } }, search: { payload: { searchText: 'string' } }, focus: NO_DATA, blur: NO_DATA },
196
- tags: {
197
- mount: NO_DATA,
198
- clickItem: {
199
- payload: { currentItem: 'tıklanan öğe (values’taki nesnenin tamamı; düz metin dizisinde metin)', index: 'number (values dizisindeki gerçek yer; atlanan öğeler kaydırmaz)' },
200
- reads: "event.data.currentItem ve event.data.index ile oku; currentItem ayrıca self.currentItem'a yazılır, index self'e YAZILMAZ. clickItem satırı yoksa etiketler tıklanamaz. Bileşen isActive'i değiştirmez — seçimi akış values'a yazar"
201
- }
202
- },
203
147
  datepicker: {
204
148
  mount: NO_DATA,
205
149
  change: {
@@ -246,153 +190,46 @@ export const componentEventContracts = {
246
190
  focus: NO_DATA,
247
191
  blur: NO_DATA
248
192
  },
249
- fileUpload: {
250
- change: {
251
- payload: { value: "Array<{ value: base64 data URL, fileName: string, type: 'file', ref: '' }>" },
252
- reads: 'self.value — dosya EKLENİNCE de SİLİNİNCE de (çipe tıklama) aynı olay yayılır ve yük her seferinde KALAN TÜM listedir, yalnız yeni dosyalar değil. isMultiple:false iken dizi tek elemanlıdır. Kilitliyken (isDisabled/isReadonly/isViewmode) hiç yayılmaz; tür/boyut/adet sınırına takılan dosya listeye girmez ve uyarı komponentin içinde çizilir, ama kabul KISMİDİR: geçen dosya varsa olay GEÇENLERLE yayılır, yalnız hepsi reddedilirse hiç yayılmaz. enableCrop açıkken görsel dosyalar kırpma katmanından geçtikten SONRA yayılır (İptal dosyayı düşürür; hepsi düşerse olay çalışmaz).'
253
- }
254
- },
255
- fileInput: {
256
- mount: NO_DATA,
257
- change: {
258
- payload: {
259
- value: '{ type: "file", fileName: string, value: string (base64 data URL) } — isMultiple açıkken bu nesnelerin DİZİSİ; boşaltma { type: "ref", value: null } (çoklu seçimde tek elemanlı dizisi)'
260
- },
261
- reads: 'Tek anahtar value düğümün prop’una yazılır: akış self.value ile okur, dosya adı self.value.fileName’dedir (ÜST DÜZEY fileName anahtarı YOKTUR — 2026-09-17’de kayıttan çıkarıldı, runtime hiç göndermiyordu). Çoklu seçimde yeni dosyalar eskilerin üstüne EKLENİR ve yük KALAN TÜM listedir. Tür/boyut/adet sınırına takılan dosya listeye girmez ve uyarı alanın altına yerel mesaj olarak yazılır, ama kabul KISMİDİR: geçen dosya varsa change GEÇENLERLE yayılır (5 dosya + maxFileCount:3 → 3’ü akışa gider), yalnız hepsi elenirse hiç yayılmaz — tek dosyalık alanda zaten hepsi ya da hiçbiri. Açılır listedeki × o dosyayı siler ve change’i KALAN listeyle yayar; son dosya silinince ve çipin temizle düğmesiyle boşaltma değeri yazılır. Kilitliyken (isDisabled/isReadonly/isViewmode) hiç yayılmaz; enableCrop açıkken görseller kırpma katmanından geçtikten SONRA yayılır (İptal dosyayı düşürür, hepsi düşerse olay çalışmaz)'
262
- }
263
- },
264
- filebutton: {
265
- mount: NO_DATA,
266
- change: {
267
- payload: {
268
- value: "tekli kipte { type: 'file', value: base64 data URL, fileName: string, ref: '' } TEK nesne (temizlenince null); çoklu kipte aynı nesnelerin DİZİSİ (temizlenince [])"
269
- },
270
- reads: "self.value — düğümün value prop'una yazılır. fileName üst düzey anahtar DEĞİLDİR, her dosyanın kendi alanıdır (2026-09-17'de düzeltildi; kayıt runtime'ın hiç göndermediği bir yük anlatıyordu). Çoklu kipte yük KALAN TÜM listedir: yeni parti mevcut listenin ÜSTÜNE eklenir, X bir satırı siler, 'Tümünü temizle' [] yayar. Kilitliyken (isDisabled/isReadonly/isViewmode) hiç yayılmaz; tür/boyut/adet sınırına takılan dosya listeye girmez, uyarı komponentin içinde çizilir ve hepsi elenirse olay çalışmaz."
271
- }
272
- },
273
- 'file-viewer': { mount: NO_DATA, load: NO_DATA, error: NO_DATA },
193
+ fileUpload: { change: { payload: {}, reads: 'self.value' } },
194
+ fileInput: { change: { payload: { value: 'Array<{ type, value }>', fileName: 'string' } } },
195
+ filebutton: { change: { payload: { value: 'Array<{ type, value }>', fileName: 'string' } } },
196
+ 'file-viewer': { mount: NO_DATA },
274
197
  modal: { open: NO_DATA, close: NO_DATA },
275
198
  drawer: { open: NO_DATA, close: NO_DATA },
276
- repeater: {
277
- mount: NO_DATA,
278
- change: {
279
- payload: { selectedIndex: 'number (satırın sırası, 0’dan)' },
280
- reads: 'self.selectedItem (seçilen satırın verisi) — seçilen satır DEĞİŞİNCE yayılır: satıra tıklama ya da satırdaki bir çocuğun olayı. Aynı satıra tekrar tıklamak change üretmez. Akış satır bağlamında koşmaz: item/Row burada boştur, satırı self.selectedItem ile oku'
281
- },
282
- select: {
283
- payload: { selectedIndex: 'number (tıklanan satırın sırası, 0’dan)' },
284
- reads: 'self.selectedItem — satıra ulaşan HER tıklamada yayılır (aynı satır dahil; tıklamayı yutan dropdown-button/tag-input/tarih seçici gibi çocuklarda gelmez, etiket tıklaması tek sayılır); satır değiştiyse change ondan önce yayılır. Satırdaki butonun kendi click akışı select’ten önce başlar'
285
- }
286
- },
287
- tabs: {
288
- mount: NO_DATA,
289
- tab: {
290
- payload: { selected: 'string (geçilen sekmenin key\'i; key boşsa sırası "0", "1"…)' },
291
- reads: "selected self'e yazılır; event.data.selected da dolu gelir. Yalnız kullanıcı selected'dan farklı key'li sekmeye geçince (tıklama, ←/→/Home/End) yayılır — selected'ın gösterdiği sekmeye tekrar tıklamak ve akışın selected yazması olay üretmez; görünen sekme bir geri düşüşse ona tıklamak yayar"
292
- }
293
- },
199
+ repeater: { mount: NO_DATA, change: { payload: { selectedIndex: 'number' }, reads: 'item / Row (satır bağlamı)' } },
200
+ tabs: { mount: NO_DATA, tab: { payload: { selected: 'string (sekme anahtarı)' } } },
294
201
  'tree-view': {
295
202
  mount: NO_DATA,
296
203
  click: {
297
204
  payload: { selected: 'string (tıklanan satırın key’i)', currentItem: 'tıklanan satırın tamamı ({ key, text, subtle, icon, image, children… })' },
298
- reads: "event.data.selected / event.data.currentItem ya da self.selected / self.currentItem — ikisi de dolu. isDisabled satır tıklanmaz. Aksiyon menüsü AYRI olay yaymaz: aksiyonun kendi flow'u çalışır, orada event.data = { currentItem, actionKey } ve satır yine self.currentItem'a yazılır"
299
- },
300
- change: {
301
- payload: {
302
- checkedKeys: "string[] (normalize edilmiş işaretli key'ler, belge sırasıyla; ağaçta çizilmeyen key'ler sonda)",
303
- currentItem: 'kutusuna tıklanan satırın tamamı',
304
- isChecked: 'boolean (tıklamadan sonra o satır tam işaretli mi; yalnız event.data’da)'
305
- },
306
- reads: "event.data.checkedKeys ya da self.checkedKeys; self.currentItem da yazılır, isChecked yalnız event.data'da. Yalnız isCheckable:true iken kullanıcı kutuya tıklayınca yayılır — akışın checkedKeys yazması olay üretmez"
307
- }
308
- },
309
- 'dropdown-button': {
310
- mount: NO_DATA,
311
- click: {
312
- payload: {},
313
- reads: 'Butonun kendisine basılınca (menüyü açan/kapatan tıklama) yayılır — menü açılmasa bile. isDisabled/isLoading iken hiç yayılmaz. Menü SATIRI bu olayı yaymaz.'
314
- },
315
- clickItem: {
316
- payload: {
317
- currentItem: 'tıklanan menü öğesinin TAMAMI ({ key, text, icon, flow, isDanger, isDisabled… }) — akışta self.currentItem ile okunur'
318
- },
319
- reads: "Her satır tıklamasında yayılır. Satırın kendi flow'u (options[].flow) varsa o akış AYRICA çalışır ve aynı currentItem'ı görür; yani flow bağlı bir satır iki akış tetikleyebilir."
320
- }
321
- },
322
- 'confirm-bar': {
323
- mount: NO_DATA,
324
- click: {
325
- payload: { currentItem: 'tıklanan aksiyonun TAMAMI (key, text, kind, variant, icon, flow, href, isDisabled, isLoading…)' },
326
- reads: "self.currentItem — şeridin aksiyon butonuna basılınca yayılır. Aksiyonun kendi flow'u varsa o akış ÖNCE koşar ve click olayına bağlı akışlar AYRICA koşar (tek tıklamada iki akış); yalnız biri istensin diye ya aksiyonun flow alanını ya da click bağını boş bırakın. href yazılmış aksiyon LİNK olur: tarayıcı adrese gider, click YAYILMAZ (Button'un type:'link' sözleşmesi). isDisabled/isLoading aksiyonun tıklaması hiç yayılmaz."
327
- },
328
- close: {
329
- payload: { isHidden: 'true' },
330
- reads: 'Yalnız showCloseButton:true iken çizilen kapatma düğmesine basılınca yayılır. Şerit KENDİNİ gizler: isHidden düğümün prop\'una yazılır (self.isHidden true olur) ve render katmanı şeridi söker — geri getirmek için akışta isHidden:false yazın. Tasarımcı kanvasında gizlenme uygulanmaz.'
205
+ reads: "aksiyon menüsü AYRI olay yaymaz: aksiyonun kendi flow'u çalışır ve satır yine self.currentItem'a yazılır"
331
206
  }
332
207
  },
208
+ 'dropdown-button': { mount: NO_DATA, click: NO_DATA, clickItem: { payload: { currentItem: 'tıklanan menü öğesi' } } },
209
+ 'confirm-bar': { mount: NO_DATA, click: { payload: { currentItem: 'tıklanan buton tanımı' } } },
333
210
  'collapsible-container': {
334
211
  mount: NO_DATA,
335
- collapsed: {
336
- payload: {},
337
- reads: "Kullanıcı bölümü KAPATINCA yayılır; komponent aynı anda isOpen'ı false'a yazar, akışta self.isOpen ile okunur. Akıştan (setter ile) isOpen yazmak bu olayı YAYMAZ. Kapanışta gövdedeki komponentler DOM'dan sökülür: onların durumu kaybolur, açılışta mount'ları yeniden koşar"
338
- },
339
- expanded: {
340
- payload: {},
341
- reads: "Kullanıcı bölümü AÇINCA yayılır (isOpen true olarak geri yazılır, akışta self.isOpen). Kapalı bölümün içi hiç kurulmadığı için verinin çekileceği doğru yer budur; her açılışta yeniden koşar, tek seferlik değildir"
342
- }
212
+ collapsed: { payload: { isOpen: 'boolean — false; yük kabın yeni durumudur ve bileşenin isOpen prop\'una yazılır' } },
213
+ expanded: { payload: { isOpen: 'boolean — true; yük kabın yeni durumudur ve bileşenin isOpen prop\'una yazılır' } }
343
214
  },
344
215
  'audit-basic': { mount: NO_DATA },
345
- 'audit-history': {
346
- mount: NO_DATA,
347
- showMore: { payload: {}, reads: 'yalnız histories visibleLogCount’u aşınca çıkan "Daha fazla göster" düğmesine basılınca; görünür sınır visibleLogCount kadar büyür, kalan kalmayınca düğme kaybolur. Bileşen veri çekmez; backend kayıt başına en fazla 5 işlem verdiği için meta.history bağlıyken düğme ancak visibleLogCount < 5 iken çıkar' }
348
- },
216
+ 'audit-history': { mount: NO_DATA },
349
217
  'form-validation-errors': { mount: NO_DATA },
350
- 'page-header': {
351
- mount: NO_DATA,
352
- clickItem: {
353
- payload: {
354
- currentItem: 'tıklanan links satırının tamamı (düz metin dizisinde metnin kendisi)',
355
- index: 'number (links dizisindeki gerçek yer; metinsiz satırlar atlanır ama kaydırmaz). Kök öğe yoktur, -1 gelmez'
356
- },
357
- reads: "event.data.currentItem ve event.data.index ile oku. currentItem düğüme de yazılır (şemada gizli durum prop'u) ama self.currentItem ifade yüzeyine yalnız düğüm o anahtarı kayıtta taşıyorsa çıkar (makine anahtar kümesini kurulurken düğümün prop'larından toplar) — güvenilir yol event.data'dır; index self'e YAZILMAZ. Olayı içteki breadcrumb yayar, page-header olduğu gibi geçirir — yalnız page-header düğümünde bir akış bağlıysa yayılır, bağsız tıklama düğüme hiçbir şey yazmaz. Başlık (pageTitle, izin son öğesi) tıklanabilir DEĞİLDİR, bu olayı hiç yaymaz. Adresi olan öğe <a> olduğu için bağlı tıklama hem bu olayı yayar HEM de adrese gider — yalnız akış karar versin isteniyorsa satırın href'ini boş bırak"
358
- }
359
- },
218
+ 'page-header': { mount: NO_DATA },
360
219
  header: { mount: NO_DATA },
361
220
  sidebar: { mount: NO_DATA },
362
221
  html: { mount: NO_DATA },
363
222
  view: { mount: NO_DATA },
364
223
  'widget-area': { mount: NO_DATA },
365
224
  'document-editor': { mount: NO_DATA },
366
- video: {
367
- mount: {
368
- payload: {},
369
- reads: "Bileşen mount'u KENDİSİ yaymaz — ortak render katmanı (RenderComponent.handleMount) her düğüm için bir kez yayar. 2026-09-16 turuna kadar Video.svelte de kendi onMount'unda yayıyordu ve mount'a bağlı akış İKİ KEZ koşuyordu (ARC-006, kapandı)"
370
- },
371
- click: {
372
- payload: {},
373
- reads: 'Yalnız akışa bağlıysa sarmalayıcı tıklanabilir olur; controls açıkken oynat/duraklat düğmesine basmak da bu olayı tetikler (tıklama sarmalayıcıya kabarır). isLoading:true iken HİÇ çalışmaz — o dalda oynatıcı yerine iskelet çizilir ve sarmalayıcı tıklanabilir değildir'
374
- },
375
- play: {
376
- payload: { isPlaying: 'boolean (true)' },
377
- reads: "setter: self.isPlaying da yazılır — akış props.isPlaying'e true yazarak videoyu BAŞLATABİLİR de (sesli videoda tarayıcı reddeder). event.data ayrıca { currentTime: number (saniye), duration: number (saniye; meta yüklenmemişse VE canlı yayında — süresi Infinity — 0) } taşır"
378
- },
379
- pause: {
380
- payload: { isPlaying: 'boolean (false)' },
381
- reads: "setter: self.isPlaying da yazılır; akış false yazarak duraklatabilir. event.data: { currentTime, duration }. DİKKAT: video BİTTİĞİNDE de yayılır — HTML spesifikasyonu bitişte önce pause sonra ended yayar, yani 'kullanıcı duraklattı' demek değildir; ayırmak için currentTime ≈ duration karşılaştır"
382
- },
383
- ended: {
384
- payload: { isPlaying: 'boolean (false)' },
385
- reads: 'loop açıkken HİÇ yayılmaz (döngü videosu bitmez). event.data: { currentTime, duration } — bitişte currentTime pratikte duration’a eşittir. Bitişte pause’dan SONRA gelir (spesifikasyon sırası), yani ended akışı pause akışının ardından koşar'
386
- }
387
- },
225
+ video: { mount: NO_DATA, click: NO_DATA, play: NO_DATA, pause: NO_DATA, ended: NO_DATA },
388
226
  // — 2026-08-25 eşleme turu: ng-apps-ui'da olay YAYAN ama burada kaydı olmayan komponentler.
389
227
  // Yükler kaynaktaki dispatch('emit', { name, data }) / machine.onEmit(id, { event, data })
390
- // çağrılarından birebir çıkarıldı. Olay yaymayan komponentler (slot ·
391
- // text) bilinçli olarak kayıtsızdır. `breadcrumb` de bu listedeydi; 2026-09-17
392
- // component-analiz turunda şemaya mount + clickItem eklendi ve kaydı yukarıda açıldı. `notification` bu listede
228
+ // çağrılarından birebir çıkarıldı. Olay yaymayan komponentler (breadcrumb · qrcode · slot · tags ·
229
+ // text) bilinçli olarak kayıtsızdır. `notification` bu listede
393
230
  // YANLIŞLIKLA yer almıştı — Notification.svelte hem timeout'ta hem kapatma tıklamasında
394
- // emit yayıyor (düzeltme 2026-08-25c, `docs/20-komponent-bilgi-katmani.md` §9); o emit'in adı
395
- // 2026-09-17'de toggled → close oldu ve şemada bildirildi, kaydı aşağıda.
231
+ // dispatch('emit', { name:'toggled', data:{isHidden:true}, setter:true }) çağırıyor (düzeltme
232
+ // 2026-08-25c, `docs/20-komponent-bilgi-katmani.md` §9).
396
233
  autocomplete: {
397
234
  mount: NO_DATA,
398
235
  change: {
@@ -411,112 +248,52 @@ export const componentEventContracts = {
411
248
  focus: NO_DATA,
412
249
  blur: NO_DATA
413
250
  },
414
- avatar: { mount: NO_DATA, click: NO_DATA },
415
- badge: {
416
- mount: NO_DATA,
417
- click: {
418
- payload: {},
419
- reads: 'yalnız şemada bir akış bağlıysa yayılır; bağlıyken rozet <button> olur, bağlı değilken salt görsel <span> kalır ve olay hiç çıkmaz'
420
- }
421
- },
422
- icon: { mount: NO_DATA, click: NO_DATA },
423
- breadcrumb: {
424
- mount: NO_DATA,
425
- clickItem: {
426
- payload: {
427
- currentItem: 'tıklanan öğe (items satırının tamamı; düz metin dizisinde metin). KÖK öğede items satırı yoktur, yük { title: homeTitle, href: homeHref } taşır',
428
- index: 'number (items dizisindeki gerçek yer; metinsiz öğeler atlanır ama kaydırmaz). KÖK öğede -1'
429
- },
430
- reads: "event.data.currentItem ve event.data.index ile oku; currentItem ayrıca self.currentItem'a yazılır (şemada gizli durum prop'u), index self'e YAZILMAZ. Yalnız şemada bir akış bağlıysa yayılır — bağsız tıklama düğüme hiçbir şey yazmaz. Bulunulan sayfa (currentTitle) tıklanabilir DEĞİLDİR, bu olayı hiç yaymaz. Adresi olan öğe <a> olduğu için bağlı tıklama hem bu olayı yayar HEM de adrese gider — yalnız akış karar versin isteniyorsa öğenin href'ini boş bırak; href'i de clickItem bağı da olmayan öğe düz metindir, tıklanamaz"
431
- }
432
- },
251
+ avatar: { click: NO_DATA },
252
+ badge: { click: NO_DATA },
253
+ icon: { click: NO_DATA },
433
254
  'breadcrumb-title': {
434
255
  mount: NO_DATA,
435
- clickItem: {
436
- payload: { currentItem: '{ key, text, flow, isHidden } — tıklanan iz öğesi (satır içi ya da … menüsünden, ikisi de aynı yükü yayar)' },
437
- reads: 'self.currentItem — öğe düğümün prop’una da yazılır; akış hangi adımın seçildiğini self.currentItem.key ile okur. Öğenin kendi flow’u varsa ÖNCE o çalışır, sonra clickItem yayılır.'
438
- },
439
- clickRoot: {
440
- payload: {},
441
- reads: 'Kök ikonuna her basışta yayılır — rootHref yazılıyken de (o durumda yalnız rootFlow atlanır, gezinme olaydan sonra başlar).'
442
- }
256
+ clickItem: { payload: { currentItem: '{ text, flow, isHidden } — tıklanan iz öğesi' } },
257
+ clickRoot: NO_DATA
443
258
  },
444
259
  carousel: {
445
260
  mount: NO_DATA,
446
- slideChange: {
447
- payload: { activeIndex: 'number (görünen slaytın 0-tabanlı indeksi)' },
448
- reads: "event.data.activeIndex ile oku; aynı değer setter ile düğümün kendi activeIndex prop'una da yazılır (self.activeIndex). Ok, nokta, klavye (←/→), swipe ve otomatik geçişin hepsi bu olaydan geçer; aynı indekse gitmek olay yaymaz"
449
- },
450
- slideClick: {
451
- payload: { currentItem: 'tıklanan slayt nesnesinin tamamı (items satırı)', index: 'number (items dizisindeki yer)' },
452
- reads: "event.data.currentItem ve event.data.index ile oku; currentItem ayrıca self.currentItem'a yazılır, index self'e YAZILMAZ. HER slayt tıklamasında yayılır (href/flow şart değil); slaytta flow varsa bu olayın akışı da slaytın kendi flow'u da çalışır, ikisi de aynı event.data'yı alır. Eşiği aşan sürükleme ve ok/nokta düğmeleri bu olayı tetiklemez"
453
- }
261
+ slideChange: { payload: { activeIndex: 'number' } },
262
+ slideClick: { payload: { currentItem: 'slayt nesnesi', index: 'number' } }
454
263
  },
455
264
  chart: {
456
265
  mount: NO_DATA,
457
- dataPointClick: { payload: { name: 'string (kategori); scatter grafiğinde x değeri', seriesName: 'string', value: 'number | null; scatter grafiğinde y', dataIndex: 'number', row: 'kaynak satırın TAMAMI | null' }, reads: 'YALNIZ seri noktasında yayılır; eksen etiketi tıklaması axisLabelClick’tir (2026-09-16 öncesinde o da boş bir dataPointClick üretiyordu). scatter noktası ECharts tarafında [x, y, size] dizisidir, yük tek değere indirgenir: name = x, value = y' },
266
+ dataPointClick: { payload: { name: 'string (kategori)', seriesName: 'string', value: 'number | null', dataIndex: 'number', row: 'kaynak satırın TAMAMI | null' } },
458
267
  breadcrumbClick: { payload: { filterValue: 'hedef seviyenin filtre değeri (kök seviyede undefined)' } },
459
268
  selectionChange: { payload: { selected: 'seçili veri noktaları' } },
460
269
  legendClick: { payload: { name: 'string (seri adı)', selected: 'seri → görünürlük haritası' } },
461
- axisLabelClick: { payload: { value: 'string (tıklanan eksen etiketi)' }, reads: 'Kategori ekseni hangi eksene düşerse oradan gelir — yatay yönelimde yAxis (2026-09-16 öncesinde yatayda hiç yayılmıyordu)' },
462
- zoom: { payload: { start: 'number | null (görünen aralığın başlangıç yüzdesi)', end: 'number | null (bitiş yüzdesi)', startValue: 'number | null (eksenin kendi birimindeki mutlak alt sınır)', endValue: 'number | null (mutlak üst sınır)' }, reads: 'Yük normalize edilir: ECharts iki dataZoom bileşeniyle alanları batch içine koysa da akış her zaman bu dört alanı görür. Aralığı sorguya çevirecekseniz yüzdeleri değil startValue/endValue kullanın (2026-09-16)' },
270
+ axisLabelClick: { payload: { value: 'string (tıklanan eksen etiketi)' } },
271
+ zoom: { payload: { start: 'number (görünen aralığın başlangıç yüzdesi)', end: 'number (bitiş yüzdesi)' }, reads: "ECharts dataZoom params'ı olduğu gibi geçer; sürüme göre batch/startValue/endValue de gelebilir" },
463
272
  refresh: NO_DATA,
464
273
  retry: NO_DATA
465
274
  },
466
275
  checkboxgroup: { mount: NO_DATA, change: valueChange('string[] (seçili değerler)'), focus: NO_DATA, blur: NO_DATA },
467
- emptystate: {
468
- mount: NO_DATA,
469
- actionClick: { payload: { text: 'string (aksiyonun metni)', index: 'number' }, reads: "aksiyonun kendi flow'u zaten doğrudan çalışır; index GÖRÜNEN aksiyonların sırasıdır (isHidden olanlar elenmiş). href dolu satırda olay YİNE yayılır ama aynı sekmede gezinme sayfayı değiştirir ve olayın sayfa-içi sonucu görünmeden kaybolur — ikisini birlikte görmek için satırda isNewTabLink aç" }
470
- },
471
- iframe: {
472
- mount: NO_DATA,
473
- load: NO_DATA,
474
- error: NO_DATA,
475
- message: {
476
- payload: {
477
- message: 'gömülü sayfanın postMessage ile yolladığı ham değer (structured clone; string, sayı, nesne…)',
478
- origin: "string — mesajı yollayan belgenin origin'i; isSandboxed AÇIKKEN opak origin yüzünden 'null' gelir"
479
- },
480
- reads: "yalnız event.data.message / event.data.origin — message hiçbir prop yazmaz. Gömülü sayfa window.parent.postMessage(payload, '*') çağırır; YALNIZ bu çerçeveden gelen mesaj kabul edilir (event.source karşılaştırması), sayfadaki başka bir iframe ya da uygulamanın kendi postMessage'ı olayı çalıştırmaz. Origin süzgeci runtime'da YOKTUR — güvenilecek origin kararı akışa aittir"
481
- }
482
- },
276
+ emptystate: { actionClick: { payload: { text: 'string (aksiyonun metni)', index: 'number' }, reads: "aksiyonun kendi flow'u zaten doğrudan çalışır" } },
277
+ iframe: { mount: NO_DATA, load: NO_DATA, error: NO_DATA },
483
278
  jsonviewer: {
484
- mount: NO_DATA,
485
279
  nodeClick: {
486
280
  payload: {
487
281
  path: "string (nokta/köşeli-parantez yolu — 'user.roles[0].name'; kökte boş)",
488
282
  key: 'string (düğümün anahtarı; dizi öğesinde indeks)',
489
283
  kind: "'object' | 'array' | 'string' | 'number' | 'boolean' | 'null'",
490
284
  value: 'düğümün ham değeri (object/array için alt ağacın tamamı)'
491
- },
492
- reads: 'event.data.path / key / kind / value; self.currentItem’a value’suz { path, key, kind } yazılır. Aç/kapa oku ve satırın kopyala düğmesi bu olayı yaymaz'
285
+ }
493
286
  },
494
287
  copy: {
495
288
  payload: {
496
289
  path: "string (kopyalanan düğümün yolu; araç çubuğundan TÜMÜNÜ kopyalamada boş + kind:'root')",
497
- key: "string (düğümün anahtarı; tümünü kopyalamada boş)",
498
290
  kind: "'root' | 'object' | 'array' | 'string' | 'number' | 'boolean' | 'null'",
499
291
  value: 'kopyalanan değer (tümünü kopyalamada normalize edilmiş TÜM veri)'
500
- },
501
- reads: 'yalnız event.data — copy hiçbir prop yazmaz. Pano yazılamazsa (izin/güvensiz bağlam) olay yayılmaz'
502
- }
503
- },
504
- 'language-selector': {
505
- mount: { ...NO_DATA, reads: 'self.value BOŞTUR: enjekte edilen geçerli dil düğümün prop kaydına yazılmıyor, oraya yalnız change yükü yazılıyor (ölçüldü 2026-09-18, ARC-098). Dili okuyacak akışı change’e bağla' },
506
- change: {
507
- payload: { value: 'string (seçilen dil kodu, projenin yazdığı biçimde)' },
508
- reads: 'Yük düğümün kendi value prop’una yazılır (yazmayı machine.onEmit yapar, çünkü olayda data var), akış self.value ile okur; aynı yük params kanalından da iner, yani event.data.value da dolu. Dili DEĞİŞTİREN yazma bu değildir: render katmanı aynı olayda machine.setLanguage(value) + setAppLocale(value) çağırır. Yalnız kullanıcı seçiminde yayılır; akışın value’ya yazması hiçbir şeyi değiştirmez (enjekte edilen değer ezer)'
509
- },
510
- focus: NO_DATA,
511
- blur: NO_DATA
512
- },
513
- notification: {
514
- mount: { payload: {}, reads: 'Ortak render katmanından gelir ve band GÖRÜNÜR olduğunda bir kez yayılır; isHidden:true iken yayılmaz' },
515
- close: {
516
- payload: { isHidden: 'boolean (her zaman true — band kendini kapatırken props.isHidden yazar)' },
517
- reads: "event.data.reason — kapatma düğmesi 'user', zaman aşımı 'timeout'. Bandı yeniden açmak akışın işidir: props.isHidden false yazılmadıkça kapalı kalır. 2026-09-17'den önce bu emit toggled adıyla yayılıyordu ve şemada bildirilmediği için akışa BAĞLANAMIYORDU"
292
+ }
518
293
  }
519
294
  },
295
+ 'language-selector': { change: { payload: { value: 'string (dil kodu)' }, reads: 'runtime ayrıca machine.setLanguage(value) çağırır' } },
296
+ notification: { toggled: { payload: { isHidden: 'boolean' } } },
520
297
  otpinput: {
521
298
  mount: NO_DATA,
522
299
  change: valueChange('string (birleşik kod)'),
@@ -525,22 +302,10 @@ export const componentEventContracts = {
525
302
  focus: NO_DATA,
526
303
  blur: NO_DATA
527
304
  },
528
- pagination: {
529
- mount: NO_DATA,
530
- change: {
531
- payload: { offset: 'number (yeni sayfanın offset’i; limit değişince 0)', limit: 'number' },
532
- reads: 'event.data.offset / event.data.limit ya da self.offset · self.limit — ikisi de dolu (sorguyu bunlara bağla). Yalnız offset ya da limit gerçekten değişince yayılır; akışın yazması yaymaz'
533
- }
534
- },
535
- progress: { mount: NO_DATA, click: NO_DATA, complete: NO_DATA },
305
+ pagination: { mount: NO_DATA, change: { payload: { offset: 'number', limit: 'number' }, reads: 'self.offset · self.limit (sorguyu bunlara bağla)' } },
306
+ progress: { complete: NO_DATA },
536
307
  rating: { mount: NO_DATA, change: valueChange('number (0..max; allowHalf ile yarım)'), focus: NO_DATA, blur: NO_DATA },
537
- result: {
538
- mount: NO_DATA,
539
- actionClick: {
540
- payload: { text: 'string (aksiyonun metni)', index: 'number' },
541
- reads: "aksiyonun kendi flow'u zaten doğrudan çalışır. index GÖRÜNEN sıradır: isHidden satırlar çizilmeden ELENİR, yani gizli satırı olan bir listede index actions dizisindeki sıra DEĞİLDİR — akışı sıraya değil text'e ya da aksiyonun kendi flow'una bağla. isLoading açıkken HİÇ yayılmaz (iskelet çizilirken düğme de yoktur); isDisabled satır da yaymaz"
542
- }
543
- },
308
+ result: { actionClick: { payload: { text: 'string (aksiyonun metni)', index: 'number' }, reads: "aksiyonun kendi flow'u zaten doğrudan çalışır" } },
544
309
  slider: {
545
310
  mount: NO_DATA,
546
311
  change: valueChange('number (sürüklerken sürekli)'),
@@ -548,7 +313,7 @@ export const componentEventContracts = {
548
313
  focus: NO_DATA,
549
314
  blur: NO_DATA
550
315
  },
551
- statcard: { mount: NO_DATA, click: { payload: {}, reads: "Yalnız bir akış bağlıysa yayılır; bağlıyken kartın ana yüzeyi <button> olur (alt satır bunun dışındadır)" }, footerClick: { payload: {}, reads: "Alt satır HER tıklamada yayar — footerHref verilmiş olsa bile; tarayıcı gezinirken akış yarıda kalabilir, isNewTabLink açıkken kalmaz" } },
316
+ statcard: { mount: NO_DATA, click: NO_DATA, footerClick: { payload: {}, reads: "footerFlow zaten doğrudan çalışır; footerHref varsa tıklama ona gider" } },
552
317
  switcher: {
553
318
  mount: NO_DATA,
554
319
  change: { payload: { value: 'boolean' }, reads: "setter: self.value da yazılır. Her geçişte İKİ olay yayılır — change ve (yeni duruma göre) checked ya da unchecked; ikisini birden bağlarsan akış iki kez koşar" },
@@ -557,31 +322,15 @@ export const componentEventContracts = {
557
322
  focus: NO_DATA,
558
323
  blur: NO_DATA
559
324
  },
560
- 'theme-toggle': {
561
- mount: NO_DATA,
562
- change: {
563
- payload: { value: "'light' | 'dark' | '' (boş = tercih temizlendi, projenin teması geçerli)" },
564
- reads: "setter: self.value da yazılır. Kullanıcı tıklamasında yayılır. Akışın SETTER adımıyla value yazması temayı değiştirir ama bu olayı yaymaz (geri besleme döngüsü olurdu); CODE adımından yazmak (Page.components.x.value = 'dark') ise onEmit üzerinden gittiği için düğümün change akışlarını ÇALIŞTIRIR — ikisini karıştırma. Studio kanvasında hiç yayılmaz (_editorMode). Boş değer yalnız hasAutoMode açıkken çıkabilir"
565
- }
566
- },
567
325
  timeline: {
568
326
  mount: NO_DATA,
569
- clickItem: {
570
- payload: { currentItem: 'tıklanan olay öğesi (items’taki nesnenin tamamı)', index: 'number (items dizisindeki gerçek yer; reverse/maxCount’tan etkilenmez)' },
571
- reads: "event.data.currentItem ve event.data.index ile oku; currentItem ayrıca self.currentItem'a yazılır, index self'e YAZILMAZ. Her satır tıklamasında yayılır; öğede flow varsa bu olayın akışı da öğenin kendi flow'u da çalışır (bu olay önce başlatılır, biri diğerini beklemez; ikisi de aynı event.data) — aynı akışı iki yere bağlarsan iki kez çalışır"
572
- },
573
- showMore: { payload: {}, reads: 'yalnız maxCount aşılınca çıkan "Show more" düğmesine basılınca; kalan öğelerin tamamı açılır ve düğme kaybolur (items yeni diziyle değişince yeniden çıkar)' }
327
+ clickItem: { payload: { currentItem: 'tıklanan olay öğesi', index: 'number' }, reads: "öğenin kendi flow'u da doğrudan çalışır" },
328
+ showMore: NO_DATA
574
329
  },
575
330
  timepicker: { mount: NO_DATA, change: { payload: { value: "string 'HH:mm' (temizlenince '')", selectedLabel: "seçilen saatin gösterilen metni — 12h kipinde '01:00 PM' (temizlenince '')" } }, focus: NO_DATA, blur: NO_DATA },
576
331
  toast: {
577
- open: {
578
- payload: {},
579
- reads: 'Toast KUYRUĞA girdiğinde yayılır: delay kadar beklenir; duplicates ignore/count ile atılan ya da do-not-disturb ile bastırılan tetikleme open YAYMAZ. Aynı konumda 5 toast doluysa fazlası ekranda görünmeden de open yayar (görünürlük ayrı bir katman). isOpen’ı false’a döndüren change setter’ı bundan bağımsız, her tetiklemede hemen yayılır'
580
- },
581
- close: {
582
- payload: { reason: "'timeout' | 'user' | 'programmatic'" },
583
- reads: 'Toast kapanınca yayılır; akışta self.reason ile okunur. timeout = süre doldu; user = kullanıcı kapattı (× düğmesi, closeOnClick tıklaması, kaydırma, Escape, aksiyon düğmesi, Clear all); programmatic = koddan dismiss/dismissAll. duplicates ile atılan tetikleme ve delay beklerken iptal edilen toast close YAYMAZ'
584
- },
332
+ open: NO_DATA,
333
+ close: NO_DATA,
585
334
  click: NO_DATA,
586
335
  actionClick: { payload: { text: 'string (aksiyonun metni)', index: 'number' }, reads: "aksiyonun kendi flow'u zaten doğrudan çalışır" }
587
336
  },
@@ -605,96 +354,47 @@ export const componentEventContracts = {
605
354
  eventcalendar: {
606
355
  mount: NO_DATA,
607
356
  monthChange: {
608
- payload: {
609
- month: 'number (1-TABANLI, imlecin ayı)',
610
- year: 'number',
611
- view: "'month' | 'week' | 'day' | 'agenda'",
612
- start: "string 'yyyy-MM-dd' (görünen ilk gün, dahil)",
613
- end: "string 'yyyy-MM-dd' (görünen son gün, dahil)"
614
- },
615
- reads: "yük self'e YAZILMAZ — event.data ile oku; gezinme okları/Bugün ile her görünümde yayılır, ilk mount'ta yayılmaz, isLoading'de de yayılır. Veri sorgusunu start/end'e KESİŞİM olarak bağla: etkinlikBaşlangıç < end+1 gün VE etkinlikBitiş >= start (end tarih-yalnız ve dahil; ay ızgarası komşu ay günlerini, ajanda/hafta ay sınırını kapsar)"
616
- },
617
- viewChange: {
618
- payload: {
619
- view: "'month' | 'week' | 'day' | 'agenda'",
620
- start: "string 'yyyy-MM-dd' (yeni görünümün ilk günü)",
621
- end: "string 'yyyy-MM-dd' (yeni görünümün son günü)"
622
- },
623
- reads: "self'e yazılmaz — event.data ile oku; yalnız görünüm düğmesiyle yayılır (defaultView değişince yayılmaz)"
357
+ payload: { month: 'number (1-TABANLI)', year: 'number' },
358
+ reads: "yük self'e YAZILMAZ — event.data ile oku; gezinme okları/Bugün ile her görünümde yayılır, ilk mount'ta yayılmaz"
624
359
  },
360
+ viewChange: { payload: { view: "'month' | 'week' | 'day'" }, reads: "self'e yazılmaz — event.data ile oku" },
625
361
  dateClick: {
626
362
  payload: { date: "string 'yyyy-MM-dd'" },
627
- reads: "yalnız AY görünümünde, isCreatable KAPALIYKEN ve isLoading değilken; self'e yazılmaz — event.data ile oku"
363
+ reads: "yalnız AY görünümünde ve isCreatable KAPALIYKEN; self'e yazılmaz — event.data ile oku"
628
364
  },
629
365
  eventCreate: {
630
- payload: {
631
- start: "string (tüm gün: 'yyyy-MM-dd' · saatli: ISO)",
632
- end: "string (tüm gün: son gün DAHİL 'yyyy-MM-dd' · saatli: ISO; tek slotta start+60dk, seçimde son slotun sonu)",
633
- allDay: 'boolean'
634
- },
635
- reads: "self'e yazılmaz — event.data ile oku; tıklama ya da sürükleyerek aralık seçimi (fare/kalem; dokunmatikte yalnız tek hücre), bırakmada tek olay; etkinlik eklenmez, akış yazıp rows'u tazeler"
366
+ payload: { start: "string (ay tıklaması: 'yyyy-MM-dd' · saat slotu: ISO)", end: 'string (slotta start+60dk)', allDay: 'boolean' },
367
+ reads: "self'e yazılmaz — event.data ile oku"
636
368
  },
637
369
  eventClick: {
638
370
  payload: { id: 'string', title: 'string', row: 'kaynak satırın TAMAMI' },
639
- reads: "self'e yazılmaz — event.data ile oku; ay/hafta/gün/ajanda hepsinde, isLoading'de yayılmaz"
371
+ reads: "self'e yazılmaz — event.data ile oku"
640
372
  },
641
373
  eventMove: {
642
- payload: {
643
- id: 'string',
644
- row: 'kaynak satırın TAMAMI',
645
- start: "string (tüm gün: 'yyyy-MM-dd' · saatli: ISO)",
646
- end: "string (tüm gün: 'yyyy-MM-dd' · saatli: ISO)",
647
- previousStart: 'string (aynı biçim; ekranda görünen önceki aralık)',
648
- previousEnd: 'string (aynı biçim)'
649
- },
650
- reads: "self'e yazılmaz — event.data ile oku; taşıma ve kenardan boyutlandırma aynı olay; akış kalıcılaştırıp rows'u tazelemezse etkinlik geri döner"
374
+ payload: { id: 'string', row: 'kaynak satırın TAMAMI', start: 'string (ISO)', end: 'string (ISO)', previousStart: 'string (ISO)', previousEnd: 'string (ISO)' },
375
+ reads: "self'e yazılmaz — event.data ile oku; akış kalıcılaştırıp rows'u tazelemezse taşınan etkinlik geri döner"
651
376
  }
652
377
  },
653
378
  importwizard: {
654
379
  mount: NO_DATA,
655
- change: {
656
- payload: {
657
- currentStep: 'number (0 dosya · 1 eşleme · 2 önizleme)',
658
- fileName: 'string (okunan dosyanın adı; henüz dosya yoksa "")',
659
- rowCount: 'number (dosyadaki HAM veri satırı sayısı — doğrulamadan önce)'
660
- },
661
- reads: "adım her değiştiğinde yayılır; currentStep ve fileName düğüme de yazılır (self.currentStep), rowCount yalnız event.data'dadır"
662
- },
663
380
  complete: {
664
381
  payload: {
665
382
  rows: 'Record<string,string>[] (TEMİZ satırlar; değerler hep string)',
666
- errors: 'Array<{ rowIndex, field, code, message, limit?, raw }> (code: required | maxRows)',
383
+ errors: 'Array<{ rowIndex, field, message, raw }>',
667
384
  fileName: 'string',
668
385
  total: 'number (temiz satır + hata KAYDI sayısı)'
669
386
  },
670
387
  reads: "hem self.rows/self.errors/… hem event.data dolu gelir (params kuşağı); satırları uca yazmak complete akışının işidir"
671
388
  },
672
- cancel: {
673
- payload: {
674
- currentStep: 'number (her zaman 0)',
675
- fileName: 'string (her zaman "")',
676
- rows: 'Record<string,string>[] (her zaman [])',
677
- errors: 'Array<…> (her zaman [])',
678
- total: 'number (her zaman 0)'
679
- },
680
- reads: '✕ sıfırlaması: aynı boş yük düğüme de yazılır, yani cancel sonrası self.rows/self.total bayat kalmaz'
681
- }
389
+ cancel: NO_DATA
682
390
  },
683
391
  kanban: {
684
392
  mount: NO_DATA,
685
393
  cardMove: {
686
394
  payload: { id: 'string', row: 'kaynak satırın TAMAMI', from: 'string (kaynak kolon value)', to: 'string (hedef kolon value)' },
687
- reads: "BİLİNÇLİ olarak self'e yazılmaz — event.data ile oku; yeni kolonu uca yaz + rows'u tazele, yoksa kart geri döner. isLoading:true iken sürükleme başlamaz, olay yayılmaz"
395
+ reads: "BİLİNÇLİ olarak self'e yazılmaz — event.data ile oku; yeni kolonu uca yaz + rows'u tazele, yoksa kart geri döner"
688
396
  },
689
- cardClick: { payload: { id: 'string', row: 'kaynak satırın TAMAMI' }, reads: "self'e yazılmaz — event.data ile oku; isLoading:true iken yayılmaz" },
690
- cardAdd: {
691
- payload: { column: 'string (düğmesine basılan kolonun value değeri)' },
692
- reads: "self'e yazılmaz — event.data.column ile oku. Yalnız isAddable:true iken kolon altındaki düğmeden yayılır; kart EKLENMEZ — akış satırı uca yazıp rows'u tazeler (ya da form açar). isLoading:true iken yayılmaz"
693
- },
694
- cardRemove: {
695
- payload: { id: 'string', row: 'kaynak satırın TAMAMI', column: 'string (kartın o anki kolonu; atanmamış kuyrukta ham değer)' },
696
- reads: "self'e yazılmaz — event.data ile oku. Yalnız isRemovable:true iken kartın × düğmesinden yayılır, cardClick YAYMAZ; kart GİZLENMEZ — akış (onay alıp) satırı siler ve rows'u tazeler. isLoading:true iken yayılmaz"
697
- }
397
+ cardClick: { payload: { id: 'string', row: 'kaynak satırın TAMAMI' }, reads: "self'e yazılmaz — event.data ile oku" }
698
398
  },
699
399
  signature: {
700
400
  mount: NO_DATA,
@@ -708,7 +408,7 @@ export const componentEventContracts = {
708
408
  mount: NO_DATA,
709
409
  stepChange: {
710
410
  payload: { currentStep: 'number (hedef adım, 0 tabanlı)', previous: 'number (önceki adım)' },
711
- reads: "currentStep self'e yazılır; event.data da dolu gelir. Gizli adımlar atlanır (currentStep bir sonraki görünür adımın indeksidir, previous ile ardışık olmayabilir); previous kullanıcının GÖRDÜĞÜ adımdır (gizli adıma yazılmış currentStep değil); isLoading:true iken düğme ve başlıklar devre dışı, olay yayılmaz"
411
+ reads: "currentStep self'e yazılır; event.data da dolu gelir"
712
412
  },
713
413
  finish: { payload: { currentStep: 'number (son adımın indeksi)' }, reads: 'adımı değiştirmez; yalnız son adımda kapı açıkken yayılır' },
714
414
  validationFail: {
@@ -725,8 +425,15 @@ export const eventPayloadNote = "Olay yükü motorda komponentin KENDİ prop'una
725
425
  "payload boşsa olay veri taşımaz; 'reads' verilmişse değer yükte değil komponentin başka bir prop'undadır. " +
726
426
  "self yerine value { type:'property', ref:{ source:'component', element:'<elementId>', property:'<prop>' } } de kullanılabilir. " +
727
427
  "payload alanı yoksa yük sözlüğe henüz işlenmemiştir; tahmin etmeyin.";
728
- export function eventContractsFor(slug, names) {
729
- const contracts = slug ? componentEventContracts[slug] : undefined;
428
+ /**
429
+ * `platformContracts` platforma özgü sözlüktür (mobilde `mobileComponentEvents.ts`): aynı olayda
430
+ * web sözleşmesinin ÖNÜNE geçer, web'de karşılığı olmayan bileşenin tek kaynağıdır.
431
+ */
432
+ export function eventContractsFor(slug, names, platformContracts) {
433
+ const own = (source) => slug !== undefined && source !== undefined && Object.hasOwn(source, slug) ? source[slug] : undefined;
434
+ const web = own(componentEventContracts);
435
+ const platform = own(platformContracts);
436
+ const contracts = web || platform ? { ...web, ...platform } : undefined;
730
437
  return names.map(name => {
731
438
  const contract = contracts?.[name];
732
439
  if (!contract)