@mmerterden/multi-agent-pipeline 20.7.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 (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,474 +1,364 @@
1
1
  ---
2
2
  name: swiftui-gestures
3
- description: "Implement, review, or improve SwiftUI gesture handling. Use when adding tap, long press, drag, magnify, or rotate gestures, composing gestures with simultaneously/sequenced/exclusively, managing transient state with @GestureState, resolving parent/child gesture conflicts with highPriorityGesture or simultaneousGesture, building custom Gesture protocol conformances, or migrating from deprecated MagnificationGesture to MagnifyGesture or using the newer RotateGesture."
3
+ description: "SwiftUI gestures: tap, spatial tap, long press, drag, magnify, rotate, composition (simultaneously, sequenced, exclusively), @GestureState, parent/child conflicts via highPriorityGesture and simultaneousGesture, GestureMask, custom Gesture types. Use when implementing, reviewing or improving gesture handling, resolving conflicts, building pinch, rotate or drag interactions, or migrating MagnificationGesture to MagnifyGesture and RotationGesture to RotateGesture."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
- # SwiftUI Gestures (iOS 26+)
8
+ # SwiftUI Gestures
9
9
 
10
- Review, write, and fix SwiftUI gesture interactions. Apply modern gesture APIs
11
- with correct composition, state management, and conflict resolution using
12
- Swift 6.3 patterns.
10
+ Recognizing touches in SwiftUI views on iOS 26 with Swift 6.3: which gesture
11
+ type to use, how to keep transient state honest, and how to stop gestures on
12
+ parents and children from fighting. Worked interactions (pinch-to-zoom with
13
+ pan, rotate plus scale, drag-to-reorder, flick-to-dismiss, press-then-drag,
14
+ UIKit interop and accessibility) are in
15
+ [references/gesture-patterns.md](references/gesture-patterns.md).
13
16
 
14
- ## Contents
17
+ ## Gesture overview
15
18
 
16
- - [Gesture Overview](#gesture-overview)
17
- - [TapGesture](#tapgesture)
18
- - [LongPressGesture](#longpressgesture)
19
- - [DragGesture](#draggesture)
20
- - [MagnifyGesture (iOS 17+)](#magnifygesture-ios-17)
21
- - [RotateGesture (iOS 17+)](#rotategesture-ios-17)
22
- - [Gesture Composition](#gesture-composition)
23
- - [`@GestureState`](#gesturestate)
24
- - [Adding Gestures to Views](#adding-gestures-to-views)
25
- - [Custom Gesture Protocol](#custom-gesture-protocol)
26
- - [Common Mistakes](#common-mistakes)
27
- - [Review Checklist](#review-checklist)
28
- - [References](#references)
29
-
30
- ## Gesture Overview
31
-
32
- | Gesture | Type | Value | Since |
33
- |---|---|---|---|
19
+ | Gesture | Kind | Value | Since |
20
+ | --- | --- | --- | --- |
34
21
  | `TapGesture` | Discrete | `Void` | iOS 13 |
35
22
  | `LongPressGesture` | Discrete | `Bool` | iOS 13 |
23
+ | `SpatialTapGesture` | Discrete | `SpatialTapGesture.Value` (location) | iOS 16 |
36
24
  | `DragGesture` | Continuous | `DragGesture.Value` | iOS 13 |
37
25
  | `MagnifyGesture` | Continuous | `MagnifyGesture.Value` | iOS 17 |
38
26
  | `RotateGesture` | Continuous | `RotateGesture.Value` | iOS 17 |
39
- | `SpatialTapGesture` | Discrete | `SpatialTapGesture.Value` | iOS 16 |
40
27
 
41
- **Discrete** gestures fire once (`.onEnded`). **Continuous** gestures stream
42
- updates (`.onChanged`, `.onEnded`, `.updating`).
28
+ A discrete gesture reports once, through `.onEnded`. A continuous gesture
29
+ streams values through `.updating` and `.onChanged`, then finishes with
30
+ `.onEnded`.
43
31
 
44
32
  ## TapGesture
45
33
 
46
- Recognizes one or more taps. Use the `count` parameter for multi-tap.
47
-
48
34
  ```swift
49
- // Single, double, and triple tap
50
- TapGesture() .onEnded { tapped.toggle() }
51
- TapGesture(count: 2) .onEnded { handleDoubleTap() }
52
- TapGesture(count: 3) .onEnded { handleTripleTap() }
35
+ Image(systemName: "heart")
36
+ .gesture(TapGesture(count: 2).onEnded { isFavorite.toggle() })
53
37
 
54
- // Shorthand modifier
55
- Text("Tap me").onTapGesture(count: 2) { handleDoubleTap() }
38
+ // Shorthand
39
+ Image(systemName: "heart")
40
+ .onTapGesture(count: 2) { isFavorite.toggle() }
56
41
  ```
57
42
 
43
+ For a plain single tap that performs an action, use a `Button` instead (see
44
+ Common mistakes).
45
+
58
46
  ## LongPressGesture
59
47
 
60
- Succeeds after the user holds for `minimumDuration`. Fails if finger moves
61
- beyond `maximumDistance`.
48
+ The press succeeds once the finger has stayed down for `minimumDuration`
49
+ (0.5 seconds unless you say otherwise). It fails if the finger travels further
50
+ than `maximumDistance` first.
62
51
 
63
52
  ```swift
64
- // Basic long press (0.5s default)
65
- LongPressGesture()
66
- .onEnded { _ in showMenu = true }
67
-
68
- // Custom duration and distance tolerance
69
- LongPressGesture(minimumDuration: 1.0, maximumDistance: 10)
70
- .onEnded { _ in triggerHaptic() }
53
+ struct HoldToConfirm: View {
54
+ @GestureState private var holding = false
55
+ @State private var confirmed = false
56
+
57
+ var body: some View {
58
+ Circle()
59
+ .fill(confirmed ? .green : (holding ? .orange : .gray))
60
+ .frame(width: 88, height: 88)
61
+ .scaleEffect(holding ? 1.15 : 1)
62
+ .animation(.easeOut(duration: 0.2), value: holding)
63
+ .gesture(
64
+ LongPressGesture(minimumDuration: 1.2, maximumDistance: 12)
65
+ .updating($holding) { pressed, state, _ in state = pressed }
66
+ .onEnded { _ in confirmed = true }
67
+ )
68
+ }
69
+ }
71
70
  ```
72
71
 
73
- With visual feedback via `@GestureState` + `.updating()`:
72
+ The shorthand takes a pressing callback for the same feedback:
74
73
 
75
74
  ```swift
76
- @GestureState private var isPressing = false
77
-
78
- Circle()
79
- .fill(isPressing ? .red : .blue)
80
- .scaleEffect(isPressing ? 1.2 : 1.0)
81
- .gesture(
82
- LongPressGesture(minimumDuration: 0.8)
83
- .updating($isPressing) { current, state, _ in state = current }
84
- .onEnded { _ in completedLongPress = true }
85
- )
75
+ .onLongPressGesture(minimumDuration: 1.2) {
76
+ confirmed = true
77
+ } onPressingChanged: { pressed in
78
+ highlight = pressed
79
+ }
86
80
  ```
87
81
 
88
- Shorthand: `.onLongPressGesture(minimumDuration:perform:onPressingChanged:)`.
89
-
90
82
  ## DragGesture
91
83
 
92
- Tracks finger movement. `Value` provides `startLocation`, `location`,
93
- `translation`, `velocity`, and `predictedEndTranslation`.
84
+ `DragGesture.Value` carries `startLocation`, `location`, `translation`,
85
+ `velocity` and `predictedEndTranslation`.
94
86
 
95
87
  ```swift
96
- @State private var offset = CGSize.zero
97
-
98
- RoundedRectangle(cornerRadius: 16)
99
- .fill(.blue)
100
- .frame(width: 100, height: 100)
101
- .offset(offset)
102
- .gesture(
103
- DragGesture()
104
- .onChanged { value in offset = value.translation }
105
- .onEnded { _ in withAnimation(.spring) { offset = .zero } }
106
- )
88
+ struct SnapBackTile: View {
89
+ @State private var shift = CGSize.zero
90
+
91
+ var body: some View {
92
+ RoundedRectangle(cornerRadius: 20)
93
+ .fill(.indigo)
94
+ .frame(width: 140, height: 140)
95
+ .offset(shift)
96
+ .gesture(
97
+ DragGesture()
98
+ .onChanged { drag in shift = drag.translation }
99
+ .onEnded { _ in withAnimation(.spring) { shift = .zero } }
100
+ )
101
+ }
102
+ }
107
103
  ```
108
104
 
109
- Configure minimum distance and coordinate space:
110
-
111
- ```swift
112
- DragGesture(minimumDistance: 20, coordinateSpace: .global)
113
- ```
105
+ `DragGesture(minimumDistance: 20, coordinateSpace: .global)` waits for 20
106
+ points of travel and reports locations in window coordinates.
114
107
 
115
108
  ## MagnifyGesture (iOS 17+)
116
109
 
117
- Replaces the deprecated `MagnificationGesture`. Tracks pinch-to-zoom scale.
110
+ `MagnifyGesture` supersedes `MagnificationGesture`. Its value exposes
111
+ `magnification`.
112
+
113
+ Transient zoom that springs back when the fingers lift:
118
114
 
119
115
  ```swift
120
- @GestureState private var magnifyBy = 1.0
116
+ @GestureState private var pinch: CGFloat = 1
121
117
 
122
- Image("photo")
123
- .resizable().scaledToFit()
124
- .scaleEffect(magnifyBy)
118
+ photo
119
+ .scaleEffect(pinch)
125
120
  .gesture(
126
- MagnifyGesture()
127
- .updating($magnifyBy) { value, state, _ in
128
- state = value.magnification
129
- }
121
+ MagnifyGesture().updating($pinch) { current, live, _ in
122
+ live = current.magnification
123
+ }
130
124
  )
131
125
  ```
132
126
 
133
- With persisted scale:
127
+ Zoom that sticks, clamped when the gesture ends:
134
128
 
135
129
  ```swift
136
- @State private var currentScale = 1.0
137
- @GestureState private var gestureScale = 1.0
130
+ @State private var zoom: CGFloat = 1
131
+ @GestureState private var livePinch: CGFloat = 1
138
132
 
139
- Image("photo")
140
- .scaleEffect(currentScale * gestureScale)
133
+ photo
134
+ .scaleEffect(zoom * livePinch)
141
135
  .gesture(
142
136
  MagnifyGesture(minimumScaleDelta: 0.01)
143
- .updating($gestureScale) { value, state, _ in state = value.magnification }
144
- .onEnded { value in
145
- currentScale = min(max(currentScale * value.magnification, 0.5), 5.0)
137
+ .updating($livePinch) { current, live, _ in live = current.magnification }
138
+ .onEnded { final in
139
+ zoom = min(max(zoom * final.magnification, 0.5), 5.0)
146
140
  }
147
141
  )
148
142
  ```
149
143
 
150
144
  ## RotateGesture (iOS 17+)
151
145
 
152
- `RotateGesture` is the newer alternative to `RotationGesture`. Tracks two-finger rotation angle.
146
+ `RotateGesture` supersedes `RotationGesture`. Its `rotation` is an `Angle`.
153
147
 
154
148
  ```swift
155
- @State private var angle = Angle.zero
149
+ @State private var turned = Angle.zero
150
+ @GestureState private var liveTurn = Angle.zero
156
151
 
157
- Rectangle()
158
- .fill(.blue).frame(width: 200, height: 200)
159
- .rotationEffect(angle)
152
+ dial
153
+ .rotationEffect(turned + liveTurn)
160
154
  .gesture(
161
155
  RotateGesture(minimumAngleDelta: .degrees(1))
162
- .onChanged { value in angle = value.rotation }
156
+ .updating($liveTurn) { current, live, _ in live = current.rotation }
157
+ .onEnded { final in turned += final.rotation }
163
158
  )
164
159
  ```
165
160
 
166
- With persisted rotation:
167
-
168
- ```swift
169
- @State private var currentAngle = Angle.zero
170
- @GestureState private var gestureAngle = Angle.zero
171
-
172
- Rectangle()
173
- .rotationEffect(currentAngle + gestureAngle)
174
- .gesture(
175
- RotateGesture()
176
- .updating($gestureAngle) { value, state, _ in state = value.rotation }
177
- .onEnded { value in currentAngle += value.rotation }
178
- )
179
- ```
161
+ ## Gesture composition
180
162
 
181
- ## Gesture Composition
163
+ ### simultaneously(with:)
182
164
 
183
- ### `.simultaneously(with:)` - both gestures recognized at the same time
165
+ Both gestures recognize together. The value is `SimultaneousGesture.Value`,
166
+ with optional `first` and `second`.
184
167
 
185
168
  ```swift
186
- let magnify = MagnifyGesture()
187
- .onChanged { value in scale = value.magnification }
188
-
189
- let rotate = RotateGesture()
190
- .onChanged { value in angle = value.rotation }
191
-
192
- Image("photo")
193
- .scaleEffect(scale)
194
- .rotationEffect(angle)
195
- .gesture(magnify.simultaneously(with: rotate))
169
+ let pinchAndTwist = MagnifyGesture()
170
+ .simultaneously(with: RotateGesture())
171
+ .onChanged { both in
172
+ liveScale = both.first?.magnification ?? 1
173
+ liveAngle = both.second?.rotation ?? .zero
174
+ }
196
175
  ```
197
176
 
198
- The value is `SimultaneousGesture.Value` with `.first` and `.second` optionals.
177
+ ### sequenced(before:)
199
178
 
200
- ### `.sequenced(before:)` - first must succeed before second begins
179
+ The second gesture can start only after the first one succeeds.
201
180
 
202
181
  ```swift
203
- let longPressBeforeDrag = LongPressGesture(minimumDuration: 0.5)
182
+ let holdThenMove = LongPressGesture(minimumDuration: 0.4)
204
183
  .sequenced(before: DragGesture())
205
- .onEnded { value in
206
- guard case .second(true, let drag?) = value else { return }
207
- finalOffset.width += drag.translation.width
208
- finalOffset.height += drag.translation.height
184
+ .onEnded { outcome in
185
+ if case .second(true, let drag?) = outcome {
186
+ anchor.x += drag.translation.width
187
+ anchor.y += drag.translation.height
188
+ }
209
189
  }
210
190
  ```
211
191
 
212
- ### `.exclusively(before:)` - only one succeeds (first has priority)
192
+ ### exclusively(before:)
193
+
194
+ Only one gesture wins, and the first one listed gets priority. Map both to a
195
+ shared type to keep the handler simple:
213
196
 
214
197
  ```swift
215
- let doubleTapOrLongPress = TapGesture(count: 2)
216
- .map { ExclusiveResult.doubleTap }
217
- .exclusively(before:
218
- LongPressGesture()
219
- .map { _ in ExclusiveResult.longPress }
220
- )
198
+ enum CardAction { case open, archive }
199
+
200
+ let openOrArchive = TapGesture(count: 2).map { CardAction.archive }
201
+ .exclusively(before: TapGesture().map { CardAction.open })
221
202
  .onEnded { result in
222
203
  switch result {
223
- case .first(let val): handleDoubleTap()
224
- case .second(let val): handleLongPress()
204
+ case .first(let action), .second(let action):
205
+ handle(action)
225
206
  }
226
207
  }
227
208
  ```
228
209
 
229
- ## `@GestureState`
210
+ ## @GestureState
230
211
 
231
- `@GestureState` is a property wrapper that **automatically resets** to its
232
- initial value when the gesture ends. Use for transient feedback; use `@State`
233
- for values that persist.
212
+ `@GestureState` returns to its initial value on its own when the gesture ends
213
+ or is cancelled. Use it for feedback that only exists while a finger is down.
214
+ Keep anything that must survive the gesture in `@State`.
234
215
 
235
216
  ```swift
236
- @GestureState private var dragOffset = CGSize.zero // resets to .zero
237
- @State private var position = CGSize.zero // persists
238
-
239
- Circle()
240
- .offset(
241
- x: position.width + dragOffset.width,
242
- y: position.height + dragOffset.height
243
- )
244
- .gesture(
245
- DragGesture()
246
- .updating($dragOffset) { value, state, _ in
247
- state = value.translation
248
- }
249
- .onEnded { value in
250
- position.width += value.translation.width
251
- position.height += value.translation.height
252
- }
253
- )
217
+ struct DraggableSticker: View {
218
+ @State private var resting = CGPoint(x: 160, y: 300)
219
+ @GestureState private var inFlight = CGSize.zero
220
+
221
+ var body: some View {
222
+ Text("Sticker")
223
+ .padding()
224
+ .background(.yellow, in: .capsule)
225
+ .position(x: resting.x + inFlight.width, y: resting.y + inFlight.height)
226
+ .gesture(
227
+ DragGesture()
228
+ .updating($inFlight) { drag, state, _ in state = drag.translation }
229
+ .onEnded { drag in
230
+ resting.x += drag.translation.width
231
+ resting.y += drag.translation.height
232
+ }
233
+ )
234
+ }
235
+ }
254
236
  ```
255
237
 
256
- Custom reset with animation: `@GestureState(resetTransaction: Transaction(animation: .spring))`
238
+ To animate the reset, give the state a reset transaction:
257
239
 
258
- ## Adding Gestures to Views
240
+ ```swift
241
+ @GestureState(resetTransaction: Transaction(animation: .spring)) private var inFlight = CGSize.zero
242
+ ```
259
243
 
260
- Three modifiers control gesture priority in the view hierarchy:
244
+ ## Adding gestures to views
261
245
 
262
- | Modifier | Behavior |
263
- |---|---|
264
- | `.gesture()` | Default priority. Child gestures win over parent. |
265
- | `.highPriorityGesture()` | Parent gesture takes precedence over child. |
266
- | `.simultaneousGesture()` | Both parent and child gestures fire. |
246
+ | Modifier | Who wins when parent and child both recognize |
247
+ | --- | --- |
248
+ | `.gesture(_:)` | The child. Gestures on subviews take precedence. |
249
+ | `.highPriorityGesture(_:)` | The parent's gesture, ahead of the child's. |
250
+ | `.simultaneousGesture(_:)` | Both fire. |
267
251
 
268
- ```swift
269
- // Problem: parent tap swallows child tap
270
- VStack {
271
- Button("Child") { handleChild() } // never fires
272
- }
273
- .gesture(TapGesture().onEnded { handleParent() })
252
+ A typical conflict: a card attaches `.gesture(TapGesture()...)` to open a
253
+ detail screen, and a `Button` inside the card toggles a bookmark. With plain
254
+ `.gesture`, the button keeps priority, so a tap on it never reaches the card's
255
+ handler. Choose deliberately:
274
256
 
275
- // Fix 1: Use simultaneousGesture on parent
276
- VStack {
277
- Button("Child") { handleChild() }
278
- }
279
- .simultaneousGesture(TapGesture().onEnded { handleParent() })
257
+ ```swift
258
+ // The card should also react when the button is tapped (for example, to log the interaction):
259
+ card.simultaneousGesture(TapGesture().onEnded { logCardTap() })
280
260
 
281
- // Fix 2: Give parent explicit priority
282
- VStack {
283
- Text("Child")
284
- .gesture(TapGesture().onEnded { handleChild() })
285
- }
286
- .highPriorityGesture(TapGesture().onEnded { handleParent() })
261
+ // The card must take the tap even over its children (the button stops responding):
262
+ card.highPriorityGesture(TapGesture().onEnded { openDetail() })
287
263
  ```
288
264
 
289
265
  ### GestureMask
290
266
 
291
- Control which gestures participate when using `.gesture(_:including:)`:
267
+ `.gesture(_:including:)` narrows which gestures stay active at this level of
268
+ the hierarchy:
269
+
270
+ | Mask | Effect |
271
+ | --- | --- |
272
+ | `.all` | This gesture and subview gestures (the default) |
273
+ | `.gesture` | Only this gesture; subview gestures are disabled |
274
+ | `.subviews` | Only subview gestures; this gesture is disabled |
275
+ | `.none` | Neither |
292
276
 
293
277
  ```swift
294
- .gesture(drag, including: .gesture) // only this gesture, not subviews
295
- .gesture(drag, including: .subviews) // only subview gestures
296
- .gesture(drag, including: .all) // default: this + subviews
278
+ canvas.gesture(panGesture, including: isEditing ? .subviews : .all)
297
279
  ```
298
280
 
299
- ## Custom Gesture Protocol
281
+ ## Custom Gesture protocol
300
282
 
301
- Create reusable gestures by conforming to `Gesture`:
283
+ Wrap a configured gesture in its own type by conforming to `Gesture` and
284
+ returning the pieces from `var body: some Gesture`.
302
285
 
303
286
  ```swift
304
- struct SwipeGesture: Gesture {
305
- enum Direction { case left, right, up, down }
306
- let minimumDistance: CGFloat
307
- let onSwipe: (Direction) -> Void
308
-
309
- init(minimumDistance: CGFloat = 50, onSwipe: @escaping (Direction) -> Void) {
310
- self.minimumDistance = minimumDistance
311
- self.onSwipe = onSwipe
312
- }
287
+ enum FlingDirection { case left, right, up, down }
288
+
289
+ struct FlingGesture: Gesture {
290
+ var threshold: CGFloat = 50
291
+ var onFling: (FlingDirection) -> Void
313
292
 
314
293
  var body: some Gesture {
315
- DragGesture(minimumDistance: minimumDistance)
316
- .onEnded { value in
317
- let h = value.translation.width, v = value.translation.height
318
- if abs(h) > abs(v) {
319
- onSwipe(h > 0 ? .right : .left)
294
+ DragGesture(minimumDistance: threshold)
295
+ .onEnded { drag in
296
+ let dx = drag.translation.width
297
+ let dy = drag.translation.height
298
+ if abs(dx) >= abs(dy) {
299
+ onFling(dx > 0 ? .right : .left)
320
300
  } else {
321
- onSwipe(v > 0 ? .down : .up)
301
+ onFling(dy > 0 ? .down : .up)
322
302
  }
323
303
  }
324
304
  }
325
305
  }
326
306
 
327
- // Usage
328
- Rectangle().gesture(SwipeGesture { print("Swiped \($0)") })
329
- ```
330
-
331
- Wrap in a `View` extension for ergonomic API:
332
-
333
- ```swift
334
307
  extension View {
335
- func onSwipe(perform action: @escaping (SwipeGesture.Direction) -> Void) -> some View {
336
- gesture(SwipeGesture(onSwipe: action))
308
+ func onFling(threshold: CGFloat = 50, perform action: @escaping (FlingDirection) -> Void) -> some View {
309
+ gesture(FlingGesture(threshold: threshold, onFling: action))
337
310
  }
338
311
  }
339
312
  ```
340
313
 
341
- ## Common Mistakes
342
-
343
- ### 1. Conflicting parent/child gestures
344
-
345
- ```swift
346
- // DON'T: Parent .gesture() conflicts with child tap
347
- VStack {
348
- Button("Action") { doSomething() }
349
- }
350
- .gesture(TapGesture().onEnded { parentAction() })
351
-
352
- // DO: Use .simultaneousGesture() or .highPriorityGesture()
353
- VStack {
354
- Button("Action") { doSomething() }
355
- }
356
- .simultaneousGesture(TapGesture().onEnded { parentAction() })
357
- ```
358
-
359
- ### 2. Using `@State` instead of `@GestureState` for transient state
360
-
361
- ```swift
362
- // DON'T: @State doesn't auto-reset - view stays offset after gesture ends
363
- @State private var dragOffset = CGSize.zero
364
-
365
- DragGesture()
366
- .onChanged { value in dragOffset = value.translation }
367
- .onEnded { _ in dragOffset = .zero } // manual reset required
368
-
369
- // DO: @GestureState auto-resets when gesture ends
370
- @GestureState private var dragOffset = CGSize.zero
371
-
372
- DragGesture()
373
- .updating($dragOffset) { value, state, _ in
374
- state = value.translation
375
- }
376
- ```
377
-
378
- ### 3. Not using .updating() for intermediate feedback
379
-
380
- ```swift
381
- // DON'T: No visual feedback during long press
382
- LongPressGesture(minimumDuration: 2.0)
383
- .onEnded { _ in showResult = true }
384
-
385
- // DO: Provide feedback while pressing
386
- @GestureState private var isPressing = false
387
-
388
- LongPressGesture(minimumDuration: 2.0)
389
- .updating($isPressing) { current, state, _ in
390
- state = current
391
- }
392
- .onEnded { _ in showResult = true }
393
- ```
394
-
395
- ### 4. Using deprecated gesture types on iOS 17+
396
-
397
- ```swift
398
- // DON'T: Deprecated since iOS 17
399
- MagnificationGesture() // deprecated - use MagnifyGesture()
400
-
401
- // DO: Use newer gesture types
402
- MagnifyGesture() // iOS 17+
403
- RotateGesture() // iOS 17+ (newer alternative to RotationGesture)
404
- ```
405
-
406
- ### 5. Heavy computation in onChanged
407
-
408
- ```swift
409
- // DON'T: Expensive work called every frame (~60-120 Hz)
410
- DragGesture()
411
- .onChanged { value in
412
- let result = performExpensiveHitTest(at: value.location)
413
- let filtered = applyComplexFilter(result)
414
- updateModel(filtered)
415
- }
416
-
417
- // DO: Throttle or defer expensive work
418
- DragGesture()
419
- .onChanged { value in
420
- dragPosition = value.location // lightweight state update only
421
- }
422
- .onEnded { value in
423
- performExpensiveHitTest(at: value.location) // once at end
424
- }
425
- ```
426
-
427
- ### 6. Using onTapGesture for actions that should be a Button
428
-
429
- ```swift
430
- // DON'T: onTapGesture has no accessibility traits, VoiceOver role,
431
- // Voice Control targeting, Switch Control scanning, or keyboard activation
432
- Text("Delete")
433
- .onTapGesture { deleteItem() }
434
-
435
- // DO: Button provides all of these automatically
436
- Button("Delete", role: .destructive) { deleteItem() }
437
-
438
- // DO: For custom visuals, use ButtonStyle instead of onTapGesture
439
- Button { toggleExpanded() } label: {
440
- CardView()
441
- }
442
- .buttonStyle(.plain)
443
- ```
444
-
445
- Reserve `onTapGesture` for multi-tap (`count: 2+`), tap-location-dependent
446
- behavior, or adding tap recognition to non-interactive content that already
447
- has appropriate accessibility traits.
448
-
449
- ## Review Checklist
450
-
451
- - [ ] Correct gesture type: `MagnifyGesture`/`RotateGesture` (not deprecated `Magnification`/`Rotation` variants)
452
- - [ ] `@GestureState` used for transient values that should reset; `@State` for persisted values
453
- - [ ] `.updating()` provides intermediate visual feedback during continuous gestures
454
- - [ ] Parent/child conflicts resolved with `.highPriorityGesture()` or `.simultaneousGesture()`
455
- - [ ] `onChanged` closures are lightweight - no heavy computation every frame
456
- - [ ] Composed gestures use correct combinator: `simultaneously`, `sequenced`, or `exclusively`
457
- - [ ] Persisted scale/rotation clamped to reasonable bounds in `onEnded`
458
- - [ ] Custom `Gesture` conformances use `var body: some Gesture` (not `View`)
459
- - [ ] Gesture-driven animations use `.spring` or similar for natural deceleration
460
- - [ ] `GestureMask` considered when mixing gestures across view hierarchy levels
461
- - [ ] `onTapGesture` only used where `count > 1`, tap location, or coordinate space matters - plain single-tap actions use `Button` instead
314
+ ## Common mistakes
315
+
316
+ 1. **Parent and child gestures fighting.** A parent's `.gesture` loses to its
317
+ children. Decide which should win and use `.simultaneousGesture` or
318
+ `.highPriorityGesture` accordingly.
319
+ 2. **`@State` for a drag offset that should not persist.** It needs a manual
320
+ reset, and a cancelled gesture can leave the view displaced. Use
321
+ `@GestureState` with `.updating`.
322
+ 3. **Long presses with no feedback while held.** Add `.updating` (or
323
+ `onPressingChanged`) so the user sees the press registering.
324
+ 4. **New code on `MagnificationGesture` or `RotationGesture`.** Both are renamed
325
+ to `MagnifyGesture` and `RotateGesture` and marked for deprecation. The
326
+ iOS 26 SDK does not warn yet, but new code on iOS 17 or later should use the
327
+ replacements.
328
+ 5. **Heavy work in `onChanged`.** It runs on every touch update, often 60 to
329
+ 120 times a second. Keep it to assignments; move expensive work to
330
+ `onEnded` or throttle it.
331
+ 6. **`onTapGesture` as a button.** It adds no button trait, no VoiceOver
332
+ action, no Voice Control or Switch Control target and no keyboard
333
+ activation. Use `Button` (with a role such as `.destructive` where it
334
+ applies), and `.buttonStyle(.plain)` when the visuals are custom.
335
+ 7. **When `onTapGesture` is right.** Multi-tap counts, handlers that need the
336
+ tap location, or non-interactive content that you have given proper
337
+ accessibility traits.
338
+
339
+ ## Review checklist
340
+
341
+ - [ ] `MagnifyGesture` and `RotateGesture`, not the older names
342
+ - [ ] `@GestureState` for transient values, `@State` for persisted ones
343
+ - [ ] Continuous gestures give live feedback through `.updating`
344
+ - [ ] Parent and child conflicts resolved with the right priority modifier
345
+ - [ ] `onChanged` handlers stay light
346
+ - [ ] Combinator matches intent: simultaneous, sequenced or exclusive
347
+ - [ ] Persisted scale and rotation clamped in `onEnded`
348
+ - [ ] Custom gestures expose `var body: some Gesture`
349
+ - [ ] Gesture-driven motion settles with `.spring` or a similar animation
350
+ - [ ] `GestureMask` considered where several hierarchy levels attach gestures
351
+ - [ ] `onTapGesture` used only for counts above one, tap location or coordinate space needs
462
352
 
463
353
  ## References
464
354
 
465
- - See [references/gesture-patterns.md](references/gesture-patterns.md) for drag-to-reorder, pinch-to-zoom, combined rotate+scale, velocity calculations, and SwiftUI/UIKit gesture interop.
466
- - [Gesture protocol](https://sosumi.ai/documentation/swiftui/gesture)
467
- - [TapGesture](https://sosumi.ai/documentation/swiftui/tapgesture)
468
- - [LongPressGesture](https://sosumi.ai/documentation/swiftui/longpressgesture)
469
- - [DragGesture](https://sosumi.ai/documentation/swiftui/draggesture)
470
- - [MagnifyGesture](https://sosumi.ai/documentation/swiftui/magnifygesture)
471
- - [RotateGesture](https://sosumi.ai/documentation/swiftui/rotategesture)
472
- - [GestureState](https://sosumi.ai/documentation/swiftui/gesturestate)
473
- - [Composing SwiftUI gestures](https://sosumi.ai/documentation/swiftui/composing-swiftui-gestures)
474
- - [Adding interactivity with gestures](https://sosumi.ai/documentation/swiftui/adding-interactivity-with-gestures)
355
+ - [references/gesture-patterns.md](references/gesture-patterns.md)
356
+ - [Gesture](https://developer.apple.com/documentation/swiftui/gesture)
357
+ - [TapGesture](https://developer.apple.com/documentation/swiftui/tapgesture)
358
+ - [LongPressGesture](https://developer.apple.com/documentation/swiftui/longpressgesture)
359
+ - [DragGesture](https://developer.apple.com/documentation/swiftui/draggesture)
360
+ - [MagnifyGesture](https://developer.apple.com/documentation/swiftui/magnifygesture)
361
+ - [RotateGesture](https://developer.apple.com/documentation/swiftui/rotategesture)
362
+ - [GestureState](https://developer.apple.com/documentation/swiftui/gesturestate)
363
+ - [Composing SwiftUI gestures](https://developer.apple.com/documentation/swiftui/composing-swiftui-gestures)
364
+ - [Adding interactivity with gestures](https://developer.apple.com/documentation/swiftui/adding-interactivity-with-gestures)