@mmerterden/multi-agent-pipeline 20.36.0 → 20.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/docs/facts.json +1 -1
  3. package/install/catalog-history.json +1 -1
  4. package/manifest.json +194 -122
  5. package/package.json +1 -1
  6. package/pipeline/commands/multi-agent/SKILL.md +33 -154
  7. package/pipeline/commands/multi-agent/analysis/SKILL.md +14 -68
  8. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +5 -8
  9. package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +38 -109
  10. package/pipeline/commands/multi-agent/channels/SKILL.md +38 -167
  11. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +37 -144
  12. package/pipeline/commands/multi-agent/design-check/SKILL.md +27 -131
  13. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +22 -48
  14. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +37 -180
  15. package/pipeline/commands/multi-agent/jira/SKILL.md +16 -46
  16. package/pipeline/commands/multi-agent/refactor/SKILL.md +23 -184
  17. package/pipeline/commands/multi-agent/resume/SKILL.md +30 -136
  18. package/pipeline/commands/multi-agent/review/SKILL.md +24 -199
  19. package/pipeline/commands/multi-agent/setup/SKILL.md +25 -181
  20. package/pipeline/commands/multi-agent/stack/SKILL.md +9 -53
  21. package/pipeline/commands/multi-agent/status/SKILL.md +13 -2
  22. package/pipeline/commands/multi-agent/store-ready/SKILL.md +27 -226
  23. package/pipeline/commands/multi-agent/sync/SKILL.md +35 -164
  24. package/pipeline/commands/multi-agent/test-gen/SKILL.md +2 -4
  25. package/pipeline/commands/multi-agent/update/SKILL.md +18 -60
  26. package/pipeline/contract/CHANGELOG.md +9 -0
  27. package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
  28. package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
  29. package/pipeline/contract/fixtures/error-unsigned.json +1 -1
  30. package/pipeline/contract/fixtures/runs-awaiting-question.json +1 -1
  31. package/pipeline/contract/fixtures/runs-empty.json +1 -1
  32. package/pipeline/contract/fixtures/runs-failed.json +1 -1
  33. package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +1 -1
  34. package/pipeline/contract/fixtures/runs-pr-opened.json +1 -1
  35. package/pipeline/contract/fixtures/runs-running.json +1 -1
  36. package/pipeline/contract/manifest.json +5 -5
  37. package/pipeline/contract/types/index.d.ts +3 -2
  38. package/pipeline/multi-agent-refs/autopilot-on/details.md +148 -0
  39. package/pipeline/multi-agent-refs/channels/generator.md +14 -0
  40. package/pipeline/multi-agent-refs/channels/preview.md +13 -0
  41. package/pipeline/multi-agent-refs/channels/reference.md +46 -0
  42. package/pipeline/multi-agent-refs/complaint-analysis/phases.md +159 -0
  43. package/pipeline/multi-agent-refs/design-check/export.md +1 -0
  44. package/pipeline/multi-agent-refs/design-check/init-inventory.md +1 -1
  45. package/pipeline/multi-agent-refs/design-check/scope-and-ledger.md +64 -0
  46. package/pipeline/multi-agent-refs/features/analysis-command-notes.md +53 -0
  47. package/pipeline/multi-agent-refs/garbage-collect/phases.md +60 -0
  48. package/pipeline/multi-agent-refs/ios-coding-standard/plan.md +71 -0
  49. package/pipeline/multi-agent-refs/ios-coding-standard/resolve-and-scan.md +135 -0
  50. package/pipeline/multi-agent-refs/jira/picker-detail.md +71 -0
  51. package/pipeline/multi-agent-refs/orchestrator/copilot-pipeline.md +88 -0
  52. package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +96 -1
  53. package/pipeline/multi-agent-refs/refactor/sweep.md +190 -0
  54. package/pipeline/multi-agent-refs/resume/details.md +115 -2
  55. package/pipeline/multi-agent-refs/review/inputs.md +33 -1
  56. package/pipeline/multi-agent-refs/review/module-guides.md +9 -1
  57. package/pipeline/multi-agent-refs/review/panel.md +75 -0
  58. package/pipeline/multi-agent-refs/review/valven.md +5 -1
  59. package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +4 -0
  60. package/pipeline/multi-agent-refs/setup/token-save-flow.md +13 -0
  61. package/pipeline/multi-agent-refs/stack/background.md +72 -0
  62. package/pipeline/multi-agent-refs/store-ready/gates.md +139 -0
  63. package/pipeline/multi-agent-refs/store-ready/report.md +40 -2
  64. package/pipeline/multi-agent-refs/sync/office.md +10 -0
  65. package/pipeline/multi-agent-refs/sync/overview.md +61 -0
  66. package/pipeline/multi-agent-refs/sync/repo.md +91 -0
  67. package/pipeline/multi-agent-refs/update/details.md +83 -0
  68. package/pipeline/schemas/runs-index.schema.json +2 -1
  69. package/pipeline/scripts/contract-server.mjs +1 -1
  70. package/pipeline/scripts/runs-index.mjs +34 -7
  71. package/pipeline/scripts/status-overview.mjs +401 -0
  72. package/pipeline/skills/.skill-manifest.json +63 -63
  73. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +7 -70
  74. package/pipeline/skills/shared/core/apple-archive-compliance/references/examples.md +67 -0
  75. package/pipeline/skills/shared/core/apple-archive-compliance/references/version-history.md +8 -0
  76. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +10 -72
  77. package/pipeline/skills/shared/core/google-play-compliance/references/examples.md +69 -0
  78. package/pipeline/skills/shared/core/google-play-compliance/references/notes.md +7 -0
  79. package/pipeline/skills/shared/core/google-play-compliance/references/version-history.md +5 -0
  80. package/pipeline/skills/shared/core/multi-agent/SKILL.md +39 -262
  81. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +35 -73
  82. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +37 -337
  83. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +27 -122
  84. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +8 -340
  85. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +37 -180
  86. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +23 -184
  87. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +14 -82
  88. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +25 -277
  89. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +13 -2
  90. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +73 -217
  91. package/pipeline/skills/shared/external/alarmkit/SKILL.md +11 -162
  92. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-code.md +257 -0
  93. package/pipeline/skills/shared/external/android-architecture/SKILL.md +7 -58
  94. package/pipeline/skills/shared/external/android-architecture/references/code-examples.md +68 -0
  95. package/pipeline/skills/shared/external/app-intents/SKILL.md +3 -45
  96. package/pipeline/skills/shared/external/app-intents/references/code-examples.md +54 -0
  97. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +5 -81
  98. package/pipeline/skills/shared/external/app-store-optimization/references/engagement-and-localization.md +96 -0
  99. package/pipeline/skills/shared/external/app-store-review/SKILL.md +6 -112
  100. package/pipeline/skills/shared/external/app-store-review/references/monetization-and-submission.md +138 -0
  101. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +10 -117
  102. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models-code.md +186 -0
  103. package/pipeline/skills/shared/external/authentication/SKILL.md +3 -50
  104. package/pipeline/skills/shared/external/authentication/references/code-examples.md +59 -0
  105. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +3 -84
  106. package/pipeline/skills/shared/external/callkit-voip/references/code-examples.md +93 -0
  107. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +7 -263
  108. package/pipeline/skills/shared/external/ci-cd-pipelines/references/pipeline-examples.md +281 -0
  109. package/pipeline/skills/shared/external/clean-code/SKILL.md +8 -41
  110. package/pipeline/skills/shared/external/clean-code/references/code-examples.md +56 -0
  111. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +8 -146
  112. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-code.md +214 -0
  113. package/pipeline/skills/shared/external/compose-components/SKILL.md +6 -80
  114. package/pipeline/skills/shared/external/compose-components/references/code-examples.md +89 -0
  115. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +5 -64
  116. package/pipeline/skills/shared/external/compose-navigation/references/code-examples.md +70 -0
  117. package/pipeline/skills/shared/external/core-data/SKILL.md +9 -157
  118. package/pipeline/skills/shared/external/core-data/references/core-data-code.md +221 -0
  119. package/pipeline/skills/shared/external/core-nfc/SKILL.md +3 -89
  120. package/pipeline/skills/shared/external/core-nfc/references/code-examples.md +98 -0
  121. package/pipeline/skills/shared/external/coreml/SKILL.md +17 -133
  122. package/pipeline/skills/shared/external/coreml/references/coreml-code.md +208 -0
  123. package/pipeline/skills/shared/external/css-modern/SKILL.md +8 -131
  124. package/pipeline/skills/shared/external/css-modern/references/code-examples.md +142 -0
  125. package/pipeline/skills/shared/external/database-patterns/SKILL.md +6 -103
  126. package/pipeline/skills/shared/external/database-patterns/references/orm-examples.md +112 -0
  127. package/pipeline/skills/shared/external/html-semantic/SKILL.md +7 -48
  128. package/pipeline/skills/shared/external/html-semantic/references/code-examples.md +54 -0
  129. package/pipeline/skills/shared/external/humanizer/SKILL.md +6 -19
  130. package/pipeline/skills/shared/external/humanizer/references/voice.md +24 -0
  131. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +13 -170
  132. package/pipeline/skills/shared/external/ios-accessibility/references/assistive-tech-review.md +224 -0
  133. package/pipeline/skills/shared/external/ios-localization/SKILL.md +2 -24
  134. package/pipeline/skills/shared/external/ios-localization/references/code-examples.md +30 -0
  135. package/pipeline/skills/shared/external/ios-networking/SKILL.md +3 -58
  136. package/pipeline/skills/shared/external/ios-networking/references/code-examples.md +67 -0
  137. package/pipeline/skills/shared/external/ios-security/SKILL.md +4 -64
  138. package/pipeline/skills/shared/external/ios-security/references/code-examples.md +74 -0
  139. package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -90
  140. package/pipeline/skills/shared/external/live-activities/references/code-examples.md +108 -0
  141. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -23
  142. package/pipeline/skills/shared/external/localization-reuse-map/references/project-settings.md +22 -0
  143. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +5 -95
  144. package/pipeline/skills/shared/external/mapkit-location/references/code-examples.md +117 -0
  145. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +7 -106
  146. package/pipeline/skills/shared/external/nextjs-app-router/references/app-router-examples.md +124 -0
  147. package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -31
  148. package/pipeline/skills/shared/external/permissionkit/references/code-examples.md +37 -0
  149. package/pipeline/skills/shared/external/play-store-review/SKILL.md +6 -74
  150. package/pipeline/skills/shared/external/play-store-review/references/signing-and-policies.md +83 -0
  151. package/pipeline/skills/shared/external/push-notifications/SKILL.md +8 -125
  152. package/pipeline/skills/shared/external/push-notifications/references/notification-code.md +176 -0
  153. package/pipeline/skills/shared/external/python-patterns/SKILL.md +7 -158
  154. package/pipeline/skills/shared/external/python-patterns/references/python-examples.md +176 -0
  155. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +7 -157
  156. package/pipeline/skills/shared/external/rest-api-design/references/api-examples.md +175 -0
  157. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +11 -230
  158. package/pipeline/skills/shared/external/swift-architecture/references/pattern-examples.md +295 -0
  159. package/pipeline/skills/shared/external/swift-codable/SKILL.md +17 -149
  160. package/pipeline/skills/shared/external/swift-codable/references/codable-recipes.md +207 -0
  161. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +12 -99
  162. package/pipeline/skills/shared/external/swift-concurrency/references/code-examples.md +100 -0
  163. package/pipeline/skills/shared/external/swift-concurrency/references/swift-6-2-additions.md +18 -0
  164. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +9 -78
  165. package/pipeline/skills/shared/external/swift-formatstyle/references/formatstyle-examples.md +113 -0
  166. package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -56
  167. package/pipeline/skills/shared/external/swift-language/references/code-examples.md +65 -0
  168. package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +1 -0
  169. package/pipeline/skills/shared/external/swiftdata/SKILL.md +6 -122
  170. package/pipeline/skills/shared/external/swiftdata/references/code-examples.md +140 -0
  171. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +12 -139
  172. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/interop-code.md +198 -0
  173. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +9 -81
  174. package/pipeline/skills/shared/external/tailwind-css/references/code-examples.md +91 -0
  175. package/pipeline/skills/shared/external/testing-backend/SKILL.md +7 -207
  176. package/pipeline/skills/shared/external/testing-backend/references/testing-examples.md +225 -0
  177. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +8 -89
  178. package/pipeline/skills/shared/external/typescript-patterns/references/code-examples.md +100 -0
  179. package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -20
  180. package/pipeline/skills/shared/external/vision-framework/references/code-examples.md +26 -0
  181. package/pipeline/skills/shared/external/vue-composition/SKILL.md +7 -169
  182. package/pipeline/skills/shared/external/vue-composition/references/vue-examples.md +187 -0
  183. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +7 -174
  184. package/pipeline/skills/shared/external/web-accessibility/references/a11y-examples.md +192 -0
  185. package/pipeline/skills/shared/external/web-performance/SKILL.md +8 -66
  186. package/pipeline/skills/shared/external/web-performance/references/code-examples.md +77 -0
  187. package/pipeline/skills/shared/external/web-testing/SKILL.md +11 -186
  188. package/pipeline/skills/shared/external/web-testing/references/testing-examples.md +213 -0
  189. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/format-and-output.md +0 -0
  190. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/publish-and-snapshot.md +0 -0
  191. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/sources-and-recipes.md +0 -0
