@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,31 +1,37 @@
1
- # FormatStyle & Locale-Aware Formatting
1
+ # FormatStyle, Locale and Layout Direction
2
2
 
3
- Comprehensive reference for locale-aware formatting in iOS 15+ using `FormatStyle`. Never hard-code date, number, or measurement formats -- these break in every locale except the one you tested. `ios-localization` owns `FormatStyle` guidance when the issue is locale-aware user-facing display: numbers, dates, currency, units, names, lists, calendars, separators, and locale preview/testing. Locale-aware formatting matters even in single-language apps; explicitly recommend testing or previewing user-facing output under multiple locales. Use the `swift-formatstyle` skill for broader standalone FormatStyle API design.
3
+ `FormatStyle` needs iOS 15 or later. This skill uses it for locale-aware
4
+ display: numbers, dates, currency, units, names, lists, calendars and
5
+ separators, plus previews and tests across locales. Custom `FormatStyle`
6
+ types, `ParseableFormatStyle`, parsing, `Date.IntervalFormatStyle`,
7
+ `URL.FormatStyle` and reusable formatter API design belong to
8
+ `swift-formatstyle`; here they only get locale risks and testing advice unless
9
+ someone asks for the implementation. Whatever the value, recommend previewing
10
+ it in several locales such as `en_US`, `de_DE`, `ar_SA` and `ja_JP`.
4
11
 
5
12
  ## Contents
6
13
 
