@appaflytech/zeyrek-ai-mcp 0.0.20 → 0.0.21

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 +14 -13
  2. package/dist/config.js +0 -2
  3. package/dist/knowledge/componentCatalog.js +940 -215
  4. package/dist/knowledge/componentEvents.js +368 -75
  5. package/dist/knowledge/normalize.js +66 -63
  6. package/dist/knowledge/rules.js +29 -6
  7. package/dist/knowledge/styleResolve.js +1 -1
  8. package/dist/knowledge/themeResolve.js +3 -3
  9. package/dist/platform/diagnostics.js +85 -0
  10. package/dist/platform/domSummary.js +1 -1
  11. package/dist/platform/ifExists.js +129 -0
  12. package/dist/platform/responses.js +2 -1
  13. package/dist/platform/{capture/capture.js → screenshot.js} +509 -23
  14. package/dist/platform/strictArguments.js +22 -2
  15. package/dist/platform/writeDiff.js +58 -31
  16. package/dist/platform/writeView.js +17 -0
  17. package/dist/resources/guides/component.md +9 -6
  18. package/dist/resources/guides/functions.md +32 -3
  19. package/dist/resources/guides/getting-started.md +35 -0
  20. package/dist/resources/guides/layout.md +7 -11
  21. package/dist/resources/guides/page.md +49 -71
  22. package/dist/resources/guides/translation.md +5 -6
  23. package/dist/resources/schema-fingerprint.json +2 -2
  24. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +18 -0
  25. package/dist/server.js +0 -2
  26. package/dist/tools/applications.js +3 -60
  27. package/dist/tools/components.js +10 -50
  28. package/dist/tools/designSchemaPatch.js +13 -18
  29. package/dist/tools/externalComponents.js +4 -25
  30. package/dist/tools/flows.js +38 -51
  31. package/dist/tools/functions.js +20 -10
  32. package/dist/tools/layouts.js +9 -41
  33. package/dist/tools/microservices.js +39 -11
  34. package/dist/tools/pages.js +95 -127
  35. package/dist/tools/platformInfo.js +1 -2
  36. package/dist/tools/schemaOps.js +2 -2
  37. package/dist/tools/screenWrite.js +2 -2
  38. package/dist/tools/screens.js +3 -9
  39. package/dist/tools/workflows.js +39 -12
  40. package/package.json +7 -2
  41. package/dist/knowledge/mobileComponentCatalog.js +0 -331
  42. package/dist/knowledge/mobileComponentEvents.js +0 -50
  43. package/dist/knowledge/platform/lint.js +0 -205
  44. package/dist/knowledge/platform/mobile.js +0 -78
  45. package/dist/knowledge/platform/mobileRules.js +0 -121
  46. package/dist/knowledge/platform/mobileTabs.js +0 -108
  47. package/dist/knowledge/platform/profile.js +0 -20
  48. package/dist/knowledge/platform/resolve.js +0 -122
  49. package/dist/knowledge/platform/web.js +0 -38
  50. package/dist/knowledge/styleResolveNative.js +0 -410
  51. package/dist/platform/capture/actions.js +0 -333
  52. package/dist/platform/capture/browser.js +0 -1
  53. package/dist/platform/capture/index.js +0 -10
  54. package/dist/platform/capture/readiness.js +0 -103
  55. package/dist/platform/capture/summary.js +0 -77
  56. package/dist/platform/capture/target.js +0 -5
  57. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  58. package/dist/platform/capture/targets/studio-web.js +0 -5
  59. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -209
  60. package/dist/resources/examples/mobile-app-shell-stack.json +0 -123
  61. package/dist/resources/examples/mobile-app-shell-tab.json +0 -174
  62. package/dist/resources/examples/mobile-list-detail-form.json +0 -656
  63. package/dist/resources/guides/mobile.md +0 -215
  64. package/dist/tools/mobile.js +0 -203
  65. package/dist/tools/profileWrite.js +0 -45
@@ -7,10 +7,13 @@ import { writeDiff, withWriteDiff } from '../platform/writeDiff.js';
7
7
  import { policyRules, microfunctionStepFindings, workflowStepFindings, undefinedInputFieldFindings } from '../knowledge/rules.js';
8
8
  import { languageHeader } from '../knowledge/languageCodes.js';
9
9
  import { handle } from '../platform/responses.js';
10
+ import { existingMatch, ifExistsParam, listAll, platformRename, withOutcome, withRename } from '../platform/ifExists.js';
11
+ import { outlineWrite, recordWriteViewParam } from '../platform/writeView.js';
10
12
  import fastJsonPatch from 'fast-json-patch';
11
13
  import { z } from 'zod';
12
14
  import { constraintSummary } from '../knowledge/backendConstraints.js';
13
15
  import { unmappedMembers, introducedUnmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
16
+ const workflowIfExistsParam = ifExistsParam('workflow', 'mevcut workflow\'u bu tanımla tam gövde günceller (id\'si korunur; workflow_update ile aynı yazma)');
14
17
  const policyOverrideParam = z.boolean().optional()
15
18
  .describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)');
16
19
  const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
@@ -111,27 +114,51 @@ export function registerWorkflowTools(server, platform) {
111
114
  }));
112
115
  server.registerTool('workflow_create', {
113
116
  title: 'Workflow oluştur',
114
- description: "Yeni workflow tanımlar (definition = CreateWorkflowCommand). type: 'workflow' | 'automation' | 'middleware'. İlk kullanımdan önce platform_guide('workflow') okuyun: DTO-önce akışı, branch bağlama (branches[].nextStepId), tip×step matrisi. Her adım ve akışın kendisi 'description' taşımak ZORUNDADIR (WF-024, block): adımın NE İŞE YARADIĞINI 1-2 cümleyle yazın — Studio kanvasında ⓘ ikonu olarak görünür; mekanizmayı değil niyeti yazın. Middleware (istek öncesi koşan guard/setter, user değişkeni, alfabetik sıra) için platform_guide('middleware') + ngapps://examples/middleware-authenticate. Adımın gerçek bir tuzağı varsa (idempotent değil, kapsam adımda değil, dış bağımlılık, sessiz düşen dal) 'caution' alanına yazın — OPSİYONELDİR, tuzak yoksa boş bırakın; doldurma metin yazmayın. Gövde politika kontrolünden geçer. " + constraintSummary('CreateWorkflowCommand'),
115
- inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, policyOverride: policyOverrideParam },
117
+ description: "Yeni workflow tanımlar (definition = CreateWorkflowCommand). type: 'workflow' | 'automation' | 'middleware'. Uygulamada aynı ad ya da slug'da workflow varsa (tipten bağımsız) varsayılan olarak YAZMAZ ve mevcut kaydın id'sini döner (WF-034 — gönderilseydi platform '<ad> (1)' adıyla ikinci bir kayıt açardı); tekrar çalıştırılabilir yazma için ifExists:'update' verin, yanıttaki outcome 'created' | 'updated' olur. Mevcut workflow'lar okunamazsa da yazmaz. İlk kullanımdan önce platform_guide('workflow') okuyun: DTO-önce akışı, branch bağlama (branches[].nextStepId), tip×step matrisi. Her adım ve akışın kendisi 'description' taşımak ZORUNDADIR (WF-024, block): adımın NE İŞE YARADIĞINI 1-2 cümleyle yazın — Studio kanvasında ⓘ ikonu olarak görünür; mekanizmayı değil niyeti yazın. Middleware (istek öncesi koşan guard/setter, user değişkeni, alfabetik sıra) için platform_guide('middleware') + ngapps://examples/middleware-authenticate. Adımın gerçek bir tuzağı varsa (idempotent değil, kapsam adımda değil, dış bağımlılık, sessiz düşen dal) 'caution' alanına yazın — OPSİYONELDİR, tuzak yoksa boş bırakın; doldurma metin yazmayın. Gövde politika kontrolünden geçer. " + constraintSummary('CreateWorkflowCommand'),
118
+ inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, ifExists: workflowIfExistsParam, view: recordWriteViewParam, policyOverride: policyOverrideParam },
116
119
  annotations: writes
