@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,169 +1,204 @@
1
- # Sheets
1
+ # Sheet Routing
2
2
 
3
- ## Contents
3
+ Part of the `swiftui-navigation` skill. Routing every modal through one place
4
+ lets any view open a sheet without threading bindings through its parents, and
5
+ it keeps working as screens are added.
4
6
 
5
- - [Intent](#intent)
6
- - [Core architecture](#core-architecture)
7
- - [Example: SheetDestination enum](#example-sheetdestination-enum)
8
- - [Example: withSheetDestinations modifier](#example-withsheetdestinations-modifier)
9
- - [Example: presenting from a child view](#example-presenting-from-a-child-view)
10
- - [Required wiring](#required-wiring)
11
- - [Example: sheets that need their own navigation](#example-sheets-that-need-their-own-navigation)
12
- - [Design choices to keep](#design-choices-to-keep)
13
- - [iOS 26 Presentation Sizing](#ios-26-presentation-sizing)
14
- - [Pitfalls](#pitfalls)
7
+ ## Building blocks
15
8
 
16
- ## Intent
9
+ - A `SheetDestination` enum, `Identifiable`, with one case per modal.
10
+ - `presentedSheet: SheetDestination?` stored on the router.
11
+ - A modifier, here `withSheetDestinations(sheet:)`, that turns a case into its
12
+ view.
13
+ - The router in the environment, so children assign `presentedSheet` directly.
17
14
 
18
- Use a centralized sheet routing pattern so any view can present modals without prop-drilling. This keeps sheet state in one place and scales as the app grows.
19
-
20
- ## Core architecture
21
-
22
- - Define a `SheetDestination` enum that describes every modal and is `Identifiable`.
23
- - Store the current sheet in a router object (`presentedSheet: SheetDestination?`).
24
- - Create a view modifier like `withSheetDestinations(...)` that maps the enum to concrete sheet views.
25
- - Inject the router into the environment so child views can set `presentedSheet` directly.
26
-
27
- ## Example: SheetDestination enum
15
+ ## The destination enum
28
16
 
29
17
  ```swift
30
- enum SheetDestination: Identifiable, Hashable {
31
- case composer
32
- case editProfile
33
- case settings
34
- case report(itemID: String)
35
-
36
- var id: String {
37
- switch self {
38
- case .composer, .editProfile:
39
- // Use the same id to ensure only one editor-like sheet is active at a time.
40
- return "editor"
41
- case .settings:
42
- return "settings"
43
- case .report:
44
- return "report"
18
+ enum SheetDestination: Hashable, Identifiable {
19
+ case newTrip
20
+ case editTrip(Trip.ID)
21
+ case sharePhoto(Photo.ID)
22
+ case report(itemID: String)
23
+
24
+ var id: String {
25
+ if case .sharePhoto = self { return "share" }
26
+ if case .report = self { return "report" }
27
+ return "trip-editor"
45
28
  }
46
- }
47
29
  }
48
30
  ```
49
31
 
50
- ## Example: withSheetDestinations modifier
32
+ `newTrip` and `editTrip` return the same `id`. They are two ways into one
33
+ editor, so they can never be on screen together.
34
+
35
+ ## The mapping modifier
51
36
 
52
37
  ```swift
53
38
  extension View {
54
- func withSheetDestinations(
55
- sheet: Binding<SheetDestination?>
56
- ) -> some View {
57
- sheet(item: sheet) { destination in
58
- Group {
59
- switch destination {
60
- case .composer:
61
- ComposerView()
62
- case .editProfile:
63
- EditProfileView()
64
- case .settings:
65
- SettingsView()
66
- case .report(let itemID):
67
- ReportView(itemID: itemID)
39
+ func withSheetDestinations(sheet: Binding<SheetDestination?>) -> some View {
40
+ self.sheet(item: sheet) { modal in
41
+ Group {
42
+ switch modal {
43
+ case .newTrip: TripEditor(trip: nil)
44
+ case .editTrip(let id): TripEditor(tripID: id)
45
+ case .sharePhoto(let id): PhotoShareView(photoID: id)
46
+ case .report(let itemID): ReportForm(itemID: itemID)
47
+ }
48
+ }
68
49
  }
69
- }
70
50
  }
71
- }
72
51
  }
73
52
  ```
74
53
 
75
- ## Example: presenting from a child view
54
+ ## Opening a sheet from deep in the tree
76
55
 
77
56
  ```swift
78
- struct StatusRow: View {
79
- @Environment(RouterPath.self) private var router
80
-
81
- var body: some View {
82
- Button("Report") {
83
- router.presentedSheet = .report(itemID: "123")
57
+ struct CommentRow: View {
58
+ @Environment(Router.self) private var router
59
+ let comment: Comment
60
+
61
+ var body: some View {
62
+ Text(comment.body)
63
+ .contextMenu {
64
+ Button("Report", systemImage: "flag") {
65
+ router.presentedSheet = .report(itemID: comment.id)
66
+ }
67
+ }
84
68
  }
85
- }
86
69
  }
87
70
  ```
88
71
 
89
- ## Required wiring
72
+ ## Wiring at the root
73
+
74
+ 1. The parent owns the router instance.
75
+ 2. It installs `withSheetDestinations(sheet: $router.presentedSheet)`; a plain
76
+ `sheet(item:)` does the same job.
77
+ 3. `.environment(router)` comes later in the chain than the sheet modifier, so
78
+ whatever the sheet shows can read the router as well.
90
79
 
91
- For the child view to work, a parent view must:
92
- - own the router instance,
93
- - attach `withSheetDestinations(sheet: $router.presentedSheet)` (or an equivalent `sheet(item:)` handler), and
94
- - inject it with `.environment(router)` after the sheet modifier so the modal content inherits it.
80
+ ```swift
81
+ struct TripsRoot: View {
82
+ @State private var router = Router()
83
+
84
+ var body: some View {
85
+ NavigationStack(path: $router.path) { TripsList().withAppRouter() }
86
+ .withSheetDestinations(sheet: $router.presentedSheet)
87
+ .environment(router)
88
+ }
89
+ }
90
+ ```
95
91
 
96
- This makes the child assignment to `router.presentedSheet` drive presentation at the root.
92
+ With that in place, a child that sets `presentedSheet` makes the root present
93
+ the sheet.
97
94
 
98
- ## Example: sheets that need their own navigation
95
+ ## Sheets that push their own screens
99
96
 
100
- Wrap sheet content in a `NavigationStack` so it can push within the modal.
97
+ Wrap the content in a stack with a close button when a sheet needs its own
98
+ navigation.
101
99
 
102
100
  ```swift
103
101
  struct NavigationSheet<Content: View>: View {
104
- var content: () -> Content
105
-
106
- var body: some View {
107
- NavigationStack {
108
- content()
109
- .toolbar { CloseToolbarItem() }
102
+ @ViewBuilder var content: Content
103
+ @Environment(\.dismiss) private var close
104
+
105
+ var body: some View {
106
+ NavigationStack {
107
+ content
108
+ .toolbar {
109
+ ToolbarItem(placement: .cancellationAction) {
110
+ Button("Close", systemImage: "xmark") { close() }
111
+ }
112
+ }
113
+ }
110
114
  }
111
- }
112
115
  }
113
116
  ```
114
117
 
115
- ## Design choices to keep
118
+ ## Rules worth keeping
116
119
 
117
- - Centralize sheet routing so features can present modals without wiring bindings through many layers.
118
- - Use `sheet(item:)` to guarantee a single sheet is active and to drive presentation from the enum.
119
- - Group related sheets under the same `id` when they are mutually exclusive (e.g., editor flows).
120
- - Keep sheet views lightweight and composed from smaller views; avoid large monoliths.
120
+ - Route sheets centrally so features do not pass bindings through layers.
121
+ - `sheet(item:)` keeps exactly one sheet active, chosen by the enum.
122
+ - Mutually exclusive sheets share an `id`.
123
+ - Sheet views stay small and composed from pieces.
121
124
 
122
- ## iOS 26 Presentation Sizing
125
+ ## Presentation sizing
123
126
 
124
- Control sheet dimensions with `presentationSizing(_:)` (iOS 18+):
127
+ The section concerns iOS 26 layouts, but `presentationSizing(_:)` itself is
128
+ available from iOS 18. Values: `.automatic`, `.page`, `.form`, `.fitted`.
129
+ `.fitted(horizontal:vertical:)` fits only the axes you pass, and
130
+ `.sticky(horizontal:vertical:)` lets the sheet grow along them without
131
+ shrinking.
125
132
 
126
133
  ```swift
127
- .sheet(item: $selectedItem) { item in
128
- EditItemSheet(item: item)
129
- .presentationSizing(.form)
130
- }
134
+ TripEditor(trip: nil)
135
+ .presentationSizing(.form.sticky(horizontal: false, vertical: true))
131
136
  ```
132
137
 
133
- `PresentationSizing` values:
134
- - `.automatic` -- platform default
135
- - `.page` -- roughly paper size, for informational content
136
- - `.form` -- slightly narrower than page, for form-style UI
137
- - `.fitted` -- sized by the content's ideal size
138
+ ## Confirming dismissal
138
139
 
139
- Modifier methods for fine-tuning:
140
- - `.fitted(horizontal:vertical:)` -- constrain fitting to specific axes
141
- - `.sticky(horizontal:vertical:)` -- grow but do not shrink in specified dimensions
142
-
143
- ### Dismissal Confirmation (macOS 15+ / iOS 26+)
144
-
145
- Show a confirmation dialog when the user tries to dismiss a sheet with unsaved changes:
140
+ On iOS, block the swipe with `.interactiveDismissDisabled(_:)` while there are
141
+ unsaved edits, and ask from your own Close button with `confirmationDialog`:
146
142
 
147
143
  ```swift
148
- .sheet(item: $selectedItem) { item in
149
- EditItemSheet(item: item)
150
- .dismissalConfirmationDialog(
151
- "Discard changes?",
152
- shouldPresent: hasUnsavedChanges
153
- ) {
154
- Button("Discard", role: .destructive) { discardChanges() }
144
+ struct TripEditorSheet: View {
145
+ let id: Trip.ID
146
+ let hasEdits: Bool
147
+ let draft: Draft
148
+ @State private var confirmsDiscard = false
149
+ @Environment(\.dismiss) private var dismiss
150
+
151
+ var body: some View {
152
+ NavigationStack {
153
+ TripEditor(tripID: id)
154
+ .toolbar {
155
+ ToolbarItem(placement: .cancellationAction) {
156
+ Button("Close", systemImage: "xmark") {
157
+ if hasEdits { confirmsDiscard = true } else { dismiss() }
158
+ }
159
+ .confirmationDialog("Throw away your edits?", isPresented: $confirmsDiscard) {
160
+ Button("Throw Away", role: .destructive) {
161
+ draft.revert()
162
+ dismiss()
163
+ }
164
+ Button("Save and Close") {
165
+ draft.save()
166
+ dismiss()
167
+ }
168
+ }
169
+ }
170
+ }
155
171
  }
172
+ .interactiveDismissDisabled(hasEdits)
173
+ }
156
174
  }
157
175
  ```
158
176
 
159
- - Cancel action is included automatically and prevents dismissal
160
- - All other action buttons allow dismissal to proceed
161
- - Use `.keyboardShortcut(.defaultAction)` to set the default button
177
+ On macOS 15 and later, `dismissalConfirmationDialog(_:shouldPresent:)` does
178
+ this for you. The SDK marks it unavailable on iOS, iPadOS, tvOS, watchOS and
179
+ visionOS, so it only compiles in a macOS target:
180
+
181
+ ```swift
182
+ TripEditor(tripID: id)
183
+ .dismissalConfirmationDialog("Throw away your edits?", shouldPresent: hasEdits) {
184
+ Button("Throw Away", role: .destructive) { draft.revert() }
185
+ Button("Save and Close") { draft.save() }
186
+ .keyboardShortcut(.defaultAction)
187
+ }
188
+ ```
189
+
190
+ The system adds Cancel on its own, and Cancel keeps the sheet open. Any other
191
+ button lets the dismissal go ahead. `.keyboardShortcut(.defaultAction)` marks
192
+ the default choice.
162
193
 
163
194
  ## Pitfalls
164
195
 
165
- - Avoid mixing `sheet(isPresented:)` and `sheet(item:)` for the same concern; prefer a single enum.
166
- - Do not store heavy state inside `SheetDestination`; pass lightweight identifiers or models.
167
- - If multiple sheets can appear from the same screen, give them distinct `id` values.
168
- - Use `presentationSizing(.form)` for form sheets instead of hard-coding frame dimensions.
169
- - Always pair `dismissalConfirmationDialog` with a `shouldPresent` condition; showing it when there are no changes is confusing.
196
+ - Two presentation styles, `sheet(isPresented:)` plus `sheet(item:)`, for one
197
+ concern. A single enum is enough.
198
+ - Carrying heavy state inside `SheetDestination`. Pass identifiers or small
199
+ models.
200
+ - Reusing an `id` for sheets that may legitimately come from the same screen
201
+ one after another; give them distinct values.
202
+ - Fixed frames instead of `presentationSizing(.form)`.
203
+ - A dismissal dialog without a real `shouldPresent` condition. Asking when
204
+ nothing changed only confuses people.
@@ -1,178 +1,144 @@
1
- # TabView
1
+ # TabView Architecture
2
2
 
3
- ## Contents
3
+ Part of the `swiftui-navigation` skill. Goal: tabs that scale across platforms,
4
+ with one source of truth for what each tab is and shows, different tab sets and
5
+ sidebar groupings per platform, tabs generated from data, and a hook that can
6
+ intercept special tabs.
4
7
 
5
- - [Intent](#intent)
6
- - [Core architecture](#core-architecture)
7
- - [Example: custom binding with side effects](#example-custom-binding-with-side-effects)
8
- - [Example: direct binding without side effects](#example-direct-binding-without-side-effects)
9
- - [Design choices to keep](#design-choices-to-keep)
10
- - [Dynamic tabs pattern](#dynamic-tabs-pattern)
11
- - [iOS 26 Tab API](#ios-26-tab-api)
12
- - [Pitfalls](#pitfalls)
8
+ ## Building blocks
13
9
 
14
- ## Intent
10
+ - `AppTab` enum: identity, title, icon and a builder for its content.
11
+ - `SidebarSections` enum: which tabs appear under which sidebar heading. Give
12
+ its `title` the type `LocalizedStringKey`. With a `String` title,
13
+ `TabSection(group.title)` makes `Tab(value:)` ambiguous and the view does not
14
+ compile.
15
+ - `AppView`: owns the `TabView` and the selection, and routes selection changes
16
+ through `updateTab(with:)`.
15
17
 
16
- Use this pattern for a scalable, multi-platform tab architecture with:
17
- - a single source of truth for tab identity and content,
18
- - platform-specific tab sets and sidebar sections,
19
- - dynamic tabs sourced from data,
20
- - an interception hook for special tabs (e.g., compose).
21
-
22
- ## Core architecture
23
-
24
- - `AppTab` enum defines identity, labels, icons, and content builder.
25
- - `SidebarSections` enum groups tabs for sidebar sections.
26
- - `AppView` owns the `TabView` and selection binding, and routes tab changes through `updateTab`.
27
-
28
- ## Example: custom binding with side effects
29
-
30
- Use this when tab selection needs side effects, like intercepting a special tab to perform an action instead of changing selection.
18
+ ## Selection with side effects
31
19
 
32
20
  ```swift
33
- @MainActor
34
21
  struct AppView: View {
35
- @Binding var selectedTab: AppTab
36
-
37
- var body: some View {
38
- TabView(selection: .init(
39
- get: { selectedTab },
40
- set: { updateTab(with: $0) }
41
- )) {
42
- ForEach(availableSections) { section in
43
- TabSection(section.title) {
44
- ForEach(section.tabs) { tab in
45
- Tab(value: tab) {
46
- tab.makeContentView(
47
- homeTimeline: $timeline,
48
- selectedTab: $selectedTab,
49
- pinnedFilters: $pinnedFilters
50
- )
51
- } label: {
52
- tab.label
53
- }
54
- .tabPlacement(tab.tabPlacement)
55
- }
56
- }
57
- .tabPlacement(.sidebarOnly)
58
- }
59
- }
60
- }
22
+ let sections: [SidebarSections]
23
+ @State private var scrollTarget: AppTab?
24
+ @State private var showsComposer = false
25
+ @State private var selectedTab: AppTab = .home
61
26
 
62
- private func updateTab(with newTab: AppTab) {
63
- if newTab == .post {
64
- // Intercept special tabs (compose) instead of changing selection.
65
- presentComposer()
66
- return
27
+ private var selection: Binding<AppTab> {
28
+ Binding(get: { selectedTab }, set: updateTab(with:))
67
29
  }
68
- selectedTab = newTab
69
- }
70
- }
71
- ```
72
-
73
- ## Example: direct binding without side effects
74
30
 
75
- Use this when selection is purely state-driven.
76
-
77
- ```swift
78
- @MainActor
79
- struct AppView: View {
80
- @Binding var selectedTab: AppTab
81
-
82
- var body: some View {
83
- TabView(selection: $selectedTab) {
84
- ForEach(availableSections) { section in
85
- TabSection(section.title) {
86
- ForEach(section.tabs) { tab in
87
- Tab(value: tab) {
88
- tab.makeContentView(
89
- homeTimeline: $timeline,
90
- selectedTab: $selectedTab,
91
- pinnedFilters: $pinnedFilters
92
- )
93
- } label: {
94
- tab.label
31
+ var body: some View {
32
+ TabView(selection: selection) {
33
+ ForEach(sections) { group in
34
+ TabSection(group.title) {
35
+ ForEach(group.tabs) { entry in
36
+ Tab(value: entry) {
37
+ entry.makeContentView(scrollTarget: $scrollTarget)
38
+ } label: {
39
+ entry.label
40
+ }
41
+ .tabPlacement(entry.tabPlacement)
42
+ }
43
+ }
44
+ .tabPlacement(.sidebarOnly)
95
45
  }
96
- .tabPlacement(tab.tabPlacement)
97
- }
98
46
  }
99
- .tabPlacement(.sidebarOnly)
100
- }
47
+ .sheet(isPresented: $showsComposer) { ComposerView() }
48
+ }
49
+
50
+ private func updateTab(with next: AppTab) {
51
+ if next == .post {
52
+ showsComposer = true
53
+ return
54
+ }
55
+ if next == selectedTab {
56
+ scrollTarget = next
57
+ }
58
+ selectedTab = next
101
59
  }
102
- }
103
60
  }
104
61
  ```
105
62
 
106
- ## Design choices to keep
63
+ Choosing `.post` opens the composer and leaves the selection where it was.
64
+ Choosing the current tab again asks it to scroll to the top.
107
65
 
108
- - Centralize tab identity and content in `AppTab` with `makeContentView(...)`.
109
- - Use `Tab(value:)` with `selection` binding for state-driven tab selection.
110
- - Route selection changes through `updateTab` to handle special tabs and scroll-to-top behavior.
111
- - Use `TabSection` + `.tabPlacement(.sidebarOnly)` for sidebar structure.
112
- - Use `.tabPlacement(.pinned)` in `AppTab.tabPlacement` for a single pinned tab; this is commonly used for iOS 26 `.searchable` tab content, but can be used for any tab.
66
+ ## Selection without side effects
113
67
 
114
- ## Dynamic tabs pattern
68
+ If selection is pure state, bind directly: `TabView(selection: $selectedTab)`
69
+ with the same `TabSection` and `Tab` structure inside.
115
70
 
116
- - `SidebarSections` handles dynamic data tabs.
117
- - `AppTab.anyTimelineFilter(filter:)` wraps dynamic tabs in a single enum case.
118
- - The enum provides label/icon/title for dynamic tabs via the filter type.
71
+ ## Rules worth keeping
119
72
 
120
- ## iOS 26 Tab API
73
+ - `AppTab` is the single home for identity and content, through
74
+ `makeContentView(...)`.
75
+ - Tabs use `Tab(value:)` together with a selection binding.
76
+ - Selection goes through `updateTab(with:)`; that one function deals with
77
+ compose-style tabs and with re-tapping to scroll up.
78
+ - Sidebar structure comes from `TabSection` plus `.tabPlacement(.sidebarOnly)`.
79
+ - `.tabPlacement(.pinned)` keeps one tab fixed in place. It is typical for an
80
+ iOS 26 `.searchable` tab but works for any tab.
121
81
 
122
- iOS 26 expands the Tab API with minimize behavior, roles, and accessory placements.
82
+ ## Tabs generated from data
123
83
 
124
- ### Tab Bar Minimization
84
+ `SidebarSections` can hold tabs that come from user data, such as saved
85
+ filters. Represent them with one case that carries a payload, for example
86
+ `AppTab.savedFilter(SavedFilter)`, and read the title and icon from the filter.
125
87
 
126
88
  ```swift
127
- TabView(selection: $selectedTab) {
128
- // tabs
129
- }
130
- .tabBarMinimizeBehavior(.onScrollDown) // iPhone only
131
- ```
132
-
133
- `TabBarMinimizeBehavior` values:
134
- - `.automatic` -- determine behavior from context
135
- - `.onScrollDown` -- minimize when user scrolls down (iPhone only)
136
- - `.onScrollUp` -- minimize when user scrolls up (iPhone only)
137
- - `.never` -- never minimize the tab bar
89
+ enum AppTab: Hashable, Identifiable {
90
+ case home, search, post, profile
91
+ case savedFilter(SavedFilter)
138
92
 
139
- ### Tab Search Role
140
-
141
- Replace the tab bar with a search field when the search tab is active:
93
+ var id: String {
94
+ guard case .savedFilter(let filter) = self else { return String(describing: self) }
95
+ return "filter-\(filter.id)"
96
+ }
142
97
 
143
- ```swift
144
- Tab(role: .search) {
145
- SearchView()
98
+ @ViewBuilder var label: some View {
99
+ switch self {
100
+ case .savedFilter(let filter): Label(filter.name, systemImage: filter.symbol)
101
+ case .home: Label("Start", systemImage: "house")
102
+ case .search: Label("Search", systemImage: "magnifyingglass")
103
+ case .post: Label("Post", systemImage: "square.and.pencil")
104
+ case .profile: Label("Profile", systemImage: "person")
105
+ }
106
+ }
146
107
  }
147
108
  ```
148
109
 
149
- ### Sidebar Customization
110
+ ## iOS 26 tab API
150
111
 
151
112
  ```swift
152
113
  TabView {
153
- // tabs
114
+ Tab("Feed", systemImage: "list.bullet") { FeedView() }
115
+ Tab(role: .search) { SearchView() }
154
116
  }
155
- .tabViewSidebarHeader { SidebarHeaderView() }
156
- .tabViewSidebarFooter { SidebarFooterView() }
157
- .tabViewSidebarBottomBar { BottomBarView() }
117
+ .tabBarMinimizeBehavior(.onScrollDown)
118
+ .tabViewBottomAccessory { MiniPlayerBar() }
119
+ .tabViewSidebarHeader { AccountHeader() }
120
+ .tabViewSidebarFooter { StorageFooter() }
121
+ .tabViewSidebarBottomBar { SettingsButton() }
158
122
  ```
159
123
 
160
- ### Bottom Accessory
161
-
162
- Use `TabViewBottomAccessoryPlacement` for content below the tab bar:
163
-
164
- ```swift
165
- TabView {
166
- // tabs
167
- }
168
- .tabViewBottomAccessory { NowPlayingBar() }
169
- ```
124
+ - `TabBarMinimizeBehavior`: `.automatic` (decided by context), `.onScrollDown`,
125
+ `.onScrollUp` and `.never`. The two scroll behaviours apply on iPhone only.
126
+ - `Tab(role: .search)` replaces the bar with a search field while that tab is
127
+ active.
128
+ - Sidebar customisation: `.tabViewSidebarHeader { }`,
129
+ `.tabViewSidebarFooter { }` and `.tabViewSidebarBottomBar { }`.
130
+ - `.tabViewBottomAccessory { }` shows content just above the tab bar; its
131
+ placement is described by `TabViewBottomAccessoryPlacement`.
170
132
 
171
133
  ## Pitfalls
172
134
 
173
- - Avoid adding ViewModels for tabs; keep state local or in `@Observable` services.
174
- - Do not nest `@Observable` objects inside other `@Observable` objects.
175
- - Ensure `AppTab.id` values are stable; dynamic cases should hash on stable IDs.
176
- - Special tabs (compose) should not change selection.
177
- - Prefer `Tab(value:)` with `TabView(selection:)` over the older `.tabItem { }` API for typed tab selection.
178
- - `tabBarMinimizeBehavior` only works on iPhone; it has no effect on iPad or Mac.
135
+ - A view model per tab. Keep state local to views or in shared `@Observable`
136
+ services.
137
+ - `@Observable` objects nested inside each other.
138
+ - An `AppTab.id` that changes between launches; dynamic cases must hash on a
139
+ stable identifier.
140
+ - Special tabs such as compose that change the selection.
141
+ - `.tabItem { }` instead of `Tab(value:)` with `TabView(selection:)`, which
142
+ loses typed selection.
143
+ - Expecting `tabBarMinimizeBehavior` to work on iPad or Mac; it does nothing
144
+ there.