@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,262 +1,161 @@
1
- # Swift Charts Patterns Reference
1
+ # Swift Charts Patterns
2
2
 
3
- Extended patterns, accessibility guidance, and theming for Swift Charts on
4
- iOS 26+. Import `Charts` in every file that uses these APIs.
5
-
6
- ```swift
7
- import SwiftUI
8
- import Charts
9
- ```
10
-
11
- ---
3
+ Companion to the `swift-charts` skill. Any source file touching these types
4
+ imports `Charts` next to `SwiftUI`.
12
5
 
13
6
  ## Contents
14
7
 
15
- - [Data Modeling](#data-modeling)
16
- - [Bar Chart Patterns](#bar-chart-patterns)
17
- - [Line Chart Patterns](#line-chart-patterns)
18
- - [Pie and Donut Chart Patterns (SectorMark, iOS 17+)](#pie-and-donut-chart-patterns-sectormark-ios-17)
19
- - [Combined Chart Patterns](#combined-chart-patterns)
20
- - [Chart Selection with Overlay Annotation](#chart-selection-with-overlay-annotation)
21
- - [Scrollable Chart with Visible Domain](#scrollable-chart-with-visible-domain)
22
- - [Function Plotting (LinePlot, iOS 18+)](#function-plotting-lineplot-ios-18)
23
- - [3D Charts and Surfaces (Chart3D, iOS 26+)](#3d-charts-and-surfaces-chart3d-ios-26)
8
+ - [Modelling the Data](#modelling-the-data)
9
+ - [Bars](#bars)
10
+ - [Lines](#lines)
11
+ - [Pies and Donuts](#pies-and-donuts)
12
+ - [Combining Marks](#combining-marks)
13
+ - [A Tooltip on Selection](#a-tooltip-on-selection)
14
+ - [Scrolling with a Bound Position](#scrolling-with-a-bound-position)
15
+ - [Function Plots (iOS 18)](#function-plots-ios-18)
16
+ - [3D Charts and Surfaces (iOS 26)](#3d-charts-and-surfaces-ios-26)
24
17
  - [Accessibility](#accessibility)
25
- - [Dynamic Type and Color Considerations](#dynamic-type-and-color-considerations)
26
- - [Performance: Vectorized Plots for Large Datasets](#performance-vectorized-plots-for-large-datasets)
18
+ - [Dynamic Type and Colour](#dynamic-type-and-colour)
19
+ - [Performance: When to Vectorize](#performance-when-to-vectorize)
27
20
  - [Dark Mode and Theming](#dark-mode-and-theming)
28
- - [Heat Map Pattern](#heat-map-pattern)
29
- - [Stacking Methods](#stacking-methods)
30
- - [MarkDimension Options](#markdimension-options)
31
- - [Symbol Configuration](#symbol-configuration)
32
- - [ChartProxy and Coordinate Conversion](#chartproxy-and-coordinate-conversion)
33
- - [Quick Reference: Chart View Modifiers](#quick-reference-chart-view-modifiers)
34
- - [Apple Documentation Links](#apple-documentation-links)
21
+ - [Heat Map](#heat-map)
22
+ - [Stacking](#stacking)
23
+ - [`MarkDimension`](#markdimension)
24
+ - [Symbols](#symbols)
25
+ - [`ChartProxy` and Coordinates](#chartproxy-and-coordinates)
26
+ - [Modifier Quick Reference](#modifier-quick-reference)
27
+ - [Apple Documentation](#apple-documentation)
35
28
 
36
- ## Data Modeling
37
-
38
- Use `@Observable` for chart data models. Pair with `@State` in views.
29
+ ## Modelling the Data
39
30
 
40
31
  ```swift
32
+ import Charts
33
+ import SwiftUI
34
+
35
+ struct MonthlyUsage: Identifiable, Sendable {
36
+ let id = UUID()
37
+ let month: Date
38
+ let kilowattHours: Double
39
+ }
40
+
41
+ @MainActor
41
42
  @Observable
42
- class SalesModel {
43
- var monthlySales: [MonthlySale] = []
43
+ final class UsageModel {
44
+ private(set) var months: [MonthlyUsage] = []
44
45
 
45
46
  func load() async {
46
- monthlySales = await SalesService.fetchMonthlySales()
47
+ months = await UsageService.shared.lastTwelveMonths()
47
48
  }
48
49
  }
49
50
 
50
- struct MonthlySale: Identifiable {
51
- let id = UUID()
52
- let month: Date
53
- let revenue: Double
54
- let category: String
55
- }
56
- ```
57
-
58
- ```swift
59
- struct SalesDashboard: View {
60
- @State private var model = SalesModel()
51
+ struct UsageChart: View {
52
+ @State private var model = UsageModel()
61
53
 
62
54
  var body: some View {
63
- Chart(model.monthlySales) { item in
64
- BarMark(
65
- x: .value("Month", item.month, unit: .month),
66
- y: .value("Revenue", item.revenue)
67
- )
68
- .foregroundStyle(by: .value("Category", item.category))
55
+ Chart(model.months) { entry in
56
+ BarMark(x: .value("Month", entry.month, unit: .month),
57
+ y: .value("kWh", entry.kilowattHours))
69
58
  }
70
59
  .task { await model.load() }
71
60
  }
72
61
  }
73
62
  ```
74
63
 
75
- ---
64
+ The view owns the model with `@State` and starts loading from `.task`.
76
65
 
77
- ## Bar Chart Patterns
66
+ ## Bars
78
67
 
79
- ### Simple vertical bars
68
+ Side by side instead of stacked: combine `.position(by:)` with
69
+ `.foregroundStyle(by:)`.
80
70
 
81
71
  ```swift
82
- Chart(data) { item in
83
- BarMark(
84
- x: .value("Department", item.department),
85
- y: .value("Revenue", item.revenue)
86
- )
72
+ Chart(results) { row in
73
+ BarMark(x: .value("Quarter", row.quarter), y: .value("Units", row.units))
74
+ .foregroundStyle(by: .value("Model", row.model))
75
+ .position(by: .value("Model", row.model))
87
76
  }
88
77
  ```
89
78
 
90
- ### Stacked bars (automatic)
91
-
92
- When multiple bars share the same x value, they stack automatically:
79
+ Horizontal bars with only value labels on the category axis:
93
80
 
94
81
  ```swift
95
- Chart(data) { item in
96
- BarMark(
97
- x: .value("Quarter", item.quarter),
98
- y: .value("Sales", item.sales)
99
- )
100
- .foregroundStyle(by: .value("Product", item.product))
101
- }
102
- ```
103
-
104
- ### Grouped bars
105
-
106
- Use `.position(by:)` to place bars side by side instead of stacking:
107
-
108
- ```swift
109
- Chart(data) { item in
110
- BarMark(
111
- x: .value("Quarter", item.quarter),
112
- y: .value("Sales", item.sales)
113
- )
114
- .foregroundStyle(by: .value("Product", item.product))
115
- .position(by: .value("Product", item.product))
116
- }
117
- ```
118
-
119
- ### Horizontal bars
120
-
121
- Swap the x and y axes:
122
-
123
- ```swift
124
- Chart(data) { item in
125
- BarMark(
126
- x: .value("Sales", item.sales),
127
- y: .value("Region", item.region)
128
- )
82
+ Chart(languages) { item in
83
+ BarMark(x: .value("Speakers", item.speakers), y: .value("Language", item.name))
129
84
  }
130
85
  .chartYAxis {
131
- AxisMarks { _ in
132
- AxisValueLabel()
133
- }
86
+ AxisMarks { _ in AxisValueLabel() }
134
87
  }
135
88
  ```
136
89
 
137
- ### Normalized stacked bars (100%)
90
+ Shares of 100 percent per bar: `BarMark(x:y:stacking: .normalized)`.
138
91
 
139
- ```swift
140
- Chart(data) { item in
141
- BarMark(
142
- x: .value("Quarter", item.quarter),
143
- y: .value("Sales", item.sales),
144
- stacking: .normalized
145
- )
146
- .foregroundStyle(by: .value("Product", item.product))
147
- }
148
- ```
149
-
150
- ### Bar with annotation
92
+ A value on top of each bar:
151
93
 
152
94
  ```swift
153
- Chart(data) { item in
154
- BarMark(
155
- x: .value("Month", item.month),
156
- y: .value("Revenue", item.revenue)
157
- )
158
- .annotation(position: .top, alignment: .center, spacing: 4) {
159
- Text(item.revenue, format: .currency(code: "USD").precision(.fractionLength(0)))
95
+ BarMark(x: .value("Store", row.store), y: .value("Sales", row.sales))
96
+ .annotation(position: .top) {
97
+ Text(row.sales, format: .currency(code: "EUR").precision(.fractionLength(0)))
160
98
  .font(.caption2)
161
99
  }
162
- }
163
100
  ```
164
101
 
165
- ### Gantt chart (interval bars)
102
+ A Gantt chart colours interval bars by status:
166
103
 
167
104
  ```swift
168
105
  Chart(tasks) { task in
169
- BarMark(
170
- xStart: .value("Start", task.startDate),
171
- xEnd: .value("End", task.endDate),
172
- y: .value("Task", task.name)
173
- )
174
- .foregroundStyle(by: .value("Status", task.status))
106
+ BarMark(xStart: .value("Start", task.start),
107
+ xEnd: .value("End", task.end),
108
+ y: .value("Task", task.title))
109
+ .foregroundStyle(by: .value("Phase", task.phase.rawValue))
175
110
  }
176
111
  ```
177
112
 
178
- ---
179
-
180
- ## Line Chart Patterns
113
+ ## Lines
181
114
 
182
- ### Single line with points
115
+ Points on the line: put a `LineMark` and a `PointMark` in the same closure.
183
116
 
184
117
  ```swift
185
- Chart(data) { item in
186
- LineMark(
187
- x: .value("Date", item.date),
188
- y: .value("Price", item.price)
189
- )
190
- PointMark(
191
- x: .value("Date", item.date),
192
- y: .value("Price", item.price)
193
- )
194
- .symbolSize(30)
118
+ Chart(temperatures) { sample in
119
+ LineMark(x: .value("Hour", sample.hour), y: .value("Celsius", sample.value))
120
+ .foregroundStyle(by: .value("City", sample.city))
121
+ .symbol(by: .value("City", sample.city))
122
+ PointMark(x: .value("Hour", sample.hour), y: .value("Celsius", sample.value))
123
+ .symbolSize(30)
195
124
  }
196
125
  ```
197
126
 
198
- ### Multi-series lines
127
+ Pairing `.foregroundStyle(by:)` with `.symbol(by:)` keeps series apart for
128
+ people who cannot tell the colours apart.
199
129
 
200
- ```swift
201
- Chart(temperatures) { item in
202
- LineMark(
203
- x: .value("Date", item.date),
204
- y: .value("Temp", item.temperature)
205
- )
206
- .foregroundStyle(by: .value("City", item.city))
207
- .symbol(by: .value("City", item.city))
208
- }
209
- ```
210
-
211
- ### Line with area fill
130
+ A line over a fading area:
212
131
 
213
132
  ```swift
214
- Chart(data) { item in
215
- AreaMark(
216
- x: .value("Date", item.date),
217
- y: .value("Value", item.value)
218
- )
219
- .foregroundStyle(
220
- .linearGradient(
221
- colors: [.blue.opacity(0.3), .blue.opacity(0.05)],
222
- startPoint: .top,
223
- endPoint: .bottom
224
- )
225
- )
226
- LineMark(
227
- x: .value("Date", item.date),
228
- y: .value("Value", item.value)
229
- )
230
- .foregroundStyle(.blue)
133
+ Chart(prices) { point in
134
+ AreaMark(x: .value("Day", point.day), y: .value("Price", point.close))
135
+ .foregroundStyle(.linearGradient(
136
+ colors: [.indigo.opacity(0.35), .indigo.opacity(0.02)],
137
+ startPoint: .top, endPoint: .bottom))
138
+ LineMark(x: .value("Day", point.day), y: .value("Price", point.close))
139
+ .foregroundStyle(.indigo)
231
140
  }
232
141
  ```
233
142
 
234
- ### Interpolation methods
143
+ Interpolation methods:
235
144
 
236
- | Method | Use Case |
237
- |---|---|
238
- | `.linear` | Default; straight segments between points |
239
- | `.monotone` | Smooth curve that preserves monotonicity |
240
- | `.catmullRom` | Smooth general-purpose curve |
241
- | `.cardinal` | Smooth with adjustable tension |
242
- | `.stepStart` | Step function starting at data point |
243
- | `.stepCenter` | Step function centered on data point |
244
- | `.stepEnd` | Step function ending at data point |
145
+ | Method | Result |
146
+ |--------|--------|
147
+ | `.linear` | Straight segments (the default) |
148
+ | `.monotone` | Smooth without overshooting; keeps monotonic data monotonic |
149
+ | `.catmullRom` | Smooth curve for general data |
150
+ | `.cardinal` | Smooth curve with adjustable tension |
151
+ | `.stepStart`, `.stepCenter`, `.stepEnd` | Steps placed at the start, middle or end of each interval |
245
152
 
246
- ```swift
247
- LineMark(x: .value("X", item.x), y: .value("Y", item.y))
248
- .interpolationMethod(.monotone)
249
- ```
250
-
251
- ### Sparkline (minimal inline chart)
153
+ A sparkline:
252
154
 
253
155
  ```swift
254
- Chart(recentData) { item in
255
- LineMark(
256
- x: .value("Time", item.time),
257
- y: .value("Value", item.value)
258
- )
259
- .interpolationMethod(.catmullRom)
156
+ Chart(recent) { point in
157
+ LineMark(x: .value("t", point.index), y: .value("v", point.value))
158
+ .interpolationMethod(.catmullRom)
260
159
  }
261
160
  .chartXAxis(.hidden)
262
161
  .chartYAxis(.hidden)
@@ -264,625 +163,360 @@ Chart(recentData) { item in
264
163
  .frame(width: 80, height: 30)
265
164
  ```
266
165
 
267
- ---
268
-
269
- ## Pie and Donut Chart Patterns (SectorMark, iOS 17+)
270
-
271
- Use strictly positive values for sectors. Filter, aggregate, or show zero and
272
- negative values outside the pie or donut so angular sizes remain meaningful.
273
-
274
- ### Basic pie chart
275
-
276
- ```swift
277
- Chart(products, id: \.name) { item in
278
- SectorMark(angle: .value("Sales", item.sales))
279
- .foregroundStyle(by: .value("Product", item.name))
280
- }
281
- ```
166
+ ## Pies and Donuts
282
167
 
283
- ### Donut chart with golden ratio inner radius
168
+ An inner radius of 0.618 (the golden ratio) gives a balanced donut. Put a label
169
+ in the hole with `.chartBackground`:
284
170
 
285
171
  ```swift
286
- Chart(products, id: \.name) { item in
287
- SectorMark(
288
- angle: .value("Sales", item.sales),
289
- innerRadius: .ratio(0.618),
290
- outerRadius: .inset(10),
291
- angularInset: 1
292
- )
293
- .cornerRadius(4)
294
- .foregroundStyle(by: .value("Product", item.name))
295
- }
296
- ```
297
-
298
- ### Donut chart with center label
299
-
300
- ```swift
301
- Chart(products, id: \.name) { item in
302
- SectorMark(
303
- angle: .value("Sales", item.sales),
304
- innerRadius: .ratio(0.618),
305
- angularInset: 1
306
- )
307
- .cornerRadius(4)
308
- .foregroundStyle(by: .value("Product", item.name))
172
+ Chart(portfolio) { holding in
173
+ SectorMark(angle: .value("Value", holding.value), innerRadius: .ratio(0.618))
174
+ .foregroundStyle(by: .value("Asset", holding.asset))
309
175
  }
310
176
  .chartBackground { _ in
311
177
  VStack {
312
- Text("Total")
313
- .font(.caption)
314
- .foregroundStyle(.secondary)
315
- Text("\(totalSales, format: .number)")
316
- .font(.title2.bold())
178
+ Text("Total").font(.caption)
179
+ Text(portfolioTotal, format: .currency(code: "EUR")).font(.headline)
317
180
  }
318
181
  }
319
182
  ```
320
183
 
321
- ### Angular selection on donut
184
+ Selecting a slice. The binding holds a position along the summed values, so
185
+ map it back to a slice:
322
186
 
323
187
  ```swift
324
- struct ProductSales: Identifiable {
325
- let id = UUID()
326
- let name: String
327
- let sales: Double
328
- }
188
+ struct PortfolioDonut: View {
189
+ let holdings: [Holding]
190
+ @State private var selectedAngle: Double?
329
191
 
330
- @State private var selectedAngle: Double?
331
-
332
- var selectedProduct: ProductSales? {
333
- guard let selectedAngle else { return nil }
334
- var runningTotal = 0.0
335
-
336
- return products.first { product in
337
- let range = runningTotal..<(runningTotal + product.sales)
338
- runningTotal += product.sales
339
- return range.contains(selectedAngle)
192
+ private var selectedHolding: Holding? {
193
+ guard let angle = selectedAngle else { return nil }
194
+ var start = 0.0
195
+ for holding in holdings {
196
+ let end = start + holding.value
197
+ if (start..<end).contains(angle) { return holding }
198
+ start = end
199
+ }
200
+ return nil
340
201
  }
341
- }
342
202
 
343
- Chart(products, id: \.name) { item in
344
- SectorMark(
345
- angle: .value("Sales", item.sales),
346
- innerRadius: .ratio(0.618),
347
- angularInset: 1
348
- )
349
- .cornerRadius(4)
350
- .foregroundStyle(by: .value("Product", item.name))
351
- .opacity(selectedProduct == nil || selectedProduct?.name == item.name ? 1.0 : 0.4)
203
+ var body: some View {
204
+ Chart(holdings) { holding in
205
+ SectorMark(angle: .value("Value", holding.value), innerRadius: .ratio(0.6))
206
+ .foregroundStyle(by: .value("Asset", holding.asset))
207
+ .opacity(selectedHolding == nil || selectedHolding?.id == holding.id ? 1 : 0.4)
208
+ }
209
+ .chartAngleSelection(value: $selectedAngle)
210
+ }
352
211
  }
353
- .chartAngleSelection(value: $selectedAngle)
354
212
  ```
355
213
 
356
- `chartAngleSelection(value:)` binds the selected plottable angle value, not the
357
- sector label. Convert that value through cumulative sector ranges before using
358
- it to highlight or annotate a category.
359
-
360
- ### Grouping small slices
361
-
362
- Limit pie/donut charts to 5-7 positive-value sectors. Group the rest into "Other":
214
+ Keep five to seven positive slices:
363
215
 
364
216
  ```swift
365
- func groupSmallSlices(_ data: [CategorySales], topN: Int = 5) -> [CategorySales] {
366
- let sorted = data.sorted { $0.sales > $1.sales }
367
- let top = Array(sorted.prefix(topN))
368
- let otherTotal = sorted.dropFirst(topN).reduce(0) { $0 + $1.sales }
369
- guard otherTotal > 0 else { return top }
370
- return top + [CategorySales(name: "Other", sales: otherTotal)]
217
+ func topSlices(_ items: [Holding], keep limit: Int = 5) -> [Holding] {
218
+ let ordered = items.filter { $0.value > 0 }.sorted { $0.value > $1.value }
219
+ let head = Array(ordered.prefix(limit))
220
+ let remainder = ordered.dropFirst(limit).reduce(0) { $0 + $1.value }
221
+ guard remainder > 0 else { return head }
222
+ return head + [Holding(asset: "Other", value: remainder)]
371
223
  }
372
224
  ```
373
225
 
374
- ---
375
-
376
- ## Combined Chart Patterns
226
+ ## Combining Marks
377
227
 
378
- ### Line + area (trend with fill)
228
+ A range band with an average line:
379
229
 
380
230
  ```swift
381
- Chart(data) { item in
382
- AreaMark(
383
- x: .value("Date", item.date),
384
- yStart: .value("Min", item.low),
385
- yEnd: .value("Max", item.high)
386
- )
387
- .foregroundStyle(.blue.opacity(0.15))
388
-
389
- LineMark(
390
- x: .value("Date", item.date),
391
- y: .value("Average", item.average)
392
- )
393
- .foregroundStyle(.blue)
394
- .lineStyle(StrokeStyle(lineWidth: 2))
231
+ Chart(week) { day in
232
+ AreaMark(x: .value("Day", day.date),
233
+ yStart: .value("Low", day.low),
234
+ yEnd: .value("High", day.high))
235
+ .opacity(0.15)
236
+ LineMark(x: .value("Day", day.date), y: .value("Mean", day.mean))
237
+ .lineStyle(StrokeStyle(lineWidth: 2))
395
238
  }
396
239
  ```
397
240
 
398
- ### Bar + threshold rule
241
+ Bars with a target line:
399
242
 
400
243
  ```swift
401
244
  Chart {
402
- ForEach(data) { item in
403
- BarMark(
404
- x: .value("Month", item.month),
405
- y: .value("Revenue", item.revenue)
406
- )
245
+ ForEach(weeks) { week in
246
+ BarMark(x: .value("Week", week.label), y: .value("Hours", week.hours))
407
247
  }
408
- RuleMark(y: .value("Target", targetRevenue))
409
- .foregroundStyle(.red)
410
- .lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 3]))
411
- .annotation(position: .top, alignment: .leading) {
412
- Text("Target: \(targetRevenue, format: .number)")
413
- .font(.caption)
414
- .foregroundStyle(.red)
415
- }
248
+ RuleMark(y: .value("Target", 38))
249
+ .lineStyle(StrokeStyle(lineWidth: 1, dash: [4, 4]))
250
+ .annotation(position: .top, alignment: .leading) { Text("38 h") }
416
251
  }
417
252
  ```
418
253
 
419
- ### Scatter + trend line
254
+ Observations with a fitted curve; marks and plots can share a chart:
420
255
 
421
256
  ```swift
422
257
  Chart {
423
- ForEach(data) { item in
424
- PointMark(
425
- x: .value("Experience", item.yearsExperience),
426
- y: .value("Salary", item.salary)
427
- )
428
- .opacity(0.6)
258
+ ForEach(samples) { sample in
259
+ PointMark(x: .value("Dose", sample.dose), y: .value("Response", sample.response))
429
260
  }
430
- LinePlot(x: "Experience", y: "Salary", domain: 0...20) { x in
431
- baseSalary + x * salaryPerYear // linear trend
261
+ LinePlot(x: "Dose", y: "Response", domain: 0...10) { dose in
262
+ fit.slope * dose + fit.intercept
432
263
  }
433
264
  .foregroundStyle(.red)
434
- .lineStyle(StrokeStyle(lineWidth: 1.5, dash: [4, 2]))
265
+ .lineStyle(StrokeStyle(lineWidth: 1, dash: [3, 3]))
435
266
  }
436
267
  ```
437
268
 
438
- ---
269
+ ## A Tooltip on Selection
439
270
 
440
- ## Chart Selection with Overlay Annotation
271
+ ```swift
272
+ struct ActivityChart: View {
273
+ let days: [ActivityDay]
274
+ @State private var focusedDate: Date?
441
275
 
442
- Show a tooltip at the selected position using `chartOverlay`:
276
+ private var focusedDay: ActivityDay? {
277
+ guard let focusedDate else { return nil }
278
+ let calendar = Calendar.current
279
+ return days.first { calendar.isDate($0.date, inSameDayAs: focusedDate) }
280
+ }
443
281
 
444
- ```swift
445
- @State private var selectedDate: Date?
446
-
447
- var body: some View {
448
- Chart(data) { item in
449
- LineMark(
450
- x: .value("Date", item.date),
451
- y: .value("Value", item.value)
452
- )
453
- if let selectedDate,
454
- let match = data.first(where: { Calendar.current.isDate($0.date, inSameDayAs: selectedDate) }) {
455
- RuleMark(x: .value("Selected", match.date))
456
- .foregroundStyle(.secondary)
457
- PointMark(
458
- x: .value("Date", match.date),
459
- y: .value("Value", match.value)
460
- )
461
- .symbolSize(60)
462
- .annotation(position: .top) {
463
- Text("\(match.value, format: .number)")
464
- .font(.caption)
465
- .padding(4)
466
- .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 4))
282
+ var body: some View {
283
+ Chart {
284
+ ForEach(days) { day in
285
+ LineMark(x: .value("Date", day.date, unit: .day),
286
+ y: .value("Minutes", day.minutes))
287
+ }
288
+ if let focusedDay {
289
+ RuleMark(x: .value("Date", focusedDay.date, unit: .day))
290
+ .foregroundStyle(.secondary)
291
+ PointMark(x: .value("Date", focusedDay.date, unit: .day),
292
+ y: .value("Minutes", focusedDay.minutes))
293
+ .symbolSize(80)
294
+ .annotation(position: .top) {
295
+ Text("\(focusedDay.minutes) min")
296
+ .padding(6)
297
+ .background(.regularMaterial, in: .rect(cornerRadius: 6))
298
+ }
467
299
  }
468
300
  }
301
+ .chartXSelection(value: $focusedDate)
469
302
  }
470
- .chartXSelection(value: $selectedDate)
471
303
  }
472
304
  ```
473
305
 
474
- ---
306
+ ## Scrolling with a Bound Position
475
307
 
476
- ## Scrollable Chart with Visible Domain
308
+ `chartScrollPosition(x:)` takes a binding to a non-optional `Plottable` value,
309
+ so bind a `Date`, not a `Date?`:
477
310
 
478
311
  ```swift
479
- @State private var scrollPosition: Date?
480
-
481
- var body: some View {
482
- Chart(dailySteps) { item in
483
- BarMark(
484
- x: .value("Date", item.date, unit: .day),
485
- y: .value("Steps", item.steps)
486
- )
487
- }
488
- .chartScrollableAxes(.horizontal)
489
- .chartXVisibleDomain(length: 3600 * 24 * 7) // 7 days
490
- .chartScrollPosition(x: $scrollPosition)
491
- .chartScrollTargetBehavior(
492
- .valueAligned(matching: DateComponents(hour: 0), majorAlignment: .page)
493
- )
494
- .chartXAxis {
495
- AxisMarks(values: .stride(by: .day)) { value in
496
- AxisGridLine()
497
- AxisValueLabel(format: .dateTime.weekday(.abbreviated))
498
- }
312
+ @State private var windowStart = Date.now.addingTimeInterval(-7 * 86_400)
313
+
314
+ Chart(readings) { reading in
315
+ BarMark(x: .value("Day", reading.date, unit: .day),
316
+ y: .value("Litres", reading.litres))
317
+ }
318
+ .chartScrollableAxes(.horizontal)
319
+ .chartXVisibleDomain(length: 3600 * 24 * 7)
320
+ .chartScrollPosition(x: $windowStart)
321
+ .chartXAxis {
322
+ AxisMarks(values: .stride(by: .day)) { value in
323
+ AxisGridLine()
324
+ AxisValueLabel(format: .dateTime.weekday(.abbreviated))
499
325
  }
500
326
  }
501
327
  ```
502
328
 
503
- ---
504
-
505
- ## Function Plotting (LinePlot, iOS 18+)
506
-
507
- ### Standard function y = f(x)
329
+ ## Function Plots (iOS 18)
508
330
 
509
331
  ```swift
510
332
  Chart {
511
- LinePlot(x: "x", y: "y", domain: -2 * .pi ... 2 * .pi) { x in
512
- sin(x)
513
- }
514
- .foregroundStyle(.blue)
333
+ LinePlot(x: "Angle", y: "Amplitude", domain: -2 * .pi ... 2 * .pi) { cos($0) }
515
334
  }
516
- .chartYScale(domain: -1.5...1.5)
517
- ```
335
+ .chartYScale(domain: -1.2...1.2)
518
336
 
519
- ### Parametric function (x, y) = f(t)
520
-
521
- ```swift
522
337
  Chart {
523
- LinePlot(x: "x", y: "y", t: "t", domain: 0 ... 2 * .pi) { t in
524
- (x: cos(t), y: sin(t))
338
+ LinePlot(x: "Across", y: "Up", t: "Turn", domain: 0...(2 * .pi)) { turn in
339
+ (x: 2 * cos(turn), y: 2 * sin(turn))
525
340
  }
526
341
  }
527
- .chartXScale(domain: -1.5...1.5)
528
- .chartYScale(domain: -1.5...1.5)
529
- ```
342
+ .chartXScale(domain: -2.5...2.5)
343
+ .chartYScale(domain: -2.5...2.5)
530
344
 
531
- ### Range area function
532
-
533
- ```swift
534
345
  Chart {
535
- AreaPlot(x: "x", yStart: "min", yEnd: "max", domain: 0...10) { x in
536
- (yStart: sin(x) - 0.5, yEnd: sin(x) + 0.5)
346
+ AreaPlot(x: "x", yStart: "lower", yEnd: "upper", domain: 0...4) { x in
347
+ (yStart: x - 0.5, yEnd: x * x / 2 + 0.5)
537
348
  }
538
- .foregroundStyle(.blue.opacity(0.2))
539
349
  }
540
350
  ```
541
351
 
542
- ---
352
+ The last chart fills the band between two functions of x.
543
353
 
544
- ## 3D Charts and Surfaces (Chart3D, iOS 26+)
354
+ ## 3D Charts and Surfaces (iOS 26)
545
355
 
546
- Use `Chart3D` when the data has a real third dimension, such as `(x, y, z)`
547
- points, 3D regions, or a bivariate surface. Keep ordinary category comparison,
548
- time series, and proportions in 2D charts because they are easier to label,
549
- compare, and make accessible.
550
-
551
- ### SurfacePlot for bivariate functions
356
+ `Chart3D` is for data with a real third dimension: points in (x, y, z), 3D
357
+ regions, or a surface of two variables. Categories, time series and shares stay
358
+ in 2D: labels, comparisons and VoiceOver all work better there.
552
359
 
553
360
  ```swift
554
- @State private var pose: Chart3DPose = .default
361
+ struct SensorCloud: View {
362
+ let readings: [SensorReading]
555
363
 
556
- Chart3D {
557
- SurfacePlot(x: "x", y: "y", z: "z") { x, z in
558
- sin(2 * x) * cos(2 * z)
364
+ var body: some View {
365
+ Chart3D(readings) { reading in
366
+ PointMark(x: .value("X", reading.x),
367
+ y: .value("Y", reading.y),
368
+ z: .value("Z", reading.z))
369
+ .foregroundStyle(by: .value("Sensor", reading.sensor))
370
+ }
371
+ .chart3DCameraProjection(.perspective)
559
372
  }
560
- .foregroundStyle(.heightBased)
561
- }
562
- .chartXScale(domain: -2...2)
563
- .chartYScale(domain: -1...1)
564
- .chartZScale(domain: -2...2)
565
- .chart3DPose($pose)
566
- ```
567
-
568
- ### 3D point cloud
569
-
570
- ```swift
571
- Chart3D(points) { point in
572
- PointMark(
573
- x: .value("Width", point.x),
574
- y: .value("Height", point.y),
575
- z: .value("Depth", point.z)
576
- )
577
- .foregroundStyle(by: .value("Cluster", point.cluster))
578
373
  }
579
- .chart3DCameraProjection(.perspective)
580
374
  ```
581
375
 
582
- ### 3D review notes
583
-
584
- - Confirm the z dimension is meaningful and labeled; do not use depth only for decoration.
585
- - Set explicit x/y/z domains when users need stable comparisons across states.
586
- - Bind `Chart3DPose` when users need to inspect the scene interactively.
587
- - Use `SurfacePlot` for `y = f(x, z)` surfaces; use 3D mark initializers for observed data points or regions.
588
-
589
- ---
376
+ Review notes:
377
+ - The z axis must mean something and carry a label.
378
+ - Set explicit x, y and z domains so charts can be compared.
379
+ - Bind a `Chart3DPose` when users should rotate the chart.
380
+ - `SurfacePlot` draws y as a function of x and z; the 3D mark initialisers
381
+ draw observed points and regions.
590
382
 
591
383
  ## Accessibility
592
384
 
593
- ### Automatic VoiceOver support
594
-
595
- Swift Charts provides automatic VoiceOver descriptions for chart elements. The
596
- framework reads axis labels and values to visually impaired users without
597
- additional code. Ensure `.value("Label", ...)` strings are descriptive.
598
-
599
- ### Custom accessibility labels
600
-
601
- ```swift
602
- Chart(data) { item in
603
- BarMark(
604
- x: .value("Month", item.month),
605
- y: .value("Sales", item.sales)
606
- )
607
- .accessibilityLabel("Sales for \(item.month)")
608
- .accessibilityValue("\(item.sales) units sold")
609
- }
610
- ```
611
-
612
- ### Accessibility on vectorized plots (KeyPath-based)
613
-
614
- ```swift
615
- BarPlot(data, x: .value("Month", \.month), y: .value("Sales", \.sales))
616
- .accessibilityLabel(\.accessibilityDescription)
617
- .accessibilityValue(\.formattedSales)
618
- ```
619
-
620
- ### Audio graphs
621
-
622
- The system automatically generates audio representations of chart data for
623
- VoiceOver users. Use clear, consistent data labels to ensure audio graphs
624
- convey meaningful patterns.
625
-
626
- ### Best practices
627
-
628
- - Use descriptive strings in `.value("Label", ...)` -- these become VoiceOver labels.
629
- - Add `.accessibilityLabel` and `.accessibilityValue` for context beyond raw numbers.
630
- - Test with VoiceOver enabled: navigate the chart and verify each element is announced.
631
- - Avoid `.accessibilityHidden(true)` on data-bearing marks.
632
-
633
- ---
634
-
635
- ## Dynamic Type and Color Considerations
636
-
637
- ### Dynamic Type
638
-
639
- Charts automatically adjust axis label sizes with Dynamic Type. Avoid fixed
640
- frame heights that clip labels at larger text sizes.
641
-
642
- ```swift
643
- // WRONG -- clips at large text sizes
644
- Chart(data) { ... }
645
- .frame(height: 200)
646
-
647
- // CORRECT -- adaptive height
648
- Chart(data) { ... }
649
- .frame(minHeight: 200)
650
- .frame(maxHeight: 400)
651
- ```
652
-
653
- Test charts at the "Accessibility Extra Extra Extra Large" text size to verify
654
- axis labels, annotations, and legends remain readable.
655
-
656
- ### Color
657
-
658
- - Avoid encoding meaning solely in color. Pair `.foregroundStyle(by:)` with
659
- `.symbol(by:)` or `.lineStyle(by:)` for distinguishability.
660
- - Use system colors that adapt to both light and dark modes.
661
- - Test with color blindness simulations in the Accessibility Inspector.
662
-
663
- ```swift
664
- LineMark(x: .value("Date", item.date), y: .value("Value", item.value))
665
- .foregroundStyle(by: .value("Category", item.category))
666
- .symbol(by: .value("Category", item.category))
667
- .lineStyle(by: .value("Category", item.category))
668
- ```
669
-
670
- ---
671
-
672
- ## Performance: Vectorized Plots for Large Datasets
673
-
674
- For datasets exceeding 1000 data points, use vectorized plot types instead of
675
- individual marks. Vectorized plots accept entire collections and render
676
- efficiently.
677
-
678
- ### When to use vectorized plots
679
-
680
- | Data Points | Recommended Approach |
681
- |---|---|
682
- | < 100 | Individual marks (`BarMark`, `LineMark`, etc.) |
683
- | 100 - 1000 | Either approach; profile if performance matters |
684
- | > 1000 | Vectorized plots (`BarPlot`, `LinePlot`, etc.) |
685
-
686
- ### Data-driven vectorized plot
687
-
688
- ```swift
689
- struct SensorReading: Identifiable {
385
+ - Swift Charts builds VoiceOver descriptions from axis labels and values, so
386
+ the strings in `.value("Label", ...)` are what VoiceOver says. Make them
387
+ descriptive.
388
+ - Add `.accessibilityLabel` and `.accessibilityValue` to marks when the
389
+ default is not clear enough.
390
+ - Vectorized plots take key paths:
391
+ `.accessibilityLabel(\.spokenName)` and `.accessibilityValue(\.spokenValue)`.
392
+ - The system creates an audio graph for VoiceOver users automatically; clear,
393
+ consistent labels make it useful.
394
+ - Move through every element with VoiceOver. Never mark data-bearing marks
395
+ `.accessibilityHidden(true)`.
396
+
397
+ ## Dynamic Type and Colour
398
+
399
+ - Axis labels follow Dynamic Type. Avoid fixed heights; give a range such as
400
+ `.frame(minHeight: 200)` with `.frame(maxHeight: 400)`.
401
+ - Check axes, annotations and legends at the largest accessibility size
402
+ (Accessibility Extra Extra Extra Large).
403
+ - Colour must not be the only carrier of meaning. Pair
404
+ `.foregroundStyle(by:)` with `.symbol(by:)`, `.lineStyle(by:)` or both.
405
+ - Prefer system colours, which adapt, and check colour-blindness filters in
406
+ Accessibility Inspector.
407
+
408
+ ## Performance: When to Vectorize
409
+
410
+ | Points | Use |
411
+ |--------|-----|
412
+ | Fewer than 100 | Individual marks |
413
+ | 100 to 1,000 | Either; profile if it feels slow |
414
+ | More than 1,000 | Vectorized plots |
415
+
416
+ ```swift
417
+ struct TemperatureSample: Identifiable {
690
418
  let id: Int
691
- let timestamp: Date
692
- let temperature: Double
693
- var color: Color { temperature > 30 ? .red : .blue }
694
- var accessibilityDescription: Text {
695
- Text("\(timestamp.formatted(.dateTime.hour().minute())): \(temperature, specifier: "%.1f") degrees")
696
- }
419
+ let time: Date
420
+ let celsius: Double
421
+ var tint: Color { celsius > 30 ? .red : .blue }
422
+ var spokenValue: Text { Text("\(celsius, specifier: "%.1f") degrees") }
697
423
  }
698
424
 
699
425
  Chart {
700
- LinePlot(
701
- readings,
702
- x: .value("Time", \.timestamp),
703
- y: .value("Temperature", \.temperature)
704
- )
705
- .foregroundStyle(.blue)
426
+ LinePlot(samples, x: .value("Time", \.time), y: .value("Celsius", \.celsius))
427
+ .foregroundStyle(\.tint)
428
+ .accessibilityValue(\.spokenValue)
706
429
  }
707
430
  ```
708
431
 
709
- ### KeyPath modifier ordering
710
-
711
- Apply KeyPath-based modifiers before simple-value modifiers:
712
-
713
- ```swift
714
- // WRONG
715
- BarPlot(data, x: .value("X", \.x), y: .value("Y", \.y))
716
- .opacity(0.8) // value modifier
717
- .foregroundStyle(\.color) // KeyPath -- compiler error
718
-
719
- // CORRECT
720
- BarPlot(data, x: .value("X", \.x), y: .value("Y", \.y))
721
- .foregroundStyle(\.color) // KeyPath first
722
- .opacity(0.8) // value modifier second
723
- ```
724
-
725
- ### Available vectorized plot types
726
-
727
- | Plot Type | Mark Equivalent | Available From |
728
- |---|---|---|
729
- | `BarPlot` | `BarMark` | iOS 18+ |
730
- | `LinePlot` | `LineMark` | iOS 18+ |
731
- | `PointPlot` | `PointMark` | iOS 18+ |
732
- | `AreaPlot` | `AreaMark` | iOS 18+ |
733
- | `RulePlot` | `RuleMark` | iOS 18+ |
734
- | `RectanglePlot` | `RectangleMark` | iOS 18+ |
735
- | `SectorPlot` | `SectorMark` | iOS 18+ |
736
-
737
- ---
432
+ | Vectorized (iOS 18) | Mark equivalent |
433
+ |---------------------|-----------------|
434
+ | `BarPlot` | `BarMark` |
435
+ | `LinePlot` | `LineMark` |
436
+ | `PointPlot` | `PointMark` |
437
+ | `AreaPlot` | `AreaMark` |
438
+ | `RulePlot` | `RuleMark` |
439
+ | `RectanglePlot` | `RectangleMark` |
440
+ | `SectorPlot` | `SectorMark` |
738
441
 
739
442
  ## Dark Mode and Theming
740
443
 
741
- ### Automatic adaptation
742
-
743
- Swift Charts inherits the current color scheme automatically. System colors
744
- (`.blue`, `.orange`, `.green`) adapt to light and dark modes without extra code.
745
-
746
- ### Custom color palettes
747
-
748
- Use `.chartForegroundStyleScale` to define a consistent palette:
444
+ Charts follow the colour scheme, and system colours adapt on their own.
749
445
 
750
446
  ```swift
751
- Chart(data) { item in
752
- BarMark(
753
- x: .value("Category", item.category),
754
- y: .value("Value", item.value)
755
- )
756
- .foregroundStyle(by: .value("Category", item.category))
447
+ Chart(spending) { entry in
448
+ BarMark(x: .value("Period", entry.period), y: .value("Spent", entry.amount))
449
+ .foregroundStyle(by: .value("Kind", entry.kind))
757
450
  }
758
451
  .chartForegroundStyleScale([
759
- "Electronics": .blue,
760
- "Clothing": .purple,
761
- "Food": .orange,
762
- "Books": .green,
763
- "Other": .gray
452
+ "Food": Color.orange,
453
+ "Travel": Color.teal,
454
+ "Home": Color.purple,
764
455
  ])
765
- ```
766
-
767
- ### Background and plot area styling
768
-
769
- ```swift
770
- Chart(data) { ... }
771
- .chartPlotStyle { plotArea in
772
- plotArea
773
- .background(.quaternary.opacity(0.3))
774
- .border(.quaternary, width: 0.5)
456
+ .chartPlotStyle { plot in
457
+ plot.background(.quaternary.opacity(0.3))
458
+ .border(.separator, width: 0.5)
775
459
  }
776
- ```
777
-
778
- ### Axis styling
779
-
780
- ```swift
781
460
  .chartXAxisStyle { axis in
782
- axis.background(.blue.opacity(0.05))
783
- }
784
- ```
785
-
786
- ### Testing dark mode
787
-
788
- Always preview charts in both light and dark color schemes. In Xcode previews:
789
-
790
- ```swift
791
- #Preview {
792
- ChartView()
793
- .preferredColorScheme(.dark)
461
+ axis.background(.thinMaterial)
794
462
  }
795
463
  ```
796
464
 
797
- Verify:
798
- - Axis labels and grid lines are readable.
799
- - Data colors maintain sufficient contrast.
800
- - Annotations and legend text adapt properly.
801
-
802
- ---
465
+ `chartForegroundStyleScale` fixes one colour per category across the app.
466
+ Preview both schemes (`.preferredColorScheme(.dark)` in a `#Preview`) and check
467
+ that labels and grid lines stay readable, data keeps its contrast, and
468
+ annotations and legends adapt.
803
469
 
804
- ## Heat Map Pattern
470
+ ## Heat Map
805
471
 
806
472
  ```swift
807
- Chart(heatMapData) { item in
808
- RectangleMark(
809
- x: .value("Hour", item.hour),
810
- y: .value("Day", item.day)
811
- )
812
- .foregroundStyle(by: .value("Count", item.count))
473
+ Chart(bookings) { cell in
474
+ RectangleMark(x: .value("Hour", cell.hour), y: .value("Weekday", cell.weekday))
475
+ .foregroundStyle(by: .value("Bookings", cell.count))
813
476
  }
814
- .chartForegroundStyleScale(range: Gradient(colors: [.blue, .yellow, .red]))
815
- ```
816
-
817
- ---
818
-
819
- ## Stacking Methods
820
-
821
- | Method | Behavior |
822
- |---|---|
823
- | `.standard` | Default. Regions stack on top showing absolute values. |
824
- | `.normalized` | Scales to 0-100% proportional view. |
825
- | `.center` | Baseline centered (streamgraph). |
826
- | `.unstacked` | Overlapping; no stacking. |
827
-
828
- ```swift
829
- AreaMark(
830
- x: .value("Date", item.date),
831
- y: .value("Revenue", item.revenue),
832
- stacking: .normalized
833
- )
834
- .foregroundStyle(by: .value("Category", item.category))
477
+ .chartForegroundStyleScale(range: Gradient(colors: [.mint, .yellow, .orange]))
835
478
  ```
836
479
 
837
- ---
838
-
839
- ## MarkDimension Options
480
+ ## Stacking
840
481
 
841
- | Dimension | Description |
842
- |---|---|
843
- | `.automatic` | Framework decides |
844
- | `.fixed(CGFloat)` | Exact pixel size |
845
- | `.inset(CGFloat)` | Inset from available space |
846
- | `.ratio(CGFloat)` | Proportion of available space (0...1) |
482
+ Pass `stacking:` to `BarMark` or `AreaMark`:
847
483
 
848
- Use for `width`, `height` on `BarMark` and `innerRadius`, `outerRadius` on `SectorMark`.
484
+ | Value | Effect |
485
+ |-------|--------|
486
+ | `.standard` | Absolute values stacked on each other (default) |
487
+ | `.normalized` | Each stack fills 0 to 100 percent |
488
+ | `.center` | Stacks centred on a baseline, as in a streamgraph |
489
+ | `.unstacked` | Series overlap instead of stacking |
849
490
 
850
- ---
491
+ ## `MarkDimension`
851
492
 
852
- ## Symbol Configuration
493
+ `.automatic`, `.fixed(CGFloat)`, `.inset(CGFloat)` and `.ratio(CGFloat)` with a
494
+ ratio between 0 and 1. Used for `width` and `height` on `BarMark` and for
495
+ `innerRadius` and `outerRadius` on `SectorMark`.
853
496
 
854
- ### Built-in shapes
497
+ ## Symbols
855
498
 
856
- `circle`, `square`, `triangle`, `diamond`, `pentagon`, `plus`, `cross`, `asterisk`
499
+ The built-in shapes are `asterisk`, `circle`, `cross`, `diamond`, `pentagon`,
500
+ `plus`, `square` and `triangle`.
857
501
 
858
502
  ```swift
859
- PointMark(x: .value("X", item.x), y: .value("Y", item.y))
503
+ PointMark(x: .value("Speed", run.speed), y: .value("Heart rate", run.bpm))
860
504
  .symbol(.diamond)
861
505
  .symbolSize(80)
862
- ```
863
506
 
864
- ### Data-driven symbol encoding
507
+ PointMark(x: .value("Speed", run.speed), y: .value("Heart rate", run.bpm))
508
+ .symbol(by: .value("Surface", run.surface))
865
509
 
866
- ```swift
867
- PointMark(x: .value("X", item.x), y: .value("Y", item.y))
868
- .symbol(by: .value("Category", item.category))
510
+ PointMark(x: .value("Speed", run.speed), y: .value("Heart rate", run.bpm))
511
+ .symbol { Image(systemName: "figure.run").font(.caption2) }
869
512
  ```
870
513
 
871
- ### Custom symbol view
514
+ ## `ChartProxy` and Coordinates
872
515
 
873
- ```swift
874
- PointMark(x: .value("X", item.x), y: .value("Y", item.y))
875
- .symbol {
876
- Image(systemName: "star.fill")
877
- .font(.caption2)
878
- }
879
- ```
880
-
881
- ---
882
-
883
- ## ChartProxy and Coordinate Conversion
884
-
885
- Use `chartOverlay` or `chartBackground` to access `ChartProxy`:
516
+ `chartOverlay` and `chartBackground` pass a `ChartProxy` that converts between
517
+ screen positions and data values. Since iOS 17, `plotFrame` (an optional
518
+ anchor) and `plotSize` replace the deprecated `plotAreaFrame` and
519
+ `plotAreaSize`.
886
520
 
887
521
  ```swift
888
522
  .chartOverlay { proxy in
@@ -891,86 +525,41 @@ Use `chartOverlay` or `chartBackground` to access `ChartProxy`:
891
525
  .fill(.clear)
892
526
  .contentShape(Rectangle())
893
527
  .gesture(
894
- DragGesture()
895
- .onChanged { value in
896
- let origin = geometry[proxy.plotAreaFrame].origin
897
- let location = CGPoint(
898
- x: value.location.x - origin.x,
899
- y: value.location.y - origin.y
900
- )
901
- if let date: Date = proxy.value(atX: location.x) {
902
- selectedDate = date
903
- }
904
- }
528
+ DragGesture(minimumDistance: 0).onChanged { drag in
529
+ guard let plotFrame = proxy.plotFrame else { return }
530
+ let origin = geometry[plotFrame].origin
531
+ let x = drag.location.x - origin.x
532
+ scrubbedDate = proxy.value(atX: x, as: Date.self)
533
+ }
905
534
  )
906
535
  }
907
536
  }
908
537
  ```
909
538
 
910
- ### Key ChartProxy methods
911
-
912
- | Method | Purpose |
913
- |---|---|
914
- | `position(forX:)` | Data value to screen x-coordinate |
915
- | `position(forY:)` | Data value to screen y-coordinate |
916
- | `value(atX:as:)` | Screen x-coordinate to data value |
917
- | `value(atY:as:)` | Screen y-coordinate to data value |
918
- | `plotAreaSize` | Size of the plot area |
919
- | `plotAreaFrame` | Anchor for the plot area frame |
920
-
921
- ---
922
-
923
- ## Quick Reference: Chart View Modifiers
924
-
925
- ### Axes
926
- - `chartXAxis(_:)` / `chartXAxis(content:)`
927
- - `chartYAxis(_:)` / `chartYAxis(content:)`
928
- - `chartXAxisLabel(...)` / `chartYAxisLabel(...)`
929
- - `chartXAxisStyle(content:)` / `chartYAxisStyle(content:)`
930
-
931
- ### Scales
932
- - `chartXScale(domain:range:type:)` and variants
933
- - `chartYScale(domain:range:type:)` and variants
934
- - `chartZScale(domain:range:type:)` for `Chart3D`
935
- - `chartForegroundStyleScale(_:)` -- custom color mapping
936
-
937
- ### 3D charts (iOS 26+)
938
- - `Chart3D` with `SurfacePlot` or 3D mark initializers
939
- - `chart3DPose(_:)` for interactive pose binding
940
- - `chart3DCameraProjection(_:)` for orthographic/perspective projection
941
-
942
- ### Legend
943
- - `chartLegend(_:)` -- visibility
944
- - `chartLegend(position:alignment:spacing:)` -- positioning
945
- - `chartLegend(position:alignment:spacing:content:)` -- custom content
946
-
947
- ### Selection (iOS 17+)
948
- - `chartXSelection(value:)` / `chartXSelection(range:)`
949
- - `chartYSelection(value:)` / `chartYSelection(range:)`
950
- - `chartAngleSelection(value:)` -- for `SectorMark`
951
-
952
- ### Scrolling (iOS 17+)
953
- - `chartScrollableAxes(_:)`
954
- - `chartXVisibleDomain(length:)` / `chartYVisibleDomain(length:)`
955
- - `chartScrollPosition(initialX:)` / `chartScrollPosition(x:)`
956
- - `chartScrollTargetBehavior(_:)`
957
-
958
- ### Overlay and Background
959
- - `chartOverlay(alignment:content:)` -- with `ChartProxy`
960
- - `chartBackground(alignment:content:)` -- with `ChartProxy`
961
- - `chartPlotStyle(content:)` -- plot area styling
962
-
963
- ---
964
-
965
- ## Apple Documentation Links
966
-
967
- - [Swift Charts](https://sosumi.ai/documentation/charts)
968
- - [Creating a chart using Swift Charts](https://sosumi.ai/documentation/charts/Creating-a-chart-using-Swift-Charts)
969
- - [BarMark](https://sosumi.ai/documentation/charts/BarMark)
970
- - [LineMark](https://sosumi.ai/documentation/charts/LineMark)
971
- - [SectorMark](https://sosumi.ai/documentation/charts/SectorMark)
972
- - [Chart3D](https://sosumi.ai/documentation/charts/Chart3D)
973
- - [SurfacePlot](https://sosumi.ai/documentation/charts/SurfacePlot)
974
- - [LinePlot](https://sosumi.ai/documentation/charts/LinePlot)
975
- - [AxisMarks](https://sosumi.ai/documentation/charts/AxisMarks)
976
- - [Swift Charts updates](https://sosumi.ai/documentation/updates/swiftcharts)
539
+ Proxy methods: `position(forX:)`, `position(forY:)`, `value(atX:as:)`,
540
+ `value(atY:as:)`, plus `plotSize` and `plotFrame`.
541
+
542
+ ## Modifier Quick Reference
543
+
544
+ | Area | Modifiers |
545
+ |------|-----------|
546
+ | Axes | hide or replace: `chartYAxis(_:)`, `chartXAxis(_:)`, and the builder forms `chartYAxis(content:)`, `chartXAxis(content:)`; titles: `chartYAxisLabel`, `chartXAxisLabel`; axis area styling: `chartYAxisStyle(content:)`, `chartXAxisStyle(content:)` |
547
+ | Scales | `chartYScale(domain:range:type:)`, `chartXScale(domain:range:type:)`; for `Chart3D` also `chartZScale(domain:range:type:)`; categorical colours with `chartForegroundStyleScale(_:)` |
548
+ | 3D | `chart3DCameraProjection(_:)` (perspective or orthographic), `chart3DPose(_:)` |
549
+ | Legend | `chartLegend(_:)` for visibility; `chartLegend(position:alignment:spacing:)` for placement; add `content:` for a custom legend view |
550
+ | Selection (iOS 17) | a single value: `chartXSelection(value:)`, `chartYSelection(value:)`; a span: `chartXSelection(range:)`, `chartYSelection(range:)`; pie slices: `chartAngleSelection(value:)` |
551
+ | Scrolling (iOS 17) | turn on with `chartScrollableAxes(_:)`; window size with `chartXVisibleDomain(length:)` or `chartYVisibleDomain(length:)`; position with `chartScrollPosition(initialX:)` or a bound `chartScrollPosition(x:)`; snapping with `chartScrollTargetBehavior(_:)` |
552
+ | Plot area and layers | `chartPlotStyle(content:)`, `chartBackground(alignment:content:)`, `chartOverlay(alignment:content:)` |
553
+
554
+ ## Apple Documentation
555
+
556
+ - [Swift Charts](https://developer.apple.com/documentation/charts)
557
+ - [Building a first chart](https://developer.apple.com/documentation/charts/creating-a-chart-using-swift-charts)
558
+ - [BarMark](https://developer.apple.com/documentation/charts/barmark)
559
+ - [LineMark](https://developer.apple.com/documentation/charts/linemark)
560
+ - [SectorMark](https://developer.apple.com/documentation/charts/sectormark)
561
+ - [Chart3D](https://developer.apple.com/documentation/charts/chart3d)
562
+ - [SurfacePlot](https://developer.apple.com/documentation/charts/surfaceplot)
563
+ - [LinePlot](https://developer.apple.com/documentation/charts/lineplot)
564
+ - [AxisMarks](https://developer.apple.com/documentation/charts/axismarks)
565
+ - [Swift Charts updates](https://developer.apple.com/documentation/updates/swiftcharts)