@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1

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 (284) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +285 -285
  5. package/package.json +3 -3
  6. package/pipeline/lib/redact.mjs +3 -2
  7. package/pipeline/scripts/_notices.mjs +1 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +13 -1
  9. package/pipeline/scripts/pre-commit-check.sh +4 -0
  10. package/pipeline/skills/.skill-manifest.json +69 -69
  11. package/pipeline/skills/shared/README.md +70 -70
  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/app-clips/SKILL.md +260 -160
  16. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  17. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  18. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  19. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  20. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  21. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  22. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  23. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
  24. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  25. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
  26. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
  27. package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
  28. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  29. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  30. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  31. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
  32. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  34. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  35. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  37. package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
  38. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  39. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
  40. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  41. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  42. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  43. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  44. package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
  45. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  46. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
  47. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  48. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  49. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  50. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  51. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  52. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  53. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  54. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  55. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  56. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
  57. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  58. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  59. package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
  60. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  61. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  62. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  63. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  64. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  65. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  66. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  67. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  68. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  69. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  70. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  71. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  72. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  73. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  74. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  75. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  76. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  77. package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
  78. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  79. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  80. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  81. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  82. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  83. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  84. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  85. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  86. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  87. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  88. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  89. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  90. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  91. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  92. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  93. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  94. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  95. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  96. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  97. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  98. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  99. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  100. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  101. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  102. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  103. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  104. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  105. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  106. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  107. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  108. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  109. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  111. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  112. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  113. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  114. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
  115. package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
  116. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
  117. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
  118. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
  119. package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
  120. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
  121. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
  122. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
  123. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
  124. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
  125. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
  126. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
  127. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
  128. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
  129. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
  130. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
  131. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  132. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  133. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  134. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  135. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  136. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  137. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  138. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  139. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  140. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  141. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  142. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  143. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  144. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  145. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  146. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  147. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  148. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  149. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  150. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  151. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  152. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  153. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  154. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  155. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  156. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  157. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  158. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  159. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  160. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  161. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  162. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  163. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  164. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  165. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  166. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  167. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  168. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  169. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  170. package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
  171. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  172. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  173. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  174. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  175. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  176. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  177. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
  178. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  179. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  180. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  181. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  182. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  183. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  184. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  185. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  186. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  187. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  188. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  189. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  190. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  191. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  192. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
  193. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  194. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  195. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  196. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  197. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  198. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  199. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  200. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  201. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  202. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  203. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  204. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  205. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  206. package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
  207. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  208. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  209. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
  210. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  211. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  212. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  213. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  214. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  215. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  216. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
  217. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  218. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  219. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  220. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
  221. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  222. package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
  223. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  224. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
  225. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  226. package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
  227. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  228. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  229. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  230. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  231. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  232. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  233. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  234. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  235. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  236. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  237. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  238. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  239. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  240. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  241. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  242. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  243. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  244. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  245. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  246. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  247. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  248. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  249. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  250. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  251. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
  252. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  253. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
  254. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  255. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
  256. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  257. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  258. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  259. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  260. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  261. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  262. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  263. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  264. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  265. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  266. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  267. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  268. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  269. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  270. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  271. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  272. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  273. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  274. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  275. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  276. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  277. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  278. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  279. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  280. package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
  281. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  282. package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
  283. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
  284. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,500 +1,468 @@
1
1
  ---
2
2
  name: pdfkit
3
- description: "Display and manipulate PDF documents using PDFKit. Use when embedding PDFView to show PDF files, creating or modifying PDFDocument instances, adding annotations (highlights, notes, signature widgets), extracting text with PDFSelection, navigating pages, generating thumbnails, filling PDF forms, or wrapping PDFView in SwiftUI."
3
+ description: "PDFKit on iOS: PDFView display and SwiftUI wrapping, creating and editing PDFDocument and PDFPage, highlight, note, signature and form annotations, PDFSelection search and text extraction, page navigation, thumbnails, form filling, encrypted saving. Use when an app displays, searches, annotates, fills, builds or saves PDFs."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
- # PDFKit
8
7
 
9
- Display, navigate, search, annotate, and manipulate PDF documents with `PDFView`, `PDFDocument`, `PDFPage`, `PDFAnnotation`, and `PDFSelection`. Targets Swift 6.3 / iOS 26+.
8
+ # PDFKit
10
9
 
11
- ## Contents
10
+ PDFKit renders, searches and edits PDF files. Most work touches five types:
11
+ `PDFView` (the on-screen viewer), `PDFDocument` (the file), `PDFPage` (one
12
+ page), `PDFAnnotation` (marks and form fields on a page) and `PDFSelection`
13
+ (a run of text). Examples target Swift 6.3 and iOS 26.
12
14
 