@@ -0,0 +1,140 @@
1
+ # SwiftData Code Examples
2
+
3
+ <!-- toc -->
4
+ - [Defining models](#defining-models)
5
+ - [Container setup](#container-setup)
6
+ - [Schema versions and migration](#schema-versions-and-migration)
7
+ <!-- /toc -->
8
+
9
+ Full code samples for the SKILL.md sections that link here. The rules and the decision guidance stay in SKILL.md; each heading below matches the SKILL.md section the code belongs to.
10
+
11
+ ## Defining models
12
+
13
+ ```swift
14
+ import SwiftData
15
+ import Foundation
16
+
17
+ @Model
18
+ class Plant {
19
+ var commonName: String
20
+ var acquiredOn: Date
21
+ var needsRepotting: Bool = false
22
+ @Attribute(.externalStorage) var photo: Data?
23
+ @Relationship(deleteRule: .cascade, inverse: \CareEvent.plant)
24
+ var careEvents: [CareEvent] = []
25
+ var bed: GardenBed?
26
+ @Transient var isHighlighted: Bool = false
27
+
28
+ init(commonName: String, acquiredOn: Date = .now) {
29
+ self.commonName = commonName
30
+ self.acquiredOn = acquiredOn
31
+ }
32
+ }
33
+
34
+ @Model
35
+ final class GardenBed {
36
+ var label: String
37
+ @Relationship(deleteRule: .nullify, inverse: \Plant.bed)
38
+ var plants: [Plant] = []
39
+ init(label: String) { self.label = label }
40
+ }
41
+
42
+ @Model
43
+ final class CareEvent {
44
+ var kind: String
45
+ var loggedAt: Date
46
+ var plant: Plant?
47
+
48
+ init(kind: String, loggedAt: Date) {
49
+ self.kind = kind
50
+ self.loggedAt = loggedAt
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## Container setup
56
+
57
+ ```swift
58
+ // Every model type the app stores, listed once.
59
+ let simple = try ModelContainer(for: Plant.self, CareEvent.self, GardenBed.self)
60
+
61
+ // Named store, shared with extensions, synced to a private CloudKit database.
62
+ let config = ModelConfiguration(
63
+ "Garden",
64
+ isStoredInMemoryOnly: false,
65
+ groupContainer: .identifier("group.example.garden"),
66
+ cloudKitDatabase: .private("iCloud.example.garden")
67
+ )
68
+ let configured = try ModelContainer(for: Plant.self, configurations: config)
69
+
70
+ // Versioned schema with a migration plan.
71
+ let migrating = try ModelContainer(
72
+ for: GardenSchemaV3.Plant.self,
73
+ migrationPlan: GardenMigrationPlan.self
74
+ )
75
+
76
+ // Tests and previews: nothing touches disk.
77
+ let scratch = try ModelContainer(
78
+ for: Plant.self,
79
+ configurations: ModelConfiguration(isStoredInMemoryOnly: true)
80
+ )
81
+ ```
82
+
83
+ ## Schema versions and migration
84
+
85
+ ```swift
86
+ enum GardenSchemaV1: VersionedSchema {
87
+ static let versionIdentifier = Schema.Version(1, 0, 0)
88
+ static var models: [any PersistentModel.Type] { [Plant.self] }
89
+
90
+ @Model final class Plant {
91
+ var name: String
92
+ init(name: String) { self.name = name }
93
+ }
94
+ }
95
+
96
+ enum GardenSchemaV2: VersionedSchema {
97
+ static let versionIdentifier = Schema.Version(2, 0, 0)
98
+ static var models: [any PersistentModel.Type] { [Plant.self] }
99
+
100
+ @Model final class Plant {
101
+ @Attribute(originalName: "name") var commonName: String
102
+ var sunlight: String = "partial"
103
+ init(commonName: String) { self.commonName = commonName }
104
+ }
105
+ }
106
+
107
+ enum GardenSchemaV3: VersionedSchema {
108
+ static let versionIdentifier = Schema.Version(3, 0, 0)
109
+ static var models: [any PersistentModel.Type] { [Plant.self] }
110
+
111
+ @Model final class Plant {
112
+ var commonName: String
113
+ var sunlight: String = "partial"
114
+ var sunlightHours: Int = 4
115
+ init(commonName: String) { self.commonName = commonName }
116
+ }
117
+ }
118
+
119
+ enum GardenMigrationPlan: SchemaMigrationPlan {
120
+ static var schemas: [any VersionedSchema.Type] {
121
+ [GardenSchemaV1.self, GardenSchemaV2.self, GardenSchemaV3.self]
122
+ }
123
+ static var stages: [MigrationStage] {
124
+ [
125
+ .lightweight(fromVersion: GardenSchemaV1.self, toVersion: GardenSchemaV2.self),
126
+ .custom(
127
+ fromVersion: GardenSchemaV2.self, toVersion: GardenSchemaV3.self,
128
+ willMigrate: nil,
129
+ didMigrate: { context in
130
+ let plants = try context.fetch(FetchDescriptor<GardenSchemaV3.Plant>())
131
+ for plant in plants {
132
+ plant.sunlightHours = plant.sunlight == "full" ? 8 : 4
133
+ }
134
+ try context.save()
135
+ }
136
+ )
137
+ ]
138
+ }
139
+ }
140
+ ```
@@ -52,39 +52,7 @@ are required:
52
52
  the view already holds can trigger a delegate callback that writes the binding
53
53
  that calls update again.
54
54
 
55
- ```swift
56
- import UIKit
57
- import SwiftUI
58
-
59
- struct PlainTextEditor: UIViewRepresentable {
60
- @Binding var draft: String
61
-
62
- func makeCoordinator() -> Coordinator { Coordinator(parent: self) }
63
-
64
- func makeUIView(context: Context) -> UITextView {
65
- let editor = UITextView(frame: .zero)
66
- editor.delegate = context.coordinator
67
- editor.font = .preferredFont(forTextStyle: .body)
68
- return editor
69
- }
70
-
71
- func updateUIView(_ editor: UITextView, context: Context) {
72
- context.coordinator.parent = self
73
- guard editor.text != draft else { return }
74
- editor.text = draft
75
- }
76
-
77
- @MainActor
78
- final class Coordinator: NSObject, UITextViewDelegate {
79
- init(parent: PlainTextEditor) { self.parent = parent }
80
- var parent: PlainTextEditor
81
-
82
- func textViewDidChange(_ editor: UITextView) {
83
- parent.draft = editor.text
84
- }
85
- }
86
- }
87
- ```
55
+ Code for this section: [Interop code](references/interop-code.md).
88
56
 
89
57
  ### Lifecycle order
90
58
 
@@ -141,28 +109,7 @@ and `makeCoordinator()`. For a modal controller the update method usually
141
109
  has nothing to push after presentation; it only refreshes the coordinator's
142
110
  `parent`.
143
111
 
144
- ```swift
145
- import VisionKit
146
- import SwiftUI
147
-
148
- struct PageScannerView: UIViewControllerRepresentable {
149
- @Environment(\.dismiss) var close
150
- @Binding var pages: [UIImage]
151
-
152
- func makeCoordinator() -> Coordinator { Coordinator(parent: self) }
153
-
154
- func makeUIViewController(context: Context) -> VNDocumentCameraViewController {
155
- let camera = VNDocumentCameraViewController()
156
- camera.delegate = context.coordinator
157
- return camera
158
- }
159
-
160
- func updateUIViewController(_ camera: VNDocumentCameraViewController,
161
- context: Context) {
162
- context.coordinator.parent = self
163
- }
164
- }
165
- ```
112
+ Code for this section: [Interop code](references/interop-code.md).
166
113
 
167
114
  ### Returning results from a presented controller
168
115
 
@@ -170,35 +117,12 @@ Delegate callbacks land in the Coordinator, which passes results on by writing
170
117
  a `@Binding` or calling a closure stored on `parent`. Every exit path, success, cancel
171
118
  and failure, ends by dismissing.
172
119
 
173
- ```swift
174
- extension PageScannerView {
175
- @MainActor
176
- final class Coordinator: NSObject, @preconcurrency VNDocumentCameraViewControllerDelegate {
177
- init(parent: PageScannerView) { self.parent = parent }
178
- var parent: PageScannerView
179
-
180
- func documentCameraViewController(_ camera: VNDocumentCameraViewController,
181
- didFinishWith result: VNDocumentCameraScan) {
182
- parent.pages = (0..<result.pageCount).map { index in result.imageOfPage(at: index) }
183
- parent.close()
184
- }
185
-
186
- func documentCameraViewControllerDidCancel(_ camera: VNDocumentCameraViewController) {
187
- parent.close()
188
- }
189
-
190
- func documentCameraViewController(_ camera: VNDocumentCameraViewController,
191
- didFailWithError failure: Error) {
192
- parent.close()
193
- }
194
- }
195
- }
196
- ```
197
-
198
120
  The coordinator is a `final class` that subclasses `NSObject`, adopts the
199
121
  delegate protocol, stores `parent`, and is built from `makeCoordinator()` by
200
122
  passing `self`.
201
123
 
124
+ Code for this section: [Interop code](references/interop-code.md).
125
+
202
126
  ## 3. The Coordinator Pattern
203
127
 
204
128
  ### Why it exists
@@ -214,40 +138,7 @@ Declare the Coordinator as a nested type of the representable, directly or
214
138
  through an extension. Give it a `parent` property holding the representable
215
139
  struct; that is how it writes to `@Binding` properties and calls closures.
216
140
 
217
- ```swift
218
- struct LegacySearchField: UIViewRepresentable {
219
- @Binding var query: String
220
- var onSubmit: (String) -> Void
221
-
222
- func makeCoordinator() -> Coordinator { .init(parent: self) }
223
-
224
- func makeUIView(context: Context) -> UISearchBar {
225
- let bar = UISearchBar(frame: .zero)
226
- bar.delegate = context.coordinator
227
- return bar
228
- }
229
-
230
- func updateUIView(_ bar: UISearchBar, context: Context) {
231
- context.coordinator.parent = self
232
- if bar.text != query { bar.text = query }
233
- }
234
-
235
- @MainActor
236
- final class Coordinator: NSObject, UISearchBarDelegate {
237
- init(parent: LegacySearchField) { self.parent = parent }
238
- var parent: LegacySearchField
239
-
240
- func searchBar(_ bar: UISearchBar, textDidChange newText: String) {
241
- parent.query = newText
242
- }
243
-
244
- func searchBarSearchButtonClicked(_ bar: UISearchBar) {
245
- parent.onSubmit(parent.query)
246
- bar.resignFirstResponder()
247
- }
248
- }
249
- }
250
- ```
141
+ Code for this section: [Interop code](references/interop-code.md).
251
142
 
252
143
  ### Rules
253
144
 
@@ -267,34 +158,15 @@ struct LegacySearchField: UIViewRepresentable {
267
158
  ### Basic embedding
268
159
 
269
160
  `UIHostingController(rootView:)` puts a SwiftUI view inside a UIKit
270
- controller. Containment has three steps and the order is fixed:
271
-
272
- ```swift
273
- final class ProfileScreenController: UIViewController {
274
- let summaryHost = UIHostingController(rootView: ProfileSummary(profile: .empty))
275
-
276
- override func viewDidLoad() {
277
- super.viewDidLoad()
278
- addChild(summaryHost) // 1
279
-
280
- let hosted: UIView = summaryHost.view
281
- hosted.translatesAutoresizingMaskIntoConstraints = false // 2
282
- view.addSubview(hosted)
283
- NSLayoutConstraint.activate([
284
- hosted.topAnchor.constraint(equalTo: view.topAnchor),
285
- hosted.bottomAnchor.constraint(equalTo: view.bottomAnchor),
286
- hosted.leadingAnchor.constraint(equalTo: view.leadingAnchor),
287
- hosted.trailingAnchor.constraint(equalTo: view.trailingAnchor)
288
- ])
289
-
290
- summaryHost.didMove(toParent: self) // 3
291
- }
292
- }
293
- ```
161
+ controller. Containment has three steps and the order is fixed: `addChild(_:)`, add the
162
+ hosting view to the hierarchy with its constraints, then
163
+ `didMove(toParent:)`.
294
164
 
295
165
  Leave out any step and containment callbacks, appearance transitions and trait
296
166
  propagation stop working correctly.
297
167
 
168
+ Code for this section: [Interop code](references/interop-code.md).
169
+
298
170
  ### Sizing options (iOS 16+)
299
171
 
300
172
  `sizingOptions` is an option set on the hosting controller:
@@ -353,7 +225,7 @@ depend on this.
353
225
 
354
226
  **Two-way with `@Binding`.** The coordinator writes `parent.value` from a
355
227
  delegate method; `updateUIView` reads the binding and applies it to the view.
356
- The `PlainTextEditor` above does both halves (`textViewDidChange(_:)` writes,
228
+ The `PlainTextEditor` wrapper in the interop code reference does both halves (`textViewDidChange(_:)` writes,
357
229
  the update method applies).
358
230
 
359
231
  **One-way with closures.** For events that flow only from UIKit to SwiftUI
@@ -431,6 +303,7 @@ is what ends that cycle.
431
303
 
432
304
  ## References
433
305
 
306
+ - [Interop code](references/interop-code.md): open for the code behind a representable wrapper, a coordinator, a presented controller that returns a result, or embedding SwiftUI in UIKit.
434
307
  - [wrapper recipes](references/representable-recipes.md): complete wrapper recipes
435
308
  - [migration guide](references/hosting-migration.md): incremental UIKit to SwiftUI migration
436
309
  - Apple: [UIViewRepresentable](https://developer.apple.com/documentation/swiftui/uiviewrepresentable),
@@ -0,0 +1,198 @@
1
+ # Interop code
2
+
3
+ <!-- toc -->
4
+ - [1. UIViewRepresentable](#1-uiviewrepresentable)
5
+ - [2. UIViewControllerRepresentable](#2-uiviewcontrollerrepresentable)
6
+ - [Returning results from a presented controller](#returning-results-from-a-presented-controller)
7
+ - [Shape](#shape)
8
+ - [Basic embedding](#basic-embedding)
9
+ <!-- /toc -->
10
+
11
+ Code for the representable protocols, returning results from a presented controller, the coordinator shape and basic hosting. SKILL.md keeps lifecycle, rules and review guidance.
12
+
13
+ ## 1. UIViewRepresentable
14
+
15
+ `UIViewRepresentable` lets SwiftUI display any `UIView` subclass. Two methods
16
+ are required:
17
+
18
+ - `makeUIView(context:)` builds and returns the UIKit view. SwiftUI calls it a
19
+ single time, when the representable is inserted. Put one-time setup here:
20
+ delegate assignment, fonts, static configuration.
21
+ - `updateUIView(_:context:)` pushes SwiftUI state into the view. It runs again
22
+ for every relevant state change, so compare before you assign. Writing a value
23
+ the view already holds can trigger a delegate callback that writes the binding
24
+ that calls update again.
25
+
26
+ ```swift
27
+ import UIKit
28
+ import SwiftUI
29
+
30
+ struct PlainTextEditor: UIViewRepresentable {
31
+ @Binding var draft: String
32
+
33
+ func makeCoordinator() -> Coordinator { Coordinator(parent: self) }
34
+
35
+ func makeUIView(context: Context) -> UITextView {
36
+ let editor = UITextView(frame: .zero)
37
+ editor.delegate = context.coordinator
38
+ editor.font = .preferredFont(forTextStyle: .body)
39
+ return editor
40
+ }
41
+
42
+ func updateUIView(_ editor: UITextView, context: Context) {
43
+ context.coordinator.parent = self
44
+ guard editor.text != draft else { return }
45
+ editor.text = draft
46
+ }
47
+
48
+ @MainActor
49
+ final class Coordinator: NSObject, UITextViewDelegate {
50
+ init(parent: PlainTextEditor) { self.parent = parent }
51
+ var parent: PlainTextEditor
52
+
53
+ func textViewDidChange(_ editor: UITextView) {
54
+ parent.draft = editor.text
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## 2. UIViewControllerRepresentable
61
+
62
+ Wrap a `UIViewController` subclass with `UIViewControllerRepresentable`. It is
63
+ the right choice for pickers the system provides, a scanner for documents, the
64
+ mail composer, and other controllers that are normally presented modally.
65
+ The methods mirror the view version: `makeUIViewController(context:)`, `updateUIViewController(_:context:)`
66
+ and `makeCoordinator()`. For a modal controller the update method usually
67
+ has nothing to push after presentation; it only refreshes the coordinator's
68
+ `parent`.
69
+
70
+ ```swift
71
+ import VisionKit
72
+ import SwiftUI
73
+
74
+ struct PageScannerView: UIViewControllerRepresentable {
75
+ @Environment(\.dismiss) var close
76
+ @Binding var pages: [UIImage]
77
+
78
+ func makeCoordinator() -> Coordinator { Coordinator(parent: self) }
79
+
80
+ func makeUIViewController(context: Context) -> VNDocumentCameraViewController {
81
+ let camera = VNDocumentCameraViewController()
82
+ camera.delegate = context.coordinator
83
+ return camera
84
+ }
85
+
86
+ func updateUIViewController(_ camera: VNDocumentCameraViewController,
87
+ context: Context) {
88
+ context.coordinator.parent = self
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### Returning results from a presented controller
94
+
95
+ Delegate callbacks land in the Coordinator, which passes results on by writing
96
+ a `@Binding` or calling a closure stored on `parent`. Every exit path, success, cancel
97
+ and failure, ends by dismissing.
98
+
99
+ ```swift
100
+ extension PageScannerView {
101
+ @MainActor
102
+ final class Coordinator: NSObject, @preconcurrency VNDocumentCameraViewControllerDelegate {
103
+ init(parent: PageScannerView) { self.parent = parent }
104
+ var parent: PageScannerView
105
+
106
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
107
+ didFinishWith result: VNDocumentCameraScan) {
108
+ parent.pages = (0..<result.pageCount).map { index in result.imageOfPage(at: index) }
109
+ parent.close()
110
+ }
111
+
112
+ func documentCameraViewControllerDidCancel(_ camera: VNDocumentCameraViewController) {
113
+ parent.close()
114
+ }
115
+
116
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
117
+ didFailWithError failure: Error) {
118
+ parent.close()
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ The coordinator is a `final class` that subclasses `NSObject`, adopts the
125
+ delegate protocol, stores `parent`, and is built from `makeCoordinator()` by
126
+ passing `self`.
127
+
128
+ ### Shape
129
+
130
+ Declare the Coordinator as a nested type of the representable, directly or
131
+ through an extension. Give it a `parent` property holding the representable
132
+ struct; that is how it writes to `@Binding` properties and calls closures.
133
+
134
+ ```swift
135
+ struct LegacySearchField: UIViewRepresentable {
136
+ @Binding var query: String
137
+ var onSubmit: (String) -> Void
138
+
139
+ func makeCoordinator() -> Coordinator { .init(parent: self) }
140
+
141
+ func makeUIView(context: Context) -> UISearchBar {
142
+ let bar = UISearchBar(frame: .zero)
143
+ bar.delegate = context.coordinator
144
+ return bar
145
+ }
146
+
147
+ func updateUIView(_ bar: UISearchBar, context: Context) {
148
+ context.coordinator.parent = self
149
+ if bar.text != query { bar.text = query }
150
+ }
151
+
152
+ @MainActor
153
+ final class Coordinator: NSObject, UISearchBarDelegate {
154
+ init(parent: LegacySearchField) { self.parent = parent }
155
+ var parent: LegacySearchField
156
+
157
+ func searchBar(_ bar: UISearchBar, textDidChange newText: String) {
158
+ parent.query = newText
159
+ }
160
+
161
+ func searchBarSearchButtonClicked(_ bar: UISearchBar) {
162
+ parent.onSubmit(parent.query)
163
+ bar.resignFirstResponder()
164
+ }
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### Basic embedding
170
+
171
+ `UIHostingController(rootView:)` puts a SwiftUI view inside a UIKit
172
+ controller. Containment has three steps and the order is fixed:
173
+
174
+ ```swift
175
+ final class ProfileScreenController: UIViewController {
176
+ let summaryHost = UIHostingController(rootView: ProfileSummary(profile: .empty))
177
+
178
+ override func viewDidLoad() {
179
+ super.viewDidLoad()
180
+ addChild(summaryHost) // 1
181
+
182
+ let hosted: UIView = summaryHost.view
183
+ hosted.translatesAutoresizingMaskIntoConstraints = false // 2
184
+ view.addSubview(hosted)
185
+ NSLayoutConstraint.activate([
186
+ hosted.topAnchor.constraint(equalTo: view.topAnchor),
187
+ hosted.bottomAnchor.constraint(equalTo: view.bottomAnchor),
188
+ hosted.leadingAnchor.constraint(equalTo: view.leadingAnchor),
189
+ hosted.trailingAnchor.constraint(equalTo: view.trailingAnchor)
190
+ ])
191
+
192
+ summaryHost.didMove(toParent: self) // 3
193
+ }
194
+ }
195
+ ```
196
+
197
+ Leave out any step and containment callbacks, appearance transitions and trait
198
+ propagation stop working correctly.
@@ -123,91 +123,15 @@ Content detection is automatic with no `content` array needed.
123
123
 
124
124
  ### Form
125
125
 
126
- ```html
127
- <form class="space-y-6 max-w-md mx-auto">
128
- <div>
129
- <label for="email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
130
- Email
131
- </label>
132
- <input
133
- type="email"
134
- id="email"
135
- class="
136
- mt-1 block w-full rounded-lg border border-gray-300
137
- px-4 py-2.5 text-gray-900
138
- shadow-sm
139
- placeholder:text-gray-400
140
- focus:border-brand focus:ring-2 focus:ring-brand/20 focus:outline-none
141
- dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100
142
- dark:focus:border-brand-light
143
- "
144
- placeholder="you@example.com"
145
- />
146
- </div>
126
+ Every input has a `<label for>`, focus styles use `focus:ring` plus `focus:outline-none`, each state has a `dark:` variant, helper text sits under the field, and the submit button carries `disabled:` styles.
147
127
 
148
- <div>
149
- <label for="password" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
150
- Password
151
- </label>
152
- <input
153
- type="password"
154
- id="password"
155
- class="
156
- mt-1 block w-full rounded-lg border border-gray-300
157
- px-4 py-2.5 text-gray-900
158
- shadow-sm
159
- focus:border-brand focus:ring-2 focus:ring-brand/20 focus:outline-none
160
- dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100
161
- "
162
- />
163
- <p class="mt-1 text-xs text-gray-500">Must be at least 8 characters.</p>
164
- </div>
165
-
166
- <button
167
- type="submit"
168
- class="
169
- w-full rounded-lg bg-brand px-4 py-2.5
170
- text-sm font-semibold text-white
171
- shadow-sm
172
- hover:bg-brand-dark focus:ring-2 focus:ring-brand/50 focus:outline-none
173
- disabled:opacity-50 disabled:cursor-not-allowed
174
- transition-colors
175
- "
176
- >
177
- Sign in
178
- </button>
179
- </form>
180
- ```
128
+ Code: [Form](references/code-examples.md#form).
181
129
 
182
130
  ### Navigation
183
131
 
184
- ```html
185
- <nav class="bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
186
- <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
187
- <div class="flex h-16 items-center justify-between">
188
- <div class="flex items-center gap-8">
189
- <a href="/" class="text-xl font-bold text-brand">Logo</a>
190
- <div class="hidden md:flex gap-6">
191
- <a href="#" class="text-sm font-medium text-gray-900 dark:text-gray-100 hover:text-brand">
192
- Home
193
- </a>
194
- <a href="#" class="text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-brand">
195
- Products
196
- </a>
197
- <a href="#" class="text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-brand">
198
- About
199
- </a>
200
- </div>
201
- </div>
202
- <button class="md:hidden p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800">
203
- <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
204
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
205
- </svg>
206
- </button>
207
- </div>
208
- </div>
209
- </nav>
210
- ```
132
+ A bordered `<nav>` with a centered `max-w-7xl` container, inline links shown from `md:` up, and a menu button visible only below `md:`.
133
+
134
+ Code: [Navigation](references/code-examples.md#navigation).
211
135
 
212
136
  ## The cn() Utility
213
137
 
@@ -310,3 +234,7 @@ function Button({ variant = 'primary', size = 'md', className, children }: Butto
310
234
  | Custom color not found | Missing `@theme` definition | Define custom values in `@theme` block |
311
235
  | Container queries not working | Missing `@container` parent | Wrap parent element with `@container` class |
312
236
  | Arbitrary value not compiled | Syntax error in brackets | Check for spaces: `w-[calc(100%-2rem)]` |
237
+
238
+ ## References
239
+
240
+ - [Code examples](references/code-examples.md): open for the full code behind Form, Navigation.