@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.
- package/CHANGELOG.md +21 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +285 -285
- package/package.json +3 -3
- package/pipeline/lib/redact.mjs +3 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/scripts/gen-skills-index.mjs +13 -1
- package/pipeline/scripts/pre-commit-check.sh +4 -0
- package/pipeline/skills/.skill-manifest.json +69 -69
- package/pipeline/skills/shared/README.md +70 -70
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,342 +1,353 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: swiftui-layout-components
|
|
3
|
-
description: "
|
|
3
|
+
description: "SwiftUI layouts: stacks, lazy stacks, LazyVGrid/LazyHGrid, List sections, swipe actions, ScrollView with ScrollPosition, validated Form, Toggle, Picker, Slider, .searchable, toast overlays. Use when building data-driven layouts, collection views, settings screens, search or transient overlay UI, or choosing between stacks, grids, lists and scroll views. Not for architecture, state or navigation."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# SwiftUI Layout
|
|
8
|
+
# SwiftUI Layout Components
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Which container you pick decides how much work SwiftUI does up front, how rows
|
|
11
|
+
are reused, and what the system gives you for free (selection, swipe actions,
|
|
12
|
+
accessibility). Examples assume Swift 6.3 and iOS 26; anything not marked with
|
|
13
|
+
a newer version also runs on iOS 17.
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
App structure and state ownership live in `swiftui-patterns`; navigation
|
|
16
|
+
stacks, links and routing live in `swiftui-navigation`.
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
- [Grid Layouts](#grid-layouts)
|
|
16
|
-
- [List Patterns](#list-patterns)
|
|
17
|
-
- [ScrollView](#scrollview)
|
|
18
|
-
- [Form and Controls](#form-and-controls)
|
|
19
|
-
- [Searchable](#searchable)
|
|
20
|
-
- [Overlay and Presentation](#overlay-and-presentation)
|
|
21
|
-
- [Common Mistakes](#common-mistakes)
|
|
22
|
-
- [Review Checklist](#review-checklist)
|
|
23
|
-
- [References](#references)
|
|
18
|
+
## Stacks: eager or lazy
|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
| Container | Builds children | Use for |
|
|
21
|
+
|-----------|-----------------|---------|
|
|
22
|
+
| `VStack`, `HStack`, `ZStack` | All at once | Small, fixed content: headers, toolbars, short forms |
|
|
23
|
+
| `LazyVStack`, `LazyHStack` inside `ScrollView` | As they scroll into view | Long or unknown-length content: feeds, chat, search results |
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
A plain stack of a thousand rows builds a thousand views before the first
|
|
26
|
+
frame. A lazy stack for three labels adds bookkeeping for nothing.
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
## Grids
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Text(title).font(.headline)
|
|
34
|
-
Text(subtitle).font(.subheadline).foregroundStyle(.secondary)
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Lazy Stacks
|
|
30
|
+
`LazyVGrid` suits dense visual choice: icon pickers, photo galleries, template
|
|
31
|
+
tiles.
|
|
39
32
|
|
|
40
|
-
|
|
33
|
+
- `.adaptive` columns let the column count follow the available width.
|
|
34
|
+
- Several `.flexible` columns give a fixed count, such as a three-up gallery.
|
|
41
35
|
|
|
42
36
|
```swift
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
struct StickerPicker: View {
|
|
38
|
+
let stickers: [Sticker]
|
|
39
|
+
|
|
40
|
+
var body: some View {
|
|
41
|
+
ScrollView {
|
|
42
|
+
LazyVGrid(columns: [GridItem(.adaptive(minimum: 96, maximum: 1024))]) {
|
|
43
|
+
ForEach(stickers) { sticker in
|
|
44
|
+
StickerTile(sticker: sticker)
|
|
45
|
+
.aspectRatio(1, contentMode: .fit)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
.padding()
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
|
-
.padding(.horizontal)
|
|
50
51
|
}
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
A fixed three-column gallery passes
|
|
55
|
+
`Array(repeating: GridItem(.flexible(minimum: 90), spacing: 2), count: 3)` as
|
|
56
|
+
the columns and `spacing: 2` to `LazyVGrid(columns:spacing:)`.
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
Give cells their shape with `.aspectRatio`. Do not put a `GeometryReader` in a
|
|
59
|
+
lazy container: it measures eagerly and undoes the laziness. When a cell really
|
|
60
|
+
needs its size, read it with `.onGeometryChange(for:of:action:)`, which Apple
|
|
61
|
+
documents as available from iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0 and
|
|
62
|
+
visionOS 1.0 (back-deployed; build with the Xcode 16 SDK or later).
|
|
58
63
|
|
|
59
|
-
|
|
64
|
+
Column strategies, sectioned grids, selection and performance:
|
|
65
|
+
[grids reference](references/grids.md).
|
|
60
66
|
|
|
61
|
-
|
|
62
|
-
// Adaptive grid -- columns adjust to fit
|
|
63
|
-
let columns = [GridItem(.adaptive(minimum: 120, maximum: 1024))]
|
|
67
|
+
## Lists
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
ThumbnailView(item: item)
|
|
68
|
-
.aspectRatio(1, contentMode: .fit)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
```
|
|
69
|
+
`List` is the right container for feeds and settings rows: it reuses rows and
|
|
70
|
+
brings selection, swipe actions and accessibility along.
|
|
72
71
|
|
|
73
72
|
```swift
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
struct AccountSettings: View {
|
|
74
|
+
var body: some View {
|
|
75
|
+
List {
|
|
76
|
+
Section("Preferences") {
|
|
77
|
+
NavigationLink("Units", value: SettingsPage.units)
|
|
78
|
+
NavigationLink("Appearance", value: SettingsPage.appearance)
|
|
79
|
+
}
|
|
80
|
+
Section("Session") {
|
|
81
|
+
Button("Log Out", role: .destructive) { logOut() }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
.listStyle(.insetGrouped)
|
|
80
85
|
}
|
|
86
|
+
|
|
87
|
+
private func logOut() {}
|
|
81
88
|
}
|
|
82
89
|
```
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
- Feeds read best as `.listStyle(.plain)`; settings screens as `.insetGrouped`.
|
|
92
|
+
- `.scrollContentBackground(.hidden)` plus your own background for themed screens.
|
|
93
|
+
- `.listRowInsets(_:)` and `.listRowSeparator(.hidden)` adjust spacing and dividers.
|
|
94
|
+
- `ScrollPosition` (iOS 18) with `.scrollPosition($position)` scrolls to the top or to an id.
|
|
95
|
+
- `.refreshable { await reload() }` adds pull to refresh.
|
|
96
|
+
- `.contentShape(Rectangle())` makes a whole row tappable, not only its text.
|
|
97
|
+
- iOS 26: `.scrollEdgeEffectStyle(.soft, for: .top)` fades content under the top bar.
|
|
87
98
|
|
|
88
|
-
|
|
99
|
+
### Swipe actions
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
Row swipe actions belong to `List` rows. Attach
|
|
102
|
+
`.swipeActions(edge:allowsFullSwipe:content:)` to the row view inside
|
|
103
|
+
`ForEach`. The trailing edge is the default; add a second modifier for leading
|
|
104
|
+
actions.
|
|
91
105
|
|
|
92
106
|
```swift
|
|
93
107
|
List {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
ForEach(inbox) { note in
|
|
109
|
+
NoteRow(note: note)
|
|
110
|
+
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
|
111
|
+
Button("Delete", systemImage: "trash", role: .destructive) {
|
|
112
|
+
store.delete(note)
|
|
113
|
+
}
|
|
114
|
+
Button("Snooze", systemImage: "clock") { store.snooze(note) }
|
|
115
|
+
.tint(.indigo)
|
|
116
|
+
}
|
|
117
|
+
.swipeActions(edge: .leading) {
|
|
118
|
+
Button(note.isPinned ? "Unpin" : "Pin", systemImage: "pin") {
|
|
119
|
+
store.togglePin(note)
|
|
120
|
+
}
|
|
121
|
+
.tint(.orange)
|
|
122
|
+
}
|
|
100
123
|
}
|
|
101
124
|
}
|
|
102
|
-
.listStyle(.insetGrouped)
|
|
103
125
|
```
|
|
104
126
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
- `.
|
|
108
|
-
|
|
109
|
-
- Use
|
|
110
|
-
|
|
111
|
-
-
|
|
127
|
+
- The first button on an edge is the one a full swipe triggers, so put the
|
|
128
|
+
most common action first and only allow full swipe when it is safe.
|
|
129
|
+
- A `.destructive` role colors the button red and animates the row out; the
|
|
130
|
+
data change must actually remove the item.
|
|
131
|
+
- Use `.tint(_:)` for non-destructive buttons; keep each edge to about three
|
|
132
|
+
actions.
|
|
133
|
+
- Swipe actions do nothing in `ScrollView` + `LazyVStack`; choose `List` when
|
|
134
|
+
rows need them. Offer the same actions in a context menu or edit mode so
|
|
135
|
+
they are discoverable.
|
|
112
136
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
See [references/list.md](references/list.md) for full list patterns including feed lists with scroll-to-top.
|
|
137
|
+
More list recipes: [list reference](references/list.md).
|
|
116
138
|
|
|
117
139
|
## ScrollView
|
|
118
140
|
|
|
119
|
-
Use `ScrollView` with lazy stacks
|
|
141
|
+
Use `ScrollView` with lazy stacks for custom layouts, mixed content and
|
|
142
|
+
horizontal strips.
|
|
120
143
|
|
|
121
144
|
```swift
|
|
122
145
|
ScrollView(.horizontal, showsIndicators: false) {
|
|
123
146
|
LazyHStack {
|
|
124
|
-
ForEach(
|
|
125
|
-
ChipView(chip: chip)
|
|
126
|
-
}
|
|
147
|
+
ForEach(genres) { genre in GenreChip(genre: genre) }
|
|
127
148
|
}
|
|
149
|
+
.padding(.horizontal)
|
|
128
150
|
}
|
|
129
151
|
```
|
|
130
152
|
|
|
131
|
-
|
|
153
|
+
`ScrollPosition` (iOS 18) tracks position in both directions and scrolls on
|
|
154
|
+
request.
|
|
155
|
+
A chat screen pinned to the newest message:
|
|
132
156
|
|
|
133
157
|
```swift
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
158
|
+
struct ThreadView: View {
|
|
159
|
+
let replies: [Reply]
|
|
160
|
+
@State private var position = ScrollPosition(edge: .bottom)
|
|
161
|
+
|
|
162
|
+
var body: some View {
|
|
163
|
+
ScrollView {
|
|
164
|
+
LazyVStack {
|
|
165
|
+
ForEach(replies) { ReplyBubble(reply: $0) }
|
|
166
|
+
}
|
|
167
|
+
.scrollTargetLayout()
|
|
168
|
+
}
|
|
169
|
+
.scrollPosition($position)
|
|
170
|
+
.onChange(of: replies.last?.id) {
|
|
171
|
+
withAnimation { position.scrollTo(edge: .bottom) }
|
|
140
172
|
}
|
|
173
|
+
.safeAreaInset(edge: .bottom) { ComposerBar() }
|
|
141
174
|
}
|
|
142
|
-
.scrollTargetLayout()
|
|
143
|
-
}
|
|
144
|
-
.scrollPosition($scrollPosition)
|
|
145
|
-
.onChange(of: messages.last?.id) {
|
|
146
|
-
withAnimation { scrollPosition.scrollTo(edge: .bottom) }
|
|
147
175
|
}
|
|
148
176
|
```
|
|
149
177
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
**`safeAreaInset(edge:)`** pins content (input bars, toolbars) above the keyboard without affecting scroll layout.
|
|
153
|
-
|
|
154
|
-
**iOS 26 additions:**
|
|
155
|
-
- `.scrollEdgeEffectStyle(.soft, for: .top)` -- fading edge effect
|
|
156
|
-
- `.backgroundExtensionEffect()` -- mirror/blur at safe area edges (use sparingly, one per screen)
|
|
157
|
-
- `.safeAreaBar(edge:)` -- attach bar views that integrate with scroll effects
|
|
178
|
+
`safeAreaInset(edge:)` keeps an input bar above the keyboard without changing
|
|
179
|
+
the scroll layout. iOS 26 adds:
|
|
158
180
|
|
|
159
|
-
|
|
181
|
+
- `.scrollEdgeEffectStyle(.soft, for: .top)` for a fading edge.
|
|
182
|
+
- `.backgroundExtensionEffect()` to mirror and blur content under safe-area
|
|
183
|
+
edges. Use it sparingly, on one view per screen.
|
|
184
|
+
- `.safeAreaBar(edge:)` for bars that take part in the scroll edge effect.
|
|
160
185
|
|
|
161
|
-
|
|
186
|
+
Details: [scroll view reference](references/scrollview.md).
|
|
162
187
|
|
|
163
|
-
|
|
188
|
+
## Forms and controls
|
|
164
189
|
|
|
165
|
-
|
|
190
|
+
`Form` lays out structured input with the platform's spacing and accessibility.
|
|
191
|
+
Group related controls in `Section`s.
|
|
166
192
|
|
|
167
193
|
```swift
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
194
|
+
struct ReaderSettings: View {
|
|
195
|
+
@AppStorage("reader.justify") private var justify = false
|
|
196
|
+
@State private var theme: ReaderTheme = .paper
|
|
197
|
+
@State private var fontScale = 1.0
|
|
198
|
+
|
|
199
|
+
var body: some View {
|
|
200
|
+
Form {
|
|
201
|
+
Section("Text") {
|
|
202
|
+
Toggle("Justify Text", isOn: $justify)
|
|
203
|
+
Picker("Theme", selection: $theme) {
|
|
204
|
+
ForEach(ReaderTheme.allCases, id: \.self) { option in
|
|
205
|
+
Text(option.title).tag(option)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
HStack {
|
|
209
|
+
Slider(value: $fontScale, in: 0.5...1.5, step: 0.1)
|
|
210
|
+
Text(fontScale, format: .number.precision(.fractionLength(1)))
|
|
211
|
+
.monospacedDigit()
|
|
212
|
+
}
|
|
213
|
+
}
|
|
176
214
|
}
|
|
177
|
-
|
|
215
|
+
.formStyle(.grouped)
|
|
216
|
+
.scrollContentBackground(.hidden)
|
|
178
217
|
}
|
|
179
218
|
}
|
|
180
|
-
.formStyle(.grouped)
|
|
181
|
-
.scrollContentBackground(.hidden)
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
Use `@FocusState` to manage keyboard focus in input-heavy forms. Wrap in `NavigationStack` only when presented standalone or in a sheet.
|
|
185
|
-
|
|
186
|
-
### Controls
|
|
187
|
-
|
|
188
|
-
| Control | Usage |
|
|
189
|
-
|---------|-------|
|
|
190
|
-
| `Toggle` | Boolean preferences |
|
|
191
|
-
| `Picker` | Discrete choices; `.segmented` for 2-4 options |
|
|
192
|
-
| `Slider` | Numeric ranges with visible value label |
|
|
193
|
-
| `DatePicker` | Date/time selection |
|
|
194
|
-
| `TextField` | Text input with `.keyboardType`, `.textInputAutocapitalization` |
|
|
195
|
-
|
|
196
|
-
Bind controls directly to `@State`, `@Binding`, or `@AppStorage`. Group related controls in `Form` sections. Use `.disabled(...)` to reflect locked or inherited settings. Use `Label` inside toggles to combine icon + text when it adds clarity.
|
|
197
|
-
|
|
198
|
-
```swift
|
|
199
|
-
// Toggle sections
|
|
200
|
-
Form {
|
|
201
|
-
Section("Notifications") {
|
|
202
|
-
Toggle("Mentions", isOn: $preferences.notificationsMentionsEnabled)
|
|
203
|
-
Toggle("Follows", isOn: $preferences.notificationsFollowsEnabled)
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Slider with value text
|
|
208
|
-
Section("Font Size") {
|
|
209
|
-
Slider(value: $fontSizeScale, in: 0.5...1.5, step: 0.1)
|
|
210
|
-
Text("Scale: \(String(format: "%.1f", fontSizeScale))")
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Picker for enums
|
|
214
|
-
Picker("Default Visibility", selection: $visibility) {
|
|
215
|
-
ForEach(Visibility.allCases, id: \.self) { option in
|
|
216
|
-
Text(option.title).tag(option)
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
- Use `@FocusState` to move the keyboard between fields in long forms.
|
|
222
|
+
- Add a `NavigationStack` around the form only for a sheet or a standalone
|
|
223
|
+
presentation; pushed inside an existing stack it already has one.
|
|
222
224
|
|
|
223
|
-
|
|
225
|
+
| Control | For | Notes |
|
|
226
|
+
|---------|-----|-------|
|
|
227
|
+
| `Toggle` | On/off values | A `Label` gives icon plus text when it helps |
|
|
228
|
+
| `Picker` | One of several choices | `.segmented` only for 2 to 4 options; menu or inline beyond that |
|
|
229
|
+
| `Slider` | A numeric range | Always show the current value next to it, never hide the label |
|
|
230
|
+
| `DatePicker` | Dates and times | |
|
|
231
|
+
| `TextField` | Text | Set `.keyboardType` and `.textInputAutocapitalization` |
|
|
224
232
|
|
|
225
|
-
|
|
233
|
+
Bind controls straight to `@State`, `@Binding` or `@AppStorage`, and use
|
|
234
|
+
`.disabled(_:)` for settings that are locked or inherited. Validation and
|
|
235
|
+
modal forms: [form reference](references/form.md).
|
|
226
236
|
|
|
227
|
-
|
|
237
|
+
## Search
|
|
228
238
|
|
|
229
239
|
```swift
|
|
230
240
|
@MainActor
|
|
231
|
-
struct
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
.searchScopes($searchScope) {
|
|
253
|
-
ForEach(SearchScope.allCases, id: \.self) { scope in
|
|
254
|
-
Text(scope.title)
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
.task(id: searchQuery) {
|
|
258
|
-
await runSearch()
|
|
241
|
+
struct RecipeSearch: View {
|
|
242
|
+
@State private var query = ""
|
|
243
|
+
@State private var scope: RecipeScope = .all
|
|
244
|
+
@State private var matches: [Recipe] = []
|
|
245
|
+
@State private var isSearching = false
|
|
246
|
+
|
|
247
|
+
var body: some View {
|
|
248
|
+
List(matches) { RecipeRow(recipe: $0) }
|
|
249
|
+
.overlay {
|
|
250
|
+
if isSearching { ProgressView() }
|
|
251
|
+
else if query.isEmpty { ContentUnavailableView("Find a Recipe", systemImage: "fork.knife") }
|
|
252
|
+
}
|
|
253
|
+
.searchable(
|
|
254
|
+
text: $query,
|
|
255
|
+
placement: .navigationBarDrawer(displayMode: .always),
|
|
256
|
+
prompt: "Dishes or ingredients"
|
|
257
|
+
)
|
|
258
|
+
.searchScopes($scope) {
|
|
259
|
+
ForEach(RecipeScope.allCases) { Text($0.title).tag($0) }
|
|
260
|
+
}
|
|
261
|
+
.task(id: query) { await search() }
|
|
259
262
|
}
|
|
260
|
-
}
|
|
261
263
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
private func search() async {
|
|
265
|
+
guard !query.isEmpty else {
|
|
266
|
+
matches = []
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
isSearching = true
|
|
270
|
+
defer { isSearching = false }
|
|
271
|
+
try? await Task.sleep(for: .seconds(0.25))
|
|
272
|
+
guard !Task.isCancelled else { return }
|
|
273
|
+
matches = await RecipeIndex.shared.lookup(query, in: scope)
|
|
266
274
|
}
|
|
267
|
-
isSearching = true
|
|
268
|
-
defer { isSearching = false }
|
|
269
|
-
try? await Task.sleep(for: .milliseconds(250))
|
|
270
|
-
results = await fetchResults(query: searchQuery, scope: searchScope)
|
|
271
|
-
}
|
|
272
275
|
}
|
|
273
276
|
```
|
|
274
277
|
|
|
275
|
-
|
|
278
|
+
`.task(id:)` cancels and restarts on every keystroke, so the short sleep acts
|
|
279
|
+
as a debounce. Skip empty queries, show a placeholder when there is nothing to
|
|
280
|
+
search, and let the screen own its search state rather than a shared model.
|
|
276
281
|
|
|
277
|
-
##
|
|
282
|
+
## Overlays and presentation
|
|
278
283
|
|
|
279
|
-
|
|
284
|
+
`.overlay(alignment:)` shows transient UI such as toasts and banners without
|
|
285
|
+
moving anything else.
|
|
280
286
|
|
|
281
287
|
```swift
|
|
282
|
-
struct
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
288
|
+
struct SaveConfirmation: ViewModifier {
|
|
289
|
+
@Binding var toast: String?
|
|
290
|
+
|
|
291
|
+
func body(content base: Content) -> some View {
|
|
292
|
+
base.overlay(alignment: .top) {
|
|
293
|
+
if let toast {
|
|
294
|
+
Text(toast)
|
|
295
|
+
.padding()
|
|
296
|
+
.background(.thinMaterial, in: Capsule())
|
|
297
|
+
.transition(.opacity.combined(with: .move(edge: .top)))
|
|
298
|
+
.task {
|
|
299
|
+
try? await Task.sleep(for: .milliseconds(2000))
|
|
300
|
+
withAnimation { self.toast = nil }
|
|
301
|
+
}
|
|
296
302
|
}
|
|
297
303
|
}
|
|
298
|
-
|
|
299
|
-
}
|
|
304
|
+
}
|
|
300
305
|
}
|
|
301
306
|
```
|
|
302
307
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
- [ ]
|
|
331
|
-
- [ ]
|
|
332
|
-
- [ ]
|
|
333
|
-
- [ ]
|
|
308
|
+
- Prefer an overlay to inserting a banner into a stack; animate it in and out
|
|
309
|
+
and dismiss it after a short time.
|
|
310
|
+
- Pin it to one clear edge (`.top` or `.bottom`).
|
|
311
|
+
- Do not block all interaction unless the moment requires it.
|
|
312
|
+
- Show one toast at a time: replace or queue, never pile them up.
|
|
313
|
+
- `.fullScreenCover(item:)` is for immersive screens such as media viewers or
|
|
314
|
+
onboarding.
|
|
315
|
+
|
|
316
|
+
## Common mistakes
|
|
317
|
+
|
|
318
|
+
- Plain stacks for big collections: everything renders up front.
|
|
319
|
+
- `GeometryReader` inside lazy containers: laziness is lost.
|
|
320
|
+
- Array indices as `ForEach` ids: wrong diffs and glitchy updates.
|
|
321
|
+
- Nested scroll views on the same axis: competing gestures.
|
|
322
|
+
- Heavy custom row layouts in `List`: use `ScrollView` with `LazyVStack`.
|
|
323
|
+
- Missing `.contentShape(Rectangle())`: only the text responds to taps.
|
|
324
|
+
- Fixed frames on sheets: use `.presentationSizing` (iOS 18) instead.
|
|
325
|
+
- Searching with an empty string: guard it.
|
|
326
|
+
- `List` and `ScrollView` mixed in one hierarchy: gesture conflicts.
|
|
327
|
+
- Segmented pickers with many options: use menu or inline.
|
|
328
|
+
- `spacing:` hard-coded everywhere: leave it out so the platform picks
|
|
329
|
+
adaptive spacing, and set it only for deliberately tight (0 to 4 pt) or wide
|
|
330
|
+
gaps.
|
|
331
|
+
- Swipe actions added to rows outside a `List`: they never appear.
|
|
332
|
+
|
|
333
|
+
## Review checklist
|
|
334
|
+
|
|
335
|
+
- [ ] Large or dynamic collections use lazy stacks or `List`
|
|
336
|
+
- [ ] Every `ForEach` item has a stable `Identifiable` id
|
|
337
|
+
- [ ] No `GeometryReader` in lazy containers
|
|
338
|
+
- [ ] List style matches the content: `.plain` feed, `.insetGrouped` settings
|
|
339
|
+
- [ ] Structured input uses `Form`, not hand-built stacks
|
|
340
|
+
- [ ] `.searchable` work is debounced with `.task(id:)`
|
|
341
|
+
- [ ] `.refreshable` is present where the data can be reloaded
|
|
342
|
+
- [ ] Swipe actions sit on `List` rows, with the safe action first on full swipe
|
|
343
|
+
- [ ] Overlays animate in and dismiss themselves
|
|
344
|
+
- [ ] Tappable rows have `.contentShape(Rectangle())`
|
|
345
|
+
- [ ] `@FocusState` drives keyboard focus in forms
|
|
346
|
+
- [ ] `spacing:` appears only where a specific value is needed
|
|
334
347
|
|
|
335
348
|
## References
|
|
336
349
|
|
|
337
|
-
-
|
|
338
|
-
-
|
|
339
|
-
-
|
|
340
|
-
-
|
|
341
|
-
- Architecture and state management: see `swiftui-patterns` skill
|
|
342
|
-
- Navigation patterns: see `swiftui-navigation` skill
|
|
350
|
+
- [Grids](references/grids.md): grid types, columns, cell sizing, selection, performance
|
|
351
|
+
- [Lists](references/list.md): feeds with scroll-to-top, settings lists, edge effects
|
|
352
|
+
- [Scroll views](references/scrollview.md): lazy content, `ScrollPosition`, iOS 26 edge effects, `safeAreaBar`
|
|
353
|
+
- [Forms](references/form.md): settings forms, modal forms with validation
|