117
- }, handle(config, async ({ project, environment, applicationId, definition, policyOverride }) => {
120
+ }, handle(config, async ({ project, environment, applicationId, definition, ifExists, view, policyOverride }) => {
118
121
  const normalized = normalizeWorkflowDefinition(definition);
119
- const findings = enforcePolicy([
120
- ...evaluatePolicy(config, policyRules, 'workflow', definition, { operation: 'create', workflowKind: definition.type }, policyOverride),
122
+ // Politika ÖNCE koşar: block alan istek platforma hiç gitmez, var-mı listesi de okunmaz.
123
+ const stepFindings = [
121
124
  ...await microfunctionStepFindings(platform, project, environment, definition, definition.type, policyOverride),
122
125
  ...await workflowStepFindings(platform, project, environment, applicationId, definition, definition.type, policyOverride),
123
126
  ...await undefinedInputFieldFindings(platform, project, environment, definition, definition.type, policyOverride)
124
- ]);
125
- const drift = unmappedMembers('CreateWorkflowCommand', definition);
126
- const payload = await platform.tenant('POST', project, `/workflows/${applicationId}`, { environment, body: definition });
127
- return attachFindings(withUnmappedMembers(withWriteDiff(withNormalization(payload, normalized), writeDiff(definition, payload)), drift), findings);
127
+ ];
128
+ const bodyFindings = (operation) => evaluatePolicy(config, policyRules, 'workflow', definition, { operation, workflowKind: definition.type }, policyOverride);
129
+ const createFindings = enforcePolicy([...bodyFindings('create'), ...stepFindings]);
130
+ const existing = await existingMatch({
131
+ code: 'WF-034',
132
+ noun: 'workflow',
133
+ where: 'bu uygulamada',
134
+ name: typeof definition.name === 'string' ? definition.name : undefined,
135
+ slug: typeof definition.slug === 'string' ? definition.slug : undefined,
136
+ id: typeof definition.id === 'string' ? definition.id : undefined,
137
+ idParam: 'definition.id',
138
+ ifExists,
139
+ list: () => listAll(platform, project, environment, `/workflows/${applicationId}`),
140
+ listTool: 'workflow_list',
141
+ copyCheck: 'kullanılıp kullanılmadığını workflow_dependencies ile kontrol edip gerekirse silin',
142
+ updateTool: 'id ile workflow_update',
143
+ kind: { key: 'type', value: definition.type }
144
+ });
145
+ // Kayıt bulunduysa yazma bir UPDATE'tir: gövde kuralları workflow_update ile aynı kipte yeniden
146
+ // değerlendirilir (R-1). Adım denetimleri operasyondan bağımsızdır, tekrar koşmaz.
147
+ const findings = existing === undefined ? createFindings : enforcePolicy([...bodyFindings('update'), ...stepFindings]);
148
+ const drift = unmappedMembers(existing === undefined ? 'CreateWorkflowCommand' : 'UpdateWorkflowCommand', definition);
149
+ const payload = existing === undefined
150
+ ? await platform.tenant('POST', project, `/workflows/${applicationId}`, { environment, body: definition })
151
+ : await platform.tenant('PUT', project, `/workflows/${applicationId}/${String(existing.id)}`, { environment, body: definition });
152
+ const saved = payload?.data;
153
+ const rename = ifExists === 'duplicate' ? platformRename(definition, saved, 'dash') : { sent: definition };
154
+ return attachFindings(withUnmappedMembers(withWriteDiff(withRename(withNormalization(withOutcome(outlineWrite(payload, view, ['type']), existing), normalized), rename.renamed), writeDiff(rename.sent, payload)), drift), findings);
128
155
  }));
129
156
  server.registerTool('workflow_update', {
130
157
  title: 'Workflow güncelle',
131
158
  description: 'Workflow tanımını günceller (definition = UpdateWorkflowCommand, tam gövde). Hedefli değişiklik için workflow_patch tercih edin. Her adım ve akışın kendisi \'description\' taşımak ZORUNDADIR (WF-024, block). Adımın gerçek bir tuzağı varsa (idempotent değil, kapsam adımda değil, dış bağımlılık, sessiz düşen dal) \'caution\' alanına yazın — OPSİYONELDİR, tuzak yoksa boş bırakın; doldurma metin yazmayın. Gövde politika kontrolünden geçer. ' + constraintSummary('UpdateWorkflowCommand'),
132
- inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, definition: definitionParam, policyOverride: policyOverrideParam },
159
+ inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, definition: definitionParam, view: recordWriteViewParam, policyOverride: policyOverrideParam },
133
160
  annotations: updates
