@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,42 +1,34 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tipkit
|
|
3
|
-
description: "
|
|
3
|
+
description: "TipKit in-app tips (iOS 17+): Tip protocol, TipView, popoverTip, rules, events, TipGroup, styles, CloudKit sync. Use when building or reviewing feature-discovery tooltips, onboarding flows, first-run experiences, coach marks, contextual tips or other feature-education UI."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# TipKit
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
TipKit (iOS 17 and later) shows short hints that teach a feature at the
|
|
11
|
+
moment it matters. The framework owns the hard parts: it decides when a tip
|
|
12
|
+
is eligible, throttles how often tips appear, and remembers which tips a
|
|
13
|
+
person has already learned so they stop appearing.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- [Defining Tips](#defining-tips)
|
|
19
|
-
- [Displaying Tips](#displaying-tips)
|
|
20
|
-
- [Tip Rules](#tip-rules)
|
|
21
|
-
- [Tip Actions](#tip-actions)
|
|
22
|
-
- [Tip Groups](#tip-groups)
|
|
23
|
-
- [Programmatic Control](#programmatic-control)
|
|
24
|
-
- [Common Mistakes](#common-mistakes)
|
|
25
|
-
- [Review Checklist](#review-checklist)
|
|
26
|
-
- [References](#references)
|
|
15
|
+
Tips are for discovery and progressive disclosure. They can be dismissed and
|
|
16
|
+
do not come back, so anything critical or safety related goes in an alert or
|
|
17
|
+
an inline warning instead.
|
|
27
18
|
|
|
28
19
|
## Setup
|
|
29
20
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
Configure TipKit once, in the `App` initializer, before the first view is
|
|
22
|
+
built. `Tips.configure` opens the tips datastore and starts evaluating rules;
|
|
23
|
+
if it runs later (in `onAppear` or `.task`), tip views can render against a
|
|
24
|
+
store that is not ready yet.
|
|
33
25
|
|
|
34
26
|
```swift
|
|
35
27
|
import SwiftUI
|
|
36
28
|
import TipKit
|
|
37
29
|
|
|
38
30
|
@main
|
|
39
|
-
struct
|
|
31
|
+
struct GardenJournalApp: App {
|
|
40
32
|
init() {
|
|
41
33
|
try? Tips.configure([
|
|
42
34
|
.datastoreLocation(.applicationDefault)
|
|
@@ -44,99 +36,117 @@ struct MyApp: App {
|
|
|
44
36
|
}
|
|
45
37
|
|
|
46
38
|
var body: some Scene {
|
|
47
|
-
WindowGroup {
|
|
39
|
+
WindowGroup {
|
|
40
|
+
JournalHomeView()
|
|
41
|
+
}
|
|
48
42
|
}
|
|
49
43
|
}
|
|
50
44
|
```
|
|
51
45
|
|
|
52
|
-
###
|
|
46
|
+
### Where the datastore lives
|
|
53
47
|
|
|
54
|
-
| Option |
|
|
55
|
-
|
|
56
|
-
| `.applicationDefault` |
|
|
57
|
-
| `.groupContainer(identifier:)` |
|
|
58
|
-
| `.url(_:)` |
|
|
48
|
+
| Option | When to pick it |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `.applicationDefault` | The app sandbox default. Correct for most apps. |
|
|
51
|
+
| `.groupContainer(identifier:)` | Tip state shared between the app and its extensions. |
|
|
52
|
+
| `.url(_:)` | A file URL you choose, when you need full control. |
|
|
59
53
|
|
|
60
|
-
### CloudKit
|
|
54
|
+
### Syncing tip state with CloudKit
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
When the app runs on several devices, sync tip state so a person who learned
|
|
57
|
+
a feature on their iPhone is not taught it again on their iPad. Add a CloudKit
|
|
58
|
+
container next to the datastore option (`cloudKitContainer` needs iOS 18):
|
|
65
59
|
|
|
66
60
|
```swift
|
|
67
61
|
try? Tips.configure([
|
|
68
62
|
.datastoreLocation(.applicationDefault),
|
|
69
|
-
.cloudKitContainer(.named("iCloud.com.example.
|
|
63
|
+
.cloudKitContainer(.named("iCloud.com.example.gardenjournal"))
|
|
70
64
|
])
|
|
71
65
|
```
|
|
72
66
|
|
|
73
|
-
## Defining
|
|
67
|
+
## Defining a tip
|
|
74
68
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
A tip is a struct that conforms to `Tip`. Only `title` (a `Text`) is
|
|
70
|
+
required. `message` (`Text?`) adds a line of context and `image` (`Image?`)
|
|
71
|
+
adds a leading icon. The callout is small, so write the title as a short
|
|
72
|
+
instruction.
|
|
78
73
|
|
|
79
74
|
```swift
|
|
80
|
-
|
|
75
|
+
struct PinPlantTip: Tip {
|
|
76
|
+
var title: Text {
|
|
77
|
+
Text("Pin a plant")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var message: Text? {
|
|
81
|
+
Text("Pinned plants stay at the top of your journal.")
|
|
82
|
+
}
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
var image: Image? { Image(systemName: "heart") }
|
|
84
|
+
var image: Image? {
|
|
85
|
+
Image(systemName: "pin")
|
|
86
|
+
}
|
|
86
87
|
}
|
|
87
88
|
```
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
Optional members:
|
|
91
|
+
|
|
92
|
+
- `actions`: buttons shown inside the tip.
|
|
93
|
+
- `rules`: conditions that must hold before the tip can appear.
|
|
94
|
+
- `options`: per-tip display settings such as a maximum count.
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
A tip moves through three states. It is pending while its rules are not yet
|
|
97
|
+
satisfied, eligible once every rule passes, and invalidated when it is
|
|
98
|
+
dismissed, acted on, or invalidated in code. An invalidated tip stays hidden
|
|
99
|
+
for good unless the datastore is reset.
|
|
92
100
|
|
|
93
|
-
##
|
|
101
|
+
## Showing a tip
|
|
94
102
|
|
|
95
|
-
### Inline
|
|
103
|
+
### Inline with TipView
|
|
96
104
|
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
`TipView(tip)` places the tip in the layout as a rounded card that animates
|
|
106
|
+
in and out. Use it for tips that sit among scrolling content.
|
|
99
107
|
|
|
100
108
|
```swift
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
struct JournalHomeView: View {
|
|
110
|
+
let pinTip = PinPlantTip()
|
|
111
|
+
|
|
112
|
+
var body: some View {
|
|
113
|
+
VStack {
|
|
114
|
+
TipView(pinTip)
|
|
115
|
+
PlantListView()
|
|
116
|
+
}
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
119
|
```
|
|
109
120
|
|
|
110
|
-
###
|
|
121
|
+
### As a popover
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
`.popoverTip(tip)` attaches the tip to a view and draws an arrow to it. Use it
|
|
124
|
+
when the tip explains one particular control. Pass `arrowEdge:` to choose the
|
|
125
|
+
arrow direction, or leave it out and let the system decide.
|
|
114
126
|
|
|
115
127
|
```swift
|
|
116
|
-
Button
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
.popoverTip(favoriteTip, arrowEdge: .bottom)
|
|
128
|
+
Button("Water", systemImage: "drop") {
|
|
129
|
+
logWatering()
|
|
130
|
+
}
|
|
131
|
+
.popoverTip(waterTip, arrowEdge: .bottom)
|
|
121
132
|
```
|
|
122
133
|
|
|
123
|
-
###
|
|
134
|
+
### A custom look with TipViewStyle
|
|
124
135
|
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
To restyle tips across the app, adopt `TipViewStyle` and implement
|
|
137
|
+
`makeBody(configuration:)`. The configuration carries `title` plus optional
|
|
138
|
+
`image` and `message`.
|
|
127
139
|
|
|
128
140
|
```swift
|
|
129
|
-
struct
|
|
141
|
+
struct LeafTipStyle: TipViewStyle {
|
|
130
142
|
func makeBody(configuration: Configuration) -> some View {
|
|
131
|
-
HStack {
|
|
132
|
-
configuration.image
|
|
133
|
-
.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
VStack(alignment: .leading) {
|
|
143
|
+
HStack(alignment: .top, spacing: 10) {
|
|
144
|
+
configuration.image
|
|
145
|
+
.foregroundStyle(.green)
|
|
146
|
+
VStack(alignment: .leading, spacing: 4) {
|
|
137
147
|
configuration.title
|
|
138
148
|
.font(.headline)
|
|
139
|
-
configuration.message
|
|
149
|
+
configuration.message
|
|
140
150
|
.font(.subheadline)
|
|
141
151
|
.foregroundStyle(.secondary)
|
|
142
152
|
}
|
|
@@ -144,353 +154,228 @@ struct CustomTipStyle: TipViewStyle {
|
|
|
144
154
|
.padding()
|
|
145
155
|
}
|
|
146
156
|
}
|
|
147
|
-
|
|
148
|
-
// Apply globally or per view
|
|
149
|
-
TipView(favoriteTip)
|
|
150
|
-
.tipViewStyle(CustomTipStyle())
|
|
151
157
|
```
|
|
152
158
|
|
|
153
|
-
|
|
159
|
+
Apply it with `.tipViewStyle(LeafTipStyle())` on a single tip view or on a
|
|
160
|
+
container to cover everything below it.
|
|
161
|
+
|
|
162
|
+
## Rules
|
|
154
163
|
|
|
155
|
-
Rules
|
|
156
|
-
|
|
157
|
-
parameter-based and event-based.
|
|
164
|
+
Rules decide eligibility. Every rule in `rules` has to pass before the tip is
|
|
165
|
+
shown. There are two kinds.
|
|
158
166
|
|
|
159
|
-
### Parameter
|
|
167
|
+
### Parameter rules (app state)
|
|
160
168
|
|
|
161
|
-
|
|
162
|
-
|
|
169
|
+
Declare a `@Parameter` static on the tip, write a rule against its projected
|
|
170
|
+
value, and assign the static when the state changes.
|
|
163
171
|
|
|
164
172
|
```swift
|
|
165
|
-
struct
|
|
173
|
+
struct SortPlantsTip: Tip {
|
|
166
174
|
@Parameter
|
|
167
|
-
static var
|
|
175
|
+
static var hasOpenedList: Bool = false
|
|
168
176
|
|
|
169
|
-
var title: Text { Text("
|
|
177
|
+
var title: Text { Text("Sort by watering date") }
|
|
170
178
|
|
|
171
179
|
var rules: [Rule] {
|
|
172
|
-
#Rule(Self.$
|
|
180
|
+
#Rule(Self.$hasOpenedList) { $0 == true }
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
183
|
|
|
176
|
-
|
|
177
|
-
FavoriteTip.hasSeenList = true
|
|
184
|
+
SortPlantsTip.hasOpenedList = true
|
|
178
185
|
```
|
|
179
186
|
|
|
180
|
-
### Event
|
|
187
|
+
### Event rules (user actions)
|
|
181
188
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
performed an action several times without discovering a related feature.
|
|
189
|
+
Declare a `Tips.Event`, donate to it every time the action happens, and write
|
|
190
|
+
a rule on the donations. A rule can look at how many donations there are or
|
|
191
|
+
when they happened.
|
|
186
192
|
|
|
187
193
|
```swift
|
|
188
|
-
struct
|
|
189
|
-
static let
|
|
194
|
+
struct QuickLogTip: Tip {
|
|
195
|
+
static let entryAdded = Tips.Event(id: "entryAdded")
|
|
190
196
|
|
|
191
|
-
var title: Text { Text("
|
|
197
|
+
var title: Text { Text("Log faster with a long press") }
|
|
192
198
|
|
|
193
199
|
var rules: [Rule] {
|
|
194
|
-
#Rule(Self.
|
|
200
|
+
#Rule(Self.entryAdded) { $0.donations.count >= 3 }
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
|
|
198
|
-
|
|
199
|
-
ShortcutTip.appOpenedEvent.donate()
|
|
204
|
+
Task { await QuickLogTip.entryAdded.donate() }
|
|
200
205
|
```
|
|
201
206
|
|
|
202
|
-
|
|
207
|
+
Event rules fit tips that should appear only after someone has repeated a
|
|
208
|
+
task several times without finding the shortcut that would help.
|
|
203
209
|
|
|
204
|
-
|
|
210
|
+
### Several rules together
|
|
205
211
|
|
|
206
|
-
|
|
207
|
-
struct AdvancedTip: Tip {
|
|
208
|
-
@Parameter
|
|
209
|
-
static var isLoggedIn: Bool = false
|
|
210
|
-
|
|
211
|
-
static let featureUsedEvent = Tips.Event(id: "featureUsed")
|
|
212
|
-
|
|
213
|
-
var title: Text { Text("Unlock Advanced Mode") }
|
|
212
|
+
List more than one `#Rule` and all of them must pass (logical AND):
|
|
214
213
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
214
|
+
```swift
|
|
215
|
+
var rules: [Rule] {
|
|
216
|
+
#Rule(Self.$isSignedIn) { $0 == true }
|
|
217
|
+
#Rule(Self.entryAdded) { $0.donations.count >= 5 }
|
|
219
218
|
}
|
|
220
219
|
```
|
|
221
220
|
|
|
222
|
-
###
|
|
221
|
+
### How often tips appear
|
|
223
222
|
|
|
224
|
-
|
|
223
|
+
Per tip, `options` adjusts display behavior:
|
|
225
224
|
|
|
226
225
|
```swift
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
var options: [TipOption] {
|
|
231
|
-
MaxDisplayCount(3) // Show at most 3 times total
|
|
232
|
-
IgnoresDisplayFrequency(true) // Bypass global frequency limit
|
|
233
|
-
}
|
|
226
|
+
var options: [TipOption] {
|
|
227
|
+
Tips.MaxDisplayCount(3)
|
|
228
|
+
Tips.IgnoresDisplayFrequency(true)
|
|
234
229
|
}
|
|
235
230
|
```
|
|
236
231
|
|
|
237
|
-
|
|
232
|
+
- `MaxDisplayCount(3)` stops the tip after three showings in total.
|
|
233
|
+
- `IgnoresDisplayFrequency(true)` lets this tip bypass the global limit.
|
|
234
|
+
|
|
235
|
+
The global limit is set at configuration time with
|
|
236
|
+
`.displayFrequency(...)`, taking `.immediate`, `.hourly`, `.daily`, `.weekly`
|
|
237
|
+
or `.monthly`. With `.daily`, the whole app shows at most one tip per day,
|
|
238
|
+
except for tips that opt out with `IgnoresDisplayFrequency(true)`.
|
|
238
239
|
|
|
239
240
|
```swift
|
|
240
|
-
try? Tips.configure([
|
|
241
|
-
.displayFrequency(.daily) // .immediate, .hourly, .daily, .weekly, .monthly
|
|
242
|
-
])
|
|
241
|
+
try? Tips.configure([.displayFrequency(.daily)])
|
|
243
242
|
```
|
|
244
243
|
|
|
245
|
-
|
|
246
|
-
app, unless a specific tip sets `IgnoresDisplayFrequency(true)`.
|
|
244
|
+
## Actions
|
|
247
245
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
and a label. Handle the action in the tip view's action handler.
|
|
246
|
+
`actions` adds buttons to a tip. Each `Action(id:title:)` gets an identifier
|
|
247
|
+
and a label. Handle taps in the closure passed to `TipView`, switching on the
|
|
248
|
+
identifier.
|
|
252
249
|
|
|
253
250
|
```swift
|
|
254
|
-
struct
|
|
255
|
-
var title: Text { Text("
|
|
256
|
-
var message: Text? { Text("We added a powerful new editing mode.") }
|
|
251
|
+
struct ReminderTip: Tip {
|
|
252
|
+
var title: Text { Text("Never miss a watering") }
|
|
257
253
|
|
|
258
254
|
var actions: [Action] {
|
|
259
|
-
Action(id: "
|
|
260
|
-
Action(id: "
|
|
255
|
+
Action(id: "set-reminder", title: "Set Reminder")
|
|
256
|
+
Action(id: "show-guide", title: "How It Works")
|
|
261
257
|
}
|
|
262
258
|
}
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
Handle actions in the view:
|
|
266
259
|
|
|
267
|
-
|
|
268
|
-
TipView(featureTip) { action in
|
|
260
|
+
TipView(reminderTip) { action in
|
|
269
261
|
switch action.id {
|
|
270
|
-
case "
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
case "
|
|
274
|
-
|
|
262
|
+
case "set-reminder":
|
|
263
|
+
reminderTip.invalidate(reason: .actionPerformed)
|
|
264
|
+
openReminderEditor()
|
|
265
|
+
case "show-guide":
|
|
266
|
+
isGuidePresented = true
|
|
275
267
|
default:
|
|
276
268
|
break
|
|
277
269
|
}
|
|
278
270
|
}
|
|
279
271
|
```
|
|
280
272
|
|
|
281
|
-
## Tip
|
|
273
|
+
## Tip groups
|
|
282
274
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
275
|
+
When one screen has several tips, put them in a `TipGroup` (iOS 18 and
|
|
276
|
+
later) so only one is visible at a time. The `.ordered` priority shows them in
|
|
277
|
+
the order listed. Render `currentTip` when it is not nil; invalidating it
|
|
278
|
+
makes the next eligible tip current.
|
|
286
279
|
|
|
287
280
|
```swift
|
|
288
|
-
struct
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
281
|
+
struct PlantDetailView: View {
|
|
282
|
+
@State private var tips = TipGroup(.ordered) {
|
|
283
|
+
PinPlantTip()
|
|
284
|
+
SortPlantsTip()
|
|
285
|
+
QuickLogTip()
|
|
293
286
|
}
|
|
294
287
|
|
|
295
288
|
var body: some View {
|
|
296
289
|
VStack {
|
|
297
|
-
if let
|
|
298
|
-
TipView(
|
|
290
|
+
if let tip = tips.currentTip {
|
|
291
|
+
TipView(tip)
|
|
299
292
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
tipGroup.currentTip?.invalidate(reason: .actionPerformed)
|
|
293
|
+
Button("Next hint") {
|
|
294
|
+
tips.currentTip?.invalidate(reason: .actionPerformed)
|
|
303
295
|
}
|
|
304
296
|
}
|
|
305
297
|
}
|
|
306
298
|
}
|
|
307
299
|
```
|
|
308
300
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
| Initializer | Behavior |
|
|
312
|
-
|---|---|
|
|
313
|
-
| `.ordered` | Tips display in the order they are listed |
|
|
314
|
-
|
|
315
|
-
When the current tip is invalidated, the next eligible tip in the group
|
|
316
|
-
becomes `currentTip`.
|
|
317
|
-
|
|
318
|
-
## Programmatic Control
|
|
319
|
-
|
|
320
|
-
### Invalidating Tips
|
|
321
|
-
|
|
322
|
-
Call `invalidate(reason:)` when the user performs the discovered action or
|
|
323
|
-
when the tip is no longer relevant.
|
|
324
|
-
|
|
325
|
-
```swift
|
|
326
|
-
let tip = FavoriteTip()
|
|
327
|
-
tip.invalidate(reason: .actionPerformed)
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
| Reason | When to Use |
|
|
331
|
-
|---|---|
|
|
332
|
-
| `.actionPerformed` | User performed the action the tip describes |
|
|
333
|
-
| `.displayCountExceeded` | Tip hit its maximum display count |
|
|
334
|
-
| `.tipClosed` | User explicitly dismissed the tip |
|
|
335
|
-
|
|
336
|
-
### Testing Utilities
|
|
337
|
-
|
|
338
|
-
TipKit provides static methods to control tip visibility during development
|
|
339
|
-
and testing. Gate these behind `#if DEBUG` or `ProcessInfo` checks so they
|
|
340
|
-
never run in production builds.
|
|
301
|
+
## Controlling tips from code
|
|
341
302
|
|
|
342
|
-
|
|
343
|
-
#if DEBUG
|
|
344
|
-
// Show all tips regardless of rules (useful during development)
|
|
345
|
-
Tips.showAllTipsForTesting()
|
|
346
|
-
|
|
347
|
-
// Show only specific tips
|
|
348
|
-
Tips.showTipsForTesting([FavoriteTip.self, ShortcutTip.self])
|
|
349
|
-
|
|
350
|
-
// Hide all tips (useful for UI tests that do not involve tips)
|
|
351
|
-
Tips.hideAllTipsForTesting()
|
|
303
|
+
### Invalidation
|
|
352
304
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
#endif
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### Using ProcessInfo for Test Schemes
|
|
305
|
+
Call `tip.invalidate(reason:)` once the person performs the action the tip
|
|
306
|
+
describes, or when the tip no longer applies.
|
|
359
307
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
308
|
+
| Reason | Meaning |
|
|
309
|
+
| --- | --- |
|
|
310
|
+
| `.actionPerformed` | The person did what the tip suggests. |
|
|
311
|
+
| `.displayCountExceeded` | The tip hit its maximum display count. |
|
|
312
|
+
| `.tipClosed` | The person closed the tip. |
|
|
365
313
|
|
|
366
|
-
|
|
367
|
-
development builds.
|
|
314
|
+
### Testing helpers
|
|
368
315
|
|
|
369
|
-
|
|
316
|
+
| Call | Effect |
|
|
317
|
+
| --- | --- |
|
|
318
|
+
| `Tips.showAllTipsForTesting()` | Shows every tip and ignores rules. |
|
|
319
|
+
| `Tips.showTipsForTesting([PinPlantTip.self, QuickLogTip.self])` | Shows only the listed tip types. |
|
|
320
|
+
| `Tips.hideAllTipsForTesting()` | Hides all tips, for UI tests that are not about tips. |
|
|
321
|
+
| `try? Tips.resetDatastore()` | Clears tip state, invalidations and event donations. |
|
|
370
322
|
|
|
371
|
-
|
|
323
|
+
None of these may run in production. Put them behind `#if DEBUG` or a
|
|
324
|
+
launch-argument check.
|
|
372
325
|
|
|
373
|
-
|
|
374
|
-
creates a race condition where tip views try to render before the
|
|
375
|
-
datastore is ready, causing missing or flickering tips.
|
|
326
|
+
### Launch arguments for development schemes
|
|
376
327
|
|
|
377
328
|
```swift
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
.task { try? Tips.configure() } // Too late, views already rendered
|
|
329
|
+
init() {
|
|
330
|
+
#if DEBUG
|
|
331
|
+
if ProcessInfo.processInfo.arguments.contains("--show-all-tips") {
|
|
332
|
+
Tips.showAllTipsForTesting()
|
|
383
333
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
// CORRECT
|
|
387
|
-
@main struct MyApp: App {
|
|
388
|
-
init() { try? Tips.configure() }
|
|
389
|
-
var body: some Scene { WindowGroup { ContentView() } }
|
|
334
|
+
#endif
|
|
335
|
+
try? Tips.configure()
|
|
390
336
|
}
|
|
391
337
|
```
|
|
392
338
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
### DON'T: Leave testing tips enabled in production
|
|
432
|
-
|
|
433
|
-
`Tips.showAllTipsForTesting()` bypasses all rules and frequency limits.
|
|
434
|
-
Shipping this in production means every user sees every tip immediately.
|
|
435
|
-
|
|
436
|
-
```swift
|
|
437
|
-
// WRONG: Always active
|
|
438
|
-
Tips.showAllTipsForTesting()
|
|
439
|
-
|
|
440
|
-
// CORRECT: Gated behind DEBUG
|
|
441
|
-
#if DEBUG
|
|
442
|
-
Tips.showAllTipsForTesting()
|
|
443
|
-
#endif
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
### DON'T: Make tip titles too long
|
|
447
|
-
|
|
448
|
-
Long titles get truncated or wrap awkwardly in the compact tip callout.
|
|
449
|
-
Put the key action in the title and supporting context in the message.
|
|
450
|
-
|
|
451
|
-
```swift
|
|
452
|
-
// WRONG
|
|
453
|
-
var title: Text { Text("You can tap the heart button to save this item to your favorites list") }
|
|
454
|
-
|
|
455
|
-
// CORRECT
|
|
456
|
-
var title: Text { Text("Save to Favorites") }
|
|
457
|
-
var message: Text? { Text("Tap the heart icon to keep items for quick access.") }
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
### DON'T: Use tips for critical information
|
|
461
|
-
|
|
462
|
-
Users can dismiss tips at any time and they do not reappear. Never put
|
|
463
|
-
essential instructions or safety information in a tip.
|
|
464
|
-
|
|
465
|
-
```swift
|
|
466
|
-
// WRONG: Critical info in a dismissible tip
|
|
467
|
-
struct DataLossTip: Tip {
|
|
468
|
-
var title: Text { Text("Unsaved changes will be lost") }
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// CORRECT: Use an alert or inline warning for critical information
|
|
472
|
-
// Reserve tips for feature discovery and progressive disclosure
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
## Review Checklist
|
|
476
|
-
|
|
477
|
-
- [ ] `Tips.configure()` called in `App.init`, before any views render
|
|
478
|
-
- [ ] Each tip has a clear, concise title (action-oriented, under ~40 characters)
|
|
479
|
-
- [ ] Tips invalidated when the user performs the discovered action
|
|
480
|
-
- [ ] Rules set so tips appear at the right time (not immediately on first launch for all tips)
|
|
481
|
-
- [ ] `TipGroup` used when multiple tips exist in one view
|
|
482
|
-
- [ ] Testing utilities (`showAllTipsForTesting`, `resetDatastore`) gated behind `#if DEBUG`
|
|
483
|
-
- [ ] CloudKit sync configured if the app supports multiple devices
|
|
484
|
-
- [ ] Display frequency set appropriately (`.daily` or `.weekly` for most apps)
|
|
485
|
-
- [ ] Tips used for feature discovery only, not for critical information
|
|
486
|
-
- [ ] Custom `TipViewStyle` applied consistently if the default style does not match the app design
|
|
487
|
-
- [ ] Tip actions handled and tip invalidated in the action handler
|
|
488
|
-
- [ ] Event donations placed at the correct user action points
|
|
489
|
-
- [ ] Ensure custom Tip types are Sendable; configure Tips on @MainActor
|
|
339
|
+
Add `--show-all-tips` under Arguments Passed On Launch in a development
|
|
340
|
+
scheme.
|
|
341
|
+
|
|
342
|
+
## Pitfalls
|
|
343
|
+
|
|
344
|
+
- Configuring in `onAppear` or `.task`. The race leaves tips missing or
|
|
345
|
+
flickering. Configure in `App.init`.
|
|
346
|
+
- Several `TipView`s on screen at once. People feel swamped and start
|
|
347
|
+
ignoring tips. Sequence them with `TipGroup(.ordered)` and `currentTip`.
|
|
348
|
+
- Leaving a tip up after the person already did the thing. A stale hint costs
|
|
349
|
+
trust. Call `invalidate(reason: .actionPerformed)` in the action of the
|
|
350
|
+
control that carries the `.popoverTip`.
|
|
351
|
+
- Shipping `showAllTipsForTesting()` without a guard. It skips rules and
|
|
352
|
+
frequency limits, so every user sees every tip at once. Wrap it in
|
|
353
|
+
`#if DEBUG`.
|
|
354
|
+
- Long titles. They truncate or wrap awkwardly. Keep the action in the title
|
|
355
|
+
and the explanation in the message.
|
|
356
|
+
- Using a tip for critical or safety information. Tips can be dismissed and
|
|
357
|
+
never return. Use an alert or an inline warning.
|
|
358
|
+
|
|
359
|
+
## Review checklist
|
|
360
|
+
|
|
361
|
+
- [ ] `Tips.configure()` runs in `App.init`, before any view renders.
|
|
362
|
+
- [ ] Titles are short, clear and action oriented, roughly 40 characters or
|
|
363
|
+
fewer.
|
|
364
|
+
- [ ] Each tip is invalidated when its action is performed.
|
|
365
|
+
- [ ] Rules keep tips from all firing on first launch.
|
|
366
|
+
- [ ] Screens with more than one tip use `TipGroup`.
|
|
367
|
+
- [ ] `showAllTipsForTesting` and `resetDatastore` sit behind `#if DEBUG`.
|
|
368
|
+
- [ ] CloudKit sync is configured when the app runs on more than one device.
|
|
369
|
+
- [ ] Display frequency suits the app; `.daily` or `.weekly` fits most.
|
|
370
|
+
- [ ] Tips are used for feature discovery only, never for critical information.
|
|
371
|
+
- [ ] A custom `TipViewStyle` is applied consistently where the default look
|
|
372
|
+
clashes with the design.
|
|
373
|
+
- [ ] Tip actions are handled and the tip is invalidated in the handler.
|
|
374
|
+
- [ ] Event donations happen at the right user-action points.
|
|
375
|
+
- [ ] Tip types are `Sendable`, and TipKit is configured on the `@MainActor`.
|
|
490
376
|
|
|
491
377
|
## References
|
|
492
378
|
|
|
493
|
-
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
379
|
+
- [references/tipkit-patterns.md](references/tipkit-patterns.md): complete
|
|
380
|
+
tips with rules and events, placement, donation values, custom styles, tip
|
|
381
|
+
group sequencing, previews and tests, onboarding and a full app example.
|