@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,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)