@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,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)