134
- }, handle(config, async ({ project, environment, applicationId, id, definition, policyOverride }) => {
161
+ }, handle(config, async ({ project, environment, applicationId, id, definition, view, policyOverride }) => {
135
162
  const normalized = normalizeWorkflowDefinition(definition);
136
163
  const findings = enforcePolicy([
137
164
  ...evaluatePolicy(config, policyRules, 'workflow', definition, { operation: 'update', workflowKind: definition.type }, policyOverride),
@@ -141,7 +168,7 @@ export function registerWorkflowTools(server, platform) {
141
168
  ]);
142
169
  const drift = unmappedMembers('UpdateWorkflowCommand', definition);
143
170
  const payload = await platform.tenant('PUT', project, `/workflows/${applicationId}/${id}`, { environment, body: definition });
144
- return attachFindings(withUnmappedMembers(withWriteDiff(withNormalization(payload, normalized), writeDiff(definition, payload)), drift), findings);
171
+ return attachFindings(withUnmappedMembers(withWriteDiff(withNormalization(outlineWrite(payload, view, ['type']), normalized), writeDiff(definition, payload)), drift), findings);
145
172
  }));
146
173
  server.registerTool('workflow_patch', {
147
174
  title: 'Workflow\'a patch uygula',
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@appaflytech/zeyrek-ai-mcp",
3
- "version": "0.0.20",
3
+ "version": "0.0.21",
4
4
  "type": "module",
5
5
  "description": "Zeyrek (NgApps) platform APIs as MCP tools — data, logic and Studio design surface in one gateway",
6
6
  "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/zeyrek-v2/zeyrek-app.git",
10
+ "directory": "zeyrek-mcp"
11
+ },
7
12
  "engines": {
8
13
  "node": ">=20"
9
14
  },
@@ -55,4 +60,4 @@
55
60
  "typescript": "^5.7.2",
56
61
  "vitest": "^3.0.0"
57
62
  }
58
- }
63
+ }
@@ -1,331 +0,0 @@
1
- /**
2
- * Bütün mobil komponentler için geçerli kurallar. Kayıt başına tekrarlanmaz;
3
- * okuyucu (`component_get`) bu notları `mobileNotes`'a ekler
4
- * (`platform/mobileRules.ts` `mobileComponentNotes`). Yerleşim (MOB-001) ve stil
5
- * (MOB-002) notları kural koduyla birlikte orada durur, burada tekrarlanmaz.
6
- */
7
- export const MOBILE_COMPONENT_NOTES = [
8
- "Tasarım kipinde (Studio kanvası) alanlar yazılamaz ve düğmeler basılamaz: dokunuş kanvasın seçim jestidir.",
9
- "Olay yükleri web ile AYNI sözleşmedir (`componentEvents.ts`): alanlar `change`/`changed`/`enter`/`focus`/`blur`, seçim bileşenleri `change` + `checked`/`unchecked`, katmanlar kapanışta `change { isOpen: false }` ve `open`/`close` yayar; `type: submit` düğme `click` yaymaz, üstteki `form`un `submit`ini tetikler (`formId` varsa o formun). Web'deki istemci tarafı şema doğrulaması (`validations` → zod) mobilde YOKTUR: doğrulamayı akışta yapın.",
10
- "Bileşenler shadcn/ui görünümünde çizilir (react-native-reusables ilkelleri, NativeWind); renk ve köşe yine PROJE TEMASINDAN gelir: `--ng-*` değişkenleri shadcn token'larına (`--primary`, `--secondary`, `--muted`, `--destructive`, `--border`, `--input`, `--ring`…) ve köşe ölçeğine köprüyle çevrilir (`shadcn-vars.ts`), koyu kip aynı köprünün ikinci çözümüdür. Tema değişince web ve mobil birlikte hareket eder; web sayfası kendi bileşen ailesiyle çizildiği için iki platformun görünüm farkı bilinçlidir. Ölçü (alan yüksekliği, punto, iç boşluk) temanın `--ng-form-*` değişkenlerinden gelir. Yazı AİLESİ köprüde yoktur: temanın ailesi alanlarda (metin, sayı, parola, açılır liste), başlıklarda (`app-bar`, `form`, `modal`/`drawer`, boş durum) ve sekme çubuğunda uygulanır; `text` ve düğme etiketi ata kabın `typographyStyle` ailesini, o da yoksa platform yazı tipini kullanır; alan, anahtar ve onay kutusu etiketleri HER ZAMAN platform yazı tipiyle çizilir.",
11
- "Boyut panelinin en-boy oranı (`appearance.aspectRatio`, SAYI — 16:9 için `1.78`) boyu genişlikten türetir ve düğüm KABUĞUNA yazılır (zemin, kenar ve iç boşluk dahil görünen kutu tam oranda). Üç koşul: `heightType: 'auto'` (web ile aynı; `fixed`/`fill` ya da yazılmamış boy oranı ezer), genişlik BELLİ — `widthType: 'fill'` ya da `'fixed'` + `widthString` (içerik genişliğinde react-native-web boyu genişlikten, cihazın Yoga'sı genişliği boydan türetir; iki kutu ayrışmasın diye oran o durumda uygulanmaz), düğüm widget örneği değil. Web'den farkı AKIŞ KAPLARI: `container`, `form`, `safe-area`, `scroll-view` mobilde oran alır ve akışları oranlı boyu doldurur (`verticalAlign` `middle`/`bottom`/`stretch` web gibi çalışır). Öteki bırakılabilir tipler (`collapsible-container`, `repeater`, `tabs`, `tooltip`), sayfa kökü ve katmanlar (`modal`, `drawer`) oran almaz; `image` oranı kendi çizimine yazar."
12
- ];
13
- /**
14
- * Web sözlüğünün `STATE_FLAG_NOTES`'undan mobilde FARKLI olan bayraklar. `component_get` mobil
15
- * uygulamada bunları web notlarının üstüne yazar; kaydı olmayan bayrak web notunu korur.
16
- * Kaynak: `packages/ng-apps-ui-native/src/renderer/renderer.functions.ts` `aspectRatioStyle`.
17
- */
18
- export const MOBILE_STATE_FLAG_NOTES = {
19
- isDroppable: "Düğüm çocuk kabul eder ve iç dolgusunu padding kutusundan alır. Web'den farklı olarak mobilde AKIŞ KAPLARI (`container`, `form`, `safe-area`, `scroll-view`) appearance.aspectRatio'yu uygular — boy `auto` ve genişlik `fill`/`fixed` iken; kabın akışı oranlı boyu doldurur. Öteki bırakılabilir tipler (katlanır kap, liste, sekmeler, ipucu, katmanlar) oranı yok sayar."
20
- };
21
- export const mobileComponentKnowledge = {
22
- container: {
23
- summary: 'Flex akışı; mobil sayfanın tek yerleşim kabı.',
24
- differences: [
25
- "`layout` düşer (flex-only), `hoverStyle` düşer (dokunmatikte hover durumu yoktur), `style` düşer.",
26
- 'Yüzey (zemin, köşe, kenarlık, gölge) düğüm kabuğunda derlenir; kabın kendisi yalnız yön, hizalama ve aralık (`gap`) taşır.',
27
- "Hiza adları web ile aynı eşlenir: `verticalAlign: 'middle'` ve `horizontalAlign: 'center'` ortalar. Dikey hizanın kullanacağı boşluk kabın boyundan gelir — `heightType` `fill`, `fixed` ya da en-boy oranlı kapta akış kabuğun boyunu doldurur; boyu içerikten gelen SÜTUN kapta dikey hiza etkisizdir (satır kapta farklı boydaki kardeşleri yine hizalar). `stretch` de web gibi: ana eksende (sütunda `verticalAlign`, satırda `horizontalAlign`) çocukları eksen boyunca yayar, çapraz eksende gerer.",
28
- 'Kutu modeli web ile AYNI kural ve varsayılanlarla çizilir (`appearance.marginType/paddingType`, `normal` = 4 / 10 dp, `custom` kenar kenar): tipi yazılmamış düğüm `normal` dış boşluk, bırakılabilir kap `normal` iç boşluk alır — kenara yaslanacak kapta `none` yazın. `wrap: true` iken satırlar çapraz hizayı izler (web `flex-layout` ile aynı: `stretch` kabı doldurur, `top`/`left` üstten dizer).'
29
- ]
30
- },
31
- 'widget-area': {
32
- summary: 'Konteyner widget`ının kökü; yerleşim sözleşmesi `container` ile aynıdır.',
33
- differences: [
34
- '`layout` düşer (flex-only), `style` düşer.',
35
- 'Özel sekme çubuğu (Ayarlar › Sekmeler › Özel widget, K14) bu kökü taşıyan mobil widget`tır: runtime onu `Widget.tabs = { items: [{ page, slug, label, icon, active }], activePage }` parametresiyle çizer, kök kimliği `__tabs`.'
36
- ]
37
- },
38
- 'safe-area': {
39
- summary: 'Güvenli alan kabı: içeriği durum çubuğu, çentik ve ev göstergesinden uzak tutar (D15).',
40
- differences: [
41
- 'Web`de karşılığı YOKTUR — mobile özgü şema; yerleşim alanları mobil `container` ile aynıdır, varsayılan yön sütun.',
42
- 'Pay barındırıcının cihaz bilgisinden gelir (`host.device.insets`): cihazda gerçek güvenli alan, Studio kanvasında seçili cihaz ön ayarı, önizlemede çerçevenin cihazı. Tarayıcıda tam sayfa `/dev`de pay yoktur.',
43
- '`edges`: all (dört kenar) · top · bottom · vertical. Tasarım kanvası ve önizleme payı KENDİLİĞİNDEN BIRAKMAZ; mobil sayfanın kökü genellikle `safe-area` (ya da içinde `app-bar`) olmalıdır.',
44
- 'Varsayılan sütun + `stretch` ve kenara yaslı: boşluk tipi yazılmamışsa dış/iç boşluk `none` sayılır (`safe-area`, `scroll-view`, `app-bar` — açıkça seçilen değer uygulanır).'
45
- ]
46
- },
47
- 'scroll-view': {
48
- summary: 'Kaydırılabilir kap; uzun içeriği kaydıran açık bir karardır.',
49
- differences: [
50
- 'Web`de karşılığı YOKTUR — mobil ekran kendiliğinden kaymaz; `heightType: fill` ile ekranın kalanını kaplatın.',
51
- '`horizontal` yatay kaydırır; yerleşim alanları içerik kabına uygulanır. Sona varınca `scrollEnd` yayılır.',
52
- '`refreshable` YALNIZ dikey kaydırmada ve yalnız runtime kipinde çekerek yenileyi açar (`refresh` olayı); tasarım kanvasında jest çizilmez. Barındırıcı (Expo) kendi çekerek yenilesini bu durumda KAPATIR, yoksa iki gösterge üst üste biner.',
53
- '`stickyHeader` (FlutterFlow StickyHeader) İLK çocuğu kaydırırken üstte tutar — tasarım kanvasında da; yalnız dikey kaydırmada (RN `stickyHeaderIndices`), `horizontal` açıkken yok sayılır ve panel alanı gizler.'
54
- ],
55
- propNotes: {
56
- refreshable: 'Çekerek yenile; akış bir söz döndürürse gösterge onu bekler, döndürmezse 600 ms döner.',
57
- stickyHeader: 'İlk çocuk yapışır: başlık olacak kabı ilk sıraya koyun ve ona kendi zeminini verin — yapışan kap saydamsa altından akan içerik görünür.'
58
- }
59
- },
60
- text: {
61
- summary: 'Metin; punto temanın tip ölçeğinden gelir.',
62
- differences: [
63
- '`wordBreak` düşer: React Native metni `numberOfLines`/`ellipsizeMode` ile sınırlar, CSS kırma kuralının karşılığı yoktur.',
64
- "Seviyenin mobil karşılığı varsa (`--ng-font-size-<seviye>-mobile`) o kullanılır; metin stili ATA KAPTAN MİRAS ALINMAZ (RN'de miras yoktur), kabuk tipografiyi bağlama yazar."
65
- ]
66
- },
67
- button: {
68
- summary: "Tıklama kaynağı; shadcn `Button` ilkeli. `kind` semantik rengi, `variant` o rengin kullanımını seçer; mobil kırılım shadcn'in `secondary`/`ghost`/`link` varyantlarını ve `icon` boyunu ekler (web şeması değişmez).",
69
- differences: [
70
- '`isNewTabLink` düşer: mobilde sekme yoktur, bağlantı sistem tarayıcısına ya da derin bağlantıya gider (F5/F6).',
71
- '`isLoading` açıkken metnin yanında `ActivityIndicator` döner.',
72
- "`icon`, `iconPosition`, `badgeValue` ve `badgeColor` şemada durur ama mobil çizer bugün ÇİZMEZ: düğmede yalnız etiket ve yükleniyor göstergesi vardır.",
73
- "Etiketin rengi düğmenin kendi kararıdır (`kind`/`variant` kontrastı): ata kabın `typographyStyle.color`ı etikete İNMEZ, punto da temanın form ölçüsünden gelir; aile ve kalınlık gibi öteki tipografi alanları iner."
74
- ],
75
- propNotes: {
76
- variant: "shadcn varyantına çevrilir: `solid` → `default` (`kind: error` iken `destructive`) · `outline` → `outline` (`--background` zemin, `--border` kenar) · `text` (web'in adı) ve `ghost` → `ghost` (zeminsiz) · `secondary` → `secondary` (nötr `--secondary` dolgu) · `link` → `link` (zeminsiz, etiket `--primary`). `secondary`, `ghost` ve `link` YALNIZ mobil şemada seçenektir.",
77
- kind: "Rengin nerede göründüğü varyanta bağlıdır. `solid`: zemin `primary` → `--primary`, `error` → `--destructive`, `info`/`success`/`warning` → `--status-*`. `outline`: `primary` NÖTR kalır (`--border` kenar, ön plan rengi etiket), `error` ve durum renkleri kenarı ve etiketi boyar. `text`: `primary` nötr ön plan etiketi, `error` ve durum renkleri etiketi boyar (`ghost` `primary`/`error`'da aynı). `secondary`: nötr dolgu, `error` etiketi `--destructive` yapar. `link`: etiket `--primary`, `error` iken `--destructive`. BİLİNEN HATA: `info`/`success`/`warning` `ghost`, `secondary` ya da `link` ile verilirse zemin de etiket de aynı durum rengine boyanır ve etiket okunmaz — bu üç varyantta `kind`'ı `primary` ya da `error` bırakın.",
78
- size: "`sm` → shadcn `sm`, `md` → `default`, `lg` → `lg`, boş (`''`) temanın varsayılanı (`--ng-form-default-size`); bu kademelerde yükseklik, punto ve yatay iç boşluk sınıftan değil temanın `--ng-form-height-*`/`--ng-form-font-size-*`/`--ng-form-padding-x-*` değişkenlerinden gelir. `icon` (yalnız mobil) için temada `--ng-form-*-icon` değişkeni YOKTUR: satır içi yükseklik tanımsız kalır, iç boşluk `spacing.md`'ye, punto taban puntoya düşer ve düğme ikon da çizmez — bu kademe bugün kullanışlı değildir."
79
- }
80
- },
81
- form: {
82
- summary: 'Alanları taşıyan kap; yerleşim sözleşmesi `container` ile aynıdır.',
83
- differences: [
84
- '`layout` düşer (flex-only).',
85
- 'Doğrulama ve `submit` akışı F5 runtime fazında bağlanır; tasarım kipinde form yalnız alanları dizer.'
86
- ]
87
- },
88
- 'form-validation-errors': {
89
- summary: 'Formun topladığı hataların listesi; renk temanın hata renginden gelir.',
90
- differences: [
91
- 'Satır metni `label` + `message` birleşiminden çıkar; düz metin dizisi de kabul edilir.',
92
- 'Başlık `hideFormValidationMessage` ile gizlenir; liste ve başlık ikisi de boşsa komponent HİÇ çizilmez (web kutuyu boş çizer).'
93
- ]
94
- },
95
- textinput: {
96
- summary: 'Tek satırlık metin alanı; etiket/açıklama/hata kabuğu bütün alanlarda ortaktır.',
97
- differences: [
98
- '`inputMask` düşer: web maskesi DOM olayına bağlıdır, mobil karşılığı (klavye tipi + biçimleyici) Faz 3.',
99
- '`clearable` düşer: temizleme düğmesi Dalga 1b`in `icon` komponentini bekliyor.',
100
- 'Sayaç kuralı web ile aynı: yalnız `showCounter` açık VE `maxChars` > 0 iken çizilir.'
101
- ]
102
- },
103
- textarea: {
104
- summary: 'Çok satırlı metin alanı.',
105
- differences: [
106
- 'Yükseklik satır sayısından hesaplanır (`lines`, `minLines`, `maxLines`): React Native `TextInput` satır sayısını kendi ölçmez, yükseklik açıkça verilmelidir.'
107
- ]
108
- },
109
- numberinput: {
110
- summary: 'Sayısal klavye açan alan; değer `Intl.NumberFormat` ile biçimlenir.',
111
- differences: [
112
- 'Klavye `allowDemicalPoints` açıkken `decimal-pad`, kapalıyken `number-pad`. Yazılan değer ayrıştırılabildiği anda `minValue`/`maxValue` aralığına kırpılarak yazılır.',
113
- 'Web alanı artı/eksi düğmelerini HEP çizer; mobilde düz alan varsayılandır. Düğmeler `variant: stepper` ile gelir — YALNIZ mobil şemada (web şeması değişmez; FlutterFlow Count Controller): alanın iki yanında `-`/`+` (shadcn `outline` `icon`), alana elle yazmak açık kalır; web gibi salt okunur ve görüntüleme kipinde çizilmez, yüklenirken pasiftir. İç roller `<elementId>__decrement` / `<elementId>__increment` — `page_screenshot` `click` onlarla basar.'
114
- ],
115
- propNotes: {
116
- variant: "`input` (varsayılan) düz alan; `stepper` ± düğmeli. Basış web `stepBy` gibi değeri `step` kadar değiştirir ve sırayla `change` ile `changed` yayar (`{ value }`): boş değer 0'dan başlar, `step` yoksa ya da pozitif değilse 1; sonuç ve adım alanın GÖSTERDİĞİ basamağa oturur (tam sayı alanında adım en az 1, ondalıkta `decimalPlaces`), yani saklanan değer ekrandakiyle aynıdır; `minValue`/`maxValue`'ya kırpılır. Web kuralıyla `+` yalnız değer üst sınırın altındayken, `-` alt sınırın üstündeyken basılır (aralık dışındaki değerde ters yöne götüren düğme pasif); tasarım kipinde basılamaz."
117
- }
118
- },
119
- password: {
120
- summary: 'Gizli metin alanı; göster/gizle düğmesi alanın içindedir.',
121
- differences: [
122
- "`autofill` düşer: tarayıcının `autocomplete` sözlüğüdür, mobil karşılığı `textContentType`/`autoComplete` (Faz 3).",
123
- 'Göster/gizle düğmesi şimdilik METİNDİR (`Show`/`Hide`); `icon` Dalga 1b`de inince ikona döner. Kimliği `<elementId>__reveal` — `page_screenshot` `click` onunla basar.'
124
- ]
125
- },
126
- checkbox: {
127
- summary: 'Onay kutusu; shadcn `Checkbox` ilkeli (`@rn-primitives/checkbox`), işaret Material Symbols glifidir. Kutu ölçüsü temanın form puntosundan çıkar.',
128
- differences: [
129
- '`isIndeterminate` `value`yu bastırır ve tire (`remove` glifi) çizer; belirsiz kutuya dokunmak onu seçili yapar.',
130
- 'Etikete dokunmak da kutuyu çevirir (basış satırın `Pressable`ında toplanır).',
131
- '`labelPosition` yalnız `left`/`right`; `left` seçilince etiket ile kutu satırın iki ucuna yaslanır.'
132
- ]
133
- },
134
- switch: {
135
- summary: 'Açma/kapama anahtarı; shadcn `Switch` ilkeli (`@rn-primitives/switch`) — üç barındırıcıda AYNI görünüm.',
136
- differences: [
137
- 'Platformun kendi anahtarı (iOS/Android `Switch`) KULLANILMAZ: açıkken zemin `--primary`, kapalıyken `--input`, baş `--background`; kanvas, önizleme ve cihaz aynı bileşeni çizer.',
138
- '`isReadonly` ve `isDisabled` anahtarı kilitler ve soldurur; `isDisabled` etiketi de soldurur. Tasarım kanvasında anahtar basılamaz olduğu için HER anahtar soluk çizilir — önizlemede ve cihazda değil.'
139
- ]
140
- },
141
- dropdown: {
142
- summary: 'Seçim listesi; liste tam ekran `Modal` olarak açılır.',
143
- differences: [
144
- 'Açılır liste kutunun altına DEĞİL, ekranın altından açılan tam ekran modala çizilir: küçük ekranda kutunun altına açılan liste klavyeyle çakışıyor.',
145
- 'Tetikleyici shadcn `Input` görünümündedir (`--input` kenarı; yükseklik, köşe ve punto öteki alanlarla aynı `--ng-form-*` ölçüsü); liste `--popover` yüzeyinde, seçili satırda `check` glifi. Tetikleyici `role="combobox"` taşır (iç rol `<elementId>__trigger`, temizleme düğmesi `<elementId>__clear`), seçilebilir satırlar `role="option"` + `data-value`; liste katmanda açıldığı için `page_screenshot` `select` seçeneği belgede arar ve değerle ya da görünen metinle seçer.',
146
- 'Seçenekler normalize edilir: düz metin dizisi, nesne dizisi ve `optionType: "grouped"` çocukları tek biçime iner; grup başlığı seçilemez, etiketi olmayan seçenek değerini gösterir.'
147
- ]
148
- },
149
- divider: {
150
- summary: 'Çizgi; etiket verilirse çizgi etiketin iki yanına bölünür.',
151
- differences: [
152
- "Kesikli/noktalı desen `borderStyle` ile çizilir (arka planla çizilen düz çizgide desen görünmez); kalınlık kenarlığa yazılır.",
153
- 'Dikey kipte çizgi kabın yüksekliğini alır (`alignSelf: stretch`).'
154
- ]
155
- },
156
- spacer: {
157
- summary: 'Boşluk; `flex` kipinde kalan alanı yer, `fixed` kipinde `size` kadar.',
158
- differences: [
159
- 'Tasarım kipinde `showInEditor` açıkken kesikli çerçeveyle görünür olur; runtime`da iz bırakmaz (web ile aynı sözleşme).'
160
- ]
161
- },
162
- image: {
163
- summary: 'Görsel; kaynak düz URL ya da platformun dosya nesnesi olabilir.',
164
- differences: [
165
- 'RN `Image` kullanılır (expo-image değil): paket üç barındırıcıda da aynı kodla çalışır.',
166
- 'Kaynak çözülemezse (boş prop, tanınmayan nesne) YER TUTUCU çizilir — boş kutu tasarımcıya "kaynak boş" demenin tek yolu.',
167
- 'Boyut panelinin en-boy oranı (`appearance.aspectRatio`) görselin KENDİSİNE yazılır (web`de de medya oranı kendi uygular): genişlik satırı kaplar, boy oranla gelir. Koşullar kaplarla aynı: boy `auto` ve genişlik `fill`/`fixed`; değilse (ya da oran yoksa) görsel 96 dp taban boyla çizilir.'
168
- ]
169
- },
170
- icon: {
171
- summary: 'Tek glif; Material Symbols LİGATÜRÜ olarak çizilir.',
172
- differences: [
173
- 'Glif bir metindir: ad (`home`) yazı tipi tarafından glife çevrilir, ayrı svg seti taşınmaz. Studio sayfası yazı tipini yüklü tutar; Expo uygulaması `expo-font` ile yükler (F6).',
174
- '`isSpinning` düşer: dönen ikon `Animated` döngüsü ister, v1`de animasyon yok.',
175
- '`isNewTabLink` düşer (button ile aynı gerekçe).'
176
- ]
177
- },
178
- card: {
179
- summary: 'Görsel + başlık + açıklama + düğme.',
180
- differences: [
181
- '`imageFit` RN `resizeMode`a çevrilir: cover→cover, contain→contain, fill→stretch, none→center.',
182
- 'Kartın TAMAMI dokunulabilir ve tek `click` yayar (web ile aynı: düğmenin kendi olayı yoktur); liste satırına dokunmak repeater şablonundaki kartın `click`idir. Kart çocuk ALMAZ — satırın alanlarını `title`/`description` kod bağıyla (`{ type: \'code\', ref: \'{{ item.alan }}\' }`) verin.'
183
- ]
184
- },
185
- emptystate: {
186
- summary: 'Liste boşken çizilen ikon + başlık + açıklama + eylemler.',
187
- differences: [
188
- 'İkon `icon` komponentiyle aynı ligatür yolunu kullanır.',
189
- 'Metni olmayan eylem kaydı çizilmez; eylem kimlikleri `__action-<sıra>`.'
190
- ]
191
- },
192
- slot: {
193
- summary: 'Layout`un sayfa yuvası; runtime`da sayfanın şeması buraya enjekte edilir.',
194
- differences: [
195
- 'Tasarım kipinde YER TUTUCU çizilir (kesikli kutu + ad): boş `View` yuvayı görünmez yapıyor, layout`ta yeri kestirilemiyordu.'
196
- ]
197
- },
198
- repeater: {
199
- summary: 'Şablon düğümlerini satır başına tekrarlar; satır kimlikleri `__row-<i>`.',
200
- differences: [
201
- '`FlatList` v1`de KULLANILMAZ: sanallaştırma yalnız gerçek veriyle anlamlı, tasarım kipinde ölçüm haritasını bozar (kaplama görünmeyen satırın kutusunu bulamaz).',
202
- 'Tasarım kipinde şablon BİR kez çizilir. Runtime`da her satır web ile AYNI makine parametresiyle (`index`, `row`, `repeaterId`) çizilir: bağlı prop`lar ve akışlar `Row` / `RowIndex` okur; satır yoksa hiçbir şey çizilmez (web ile aynı).',
203
- 'Satırdaki bir düğümün olayı ÖNCE tekrarlayıcıya `change { selectedIndex }` yazar (aynı satırsa yazmaz), sonra kendi akışını koşar (web sırası): akışta tıklanan satır `<tekrarlayıcı>.selectedItem`dır. `item`/`Row`/`RowIndex` yalnız prop BAĞLARINDA satırdır; akış ifadesinde tanımsız döner (ölçüldü 2026-09-19).',
204
- '`columnCount` > 1 iken satırlar yüzde genişlikle sarılır (RN`de CSS grid yok).',
205
- '`swipeActions` ve `itemPressable` MOBİLE ÖZGÜDÜR (webde yok). Jest RN `Animated` + `PanResponder` ile kurulur — paket v1`de `reanimated`/`gesture-handler` yok — ve yalnız YATAY harekette yakalanır, böylece dikey kaydırma kaba kalır. Tasarım kipinde satırlar şablon olarak çizildiği için jest hiç bağlanmaz.',
206
- '`swipe` ve `itemPress` yükleri satırı `row` alanında TAŞIR; akış ifadesindeki `Row`/`RowIndex` bağı ayrı bir konudur (ARC-080).'
207
- ],
208
- propNotes: {
209
- itemPressable: 'Satıra dokunulabilir yapar; dokunuş önce `change { selectedIndex }`, sonra `itemPress` yayar.',
210
- swipeActions: 'Sola kaydırınca açılan eylemler: `key` (zorunlu), `label`, `tone` (default · danger), `icon`. Her eylem 72 pt genişliktedir.'
211
- }
212
- },
213
- modal: {
214
- summary: 'Widget kökü; sayfa akışının dışında, üstte açılan katman.',
215
- differences: [
216
- 'RN `Modal` kullanılır; genişlik web kademelerinden ekran ORANINA çevrilir (small 0.75 · medium 0.85 · large 0.95).',
217
- 'Görünüm temanın shadcn token`larından: perde `--overlay` yarı saydam, gövde `--background` zemin + `--border` kenar + büyük köşe + gölge. Açılış, kapanış ve olaylar değişmedi.',
218
- 'Gövdenin kapatma (×) düğmesinin iç rol kimliği `<elementId>__overlay` (adı tarihsel; `isDismissDisabled` açıkken çizilmez) — `page_screenshot` `click` onunla kapatır.',
219
- 'Tasarım kipinde HER ZAMAN açık ve YERİNDE (sayfa akışında) çizilir: kapalı bir widget`ın içi düzenlenemez; RN `Modal` react-native-web`de sayfanın tamamını kaplayan bir portal açtığı için kanvasta kullanılmaz.',
220
- '`presentation` YALNIZ mobil şemadadır (web şeması değişmez; FlutterFlow BottomSheet): `center` ortadaki kutu, `sheet` alt sayfa, `fullscreen` tam ekran. Tasarım kipinde üçü de yerinde, kendi görünümüyle çizilir.'
221
- ],
222
- propNotes: {
223
- presentation: "`center` (varsayılan; kayıtlı modallar böyle kalır) web ile aynı kutu, genişlik `size`dan. `sheet`: ekranın altına yapışık, tam genişlik, üst köşeleri yuvarlak ve tutamaçlı; cihazda alttan kayarak açılır. Tutamaç + başlık şeridinden aşağı sürükleyince — boyunun üçte biri ya da hızlı savurma — `change { isOpen: false }` ile kapanır; `isDismissDisabled` açıkken yerine döner. İçerik kendi kaydırmasını korur (sürükleme yalnız şeritte); alt sayfa en çok ekranın %90'ıdır, uzun içerik kesilir — kaydırmak için içine `scroll-view` koyun. Kapanış isteği tutmazsa (bir bağ `isOpen`'ı geri yazarsa) sayfa 300 ms sonra yerine döner. `fullscreen`: perdesiz tam ekran, çentik ve ev göstergesi payı dolguda; cihazda kayarak açılır. `size` yalnız `center`da anlamlıdır, panel diğer ikisinde gizler."
224
- }
225
- },
226
- drawer: {
227
- summary: 'Mobil ÇEKMECE (D14): expo-router Drawer navigator`ı yerine widget.',
228
- differences: [
229
- 'RN `Modal` + kenara yaslı panel; kenardan kaydırma ve yumuşak geçiş Faz 3 (reanimated/gesture-handler v1`de paket bağımlılığı değil).',
230
- 'Görünüm temanın shadcn token`larından: perde `--overlay` yarı saydam, panel `--background` zemin + iç kenarda `--border` çizgisi + gölge.',
231
- '`size` kademeleri ekran oranına iner (default 0.72 … full 1); `position` yalnız left/right.',
232
- 'Kaplamaya dokunuş kapatır (`__overlay` iç rolü), `isDismissDisabled` açıkken dokunuş yutulur.',
233
- '`app-bar.menuTarget` bu widget`ı açar (`host.shell.openMenu` → makinede `isOpen: true`); kapanış `change { isOpen: false }` yazar, geçişte `open`/`close` yayılır.',
234
- 'Tasarım kipinde yerinde çizilir (modal ile aynı gerekçe).'
235
- ]
236
- },
237
- 'app-bar': {
238
- summary: 'Ekranın üst çubuğu: başlık, sol uç (geri ya da çekmece menüsü) ve sağ eylemler.',
239
- differences: [
240
- 'Web`de karşılığı YOKTUR — mobile özgü şema (web `header` sayfa akışının parçasıdır, bu ekranın kabuğudur).',
241
- '`leading: auto` runtime`da `host.shell.canGoBack`tan çözülür: geri gidilebiliyorsa geri, gidilemiyorsa `menuTarget` varsa menü, yoksa boş. Tasarım kipinde çubuk boş kalmasın diye menü/geri çizilir.',
242
- 'İç roller `__back`, `__menu`, `__action-<key>` (K2 kalıbı); `page_screenshot` eylemleri bunları kullanır.',
243
- 'Üst güvenli alan payı çubuğun işi DEĞİLDİR: düz kanvas kararından (D15) sonra payı kullanıcı `SafeAreaView` ile kurar.'
244
- ]
245
- },
246
- badge: {
247
- summary: 'Sayaç ya da durum rozeti; taşma (99+) ve nokta kipi var.',
248
- differences: [
249
- '`isPulsing` DÜŞÜRÜLDÜ: nabız animasyonu web CSS keyframe`idir, mobilde karşılığı yoktur.',
250
- 'İkon İSTEĞE BAĞLIDIR ve verilmediğinde ÇİZİLMEZ — ortak ikon çözücü boş prop`ta `star`a düştüğü için bu slug prop`un gerçekten verilip verilmediğine kendisi bakar.'
251
- ],
252
- propNotes: {
253
- color: 'Renk SINIFTAN gelir (`bg-status-*`); `custom` seçilirse `customColor` ham renktir.',
254
- maxCount: 'Aşıldığında metin `<maxCount>+` olur (99 → `99+`). Web ikiziyle aynı beş altın vaka `badge-logic.spec.ts`te kilitli.'
255
- }
256
- },
257
- avatar: {
258
- summary: 'Kullanıcı avatarı: görsel, baş harf yedeği ve `+N` grup kipi.',
259
- differences: [
260
- 'Grup kipinde üst üste binme `spacing` ile negatif kenar boşluğundan çizilir; web`in `z-index` katmanı yerine çizim SIRASI belirler.'
261
- ]
262
- },
263
- progress: {
264
- summary: 'Çubuk ilerleme göstergesi; eşiklere göre renk değiştirir.',
265
- differences: [
266
- '`variant` (dairesel), `isStriped` ve `isIndeterminate` DÜŞÜRÜLDÜ: üçü de CSS animasyonu ya da `conic-gradient` ister.',
267
- 'Kutu satırın tamamını kaplar (`width: 12`).'
268
- ]
269
- },
270
- radio: {
271
- summary: 'Tek seçimli seçenek listesi.',
272
- differences: [
273
- '`autofocus` DÜŞÜRÜLDÜ: mobilde odak kavramı yoktur.',
274
- 'Seçenekler HER ZAMAN alt alta çizilir — dokunma hedefi korunur.',
275
- 'Seçeneğin iç rol kimliği `<elementId>__option-<değer>` (runtime\'da `data-element-id`) — `page_screenshot` `click` seçeneğe onunla basar.'
276
- ]
277
- },
278
- checkboxgroup: {
279
- summary: 'Seçili değerleri bir liste oluşturan onay kutusu grubu.',
280
- differences: [
281
- '`autofocus` ve `columnCount` DÜŞÜRÜLDÜ: çok sütun telefon genişliğinde dokunma hedefini bozar; yerine `direction: horizontal` sarmalı kullanılır.',
282
- 'Kutu satırın tamamını kaplar (`width: 12`).',
283
- 'İç roller `<elementId>__option-<değer>` ve (`showSelectAll` açıkken) `<elementId>__select-all` — `page_screenshot` `click` onlarla basar.'
284
- ]
285
- },
286
- 'choice-chips': {
287
- summary: 'Dokunma için boyutlandırılmış, satır sarmalı seçilebilir çip dizisi. Web`de karşılığı YOKTUR.',
288
- differences: [
289
- 'Mobile özgü şema: web`de bu işi `checkboxgroup`/`radio` görür; dokunmatikte çip dizisi daha az yer kaplar.',
290
- '`multiple` açıkken `value` virgülle ayrılmış listedir, kapalıyken tek değer.',
291
- 'İkon İSTEĞE BAĞLIDIR ve verilmediğinde çizilmez (`badge` ile aynı gerekçe).',
292
- 'Çipin iç rol kimliği `<elementId>__chip-<değer>` — `page_screenshot` `click` çipe onunla basar.'
293
- ]
294
- },
295
- 'collapsible-container': {
296
- summary: 'Başlığa dokununca açılıp kapanan kap; çocuklar gövdeye iner.',
297
- differences: [
298
- 'Bırakılabilir bir KAPTIR (`isDroppable`), gövdesi çocuklardır.',
299
- 'Açılma animasyonu YOKTUR: yükseklik anında değişir (düzen animasyonu bu dalgada kullanılmadı).',
300
- 'Başlığa basmak web ile AYNI olayı yayar (`expanded`/`collapsed { isOpen }`); makine `isOpen`\'ı yazar ve gövde açılıp kapanır. Tetikleyicinin iç rol kimliği `<elementId>__trigger` — `page_screenshot` `click` onunla basar.'
301
- ]
302
- },
303
- slider: {
304
- summary: 'En küçük ve en büyük değer arasında sayısal kaydırıcı.',
305
- differences: [
306
- '`marks`, `showTicks` ve `autofocus` DÜŞÜRÜLDÜ.',
307
- 'Jest `PanResponder` ile çözülür ve YALNIZ YATAY sürüklemeyi yakalar: dokunuşu başlangıçta yakalasaydı sayfa kaydırması değeri değiştirirdi (ölçüldü — kaydırma 40`ı 100 yapıyordu).',
308
- 'Sürüklerken `change`, parmak kalkınca `changed` yayılır; akış genelde `changed`e bağlanır.'
309
- ]
310
- },
311
- tabs: {
312
- summary: 'Başlıkların altında içerik gösteren sekme kabı.',
313
- differences: [
314
- 'İçerik modeli web ile AYNI: her sekmenin gövdesi SIRADAKİ çocuk düğümdür — etkin sekmenin (`selected` anahtarı) `tabs` dizisindeki sırası hangi çocuğun çizileceğini seçer; gizli/pasif sekme sırayı kaydırmaz.',
315
- 'Basılan sekme web ile AYNI olayı yayar (`tab { selected }`); makine `selected`\'ı yazar ve gövde değişir. Sekmenin iç rol kimliği `<elementId>__tab-<anahtar>` (runtime\'da `data-element-id`) — `page_screenshot` `tab` onu anahtarla bulur.',
316
- 'Sekme başlıkları taşarsa yatay kaydırılır; telefonda sarmalanmaz.'
317
- ]
318
- },
319
- tooltip: {
320
- summary: 'DOKUNUŞLA açılan ipucu balonu; çocuklar tetikleyicidir. Web`de karşılığı YOKTUR.',
321
- differences: [
322
- 'Web`de ipucu hover ile açılır; dokunmatikte hover yoktur (MOB-002), bu yüzden jest DOKUNUŞTUR — ikinci dokunuş kapatır, dışarı dokunmak da kapatır.',
323
- 'Bırakılabilir bir KAPTIR: tetikleyici çocuklarıdır, yani her şeye (düğme, ikon, kart) ipucu takılabilir.',
324
- 'TASARIM KİPİNDE BALON ÇİZİLMEZ: kanvasta açık balon ölçümü ve seçim kutusunu kaydırırdı. Tasarımcı metni panelden düzenler.',
325
- 'Balon sayfa ağacının DIŞINA, barındırıcının katmanına çizilir (`modal`/`drawer` ile aynı çerçeve) — kaydırma kabı ya da kırpan kap onu kesmesin diye.'
326
- ],
327
- propNotes: {
328
- side: 'Balonun tetikleyiciye göre yanı. Seçilen yan ekrana sığmazsa balon ÇEVRİLMEZ, yalnız ekran içine kaydırılır.'
329
- }
330
- }
331
- };
@@ -1,50 +0,0 @@
1
- /**
2
- * MOBİLE ÖZGÜ olay yükleri. Mobil komponentlerin ÇOĞU web şemasını genişletir ve
3
- * olayları web sözleşmesindedir (`componentEvents.ts`) — bu dosya yalnız web'de
4
- * karşılığı OLMAYAN komponentler içindir (`app-bar` gibi kabuk komponentleri).
5
- *
6
- * Okuyucu önce buraya, sonra web sözlüğüne bakar; parity testi
7
- * (`test/mobile-component-parity.test.ts`) her mobil olayın iki sözlükten
8
- * birinde karşılanmasını zorunlu tutar.
9
- */
10
- const NO_DATA = { payload: {} };
11
- export const mobileComponentEventContracts = {
12
- 'choice-chips': {
13
- change: {
14
- payload: {
15
- value: 'string — seçili çipin değeri. `multiple` açıkken seçili değerler virgülle ayrılmış tek dize olarak gelir.'
16
- }
17
- }
18
- },
19
- tooltip: {
20
- open: NO_DATA
21
- },
22
- 'app-bar': {
23
- clickBack: NO_DATA,
24
- clickMenu: NO_DATA,
25
- clickAction: { payload: { key: 'string (eylemin key alanı; yoksa dizideki sırası)' } }
26
- },
27
- 'safe-area': {
28
- mount: NO_DATA
29
- },
30
- 'scroll-view': {
31
- mount: NO_DATA,
32
- scrollEnd: NO_DATA,
33
- refresh: NO_DATA
34
- },
35
- repeater: {
36
- swipe: {
37
- payload: {
38
- key: 'string (kaydırma eyleminin key alanı)',
39
- index: 'number (satırın sırası, 0 tabanlı)',
40
- row: 'object (satırın verisi)'
41
- }
42
- },
43
- itemPress: {
44
- payload: {
45
- index: 'number (satırın sırası, 0 tabanlı)',
46
- row: 'object (satırın verisi)'
47
- }
48
- }
49
- }
50
- };