@appaflytech/zeyrek-ai-mcp 0.0.42 → 0.0.45
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.
- package/dist/knowledge/backendConstraints.js +86 -2
- package/dist/knowledge/componentCatalog.js +63 -26
- package/dist/knowledge/componentEvents.js +6 -0
- package/dist/knowledge/connectDataBind.js +43 -6
- package/dist/knowledge/connectDataDefinition.js +74 -3
- package/dist/knowledge/connectDataRules.js +14 -0
- package/dist/knowledge/mobileComponentCatalog.js +66 -7
- package/dist/knowledge/mobileStore.js +61 -2
- package/dist/knowledge/platform/mobile.js +1 -1
- package/dist/knowledge/platform/mobileRules.js +2 -1
- package/dist/knowledge/platform/mobileTabs.js +31 -2
- package/dist/knowledge/platform/web.js +1 -1
- package/dist/knowledge/rules.js +195 -4
- package/dist/knowledge/textHooks.js +434 -0
- package/dist/platform/capture/capture.js +1 -1
- package/dist/platform/capture/readiness.js +4 -0
- package/dist/platform/errors.js +22 -2
- package/dist/prompts/mobilePublish.js +21 -0
- package/dist/resources/examples/flow-biometric-confirm.json +199 -0
- package/dist/resources/examples/microfunction-node-dependencies.json +19 -0
- package/dist/resources/guides/access.md +3 -3
- package/dist/resources/guides/component.md +20 -4
- package/dist/resources/guides/deployment.md +98 -0
- package/dist/resources/guides/entity.md +1 -1
- package/dist/resources/guides/expressions.md +5 -1
- package/dist/resources/guides/external-component.md +6 -4
- package/dist/resources/guides/merge.md +81 -4
- package/dist/resources/guides/microfunction.md +104 -9
- package/dist/resources/guides/microservice.md +34 -5
- package/dist/resources/guides/mobile-connect-data.md +70 -0
- package/dist/resources/guides/mobile-flow.md +64 -0
- package/dist/resources/guides/mobile-publish.md +161 -16
- package/dist/resources/guides/mobile-steps.md +17 -0
- package/dist/resources/guides/mobile.md +41 -23
- package/dist/resources/guides/page.md +11 -5
- package/dist/resources/guides/translation.md +95 -0
- package/dist/resources/knowledge.js +3 -1
- package/dist/resources/prompts/mobile-publish-prepare.md +89 -0
- package/dist/resources/schema-fingerprint.json +4 -4
- package/dist/resources/schemas/ApplyMicrofunctionArchiveChangesCommand.json +76 -0
- package/dist/resources/schemas/ConnectDataDescribeDto.json +44 -0
- package/dist/resources/schemas/ConnectDataResultDto.json +10 -0
- package/dist/resources/schemas/CreateMicrofunctionCommand.json +8 -0
- package/dist/resources/schemas/InvokeMicrofunctionCommand.json +0 -4
- package/dist/resources/schemas/MobileStorePreflightScope.json +13 -0
- package/dist/resources/schemas/StartMobileBuildCommand.json +35 -1
- package/dist/resources/schemas/UpdateMicrofunctionCommand.json +8 -0
- package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +75 -0
- package/dist/server.js +2 -0
- package/dist/tools/common.js +6 -0
- package/dist/tools/components.js +19 -6
- package/dist/tools/connectData.js +9 -4
- package/dist/tools/deployments.js +1 -1
- package/dist/tools/designSchemaPatch.js +16 -4
- package/dist/tools/environments.js +3 -3
- package/dist/tools/files.js +1 -1
- package/dist/tools/flows.js +29 -3
- package/dist/tools/layouts.js +32 -12
- package/dist/tools/merges.js +8 -8
- package/dist/tools/microfunctions.js +53 -3
- package/dist/tools/mobileStore.js +83 -21
- package/dist/tools/pages.js +59 -24
- package/dist/tools/platformInfo.js +4 -2
- package/dist/tools/textHookGuard.js +116 -0
- package/package.json +2 -2
|
@@ -30,6 +30,11 @@ const HERO_TAG_NOTE = "Paylaşılan öğe etiketi (mobile özgü; panelde 'Share
|
|
|
30
30
|
"Kaynak, dokunuşun içinde başladığı en içteki etiketli düğümdür; dokunuş etiketli bir düğümün dışındaysa dokunulan liste satırının (ya da `click`i bağlı kabın) ilk KURULAN etiketli düğümü (kardeşlerde belge sırası; iç içe iki etiketli düğümde İÇTEKİ — satıra tek etiket yazın). Yani satıra dokunmak satırdaki etiketli görselden açar ve etiketi satıra özgü yazmak GEREKMEZ; hedef sayfada birden çok etiketli düğüm varsa doğrusunu ifade seçtirir (satırda `{{ 'urun-' + item.id }}`, hedefte `{{ 'urun-' + Page.queryParams.id }}`). Hedef etiketini SORGU PARAMETRESİNDEN türetin: sonradan yüklenen veriye bağlı etiket ilk çizimde boştur, değer gelince düğüm yeniden kurulur (mount akışları ikinci kez koşar). " +
|
|
31
31
|
"YALNIZ iOS 18+ cihazda oynar: Android'de, `/dev` önizlemesinde, `page_screenshot`'ta ve kanvasta sayfa adımın geçişiyle açılır (`redirect.transition`, MOB-029). Etiketli öğeden açılan sayfada adımın geçişi oynamaz (yakınlaşma yerine geçer); `modal` sunumda da oynar; sekme değişiminde, `replace` sunumda ve cihazın 'hareketi azalt' ayarında oynamaz. " +
|
|
32
32
|
"Hedef düğümün `motionStyle.enter`'ı oynamaz (öncelik yakınlaşmanın); hedef olmayan düğümünki oynar. Aynı sayfada aynı statik etiketi iki düğüme yazmak KAYNAK sayfada olağandır (aynı etiketli kartlar); HEDEF sayfada hizalama kutusu tektir ve ilk çizilen düğüm hizalanır — yazım bunu bilgi notuyla söyler (MOB-030). Eşi olmayan etiket için uyarı yoktur: sayfanın etiketleri (layout'unkiler dahil) `page_runtime_get` özetinde `heroTags`'te okunur — iki sayfayı oradan karşılaştırın.";
|
|
33
|
+
/**
|
|
34
|
+
* Web bileşeninin kelime ayarı mobil ikizde yoktur (frontend ADR 0023 / 0024): not tek yerde yazılır, kelimesi olan
|
|
35
|
+
* web bileşeninin ikizinin kaydına oradan girer.
|
|
36
|
+
*/
|
|
37
|
+
const WEB_WORDS_NOTE = 'Düşen: `texts` (web bileşeninin düğüme özel kelime ayarı; mobil bileşen kelimelerini uygulama sözlüğünden okumaz, kütüphanenin tohumunu gösterir — Translations sekmesi ve sözlük satırları yalnız web).';
|
|
33
38
|
/**
|
|
34
39
|
* Bütün mobil komponentler için geçerli kurallar. Kayıt başına tekrarlanmaz;
|
|
35
40
|
* okuyucu (`component_get`) bu notları `mobileNotes`'a ekler
|
|
@@ -139,6 +144,7 @@ export const mobileComponentKnowledge = {
|
|
|
139
144
|
text: {
|
|
140
145
|
summary: 'Metin; punto temanın tip ölçeğinden gelir.',
|
|
141
146
|
differences: [
|
|
147
|
+
WEB_WORDS_NOTE,
|
|
142
148
|
'`wordBreak` düşer: React Native metni `numberOfLines`/`ellipsizeMode` ile sınırlar, CSS kırma kuralının karşılığı yoktur.',
|
|
143
149
|
'Düşenler: `record`, `recordField`, `revealEntity` (korumalı değerin kilitli maskesi ve "Göster"i mobilde yok; metin bağlandığı değeri olduğu gibi çizer).',
|
|
144
150
|
"`lineClamp` (1–10) `numberOfLines` + sonda üç nokta olarak uygulanır (2026-09-27, f-05). Mobile-only `highlight`: aramaya bağlanan metin — eşleşen parçalar `font-semibold text-primary`; karşılaştırma uygulama diline göre katlanır (`tr`'de `I`↔`ı`, `İ`↔`i`). Satır içi bağlantı için `markdown` + `linkClick` kullanın.",
|
|
@@ -178,6 +184,7 @@ export const mobileComponentKnowledge = {
|
|
|
178
184
|
textinput: {
|
|
179
185
|
summary: 'Tek satırlık metin alanı; etiket/açıklama/hata kabuğu bütün alanlarda ortaktır.',
|
|
180
186
|
differences: [
|
|
187
|
+
WEB_WORDS_NOTE,
|
|
181
188
|
"`inputMask` web'in `input-mask` modülüyle girişte uygulanır (`pattern:`/`date:`/`time:`… biçimlenir, `regex:`/`iban:` yalnız doğrulanır); değer MASKELİ yazılır (web gibi), imleç sonda. Telefon deseni (`(` ya da `+` taşıyan) klavyeyi telefon tuş takımına, rakamlı aileler sayı klavyesine çevirir.",
|
|
182
189
|
"`clearable`: değer doluyken ve alan düzenlenebilirken sağda × (`<elementId>__clear`); basış `change('')` + `changed('')`, odak alanda kalır.",
|
|
183
190
|
"Mobile-only (D11): `keyboardType` (`default|email|phone|number|decimal|url`; boşsa maskeden), `autoComplete` (`off|email|name|tel|username|postal-code|one-time-code` → iOS `textContentType`), `variant: search` (hap köşe, başta arama ikonu, odaktayken sağda uygulama dilinde \"Vazgeç\" `<elementId>__cancel`: değeri temizler, klavyeyi kapatır, `cancel` yayar), `isValid` (yeşil kenar + ✓; geçersizlik kazanır).",
|
|
@@ -189,12 +196,14 @@ export const mobileComponentKnowledge = {
|
|
|
189
196
|
textarea: {
|
|
190
197
|
summary: 'Çok satırlı metin alanı.',
|
|
191
198
|
differences: [
|
|
199
|
+
WEB_WORDS_NOTE,
|
|
192
200
|
'Yükseklik açıkça verilir (React Native `TextInput` satır sayısını kendi ölçmez): `autoGrow` (web varsayılanı AÇIK) iken içerikle `minLines`–`maxLines` arasında büyür, kapalıyken sabit `lines`. 2026-09-27\'ye dek hep sabit boydu (f-05). Satır yüksekliği `punto × 1,45` stile yazılır ve satır tabanlı boylar iç boşluk + kenarlığı içerir: `maxLines: 5` beş tam satır gösterir (2026-09-29). `autofocus` runtime\'da klavyeyi açar.'
|
|
193
201
|
]
|
|
194
202
|
},
|
|
195
203
|
numberinput: {
|
|
196
204
|
summary: 'Sayısal klavye açan alan; değer `Intl.NumberFormat` ile biçimlenir.',
|
|
197
205
|
differences: [
|
|
206
|
+
WEB_WORDS_NOTE,
|
|
198
207
|
'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. `prefixIcon`/`suffixIcon` alanın içinde, `autofocus` runtime\'da (f-05).',
|
|
199
208
|
'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.'
|
|
200
209
|
],
|
|
@@ -205,6 +214,7 @@ export const mobileComponentKnowledge = {
|
|
|
205
214
|
password: {
|
|
206
215
|
summary: 'Gizli metin alanı; göster/gizle düğmesi alanın içindedir.',
|
|
207
216
|
differences: [
|
|
217
|
+
WEB_WORDS_NOTE,
|
|
208
218
|
"`autofill` web değerleriyle çalışır: `current-password` → iOS `password` (Anahtar Zinciri), `new-password` → `newPassword` + parola kuralı (\"Güçlü parola\" önerisi), `off`.",
|
|
209
219
|
'Göster/gizle göz ikonudur (`visibility`/`visibility_off`), ekran okuyucu adı uygulama dilinden ("Göster"/"Gizle"). Kimliği `<elementId>__reveal` — `page_screenshot` `click` onunla basar. 2026-09-27\'ye dek sabit İngilizce "Show"/"Hide" metniydi.',
|
|
210
220
|
"Mobile-only: `showStrength` (altta dört parça + Zayıf/Orta/İyi/Güçlü; ölçütler: 8+ karakter, büyük+küçük harf, rakam, sembol; 8'den kısa parola en çok Zayıf), `isValid`. `maxChars`/`showCounter`/`prefixIcon`/`suffixIcon`/`autofocus` `textinput` kuralıyla uygulanır."
|
|
@@ -213,6 +223,7 @@ export const mobileComponentKnowledge = {
|
|
|
213
223
|
checkbox: {
|
|
214
224
|
summary: 'Onay kutusu; shadcn `Checkbox` ilkeli (`@rn-primitives/checkbox`), işaret Material Symbols glifidir. Kutu ölçüsü temanın form puntosundan çıkar.',
|
|
215
225
|
differences: [
|
|
226
|
+
WEB_WORDS_NOTE,
|
|
216
227
|
'`isIndeterminate` `value`yu bastırır ve tire (`remove` glifi) çizer; belirsiz kutuya dokunmak onu seçili yapar.',
|
|
217
228
|
'Etikete dokunmak da kutuyu çevirir (basış satırın `Pressable`ında toplanır).',
|
|
218
229
|
'`page_screenshot` kutuyu `<elementId>__press` yüzeyinden çevirir (düğmedeki gibi); kök kimliğe `click` de o yüzeye basar (SCR-015).',
|
|
@@ -223,6 +234,7 @@ export const mobileComponentKnowledge = {
|
|
|
223
234
|
switch: {
|
|
224
235
|
summary: 'Açma/kapama anahtarı; shadcn `Switch` ilkeli (`@rn-primitives/switch`) — üç barındırıcıda AYNI görünüm.',
|
|
225
236
|
differences: [
|
|
237
|
+
WEB_WORDS_NOTE,
|
|
226
238
|
'`page_screenshot` anahtarı `<elementId>__press` (`role="switch"`) yüzeyinden çevirir; kök kimliğe `click` de o yüzeye basar (SCR-015).',
|
|
227
239
|
'Platformun kendi anahtarı (iOS/Android `Switch`) KULLANILMAZ: açıkken zemin `--primary`, kapalıyken `--input`, baş `--background`; kanvas, önizleme ve cihaz aynı bileşeni çizer.',
|
|
228
240
|
'`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.',
|
|
@@ -232,13 +244,26 @@ export const mobileComponentKnowledge = {
|
|
|
232
244
|
dropdown: {
|
|
233
245
|
summary: 'Seçim listesi; kısa liste alanın altında, uzun ya da aramalı liste alttan açılan sayfada açılır.',
|
|
234
246
|
differences: [
|
|
247
|
+
WEB_WORDS_NOTE,
|
|
235
248
|
'`presentation` (mobile özgü): `auto` (varsayılan) sekiz ve daha az seçenekli, aramasız listeyi alanın hemen ALTINDA açar (altta yer yoksa ya da klavye açıksa üstte), öbürünü ekranın altından açılan sayfada; `sheet` hep sayfa, `inline` hep alan altı (arama varsa sayfa).',
|
|
236
249
|
'Sayfada dokuz ve daha çok seçenek ya da `search` akışa bağlıyken tepede arama kutusu durur (iç rol `<elementId>__search`): bağlıysa `search { searchText }` yayar ve listeyi akış yazar, değilse yerelde süzer. Açılış `focus`, kapanış `blur` yayar.',
|
|
237
|
-
'Seçenek görseli web `SelectItem` önceliğiyle: `prefixImage` > `prefixText` (zemini `color`) > `icon` (rengi `color`); seçiliyken kutuda da çizilir. Gizli seçenek (`isHidden`) çizilmez. `isViewmode` kutuyu kilitler, ok ve temizleme düğmesini kaldırır. Düşenler: `options[].tooltip`, `isExpanded`, `isSelectable` (ağaç ve üzerine gelme yok).
|
|
250
|
+
'Seçenek görseli web `SelectItem` önceliğiyle: `prefixImage` > `prefixText` (zemini `color`) > `icon` (rengi `color`); seçiliyken kutuda da çizilir. Gizli seçenek (`isHidden`) çizilmez. `isViewmode` kutuyu kilitler, ok ve temizleme düğmesini kaldırır. Düşenler: `options[].tooltip`, `isExpanded`, `isSelectable` (ağaç ve üzerine gelme yok).',
|
|
251
|
+
'Lookup (bağlamanın kök `lookup`ı açıkken; web pencere/çekmecesinin telefon karşılığı, plan mobil-tasarimci-kabuk-ekranlari 33): alanın sağında ↗ (iç rol `<elementId>__lookup`). Alana dokunmak tanımın `lookup.mobileMode`una göre hızlı liste ALT SAYFASINI (`sheet`, varsayılan: arama yalnız `behavior.mobile.search` açıkken, son seçilenler, ilk 5 satır, "Ayrıntılı ara") ya da TAM EKRAN seçimi (`fullscreen`) açar; ↗ hep tam ekranı açar. Tam ekranda arama, kolon filtresi (web işleçleri: eq · neq · contains · icontains; yalnız `lookup.behavior.filterable` kolonları) ve tek alanlı sıralama; `behavior.mobile.infiniteScroll` sonsuz kaydırma (varsayılan açık), `pullToRefresh` çekerek yenile. Satır `lookup.mobileRow` (Başlık · Alt satır · Sağ değer; yoksa label alanı). Seçim `change { value, selectedLabel }` yayıp kapatır; alan seçimin Alt satırını ikinci satırda gösterir. `recentSelections` son 5 seçimi cihaz deposunda tutar (uygulama + sayfa + kaynak + alan). Gizli `lookupMode` telefonda yüzey seçmez. Kanvasta ↗ görünür, yüzey açılmaz.',
|
|
238
252
|
'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.',
|
|
239
253
|
'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.'
|
|
240
254
|
]
|
|
241
255
|
},
|
|
256
|
+
autocomplete: {
|
|
257
|
+
summary: 'Serbest metin + öneri; öneri listesi alanın hemen ALTINDA, sayfanın akışında açılır (katman yok). Lookup YOKTUR — seçim listesi gerekiyorsa `dropdown`.',
|
|
258
|
+
differences: [
|
|
259
|
+
"Web şemasının ikizidir (plan mobil-tasarimci-kabuk-ekranlari 35, K7): prop'lar, olaylar ve yükler web ile aynı; yalnız `style` ve kelime ayarı (aşağıda) düşer. Bağlanabilir `options` `value` + `label` ister, `caption` ve `icon` isteğe bağlı (sihirbaz Label/Value + Caption sorar, lookup bölümü açmaz). Panelde öneri ayarları (`minChars`, `debounce`, `maxSuggestions`, `highlightMatch`, `strict`, `openOnFocus`) \"Davranış\", `options` \"Veri\" grubundadır.",
|
|
260
|
+
WEB_WORDS_NOTE,
|
|
261
|
+
"Öneri kaynağı: bağlantı arama alanı seçmişse (`behavior.searchable`) ya da kaynak istemci kipliyse yazılan metin `search { searchText }` ile düğüme yazılır VE bağlantı yeniden okunur — sunucu arar, akış gerekmez (web'de bu yalnız `search` akışa bağlıyken olur). `search` akışa bağlıysa akış süzer; ikisi de yoksa liste yerelde bulanık süzülür. `minChars` altında arama gitmez, `debounce` kadar beklenir; `maxSuggestions` her kipte kırpar.",
|
|
262
|
+
"Klavyenin dönüş tuşu \"Ara\"dır: bekleyen gecikmeyi atlayıp hemen arar (eşik yine geçerli) ve `enter { value }` yayar. Öneri seçimi `change { value: <etiket> }` + `select { selectedValue, selectedLabel }` yayar, klavyeyi kapatır; × (`clearable`, iç rol `<elementId>__clear`) `change { value: '', selectedValue: '', selectedLabel: '' }`. `strict` odak kaybında eşleşmeyen metni aynı olayla boşaltır.",
|
|
263
|
+
"Yazılmış metin için öneri yoksa \"Eşleşme yok\" satırı (`emptyText` kazanır), yüklenirken `loadingText` satırı — `isLoading`'i bileşen kendisi çizer, kabuk iskelet koymaz. `openOnFocus` boş alanda önce son seçilenleri gösterir (en çok 5; cihaz deposunda, anahtar uygulama + sayfa + kaynak + alan — bağlantısız alanın kaynağı `options`), yoksa önerileri. Eşleşen parça `highlightMatch` ile kalın.",
|
|
264
|
+
"Öneri satırları `role=\"option\"` + `data-value` taşır (liste kabı iç rol `<elementId>__list`). Kanvasta (tasarım kipi) liste kapalıdır ve alan dolu çizilir: `value`, yoksa ilk seçeneğin etiketi."
|
|
265
|
+
]
|
|
266
|
+
},
|
|
242
267
|
'language-selector': {
|
|
243
268
|
summary: 'Dil değiştirici; `dropdown`un tam ekran `Modal` listesiyle çizilir, seçim uygulama çapında kalıcı olur.',
|
|
244
269
|
differences: [
|
|
@@ -268,6 +293,7 @@ export const mobileComponentKnowledge = {
|
|
|
268
293
|
image: {
|
|
269
294
|
summary: 'Görsel; kaynak düz URL ya da platformun dosya nesnesi olabilir.',
|
|
270
295
|
differences: [
|
|
296
|
+
WEB_WORDS_NOTE,
|
|
271
297
|
'RN `Image` kullanılır (expo-image değil): paket üç barındırıcıda da aynı kodla çalışır.',
|
|
272
298
|
"Kayıttan okunan FILE alanı `{ id, type: 'ref', value: <dosya id>, absolute_path: <url>, fileName }` döner: prop'a NESNENİN KENDİSİNİ verin (`{{ item.foto }}`) ya da `.absolute_path` yazın — `.value` dosya kimliğidir (GUID), görsel çizilmez (MOB-011). Çözüm web `getfileUrl` ile aynı: metin olduğu gibi, `type: 'file'` nesnede `data`/`value` (base64), öteki nesnelerde `absolute_path`/`url`.",
|
|
273
299
|
'Göreli dosya yolu (`/files/...`) runtime\'da API kökünün kaynağına çözülür (`resolveMediaUrl`; `video`, `audio`, `lottie`, `card`, `carousel`, `list-item`, `avatar`, `emptystate`, `file-field`, `photo-viewer`, `timeline` ve seçenek görselleri de): cihaz kök bilmez. Mutlak, `data:`/`blob:` adres olduğu gibi kalır; web önizlemede yol aynı kökten yüklenir.',
|
|
@@ -307,6 +333,7 @@ export const mobileComponentKnowledge = {
|
|
|
307
333
|
slot: {
|
|
308
334
|
summary: 'Layout`un sayfa yuvası; runtime`da sayfanın şeması buraya enjekte edilir.',
|
|
309
335
|
differences: [
|
|
336
|
+
WEB_WORDS_NOTE,
|
|
310
337
|
'Tasarım kipinde YER TUTUCU çizilir (kesikli kutu + ad): boş `View` yuvayı görünmez yapıyor, layout`ta yeri kestirilemiyordu.'
|
|
311
338
|
]
|
|
312
339
|
},
|
|
@@ -341,6 +368,7 @@ export const mobileComponentKnowledge = {
|
|
|
341
368
|
modal: {
|
|
342
369
|
summary: 'Widget kökü; sayfa akışının dışında, üstte açılan katman.',
|
|
343
370
|
differences: [
|
|
371
|
+
WEB_WORDS_NOTE,
|
|
344
372
|
'RN `Modal` kullanılır; genişlik web kademelerinden ekran ORANINA çevrilir (small 0.75 · medium 0.85 · large 0.95).',
|
|
345
373
|
'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.',
|
|
346
374
|
'Gövdenin kapatma (×) düğmesinin iç rol kimliği `<elementId>__overlay` (adı tarihsel; `isDismissDisabled` açıkken çizilmez) — `page_screenshot` `click` onunla kapatır.',
|
|
@@ -355,6 +383,7 @@ export const mobileComponentKnowledge = {
|
|
|
355
383
|
drawer: {
|
|
356
384
|
summary: 'Mobil ÇEKMECE (D14): expo-router Drawer navigator`ı yerine widget.',
|
|
357
385
|
differences: [
|
|
386
|
+
WEB_WORDS_NOTE,
|
|
358
387
|
'RN `Modal` + kenara yaslı panel; panel kendi genişliği kadar kenardan 260 ms`de kayar, perde solar; kapanışta geri kayar, katman sonra kalkar (f-19). Kaydırarak kapatma jesti yok.',
|
|
359
388
|
'Görünüm temanın shadcn token`larından: perde `--overlay` yarı saydam, panel `--background` zemin + iç kenarda `--border` çizgisi + gölge.',
|
|
360
389
|
'`size` kademeleri ekran oranına iner (default 0.72 … full 1); `position` yalnız left/right.',
|
|
@@ -394,6 +423,7 @@ export const mobileComponentKnowledge = {
|
|
|
394
423
|
avatar: {
|
|
395
424
|
summary: 'Kullanıcı avatarı: görsel, baş harf yedeği ve `+N` grup kipi.',
|
|
396
425
|
differences: [
|
|
426
|
+
WEB_WORDS_NOTE,
|
|
397
427
|
'Grup kipinde üst üste binme `spacing` YÜZDESİdir (web "Group overlap (%)"; boşsa %30) ve negatif kenar boşluğuyla çizilir; web`in `z-index` katmanı yerine çizim SIRASI belirler. 2026-09-28`e dek mobil `spacing`i okumuyordu.',
|
|
398
428
|
'Web anlamıyla (2026-09-28): baş harf zemini `color` (ya da `isColorful` ile addan deterministik), `hasRing` 2 px halka (`ringColor`), `status` (online · away · busy · offline) sağ altta nokta, köşe rozeti `badgeValue` (99+) ya da MOBİLE ÖZGÜ `badgeIcon` (glif, ör. `photo_camera` — profil fotoğrafı düzenleme rozeti; doluysa metne üstündür, renk `badgeColor`). `click` bağlıysa avatar düğmedir. Grup boşsa `emptyText`.',
|
|
399
429
|
"`src` (ve grup kipinde öğelerin görseli) `image` ile aynı çözümden geçer: kayıttaki FILE alanını nesne olarak verin (`{{ item.foto }}`) ya da `.absolute_path` yazın; `.value` dosya kimliğidir, görsel yerine baş harfler çizilir (MOB-011)."
|
|
@@ -417,6 +447,7 @@ export const mobileComponentKnowledge = {
|
|
|
417
447
|
radio: {
|
|
418
448
|
summary: 'Tek seçimli seçenek listesi.',
|
|
419
449
|
differences: [
|
|
450
|
+
WEB_WORDS_NOTE,
|
|
420
451
|
'`autofocus` DÜŞÜRÜLDÜ: mobilde odak kavramı yoktur.',
|
|
421
452
|
'Dizilim mobile özgü alanlarla: `columns` 2–5 ızgaradır (üç ve daha çok sütunda kart karo olur: görsel/ikon üstte, gösterge yok, seçim kenardan okunur), yoksa `direction: horizontal` sarar, varsayılan alt alta.',
|
|
422
453
|
'`variant: card` kenarlıklı karo (seçili kenar vurgu rengi). Seçenek alanları (mobil): `caption` ikinci satır, `icon`, `image` (76 px küçük resim), `isDisabled`. Seçim seçeneği ÖZGÜN tipinde yayar (`34` sayı kalır).',
|
|
@@ -426,6 +457,7 @@ export const mobileComponentKnowledge = {
|
|
|
426
457
|
checkboxgroup: {
|
|
427
458
|
summary: 'Seçili değerleri bir liste oluşturan onay kutusu grubu.',
|
|
428
459
|
differences: [
|
|
460
|
+
WEB_WORDS_NOTE,
|
|
429
461
|
'`autofocus` ve `columnCount` DÜŞÜRÜLDÜ: çok sütun telefon genişliğinde dokunma hedefini bozar; yerine `direction: horizontal` sarmalı kullanılır.',
|
|
430
462
|
'Kutu satırın tamamını kaplar (`width: 12`).',
|
|
431
463
|
'`variant: card`, `options[].caption`/`icon`, `gap`, `align` ve `isViewmode` web gibi çizilir (radyonun kart parçası ortak). Seçim seçenekleri ÖZGÜN tipinde yayar.',
|
|
@@ -446,6 +478,7 @@ export const mobileComponentKnowledge = {
|
|
|
446
478
|
'collapsible-container': {
|
|
447
479
|
summary: 'Başlığa dokununca açılıp kapanan kap; çocuklar gövdeye iner.',
|
|
448
480
|
differences: [
|
|
481
|
+
WEB_WORDS_NOTE,
|
|
449
482
|
'Bırakılabilir bir KAPTIR (`isDroppable`), gövdesi çocuklardır.',
|
|
450
483
|
'Gövde 220 ms`de açılıp kapanır (yükseklik ölçülen içeriğin oranı; alttaki kardeşler kayarak iner), ok 180° döner — ok yalnız `openButtonIcon`/`closeButtonIcon` yazılmamışsa döner, yazılmışlar yer değiştirir. `description` başlığın altında soluk ikinci satırdır (web). Kanvasta ve "hareketi azalt"ta anında.',
|
|
451
484
|
'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.',
|
|
@@ -455,6 +488,7 @@ export const mobileComponentKnowledge = {
|
|
|
455
488
|
slider: {
|
|
456
489
|
summary: 'En küçük ve en büyük değer arasında sayısal kaydırıcı.',
|
|
457
490
|
differences: [
|
|
491
|
+
WEB_WORDS_NOTE,
|
|
458
492
|
'`marks`, `showTicks` ve `autofocus` DÜŞÜRÜLDÜ.',
|
|
459
493
|
'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).',
|
|
460
494
|
'Sürüklerken `change`, parmak kalkınca `changed` yayılır; akış genelde `changed`e bağlanır. İze dokunuş değeri o noktaya getirir (`change` + `changed`). Jest `modal`/çekmece içinde de çalışır.',
|
|
@@ -517,6 +551,7 @@ export const mobileComponentKnowledge = {
|
|
|
517
551
|
otpinput: {
|
|
518
552
|
summary: 'Tek kullanımlık kod kutuları; kurallar web ile AYNI modülden (`otp-logic`): temizleme, tamamlanma, ayraç, yeniden gönder sayacı.',
|
|
519
553
|
differences: [
|
|
554
|
+
WEB_WORDS_NOTE,
|
|
520
555
|
'Web her kutuyu ayrı alan yapar; mobilde yazıyı kutuların üstündeki TEK görünmez alan alır (`<elementId>__input`): yapıştırma, SMS`ten otomatik doldurma (`oneTimeCode`) ve silme klavyenin kendi davranışıdır, kutular yalnız gösterir. Alan uzunluk sınırı taşımaz — ayraçlı yapıştırma (`123-456`) temizlenip kutu sayısına kesilir, rakam kaybolmaz — ve imleç hep sondadır. `page_screenshot` `set` o alana yazar.',
|
|
521
556
|
'`change` ve `complete` web gibi yalnız GERÇEK değişimde yayılır (`complete` kodu dolduran değişimle birlikte); kabul edilmeyen karakter ve fazlası düşer.',
|
|
522
557
|
'Kilitler web ile aynı: pasif, salt okunur, görünüm ve yükleniyor kipleri yazmayı kapatır; görünüm kipinde kutular düz metne iner ve yeniden gönder çizilmez. Sayaç bağlanınca başlar, `<elementId>__resend` basınca `resend` yayar ve yeniden başlar; tasarım kipinde sayaç koşmaz.',
|
|
@@ -561,6 +596,7 @@ export const mobileComponentKnowledge = {
|
|
|
561
596
|
carousel: {
|
|
562
597
|
summary: 'Parmakla kaydırılan sayfalar (FlutterFlow Carousel ve PageView): çocuk sayfalar ya da web gibi `items` görselleri.',
|
|
563
598
|
differences: [
|
|
599
|
+
WEB_WORDS_NOTE,
|
|
564
600
|
'Prop adları ve olaylar web kaydırıcısınınki: `activeIndex` etkin sayfadır, kaydırma/oklar/noktalar/otomatik oynatma yalnız `slideChange { activeIndex }` yayar ve şerit prop değişince kayar (web gibi denetimli).',
|
|
565
601
|
'Mobilde bırakılabilir: çocuğu varsa her ÇOCUK bir sayfadır ve `items` okunmaz (`tabs` gövde modeli); çocuksuz kaydırıcı `items` görsellerini çizer. Kanvasta yalnız `activeIndex` sayfası çizilir — sayfa seçici paneldeki bu alandır.',
|
|
566
602
|
'Görsel sayfaya dokunuş web gibi yalnız bağlantısı ya da akışı olan sayfada `slideClick { currentItem, index }` yayar; dış adres (http(s), mailto, tel, alan adı) sistem tarayıcısında açılır, uygulama içi yol (`/sayfa`) açılmaz — gezinmeyi `slideClick` akışı yapar.',
|
|
@@ -589,6 +625,7 @@ export const mobileComponentKnowledge = {
|
|
|
589
625
|
eventcalendar: {
|
|
590
626
|
summary: 'Etkinlik takvimi (web ikizi): satırları ay ızgarasında renkli nokta, hafta şeridinde gün ve gün çizelgesinde saat bloğu olarak çizer.',
|
|
591
627
|
differences: [
|
|
628
|
+
WEB_WORDS_NOTE,
|
|
592
629
|
'Alan adları web ile AYNI: `rows` + eşleme alanları (`titleField`, `startField`, `endField`, `colorField`, `idField`, `allDayField`); eşleme, gün süzme ve gün yerleşimi web modüllerinden gelir. Renk anlamsal ad (`primary`, `success`, `warning`, `error`) ya da ham renk. Varsayılan temada `info` bir renk değil nötr yüzeydir (#F8F8F8) — etkinlikte görünmez, kullanmayın.',
|
|
593
630
|
'`defaultView: month | week | day`. Ay: günde en çok `maxVisibleEvents` (varsayılan 3) nokta, fazlası `+`; seçili gün dolgulu, altında `dayCountLabel` sayacı (`{n} görev`); geçmiş günler `pastDimmed` ile soluk. Hafta: 7 günlük şerit, yatay kaydırma haftayı değiştirir. Gün: `startHour`–`endHour` saat satırları, çakışan bloklar yan yana, süresiz satır 30 dk, `doneField` doluysa blok soluk, bugünde "şimdi" çizgisi.',
|
|
594
631
|
'MOBİLE ÖZGÜ: `pastDimmed`, `showTodayButton`, `legend` (açık `{label, color}` listesi — satırlardan türetilmez), `dayCountLabel`, `doneField`.',
|
|
@@ -613,7 +650,8 @@ export const mobileComponentKnowledge = {
|
|
|
613
650
|
'Öğe şablonu basılabilir bir bileşense (`button`, `click`i bağlı `list-item`) dokunuş onun `click`ine gider ve `itemPress` yayılmaz (repeater ile aynı); `click`i bağlı olmayan `list-item` basılamaz, dokunuş `itemPress`e gider (2026-10-08). Akışı `list-item.click`e bağlarsanız satır seçimi yine olur.',
|
|
614
651
|
'Çoklu seçim `repeater` ile AYNI sözleşmedir: `selectionMode: multiple` (onay kutusu, dokunuş seçer, `itemPress` yayılmaz), `longPressSelects`, `selectionChange { selectedIndices, count }`, düğümde `selectedIndices`/`selectedItems` — gruplu görev listesinde toplu Ertele/Tamamla.',
|
|
615
652
|
ROW_LIST_NESTING_NOTE,
|
|
616
|
-
'v1`de yok: `columnCount`, sanallaştırma, başlıktan yazan akış. Studio
|
|
653
|
+
'v1`de yok: `columnCount`, sanallaştırma, başlıktan yazan akış. Studio satır kapsamı (`@ng-apps/ui` row-scope) `grouped-list`i tanır: `item.<alan>` önerisi `columns`tan gelir.',
|
|
654
|
+
'VERİ BAĞLA (kök ADR 0019, 2026-10-10): `rows` connect_data_bind ile bağlanır ve `grouping { by, sectionOrder, dateBucket? }` ZORUNLUDUR (CD-019; başka bileşende CD-020). Bağlıyken bölümleme tanımın `grouping`inden okunur (`groupBy`/`sectionOrder`/`otherSectionTitle`/`stickySectionHeaders`/`showCounts` prop`ları yok sayılır ve Studio panelinde gizlenir — `connectData.props.rows.managedProps`); sunucu sırayı gruplama alanıyla başlatır, `dateBucket` (day · week · month, yalnız tarih alanı) kovasını `date` alanında satıra `__section` yazar (`datetime` cihazın yerel gününden kovalanır), azalanda boşlar sonda; başlık cihaz dilinde ("Bugün", "12 Eki", "Bu hafta", "Ekim"). Sonsuz kaydırma ve çekerek yenile repeater ile aynı (`behavior.mobile`).'
|
|
617
655
|
],
|
|
618
656
|
propNotes: {
|
|
619
657
|
rows: 'Düz satır dizisi (repeater `rows` ile aynı biçim); genellikle bir sorgu/microservice sonucuna kod bağıyla verilir: `{ type: \'code\', ref: \'{{ q_tasks.data }}\' }`.',
|
|
@@ -625,7 +663,10 @@ export const mobileComponentKnowledge = {
|
|
|
625
663
|
swipeActions: 'repeater ile aynı: `key` (zorunlu), `label`, `tone` (default · danger), `icon`; sola kaydırınca açılır, `swipe { key, index, row }` yayar.',
|
|
626
664
|
itemSpacing: 'Öğeler arası dikey boşluk (dp), varsayılan 0.',
|
|
627
665
|
selectionMode: 'repeater ile aynı: `single` · `multiple` · `none`.',
|
|
628
|
-
longPressSelects: 'Uzun basış çoklu seçim kipini açar.'
|
|
666
|
+
longPressSelects: 'Uzun basış çoklu seçim kipini açar.',
|
|
667
|
+
columns: 'Satır alanlarının bildirimi (repeater `columns` ile aynı: `{ name, label, type }`); çizim okumaz, Studio `item.<alan>` önerisini ve connect_data_bind kolonlarını buradan kurar.',
|
|
668
|
+
sectionLabels: 'Tarih bölümlerinde göreli etiket: "Bugün" · "Yarın" · "Dün", hafta kovasında "Bu hafta" · "Gelecek hafta"; kapalıyken kısa tarih ("12 Eki").',
|
|
669
|
+
showCounts: 'Bölüm başlığının sağına bölümdeki satır sayısını yazar (bağlıyken tanımın `grouping.showCounts`ı).'
|
|
629
670
|
}
|
|
630
671
|
},
|
|
631
672
|
'flip-card': {
|
|
@@ -700,6 +741,7 @@ export const mobileComponentKnowledge = {
|
|
|
700
741
|
rating: {
|
|
701
742
|
summary: 'Yıldızla puanlama; kurallar web ile AYNI modülden (`rating-logic`): yarım yıldız, aynı puana dokununca temizleme, puan metni.',
|
|
702
743
|
differences: [
|
|
744
|
+
WEB_WORDS_NOTE,
|
|
703
745
|
'Yıldıza dokunuş `change { value }` yayar; `allowHalf` açıkken yıldızın SOL yarısı ayrı dokunma alanıdır ve yarım puan verir. İç roller: `<elementId>__star-<n>` (1`den; tam puan — yarım açıkken yıldızın sağ yarısı) ve `<elementId>__star-<n>-half` (sol yarı) — `page_screenshot` `click` onlarla basar.',
|
|
704
746
|
'Ekran okuyucuda yıldız şeridi TEK ayarlanabilir öğedir: değeri okunur, yukarı/aşağı kaydırma web`in ok tuşu adımıyla arttırır/azaltır (yarım açıkken 0,5). Pasif (`isDisabled`) soluk çizilir.',
|
|
705
747
|
'Cihazın ikon yazı tipi dolgusuzdur: varsayılan yıldız Unicode ★ ile iki hâlde de dolu çizilir, hâl RENKLE ayrışır (`inactiveColor` `default` kenar rengi, öteki tonlar soluk). Seçilen `icon` glif olarak kalır ve dolu/boş yalnız renkle ayrışır.',
|
|
@@ -709,16 +751,19 @@ export const mobileComponentKnowledge = {
|
|
|
709
751
|
'multi-select': {
|
|
710
752
|
summary: 'Çoklu seçim: alanda kaldırılabilir çipler, dokununca alttan açılan onay kutulu liste; değer ve olaylar web ile aynı.',
|
|
711
753
|
differences: [
|
|
754
|
+
WEB_WORDS_NOTE,
|
|
712
755
|
'Değer `{ label, value }` DİZİSİDİR (düz değer ve `{ id, text }` de okunur); her dokunuş `change { value }` yayar, yük `id`/`text` ikizlerini taşır — web `multi-select.functions.ts`in kuralları mobilde ikizlendi.',
|
|
713
756
|
'Liste alttan açılır (`dropdown` emsali): gruplu listede (`optionType: grouped`) çocuklu satır `isSelectable` değilse başlıktır, gruplar hep açıktır (`isExpanded` okunmaz). Arama kutusu `search` olayına akış bağlıysa `search { searchText }` yayar ve listeyi akış yazar, değilse yerelde süzer. Liste açılınca `focus`, kapanınca (`Done` ya da perde) `blur`; arama doluyken kapanırsa ve `search` akışa bağlıysa web gibi `search { searchText: "" }` de yayılır (yeniden açılan liste eski sonuçla kalmasın).',
|
|
714
|
-
'
|
|
757
|
+
'Düz listede üst sınır web gibi formun `maxItems` doğrulamasıdır, seçim kesilmez (lookup yüzeyinde keser, aşağıda). Alanda en çok üç çip, gerisi "+n". İç roller `__trigger`, `__clear`, `__done`; satırlar `role="option"` + `data-value`.',
|
|
715
758
|
'Yerel arama (akış bağlı değilken) `dropdown` gibi veri dilinin yereliyle ve işaretsiz katlanır: İngilizce uygulamada "in" "India"yı, "suk" "Sükkülent"i bulur (2026-09-29; öncesinde hep `tr-TR`).',
|
|
716
|
-
'Satırın görseli web `SelectItem` önceliğiyle: `prefixImage` > `prefixText` (zemini `color`) > `icon` (rengi `color`). Düşenler: `options[].tooltip`, `isExpanded` (gruplar hep açık; üzerine gelme yok).
|
|
759
|
+
'Satırın görseli web `SelectItem` önceliğiyle: `prefixImage` > `prefixText` (zemini `color`) > `icon` (rengi `color`). Düşenler: `options[].tooltip`, `isExpanded` (gruplar hep açık; üzerine gelme yok).',
|
|
760
|
+
'Lookup (bağlamanın kök `lookup`ı açıkken, plan mobil-tasarimci-kabuk-ekranlari 33): çiplerin sağında ↗ (iç rol `<elementId>__lookup`); yüzeyler `dropdown`unkiyle aynı (alt sayfa / tam ekran, `lookup.mobileMode`). Satırda onay kutusu; seçim taslakta birikir, altta Temizle / Uygula — `change { value }` yalnız Uygula`da yayılır. "Seçililer (n)" çipi listeyi taslağa süzer. Formun `maxItems`ı (panelin `max-length` doğrulaması) doluyken seçilmemiş satırlar pasif ve altta mesaj çıkar. Kanvasta ↗ görünür, yüzey açılmaz.'
|
|
717
761
|
]
|
|
718
762
|
},
|
|
719
763
|
toast: {
|
|
720
764
|
summary: 'Geçici bildirim tetikleyicisi; tetikleme sözleşmesi web ile aynı (akış `isOpen`ı açar, bileşen bildirimi gösterip `isOpen`ı kapatır).',
|
|
721
765
|
differences: [
|
|
766
|
+
WEB_WORDS_NOTE,
|
|
722
767
|
'Bildirim uygulamanın toast deposuna eklenir ve SAYFADAN BAĞIMSIZ yaşar: "Kaydedildi" gösterip `redirect` yapan akışta hedef sayfada görünmeye devam eder. Düğümün kendisi runtime`da hiçbir şey çizmez; kanvasta örnek balon yerinde çizilir.',
|
|
723
768
|
'Web`in dokuz `position`ı telefonda üçe iner: `top-*`/`top-full` üst, `center` orta, öteki hepsi (varsayılan `bottom-right`) alt; bildirim ekran genişliğindedir. Alttaki bildirim sekme çubuğunun üstünde durur.',
|
|
724
769
|
'Açık `modal`, çekmece ya da `dropdown`/`multi-select` listesi varken bildirim onun ÜSTÜNDE çizilir (modaldaki formun tipli uyarısı, çoklu seçimin her dokunuşunda koşan akışın uyarısı görünür); saydam `tooltip` balonunun altında sayfadaki yerinde kalır. Klavye açıkken alttaki bildirim klavyenin üstüne çıkar.',
|
|
@@ -768,6 +813,7 @@ export const mobileComponentKnowledge = {
|
|
|
768
813
|
signature: {
|
|
769
814
|
summary: 'İmza pedi; prop ve olaylar web ikizininki (`value` PNG data URL ya da ham SVG, `penColor`, `penWidth`, `outputFormat`, `clearText`; `change { value }`, `clear`).',
|
|
770
815
|
differences: [
|
|
816
|
+
WEB_WORDS_NOTE,
|
|
771
817
|
'Cihazda mürekkep `react-native-svg`, jest `PanResponder`; kanvas ve önizlemede DOM `<svg>`. Her tamamlanan vuruşta değer web gibi `change { value }` ile yazılır: `self.value` de `event.data.value` da dolu gelir. PNG cihazda görünmez bir `Svg`nin anlık görüntüsüdür (ekran ölçeğinde), web`de `<canvas>`ın; ikisi aynı SVG belgesinin çizimidir ve kalem rengi boşsa ekranda tema metin rengi, değerde somut `#111111` olur.',
|
|
772
818
|
'Vuruş sürerken sayfanın ve `scroll-view`un kaydırması kilitlidir: dikey vuruş sayfayı sürüklemez (web`de pedin `touch-action: none`ı); parmak kalkınca sayfa normal kayar.',
|
|
773
819
|
'Temizle düğmesi (`<elementId>__clear`, `clearText`, boşsa "Clear") çizim ya da değer varken ve alan kilitsizken görünür; basınca önce `change { value: \'\' }`, sonra `clear`. Ped `<elementId>__pad`. Tasarım kipinde çizilmez, Temizle basılmaz.',
|
|
@@ -814,6 +860,7 @@ export const mobileComponentKnowledge = {
|
|
|
814
860
|
chart: {
|
|
815
861
|
summary: 'Grafik; prop`lar, on altı tip (scatter dahil) ve kalan olaylar web ikizininki. Seçenek ve olay eşlemesi web`in modülünden gelir (`buildChartOption`, `chart-events.ts`): iki platform aynı ECharts seçeneğini çizer, aynı olayları yayar.',
|
|
816
862
|
differences: [
|
|
863
|
+
WEB_WORDS_NOTE,
|
|
817
864
|
'Cihazda ECharts `@wuba/react-native-echarts`in SVG motoruyla (`react-native-svg`) çizilir, kanvas ve önizlemede ECharts`ın kendi tuvaliyle. Tema renkleri ve yazı ailesi temanın `--ng-*` değişkenlerinden; cihazda yazı yığının ilk ailesidir, yüklü değilse platform yazı tipi.',
|
|
818
865
|
'Düşenler: `style`; `isExportable` ve `exportFileName` (CSV/PNG indirme, tablo görünümü, tam ekran — dosya kaydetmek ayrı native modül ister); `showTypeSwitcher` ve `showRefresh` ile `refresh` olayı (tip akışla `chartType` yazılarak, yenileme sayfanın kaydırarak yenilemesiyle); `isDrillDown` ile `breadcrumbClick` (tıklanan noktanın satırı `dataPointClick { row }` ile yine gelir).',
|
|
819
866
|
'Kutu: kabuktan gelen boy (`heightType: fixed` ölçülü ya da `fill`) ya da panelin `aspectRatio`su, yoksa 240 dp; `caption` web`deki gibi kutunun altında metindir ve grafik alanından pay alır. Durum web`in sırasıyla: yükleniyor (ortada dönen gösterge — web kutuyu boş bırakır, ARC-127), hata (`errorText` + Yeniden dene düğmesi `<elementId>__retry`, `retry` yayar), veri yok (`emptyText`).',
|
|
@@ -824,6 +871,7 @@ export const mobileComponentKnowledge = {
|
|
|
824
871
|
datepicker: {
|
|
825
872
|
summary: 'Tek gün seçici; kutuya dokununca cihazda işletim sisteminin seçicisi (iOS satır içi takvim, Android iletişim kutusu), önizlemede (`/preview`, `/dev`) tarayıcının seçicisi açılır — kanvasta alan kilitlidir. Değer, sınır ve olaylar web ikizininki.',
|
|
826
873
|
differences: [
|
|
874
|
+
WEB_WORDS_NOTE,
|
|
827
875
|
'Kutu `dropdown` tetikleyicisinin görünümündedir (`role="combobox"`, iç rol `<elementId>__trigger`, temizleme `<elementId>__clear`); X değer varken, alan kilitli değilken ve yüklenmiyorken çizilir. `isLoading` ikonun yerinde dönen gösterge çizer, kilit değildir (kutu açılır — web gibi).',
|
|
828
876
|
'Seçici: iOS`ta alttan açılan sayfada satır içi takvim — gün seçilip Tamam/Done (`<elementId>__done`) ile yazılır, dışına dokunmak vazgeçer (seçimde yazılmaz: seçili güne yeniden dokunmak değer bildirmez, takvimin ay/yıl çarkı bildirir — ikisi iOS 26.2 simülatöründe ölçüldü, 09 adım 4); Android`de sistem iletişim kutusu (Android cihazda ölçülmedi). Önizlemede kutunun içindeki görünmez `<input type="date">` tarayıcının seçicisini açar (`showPicker()`).',
|
|
829
877
|
'Otomasyon: `page_screenshot` `set` KÖKE değil `<elementId>__input`a yazılır, HTML biçimiyle — `yyyy-MM-dd` (`2026-08-01`). Kök `set` kutunun `role="combobox"`u yüzünden açılır kutu yoluna girer ve "açılır kutu AÇILMADI" der; biçimsiz değer (`1 Ağu 2026`, saatli metin) tarayıcıda boşalır ve yok sayılır — alan yalnız X`le (`__clear`) boşalır.',
|
|
@@ -835,6 +883,7 @@ export const mobileComponentKnowledge = {
|
|
|
835
883
|
daterangepicker: {
|
|
836
884
|
summary: 'Tarih aralığı seçici (web ikizi): tek kutuda iki uç, basış alttan takvim sayfası açar ve iki güne basılarak aralık seçilir. `change` web gibi `{ valueFrom, valueTo }`.',
|
|
837
885
|
differences: [
|
|
886
|
+
WEB_WORDS_NOTE,
|
|
838
887
|
'İşletim sisteminin seçicisi aralık seçmediği için her zaman takvim sayfasıdır (`datepicker` `presentation: calendar` ile aynı sayfa ve iç roller: `__trigger`, `__clear`, `__prev`, `__next`, `__day-yyyy-MM-dd`, `__done`).',
|
|
839
888
|
'İlk basış başlangıç (`valueTo: null` yazılır), ikinci basış bitiş; başlangıçtan önceki gün seçilirse uçlar YER DEĞİŞTİRİR, tamamlanmış aralığa basış yeniden başlatır. Uçlar `minDate`/`maxDate` gün sınırına çekilir, `valueOffset` eklenir; aralık tamamlanınca dokunulmayan uç web `toRangeValue` gibi SAKLANDIĞI GİBİ yazılır (akışın yazdığı saat korunur). Takvim `displayOffset`le gösterilen günü işaretler. `closeOnSelect` (varsayılan açık) bitişte kapatır.',
|
|
840
889
|
'Kutu metni `başlangıç – bitiş` (`displayFormat` ya da dilin kalıbı), boşken `startPlaceholder – endPlaceholder`; X iki ucu birden `null` yapar. Düşen: `style`.'
|
|
@@ -843,6 +892,7 @@ export const mobileComponentKnowledge = {
|
|
|
843
892
|
timepicker: {
|
|
844
893
|
summary: 'Saat seçici (`HH:mm`); cihazda işletim sisteminin saat çarkı/kutusu, önizlemede tarayıcının seçicisi. `change` web gibi `{ value, selectedLabel }`.',
|
|
845
894
|
differences: [
|
|
895
|
+
WEB_WORDS_NOTE,
|
|
846
896
|
'Web`in listesi yerine işletim sisteminin seçicisi: iOS`ta alttan açılan sayfada çark + Tamam/Done, Android`de sistem saat kutusu; önizlemede `<input type="time">` tarayıcı seçicisi. Çark izinli en yakın saatte açılır — kaydırmadan Tamam yazılanı görünenle aynı tutar. Kutu, temizleme ve otomasyon `datepicker` ile aynı (`set` `<elementId>__input`a `HH:mm`). Web listesi gibi `isLoading` iken açılmaz.',
|
|
847
897
|
'Sistem seçicisi tek tek saati KAPATAMAZ: `minTime`/`maxTime` dışındaki, `disabledTimes`taki ya da adım dışı seçim İZİNLİ EN YAKIN saate yaslanır (eşitlikte erken olan; iOS çarkı sınırı zaten uygular); izinli saat yoksa hiçbir şey yazılmaz. Web`de bu saatler listede kapalı görünür. Ters sınır (`22:00`–`06:00`) seçiciye verilmez — her saat kapalı sayılır, web gibi.',
|
|
848
898
|
'`format: 12h` web gibi yalnız gösterimdir (kutu ve `selectedLabel` `01:00 PM`, değer `13:00`); iOS çarkı dilin kendi saat düzeniyle açılır (Türkçe 24, İngilizce 12 saat); Android saat kutusuna `format` verilir (Android cihazda ölçülmedi). `clearable: false` X`i kaldırır.',
|
|
@@ -855,7 +905,8 @@ export const mobileComponentKnowledge = {
|
|
|
855
905
|
datetimepicker: {
|
|
856
906
|
summary: 'Tarih + saat tek kutuda; cihazda iOS satır içi takvim + saat tek sayfada (Tamam/Done ile gösterilen an yazılır — boş alan şimdiyle, adımın ızgarasında açılır), Android önce tarih sonra saat (saatten vazgeçmek hiçbir şey yazmaz — kodla, Android cihazda ölçülmedi); önizlemede `<input type="datetime-local">`.',
|
|
857
907
|
differences: [
|
|
858
|
-
|
|
908
|
+
WEB_WORDS_NOTE,
|
|
909
|
+
'Web`in iki kutusu (tarih + saat) mobilde TEK kutudur: metin tarih ve saati birlikte gösterir (dilin kendi saat düzeni: İngilizce ve Arapça 12, Türkçe ve Rusça 24; saat metni platformun Intl`iyle — cihaz `3:00 PM`, web `03:00 PM`); boşken `placeholder` görünür.',
|
|
859
910
|
'Seçilen an saniyesi sıfırlanıp web`in saat başı ızgarasına (`minutesStep`; 45 dakikada :00 ve :45, saatten uzun adımda saat başları) ve `minDate`/`maxDate` an sınırına çekilir, `valueOffset` eklenir: `yyyy-MM-ddTHH:mm:ss`. Android`de saat kutusundan vazgeçmek hiçbir şey yazmaz (web: boş alanda yalnız gün seçmek yaymaz, CQ-237).',
|
|
860
911
|
'Kutu, temizleme, otomasyon (`set` `<elementId>__input`a `yyyy-MM-ddTHH:mm`) ve `focus`/`blur` `datepicker` ile aynı. Düşenler: `style`, `timePlaceholder` (web`in ayrı saat kutusunun metni).'
|
|
861
912
|
]
|
|
@@ -863,6 +914,7 @@ export const mobileComponentKnowledge = {
|
|
|
863
914
|
fileInput: {
|
|
864
915
|
summary: 'Dosya alanı; kutuya ya da Gözat`a dokununca cihazda `source`un seçicisi (varsayılan belge seçici), önizlemede tarayıcının dosya penceresi açılır — kanvasta alan kilitlidir. Değer, kapılar ve `change` web ikizininki: base64 veri URL`si düğüme yazılır ve Table microservice`in FILE parametresiyle kaydedilir (değeri olduğu gibi gövdeye verin — platform_guide(\'mobile\') §Dosya ve fotoğraf); fotoğrafı istemci küçültür (`maxImageDimension`), `maxFileSizeMb` varsayılanı 10.',
|
|
865
916
|
differences: [
|
|
917
|
+
WEB_WORDS_NOTE,
|
|
866
918
|
'Seçici `source` ile seçilir (yalnız mobilde): `files` belge seçicisi (bütün türleri gösterir; izin listesi seçimden SONRA uygulanır ve web`in tür uyarısını çizer), `library` fotoğraf arşivi, `camera` kamera (izin istenir, verilmezse hiçbir şey olmaz), `ask` her seferinde sorar. Önizlemede görünmez `<input type="file">` açılır (`library`/`camera` `accept="image/*"`); otomasyon `<elementId>__input`a dosya verir. Seçici açıkken ve okuma sürerken alan meşguldür: ikinci seçici açılmaz, satır silme ve temizleme bekler.',
|
|
867
919
|
'Değer web gibi `{ value: base64 veri URL`si, fileName, type: "file" }` (çoklu kipte dizi, yeni seçim üstüne eklenir; boşaltma `{ type: "ref", value: null }`, çoklu kipte `[{ type: "ref", value: null }]`) — backend `TableFileParameter { value, type: ref|file|document, fileName }` biçiminin aynısı: `file` depoya yazılır, `ref` var olan dosyayı bağlar, `null` alanı boşaltır. Base64 sayfa durumunda ve istek gövdesinde taşındığı için `maxFileSizeMb` (mobil varsayılan 10) sıfırlanmaz. Kamera/galeri fotoğrafı uzun kenarı `maxImageDimension`a (varsayılan 1600 px; 0 = kapalı) indirilip JPEG olarak yeniden kodlanır — boyut kapısı küçültülmüş dosyaya bakar; belge seçiciden gelen dosyaya dokunulmaz. Fotoğraf arşivinden gelen HEIC iOS`ta JPEG`e çevrilir (`.jpg` — web`de Safari`nin yaptığı gibi), fotoğraflar `quality` ile sıkıştırılır. Görsel seçimler alanda küçük resimle görünür.',
|
|
868
920
|
'Tür/boyut/adet kapısı web kuralıdır (tek uyarı, tür ihlali önce; uyarı metni uygulama dilinde). İç roller: kutu `<elementId>__field`, Gözat `__browse`, temizle `__clear`, çoklu kipte satır silme `__file-<n>__delete`. `isReadonly`/`isViewmode` Gözat`ı ve X`i gizler.',
|
|
@@ -878,6 +930,7 @@ export const mobileComponentKnowledge = {
|
|
|
878
930
|
filebutton: {
|
|
879
931
|
summary: 'Ataşlı dosya düğmesi; dokununca varsayılan olarak kaynak sorulur (Kamera / Fotoğraflar / Dosyalar), önizlemede tarayıcının dosya penceresi açılır — kanvasta düğme kilitlidir. Değer, kapılar ve `change` web ikizininki: Table microservice`in FILE parametresiyle kaydedilir (değeri olduğu gibi gövdeye verin — platform_guide(\'mobile\') §Dosya ve fotoğraf); fotoğrafı istemci küçültür (`maxImageDimension`), `maxFileSizeMb` varsayılanı 10.',
|
|
880
932
|
differences: [
|
|
933
|
+
WEB_WORDS_NOTE,
|
|
881
934
|
'`source` varsayılanı `ask`: iOS`ta eylem sayfası, Android`de üç düğmeli uyarı (dışına dokunmak vazgeçer; Android cihazda ölçülmedi); `files`/`library`/`camera` doğrudan açar. Vazgeçmek değeri değiştirmez; seçici açıkken ve okuma sürerken düğme meşguldür (ikinci seçici açılmaz, satır silme bekler). Simülatörde kamera açılır ama görüntü üretmez — çekim gerçek cihazda sınanır.',
|
|
882
935
|
'Değer web gibi `{ type: "file", value: base64 veri URL`si, fileName, ref: "" }` (çoklu kipte dizi, yeni seçim üstüne eklenir; boşaltma `null`, çoklu kipte `[]`) — backend `TableFileParameter` biçimi, FILE parametresine dönüştürmeden verilir. Tür ve sınır web gibi İKİ bağımsız uyarıdır; `maxFileSizeMb` mobil varsayılanı 10. Kamera/galeri fotoğrafı `maxImageDimension`a (varsayılan 1600 px; 0 = kapalı) küçültülüp JPEG olarak yeniden kodlanır, sınır küçültülmüş dosyaya bakar. HEIC fotoğraf iOS`ta JPEG`e çevrilir (`.jpg`); kameradan gelen fotoğrafın özgün adı olmadığı için geçici dosya adıyla yazılır. Görsel seçimler küçük resimle listelenir.',
|
|
883
936
|
'İç roller: düğme `<elementId>__button`, satır silme `__file-<n>__delete`, çoklu kipte "Tümünü temizle" `__clear`. Açıklama yalnız dosya yokken görünür (web gibi).',
|
|
@@ -925,10 +978,14 @@ export const mobileComponentKnowledge = {
|
|
|
925
978
|
datatable: {
|
|
926
979
|
summary: 'Veri tablosu (FlutterFlow DataTable); prop`lar ve akış sözleşmesi web ikizininki: sıralama ya da sayfa değişince sorgu prop`ları (`sortField`/`sortType`/`offset`) düğüme yazılır ve `mount` yeniden koşar, satır eylemi önce `selectedRow`u yazar sonra eylemin kendi akışını koşturur (yazım web gibi sessizdir, `silentUpdate: [elementId]`: tablo yeniden çizilmez, kaydırma konumu korunur). Hücre biçimi, görünür kolonlar, sıralama döngüsü ve sayfa hesabı web`in modülünden gelir (`renderCell`, `buildViewColumns`, `nextSort`, `computePageState`): iki platform aynı veriden aynı metni üretir.',
|
|
927
980
|
differences: [
|
|
981
|
+
WEB_WORDS_NOTE,
|
|
928
982
|
'`variant: table` (varsayılan) yatay kaydırılan tablodur: başlık satırı, sıralanabilir kolonda başlığa dokunuş (`<elementId>__sort-<kolon>`, yön oku başlıkta), eylem sütunu satırın sonunda; dikey kaydırma sayfanındır, tablonun üstünden başlayan dikey kaydırma sayfayı kaydırır; kolonların toplamı çerçeveden darsa kolonlar web gibi çerçeveye yayılır (`table-layout: fixed`). `variant: cards` satır başına kart çizer: ilk görünür görsel kolon kartın başına, ilk görsel olmayan kolon başlığa, kalanlar etiket-değer satırlarına; kart kipinde sıralama başlığı yoktur (sıralama akışla yazılır).',
|
|
929
983
|
'Eylemler web paletiyle (`solid` birincil, `information` kenarlı, `transparent` hayalet, `error`/`danger` yıkıcı, `warning`, `dark`): `actionType: button` satırda düğmeler (`<elementId>__action-<satır>-<sıra>`), `dropdown` ⋯ düğmesi (`<elementId>__more-<satır>`) alttan açılan eylem sayfası (`<elementId>__sheet-action-<sıra>`; cihazda `modal` ile aynı katman). Satırın `_actions` dizisi web gibi eylemi ezer, `isHidden` gizler, `isDisabled` kilitler.',
|
|
930
984
|
'Sayfalama (`isPaginated`): ‹ `1–10 / 57` › çubuğu (`<elementId>__page-prev`, `__page-next`); metin dil bağımsızdır. Web`in sayfa numarası kutusu ve sayfa başına satır seçimi yok (`limit` panelden ya da akıştan; düğümde hiç yazılmamışsa web gibi 10). Başlık doluyken yanındaki yenile düğmesi (`<elementId>__refresh`) `mount`u koşturur; `showRefresh: false` düğmeyi kaldırır.',
|
|
931
|
-
'Düşenler: `style`, `actionsPinned
|
|
985
|
+
'Düşenler: `style`, `actionsPinned`, `advancedFilter`, `filterPosition`, `showFilterSummary`, `showExport`, `showColumnManager`, `toolsPosition`, `footerPosition`, `stickyHeader`, `stickyFooter`, `paginationPosition`, `addRowShortcut`, `canReorderRows`, `orderField`, `revealEntity`, `rowDoubleClick`, `cellSelectionChange`; kolonların `relationTypeField` ve `relationTargets` alanı. Gelişmiş filtre oluşturucu, dışa aktarma, kolon menüsü, sürükle-sırala ve korumalı alanı gösterme telefonda yok; uzun veri için yol sayfalama ya da sonsuz kaydırmadır (satır sanallaştırma yok).',
|
|
986
|
+
'Telefonda filtre (plan mobil-tasarimci-kabuk-ekranlari 34): `isFilterable` kolonlar (bağlı tabloda sunucunun kabiliyeti son sözü söyler) üstte çip şerididir (`<elementId>__chip-<kolon>`, başta rozetli `__filters`: etkin çip sayısı, ✕ hepsini temizler). Çipe dokunmak alt sayfa açar: metin kolonunda işleç (sunucunun açtıkları) + değer, seçenekli kolonda liste (`in` açıksa çoklu), anahtarda Evet/Hayır, ilişki kolonunda seçim bileşenlerinin lookup alt sayfası. Uygula `filters`a kök `and` tekil kural yazar (web filtre çubuğuyla aynı sözleşme) ve `offset: 0` ile `mount` koşturur; etkin çip mavi. Bağlı tabloda çipler bağlamanın `behavior.mobile.filterChips`ıyla açılır; `filterMode: none` her durumda kapatır.',
|
|
987
|
+
'Telefonda düzenleme (34): bağlantının yazdığı `editMode`/`canEditRow`/`canAddRow`/`canDeleteRow`/`bulkActions` okunur. Satıra dokunmak `rowClick`i yayar (`selectedRow` sessiz yazılır) ve düzenlenebilir kolon varsa "Satırı düzenle" alt sayfasını açar (alan türüne göre denetim: metin/sayı/tarih girişi, anahtar, seçenek çipleri, ilişkide lookup). `canAddRow` + `addRowButton` ≠ `none` "Yeni satır" düğmesi (`__add-row`). `bulkActions` açıksa uzun basış seçim kipidir (`rowSelectionChange`, `selectedRows`): çubukta Toplu düzenle (tek alan, bütün seçililere) ve Sil. Bağlamanın `behavior.mobile.swipeDelete`ı kartı kaydırınca Sil (onaylı) açar. Kayıt `save` olayıyla gider (changeset + `operation`, web f-22 ile aynı); `row`/`cell` kipi anında, `batch` alt çubuktaki Kaydet ile (`discard` Vazgeç). Kısmi başarıda hatalı satır kırmızı çerçeve + satır hatası, özet şeridi "2 satır yazıldı, 1 düşmedi" (`__save-outcome`); düşen satırlar seçili kalır.',
|
|
988
|
+
'Kart alanları ve sayfa (34): `variant: cards` iken kart bağlamanın `behavior.mobileCard`ından çizilir (başlık, sıralı etiket-değer alanları, sağ değer); eşleme yoksa ilk görsel/ilk metin kuralı. `paginationMode: infinite` ya da bağlamanın `behavior.mobile.infiniteScroll`ı (yazılmamışsa açık) sayfaları birleştirir: sayfa kaydırıcısı sona yaklaşınca sonraki `offset` kendiliğinden istenir, yeni sayfa sona eklenir, altta "Yükleniyor…"; sayfa çubuğu çizilmez (sayfa kaydırıcısı olmayan kapta "Daha fazla" `__load-more`). `behavior.mobile.pullToRefresh` sayfayı aşağı çekince listeyi yeniler (web önizlemede çekme yok: başlıkta yenile düğmesi). `showRefresh: false` yenile düğmesini kaldırır. `showRecordSummary: false` kayıt aralığı metnini kaldırır. Bunların ve yukarıdaki çip/düzenleme davranışlarının hepsi yalnız `variant: cards` kipindedir: `variant: table` salt okunur ızgaradır (dokunuş, düzenleme, seçim, çip yok).',
|
|
932
989
|
'Hücre: metin tablo kipinde tek satırda kırpılır (`multiLine` ise `lineClamp` kadar satır), kart kipinde sarar; etiket rengi temadan çözülür, üstündeki metin koyu/açık seçilir; `image` kolonu `imageHeight` karesi; `file` ve `url` dokunuşla sistemde açılır (kanvasta kilitli); `progress` her zaman çubuktur (daire kipi çubuk çizilir). Yükleniyor (`isLoading`) satırların yerine ortada dönen gösterge; satır yokken gövde web`in boş satırı kadar (120) boş kalır, ileti yazılmaz. Bırakılamaz — web ikizi bırakılabilir bildirir ama çocuk çizmez.'
|
|
933
990
|
],
|
|
934
991
|
propNotes: {
|
|
@@ -951,6 +1008,7 @@ export const mobileComponentKnowledge = {
|
|
|
951
1008
|
'dropdown-button': {
|
|
952
1009
|
summary: 'Menü açan düğme (bağlam menüsü ⋮): web ikizinin prop ve olayları; menü tetikleyiciye çapalı 230 dp`lik katmandır.',
|
|
953
1010
|
differences: [
|
|
1011
|
+
WEB_WORDS_NOTE,
|
|
954
1012
|
'Menü tetikleyicinin altında (sığmazsa üstünde) açılır, ekranın içinde kalır; arka plan hafif kararır, dışarı dokunuş kapatır. Başlık (`optionsTitle`), ikonlu satırlar, `isDanger` kırmızı, `isDisabled` soluk ve basılmaz.',
|
|
955
1013
|
'Satıra basış menüyü kapatır ve `clickItem { currentItem }` yayar; satırın kendi `flow`u varsa ÖNCE o akış koşar (web). Düğmenin kendisine basış `click`. İç roller `<elementId>__press` (düğme) ve `<elementId>__item-<key>` (satır) — `page_screenshot` `click` onlarla basar.',
|
|
956
1014
|
'Satır ikonu düz ad olmalı (`"icon": "edit"`): statik dizi satırındaki iç içe nesne mobilde okunmaz. Düşenler: `style`.'
|
|
@@ -959,6 +1017,7 @@ export const mobileComponentKnowledge = {
|
|
|
959
1017
|
timeline: {
|
|
960
1018
|
summary: 'Zaman çizelgesi (bakım geçmişi): gün başlıkları, renkli ikon düğümü + dikey çizgi, saat ve meta satırı, not balonu, küçük resimler; web ikizinin prop ve olayları.',
|
|
961
1019
|
differences: [
|
|
1020
|
+
WEB_WORDS_NOTE,
|
|
962
1021
|
'Dikey tek düzen. Satırlar `groupByDate` (MOBİLE ÖZGÜ, varsayılan açık) ile gün başlıklarına ayrılır ("Bugün", "Dün", yoksa `dateFormat`); kapalıyken tek liste. `items[].images` (MOBİLE ÖZGÜ): adres dizisi (`["a.jpg", "b.jpg"]`, statik satırda da kabul edilir — ARC-152) ya da virgülle ayrılmış metin (`"a.jpg, b.jpg"`); bağla gelen satırda `[{ src }]` de okunur. Satırın altında küçük resimler.',
|
|
963
1022
|
'Satıra dokunuş `clickItem { currentItem, index }` yayar; öğenin kendi `flow`u da koşar (web: bağlı akış önce başlatılır). `maxCount` aşılınca "Tümünü göster" (`<elementId>__show-more`) kalanı açar ve `showMore` yayar. `showMoreText`/`emptyText` yazılmamışsa uygulama dilinden gelir ("Tümünü göster" / "Henüz kayıt yok"). Satır iç rolü `<elementId>__item-<index>`.',
|
|
964
1023
|
'Düşenler: `orientation` (mobil yalnız dikey), `style`, `isClickable` (satır, düğümün `clickItem`ı bağlıysa kendiliğinden basılır).'
|
|
@@ -16,6 +16,19 @@ export const SPLASH_RESIZE_MODES = ['contain', 'cover'];
|
|
|
16
16
|
export const RELEASE_STATUSES = ['draft', 'completed'];
|
|
17
17
|
/** İznin mağaza derlemesindeki kipi (kök ADR 0010): kullanıma göre · her zaman · hiç. Anahtarları backend doğrular. */
|
|
18
18
|
export const PERMISSION_MODES = ['auto', 'on', 'off'];
|
|
19
|
+
/**
|
|
20
|
+
* Mağaza yayın ayarı (plan mobil-tasarimci-kabuk-ekranlari b-24/g-21) — backend `MobileStoreSettings` /
|
|
21
|
+
* `MobileStoreSettingsValidator` aynası: iOS yayın şekli, fiyat basamağı, ülke (ISO 3166 alfa-3 ya da tek
|
|
22
|
+
* başına 'all'), Play iletişim telefonu (E.164), YouTube tanıtım videosu, kademeli yayın yüzdesi.
|
|
23
|
+
*/
|
|
24
|
+
export const APPLE_RELEASE_TYPES = ['manual', 'automatic', 'scheduled'];
|
|
25
|
+
export const FREE_PRICING = 'free';
|
|
26
|
+
export const ALL_TERRITORIES = 'all';
|
|
27
|
+
export const PRICE_TIER_PATTERN = /^tier-([1-9]|[1-7][0-9]|8[0-7])$/;
|
|
28
|
+
export const TERRITORY_PATTERN = /^[A-Z]{3}$/;
|
|
29
|
+
export const PHONE_PATTERN = /^\+[1-9]\d{6,14}$/;
|
|
30
|
+
export const YOUTUBE_HOSTS = ['youtube.com', 'www.youtube.com', 'm.youtube.com', 'youtu.be'];
|
|
31
|
+
export const PLAY_TRACKS = ['closed', 'production'];
|
|
19
32
|
/** Reklam ayarı (kök ADR 0012) — backend `MobileStoreSettingsValidator` / `MobileAdFormat` aynası. */
|
|
20
33
|
export const AD_APP_ID_PATTERN = /^ca-app-pub-\d{16}~\d{10}$/;
|
|
21
34
|
export const AD_UNIT_ID_PATTERN = /^ca-app-pub-\d{16}\/\d{10}$/;
|
|
@@ -24,6 +37,10 @@ export const AD_UNITS_MAX_COUNT = 40;
|
|
|
24
37
|
export const AD_FORMATS = ['banner', 'interstitial', 'rewarded', 'rewardedInterstitial', 'appOpen'];
|
|
25
38
|
/** Reklam açıkken taşınması gereken izin: iOS ATT (backend `MobileStoreSettings.AdsPermission`). */
|
|
26
39
|
export const ADS_PERMISSION = 'tracking';
|
|
40
|
+
/** Uygulama kilidi (kök ADR 0021 madde 8): kapalı süre kümesi (saniye, `MobileStoreSettings.AppLockTimeouts`), kullandığı izin ve kabuk yeteneğinin sürümü (`MobileBuildOptions` `appLock`) */
|
|
41
|
+
export const APP_LOCK_TIMEOUTS = [0, 60, 300, 900];
|
|
42
|
+
export const APP_LOCK_PERMISSION = 'biometric';
|
|
43
|
+
export const APP_LOCK_SHELL_VERSION = '0.6.0';
|
|
27
44
|
export const LISTING_LIMITS = {
|
|
28
45
|
title: 30,
|
|
29
46
|
subtitle: 30,
|
|
@@ -47,7 +64,7 @@ export const JAVA_KEYWORDS = new Set([
|
|
|
47
64
|
* `MobileStoreAssetValidator.cs`; Studio kopyası `store-assets.validation.ts`. Parite:
|
|
48
65
|
* `test/mobile-store-assets.test.ts` (plans/mobil-yayin-mcp g-01).
|
|
49
66
|
*/
|
|
50
|
-
export const ASSET_KINDS = ['icon', 'adaptiveForeground', 'adaptiveBackground', 'adaptiveMonochrome', 'splash', 'featureGraphic', 'screenshot', 'promo'];
|
|
67
|
+
export const ASSET_KINDS = ['icon', 'adaptiveForeground', 'adaptiveBackground', 'adaptiveMonochrome', 'splash', 'featureGraphic', 'screenshot', 'promo', 'reviewAttachment'];
|
|
51
68
|
/** Derlemeye giren görseller dilsizdir (`MobileStoreAssetValidator.BuildKinds`); PNG zorunlu */
|
|
52
69
|
export const BUILD_ASSET_KINDS = ['icon', 'adaptiveForeground', 'adaptiveBackground', 'adaptiveMonochrome', 'splash'];
|
|
53
70
|
export const DEVICE_CLASSES = ['iphone69', 'ipad13', 'phone', 'tablet7', 'tablet10'];
|
|
@@ -76,6 +93,9 @@ export function assetSlotProblem(kind, locale, deviceClass) {
|
|
|
76
93
|
if (BUILD_ASSET_KINDS.includes(kind) && locale !== undefined) {
|
|
77
94
|
return `'${kind}' derlemeye giren görseldir ve dilsizdir — locale verilmez`;
|
|
78
95
|
}
|
|
96
|
+
if (kind === 'reviewAttachment' && locale !== undefined) {
|
|
97
|
+
return "'reviewAttachment' App Review ekidir ve dilsizdir — locale verilmez";
|
|
98
|
+
}
|
|
79
99
|
if (kind === 'screenshot' && deviceClass === undefined) {
|
|
80
100
|
return `'screenshot' cihaz sınıfı ister — deviceClass: ${DEVICE_CLASSES.join(' | ')}`;
|
|
81
101
|
}
|
|
@@ -107,8 +127,10 @@ const isHttpsUrl = (value) => {
|
|
|
107
127
|
return false;
|
|
108
128
|
}
|
|
109
129
|
};
|
|
130
|
+
/** Saat dilimsiz ISO tarih backend'de UTC sayılır (`DateTime` Unspecified, `DateTime.UtcNow` ile karşılaştırılır); JS onu yerel sayardı. */
|
|
131
|
+
const parseUtc = (value) => Date.parse(/T/.test(value) && !/(Z|[+-]\d{2}:?\d{2})$/i.test(value) ? `${value}Z` : value);
|
|
110
132
|
/** Biçim hataları: backend `PUT`'u 422 ile reddedecek her alan (alan yolu = backend `errorFields` anahtarı). */
|
|
111
|
-
export function storeSettingsFormatErrors(settings) {
|
|
133
|
+
export function storeSettingsFormatErrors(settings, now = Date.now()) {
|
|
112
134
|
const errors = [];
|
|
113
135
|
const add = (field, message) => errors.push({ field, message });
|
|
114
136
|
const displayName = settings.displayName;
|
|
@@ -208,6 +230,26 @@ export function storeSettingsFormatErrors(settings) {
|
|
|
208
230
|
add('review.email', 'geçerli e-posta olmalı');
|
|
209
231
|
if (text(apple.copyright).length > COPYRIGHT_MAX_LENGTH)
|
|
210
232
|
add('apple.copyright', `en çok ${COPYRIGHT_MAX_LENGTH} karakter`);
|
|
233
|
+
if (apple.releaseType !== undefined && apple.releaseType !== null && !APPLE_RELEASE_TYPES.includes(text(apple.releaseType)))
|
|
234
|
+
add('apple.releaseType', `kabul edilen değerler: ${APPLE_RELEASE_TYPES.join(' | ')}`);
|
|
235
|
+
if (apple.releaseType === 'scheduled' && !(parseUtc(text(apple.scheduledAt)) > now))
|
|
236
|
+
add('apple.scheduledAt', "releaseType 'scheduled' ileri bir tarih ister (ISO 8601, UTC)");
|
|
237
|
+
if (apple.pricing !== undefined && apple.pricing !== null && text(apple.pricing) !== FREE_PRICING && !PRICE_TIER_PATTERN.test(text(apple.pricing)))
|
|
238
|
+
add('apple.pricing', `'${FREE_PRICING}' ya da tier-1…tier-87 olmalı`);
|
|
239
|
+
if (Array.isArray(apple.territories)) {
|
|
240
|
+
const territories = apple.territories.map(text);
|
|
241
|
+
if (territories.length === 0 || (territories.includes(ALL_TERRITORIES) && territories.length > 1) || territories.some(code => code !== ALL_TERRITORIES && !TERRITORY_PATTERN.test(code))) {
|
|
242
|
+
add('apple.territories', `tek başına '${ALL_TERRITORIES}' ya da ISO 3166 alfa-3 ülke kodları (TUR, DEU)`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (!isBlank(play.contactPhone) && !PHONE_PATTERN.test(text(play.contactPhone)))
|
|
246
|
+
add('play.contactPhone', 'uluslararası biçimde olmalı (+905551112233)');
|
|
247
|
+
if (!isBlank(play.contactWebsite) && !isHttpsUrl(text(play.contactWebsite)))
|
|
248
|
+
add('play.contactWebsite', 'mutlak https:// adres olmalı');
|
|
249
|
+
if (!isBlank(play.promoVideoUrl) && !(isHttpsUrl(text(play.promoVideoUrl)) && YOUTUBE_HOSTS.includes(new URL(text(play.promoVideoUrl)).hostname)))
|
|
250
|
+
add('play.promoVideoUrl', `https:// YouTube adresi olmalı (${YOUTUBE_HOSTS.join(', ')})`);
|
|
251
|
+
if (play.rolloutPercent !== undefined && play.rolloutPercent !== null && !(Number.isInteger(play.rolloutPercent) && Number(play.rolloutPercent) >= 1 && Number(play.rolloutPercent) <= 100))
|
|
252
|
+
add('play.rolloutPercent', '1 ile 100 arasında tam sayı');
|
|
211
253
|
const ads = isObject(settings.ads) ? settings.ads : {};
|
|
212
254
|
const units = (Array.isArray(ads.units) ? ads.units : []).filter(isObject);
|
|
213
255
|
const appIdExample = 'ca-app-pub-0000000000000000~0000000000';
|
|
@@ -238,6 +280,12 @@ export function storeSettingsFormatErrors(settings) {
|
|
|
238
280
|
add('ads.appOpenUnit', `'${text(ads.appOpenUnit)}' appOpen biçiminde tanımlı bir yerleşim değil`);
|
|
239
281
|
if (ads.enabled === true && isObject(settings.permissionModes) && settings.permissionModes[ADS_PERMISSION] === 'off')
|
|
240
282
|
add(`permissionModes.${ADS_PERMISSION}`, "reklam açıkken izleme izni (tracking) kapatılamaz — iOS'ta kişiselleştirilmiş reklam ATT ister; kipi auto ya da on yapın");
|
|
283
|
+
const appLock = isObject(settings.appLock) ? settings.appLock : null;
|
|
284
|
+
// Backend eksik süreyi int varsayılanı 0'a bağlar (geçerli)
|
|
285
|
+
if (appLock && !APP_LOCK_TIMEOUTS.includes(appLock.timeoutSeconds ?? 0))
|
|
286
|
+
add('appLock.timeoutSeconds', `bekleme süresi şu saniyelerden biri olmalı: ${APP_LOCK_TIMEOUTS.join(', ')} (hemen, 1, 5 ya da 15 dakika)`);
|
|
287
|
+
else if (appLock?.enabled === true && isObject(settings.permissionModes) && settings.permissionModes[APP_LOCK_PERMISSION] === 'off')
|
|
288
|
+
add('appLock.enabled', `permissionModes.${APP_LOCK_PERMISSION} 'off': derleme biyometriyi taşımayacağı için uygulama kilitlenemez — kipi auto ya da on yapın ya da appLock.enabled: false (MOB-031)`);
|
|
241
289
|
return errors;
|
|
242
290
|
}
|
|
243
291
|
/**
|
|
@@ -326,6 +374,17 @@ export function permissionLaunchShellWarnings(permissions, shell) {
|
|
|
326
374
|
return [];
|
|
327
375
|
return [`${asked.join(', ')}: açılışta sorulacak diye ayarlı ama yayındaki kabuk paketi (${text(shell.version)}) açılışta izin sormuyor — ayar saklanır, mağaza derlemesi sormaz (ön kontrol P-12 uyarır). Daha yeni bir kabuk yayınlanana kadar izni bir akış adımından isteyin (MOB-025, ${guide}).`];
|
|
328
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* MOB-031 — uygulama kilidi kabuğun ayrı bir yeteneğidir (`shell.carriesAppLock`, kök ADR 0021 madde 8). Kilit açıkken
|
|
379
|
+
* (`biometric`'in `source: lock` kullanımı) yayındaki kabuk onu taşımıyorsa ayar saklanır ama manifest `appLock`
|
|
380
|
+
* yazmaz: mağaza sürümü kilitsiz açılır. Eski backend alanı söylemez; o zaman iddia edilmez.
|
|
381
|
+
*/
|
|
382
|
+
export function permissionLockShellWarnings(permissions, shell) {
|
|
383
|
+
const locked = permissions.some(entry => entry.key === APP_LOCK_PERMISSION && Array.isArray(entry.usage) && entry.usage.some(place => isObject(place) && place.source === 'lock'));
|
|
384
|
+
if (!locked || !isObject(shell) || shell.carriesAppLock !== false)
|
|
385
|
+
return [];
|
|
386
|
+
return [`appLock: uygulama kilidi açık ama yayındaki kabuk paketi (${text(shell.version)}) kilidi taşımıyor — kabuk ${APP_LOCK_SHELL_VERSION} ister; ayar saklanır, mağaza sürümü kilitsiz açılır (ön kontrol P-12 uyarır; kabuk uyarıları tek satırda birleştiği için kod kabuğun sürümüne göre değişir) (MOB-031, ${guide}).`];
|
|
387
|
+
}
|
|
329
388
|
/**
|
|
330
389
|
* MOB-027 — izleme izni (kök ADR 0011): mağaza derlemesi `tracking`'i taşıyorsa App Store Connect App Privacy'de
|
|
331
390
|
* "Device ID — Used to Track You" ve Play Data safety'de "Advertising ID" beyanı insanın işidir; Apple izin penceresinden
|
|
@@ -116,7 +116,7 @@ export const mobileProfile = Object.freeze({
|
|
|
116
116
|
},
|
|
117
117
|
style: { freeStyle: false, hoverStyle: false, resolver: 'native' },
|
|
118
118
|
steps: {
|
|
119
|
-
registered: new Set([...ENGINE_STEP_TYPES, 'alert', 'confirm', 'redirect', 'navigate', 'storage', 'setcookie', 'download', 'share', 'haptic', 'location', 'notification-permission', 'notification-schedule', 'notification-cancel', 'permission', 'open-settings', 'ad-show', 'back', 'scan-code']),
|
|
119
|
+
registered: new Set([...ENGINE_STEP_TYPES, 'alert', 'confirm', 'redirect', 'navigate', 'storage', 'setcookie', 'download', 'share', 'haptic', 'location', 'notification-permission', 'notification-schedule', 'notification-cancel', 'permission', 'open-settings', 'ad-show', 'back', 'biometric-auth', 'scan-code']),
|
|
120
120
|
aliases: STEP_ALIASES,
|
|
121
121
|
infoOnly: new Set(['download', 'setcookie'])
|
|
122
122
|
},
|
|
@@ -201,7 +201,8 @@ export const MOBILE_WEB_ONLY = {
|
|
|
201
201
|
'theme-toggle': "uygulama içi tema ayarı: 'choice-chips' (variant: segmented, Sistem/Açık/Koyu) → storage adımı name: 'zeyrek:theme-mode', value: system | light | dark; barındırıcı temayı anında değiştirir, cihazda kalıcı (seçim yazılmadıysa açık tema; cihaz teması yalnız system seçilince)",
|
|
202
202
|
pagination: "'repeater' + daha fazla yükle düğmesi",
|
|
203
203
|
breadcrumb: "yığın gezinmesi (app-bar geri düğmesi)",
|
|
204
|
-
fileUpload: "'fileInput' (alan) ya da 'filebutton' (düğme) — dokunmatikte sürükle-bırak yok; ikisi de aynı base64 değeri yazar"
|
|
204
|
+
fileUpload: "'fileInput' (alan) ya da 'filebutton' (düğme) — dokunmatikte sürükle-bırak yok; ikisi de aynı base64 değeri yazar",
|
|
205
|
+
attachments: "'filebutton' (isMultiple açık; seçilenler düğmenin altında satır satır) — mobilde önizlemeli kart ızgarası, popup ve sürükle-bırak yok; değer aynı base64 dizisidir"
|
|
205
206
|
};
|
|
206
207
|
const STYLE_REPLACEMENTS = {
|
|
207
208
|
className: "yerine surfaceStyle (zemin, kenar, köşe, gölge) ve typographyStyle tipli gruplarını kullanın",
|