7
- - [Date Formatting](#date-formatting)
8
- - [Number Formatting](#number-formatting)
9
- - [Measurement Formatting](#measurement-formatting)
10
- - [Duration Formatting](#duration-formatting)
11
- - [PersonNameComponents Formatting](#personnamecomponents-formatting)
12
- - [ByteCountFormatStyle](#bytecountformatstyle)
13
- - [ListFormatStyle](#listformatstyle)
14
- - [Custom FormatStyle Implementation](#custom-formatstyle-implementation)
15
- - [Forcing a Specific Locale](#forcing-a-specific-locale)
16
- - [RTL Layout Deep Dive](#rtl-layout-deep-dive)
17
- - [`@ScaledMetric for Dynamic Type`](#scaledmetric-for-dynamic-type)
18
- - [Layout Testing with Accessibility Inspector](#layout-testing-with-accessibility-inspector)
19
- - [Quick Reference Table](#quick-reference-table)
20
-
21
- ## Migration from Legacy Formatters
22
-
23
- `FormatStyle` (iOS 15+) replaces the older `Formatter` subclasses. If you encounter legacy code, migrate to `FormatStyle`:
24
-
25
- | Legacy | Modern replacement |
26
- |--------|-------------------|
27
- | `DateFormatter` | `.formatted(.dateTime...)` or `Date.FormatStyle` |
28
- | `NumberFormatter` | `.formatted(.number...)` or `IntegerFormatStyle` / `FloatingPointFormatStyle` |
14
+ 1. [Replacing legacy formatters](#replacing-legacy-formatters)
15
+ 2. [Dates](#dates)
16
+ 3. [Numbers](#numbers)
17
+ 4. [Measurements](#measurements)
18
+ 5. [Durations](#durations)
19
+ 6. [Person names](#person-names)
20
+ 7. [Byte counts](#byte-counts)
21
+ 8. [Lists](#lists)
22
+ 9. [Custom styles](#custom-styles)
23
+ 10. [Pinning a locale](#pinning-a-locale)
24
+ 11. [Right-to-left in depth](#right-to-left-in-depth)
25
+ 12. [ScaledMetric and Dynamic Type](#scaledmetric-and-dynamic-type)
26
+ 13. [Checking layout with Accessibility Inspector](#checking-layout-with-accessibility-inspector)
27
+ 14. [Cheat sheet](#cheat-sheet)
28
+
29
+ ## Replacing legacy formatters
30
+
31
+ | Old formatter | FormatStyle replacement |
32
+ |---|---|
33
+ | `DateFormatter` | `.formatted(.dateTime...)`, `Date.FormatStyle` |
34
+ | `NumberFormatter` | `.formatted(.number...)`, `IntegerFormatStyle`, `FloatingPointFormatStyle` |
29
35
  | `DateComponentsFormatter` | `Duration.formatted(.units(...))` or `.time(pattern:)` |
30
36
  | `MeasurementFormatter` | `Measurement.formatted(.measurement(...))` |
31
37
  | `DateIntervalFormatter` | `(start..<end).formatted(date:time:)` |
@@ -33,612 +39,398 @@ Comprehensive reference for locale-aware formatting in iOS 15+ using `FormatStyl
33
39
  | `ByteCountFormatter` | `.formatted(.byteCount(style:))` |
34
40
  | `ListFormatter` | `.formatted(.list(type:))` |
35
41
 
36
- `FormatStyle` is value-type, `Sendable`, composable, and works directly in SwiftUI `Text` views. The legacy formatters are reference types that require manual locale and calendar configuration.
42
+ Format styles are value types, `Sendable` and composable, and SwiftUI `Text`
43
+ accepts them directly. The old formatters are classes whose locale and calendar
44
+ you had to configure and share by hand.
37
45
 
38
- ## Date Formatting
46
+ ## Dates
39
47
 
40
- ### Preset date and time styles
48
+ Presets:
41
49
 
42
50
  ```swift
43
- let date = Date.now
44
-
45
- // Date only
46
- date.formatted(date: .numeric, time: .omitted) // "1/15/2026" (US) / "15.01.2026" (DE)
47
- date.formatted(date: .abbreviated, time: .omitted) // "Jan 15, 2026" (US) / "15. Jan. 2026" (DE)
48
- date.formatted(date: .long, time: .omitted) // "January 15, 2026" (US) / "15. Januar 2026" (DE)
49
- date.formatted(date: .complete, time: .omitted) // "Thursday, January 15, 2026" (US)
50
-
51
- // Time only
52
- date.formatted(date: .omitted, time: .shortened) // "3:30 PM" (US) / "15:30" (DE)
53
- date.formatted(date: .omitted, time: .standard) // "3:30:45 PM" (US) / "15:30:45" (DE)
54
- date.formatted(date: .omitted, time: .complete) // includes time zone
55
-
56
- // Combined
57
- date.formatted(date: .long, time: .shortened) // "January 15, 2026 at 3:30 PM"
58
- date.formatted() // platform default
59
- ```
60
-
61
- ### Component-based date formatting
51
+ let pickup = Date.now
62
52
 
63
- Build custom date formats by composing components. The system reorders components for each locale.
53
+ pickup.formatted(date: .numeric, time: .omitted) // 6/3/2026
54
+ pickup.formatted(date: .abbreviated, time: .omitted) // Jun 3, 2026
55
+ pickup.formatted(date: .long, time: .omitted) // June 3, 2026
56
+ pickup.formatted(date: .complete, time: .omitted) // Wednesday, June 3, 2026
64
57
 
65
- ```swift
66
- // Month and day
67
- date.formatted(.dateTime.month().day()) // "Jan 15" (US) / "15 Jan" (UK)
68
-
69
- // Full date with weekday
70
- date.formatted(.dateTime.weekday(.wide).month(.wide).day().year())
71
- // "Thursday, January 15, 2026" (US) / "Donnerstag, 15. Januar 2026" (DE)
72
-
73
- // Month name styles
74
- date.formatted(.dateTime.month(.wide)) // "January"
75
- date.formatted(.dateTime.month(.abbreviated)) // "Jan"
76
- date.formatted(.dateTime.month(.narrow)) // "J"
77
- date.formatted(.dateTime.month(.twoDigits)) // "01"
78
-
79
- // Day styles
80
- date.formatted(.dateTime.day(.twoDigits)) // "15"
81
- date.formatted(.dateTime.day(.ordinalOfDayInMonth)) // "3" (third Thursday)
82
-
83
- // Year
84
- date.formatted(.dateTime.year(.defaultDigits)) // "2026"
85
- date.formatted(.dateTime.year(.twoDigits)) // "26"
86
-
87
- // Hour/minute
88
- date.formatted(.dateTime.hour().minute()) // "3:30 PM" (US, 12h) / "15:30" (DE, 24h)
89
- date.formatted(.dateTime.hour(.defaultDigits(amPM: .omitted)).minute()) // "3:30"
58
+ pickup.formatted(date: .omitted, time: .shortened) // 9:40 AM
59
+ pickup.formatted(date: .omitted, time: .standard) // 9:40:12 AM
60
+ pickup.formatted(date: .omitted, time: .complete) // adds the time zone
61
+ pickup.formatted() // platform default
90
62
  ```
91
63
 
92
- ### SwiftUI date display
64
+ Components: list what you want and the system arranges it for the locale.
93
65
 
94
66
  ```swift
95
- // Automatic format
96
- Text(event.date, format: .dateTime.month().day().year())
97
-
98
- // Date range
99
- Text(event.start...event.end) // "Jan 15 - Jan 20, 2026"
100
-
101
- // Relative (auto-updates)
102
- Text(event.date, style: .relative) // "2 hours ago", "in 3 days"
103
- Text(event.date, style: .timer) // counts up/down live
104
- Text(event.date, style: .offset) // "+2 hours" / "-3 days"
67
+ pickup.formatted(.dateTime.weekday(.abbreviated).day().month(.wide))
68
+ pickup.formatted(.dateTime.month(.narrow)) // "J"
69
+ pickup.formatted(.dateTime.month(.twoDigits).day(.twoDigits))
70
+ pickup.formatted(.dateTime.day(.ordinalOfDayInMonth)) // first Wednesday -> 1
71
+ pickup.formatted(.dateTime.year(.twoDigits))
72
+ pickup.formatted(.dateTime.year(.defaultDigits))
73
+ pickup.formatted(.dateTime.hour().minute()) // 12h or 24h per locale
74
+ pickup.formatted(.dateTime.hour(.defaultDigits(amPM: .omitted)).minute())
105
75
  ```
106
76
 
107
- ### Relative date formatting
108
-
109
- ```swift
110
- // Relative (named style)
111
- let relative = date.formatted(.relative(presentation: .named))
112
- // "yesterday", "today", "tomorrow", "last Friday", "in 2 weeks"
113
-
114
- // Relative (numeric style)
115
- let relativeNum = date.formatted(.relative(presentation: .numeric))
116
- // "1 day ago", "in 2 days", "3 weeks ago"
117
-
118
- // Relative with specific units
119
- let relativeCustom = date.formatted(.relative(presentation: .named, unitsStyle: .wide))
120
- ```
77
+ `month(_:)` takes `.wide`, `.abbreviated`, `.narrow`, `.twoDigits`. `day(_:)`
78
+ takes `.twoDigits` or `.ordinalOfDayInMonth`, which counts which occurrence of
79
+ that weekday the date is in the month.
121
80
 
122
- ### Date ranges and intervals
81
+ In SwiftUI:
123
82
 
124
83
  ```swift
125
- let start = Date.now
126
- let end = Calendar.current.date(byAdding: .day, value: 5, to: start)!
127
-
128
- // Range formatting
129
- (start..<end).formatted(date: .abbreviated, time: .omitted)
130
- // "Jan 15 - 20, 2026" (smart about shared month/year)
131
-
132
- // Duration of interval
133
- (start..<end).formatted(.components(style: .wide))
134
- // "5 days"
84
+ Text(pickup, format: .dateTime.day().month())
85
+ Text(pickup...pickup.addingTimeInterval(7_200)) // a range
86
+ Text(pickup, style: .relative) // updates itself
87
+ Text(pickup, style: .timer) // counts live
88
+ Text(pickup, style: .offset)
135
89
  ```
136
90
 
137
- ### ISO 8601 (for APIs, not for display)
91
+ Relative phrasing:
138
92
 
139
93
  ```swift
140
- // For serialization to APIs -- NOT for user-facing display
141
- date.formatted(.iso8601) // "2026-01-15T15:30:45Z"
142
- date.formatted(.iso8601.dateSeparator(.dash).timeSeparator(.colon))
94
+ let lastSync = Date.now.addingTimeInterval(-86_400)
95
+ lastSync.formatted(.relative(presentation: .named)) // "yesterday"
96
+ lastSync.formatted(.relative(presentation: .numeric)) // "1 day ago"
97
+ lastSync.formatted(.relative(presentation: .numeric, unitsStyle: .wide))
143
98
  ```
144
99
 
145
- ## Number Formatting
146
-
147
- ### Integer and decimal
100
+ Ranges:
148
101
 
149
102
  ```swift
150
- let value = 1234567
151
-
152
- value.formatted() // "1,234,567" (US) / "1.234.567" (DE) / "1 234 567" (FR)
153
- value.formatted(.number.grouping(.never)) // "1234567"
154
- value.formatted(.number.precision(.significantDigits(3))) // "1,230,000"
155
-
156
- let decimal = 3.14159
157
- decimal.formatted(.number.precision(.fractionLength(2))) // "3.14"
158
- decimal.formatted(.number.precision(.fractionLength(0...3))) // "3.142"
159
-
160
- // Notation
161
- value.formatted(.number.notation(.compactName)) // "1.2M" (US) / "1,2 Mio." (DE)
162
- value.formatted(.number.notation(.scientific)) // "1.234567E6"
103
+ let checkIn = Date.now
104
+ let checkOut = checkIn.addingTimeInterval(4 * 86_400)
105
+ (checkIn..<checkOut).formatted(date: .abbreviated, time: .omitted)
106
+ // shared month and year are written once: "Jun 3 - 7, 2026"
107
+ (checkIn..<checkOut).formatted(.components(style: .wide)) // "4 days"
163
108
  ```
164
109
 
165
- ### Rounding
110
+ ISO 8601 is for the wire, never for people:
166
111
 
167
112
  ```swift
168
- let num = 3.456
169
-
170
- // Round to 2 fraction digits
171
- num.formatted(.number.precision(.fractionLength(2)).rounded(rule: .up)) // "3.46"
172
- num.formatted(.number.precision(.fractionLength(2)).rounded(rule: .down)) // "3.45"
173
- num.formatted(.number.precision(.fractionLength(2)).rounded(rule: .toNearestOrEven)) // "3.46"
113
+ pickup.formatted(.iso8601.dateSeparator(.dash).timeSeparator(.colon))
174
114
  ```
175
115
 
176
- ### Percent
116
+ ## Numbers
177
117
 
178
- ```swift
179
- let ratio = 0.856
180
-
181
- ratio.formatted(.percent) // "86%" (US) / "86 %" (FR)
182
- ratio.formatted(.percent.precision(.fractionLength(1))) // "85.6%"
183
-
184
- // Integer percentage
185
- let score = 92
186
- score.formatted(.percent) // "9,200%" -- probably not what you want!
187
- // For integer percentages, divide first:
188
- (Double(score) / 100).formatted(.percent) // "92%"
189
- ```
190
-
191
- ### Currency
192
-
193
- Always specify the currency code explicitly. The locale controls formatting (symbol position, decimal separator), but the currency code determines the currency.
118
+ Grouping follows the locale: 2,500,000 in the US, 2.500.000 in Germany,
119
+ 2 500 000 in France.
194
120
 
195
121
  ```swift
196
- let price = Decimal(29.99)
122
+ 2_500_000.formatted() // locale grouping
123
+ 2_500_000.formatted(.number.grouping(.never)) // 2500000
197
124
 
198
- // Explicit currency code (recommended)
199
- price.formatted(.currency(code: "USD")) // "$29.99" (US) / "29,99 $US" (FR) / "US$29.99" (AU)
200
- price.formatted(.currency(code: "EUR")) // "EUR29.99" (US) / "29,99 EUR" (DE) / "29,99 EUR" (FR)
201
- price.formatted(.currency(code: "JPY")) // "JPY30" (no decimals for yen)
125
+ 0.004218.formatted(.number.precision(.significantDigits(3))) // 0.00422
126
+ 72.5.formatted(.number.precision(.fractionLength(2))) // 72.50
127
+ 72.5.formatted(.number.precision(.fractionLength(0...3))) // 72.5
202
128
 
203
- // Narrow symbol (when space is limited)
204
- price.formatted(.currency(code: "USD").presentation(.narrow)) // "$29.99" even in non-US locales
129
+ 4_300_000.formatted(.number.notation(.compactName)) // "4.3M", German "4,3 Mio."
130
+ 6_022.0.formatted(.number.notation(.scientific))
205
131
 
206
- // In SwiftUI
207
- Text(price, format: .currency(code: order.currencyCode))
132
+ 18.6.formatted(.number.rounded(rule: .up, increment: 1)) // 19
133
+ 18.6.formatted(.number.rounded(rule: .down, increment: 1)) // 18
134
+ 18.5.formatted(.number.rounded(rule: .toNearestOrEven, increment: 1)) // 18
208
135
  ```
209
136
 
210
- **Important:** Use `Decimal` (not `Double`) for monetary values to avoid floating-point precision errors.
137
+ Without `increment:` (or a `.precision` of zero fraction digits) the rule only
138
+ applies at the style's default precision, so `18.6` still prints "18.6".
211
139
 
212
- ### Ordinal numbers
140
+ Percent multiplies by 100. The integer `92` with `.percent` prints
141
+ "9,200%". Convert to a fraction first:
213
142
 
214
143
  ```swift
215
- let position = 3
216
- position.formatted(.number.notation(.ordinal)) // "3rd" (EN) / "3." (DE) / "3e" (FR)
144
+ let batteryLevel = 92
145
+ (Double(batteryLevel) / 100).formatted(.percent) // "92%"
146
+ 0.1275.formatted(.percent.precision(.fractionLength(1))) // "12.8%"
217
147
  ```
218
148
 
219
- ## Measurement Formatting
220
-
221
- The system auto-converts units based on locale (metric vs imperial) unless you opt out.
222
-
223
- ### Length / distance
149
+ Currency: always pass `code:`. The code picks the currency; the locale only
150
+ decides where the symbol goes and which separators are used.
224
151
 
225
152
  ```swift
226
- let distance = Measurement(value: 5, unit: UnitLength.kilometers)
227
-
228
- distance.formatted(.measurement(width: .wide))
229
- // US: "3.1 miles" (auto-converts to imperial!)
230
- // DE: "5 Kilometer"
231
- // JP: "5 km" (with .abbreviated)
232
-
233
- distance.formatted(.measurement(width: .abbreviated)) // "3.1 mi" (US) / "5 km" (DE)
234
- distance.formatted(.measurement(width: .narrow)) // "3.1mi" (US) / "5km" (DE)
235
-
236
- // Prevent auto-conversion (keep original unit)
237
- distance.formatted(.measurement(width: .wide, usage: .asProvided))
238
- // US: "5 kilometers" (keeps km even in US locale)
153
+ let fare = Decimal(124_950) / 100
154
+ fare.formatted(.currency(code: "USD")) // $1,249.50 in en_US
155
+ fare.formatted(.currency(code: "EUR")) // de_DE: "1.249,50" then the euro sign
156
+ Decimal(3200).formatted(.currency(code: "JPY")) // no decimals for yen
157
+ fare.formatted(.currency(code: "CAD").presentation(.narrow)) // "$" when space is tight
158
+ Text(fare, format: .currency(code: "GBP"))
239
159
  ```
240
160
 
241
- ### Weight / mass
242
-
243
- ```swift
244
- let weight = Measurement(value: 75, unit: UnitMass.kilograms)
161
+ Money belongs in `Decimal`, not `Double`, so binary rounding never shows up in
162
+ a price.
245
163
 
246
- weight.formatted(.measurement(width: .wide))
247
- // US: "165.3 pounds" / DE: "75 Kilogramm"
248
-
249
- weight.formatted(.measurement(width: .abbreviated, usage: .personWeight))
250
- // Uses locale-appropriate unit for body weight
251
- ```
252
-
253
- ### Temperature
164
+ Ordinals: the iOS 26.4 SDK has no ordinal `FormatStyle` (`.number.notation`
165
+ offers only `.automatic`, `.compactName` and `.scientific`), so this is the one
166
+ case that still uses `NumberFormatter`:
254
167
 
255
168
  ```swift
256
- let temp = Measurement(value: 22, unit: UnitTemperature.celsius)
257
-
258
- temp.formatted(.measurement(width: .abbreviated))
259
- // US: "72 F" (auto-converts!) / FR: "22 C" / DE: "22 C"
260
-
261
- // Weather-specific (ensures locale-correct unit)
262
- temp.formatted(.measurement(width: .abbreviated, usage: .weather))
169
+ let ordinals = NumberFormatter()
170
+ ordinals.numberStyle = .ordinal
171
+ ordinals.string(from: 3) // "3rd", German "3.", French "3e"
263
172
  ```
264
173
 
265
- ### Speed
174
+ ## Measurements
266
175
 
267
- ```swift
268
- let speed = Measurement(value: 100, unit: UnitSpeed.kilometersPerHour)
269
- speed.formatted(.measurement(width: .abbreviated))
270
- // US: "62.1 mph" / DE: "100 km/h"
271
- ```
272
-
273
- ### Volume
176
+ Units convert to the locale's system (metric or imperial) unless you opt out.
274
177
 
275
178
  ```swift
276
- let volume = Measurement(value: 500, unit: UnitVolume.milliliters)
277
- volume.formatted(.measurement(width: .abbreviated, usage: .drink))
278
- // US: "16.9 fl oz" / DE: "500 ml"
279
- ```
179
+ let hike = Measurement(value: 12.4, unit: UnitLength.kilometers)
180
+ hike.formatted(.measurement(width: .wide)) // "7.7 miles" in en_US
181
+ hike.formatted(.measurement(width: .abbreviated)) // "7.7 mi"
182
+ hike.formatted(.measurement(width: .narrow)) // "7.7mi"
183
+ hike.formatted(.measurement(width: .wide, usage: .asProvided)) // keeps km
280
184
 
281
- ## Duration Formatting
185
+ let luggage = Measurement(value: 23, unit: UnitMass.kilograms)
186
+ luggage.formatted(.measurement(width: .abbreviated, usage: .personWeight))
282
187
 
283
- ### Time pattern
188
+ let outside = Measurement(value: 28, unit: UnitTemperature.celsius)
189
+ outside.formatted(.measurement(width: .abbreviated, usage: .weather)) // F in en_US
284
190
 
285
- ```swift
286
- let dur = Duration.seconds(3661) // 1 hour, 1 minute, 1 second
191
+ let windSpeed = Measurement(value: 40, unit: UnitSpeed.kilometersPerHour)
192
+ windSpeed.formatted(.measurement(width: .abbreviated)) // mph in en_US
287
193
 
288
- dur.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01"
289
- dur.formatted(.time(pattern: .hourMinute)) // "1:01"
290
- dur.formatted(.time(pattern: .minuteSecond)) // "61:01"
194
+ let bottle = Measurement(value: 500, unit: UnitVolume.milliliters)
195
+ bottle.formatted(.measurement(width: .abbreviated, usage: .liquid)) // "1.1 pt" in en_US
291
196
  ```
292
197
 
293
- ### Units style (iOS 16+)
294
-
295
- ```swift
296
- dur.formatted(.units(allowed: [.hours, .minutes], width: .wide))
297
- // "1 hour, 1 minute" (EN) / "1 Stunde, 1 Minute" (DE)
198
+ Usage hints such as `.personWeight`, `.weather` and `.liquid` (iOS 16) choose
199
+ the unit people expect for that kind of value.
298
200
 
299
- dur.formatted(.units(allowed: [.hours, .minutes], width: .abbreviated))
300
- // "1 hr, 1 min" (EN) / "1 Std., 1 Min." (DE)
201
+ ## Durations
301
202
 
302
- dur.formatted(.units(allowed: [.hours, .minutes], width: .narrow))
303
- // "1h 1m"
304
-
305
- // Maximum unit count
306
- dur.formatted(.units(allowed: [.hours, .minutes, .seconds],
307
- width: .abbreviated,
308
- maximumUnitCount: 2))
309
- // "1 hr, 1 min" (drops seconds)
203
+ ```swift
204
+ let workout = Duration.seconds(3_725)
205
+ workout.formatted(.time(pattern: .hourMinuteSecond)) // "1:02:05"
206
+ workout.formatted(.time(pattern: .hourMinute)) // "1:02"
207
+ workout.formatted(.time(pattern: .minuteSecond)) // "62:05", minutes may pass 59
208
+
209
+ // iOS 16+
210
+ workout.formatted(.units(allowed: [.hours, .minutes], width: .wide)) // "1 hour, 2 minutes"
211
+ workout.formatted(.units(allowed: [.hours, .minutes, .seconds], width: .abbreviated))
212
+ workout.formatted(.units(width: .narrow, maximumUnitCount: 1)) // "1h"
310
213
  ```
311
214
 
312
- ## PersonNameComponents Formatting
215
+ Widths are `.wide`, `.abbreviated` and `.narrow`; `maximumUnitCount:` drops the
216
+ smaller units.
313
217
 
314
- Respects locale conventions for name ordering (given-family vs family-given).
218
+ ## Person names
315
219
 
316
220
  ```swift
317
- var name = PersonNameComponents()
318
- name.givenName = "John"
319
- name.familyName = "Appleseed"
320
- name.namePrefix = "Dr."
321
- name.nickname = "Johnny"
322
-
323
- name.formatted(.name(style: .long)) // "Dr. John Appleseed" (US) / "Appleseed John" (JP)
324
- name.formatted(.name(style: .medium)) // "John Appleseed" (US) / "Appleseed John" (JP)
325
- name.formatted(.name(style: .short)) // "John" (US) / "Appleseed" (JP)
326
- name.formatted(.name(style: .abbreviated)) // "JA" (initials)
327
-
328
- // In SwiftUI
329
- Text(name, format: .name(style: .medium))
221
+ var guest = PersonNameComponents()
222
+ guest.namePrefix = "Dr."
223
+ guest.givenName = "Hana"
224
+ guest.familyName = "Sato"
225
+
226
+ guest.formatted(.name(style: .long)) // includes the prefix; order follows locale
227
+ guest.formatted(.name(style: .medium))
228
+ guest.formatted(.name(style: .short)) // "Hana" in en_US
229
+ guest.formatted(.name(style: .abbreviated)) // initials
230
+ Text(guest, format: .name(style: .medium))
330
231
  ```
331
232
 
332
- ## ByteCountFormatStyle
333
-
334
- Format file sizes with locale-appropriate units.
233
+ ## Byte counts
335
234
 
336
235
  ```swift
337
- let bytes: Int64 = 1_536_000
338
-
339
- bytes.formatted(.byteCount(style: .file)) // "1.5 MB"
340
- bytes.formatted(.byteCount(style: .memory)) // "1.46 MB" (uses 1024-based)
341
- bytes.formatted(.byteCount(style: .binary)) // "1.46 MB"
342
-
343
- // Specific allowed units
344
- bytes.formatted(.byteCount(style: .file, allowedUnits: [.kb])) // "1,536 kB"
236
+ let backupSize: Int64 = 3_400_000_000
237
+ backupSize.formatted(.byteCount(style: .file))
238
+ backupSize.formatted(.byteCount(style: .memory)) // 1024-based
239
+ backupSize.formatted(.byteCount(style: .binary))
240
+ Int64(5_120).formatted(.byteCount(style: .file, allowedUnits: [.kb]))
345
241
  ```
346
242
 
347
- ## ListFormatStyle
348
-
349
- Join arrays into grammatically correct lists.
243
+ ## Lists
350
244
 
351
245
  ```swift
352
- let fruits = ["Apples", "Oranges", "Bananas"]
353
-
354
- fruits.formatted(.list(type: .and))
355
- // EN: "Apples, Oranges, and Bananas"
356
- // FR: "Apples, Oranges et Bananas"
357
- // AR: "Apples وOranges وBananas"
246
+ let toppings = ["olives", "basil", "garlic"]
247
+ toppings.formatted(.list(type: .and)) // "olives, basil, and garlic"; French uses "et"
248
+ toppings.formatted(.list(type: .or))
358
249
 
359
- fruits.formatted(.list(type: .or))
360
- // EN: "Apples, Oranges, or Bananas"
250
+ let tips: [Decimal] = [5, 10, 15]
251
+ tips.formatted(.list(memberStyle: .currency(code: "USD"), type: .or))
361
252
 
362
- // With member formatting
363
- let prices = [Decimal(1.99), Decimal(2.49), Decimal(3.99)]
364
- prices.formatted(.list(memberStyle: .currency(code: "USD"), type: .and))
365
- // "$1.99, $2.49, and $3.99"
366
-
367
- // Two items
368
- ["Red", "Blue"].formatted(.list(type: .and))
369
- // "Red and Blue" (no Oxford comma for two items)
253
+ ["olives", "basil"].formatted(.list(type: .and)) // "olives and basil", no serial comma
370
254
  ```
371
255
 
372
- ## Custom FormatStyle Implementation
256
+ ## Custom styles
373
257
 
374
- Create a reusable `FormatStyle` for domain-specific formatting.
258
+ Designing custom and parseable styles is `swift-formatstyle` territory. The
259
+ shape, for recognition:
375
260
 
376
261
  ```swift
377
- struct AbbreviatedCountStyle: FormatStyle {
262
+ struct ScoreFormat: FormatStyle {
378
263
  func format(_ value: Int) -> String {
264
+ let number = Double(value)
265
+ let style = FloatingPointFormatStyle<Double>.number.precision(.fractionLength(0...1))
379
266
  switch value {
380
- case ..<1_000:
381
- return "\(value)"
382
- case 1_000..<1_000_000:
383
- let k = Double(value) / 1_000.0
384
- return k.formatted(.number.precision(.fractionLength(0...1))) + "K"
385
- case 1_000_000..<1_000_000_000:
386
- let m = Double(value) / 1_000_000.0
387
- return m.formatted(.number.precision(.fractionLength(0...1))) + "M"
388
- default:
389
- let b = Double(value) / 1_000_000_000.0
390
- return b.formatted(.number.precision(.fractionLength(0...1))) + "B"
267
+ case 1_000_000_000...: return (number / 1_000_000_000).formatted(style) + "B"
268
+ case 1_000_000...: return (number / 1_000_000).formatted(style) + "M"
269
+ case 1_000...: return (number / 1_000).formatted(style) + "K"
270
+ default: return value.formatted()
391
271
  }
392
272
  }
393
273
  }
394
274
 
395
- extension FormatStyle where Self == AbbreviatedCountStyle {
396
- static var abbreviatedCount: AbbreviatedCountStyle { .init() }
275
+ extension FormatStyle where Self == ScoreFormat {
276
+ static var score: ScoreFormat { ScoreFormat() }
397
277
  }
398
278
 
399
- // Usage
400
- let followers = 12_500
401
- followers.formatted(.abbreviatedCount) // "12.5K"
402
-
403
- // In SwiftUI
404
- Text(followers, format: .abbreviatedCount)
279
+ let shown = 48_200.formatted(.score) // "48.2K"
280
+ Text(48_200, format: .score)
405
281
  ```
406
282
 
407
- ### Custom ParseableFormatStyle (for input parsing)
408
-
409
- ```swift
410
- struct AbbreviatedCountStyle: ParseableFormatStyle {
411
- var parseStrategy: AbbreviatedCountParseStrategy { .init() }
412
-
413
- func format(_ value: Int) -> String { /* same as above */ }
414
- }
415
-
416
- struct AbbreviatedCountParseStrategy: ParseStrategy {
417
- func parse(_ value: String) throws -> Int {
418
- let cleaned = value.uppercased().trimmingCharacters(in: .whitespaces)
419
- if cleaned.hasSuffix("K") {
420
- guard let num = Double(cleaned.dropLast()) else { throw parseError }
421
- return Int(num * 1_000)
422
- }
423
- // ... handle M, B, plain numbers
424
- guard let num = Int(cleaned) else { throw parseError }
425
- return num
426
- }
427
-
428
- private var parseError: some Error {
429
- DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "Invalid count"))
430
- }
431
- }
432
- ```
283
+ A parseable variant adds `ParseableFormatStyle` with a `parseStrategy` whose
284
+ `parse(_:) throws` reads the suffix back and throws on malformed input, for
285
+ example `DecodingError.dataCorrupted`. Send any real implementation work there.
433
286
 
434
- ## Forcing a Specific Locale
287
+ ## Pinning a locale
435
288
 
436
- Occasionally you need a specific locale (server APIs, fixed-format exports). Use `.locale()` modifier:
289
+ `.locale(_:)` forces a locale, which is right for serialization or for a
290
+ document that must always look one way, such as a German invoice PDF:
437
291
 
438
292
  ```swift
439
- // Force US format for API serialization (not user display)
440
- let usPrice = price.formatted(.currency(code: "USD").locale(Locale(identifier: "en_US")))
441
-
442
- // Force a date format for an API
443
- let apiDate = date.formatted(.iso8601) // Prefer ISO 8601 for APIs
444
-
445
- // Force German format for a German-language PDF export
446
- let deDate = date.formatted(.dateTime.month(.wide).day().year().locale(Locale(identifier: "de_DE")))
293
+ let invoiceDate = Date.now.formatted(.dateTime.day().month().year().locale(Locale(identifier: "de_DE")))
294
+ let payloadDate = Date.now.formatted(.iso8601) // preferred for APIs
447
295
  ```
448
296
 
449
- **Warning:** Never force a locale for user-facing UI. Always let the system locale drive user-visible formatting.
450
-
451
- ## RTL Layout Deep Dive
452
-
453
- ### How SwiftUI auto-mirrors
297
+ Never pin a locale in user-facing UI.
454
298
 
455
- SwiftUI respects `layoutDirection` from the environment. When the user's language is RTL:
299
+ ## Right-to-left in depth
456
300
 
457
- 1. **HStack**: Children render right-to-left
458
- 2. **Leading/Trailing**: `.leading` = right side, `.trailing` = left side
459
- 3. **Padding**: `.padding(.leading, 16)` applies to right side
460
- 4. **NavigationStack**: Back button appears on trailing (left) side
461
- 5. **Lists**: Disclosure chevrons point left
462
- 6. **ScrollView**: Horizontal scrolling starts from the right
463
- 7. **Text alignment**: Default alignment follows reading direction
301
+ SwiftUI takes `layoutDirection` from the environment. Under RTL, `.leading` is
302
+ the right edge, horizontal `ScrollView` content starts at the right, list
303
+ chevrons point left and the back button sits on the left.
464
304
 
465
- ### Image flipping
305
+ Flip: `chevron.forward`, `arrow.right` and custom directional assets, using
306
+ `.flipsForRightToLeftLayoutDirection(true)`.
466
307
 
467
- ```swift
468
- // Directional images SHOULD flip
469
- Image(systemName: "chevron.forward")
470
- .flipsForRightToLeftLayoutDirection(true)
471
-
472
- Image(systemName: "arrow.right")
473
- .flipsForRightToLeftLayoutDirection(true)
474
-
475
- Image("progress-arrow")
476
- .flipsForRightToLeftLayoutDirection(true)
477
-
478
- // These should NOT flip:
479
- // - Logos and brand marks
480
- // - Photos and illustrations
481
- // - Clock faces (clockwise is universal)
482
- // - Music notation
483
- // - Checkmarks
484
- // - Mathematical symbols (+, -, =)
485
- // - Media playback controls (play triangle always points right)
486
-
487
- // SF Symbols with .rtl variant auto-flip (e.g., text.alignleft has text.alignright)
488
- // Check SF Symbols app for RTL variants
489
- ```
308
+ Do not flip: logos and brand marks, photos and illustrations, clock faces,
309
+ music notation, checkmarks, mathematical symbols, media playback controls.
490
310
 
491
- ### Environment-based testing
311
+ SF Symbols that ship an RTL variant switch on their own; the SF Symbols app
312
+ shows which do.
492
313
 
493
314
  ```swift
494
- // Preview with RTL
495
- #Preview("Arabic RTL") {
496
- ContentView()
315
+ #Preview("Seat map, Hebrew") {
316
+ SeatMapView()
497
317
  .environment(\.layoutDirection, .rightToLeft)
498
- .environment(\.locale, Locale(identifier: "ar"))
318
+ .environment(\.locale, Locale(identifier: "he"))
499
319
  }
500
320
 
501
- // Preview with both directions side by side
502
- #Preview("LTR vs RTL") {
503
- HStack(spacing: 0) {
504
- ContentView()
505
- .environment(\.layoutDirection, .leftToRight)
506
- .frame(maxWidth: .infinity)
507
- Divider()
508
- ContentView()
509
- .environment(\.layoutDirection, .rightToLeft)
510
- .environment(\.locale, Locale(identifier: "ar"))
511
- .frame(maxWidth: .infinity)
321
+ #Preview("Both directions") {
322
+ HStack {
323
+ FareRow().environment(\.layoutDirection, .leftToRight)
324
+ FareRow().environment(\.layoutDirection, .rightToLeft)
512
325
  }
513
326
  }
514
327
  ```
515
328
 
516
- ### Semantic content attributes (UIKit interop)
517
-
518
- When mixing UIKit views via `UIViewRepresentable`, set semantic content attribute:
329
+ UIKit views inside a `UIViewRepresentable` read `semanticContentAttribute`:
330
+ `.forceLeftToRight`, `.forceRightToLeft`, or `.unspecified`, the default, which
331
+ follows the system.
519
332
 
520
333
  ```swift
521
- class MyUIView: UIView {
522
- override var semanticContentAttribute: UISemanticContentAttribute {
523
- // .forceLeftToRight for phone numbers, code
524
- // .forceRightToLeft to force RTL
525
- // .unspecified to follow system (default)
526
- .unspecified
334
+ struct CardNumberField: UIViewRepresentable {
335
+ func makeUIView(context: Context) -> UITextField {
336
+ let field = UITextField()
337
+ field.semanticContentAttribute = .forceLeftToRight
338
+ return field
527
339
  }
340
+ func updateUIView(_ uiView: UITextField, context: Context) {}
528
341
  }
529
342
  ```
530
343
 
531
- ### Bidirectional text
532
-
533
- When mixing LTR and RTL text (e.g., English brand names in Arabic text), Unicode bidirectional algorithm handles it automatically. For edge cases:
344
+ Mixed-direction text follows the Unicode bidirectional algorithm. For edge
345
+ cases like a phone number inside Arabic text, prefix a left-to-right mark
346
+ `\u{200E}`, or set `.environment(\.layoutDirection, .leftToRight)` on that one
347
+ view.
534
348
 
535
- ```swift
536
- // Force LTR for specific content within RTL context
537
- Text("\u{200E}+1 (555) 123-4567") // LTR mark before phone number
538
-
539
- // Or use environment override on a specific view
540
- Text(phoneNumber)
541
- .environment(\.layoutDirection, .leftToRight)
542
- ```
349
+ | Problem | Fix |
350
+ |---|---|
351
+ | `.padding(.left)` | `.padding(.leading)` |
352
+ | `.offset(x:)` to push content one way | Alignment or trailing padding |
353
+ | `.multilineTextAlignment(.left)` | `.multilineTextAlignment(.leading)` |
354
+ | Rounding top-left and top-right corners | Round leading and trailing corners |
355
+ | "Swipe right to archive" | "Swipe toward the leading edge", or rely on system swipe actions |
543
356
 
544
- ### Common RTL pitfalls
357
+ ## ScaledMetric and Dynamic Type
545
358
 
546
- | Issue | Wrong | Correct |
547
- |-------|-------|---------|
548
- | Fixed position | `.padding(.left, 16)` | `.padding(.leading, 16)` |
549
- | Absolute offset | `.offset(x: -20)` for "move left" | Use alignment or `.padding(.trailing)` |
550
- | Text alignment | `.multilineTextAlignment(.left)` | `.multilineTextAlignment(.leading)` |
551
- | Corner radius | Only rounding top-left/top-right | Round leading/trailing corners |
552
- | Swipe gestures | "Swipe right to delete" | "Swipe to leading edge" -- or use system gestures |
553
-
554
- ## `@ScaledMetric` for Dynamic Type
555
-
556
- Use `@ScaledMetric` to make custom spacing, icon sizes, and padding scale with the user's Dynamic Type setting.
359
+ `@ScaledMetric(relativeTo:)` scales your own numbers, such as spacing, icon
360
+ size and padding, together with the text style you name.
557
361
 
558
362
  ```swift
559
- struct ProfileRow: View {
560
- @ScaledMetric(relativeTo: .body) private var avatarSize = 44.0
561
- @ScaledMetric(relativeTo: .body) private var spacing = 12.0
363
+ struct ContactRow: View {
364
+ @ScaledMetric(relativeTo: .body) private var portraitSide: CGFloat = 36
365
+ @ScaledMetric(relativeTo: .body) private var gap: CGFloat = 10
562
366
 
563
367
  var body: some View {
564
- HStack(spacing: spacing) {
565
- AvatarView()
566
- .frame(width: avatarSize, height: avatarSize)
567
- VStack(alignment: .leading) {
568
- Text(name).font(.headline)
569
- Text(subtitle).font(.subheadline)
570
- }
368
+ HStack(spacing: gap) {
369
+ Image(systemName: "person.crop.circle")
370
+ .resizable()
371
+ .frame(width: portraitSide, height: portraitSide)
372
+ Text("Mira Lopez")
571
373
  }
572
374
  }
573
375
  }
574
376
  ```
575
377
 
576
- ### relativeTo parameter
577
-
578
- `@ScaledMetric` scales proportionally to a text style. Choose the text style that the metric logically accompanies:
579
-
580
- | Text style | Base size | Use for |
581
- |------------|-----------|---------|
582
- | `.body` | 17pt | General spacing, icons next to body text |
583
- | `.caption` | 12pt | Small icons, fine spacing |
584
- | `.title` | 28pt | Large icons, hero spacing |
585
- | `.largeTitle` | 34pt | Hero images, splash elements |
378
+ Which style to scale against:
586
379
 
587
- ### Testing Dynamic Type
380
+ | `relativeTo` | Base size | Good for |
381
+ |---|---|---|
382
+ | `.body` | 17 pt | General spacing |
383
+ | `.caption` | 12 pt | Small icons |
384
+ | `.title` | 28 pt | Large icons |
385
+ | `.largeTitle` | 34 pt | Hero elements |
588
386
 
589
387
  ```swift
590
- // Preview with large text
591
- #Preview("Accessibility XXL") {
592
- ContentView()
593
- .dynamicTypeSize(.accessibility3)
388
+ #Preview("Accessibility 3") {
389
+ ContactRow().dynamicTypeSize(.accessibility3)
594
390
  }
595
391
 
596
- // Preview matrix
597
- #Preview("Dynamic Type Sizes") {
392
+ #Preview("All sizes") {
598
393
  ScrollView {
599
394
  ForEach(DynamicTypeSize.allCases, id: \.self) { size in
600
- ContentView()
601
- .dynamicTypeSize(size)
602
- .padding()
603
- .border(Color.gray)
395
+ ContactRow().dynamicTypeSize(size)
604
396
  }
605
397
  }
606
398
  }
607
399
  ```
608
400
 
609
- ## Layout Testing with Accessibility Inspector
610
-
611
- Accessibility Inspector (Xcode > Open Developer Tool > Accessibility Inspector) provides:
612
-
613
- 1. **Audit**: Scans running app for accessibility issues including truncated text
614
- 2. **Inspection**: Shows exact font sizes and Dynamic Type response
615
- 3. **Settings**: Override Dynamic Type size, Bold Text, Reduce Motion on device without changing system settings
616
-
617
- ### Quick test workflow
618
-
619
- 1. Launch app in Simulator
620
- 2. Open Accessibility Inspector, target the Simulator
621
- 3. Use the Settings panel to set Dynamic Type to "Accessibility XXL"
622
- 4. Navigate through every screen -- look for truncated text, overlapping elements, broken layouts
623
- 5. Switch to RTL (set language to Arabic in scheme options)
624
- 6. Repeat navigation -- check all alignment and reading order
625
-
626
- ## Quick Reference Table
627
-
628
- | Data type | FormatStyle | Example output (US) |
629
- |-----------|-------------|---------------------|
630
- | `Date` | `.dateTime.month().day().year()` | "Jan 15, 2026" |
631
- | `Date` range | `(start..<end).formatted(date:time:)` | "Jan 15 - 20, 2026" |
632
- | `Date` relative | `.relative(presentation: .named)` | "yesterday" |
633
- | `Int` | `.number` | "1,234,567" |
634
- | `Int` ordinal | `.number.notation(.ordinal)` | "3rd" |
635
- | `Int` compact | `.number.notation(.compactName)` | "1.2M" |
636
- | `Double` | `.number.precision(.fractionLength(2))` | "3.14" |
637
- | `Double` | `.percent` | "85.6%" |
638
- | `Decimal` | `.currency(code: "USD")` | "$29.99" |
639
- | `Measurement` | `.measurement(width: .abbreviated)` | "5 km" / "3.1 mi" |
640
- | `Duration` | `.time(pattern: .hourMinuteSecond)` | "1:01:01" |
641
- | `Duration` | `.units(width: .abbreviated)` | "1 hr, 1 min" |
642
- | `PersonNameComponents` | `.name(style: .medium)` | "John Doe" |
643
- | `Int64` (bytes) | `.byteCount(style: .file)` | "1.5 MB" |
644
- | `[String]` | `.list(type: .and)` | "A, B, and C" |
401
+ ## Checking layout with Accessibility Inspector
402
+
403
+ Open it from Xcode > Open Developer Tool > Accessibility Inspector.
404
+
405
+ - Audit finds problems, truncated text among them.
406
+ - Inspection shows font sizes and whether an element reacts to Dynamic Type.
407
+ - Settings overrides Dynamic Type, Bold Text and Reduce Motion without touching
408
+ system settings.
409
+
410
+ Routine:
411
+
412
+ 1. Run the app in Simulator and point the inspector at it.
413
+ 2. Set Dynamic Type to Accessibility XXL.
414
+ 3. Visit every screen and look for truncation and overlap.
415
+ 4. Switch the scheme's App Language to Arabic.
416
+ 5. Visit the screens again for alignment and reading order.
417
+
418
+ ## Cheat sheet
419
+
420
+ | Value | Style | en_US sample |
421
+ |---|---|---|
422
+ | `Date` | `.dateTime.month().day().year()` | Jun 3, 2026 |
423
+ | Date range | `(start..<end).formatted(date:time:)` | Jun 3 - 7, 2026 |
424
+ | Relative date | `.relative(presentation: .named)` | yesterday |
425
+ | `Int` | `.number` | 2,500,000 |
426
+ | `Int` | `NumberFormatter` with `numberStyle = .ordinal` | 3rd |
427
+ | `Int` | `.number.notation(.compactName)` | 4.3M |
428
+ | `Double` | `.number.precision(.fractionLength(2))` | 72.50 |
429
+ | `Double` | `.percent` | 92% (for 0.92) |
430
+ | `Decimal` | `.currency(code: "USD")` | $1,249.50 |
431
+ | `Measurement` | `.measurement(width: .abbreviated)` | 7.7 mi |
432
+ | `Duration` | `.time(pattern: .hourMinuteSecond)` | 1:02:05 |
433
+ | `Duration` | `.units(width: .abbreviated)` | 1 hr, 2 min, 5 sec |
434
+ | `PersonNameComponents` | `.name(style: .medium)` | Hana Sato |
435
+ | `Int64` | `.byteCount(style: .file)` | 3.4 GB |
436
+ | `[String]` | `.list(type: .and)` | olives, basil, and garlic |