13
- - [Setup](#setup)
14
- - [Displaying PDFs](#displaying-pdfs)
15
- - [Loading Documents](#loading-documents)
16
- - [Page Navigation](#page-navigation)
17
- - [Text Search and Selection](#text-search-and-selection)
18
- - [Annotations](#annotations)
19
- - [Thumbnails](#thumbnails)
20
- - [SwiftUI Integration](#swiftui-integration)
21
- - [Common Mistakes](#common-mistakes)
22
- - [Review Checklist](#review-checklist)
23
- - [References](#references)
15
+ Freehand drawing tools are not PDFKit work: use PencilKit or PaperKit.
24
16
 
25
17
  ## Setup
26
18
 
27
- PDFKit requires no entitlements or Info.plist entries.
19
+ No entitlement and no Info.plist key is needed.
28
20
 
29
21
  ```swift
30
22
  import PDFKit
31
23
  ```
32
24
 
33
- **Platform availability:** iOS 11+, iPadOS 11+, Mac Catalyst 13.1+, macOS 10.4+, tvOS 11+, visionOS 1.0+.
25
+ | Platform | Minimum |
26
+ |---|---|
27
+ | iOS, iPadOS | 11 |
28
+ | Mac Catalyst | 13.1 |
29
+ | macOS | 10.4 |
30
+ | tvOS | 11 |
31
+ | visionOS | 1.0 |
34
32
 
35
- ## Displaying PDFs
33
+ ## Showing a PDF
36
34
 
37
- `PDFView` is a `UIView` subclass that renders PDF content, handles zoom,
38
- scroll, text selection, and page navigation out of the box.
35
+ `PDFView` is a `UIView` subclass. Out of the box it zooms, scrolls, selects text
36
+ and pages through the document.
39
37
 
40
38
  ```swift
41
39
  import PDFKit
42
40
  import UIKit
43
41
 
44
- class PDFViewController: UIViewController {
45
- let pdfView = PDFView()
42
+ final class ManualViewController: UIViewController {
43
+ private let reader = PDFView()
46
44
 
47
45
  override func viewDidLoad() {
48
46
  super.viewDidLoad()
49
- pdfView.frame = view.bounds
50
- pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
51
- view.addSubview(pdfView)
52
-
53
- pdfView.autoScales = true
54
- pdfView.displayMode = .singlePageContinuous
55
- pdfView.displayDirection = .vertical
56
-
57
- if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf") {
58
- pdfView.document = PDFDocument(url: url)
47
+ reader.frame = view.bounds
48
+ reader.autoresizingMask = [.flexibleWidth, .flexibleHeight]
49
+ reader.autoScales = true
50
+ reader.displayMode = .singlePageContinuous
51
+ reader.displayDirection = .vertical
52
+ view.addSubview(reader)
53
+
54
+ if let url = Bundle.main.url(forResource: "assembly-guide", withExtension: "pdf"),
55
+ let file = PDFDocument(url: url) {
56
+ reader.document = file
59
57
  }
60
58
  }
61
59
  }
62
60
  ```
63
61
 
64
- ### Display Modes
62
+ ### Display modes
65
63
 
66
- | Mode | Behavior |
64
+ | Mode | Layout |
67
65
  |---|---|
68
- | `.singlePage` | One page at a time |
69
- | `.singlePageContinuous` | Pages stacked vertically, scrollable |
70
- | `.twoUp` | Two pages side by side |
71
- | `.twoUpContinuous` | Two-up with continuous scrolling |
66
+ | `.singlePage` | one page on screen at a time |
67
+ | `.singlePageContinuous` | one column of pages, scrolling |
68
+ | `.twoUp` | facing pages side by side |
69
+ | `.twoUpContinuous` | facing pages, scrolling |
72
70
 
73
- ### Scaling and Appearance
71
+ ### Scale and look
74
72
 
75
73
  ```swift
76
- pdfView.autoScales = true
77
- pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
78
- pdfView.maxScaleFactor = 4.0
74
+ import PDFKit
79
75
 
80
- pdfView.displaysPageBreaks = true
81
- pdfView.pageShadowsEnabled = true
82
- pdfView.interpolationQuality = .high
76
+ @MainActor
77
+ func tune(_ reader: PDFView) {
78
+ reader.autoScales = true
79
+ reader.minScaleFactor = reader.scaleFactorForSizeToFit
80
+ reader.maxScaleFactor = 5.0
81
+ reader.displaysPageBreaks = true
82
+ reader.pageShadowsEnabled = false
83
+ reader.interpolationQuality = .high
84
+ }
83
85
  ```
84
86
 
85
- ## Loading Documents
87
+ ## Loading documents
86
88
 
87
- `PDFDocument` loads from a URL, `Data`, or can be created empty.
89
+ There are three initializers: `PDFDocument(url:)`, `PDFDocument(data:)` and
90
+ the empty `PDFDocument()`. The first two are failable.
88
91
 
89
- ```swift
90
- let fileDoc = PDFDocument(url: fileURL)
91
- let dataDoc = PDFDocument(data: pdfData)
92
- let emptyDoc = PDFDocument()
93
- ```
94
-
95
- ### Password-Protected PDFs
92
+ ### Locked files
96
93
 
97
94
  ```swift
98
- guard let document = PDFDocument(url: url) else { return }
99
- if document.isLocked {
100
- if !document.unlock(withPassword: userPassword) {
101
- // Show password prompt
102
- }
95
+ import PDFKit
96
+
97
+ func open(_ file: PDFDocument, passcode: String) -> Bool {
98
+ guard file.isLocked else { return true }
99
+ return file.unlock(withPassword: passcode)
103
100
  }
104
101
  ```
105
102
 
106
- ### Saving and Page Manipulation
103
+ If `unlock(withPassword:)` returns `false`, ask the user for the password again.
104
+
105
+ ### Saving and rearranging pages
107
106
 
108
107
  ```swift
109
- document.write(to: outputURL)
110
- document.write(to: outputURL, withOptions: [
111
- .ownerPasswordOption: "ownerPass", .userPasswordOption: "userPass"
112
- ])
113
- let data = document.dataRepresentation()
114
-
115
- // Pages are zero-based. Validate indices; out-of-range calls raise exceptions.
116
- let count = document.pageCount
117
- document.insert(PDFPage(), at: count)
118
- if document.pageCount > 2 {
119
- document.removePage(at: 2)
108
+ import PDFKit
109
+
110
+ func export(_ file: PDFDocument, to url: URL, ownerKey: String, readerKey: String) -> Bool {
111
+ file.write(to: url, withOptions: [
112
+ .ownerPasswordOption: ownerKey,
113
+ .userPasswordOption: readerKey
114
+ ])
120
115
  }
121
- if document.pageCount > 3 {
122
- document.exchangePage(at: 0, withPageAt: 3)
116
+
117
+ func reorder(_ file: PDFDocument) {
118
+ let blank = PDFPage()
119
+ file.insert(blank, at: file.pageCount)
120
+ if file.pageCount > 2 {
121
+ file.exchangePage(at: 0, withPageAt: 2)
122
+ }
123
+ if file.pageCount > 1 {
124
+ file.removePage(at: 1)
125
+ }
123
126
  }
124
127
  ```
125
128
 
126
- ## Page Navigation
127
-
128
- `PDFView` provides built-in navigation with history tracking.
129
-
130
- ```swift
131
- // Go to a specific page
132
- let pageIndex = 5
133
- if let document = pdfView.document,
134
- pageIndex >= 0,
135
- pageIndex < document.pageCount,
136
- let page = document.page(at: pageIndex) {
137
- pdfView.go(to: page)
138
- }
129
+ - `write(to:)` saves as is; `write(to:withOptions:)` with
130
+ `.ownerPasswordOption` and `.userPasswordOption` encrypts.
131
+ - `dataRepresentation()` returns `Data?` for upload or sharing.
132
+ - Page indices start at 0. Inserting at `pageCount` appends.
133
+ - An index outside `0..<pageCount` raises an Objective-C exception rather than
134
+ returning `nil`, so check it before `page(at:)`, `insert(_:at:)`,
135
+ `removePage(at:)` or `exchangePage(at:withPageAt:)`.
139
136
 
140
- // Sequential navigation
141
- pdfView.goToNextPage(nil)
142
- pdfView.goToPreviousPage(nil)
143
- pdfView.goToFirstPage(nil)
144
- pdfView.goToLastPage(nil)
137
+ ## Navigating
145
138
 
146
- // Check navigation state
147
- if pdfView.canGoToNextPage { /* ... */ }
139
+ `PDFView` keeps its own history of where the user has been.
148
140
 
149
- // History navigation
150
- if pdfView.canGoBack { pdfView.goBack(nil) }
141
+ ```swift
142
+ import PDFKit
151
143
 
152
- // Go to a specific point on the current page
153
- if let page = pdfView.currentPage {
154
- let destination = PDFDestination(page: page, at: CGPoint(x: 0, y: 500))
155
- pdfView.go(to: destination)
144
+ @MainActor
145
+ func show(pageNumber index: Int, in reader: PDFView) {
146
+ guard let file = reader.document, index >= 0, index < file.pageCount,
147
+ let target = file.page(at: index) else { return }
148
+ reader.go(to: target)
156
149
  }
157
- ```
158
150
 
159
- ### Observing Page Changes
151
+ @MainActor
152
+ func stepThrough(_ reader: PDFView) {
153
+ if reader.canGoToNextPage { reader.goToNextPage(nil) }
154
+ reader.goToPreviousPage(nil)
155
+ reader.goToFirstPage(nil)
156
+ reader.goToLastPage(nil)
157
+ if reader.canGoBack { reader.goBack(nil) }
158
+ }
160
159
 
161
- ```swift
162
- NotificationCenter.default.addObserver(
163
- self, selector: #selector(pageChanged),
164
- name: .PDFViewPageChanged, object: pdfView
165
- )
166
-
167
- @objc func pageChanged(_ notification: Notification) {
168
- guard let page = pdfView.currentPage,
169
- let doc = pdfView.document else { return }
170
- let index = doc.index(for: page)
171
- pageLabel.text = "Page \(index + 1) of \(doc.pageCount)"
160
+ @MainActor
161
+ func jump(to point: CGPoint, on page: PDFPage, in reader: PDFView) {
162
+ reader.go(to: PDFDestination(page: page, at: point))
163
+ _ = reader.currentPage
172
164
  }
173
165
  ```
174
166
 
175
- ## Text Search and Selection
176
-
177
- ### Synchronous Search
167
+ ### Tracking the current page
178
168
 
179
169
  ```swift
180
- let results: [PDFSelection] = document.findString(
181
- "search term", withOptions: [.caseInsensitive]
182
- )
170
+ import PDFKit
171
+
172
+ @MainActor
173
+ func watchPages(of reader: PDFView, update: @escaping @MainActor @Sendable (String) -> Void) -> NSObjectProtocol {
174
+ NotificationCenter.default.addObserver(forName: .PDFViewPageChanged, object: reader, queue: .main) { _ in
175
+ MainActor.assumeIsolated {
176
+ guard let file = reader.document, let page = reader.currentPage else { return }
177
+ update("\(file.index(for: page) + 1) / \(file.pageCount)")
178
+ }
179
+ }
180
+ }
183
181
  ```
184
182
 
185
- ### Asynchronous Search
183
+ ## Search and text
186
184
 
187
- Use `PDFDocumentDelegate` for background searches on large documents.
188
- Implement `didMatchString(_:)` to receive each match and
189
- `documentDidEndDocumentFind(_:)` for completion.
185
+ ### Synchronous
190
186
 
191
- ### Incremental Search and Find Interaction
187
+ `findString(_:withOptions:)` returns every match as `[PDFSelection]`:
192
188
 
193
189
  ```swift
194
- // Find next match from current selection
195
- let next = document.findString("term", fromSelection: current, withOptions: [.caseInsensitive])
190
+ import PDFKit
196
191
 
197
- // System find bar (iOS 16+)
198
- pdfView.isFindInteractionEnabled = true
192
+ func matches(of term: String, in file: PDFDocument) -> [PDFSelection] {
193
+ file.findString(term, withOptions: [.caseInsensitive])
194
+ }
199
195
  ```
200
196
 
201
- ### Text Extraction
197
+ ### Asynchronous
198
+
199
+ For long documents, search in the background with `beginFindString(_:withOptions:)`
200
+ and a `PDFDocumentDelegate`. `didMatchString(_:)` is called per hit and
201
+ `documentDidEndDocumentFind(_:)` when the pass finishes.
202
202
 
203
203
  ```swift
204
- let fullText = document.string // Entire document
205
- let firstPage = document.pageCount > 0 ? document.page(at: 0) : nil
206
- let pageText = firstPage?.string // Single page
207
- let attributed = firstPage?.attributedString // With formatting
208
-
209
- // Region-based extraction
210
- if let page = firstPage {
211
- let selection = page.selection(for: CGRect(x: 50, y: 50, width: 400, height: 200))
212
- let text = selection?.string
213
- }
214
- ```
204
+ import PDFKit
215
205
 
216
- ### Highlighting Search Results
206
+ final class ContractSearch: NSObject, PDFDocumentDelegate {
207
+ private(set) var hits: [PDFSelection] = []
208
+ var onFinish: (([PDFSelection]) -> Void)?
217
209
 
218
- ```swift
219
- let results = document.findString("important", withOptions: [.caseInsensitive])
220
- for selection in results { selection.color = .yellow }
221
- pdfView.highlightedSelections = results
210
+ func run(_ term: String, in file: PDFDocument) {
211
+ hits.removeAll()
212
+ file.delegate = self
213
+ file.beginFindString(term, withOptions: [.caseInsensitive])
214
+ }
222
215
 
223
- if let first = results.first {
224
- pdfView.setCurrentSelection(first, animate: true)
225
- pdfView.go(to: first)
216
+ func didMatchString(_ instance: PDFSelection) {
217
+ hits.append(instance)
218
+ }
219
+
220
+ func documentDidEndDocumentFind(_ notification: Notification) {
221
+ onFinish?(hits)
222
+ }
226
223
  }
227
224
  ```
228
225
 
229
- ## Annotations
226
+ ### Next match and the system find bar
230
227
 
231
- Annotations are created with `PDFAnnotation(bounds:forType:withProperties:)`
232
- and added to a `PDFPage`.
228
+ - `findString(_:fromSelection:withOptions:)` returns the first hit after a
229
+ given selection, which is how "Find next" works.
230
+ - `reader.isFindInteractionEnabled = true` turns on the system find bar
231
+ (iOS 16+).
233
232
 
234
- ### Highlight Annotation
233
+ ### Extracting text
235
234
 
236
235
  ```swift
237
- func addHighlight(to page: PDFPage, selection: PDFSelection) {
238
- let highlight = PDFAnnotation(
239
- bounds: selection.bounds(for: page),
240
- forType: .highlight, withProperties: nil
241
- )
242
- highlight.color = UIColor.yellow.withAlphaComponent(0.5)
243
- page.addAnnotation(highlight)
236
+ import PDFKit
237
+
238
+ func textSamples(from file: PDFDocument) -> (all: String?, first: String?, box: String?) {
239
+ let all = file.string
240
+ guard file.pageCount > 0, let first = file.page(at: 0) else { return (all, nil, nil) }
241
+ _ = first.attributedString
242
+ let box = first.selection(for: CGRect(x: 36, y: 700, width: 300, height: 60))?.string
243
+ return (all, first.string, box)
244
244
  }
245
245
  ```
246
246
 
247
- ### Text Note Annotation
248
-
249
- ```swift
250
- let note = PDFAnnotation(
251
- bounds: CGRect(x: 100, y: 700, width: 30, height: 30),
252
- forType: .text, withProperties: nil
253
- )
254
- note.contents = "This is a sticky note."
255
- note.color = .systemYellow
256
- note.iconType = .comment
257
- page.addAnnotation(note)
258
- ```
247
+ `document.string` is the whole document, `page.string` one page,
248
+ `page.attributedString` keeps fonts and styles, and `page.selection(for:)`
249
+ limits extraction to a rectangle. Check `pageCount > 0` before asking for
250
+ page 0.
259
251
 
260
- ### Free Text Annotation
252
+ ### Highlighting hits
261
253
 
262
254
  ```swift
263
- let freeText = PDFAnnotation(
264
- bounds: CGRect(x: 50, y: 600, width: 300, height: 40),
265
- forType: .freeText, withProperties: nil
266
- )
267
- freeText.contents = "Added commentary"
268
- freeText.font = UIFont.systemFont(ofSize: 14)
269
- freeText.fontColor = .darkGray
270
- page.addAnnotation(freeText)
255
+ import PDFKit
256
+
257
+ @MainActor
258
+ func mark(_ hits: [PDFSelection], in reader: PDFView) {
259
+ for hit in hits { hit.color = .systemOrange }
260
+ reader.highlightedSelections = hits
261
+ if let firstHit = hits.first {
262
+ reader.setCurrentSelection(firstHit, animate: true)
263
+ reader.go(to: firstHit)
264
+ }
265
+ }
271
266
  ```
272
267
 
273
- ### Link Annotation
268
+ ## Annotations
269
+
270
+ Create an annotation with `PDFAnnotation(bounds:forType:withProperties:)` and
271
+ attach it with `page.addAnnotation(_:)`.
274
272
 
275
273
  ```swift
276
- let link = PDFAnnotation(
277
- bounds: CGRect(x: 50, y: 500, width: 200, height: 20),
278
- forType: .link, withProperties: nil
279
- )
280
- link.url = URL(string: "https://example.com")
281
- page.addAnnotation(link)
282
-
283
- // Internal page link
284
- link.destination = PDFDestination(page: targetPage, at: .zero)
285
- ```
274
+ import PDFKit
275
+ import UIKit
286
276
 
287
- ### Removing Annotations
277
+ func annotate(_ page: PDFPage, hit: PDFSelection, target: PDFPage) {
278
+ let marker = PDFAnnotation(bounds: hit.bounds(for: page), forType: .highlight, withProperties: nil)
279
+ marker.color = UIColor.systemGreen.withAlphaComponent(0.5)
280
+ page.addAnnotation(marker)
281
+
282
+ let note = PDFAnnotation(bounds: CGRect(x: 40, y: 40, width: 24, height: 24), forType: .text, withProperties: nil)
283
+ note.contents = "Check this total"
284
+ note.color = .systemBlue
285
+ note.iconType = .comment
286
+ page.addAnnotation(note)
287
+
288
+ let label = PDFAnnotation(bounds: CGRect(x: 72, y: 120, width: 220, height: 30), forType: .freeText, withProperties: nil)
289
+ label.contents = "Approved"
290
+ label.font = .boldSystemFont(ofSize: 16)
291
+ label.fontColor = .systemRed
292
+ page.addAnnotation(label)
293
+
294
+ let web = PDFAnnotation(bounds: CGRect(x: 72, y: 170, width: 160, height: 20), forType: .link, withProperties: nil)
295
+ web.url = URL(string: "https://example.org/terms")
296
+ page.addAnnotation(web)
297
+
298
+ let internalJump = PDFAnnotation(bounds: CGRect(x: 72, y: 200, width: 160, height: 20), forType: .link, withProperties: nil)
299
+ internalJump.destination = PDFDestination(page: target, at: CGPoint(x: 0, y: 792))
300
+ page.addAnnotation(internalJump)
301
+ }
288
302
 
289
- ```swift
290
- for annotation in page.annotations {
291
- page.removeAnnotation(annotation)
303
+ func stripMarkup(from page: PDFPage) {
304
+ for item in page.annotations {
305
+ page.removeAnnotation(item)
306
+ }
292
307
  }
293
308
  ```
294
309
 
295
- Common subtypes include `.highlight`, `.underline`, `.strikeOut`, `.text`,
296
- `.freeText`, `.ink`, `.link`, `.line`, `.square`, `.circle`, `.stamp`, and
310
+ Commonly used subtypes: `.highlight`, `.underline`, `.strikeOut`, `.text`,
311
+ `.freeText`, `.ink`, `.link`, `.line`, `.square`, `.circle`, `.stamp`,
297
312
  `.widget`.
298
313
 
299
314
  ## Thumbnails
300
315
 
301
316
  ### PDFThumbnailView
302
317
 
303
- `PDFThumbnailView` shows a strip of page thumbnails linked to a `PDFView`.
318
+ `PDFThumbnailView` shows a strip of page previews. Point its `pdfView` at the
319
+ main viewer so taps navigate and the current page is highlighted.
304
320
 
305
321
  ```swift
306
- let thumbnailView = PDFThumbnailView()
307
- thumbnailView.pdfView = pdfView
308
- thumbnailView.thumbnailSize = CGSize(width: 60, height: 80)
309
- thumbnailView.layoutMode = .vertical
310
- thumbnailView.translatesAutoresizingMaskIntoConstraints = false
311
- view.addSubview(thumbnailView)
322
+ import PDFKit
323
+
324
+ @MainActor
325
+ func makeStrip(for reader: PDFView) -> PDFThumbnailView {
326
+ let strip = PDFThumbnailView()
327
+ strip.pdfView = reader
328
+ strip.thumbnailSize = CGSize(width: 48, height: 64)
329
+ strip.layoutMode = .vertical
330
+ return strip
331
+ }
312
332
  ```
313
333
 
314
- ### Generating Thumbnails Programmatically
334
+ ### Generating images
315
335
 
316
336
  ```swift
317
- let thumbnail = page.thumbnail(of: CGSize(width: 120, height: 160), for: .mediaBox)
337
+ import PDFKit
338
+ import UIKit
318
339
 
319
- // All pages
320
- let thumbnails = (0..<document.pageCount).compactMap {
321
- document.page(at: $0)?.thumbnail(of: CGSize(width: 120, height: 160), for: .mediaBox)
340
+ func previews(of file: PDFDocument) -> [UIImage] {
341
+ let size = CGSize(width: 120, height: 160)
342
+ let cover = file.page(at: 0)?.thumbnail(of: size, for: .mediaBox)
343
+ _ = cover
344
+ return (0..<file.pageCount).compactMap { file.page(at: $0)?.thumbnail(of: size, for: .mediaBox) }
322
345
  }
323
346
  ```
324
347
 
325
- ## SwiftUI Integration
348
+ ## SwiftUI
326
349
 
327
- Wrap `PDFView` in a `UIViewRepresentable` for SwiftUI. PDF-specific wrappers
328
- that configure `PDFView`, pages, annotations, search, thumbnails, or overlays
329
- belong in this skill; route only generic representable lifecycle, layout, or SwiftUI state architecture questions to SwiftUI/UIKit interop guidance.
350
+ Wrap `PDFView` in a `UIViewRepresentable`. Wrappers that configure the viewer,
351
+ move between pages, manage annotations, search, show thumbnails or install
352
+ overlays belong to this skill. Only generic representable questions (lifecycle,
353
+ sizing, state architecture) go to `swiftui-uikit-interop`.
330
354
 
331
355
  ```swift
332
- import SwiftUI
333
356
  import PDFKit
357
+ import SwiftUI
334
358
 
335
- struct PDFKitView: UIViewRepresentable {
359
+ struct PDFReader: UIViewRepresentable {
336
360
  let document: PDFDocument
337
361
 
338
362
  func makeUIView(context: Context) -> PDFView {
339
- let pdfView = PDFView()
340
- pdfView.autoScales = true
341
- pdfView.displayMode = .singlePageContinuous
342
- pdfView.document = document
343
- return pdfView
363
+ let reader = PDFView()
364
+ reader.autoScales = true
365
+ reader.displayMode = .singlePageContinuous
366
+ reader.document = document
367
+ return reader
344
368
  }
345
369
 
346
- func updateUIView(_ pdfView: PDFView, context: Context) {
347
- if pdfView.document !== document {
348
- pdfView.document = document
370
+ func updateUIView(_ reader: PDFView, context: Context) {
371
+ if reader.document !== document {
372
+ reader.document = document
349
373
  }
350
374
  }
351
375
  }
352
- ```
353
-
354
- ### Usage
355
376
 
356
- ```swift
357
- struct DocumentScreen: View {
358
- let url: URL
377
+ struct InvoiceScreen: View {
378
+ let fileURL: URL
359
379
 
360
380
  var body: some View {
361
- if let document = PDFDocument(url: url) {
362
- PDFKitView(document: document)
381
+ if let file = PDFDocument(url: fileURL) {
382
+ PDFReader(document: file)
363
383
  .ignoresSafeArea()
364
384
  } else {
365
- ContentUnavailableView("Unable to load PDF", systemImage: "doc.questionmark")
385
+ ContentUnavailableView("Cannot open invoice", systemImage: "doc.questionmark")
366
386
  }
367
387
  }
368
388
  }
369
389
  ```
370
390
 
371
- For interactive wrappers with page tracking, annotation hit detection, and
372
- coordinator patterns, see [references/pdfkit-patterns.md](references/pdfkit-patterns.md).
391
+ A version that binds the current page, reports annotation taps and uses a
392
+ coordinator is in [the patterns reference](references/pdfkit-patterns.md#coordinator-based-swiftui-wrapper).
373
393
 
374
- ### Page Overlays (iOS 16+)
394
+ ### Page overlays (iOS 16+)
375
395
 
376
- `PDFPageOverlayViewProvider` places UIKit views on top of individual pages
377
- for interactive controls or custom rendering beyond standard annotations.
396
+ `PDFPageOverlayViewProvider` places a UIKit view above each page, for
397
+ interactive controls or custom drawing. Implement
398
+ `pdfView(_:overlayViewFor:) -> UIView?` and assign the provider to
399
+ `pdfView.pageOverlayViewProvider`. That property is weak, so something else
400
+ must keep the provider alive.
378
401
 
379
402
  ```swift
380
- class OverlayProvider: NSObject, PDFPageOverlayViewProvider {
403
+ import PDFKit
404
+ import UIKit
405
+
406
+ @MainActor
407
+ final class StampOverlays: NSObject, @preconcurrency PDFPageOverlayViewProvider {
381
408
  func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? {
382
- let overlay = UIView()
383
- // Add custom subviews
384
- return overlay
409
+ let badge = UILabel()
410
+ badge.text = "DRAFT"
411
+ badge.textColor = .systemRed
412
+ badge.sizeToFit()
413
+ return badge
385
414
  }
386
415
  }
387
416
 
388
- class PDFOverlayController: UIViewController {
389
- let pdfView = PDFView()
390
- private let overlayProvider = OverlayProvider()
417
+ final class DraftViewer: UIViewController {
418
+ private let reader = PDFView()
419
+ private let overlays = StampOverlays()
391
420
 
392
421
  override func viewDidLoad() {
393
422
  super.viewDidLoad()
394
- pdfView.pageOverlayViewProvider = overlayProvider
395
- }
396
- }
397
- ```
398
-
399
- `pageOverlayViewProvider` is weak, so keep the provider strongly owned. For overlay lifecycle and save handling, read [references/pdfkit-patterns.md](references/pdfkit-patterns.md).
400
-
401
- ## Common Mistakes
402
-
403
- ### DON'T: Force-unwrap PDFDocument init
404
-
405
- `PDFDocument(url:)` and `PDFDocument(data:)` are failable initializers.
406
-
407
- ```swift
408
- // WRONG
409
- let document = PDFDocument(url: url)!
410
-
411
- // CORRECT
412
- guard let document = PDFDocument(url: url) else { return }
413
- ```
414
-
415
- ### DON'T: Forget autoScales on PDFView
416
-
417
- Without `autoScales`, the PDF renders at its native resolution.
418
-
419
- ```swift
420
- // WRONG
421
- pdfView.document = document
422
-
423
- // CORRECT
424
- pdfView.autoScales = true
425
- pdfView.document = document
426
- ```
427
-
428
- ### DON'T: Ignore PDF coordinate system in annotations
429
-
430
- PDF page coordinates have origin at the bottom-left with Y increasing
431
- upward -- opposite of UIKit.
432
-
433
- ```swift
434
- // WRONG: UIKit coordinates
435
- let bounds = CGRect(x: 50, y: 50, width: 200, height: 30)
436
-
437
- // CORRECT: PDF coordinates (origin bottom-left)
438
- let pageBounds = page.bounds(for: .mediaBox)
439
- let pdfY = pageBounds.height - 50 - 30
440
- let bounds = CGRect(x: 50, y: pdfY, width: 200, height: 30)
441
- ```
442
-
443
- ### DON'T: Modify annotations on a background thread
444
-
445
- PDFKit classes are not thread-safe.
446
-
447
- ```swift
448
- // WRONG
449
- DispatchQueue.global().async { page.addAnnotation(annotation) }
450
-
451
- // CORRECT
452
- DispatchQueue.main.async { page.addAnnotation(annotation) }
453
- ```
454
-
455
- ### DON'T: Compare PDFDocument with == in UIViewRepresentable
456
-
457
- `PDFDocument` is a reference type. Use identity (`!==`).
458
-
459
- ```swift
460
- // WRONG: Always replaces document
461
- func updateUIView(_ pdfView: PDFView, context: Context) {
462
- pdfView.document = document
463
- }
464
-
465
- // CORRECT
466
- func updateUIView(_ pdfView: PDFView, context: Context) {
467
- if pdfView.document !== document {
468
- pdfView.document = document
423
+ reader.pageOverlayViewProvider = overlays
469
424
  }
470
425
  }
471
426
  ```
472
427
 
473
- ## Review Checklist
474
-
475
- - [ ] `PDFDocument` init uses optional binding, not force-unwrap
476
- - [ ] `pdfView.autoScales = true` set for proper initial display
477
- - [ ] Page indices checked against `pageCount` before access
478
- - [ ] `displayMode` and `displayDirection` configured to match design
479
- - [ ] Annotations use PDF coordinate space (origin bottom-left, Y up)
480
- - [ ] All PDFKit mutations happen on the main thread
481
- - [ ] Password-protected PDFs handled with `isLocked` / `unlock(withPassword:)`
482
- - [ ] SwiftUI wrapper uses `!==` identity check in `updateUIView`
483
- - [ ] `PDFViewPageChanged` notification observed for page tracking
484
- - [ ] `PDFThumbnailView.pdfView` linked to the main `PDFView`
485
- - [ ] Large-document search uses async `beginFindString` with delegate
486
- - [ ] Saved documents use `write(to:withOptions:)` when encryption needed
428
+ ## Common mistakes
429
+
430
+ - **Force-unwrapping the initializers.** `PDFDocument(url:)` and
431
+ `PDFDocument(data:)` return `nil` for a bad file. Use `guard let`.
432
+ - **Forgetting `autoScales`.** Without it, pages appear at their native size.
433
+ - **Using UIKit coordinates on a page.** PDF space starts at the bottom-left and
434
+ y grows upward. To place something at a UIKit-style top offset, compute
435
+ `page.bounds(for: .mediaBox).height - topOffset - itemHeight`.
436
+ - **Mutating from a background queue.** PDFKit classes are not thread-safe.
437
+ Add or change annotations on the main thread.
438
+ - **Reassigning the document in `updateUIView`.** `PDFDocument` is a class;
439
+ compare with `!==` first, otherwise every SwiftUI update reloads the file.
440
+
441
+ ## Review checklist
442
+
443
+ - [ ] `PDFDocument` is created with optional binding
444
+ - [ ] `autoScales = true` is set
445
+ - [ ] Every page index is checked against `pageCount`
446
+ - [ ] `displayMode` and `displayDirection` match the design
447
+ - [ ] Annotation rectangles are in PDF coordinate space
448
+ - [ ] All PDFKit mutation happens on the main thread
449
+ - [ ] Locked files go through `isLocked` and `unlock(withPassword:)`
450
+ - [ ] The SwiftUI wrapper compares documents with `!==` in `updateUIView`
451
+ - [ ] `PDFViewPageChanged` drives any page indicator
452
+ - [ ] `PDFThumbnailView.pdfView` points at the main `PDFView`
453
+ - [ ] Long documents are searched with `beginFindString` and the delegate
454
+ - [ ] `write(to:withOptions:)` is used when the file must be encrypted
487
455
 
488
456
  ## References
489
457
 
490
- - Extended patterns (forms, watermarks, merging, printing, overlays, outlines, custom drawing): [references/pdfkit-patterns.md](references/pdfkit-patterns.md)
491
- - [PDFKit framework](https://sosumi.ai/documentation/pdfkit)
492
- - [PDFView](https://sosumi.ai/documentation/pdfkit/pdfview)
493
- - [PDFDocument](https://sosumi.ai/documentation/pdfkit/pdfdocument)
494
- - [PDFPage](https://sosumi.ai/documentation/pdfkit/pdfpage)
495
- - [PDFAnnotation](https://sosumi.ai/documentation/pdfkit/pdfannotation)
496
- - [PDFSelection](https://sosumi.ai/documentation/pdfkit/pdfselection)
497
- - [PDFThumbnailView](https://sosumi.ai/documentation/pdfkit/pdfthumbnailview)
498
- - [PDFPageOverlayViewProvider](https://sosumi.ai/documentation/pdfkit/pdfpageoverlayviewprovider)
499
- - [Adding Widgets to a PDF Document](https://sosumi.ai/documentation/pdfkit/adding-widgets-to-a-pdf-document)
500
- - [Adding Custom Graphics to a PDF](https://sosumi.ai/documentation/pdfkit/adding-custom-graphics-to-a-pdf)
458
+ - [PDFKit patterns](references/pdfkit-patterns.md) - forms, building PDFs, watermarks, merging and splitting, printing, outlines, custom annotation and page classes, overlay lifecycle, rendering, rotation and crop, burn-in, permissions, coordinator wrapper
459
+ - [PDFKit](https://developer.apple.com/documentation/pdfkit)
460
+ - [PDFView](https://developer.apple.com/documentation/pdfkit/pdfview)
461
+ - [PDFDocument](https://developer.apple.com/documentation/pdfkit/pdfdocument)
462
+ - [PDFPage](https://developer.apple.com/documentation/pdfkit/pdfpage)
463
+ - [PDFAnnotation](https://developer.apple.com/documentation/pdfkit/pdfannotation)
464
+ - [PDFSelection](https://developer.apple.com/documentation/pdfkit/pdfselection)
465
+ - [PDFThumbnailView](https://developer.apple.com/documentation/pdfkit/pdfthumbnailview)
466
+ - [PDFPageOverlayViewProvider](https://developer.apple.com/documentation/pdfkit/pdfpageoverlayviewprovider)
467
+ - [Adding widgets to a PDF document](https://developer.apple.com/documentation/pdfkit/adding-widgets-to-a-pdf-document)
468
+ - [Adding custom graphics to a PDF](https://developer.apple.com/documentation/pdfkit/adding-custom-graphics-to-a-pdf)