@devo-bmad-custom/agent-orchestration 1.0.2 → 1.0.3
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/lib/installer.js +33 -0
- package/package.json +1 -1
- package/src/.agents/skills/audit-website/README.md +20 -20
- package/src/.agents/skills/audit-website/SKILL.md +470 -470
- package/src/.agents/skills/audit-website/agents/openai.yaml +6 -6
- package/src/.agents/skills/audit-website/assets/icon-small.svg +41 -41
- package/src/.agents/skills/audit-website/references/OUTPUT-FORMAT.md +250 -250
- package/src/.agents/skills/clean-code-standards/SKILL.md +104 -104
- package/src/.agents/skills/excalidraw-dark-standard/SKILL.md +281 -281
- package/src/.agents/skills/frontend-responsive-design-standards/SKILL.md +434 -434
- package/src/.agents/skills/java-fundamentals/SKILL.md +116 -116
- package/src/.agents/skills/java-performance/SKILL.md +119 -119
- package/src/.agents/skills/next-best-practices/SKILL.md +153 -153
- package/src/.agents/skills/next-best-practices/async-patterns.md +87 -87
- package/src/.agents/skills/next-best-practices/bundling.md +180 -180
- package/src/.agents/skills/next-best-practices/data-patterns.md +297 -297
- package/src/.agents/skills/next-best-practices/debug-tricks.md +105 -105
- package/src/.agents/skills/next-best-practices/directives.md +73 -73
- package/src/.agents/skills/next-best-practices/error-handling.md +227 -227
- package/src/.agents/skills/next-best-practices/file-conventions.md +140 -140
- package/src/.agents/skills/next-best-practices/font.md +245 -245
- package/src/.agents/skills/next-best-practices/functions.md +108 -108
- package/src/.agents/skills/next-best-practices/hydration-error.md +91 -91
- package/src/.agents/skills/next-best-practices/image.md +173 -173
- package/src/.agents/skills/next-best-practices/metadata.md +301 -301
- package/src/.agents/skills/next-best-practices/parallel-routes.md +287 -287
- package/src/.agents/skills/next-best-practices/route-handlers.md +146 -146
- package/src/.agents/skills/next-best-practices/rsc-boundaries.md +159 -159
- package/src/.agents/skills/next-best-practices/runtime-selection.md +39 -39
- package/src/.agents/skills/next-best-practices/scripts.md +141 -141
- package/src/.agents/skills/next-best-practices/self-hosting.md +371 -371
- package/src/.agents/skills/next-best-practices/suspense-boundaries.md +67 -67
- package/src/.agents/skills/nextjs-app-router-patterns/SKILL.md +537 -537
- package/src/.agents/skills/postgresql-optimization/SKILL.md +404 -404
- package/src/.agents/skills/python-backend/SKILL.md +153 -153
- package/src/.agents/skills/python-fundamentals/SKILL.md +234 -234
- package/src/.agents/skills/python-performance/SKILL.md +404 -404
- package/src/.agents/skills/react-expert/SKILL.md +335 -335
- package/src/.agents/skills/redis-best-practices/SKILL.md +438 -438
- package/src/.agents/skills/security-best-practices/SKILL.md +288 -288
- package/src/.agents/skills/security-review/LICENSE +22 -22
- package/src/.agents/skills/security-review/SKILL.md +312 -312
- package/src/.agents/skills/security-review/infrastructure/docker.md +432 -432
- package/src/.agents/skills/security-review/languages/javascript.md +388 -388
- package/src/.agents/skills/security-review/languages/python.md +363 -363
- package/src/.agents/skills/security-review/references/api-security.md +519 -519
- package/src/.agents/skills/security-review/references/authentication.md +353 -353
- package/src/.agents/skills/security-review/references/authorization.md +372 -372
- package/src/.agents/skills/security-review/references/business-logic.md +443 -443
- package/src/.agents/skills/security-review/references/cryptography.md +329 -329
- package/src/.agents/skills/security-review/references/csrf.md +398 -398
- package/src/.agents/skills/security-review/references/data-protection.md +378 -378
- package/src/.agents/skills/security-review/references/deserialization.md +410 -410
- package/src/.agents/skills/security-review/references/error-handling.md +436 -436
- package/src/.agents/skills/security-review/references/file-security.md +457 -457
- package/src/.agents/skills/security-review/references/injection.md +259 -259
- package/src/.agents/skills/security-review/references/logging.md +433 -433
- package/src/.agents/skills/security-review/references/misconfiguration.md +435 -435
- package/src/.agents/skills/security-review/references/modern-threats.md +475 -475
- package/src/.agents/skills/security-review/references/ssrf.md +415 -415
- package/src/.agents/skills/security-review/references/supply-chain.md +405 -405
- package/src/.agents/skills/security-review/references/xss.md +336 -336
- package/src/.agents/skills/subagent-driven-development/SKILL.md +275 -275
- package/src/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -26
- package/src/.agents/skills/subagent-driven-development/implementer-prompt.md +113 -113
- package/src/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -61
- package/src/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/src/.agents/skills/systematic-debugging/SKILL.md +296 -296
- package/src/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/src/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/src/.agents/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/src/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/src/.agents/skills/systematic-debugging/test-academic.md +14 -14
- package/src/.agents/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/src/.agents/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/src/.agents/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/src/.agents/skills/typescript-best-practices/SKILL.md +373 -373
- package/src/.agents/skills/ui-ux-pro-custom/SKILL.md +348 -348
- package/src/.agents/skills/ui-ux-pro-custom/data/charts.csv +26 -26
- package/src/.agents/skills/ui-ux-pro-custom/data/colors.csv +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/icons.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/SKILL.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/accessibility.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/animation.md +466 -466
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/composition-locals.md +231 -231
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/deprecated-patterns.md +323 -323
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/lists-scrolling.md +400 -400
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/modifiers.md +331 -331
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/navigation.md +416 -416
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/performance.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/side-effects.md +516 -516
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/foundation-source.md +13327 -13327
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/material3-source.md +19097 -19097
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/navigation-source.md +2947 -2947
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/runtime-source.md +11316 -11316
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/ui-source.md +7896 -7896
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/state-management.md +377 -377
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/styles-experimental.md +470 -470
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/theming-material3.md +349 -349
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/view-composition.md +595 -595
- package/src/.agents/skills/ui-ux-pro-custom/data/landing.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/data/mobile-ui-layout.md +654 -654
- package/src/.agents/skills/ui-ux-pro-custom/data/products.csv +96 -96
- package/src/.agents/skills/ui-ux-pro-custom/data/react-performance.csv +45 -45
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/astro.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/flutter.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/html-tailwind.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/jetpack-compose.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nextjs.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxt-ui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxtjs.csv +59 -59
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react-native.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/shadcn.csv +61 -61
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/svelte.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/swiftui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/vue.csv +50 -50
- package/src/.agents/skills/ui-ux-pro-custom/data/styles.csv +68 -68
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/SKILL.md +438 -438
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/references/alarmkit-patterns.md +584 -584
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-clips/SKILL.md +436 -436
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/SKILL.md +489 -489
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/references/appintents-advanced.md +1076 -1076
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/SKILL.md +340 -340
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/privacy-manifest.md +90 -90
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/review-checklists.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-conversion.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-optimization.md +344 -344
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/foundation-models.md +508 -508
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/mlx-swift.md +285 -285
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/references/keychain-biometric.md +211 -211
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/SKILL.md +499 -499
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/references/background-task-patterns.md +390 -390
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/SKILL.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/references/callkit-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/SKILL.md +492 -492
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/references/cloudkit-patterns.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/codable-patterns/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/SKILL.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/references/contacts-patterns.md +409 -409
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/references/ble-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/SKILL.md +388 -388
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/references/motion-patterns.md +405 -405
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/SKILL.md +495 -495
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/references/nfc-patterns.md +420 -420
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/SKILL.md +459 -459
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/references/coreml-swift-integration.md +765 -765
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/SKILL.md +422 -422
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/instruments-guide.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/lldb-patterns.md +298 -298
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/device-integrity/SKILL.md +477 -477
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/SKILL.md +460 -460
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/references/energykit-patterns.md +541 -541
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/references/eventkit-patterns.md +326 -326
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/references/healthkit-patterns.md +602 -602
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/references/matter-commissioning.md +455 -455
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/SKILL.md +301 -301
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/references/a11y-patterns.md +140 -140
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/SKILL.md +418 -418
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/formatstyle-locale.md +627 -627
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/string-catalogs.md +462 -462
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/SKILL.md +441 -441
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/background-websocket.md +862 -862
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/lightweight-clients.md +93 -93
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/network-framework.md +563 -563
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/urlsession-patterns.md +1116 -1116
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/app-review-guidelines.md +174 -174
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/cryptokit-advanced.md +296 -296
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/file-storage-patterns.md +354 -354
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/privacy-manifest.md +117 -117
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/references/live-activity-patterns.md +868 -868
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/corelocation-patterns.md +730 -730
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/mapkit-patterns.md +748 -748
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/metrickit-diagnostics/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/SKILL.md +395 -395
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/references/musickit-patterns.md +363 -363
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/SKILL.md +412 -412
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/references/translation-patterns.md +311 -311
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/SKILL.md +398 -398
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/references/wallet-passes.md +254 -254
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/SKILL.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/paperkit-integration.md +376 -376
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/pencilkit-patterns.md +302 -302
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/SKILL.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/references/permissionkit-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/av-playback.md +701 -701
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/camera-capture.md +774 -774
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/image-loading-caching.md +869 -869
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/photospicker-patterns.md +597 -597
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/notification-patterns.md +677 -677
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/rich-notifications.md +745 -745
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/references/realitykit-patterns.md +480 -480
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/references/shareplay-patterns.md +544 -544
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/speech-recognition/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/SKILL.md +478 -478
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/app-review-guidelines.md +58 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/storekit-advanced.md +755 -755
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/SKILL.md +487 -487
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/references/charts-patterns.md +895 -895
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/SKILL.md +408 -408
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/approachable-concurrency.md +80 -80
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swift-6-2-concurrency.md +233 -233
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swiftui-concurrency.md +187 -187
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/synchronization-primitives.md +341 -341
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/references/swift-patterns-extended.md +505 -505
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/references/testing-patterns.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/SKILL.md +334 -334
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/core-data-coexistence.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-advanced.md +975 -975
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-queries.md +675 -675
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/SKILL.md +481 -481
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/animation-advanced.md +804 -804
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/core-animation-bridge.md +553 -553
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/SKILL.md +450 -450
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/references/gesture-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/SKILL.md +336 -336
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/form.md +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/grids.md +69 -69
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/list.md +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/scrollview.md +147 -147
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/SKILL.md +325 -325
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/references/liquid-glass.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/SKILL.md +262 -262
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/deeplinks.md +207 -207
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/navigationstack.md +177 -177
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/sheets.md +169 -169
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/tabview.md +178 -178
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/SKILL.md +381 -381
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/architecture-patterns.md +486 -486
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/deprecated-migration.md +1097 -1097
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/design-polish.md +780 -780
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/platform-and-sharing.md +696 -696
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -46
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -29
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -33
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -52
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/SKILL.md +428 -428
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/hosting-migration.md +534 -534
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/representable-recipes.md +1133 -1133
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/SKILL.md +494 -494
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/references/tipkit-patterns.md +782 -782
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +736 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +738 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +410 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +567 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +497 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +871 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +57 -57
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +253 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +1067 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +114 -114
- package/src/.agents/skills/ux-audit/SKILL.md +150 -150
- package/src/.agents/skills/websocket-engineer/SKILL.md +168 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +391 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +400 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +195 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +333 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +474 -474
- package/src/.agents/skills/writing-skills/SKILL.md +655 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/src/.agents/skills/writing-skills/persuasion-principles.md +187 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +168 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/src/.claude/commands/master-orchestrator.md +15 -0
- package/src/_memory/config.yaml +11 -11
- package/src/_memory/master-orchestrator-sidecar/instructions.md +85 -32
- package/src/_memory/skills/nimbalyst-tracking/SKILL.md +103 -103
- package/src/_memory/skills/writing-skills/SKILL.md +655 -655
- package/src/bmb/agents/agent-builder.md +59 -59
- package/src/bmb/agents/module-builder.md +60 -60
- package/src/bmb/agents/workflow-builder.md +61 -61
- package/src/bmb/config.yaml +12 -12
- package/src/bmb/module-help.csv +13 -13
- package/src/bmb/workflows/agent/data/agent-architecture.md +258 -258
- package/src/bmb/workflows/agent/data/agent-compilation.md +185 -185
- package/src/bmb/workflows/agent/data/agent-menu-patterns.md +189 -189
- package/src/bmb/workflows/agent/data/agent-metadata.md +133 -133
- package/src/bmb/workflows/agent/data/agent-validation.md +111 -111
- package/src/bmb/workflows/agent/data/brainstorm-context.md +96 -96
- package/src/bmb/workflows/agent/data/communication-presets.csv +61 -61
- package/src/bmb/workflows/agent/data/critical-actions.md +75 -75
- package/src/bmb/workflows/agent/data/persona-properties.md +252 -252
- package/src/bmb/workflows/agent/data/principles-crafting.md +142 -142
- package/src/bmb/workflows/agent/data/reference/module-examples/architect.md +68 -68
- package/src/bmb/workflows/agent/data/reference/with-sidecar/journal-keeper/journal-keeper-sidecar/entries/yy-mm-dd-entry-template.md +16 -16
- package/src/bmb/workflows/agent/data/understanding-agent-types.md +126 -126
- package/src/bmb/workflows/agent/steps-c/step-01-brainstorm.md +129 -129
- package/src/bmb/workflows/agent/steps-c/step-02-discovery.md +170 -170
- package/src/bmb/workflows/agent/steps-c/step-03-sidecar-metadata.md +309 -309
- package/src/bmb/workflows/agent/steps-c/step-04-persona.md +213 -213
- package/src/bmb/workflows/agent/steps-c/step-05-commands-menu.md +179 -179
- package/src/bmb/workflows/agent/steps-c/step-06-activation.md +278 -278
- package/src/bmb/workflows/agent/steps-c/step-07-build-agent.md +316 -316
- package/src/bmb/workflows/agent/steps-c/step-08-celebrate.md +247 -247
- package/src/bmb/workflows/agent/steps-e/e-01-load-existing.md +221 -221
- package/src/bmb/workflows/agent/steps-e/e-02-discover-edits.md +195 -195
- package/src/bmb/workflows/agent/steps-e/e-04-sidecar-metadata.md +126 -126
- package/src/bmb/workflows/agent/steps-e/e-05-persona.md +135 -135
- package/src/bmb/workflows/agent/steps-e/e-06-commands-menu.md +123 -123
- package/src/bmb/workflows/agent/steps-e/e-07-activation.md +124 -124
- package/src/bmb/workflows/agent/steps-e/e-08-edit-agent.md +197 -197
- package/src/bmb/workflows/agent/steps-e/e-09-celebrate.md +155 -155
- package/src/bmb/workflows/agent/steps-v/v-01-load-review.md +137 -137
- package/src/bmb/workflows/agent/steps-v/v-02a-validate-metadata.md +116 -116
- package/src/bmb/workflows/agent/steps-v/v-02b-validate-persona.md +124 -124
- package/src/bmb/workflows/agent/steps-v/v-02c-validate-menu.md +127 -127
- package/src/bmb/workflows/agent/steps-v/v-02d-validate-structure.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-02e-validate-sidecar.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-03-summary.md +104 -104
- package/src/bmb/workflows/agent/templates/agent-plan.template.md +5 -5
- package/src/bmb/workflows/agent/templates/agent-template.md +89 -89
- package/src/bmb/workflows/agent/workflow-create-agent.md +72 -72
- package/src/bmb/workflows/agent/workflow-edit-agent.md +75 -75
- package/src/bmb/workflows/agent/workflow-validate-agent.md +73 -73
- package/src/bmb/workflows/module/data/agent-architecture.md +179 -179
- package/src/bmb/workflows/module/data/agent-spec-template.md +79 -79
- package/src/bmb/workflows/module/data/module-standards.md +263 -263
- package/src/bmb/workflows/module/data/module-yaml-conventions.md +392 -392
- package/src/bmb/workflows/module/module-help-generate.md +254 -254
- package/src/bmb/workflows/module/steps-b/step-01-welcome.md +148 -148
- package/src/bmb/workflows/module/steps-b/step-02-spark.md +141 -141
- package/src/bmb/workflows/module/steps-b/step-03-module-type.md +149 -149
- package/src/bmb/workflows/module/steps-b/step-04-vision.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-05-identity.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-06-users.md +86 -86
- package/src/bmb/workflows/module/steps-b/step-07-value.md +76 -76
- package/src/bmb/workflows/module/steps-b/step-08-agents.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-09-workflows.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-10-tools.md +91 -91
- package/src/bmb/workflows/module/steps-b/step-11-scenarios.md +84 -84
- package/src/bmb/workflows/module/steps-b/step-12-creative.md +95 -95
- package/src/bmb/workflows/module/steps-b/step-13-review.md +105 -105
- package/src/bmb/workflows/module/steps-b/step-14-finalize.md +117 -117
- package/src/bmb/workflows/module/steps-c/step-01-load-brief.md +179 -179
- package/src/bmb/workflows/module/steps-c/step-01b-continue.md +82 -82
- package/src/bmb/workflows/module/steps-c/step-02-structure.md +105 -105
- package/src/bmb/workflows/module/steps-c/step-03-config.md +119 -119
- package/src/bmb/workflows/module/steps-c/step-04-agents.md +168 -168
- package/src/bmb/workflows/module/steps-c/step-05-workflows.md +184 -184
- package/src/bmb/workflows/module/steps-c/step-06-docs.md +401 -401
- package/src/bmb/workflows/module/steps-c/step-07-complete.md +152 -152
- package/src/bmb/workflows/module/steps-e/step-01-load-target.md +81 -81
- package/src/bmb/workflows/module/steps-e/step-02-select-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-03-apply-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-04-review.md +80 -80
- package/src/bmb/workflows/module/steps-e/step-05-confirm.md +75 -75
- package/src/bmb/workflows/module/steps-v/step-01-load-target.md +96 -96
- package/src/bmb/workflows/module/steps-v/step-02-file-structure.md +93 -93
- package/src/bmb/workflows/module/steps-v/step-03-module-yaml.md +99 -99
- package/src/bmb/workflows/module/steps-v/step-04-agent-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-05-workflow-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-06-documentation.md +143 -143
- package/src/bmb/workflows/module/steps-v/step-07-installation.md +102 -102
- package/src/bmb/workflows/module/steps-v/step-08-report.md +197 -197
- package/src/bmb/workflows/module/templates/brief-template.md +154 -154
- package/src/bmb/workflows/module/templates/workflow-spec-template.md +96 -96
- package/src/bmb/workflows/module/workflow-create-module-brief.md +71 -71
- package/src/bmb/workflows/module/workflow-create-module.md +86 -86
- package/src/bmb/workflows/module/workflow-edit-module.md +66 -66
- package/src/bmb/workflows/module/workflow-validate-module.md +66 -66
- package/src/bmb/workflows/workflow/data/architecture.md +150 -150
- package/src/bmb/workflows/workflow/data/common-workflow-tools.csv +19 -19
- package/src/bmb/workflows/workflow/data/csv-data-file-standards.md +53 -53
- package/src/bmb/workflows/workflow/data/frontmatter-standards.md +184 -184
- package/src/bmb/workflows/workflow/data/input-discovery-standards.md +191 -191
- package/src/bmb/workflows/workflow/data/intent-vs-prescriptive-spectrum.md +44 -44
- package/src/bmb/workflows/workflow/data/menu-handling-standards.md +133 -133
- package/src/bmb/workflows/workflow/data/output-format-standards.md +135 -135
- package/src/bmb/workflows/workflow/data/step-file-rules.md +235 -235
- package/src/bmb/workflows/workflow/data/step-type-patterns.md +257 -257
- package/src/bmb/workflows/workflow/data/subprocess-optimization-patterns.md +188 -188
- package/src/bmb/workflows/workflow/data/trimodal-workflow-structure.md +164 -164
- package/src/bmb/workflows/workflow/data/workflow-chaining-standards.md +222 -222
- package/src/bmb/workflows/workflow/data/workflow-examples.md +232 -232
- package/src/bmb/workflows/workflow/data/workflow-type-criteria.md +134 -134
- package/src/bmb/workflows/workflow/steps-c/step-00-conversion.md +263 -263
- package/src/bmb/workflows/workflow/steps-c/step-01-discovery.md +194 -194
- package/src/bmb/workflows/workflow/steps-c/step-01b-continuation.md +3 -3
- package/src/bmb/workflows/workflow/steps-c/step-02-classification.md +270 -270
- package/src/bmb/workflows/workflow/steps-c/step-03-requirements.md +283 -283
- package/src/bmb/workflows/workflow/steps-c/step-04-tools.md +282 -282
- package/src/bmb/workflows/workflow/steps-c/step-05-plan-review.md +243 -243
- package/src/bmb/workflows/workflow/steps-c/step-06-design.md +330 -330
- package/src/bmb/workflows/workflow/steps-c/step-07-foundation.md +239 -239
- package/src/bmb/workflows/workflow/steps-c/step-08-build-step-01.md +379 -379
- package/src/bmb/workflows/workflow/steps-c/step-09-build-next-step.md +350 -350
- package/src/bmb/workflows/workflow/steps-c/step-10-confirmation.md +322 -322
- package/src/bmb/workflows/workflow/steps-c/step-11-completion.md +191 -191
- package/src/bmb/workflows/workflow/steps-e/step-e-01-assess-workflow.md +237 -237
- package/src/bmb/workflows/workflow/steps-e/step-e-02-discover-edits.md +251 -251
- package/src/bmb/workflows/workflow/steps-e/step-e-03-fix-validation.md +254 -254
- package/src/bmb/workflows/workflow/steps-e/step-e-04-direct-edit.md +277 -277
- package/src/bmb/workflows/workflow/steps-e/step-e-05-apply-edit.md +154 -154
- package/src/bmb/workflows/workflow/steps-e/step-e-06-validate-after.md +190 -190
- package/src/bmb/workflows/workflow/steps-e/step-e-07-complete.md +206 -206
- package/src/bmb/workflows/workflow/steps-v/step-01-validate-max-mode.md +109 -109
- package/src/bmb/workflows/workflow/steps-v/step-01-validate.md +221 -221
- package/src/bmb/workflows/workflow/steps-v/step-01b-structure.md +152 -152
- package/src/bmb/workflows/workflow/steps-v/step-02-frontmatter-validation.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-02b-path-violations.md +265 -265
- package/src/bmb/workflows/workflow/steps-v/step-03-menu-validation.md +164 -164
- package/src/bmb/workflows/workflow/steps-v/step-04-step-type-validation.md +211 -211
- package/src/bmb/workflows/workflow/steps-v/step-05-output-format-validation.md +200 -200
- package/src/bmb/workflows/workflow/steps-v/step-06-validation-design-check.md +195 -195
- package/src/bmb/workflows/workflow/steps-v/step-07-instruction-style-check.md +209 -209
- package/src/bmb/workflows/workflow/steps-v/step-08-collaborative-experience-check.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-08b-subprocess-optimization.md +179 -179
- package/src/bmb/workflows/workflow/steps-v/step-09-cohesive-review.md +186 -186
- package/src/bmb/workflows/workflow/steps-v/step-10-report-complete.md +154 -154
- package/src/bmb/workflows/workflow/steps-v/step-11-plan-validation.md +237 -237
- package/src/bmb/workflows/workflow/templates/minimal-output-template.md +11 -11
- package/src/bmb/workflows/workflow/templates/step-01-init-continuable-template.md +241 -241
- package/src/bmb/workflows/workflow/templates/step-1b-template.md +224 -224
- package/src/bmb/workflows/workflow/templates/step-template.md +294 -294
- package/src/bmb/workflows/workflow/templates/workflow-template.md +102 -102
- package/src/bmb/workflows/workflow/workflow-create-workflow.md +79 -79
- package/src/bmb/workflows/workflow/workflow-edit-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-rework-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-validate-max-parallel-workflow.md +66 -66
- package/src/bmb/workflows/workflow/workflow-validate-workflow.md +65 -65
- package/src/bmm/agents/analyst.md +104 -104
- package/src/bmm/agents/dev.md +100 -100
- package/src/bmm/agents/qa.md +100 -90
- package/src/bmm/agents/tech-writer/tech-writer.md +94 -94
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +115 -115
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +107 -107
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +141 -141
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +144 -144
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +147 -147
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +161 -161
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +99 -99
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -57
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +156 -156
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +165 -165
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +140 -140
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +152 -152
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +345 -345
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +92 -92
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +164 -164
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +174 -174
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +184 -184
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +105 -105
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +360 -360
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +165 -165
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +174 -174
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +141 -141
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +159 -159
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +387 -387
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -54
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +100 -100
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +160 -160
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +88 -88
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +99 -99
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +169 -169
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +156 -156
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +176 -176
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +184 -184
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +174 -174
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +175 -175
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +189 -189
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +162 -162
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +79 -79
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +183 -183
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +149 -149
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +187 -187
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +108 -108
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +166 -166
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +131 -131
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +150 -150
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +155 -155
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +170 -170
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +158 -158
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +147 -147
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +182 -182
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +202 -202
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +148 -148
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +201 -201
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +179 -179
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +164 -164
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +106 -106
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +111 -111
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +115 -115
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +127 -127
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +167 -167
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +143 -143
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +154 -154
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +165 -165
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +135 -135
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +101 -101
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +45 -45
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +185 -185
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +130 -130
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +93 -93
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +196 -196
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -54
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +82 -82
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +106 -106
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +138 -138
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +129 -129
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +166 -166
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +186 -186
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +163 -163
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +38 -38
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -49
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +124 -124
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +122 -122
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +84 -84
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -58
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +43 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +53 -53
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +159 -159
- package/src/bmm/workflows/4-implementation/create-story/template.md +79 -79
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +20 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -25
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +158 -158
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +122 -122
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +87 -87
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -146
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -50
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +152 -152
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +123 -123
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -201
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -79
- package/src/bmm/workflows/document-project/workflow.yaml +22 -22
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -184
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +322 -322
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +235 -235
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -49
- package/src/bmm/workflows/qa/automate/workflow.yaml +233 -233
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +42 -42
- package/src/core/config.yaml +9 -9
- package/src/core/module-help.csv +10 -10
- package/src/core/scripts/generate-loop-report.py +72 -72
- package/src/core/tasks/editorial-review-prose.xml +101 -101
- package/src/core/tasks/editorial-review-structure.xml +207 -207
- package/src/core/tasks/help.md +86 -86
- package/src/core/tasks/index-docs.xml +64 -64
- package/src/core/tasks/review-adversarial-general.xml +66 -66
- package/src/core/tasks/review-adversarial-loop.xml +46 -46
- package/src/core/tasks/review-edge-case-hunter.xml +63 -63
- package/src/core/tasks/review-party-loop.xml +46 -46
- package/src/core/tasks/shard-doc.xml +107 -107
- package/src/core/tasks/workflow.xml +235 -235
- package/src/core/templates/review-loop-report.html +88 -88
- package/src/core/templates/review-loop-report.md +5 -5
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -117
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +212 -212
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -122
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -225
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -237
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -209
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -264
- package/src/core/workflows/brainstorming/steps/step-02e-deep-dive.md +68 -68
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +403 -403
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -303
- package/src/core/workflows/brainstorming/workflow.md +60 -60
- package/src/core/workflows/extract-trackers/workflow.md +45 -45
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +142 -142
- package/src/core/workflows/party-mode/workflow.md +194 -194
- package/src/docs/dev/tmux/actions_popup.py +291 -291
- package/src/docs/dev/tmux/tmux-setup.md +62 -1
|
@@ -1,696 +1,696 @@
|
|
|
1
|
-
# Platform And Sharing
|
|
2
|
-
|
|
3
|
-
## Contents
|
|
4
|
-
- [Transferable, Drag & Drop, and ShareLink](#transferable-drag-drop-and-sharelink)
|
|
5
|
-
- [Media Patterns](#media-patterns)
|
|
6
|
-
- [Top Bar Overlays](#top-bar-overlays)
|
|
7
|
-
- [Title Menus](#title-menus)
|
|
8
|
-
- [Input Toolbar](#input-toolbar)
|
|
9
|
-
- [Menu Bar Commands](#menu-bar-commands)
|
|
10
|
-
- [macOS Settings](#macos-settings)
|
|
11
|
-
|
|
12
|
-
## Transferable, Drag & Drop, and ShareLink
|
|
13
|
-
|
|
14
|
-
### Intent
|
|
15
|
-
|
|
16
|
-
Adopt the `Transferable` protocol to enable sharing, drag and drop, copy/paste, and `ShareLink` with a unified API. Available iOS 16+.
|
|
17
|
-
|
|
18
|
-
> **Docs:** [Transferable](https://sosumi.ai/documentation/coretransferable/transferable) · [Choosing a transfer representation](https://sosumi.ai/documentation/coretransferable/choosing-a-transfer-representation-for-a-model-type)
|
|
19
|
-
|
|
20
|
-
### Transferable protocol overview
|
|
21
|
-
|
|
22
|
-
`Transferable` describes how a type converts to and from transfer representations (clipboard, drag, share sheet). Conform by implementing a static `transferRepresentation` property.
|
|
23
|
-
|
|
24
|
-
```swift
|
|
25
|
-
struct Note: Codable, Identifiable {
|
|
26
|
-
let id: UUID
|
|
27
|
-
var title: String
|
|
28
|
-
var body: String
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
extension Note: Transferable {
|
|
32
|
-
static var transferRepresentation: some TransferRepresentation {
|
|
33
|
-
CodableRepresentation(contentType: .note)
|
|
34
|
-
ProxyRepresentation(exporting: \.body) // fallback: plain text
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
extension UTType {
|
|
39
|
-
static let note = UTType(exportedAs: "com.example.note")
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Representation order matters — place the most specific first, with broader fallbacks after.
|
|
44
|
-
|
|
45
|
-
### Built-in conformances
|
|
46
|
-
|
|
47
|
-
These types already conform to `Transferable` out of the box:
|
|
48
|
-
|
|
49
|
-
| Type | Content type |
|
|
50
|
-
|------|-------------|
|
|
51
|
-
| `String` | `.plainText`, `.utf8PlainText` |
|
|
52
|
-
| `Data` | `.data` |
|
|
53
|
-
| `URL` | `.url` |
|
|
54
|
-
| `AttributedString` | `.rtf` |
|
|
55
|
-
| `Image` (SwiftUI) | `.image` |
|
|
56
|
-
| `Color` (SwiftUI) | `.color` |
|
|
57
|
-
|
|
58
|
-
### TransferRepresentation types
|
|
59
|
-
|
|
60
|
-
#### CodableRepresentation
|
|
61
|
-
|
|
62
|
-
For types conforming to `Codable`. Serializes to JSON by default:
|
|
63
|
-
|
|
64
|
-
```swift
|
|
65
|
-
static var transferRepresentation: some TransferRepresentation {
|
|
66
|
-
CodableRepresentation(contentType: .myType)
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
#### ProxyRepresentation
|
|
71
|
-
|
|
72
|
-
Delegate to another `Transferable` type. Ideal for quick text or URL fallbacks:
|
|
73
|
-
|
|
74
|
-
```swift
|
|
75
|
-
ProxyRepresentation(exporting: \.title) // export only
|
|
76
|
-
ProxyRepresentation(\.url) // import + export via URL
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
#### DataRepresentation
|
|
80
|
-
|
|
81
|
-
Full control over binary serialization:
|
|
82
|
-
|
|
83
|
-
```swift
|
|
84
|
-
DataRepresentation(contentType: .png) { image in
|
|
85
|
-
try image.pngData()
|
|
86
|
-
} importing: { data in
|
|
87
|
-
try MyImage(data: data)
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Use `DataRepresentation(exportedContentType:)` for export-only representations.
|
|
92
|
-
|
|
93
|
-
#### FileRepresentation
|
|
94
|
-
|
|
95
|
-
For large content best transferred as files:
|
|
96
|
-
|
|
97
|
-
```swift
|
|
98
|
-
FileRepresentation(contentType: .movie) { video in
|
|
99
|
-
SentTransferredFile(video.fileURL)
|
|
100
|
-
} importing: { receivedFile in
|
|
101
|
-
let dest = FileManager.default.temporaryDirectory.appendingPathComponent(receivedFile.file.lastPathComponent)
|
|
102
|
-
try FileManager.default.copyItem(at: receivedFile.file, to: dest)
|
|
103
|
-
return Video(url: dest)
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### ShareLink
|
|
108
|
-
|
|
109
|
-
Present the system share sheet with a `Transferable` item:
|
|
110
|
-
|
|
111
|
-
```swift
|
|
112
|
-
ShareLink(item: note, preview: SharePreview(note.title)) {
|
|
113
|
-
Label("Share", systemImage: "square.and.arrow.up")
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Multiple items
|
|
117
|
-
ShareLink(items: selectedNotes) { note in
|
|
118
|
-
SharePreview(note.title)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Simple string sharing
|
|
122
|
-
ShareLink(item: "Check out this app!", subject: Text("Cool App"))
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
`ShareLink` requires the item to conform to `Transferable`. The preview provides a title, optional image, and optional icon for the share sheet.
|
|
126
|
-
|
|
127
|
-
### Drag and drop
|
|
128
|
-
|
|
129
|
-
#### Making views draggable
|
|
130
|
-
|
|
131
|
-
```swift
|
|
132
|
-
struct NoteCard: View {
|
|
133
|
-
let note: Note
|
|
134
|
-
|
|
135
|
-
var body: some View {
|
|
136
|
-
Text(note.title)
|
|
137
|
-
.draggable(note) // Note must be Transferable
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Use `.draggable(note) { DragPreview(note) }` to provide a custom drag preview.
|
|
143
|
-
|
|
144
|
-
#### Drop destination
|
|
145
|
-
|
|
146
|
-
```swift
|
|
147
|
-
struct NoteBoard: View {
|
|
148
|
-
@State private var notes: [Note] = []
|
|
149
|
-
|
|
150
|
-
var body: some View {
|
|
151
|
-
VStack {
|
|
152
|
-
ForEach(notes) { NoteCard(note: $0) }
|
|
153
|
-
}
|
|
154
|
-
.dropDestination(for: Note.self) { droppedNotes, location in
|
|
155
|
-
notes.append(contentsOf: droppedNotes)
|
|
156
|
-
return true
|
|
157
|
-
} isTargeted: { isOver in
|
|
158
|
-
// Highlight drop zone
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
For reordering within a list, combine `.draggable` with `.dropDestination` or use `onMove` on `ForEach` inside `List`.
|
|
165
|
-
|
|
166
|
-
#### Handling multiple types
|
|
167
|
-
|
|
168
|
-
Accept multiple content types with separate `.dropDestination` modifiers or use `DropDelegate` for advanced logic:
|
|
169
|
-
|
|
170
|
-
```swift
|
|
171
|
-
.dropDestination(for: String.self) { strings, _ in
|
|
172
|
-
notes.append(contentsOf: strings.map { Note(id: UUID(), title: $0, body: "") })
|
|
173
|
-
return true
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Pasteboard integration
|
|
178
|
-
|
|
179
|
-
For direct clipboard access outside SwiftUI's drag/drop system, use `UIPasteboard`:
|
|
180
|
-
|
|
181
|
-
```swift
|
|
182
|
-
// Copy
|
|
183
|
-
UIPasteboard.general.string = note.title
|
|
184
|
-
|
|
185
|
-
// Paste
|
|
186
|
-
if let text = UIPasteboard.general.string {
|
|
187
|
-
// use text
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
For `Transferable` types with custom content types, export to `Data` first:
|
|
192
|
-
|
|
193
|
-
```swift
|
|
194
|
-
let data = try await note.exported(as: .note)
|
|
195
|
-
UIPasteboard.general.setData(data, forPasteboardType: UTType.note.identifier)
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Prefer SwiftUI's `.copyable`, `.cuttable`, and `.pasteDestination` modifiers (iOS 16+) over direct `UIPasteboard` usage when possible — they integrate with the Edit menu and keyboard shortcuts automatically.
|
|
199
|
-
|
|
200
|
-
### Common patterns
|
|
201
|
-
|
|
202
|
-
#### Transferable enum with multiple representations
|
|
203
|
-
|
|
204
|
-
```swift
|
|
205
|
-
enum SharedContent: Transferable {
|
|
206
|
-
case text(String)
|
|
207
|
-
case url(URL)
|
|
208
|
-
|
|
209
|
-
static var transferRepresentation: some TransferRepresentation {
|
|
210
|
-
ProxyRepresentation { content in
|
|
211
|
-
switch content {
|
|
212
|
-
case .text(let s): return s
|
|
213
|
-
case .url(let u): return u.absoluteString
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
#### Export-only conformance
|
|
221
|
-
|
|
222
|
-
When your type should be sharable but not importable:
|
|
223
|
-
|
|
224
|
-
```swift
|
|
225
|
-
extension Report: Transferable {
|
|
226
|
-
static var transferRepresentation: some TransferRepresentation {
|
|
227
|
-
DataRepresentation(exportedContentType: .pdf) { report in
|
|
228
|
-
try report.renderPDF()
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### Pitfalls
|
|
235
|
-
|
|
236
|
-
- Always declare custom `UTType` identifiers in Info.plist under Exported/Imported Type Identifiers.
|
|
237
|
-
- Representation order matters — the first matching representation wins. Put the richest format first.
|
|
238
|
-
- `FileRepresentation` files are temporary; copy them if you need to persist.
|
|
239
|
-
- `Transferable` conformance must be on the main type, not an extension in a different module, to avoid linker issues.
|
|
240
|
-
- Test drag and drop on device — Simulator haptics and drop targeting differ from hardware.
|
|
241
|
-
|
|
242
|
-
## Media Patterns
|
|
243
|
-
|
|
244
|
-
### Intent
|
|
245
|
-
|
|
246
|
-
Use consistent patterns for loading images, previewing media, and presenting a full-screen viewer.
|
|
247
|
-
|
|
248
|
-
### Core patterns
|
|
249
|
-
|
|
250
|
-
- Use `AsyncImage` for simple remote images. `LazyImage` is from the third-party Nuke library if you need advanced caching and prefetching.
|
|
251
|
-
- Prefer a lightweight preview component for inline media.
|
|
252
|
-
- Use a shared viewer state (e.g., `QuickLook`) to present a full-screen media viewer.
|
|
253
|
-
- Use `openWindow` for desktop/visionOS and a sheet for iOS.
|
|
254
|
-
|
|
255
|
-
### Example: inline media preview
|
|
256
|
-
|
|
257
|
-
```swift
|
|
258
|
-
struct MediaPreviewRow: View {
|
|
259
|
-
@Environment(QuickLook.self) private var quickLook
|
|
260
|
-
|
|
261
|
-
let attachments: [MediaAttachment]
|
|
262
|
-
|
|
263
|
-
var body: some View {
|
|
264
|
-
ScrollView(.horizontal, showsIndicators: false) {
|
|
265
|
-
HStack {
|
|
266
|
-
ForEach(attachments) { attachment in
|
|
267
|
-
LazyImage(url: attachment.previewURL) { state in
|
|
268
|
-
if let image = state.image {
|
|
269
|
-
image.resizable().aspectRatio(contentMode: .fill)
|
|
270
|
-
} else {
|
|
271
|
-
ProgressView()
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
.frame(width: 120, height: 120)
|
|
275
|
-
.clipped()
|
|
276
|
-
.onTapGesture {
|
|
277
|
-
quickLook.prepareFor(
|
|
278
|
-
selectedMediaAttachment: attachment,
|
|
279
|
-
mediaAttachments: attachments
|
|
280
|
-
)
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
### Example: global media viewer sheet
|
|
290
|
-
|
|
291
|
-
```swift
|
|
292
|
-
struct AppRoot: View {
|
|
293
|
-
@State private var quickLook = QuickLook.shared
|
|
294
|
-
|
|
295
|
-
var body: some View {
|
|
296
|
-
content
|
|
297
|
-
.environment(quickLook)
|
|
298
|
-
.sheet(item: $quickLook.selectedMediaAttachment) { selected in
|
|
299
|
-
MediaUIView(selectedAttachment: selected, attachments: quickLook.mediaAttachments)
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Design choices to keep
|
|
306
|
-
|
|
307
|
-
- Keep previews lightweight; load full media in the viewer.
|
|
308
|
-
- Use shared viewer state so any view can open media without prop-drilling.
|
|
309
|
-
- Use a single entry point for the viewer (sheet/window) to avoid duplicates.
|
|
310
|
-
|
|
311
|
-
### Pitfalls
|
|
312
|
-
|
|
313
|
-
- Avoid loading full-size images in list rows; use resized previews.
|
|
314
|
-
- Don’t present multiple viewer sheets at once; keep a single source of truth.
|
|
315
|
-
|
|
316
|
-
## Top Bar Overlays
|
|
317
|
-
|
|
318
|
-
### Intent
|
|
319
|
-
|
|
320
|
-
Provide a custom top selector or pill row that sits above scroll content, using `safeAreaBar(.top)` on iOS 26 and a compatible fallback on earlier OS versions.
|
|
321
|
-
|
|
322
|
-
### iOS 26+ approach
|
|
323
|
-
|
|
324
|
-
Use `safeAreaBar(edge: .top)` to attach the view to the safe area bar.
|
|
325
|
-
|
|
326
|
-
```swift
|
|
327
|
-
if #available(iOS 26.0, *) {
|
|
328
|
-
content
|
|
329
|
-
.safeAreaBar(edge: .top) {
|
|
330
|
-
TopSelectorView()
|
|
331
|
-
.padding(.horizontal, .layoutPadding)
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
### Fallback for earlier iOS
|
|
337
|
-
|
|
338
|
-
Use `.safeAreaInset(edge: .top)` and hide the toolbar background to avoid double layers.
|
|
339
|
-
|
|
340
|
-
```swift
|
|
341
|
-
content
|
|
342
|
-
.toolbarBackground(.hidden, for: .navigationBar)
|
|
343
|
-
.safeAreaInset(edge: .top, spacing: 0) {
|
|
344
|
-
VStack(spacing: 0) {
|
|
345
|
-
TopSelectorView()
|
|
346
|
-
.padding(.vertical, 8)
|
|
347
|
-
.padding(.horizontal, .layoutPadding)
|
|
348
|
-
.background(Color.primary.opacity(0.06))
|
|
349
|
-
.background(Material.ultraThin)
|
|
350
|
-
Divider()
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
### Design choices to keep
|
|
356
|
-
|
|
357
|
-
- Use `safeAreaBar` when available; it integrates better with the navigation bar.
|
|
358
|
-
- Use a subtle background + divider in the fallback to keep separation from content.
|
|
359
|
-
- Keep the selector height compact to avoid pushing content too far down.
|
|
360
|
-
|
|
361
|
-
### Pitfalls
|
|
362
|
-
|
|
363
|
-
- Don’t stack multiple top insets; it can create extra padding.
|
|
364
|
-
- Avoid heavy, opaque backgrounds that fight the navigation bar.
|
|
365
|
-
|
|
366
|
-
## Title Menus
|
|
367
|
-
|
|
368
|
-
### Intent
|
|
369
|
-
|
|
370
|
-
Use a title menu in the navigation bar to provide context‑specific filtering or quick actions without adding extra chrome.
|
|
371
|
-
|
|
372
|
-
### Core patterns
|
|
373
|
-
|
|
374
|
-
- Use `ToolbarTitleMenu` to attach a menu to the navigation title.
|
|
375
|
-
- Keep the menu content compact and grouped with dividers.
|
|
376
|
-
|
|
377
|
-
### Example: title menu for filters
|
|
378
|
-
|
|
379
|
-
```swift
|
|
380
|
-
@ToolbarContentBuilder
|
|
381
|
-
private var toolbarView: some ToolbarContent {
|
|
382
|
-
ToolbarTitleMenu {
|
|
383
|
-
Button("Latest") { timeline = .latest }
|
|
384
|
-
Button("Resume") { timeline = .resume }
|
|
385
|
-
Divider()
|
|
386
|
-
Button("Local") { timeline = .local }
|
|
387
|
-
Button("Federated") { timeline = .federated }
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
### Example: attach to a view
|
|
393
|
-
|
|
394
|
-
```swift
|
|
395
|
-
NavigationStack {
|
|
396
|
-
TimelineView()
|
|
397
|
-
.toolbar {
|
|
398
|
-
toolbarView
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Example: title + menu together
|
|
404
|
-
|
|
405
|
-
```swift
|
|
406
|
-
struct TimelineScreen: View {
|
|
407
|
-
@State private var timeline: TimelineFilter = .home
|
|
408
|
-
|
|
409
|
-
var body: some View {
|
|
410
|
-
NavigationStack {
|
|
411
|
-
TimelineView()
|
|
412
|
-
.toolbar {
|
|
413
|
-
ToolbarItem(placement: .principal) {
|
|
414
|
-
VStack(spacing: 2) {
|
|
415
|
-
Text(timeline.title)
|
|
416
|
-
.font(.headline)
|
|
417
|
-
Text(timeline.subtitle)
|
|
418
|
-
.font(.caption)
|
|
419
|
-
.foregroundStyle(.secondary)
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
ToolbarTitleMenu {
|
|
424
|
-
Button("Home") { timeline = .home }
|
|
425
|
-
Button("Local") { timeline = .local }
|
|
426
|
-
Button("Federated") { timeline = .federated }
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
.navigationBarTitleDisplayMode(.inline)
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Example: title + subtitle with menu
|
|
436
|
-
|
|
437
|
-
```swift
|
|
438
|
-
ToolbarItem(placement: .principal) {
|
|
439
|
-
VStack(spacing: 2) {
|
|
440
|
-
Text(title)
|
|
441
|
-
.font(.headline)
|
|
442
|
-
Text(subtitle)
|
|
443
|
-
.font(.caption)
|
|
444
|
-
.foregroundStyle(.secondary)
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### Design choices to keep
|
|
450
|
-
|
|
451
|
-
- Only show the title menu when filtering or context switching is available.
|
|
452
|
-
- Keep the title readable; avoid long labels that truncate.
|
|
453
|
-
- Use secondary text below the title if extra context is needed.
|
|
454
|
-
|
|
455
|
-
### Pitfalls
|
|
456
|
-
|
|
457
|
-
- Don’t overload the menu with too many options.
|
|
458
|
-
- Avoid using title menus for destructive actions.
|
|
459
|
-
|
|
460
|
-
## Input Toolbar
|
|
461
|
-
|
|
462
|
-
### Intent
|
|
463
|
-
|
|
464
|
-
Use a bottom-anchored input bar for chat, composer, or quick actions without fighting the keyboard.
|
|
465
|
-
|
|
466
|
-
### Core patterns
|
|
467
|
-
|
|
468
|
-
- Use `.safeAreaInset(edge: .bottom)` to anchor the toolbar above the keyboard.
|
|
469
|
-
- Keep the main content in a `ScrollView` or `List`.
|
|
470
|
-
- Drive focus with `@FocusState` and set initial focus when needed.
|
|
471
|
-
- Avoid embedding the input bar inside the scroll content; keep it separate.
|
|
472
|
-
|
|
473
|
-
### Example: scroll view + bottom input
|
|
474
|
-
|
|
475
|
-
```swift
|
|
476
|
-
@MainActor
|
|
477
|
-
struct ConversationView: View {
|
|
478
|
-
@FocusState private var isInputFocused: Bool
|
|
479
|
-
|
|
480
|
-
var body: some View {
|
|
481
|
-
ScrollViewReader { _ in
|
|
482
|
-
ScrollView {
|
|
483
|
-
LazyVStack {
|
|
484
|
-
ForEach(messages) { message in
|
|
485
|
-
MessageRow(message: message)
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
.padding(.horizontal, .layoutPadding)
|
|
489
|
-
}
|
|
490
|
-
.safeAreaInset(edge: .bottom) {
|
|
491
|
-
InputBar(text: $draft)
|
|
492
|
-
.focused($isInputFocused)
|
|
493
|
-
}
|
|
494
|
-
.scrollDismissesKeyboard(.interactively)
|
|
495
|
-
.onAppear { isInputFocused = true }
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
### Design choices to keep
|
|
502
|
-
|
|
503
|
-
- Keep the input bar visually separated from the scrollable content.
|
|
504
|
-
- Use `.scrollDismissesKeyboard(.interactively)` for chat-like screens.
|
|
505
|
-
- Ensure send actions are reachable via keyboard return or a clear button.
|
|
506
|
-
|
|
507
|
-
### Pitfalls
|
|
508
|
-
|
|
509
|
-
- Avoid placing the input view inside the scroll stack; it will jump with content.
|
|
510
|
-
- Avoid nested scroll views that fight for drag gestures.
|
|
511
|
-
|
|
512
|
-
## Menu Bar Commands
|
|
513
|
-
|
|
514
|
-
### Contents
|
|
515
|
-
|
|
516
|
-
- [Intent](#intent)
|
|
517
|
-
- [Core patterns](#core-patterns)
|
|
518
|
-
- [Example: basic command menu](#example-basic-command-menu)
|
|
519
|
-
- [Example: insert and replace groups](#example-insert-and-replace-groups)
|
|
520
|
-
- [Example: focused menu state](#example-focused-menu-state)
|
|
521
|
-
- [Menu bar and Settings](#menu-bar-and-settings)
|
|
522
|
-
- [Pitfalls](#pitfalls)
|
|
523
|
-
|
|
524
|
-
### Intent
|
|
525
|
-
|
|
526
|
-
Use this when adding or customizing the macOS/iPadOS menu bar with SwiftUI commands.
|
|
527
|
-
|
|
528
|
-
### Core patterns
|
|
529
|
-
|
|
530
|
-
- Add commands at the `Scene` level with `.commands { ... }`.
|
|
531
|
-
- Use `SidebarCommands()` when your UI includes a navigation sidebar.
|
|
532
|
-
- Use `CommandMenu` for app-specific menus and group related actions.
|
|
533
|
-
- Use `CommandGroup` to insert items before/after system groups or replace them.
|
|
534
|
-
- Use `FocusedValue` for context-sensitive menu items that depend on the active scene.
|
|
535
|
-
|
|
536
|
-
### Example: basic command menu
|
|
537
|
-
|
|
538
|
-
```swift
|
|
539
|
-
@main
|
|
540
|
-
struct MyApp: App {
|
|
541
|
-
var body: some Scene {
|
|
542
|
-
WindowGroup {
|
|
543
|
-
ContentView()
|
|
544
|
-
}
|
|
545
|
-
.commands {
|
|
546
|
-
CommandMenu("Actions") {
|
|
547
|
-
Button("Run", action: run)
|
|
548
|
-
.keyboardShortcut("R")
|
|
549
|
-
Button("Stop", action: stop)
|
|
550
|
-
.keyboardShortcut(".")
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
private func run() {}
|
|
556
|
-
private func stop() {}
|
|
557
|
-
}
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
### Example: insert and replace groups
|
|
561
|
-
|
|
562
|
-
```swift
|
|
563
|
-
WindowGroup {
|
|
564
|
-
ContentView()
|
|
565
|
-
}
|
|
566
|
-
.commands {
|
|
567
|
-
CommandGroup(before: .systemServices) {
|
|
568
|
-
Button("Check for Updates") { /* open updater */ }
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
CommandGroup(after: .newItem) {
|
|
572
|
-
Button("New from Clipboard") { /* create item */ }
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
CommandGroup(replacing: .help) {
|
|
576
|
-
Button("User Manual") { /* open docs */ }
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
### Example: focused menu state
|
|
582
|
-
|
|
583
|
-
```swift
|
|
584
|
-
@Observable
|
|
585
|
-
final class DataModel {
|
|
586
|
-
var items: [String] = []
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
struct ContentView: View {
|
|
590
|
-
@State private var model = DataModel()
|
|
591
|
-
|
|
592
|
-
var body: some View {
|
|
593
|
-
List(model.items, id: \.self) { item in
|
|
594
|
-
Text(item)
|
|
595
|
-
}
|
|
596
|
-
.focusedSceneValue(model)
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
struct ItemCommands: Commands {
|
|
601
|
-
@FocusedValue(DataModel.self) private var model: DataModel?
|
|
602
|
-
|
|
603
|
-
var body: some Commands {
|
|
604
|
-
CommandGroup(after: .newItem) {
|
|
605
|
-
Button("New Item") {
|
|
606
|
-
model?.items.append("Untitled")
|
|
607
|
-
}
|
|
608
|
-
.disabled(model == nil)
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
### Menu bar and Settings
|
|
615
|
-
|
|
616
|
-
- Defining a `Settings` scene adds the Settings menu item on macOS automatically.
|
|
617
|
-
- If you need a custom entry point inside the app, use `OpenSettingsAction` or `SettingsLink`.
|
|
618
|
-
|
|
619
|
-
### Pitfalls
|
|
620
|
-
|
|
621
|
-
- Avoid registering the same keyboard shortcut in multiple command groups.
|
|
622
|
-
- Don’t use menu items as the only discoverable entry point for critical features.
|
|
623
|
-
|
|
624
|
-
## macOS Settings
|
|
625
|
-
|
|
626
|
-
### Intent
|
|
627
|
-
|
|
628
|
-
Use this when building a macOS Settings window backed by SwiftUI's `Settings` scene.
|
|
629
|
-
|
|
630
|
-
### Core patterns
|
|
631
|
-
|
|
632
|
-
- Declare the Settings scene in the `App` and compile it only for macOS.
|
|
633
|
-
- Keep settings content in a dedicated root view (`SettingsView`) and drive values with `@AppStorage`.
|
|
634
|
-
- Use `TabView` to group settings sections when you have more than one category.
|
|
635
|
-
- Use `Form` inside each tab to keep controls aligned and accessible.
|
|
636
|
-
- Use `OpenSettingsAction` or `SettingsLink` for in-app entry points to the Settings window.
|
|
637
|
-
|
|
638
|
-
### Example: settings scene
|
|
639
|
-
|
|
640
|
-
```swift
|
|
641
|
-
@main
|
|
642
|
-
struct MyApp: App {
|
|
643
|
-
var body: some Scene {
|
|
644
|
-
WindowGroup {
|
|
645
|
-
ContentView()
|
|
646
|
-
}
|
|
647
|
-
#if os(macOS)
|
|
648
|
-
Settings {
|
|
649
|
-
SettingsView()
|
|
650
|
-
}
|
|
651
|
-
#endif
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
### Example: tabbed settings view
|
|
657
|
-
|
|
658
|
-
```swift
|
|
659
|
-
@MainActor
|
|
660
|
-
struct SettingsView: View {
|
|
661
|
-
@AppStorage("showPreviews") private var showPreviews = true
|
|
662
|
-
@AppStorage("fontSize") private var fontSize = 12.0
|
|
663
|
-
|
|
664
|
-
var body: some View {
|
|
665
|
-
TabView {
|
|
666
|
-
Tab("General", systemImage: "gear") {
|
|
667
|
-
Form {
|
|
668
|
-
Toggle("Show Previews", isOn: $showPreviews)
|
|
669
|
-
Slider(value: $fontSize, in: 9...96) {
|
|
670
|
-
Text("Font Size (\(fontSize, specifier: "%.0f") pts)")
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
Tab("Advanced", systemImage: "star") {
|
|
676
|
-
Form {
|
|
677
|
-
Toggle("Enable Advanced Mode", isOn: .constant(false))
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
.scenePadding()
|
|
682
|
-
.frame(maxWidth: 420, minHeight: 240)
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
### Skip navigation
|
|
688
|
-
|
|
689
|
-
- Avoid wrapping `SettingsView` in a `NavigationStack` unless you truly need deep push navigation.
|
|
690
|
-
- Prefer tabs or sections; Settings is already presented as a separate window and should feel flat.
|
|
691
|
-
- If you must show hierarchical settings, use a single `NavigationSplitView` with a sidebar list of categories.
|
|
692
|
-
|
|
693
|
-
### Pitfalls
|
|
694
|
-
|
|
695
|
-
- Don’t reuse iOS-only settings layouts (full-screen stacks, toolbar-heavy flows).
|
|
696
|
-
- Avoid large custom view hierarchies inside `Form`; keep rows focused and accessible.
|
|
1
|
+
# Platform And Sharing
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- [Transferable, Drag & Drop, and ShareLink](#transferable-drag-drop-and-sharelink)
|
|
5
|
+
- [Media Patterns](#media-patterns)
|
|
6
|
+
- [Top Bar Overlays](#top-bar-overlays)
|
|
7
|
+
- [Title Menus](#title-menus)
|
|
8
|
+
- [Input Toolbar](#input-toolbar)
|
|
9
|
+
- [Menu Bar Commands](#menu-bar-commands)
|
|
10
|
+
- [macOS Settings](#macos-settings)
|
|
11
|
+
|
|
12
|
+
## Transferable, Drag & Drop, and ShareLink
|
|
13
|
+
|
|
14
|
+
### Intent
|
|
15
|
+
|
|
16
|
+
Adopt the `Transferable` protocol to enable sharing, drag and drop, copy/paste, and `ShareLink` with a unified API. Available iOS 16+.
|
|
17
|
+
|
|
18
|
+
> **Docs:** [Transferable](https://sosumi.ai/documentation/coretransferable/transferable) · [Choosing a transfer representation](https://sosumi.ai/documentation/coretransferable/choosing-a-transfer-representation-for-a-model-type)
|
|
19
|
+
|
|
20
|
+
### Transferable protocol overview
|
|
21
|
+
|
|
22
|
+
`Transferable` describes how a type converts to and from transfer representations (clipboard, drag, share sheet). Conform by implementing a static `transferRepresentation` property.
|
|
23
|
+
|
|
24
|
+
```swift
|
|
25
|
+
struct Note: Codable, Identifiable {
|
|
26
|
+
let id: UUID
|
|
27
|
+
var title: String
|
|
28
|
+
var body: String
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
extension Note: Transferable {
|
|
32
|
+
static var transferRepresentation: some TransferRepresentation {
|
|
33
|
+
CodableRepresentation(contentType: .note)
|
|
34
|
+
ProxyRepresentation(exporting: \.body) // fallback: plain text
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
extension UTType {
|
|
39
|
+
static let note = UTType(exportedAs: "com.example.note")
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Representation order matters — place the most specific first, with broader fallbacks after.
|
|
44
|
+
|
|
45
|
+
### Built-in conformances
|
|
46
|
+
|
|
47
|
+
These types already conform to `Transferable` out of the box:
|
|
48
|
+
|
|
49
|
+
| Type | Content type |
|
|
50
|
+
|------|-------------|
|
|
51
|
+
| `String` | `.plainText`, `.utf8PlainText` |
|
|
52
|
+
| `Data` | `.data` |
|
|
53
|
+
| `URL` | `.url` |
|
|
54
|
+
| `AttributedString` | `.rtf` |
|
|
55
|
+
| `Image` (SwiftUI) | `.image` |
|
|
56
|
+
| `Color` (SwiftUI) | `.color` |
|
|
57
|
+
|
|
58
|
+
### TransferRepresentation types
|
|
59
|
+
|
|
60
|
+
#### CodableRepresentation
|
|
61
|
+
|
|
62
|
+
For types conforming to `Codable`. Serializes to JSON by default:
|
|
63
|
+
|
|
64
|
+
```swift
|
|
65
|
+
static var transferRepresentation: some TransferRepresentation {
|
|
66
|
+
CodableRepresentation(contentType: .myType)
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### ProxyRepresentation
|
|
71
|
+
|
|
72
|
+
Delegate to another `Transferable` type. Ideal for quick text or URL fallbacks:
|
|
73
|
+
|
|
74
|
+
```swift
|
|
75
|
+
ProxyRepresentation(exporting: \.title) // export only
|
|
76
|
+
ProxyRepresentation(\.url) // import + export via URL
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### DataRepresentation
|
|
80
|
+
|
|
81
|
+
Full control over binary serialization:
|
|
82
|
+
|
|
83
|
+
```swift
|
|
84
|
+
DataRepresentation(contentType: .png) { image in
|
|
85
|
+
try image.pngData()
|
|
86
|
+
} importing: { data in
|
|
87
|
+
try MyImage(data: data)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Use `DataRepresentation(exportedContentType:)` for export-only representations.
|
|
92
|
+
|
|
93
|
+
#### FileRepresentation
|
|
94
|
+
|
|
95
|
+
For large content best transferred as files:
|
|
96
|
+
|
|
97
|
+
```swift
|
|
98
|
+
FileRepresentation(contentType: .movie) { video in
|
|
99
|
+
SentTransferredFile(video.fileURL)
|
|
100
|
+
} importing: { receivedFile in
|
|
101
|
+
let dest = FileManager.default.temporaryDirectory.appendingPathComponent(receivedFile.file.lastPathComponent)
|
|
102
|
+
try FileManager.default.copyItem(at: receivedFile.file, to: dest)
|
|
103
|
+
return Video(url: dest)
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### ShareLink
|
|
108
|
+
|
|
109
|
+
Present the system share sheet with a `Transferable` item:
|
|
110
|
+
|
|
111
|
+
```swift
|
|
112
|
+
ShareLink(item: note, preview: SharePreview(note.title)) {
|
|
113
|
+
Label("Share", systemImage: "square.and.arrow.up")
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Multiple items
|
|
117
|
+
ShareLink(items: selectedNotes) { note in
|
|
118
|
+
SharePreview(note.title)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Simple string sharing
|
|
122
|
+
ShareLink(item: "Check out this app!", subject: Text("Cool App"))
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`ShareLink` requires the item to conform to `Transferable`. The preview provides a title, optional image, and optional icon for the share sheet.
|
|
126
|
+
|
|
127
|
+
### Drag and drop
|
|
128
|
+
|
|
129
|
+
#### Making views draggable
|
|
130
|
+
|
|
131
|
+
```swift
|
|
132
|
+
struct NoteCard: View {
|
|
133
|
+
let note: Note
|
|
134
|
+
|
|
135
|
+
var body: some View {
|
|
136
|
+
Text(note.title)
|
|
137
|
+
.draggable(note) // Note must be Transferable
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Use `.draggable(note) { DragPreview(note) }` to provide a custom drag preview.
|
|
143
|
+
|
|
144
|
+
#### Drop destination
|
|
145
|
+
|
|
146
|
+
```swift
|
|
147
|
+
struct NoteBoard: View {
|
|
148
|
+
@State private var notes: [Note] = []
|
|
149
|
+
|
|
150
|
+
var body: some View {
|
|
151
|
+
VStack {
|
|
152
|
+
ForEach(notes) { NoteCard(note: $0) }
|
|
153
|
+
}
|
|
154
|
+
.dropDestination(for: Note.self) { droppedNotes, location in
|
|
155
|
+
notes.append(contentsOf: droppedNotes)
|
|
156
|
+
return true
|
|
157
|
+
} isTargeted: { isOver in
|
|
158
|
+
// Highlight drop zone
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
For reordering within a list, combine `.draggable` with `.dropDestination` or use `onMove` on `ForEach` inside `List`.
|
|
165
|
+
|
|
166
|
+
#### Handling multiple types
|
|
167
|
+
|
|
168
|
+
Accept multiple content types with separate `.dropDestination` modifiers or use `DropDelegate` for advanced logic:
|
|
169
|
+
|
|
170
|
+
```swift
|
|
171
|
+
.dropDestination(for: String.self) { strings, _ in
|
|
172
|
+
notes.append(contentsOf: strings.map { Note(id: UUID(), title: $0, body: "") })
|
|
173
|
+
return true
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Pasteboard integration
|
|
178
|
+
|
|
179
|
+
For direct clipboard access outside SwiftUI's drag/drop system, use `UIPasteboard`:
|
|
180
|
+
|
|
181
|
+
```swift
|
|
182
|
+
// Copy
|
|
183
|
+
UIPasteboard.general.string = note.title
|
|
184
|
+
|
|
185
|
+
// Paste
|
|
186
|
+
if let text = UIPasteboard.general.string {
|
|
187
|
+
// use text
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
For `Transferable` types with custom content types, export to `Data` first:
|
|
192
|
+
|
|
193
|
+
```swift
|
|
194
|
+
let data = try await note.exported(as: .note)
|
|
195
|
+
UIPasteboard.general.setData(data, forPasteboardType: UTType.note.identifier)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Prefer SwiftUI's `.copyable`, `.cuttable`, and `.pasteDestination` modifiers (iOS 16+) over direct `UIPasteboard` usage when possible — they integrate with the Edit menu and keyboard shortcuts automatically.
|
|
199
|
+
|
|
200
|
+
### Common patterns
|
|
201
|
+
|
|
202
|
+
#### Transferable enum with multiple representations
|
|
203
|
+
|
|
204
|
+
```swift
|
|
205
|
+
enum SharedContent: Transferable {
|
|
206
|
+
case text(String)
|
|
207
|
+
case url(URL)
|
|
208
|
+
|
|
209
|
+
static var transferRepresentation: some TransferRepresentation {
|
|
210
|
+
ProxyRepresentation { content in
|
|
211
|
+
switch content {
|
|
212
|
+
case .text(let s): return s
|
|
213
|
+
case .url(let u): return u.absoluteString
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
#### Export-only conformance
|
|
221
|
+
|
|
222
|
+
When your type should be sharable but not importable:
|
|
223
|
+
|
|
224
|
+
```swift
|
|
225
|
+
extension Report: Transferable {
|
|
226
|
+
static var transferRepresentation: some TransferRepresentation {
|
|
227
|
+
DataRepresentation(exportedContentType: .pdf) { report in
|
|
228
|
+
try report.renderPDF()
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Pitfalls
|
|
235
|
+
|
|
236
|
+
- Always declare custom `UTType` identifiers in Info.plist under Exported/Imported Type Identifiers.
|
|
237
|
+
- Representation order matters — the first matching representation wins. Put the richest format first.
|
|
238
|
+
- `FileRepresentation` files are temporary; copy them if you need to persist.
|
|
239
|
+
- `Transferable` conformance must be on the main type, not an extension in a different module, to avoid linker issues.
|
|
240
|
+
- Test drag and drop on device — Simulator haptics and drop targeting differ from hardware.
|
|
241
|
+
|
|
242
|
+
## Media Patterns
|
|
243
|
+
|
|
244
|
+
### Intent
|
|
245
|
+
|
|
246
|
+
Use consistent patterns for loading images, previewing media, and presenting a full-screen viewer.
|
|
247
|
+
|
|
248
|
+
### Core patterns
|
|
249
|
+
|
|
250
|
+
- Use `AsyncImage` for simple remote images. `LazyImage` is from the third-party Nuke library if you need advanced caching and prefetching.
|
|
251
|
+
- Prefer a lightweight preview component for inline media.
|
|
252
|
+
- Use a shared viewer state (e.g., `QuickLook`) to present a full-screen media viewer.
|
|
253
|
+
- Use `openWindow` for desktop/visionOS and a sheet for iOS.
|
|
254
|
+
|
|
255
|
+
### Example: inline media preview
|
|
256
|
+
|
|
257
|
+
```swift
|
|
258
|
+
struct MediaPreviewRow: View {
|
|
259
|
+
@Environment(QuickLook.self) private var quickLook
|
|
260
|
+
|
|
261
|
+
let attachments: [MediaAttachment]
|
|
262
|
+
|
|
263
|
+
var body: some View {
|
|
264
|
+
ScrollView(.horizontal, showsIndicators: false) {
|
|
265
|
+
HStack {
|
|
266
|
+
ForEach(attachments) { attachment in
|
|
267
|
+
LazyImage(url: attachment.previewURL) { state in
|
|
268
|
+
if let image = state.image {
|
|
269
|
+
image.resizable().aspectRatio(contentMode: .fill)
|
|
270
|
+
} else {
|
|
271
|
+
ProgressView()
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
.frame(width: 120, height: 120)
|
|
275
|
+
.clipped()
|
|
276
|
+
.onTapGesture {
|
|
277
|
+
quickLook.prepareFor(
|
|
278
|
+
selectedMediaAttachment: attachment,
|
|
279
|
+
mediaAttachments: attachments
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Example: global media viewer sheet
|
|
290
|
+
|
|
291
|
+
```swift
|
|
292
|
+
struct AppRoot: View {
|
|
293
|
+
@State private var quickLook = QuickLook.shared
|
|
294
|
+
|
|
295
|
+
var body: some View {
|
|
296
|
+
content
|
|
297
|
+
.environment(quickLook)
|
|
298
|
+
.sheet(item: $quickLook.selectedMediaAttachment) { selected in
|
|
299
|
+
MediaUIView(selectedAttachment: selected, attachments: quickLook.mediaAttachments)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Design choices to keep
|
|
306
|
+
|
|
307
|
+
- Keep previews lightweight; load full media in the viewer.
|
|
308
|
+
- Use shared viewer state so any view can open media without prop-drilling.
|
|
309
|
+
- Use a single entry point for the viewer (sheet/window) to avoid duplicates.
|
|
310
|
+
|
|
311
|
+
### Pitfalls
|
|
312
|
+
|
|
313
|
+
- Avoid loading full-size images in list rows; use resized previews.
|
|
314
|
+
- Don’t present multiple viewer sheets at once; keep a single source of truth.
|
|
315
|
+
|
|
316
|
+
## Top Bar Overlays
|
|
317
|
+
|
|
318
|
+
### Intent
|
|
319
|
+
|
|
320
|
+
Provide a custom top selector or pill row that sits above scroll content, using `safeAreaBar(.top)` on iOS 26 and a compatible fallback on earlier OS versions.
|
|
321
|
+
|
|
322
|
+
### iOS 26+ approach
|
|
323
|
+
|
|
324
|
+
Use `safeAreaBar(edge: .top)` to attach the view to the safe area bar.
|
|
325
|
+
|
|
326
|
+
```swift
|
|
327
|
+
if #available(iOS 26.0, *) {
|
|
328
|
+
content
|
|
329
|
+
.safeAreaBar(edge: .top) {
|
|
330
|
+
TopSelectorView()
|
|
331
|
+
.padding(.horizontal, .layoutPadding)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Fallback for earlier iOS
|
|
337
|
+
|
|
338
|
+
Use `.safeAreaInset(edge: .top)` and hide the toolbar background to avoid double layers.
|
|
339
|
+
|
|
340
|
+
```swift
|
|
341
|
+
content
|
|
342
|
+
.toolbarBackground(.hidden, for: .navigationBar)
|
|
343
|
+
.safeAreaInset(edge: .top, spacing: 0) {
|
|
344
|
+
VStack(spacing: 0) {
|
|
345
|
+
TopSelectorView()
|
|
346
|
+
.padding(.vertical, 8)
|
|
347
|
+
.padding(.horizontal, .layoutPadding)
|
|
348
|
+
.background(Color.primary.opacity(0.06))
|
|
349
|
+
.background(Material.ultraThin)
|
|
350
|
+
Divider()
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Design choices to keep
|
|
356
|
+
|
|
357
|
+
- Use `safeAreaBar` when available; it integrates better with the navigation bar.
|
|
358
|
+
- Use a subtle background + divider in the fallback to keep separation from content.
|
|
359
|
+
- Keep the selector height compact to avoid pushing content too far down.
|
|
360
|
+
|
|
361
|
+
### Pitfalls
|
|
362
|
+
|
|
363
|
+
- Don’t stack multiple top insets; it can create extra padding.
|
|
364
|
+
- Avoid heavy, opaque backgrounds that fight the navigation bar.
|
|
365
|
+
|
|
366
|
+
## Title Menus
|
|
367
|
+
|
|
368
|
+
### Intent
|
|
369
|
+
|
|
370
|
+
Use a title menu in the navigation bar to provide context‑specific filtering or quick actions without adding extra chrome.
|
|
371
|
+
|
|
372
|
+
### Core patterns
|
|
373
|
+
|
|
374
|
+
- Use `ToolbarTitleMenu` to attach a menu to the navigation title.
|
|
375
|
+
- Keep the menu content compact and grouped with dividers.
|
|
376
|
+
|
|
377
|
+
### Example: title menu for filters
|
|
378
|
+
|
|
379
|
+
```swift
|
|
380
|
+
@ToolbarContentBuilder
|
|
381
|
+
private var toolbarView: some ToolbarContent {
|
|
382
|
+
ToolbarTitleMenu {
|
|
383
|
+
Button("Latest") { timeline = .latest }
|
|
384
|
+
Button("Resume") { timeline = .resume }
|
|
385
|
+
Divider()
|
|
386
|
+
Button("Local") { timeline = .local }
|
|
387
|
+
Button("Federated") { timeline = .federated }
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Example: attach to a view
|
|
393
|
+
|
|
394
|
+
```swift
|
|
395
|
+
NavigationStack {
|
|
396
|
+
TimelineView()
|
|
397
|
+
.toolbar {
|
|
398
|
+
toolbarView
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Example: title + menu together
|
|
404
|
+
|
|
405
|
+
```swift
|
|
406
|
+
struct TimelineScreen: View {
|
|
407
|
+
@State private var timeline: TimelineFilter = .home
|
|
408
|
+
|
|
409
|
+
var body: some View {
|
|
410
|
+
NavigationStack {
|
|
411
|
+
TimelineView()
|
|
412
|
+
.toolbar {
|
|
413
|
+
ToolbarItem(placement: .principal) {
|
|
414
|
+
VStack(spacing: 2) {
|
|
415
|
+
Text(timeline.title)
|
|
416
|
+
.font(.headline)
|
|
417
|
+
Text(timeline.subtitle)
|
|
418
|
+
.font(.caption)
|
|
419
|
+
.foregroundStyle(.secondary)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
ToolbarTitleMenu {
|
|
424
|
+
Button("Home") { timeline = .home }
|
|
425
|
+
Button("Local") { timeline = .local }
|
|
426
|
+
Button("Federated") { timeline = .federated }
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
.navigationBarTitleDisplayMode(.inline)
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Example: title + subtitle with menu
|
|
436
|
+
|
|
437
|
+
```swift
|
|
438
|
+
ToolbarItem(placement: .principal) {
|
|
439
|
+
VStack(spacing: 2) {
|
|
440
|
+
Text(title)
|
|
441
|
+
.font(.headline)
|
|
442
|
+
Text(subtitle)
|
|
443
|
+
.font(.caption)
|
|
444
|
+
.foregroundStyle(.secondary)
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Design choices to keep
|
|
450
|
+
|
|
451
|
+
- Only show the title menu when filtering or context switching is available.
|
|
452
|
+
- Keep the title readable; avoid long labels that truncate.
|
|
453
|
+
- Use secondary text below the title if extra context is needed.
|
|
454
|
+
|
|
455
|
+
### Pitfalls
|
|
456
|
+
|
|
457
|
+
- Don’t overload the menu with too many options.
|
|
458
|
+
- Avoid using title menus for destructive actions.
|
|
459
|
+
|
|
460
|
+
## Input Toolbar
|
|
461
|
+
|
|
462
|
+
### Intent
|
|
463
|
+
|
|
464
|
+
Use a bottom-anchored input bar for chat, composer, or quick actions without fighting the keyboard.
|
|
465
|
+
|
|
466
|
+
### Core patterns
|
|
467
|
+
|
|
468
|
+
- Use `.safeAreaInset(edge: .bottom)` to anchor the toolbar above the keyboard.
|
|
469
|
+
- Keep the main content in a `ScrollView` or `List`.
|
|
470
|
+
- Drive focus with `@FocusState` and set initial focus when needed.
|
|
471
|
+
- Avoid embedding the input bar inside the scroll content; keep it separate.
|
|
472
|
+
|
|
473
|
+
### Example: scroll view + bottom input
|
|
474
|
+
|
|
475
|
+
```swift
|
|
476
|
+
@MainActor
|
|
477
|
+
struct ConversationView: View {
|
|
478
|
+
@FocusState private var isInputFocused: Bool
|
|
479
|
+
|
|
480
|
+
var body: some View {
|
|
481
|
+
ScrollViewReader { _ in
|
|
482
|
+
ScrollView {
|
|
483
|
+
LazyVStack {
|
|
484
|
+
ForEach(messages) { message in
|
|
485
|
+
MessageRow(message: message)
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
.padding(.horizontal, .layoutPadding)
|
|
489
|
+
}
|
|
490
|
+
.safeAreaInset(edge: .bottom) {
|
|
491
|
+
InputBar(text: $draft)
|
|
492
|
+
.focused($isInputFocused)
|
|
493
|
+
}
|
|
494
|
+
.scrollDismissesKeyboard(.interactively)
|
|
495
|
+
.onAppear { isInputFocused = true }
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Design choices to keep
|
|
502
|
+
|
|
503
|
+
- Keep the input bar visually separated from the scrollable content.
|
|
504
|
+
- Use `.scrollDismissesKeyboard(.interactively)` for chat-like screens.
|
|
505
|
+
- Ensure send actions are reachable via keyboard return or a clear button.
|
|
506
|
+
|
|
507
|
+
### Pitfalls
|
|
508
|
+
|
|
509
|
+
- Avoid placing the input view inside the scroll stack; it will jump with content.
|
|
510
|
+
- Avoid nested scroll views that fight for drag gestures.
|
|
511
|
+
|
|
512
|
+
## Menu Bar Commands
|
|
513
|
+
|
|
514
|
+
### Contents
|
|
515
|
+
|
|
516
|
+
- [Intent](#intent)
|
|
517
|
+
- [Core patterns](#core-patterns)
|
|
518
|
+
- [Example: basic command menu](#example-basic-command-menu)
|
|
519
|
+
- [Example: insert and replace groups](#example-insert-and-replace-groups)
|
|
520
|
+
- [Example: focused menu state](#example-focused-menu-state)
|
|
521
|
+
- [Menu bar and Settings](#menu-bar-and-settings)
|
|
522
|
+
- [Pitfalls](#pitfalls)
|
|
523
|
+
|
|
524
|
+
### Intent
|
|
525
|
+
|
|
526
|
+
Use this when adding or customizing the macOS/iPadOS menu bar with SwiftUI commands.
|
|
527
|
+
|
|
528
|
+
### Core patterns
|
|
529
|
+
|
|
530
|
+
- Add commands at the `Scene` level with `.commands { ... }`.
|
|
531
|
+
- Use `SidebarCommands()` when your UI includes a navigation sidebar.
|
|
532
|
+
- Use `CommandMenu` for app-specific menus and group related actions.
|
|
533
|
+
- Use `CommandGroup` to insert items before/after system groups or replace them.
|
|
534
|
+
- Use `FocusedValue` for context-sensitive menu items that depend on the active scene.
|
|
535
|
+
|
|
536
|
+
### Example: basic command menu
|
|
537
|
+
|
|
538
|
+
```swift
|
|
539
|
+
@main
|
|
540
|
+
struct MyApp: App {
|
|
541
|
+
var body: some Scene {
|
|
542
|
+
WindowGroup {
|
|
543
|
+
ContentView()
|
|
544
|
+
}
|
|
545
|
+
.commands {
|
|
546
|
+
CommandMenu("Actions") {
|
|
547
|
+
Button("Run", action: run)
|
|
548
|
+
.keyboardShortcut("R")
|
|
549
|
+
Button("Stop", action: stop)
|
|
550
|
+
.keyboardShortcut(".")
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
private func run() {}
|
|
556
|
+
private func stop() {}
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Example: insert and replace groups
|
|
561
|
+
|
|
562
|
+
```swift
|
|
563
|
+
WindowGroup {
|
|
564
|
+
ContentView()
|
|
565
|
+
}
|
|
566
|
+
.commands {
|
|
567
|
+
CommandGroup(before: .systemServices) {
|
|
568
|
+
Button("Check for Updates") { /* open updater */ }
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
CommandGroup(after: .newItem) {
|
|
572
|
+
Button("New from Clipboard") { /* create item */ }
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
CommandGroup(replacing: .help) {
|
|
576
|
+
Button("User Manual") { /* open docs */ }
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### Example: focused menu state
|
|
582
|
+
|
|
583
|
+
```swift
|
|
584
|
+
@Observable
|
|
585
|
+
final class DataModel {
|
|
586
|
+
var items: [String] = []
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
struct ContentView: View {
|
|
590
|
+
@State private var model = DataModel()
|
|
591
|
+
|
|
592
|
+
var body: some View {
|
|
593
|
+
List(model.items, id: \.self) { item in
|
|
594
|
+
Text(item)
|
|
595
|
+
}
|
|
596
|
+
.focusedSceneValue(model)
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
struct ItemCommands: Commands {
|
|
601
|
+
@FocusedValue(DataModel.self) private var model: DataModel?
|
|
602
|
+
|
|
603
|
+
var body: some Commands {
|
|
604
|
+
CommandGroup(after: .newItem) {
|
|
605
|
+
Button("New Item") {
|
|
606
|
+
model?.items.append("Untitled")
|
|
607
|
+
}
|
|
608
|
+
.disabled(model == nil)
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
### Menu bar and Settings
|
|
615
|
+
|
|
616
|
+
- Defining a `Settings` scene adds the Settings menu item on macOS automatically.
|
|
617
|
+
- If you need a custom entry point inside the app, use `OpenSettingsAction` or `SettingsLink`.
|
|
618
|
+
|
|
619
|
+
### Pitfalls
|
|
620
|
+
|
|
621
|
+
- Avoid registering the same keyboard shortcut in multiple command groups.
|
|
622
|
+
- Don’t use menu items as the only discoverable entry point for critical features.
|
|
623
|
+
|
|
624
|
+
## macOS Settings
|
|
625
|
+
|
|
626
|
+
### Intent
|
|
627
|
+
|
|
628
|
+
Use this when building a macOS Settings window backed by SwiftUI's `Settings` scene.
|
|
629
|
+
|
|
630
|
+
### Core patterns
|
|
631
|
+
|
|
632
|
+
- Declare the Settings scene in the `App` and compile it only for macOS.
|
|
633
|
+
- Keep settings content in a dedicated root view (`SettingsView`) and drive values with `@AppStorage`.
|
|
634
|
+
- Use `TabView` to group settings sections when you have more than one category.
|
|
635
|
+
- Use `Form` inside each tab to keep controls aligned and accessible.
|
|
636
|
+
- Use `OpenSettingsAction` or `SettingsLink` for in-app entry points to the Settings window.
|
|
637
|
+
|
|
638
|
+
### Example: settings scene
|
|
639
|
+
|
|
640
|
+
```swift
|
|
641
|
+
@main
|
|
642
|
+
struct MyApp: App {
|
|
643
|
+
var body: some Scene {
|
|
644
|
+
WindowGroup {
|
|
645
|
+
ContentView()
|
|
646
|
+
}
|
|
647
|
+
#if os(macOS)
|
|
648
|
+
Settings {
|
|
649
|
+
SettingsView()
|
|
650
|
+
}
|
|
651
|
+
#endif
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### Example: tabbed settings view
|
|
657
|
+
|
|
658
|
+
```swift
|
|
659
|
+
@MainActor
|
|
660
|
+
struct SettingsView: View {
|
|
661
|
+
@AppStorage("showPreviews") private var showPreviews = true
|
|
662
|
+
@AppStorage("fontSize") private var fontSize = 12.0
|
|
663
|
+
|
|
664
|
+
var body: some View {
|
|
665
|
+
TabView {
|
|
666
|
+
Tab("General", systemImage: "gear") {
|
|
667
|
+
Form {
|
|
668
|
+
Toggle("Show Previews", isOn: $showPreviews)
|
|
669
|
+
Slider(value: $fontSize, in: 9...96) {
|
|
670
|
+
Text("Font Size (\(fontSize, specifier: "%.0f") pts)")
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
Tab("Advanced", systemImage: "star") {
|
|
676
|
+
Form {
|
|
677
|
+
Toggle("Enable Advanced Mode", isOn: .constant(false))
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
.scenePadding()
|
|
682
|
+
.frame(maxWidth: 420, minHeight: 240)
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### Skip navigation
|
|
688
|
+
|
|
689
|
+
- Avoid wrapping `SettingsView` in a `NavigationStack` unless you truly need deep push navigation.
|
|
690
|
+
- Prefer tabs or sections; Settings is already presented as a separate window and should feel flat.
|
|
691
|
+
- If you must show hierarchical settings, use a single `NavigationSplitView` with a sidebar list of categories.
|
|
692
|
+
|
|
693
|
+
### Pitfalls
|
|
694
|
+
|
|
695
|
+
- Don’t reuse iOS-only settings layouts (full-screen stacks, toolbar-heavy flows).
|
|
696
|
+
- Avoid large custom view hierarchies inside `Form`; keep rows focused and accessible.
|