swift-code-reviewer-skill 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +44 -162
  2. package/README.md +91 -21
  3. package/SKILL.md +107 -725
  4. package/bin/install.js +87 -22
  5. package/package.json +16 -2
  6. package/references/companion-skills.md +70 -0
  7. package/skills/README.md +43 -0
  8. package/skills/swift-concurrency/NOTICE.md +18 -0
  9. package/skills/swift-concurrency/SKILL.md +235 -0
  10. package/skills/swift-concurrency/references/actors.md +640 -0
  11. package/skills/swift-concurrency/references/async-await-basics.md +249 -0
  12. package/skills/swift-concurrency/references/async-sequences.md +635 -0
  13. package/skills/swift-concurrency/references/core-data.md +533 -0
  14. package/skills/swift-concurrency/references/glossary.md +96 -0
  15. package/skills/swift-concurrency/references/linting.md +38 -0
  16. package/skills/swift-concurrency/references/memory-management.md +542 -0
  17. package/skills/swift-concurrency/references/migration.md +721 -0
  18. package/skills/swift-concurrency/references/performance.md +574 -0
  19. package/skills/swift-concurrency/references/sendable.md +578 -0
  20. package/skills/swift-concurrency/references/tasks.md +604 -0
  21. package/skills/swift-concurrency/references/testing.md +565 -0
  22. package/skills/swift-concurrency/references/threading.md +452 -0
  23. package/skills/swift-expert/NOTICE.md +18 -0
  24. package/skills/swift-expert/SKILL.md +226 -0
  25. package/skills/swift-expert/references/async-concurrency.md +363 -0
  26. package/skills/swift-expert/references/memory-performance.md +380 -0
  27. package/skills/swift-expert/references/protocol-oriented.md +357 -0
  28. package/skills/swift-expert/references/swiftui-patterns.md +294 -0
  29. package/skills/swift-expert/references/testing-patterns.md +402 -0
  30. package/skills/swift-testing/NOTICE.md +18 -0
  31. package/skills/swift-testing/SKILL.md +295 -0
  32. package/skills/swift-testing/references/async-testing.md +245 -0
  33. package/skills/swift-testing/references/dump-snapshot-testing.md +265 -0
  34. package/skills/swift-testing/references/fixtures.md +193 -0
  35. package/skills/swift-testing/references/integration-testing.md +189 -0
  36. package/skills/swift-testing/references/migration-xctest.md +301 -0
  37. package/skills/swift-testing/references/parameterized-tests.md +171 -0
  38. package/skills/swift-testing/references/snapshot-testing.md +201 -0
  39. package/skills/swift-testing/references/test-doubles.md +243 -0
  40. package/skills/swift-testing/references/test-organization.md +231 -0
  41. package/skills/swiftui-expert-skill/NOTICE.md +18 -0
  42. package/skills/swiftui-expert-skill/SKILL.md +281 -0
  43. package/skills/swiftui-expert-skill/references/accessibility-patterns.md +151 -0
  44. package/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
  45. package/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  46. package/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  47. package/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
  48. package/skills/swiftui-expert-skill/references/charts.md +602 -0
  49. package/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
  50. package/skills/swiftui-expert-skill/references/latest-apis.md +464 -0
  51. package/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
  52. package/skills/swiftui-expert-skill/references/liquid-glass.md +414 -0
  53. package/skills/swiftui-expert-skill/references/list-patterns.md +394 -0
  54. package/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
  55. package/skills/swiftui-expert-skill/references/macos-views.md +357 -0
  56. package/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
  57. package/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
  58. package/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
  59. package/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
  60. package/skills/swiftui-expert-skill/references/state-management.md +417 -0
  61. package/skills/swiftui-expert-skill/references/view-structure.md +389 -0
  62. package/skills/swiftui-ui-patterns/NOTICE.md +18 -0
  63. package/skills/swiftui-ui-patterns/SKILL.md +95 -0
  64. package/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
  65. package/skills/swiftui-ui-patterns/references/async-state.md +96 -0
  66. package/skills/swiftui-ui-patterns/references/components-index.md +50 -0
  67. package/skills/swiftui-ui-patterns/references/controls.md +57 -0
  68. package/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
  69. package/skills/swiftui-ui-patterns/references/focus.md +90 -0
  70. package/skills/swiftui-ui-patterns/references/form.md +97 -0
  71. package/skills/swiftui-ui-patterns/references/grids.md +71 -0
  72. package/skills/swiftui-ui-patterns/references/haptics.md +71 -0
  73. package/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  74. package/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  75. package/skills/swiftui-ui-patterns/references/list.md +86 -0
  76. package/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  77. package/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
  78. package/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  79. package/skills/swiftui-ui-patterns/references/media.md +73 -0
  80. package/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
  81. package/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
  82. package/skills/swiftui-ui-patterns/references/overlay.md +45 -0
  83. package/skills/swiftui-ui-patterns/references/performance.md +62 -0
  84. package/skills/swiftui-ui-patterns/references/previews.md +48 -0
  85. package/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  86. package/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
  87. package/skills/swiftui-ui-patterns/references/searchable.md +71 -0
  88. package/skills/swiftui-ui-patterns/references/sheets.md +155 -0
  89. package/skills/swiftui-ui-patterns/references/split-views.md +72 -0
  90. package/skills/swiftui-ui-patterns/references/tabview.md +114 -0
  91. package/skills/swiftui-ui-patterns/references/theming.md +71 -0
  92. package/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
  93. package/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
  94. package/templates/agents/swift-code-reviewer.md +78 -0
  95. package/templates/commands/review.md +56 -0
@@ -0,0 +1,363 @@
1
+ # SwiftUI Sheet, Navigation & Inspector Patterns Reference
2
+
3
+ ## Table of Contents
4
+
5
+ - [Sheet Patterns](#sheet-patterns)
6
+ - [Navigation Patterns](#navigation-patterns)
7
+ - [Multi-Column Navigation with NavigationSplitView](#multi-column-navigation-with-navigationsplitview)
8
+ - [Inspector](#inspector)
9
+ - [Presentation Modifiers](#presentation-modifiers)
10
+ - [Summary Checklist](#summary-checklist)
11
+
12
+ ## Sheet Patterns
13
+
14
+ ### Item-Driven Sheets (Preferred)
15
+
16
+ **Use `.sheet(item:)` instead of `.sheet(isPresented:)` when presenting model-based content.**
17
+
18
+ ```swift
19
+ // Good - item-driven
20
+ @State private var selectedItem: Item?
21
+
22
+ var body: some View {
23
+ List(items) { item in
24
+ Button(item.name) {
25
+ selectedItem = item
26
+ }
27
+ }
28
+ .sheet(item: $selectedItem) { item in
29
+ ItemDetailSheet(item: item)
30
+ }
31
+ }
32
+
33
+ // Avoid - boolean flag requires separate state
34
+ @State private var showSheet = false
35
+ @State private var selectedItem: Item?
36
+
37
+ var body: some View {
38
+ List(items) { item in
39
+ Button(item.name) {
40
+ selectedItem = item
41
+ showSheet = true
42
+ }
43
+ }
44
+ .sheet(isPresented: $showSheet) {
45
+ if let selectedItem {
46
+ ItemDetailSheet(item: selectedItem)
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ **Why**: `.sheet(item:)` automatically handles presentation state and avoids optional unwrapping in the sheet body.
53
+
54
+ ### Sheets Own Their Actions
55
+
56
+ **Sheets should handle their own dismiss and actions internally** using `@Environment(\.dismiss)`. Avoid passing `onSave`/`onCancel` closures from the parent -- it creates callback prop-drilling and reduces reusability.
57
+
58
+ ```swift
59
+ struct EditItemSheet: View {
60
+ @Environment(\.dismiss) private var dismiss
61
+ let item: Item
62
+ @State private var name: String
63
+
64
+ init(item: Item) {
65
+ self.item = item
66
+ _name = State(initialValue: item.name)
67
+ }
68
+
69
+ var body: some View {
70
+ NavigationStack {
71
+ Form { TextField("Name", text: $name) }
72
+ .navigationTitle("Edit Item")
73
+ .toolbar {
74
+ ToolbarItem(placement: .cancellationAction) { Button("Cancel") { dismiss() } }
75
+ ToolbarItem(placement: .confirmationAction) { Button("Save") { /* save and dismiss */ } }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### Enum-Based Sheet Management
83
+
84
+ When presenting multiple different sheets, use an `Identifiable` enum with `.sheet(item:)` instead of multiple boolean state properties:
85
+
86
+ ```swift
87
+ struct ArticlesView: View {
88
+ enum Sheet: Identifiable {
89
+ case add, edit(Article), categories
90
+ var id: String {
91
+ switch self {
92
+ case .add: "add"
93
+ case .edit(let a): "edit-\(a.id)"
94
+ case .categories: "categories"
95
+ }
96
+ }
97
+ }
98
+
99
+ @State private var presentedSheet: Sheet?
100
+
101
+ var body: some View {
102
+ List { /* ... */ }
103
+ .toolbar {
104
+ Button("Add") { presentedSheet = .add }
105
+ }
106
+ .sheet(item: $presentedSheet) { sheet in
107
+ switch sheet {
108
+ case .add: AddArticleView()
109
+ case .edit(let article): EditArticleView(article: article)
110
+ case .categories: CategoriesView()
111
+ }
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ **Why**: A single `@State` property and one `.sheet(item:)` modifier replaces N boolean properties and N sheet modifiers, improving readability and preventing only-one-sheet-at-a-time conflicts.
118
+
119
+ ## Navigation Patterns
120
+
121
+ ### Type-Safe Navigation with NavigationStack
122
+
123
+ ```swift
124
+ struct ContentView: View {
125
+ var body: some View {
126
+ NavigationStack {
127
+ List {
128
+ NavigationLink("Profile", value: Route.profile)
129
+ NavigationLink("Settings", value: Route.settings)
130
+ }
131
+ .navigationDestination(for: Route.self) { route in
132
+ switch route {
133
+ case .profile:
134
+ ProfileView()
135
+ case .settings:
136
+ SettingsView()
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ enum Route: Hashable {
144
+ case profile
145
+ case settings
146
+ }
147
+ ```
148
+
149
+ ### Programmatic Navigation
150
+
151
+ ```swift
152
+ struct ContentView: View {
153
+ @State private var navigationPath = NavigationPath()
154
+
155
+ var body: some View {
156
+ NavigationStack(path: $navigationPath) {
157
+ List {
158
+ Button("Go to Detail") {
159
+ navigationPath.append(DetailRoute.item(id: 1))
160
+ }
161
+ }
162
+ .navigationDestination(for: DetailRoute.self) { route in
163
+ switch route {
164
+ case .item(let id):
165
+ ItemDetailView(id: id)
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ enum DetailRoute: Hashable {
173
+ case item(id: Int)
174
+ }
175
+ ```
176
+
177
+ ## Multi-Column Navigation with NavigationSplitView
178
+
179
+ ### Two-Column Layout
180
+
181
+ Use `NavigationSplitView` for sidebar-driven navigation. Available on iOS 16+, macOS 13+, tvOS 16+, watchOS 9+.
182
+
183
+ ```swift
184
+ struct ContentView: View {
185
+ @State private var selectedItem: Item.ID?
186
+
187
+ var body: some View {
188
+ NavigationSplitView {
189
+ List(items, selection: $selectedItem) { item in
190
+ Text(item.name)
191
+ }
192
+ .navigationTitle("Items")
193
+ } detail: {
194
+ if let selectedItem, let item = items.first(where: { $0.id == selectedItem }) {
195
+ ItemDetailView(item: item)
196
+ } else {
197
+ ContentUnavailableView("Select an Item", systemImage: "doc")
198
+ }
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ ### Three-Column Layout
205
+
206
+ ```swift
207
+ struct ContentView: View {
208
+ @State private var departmentId: Department.ID?
209
+ @State private var employeeIds = Set<Employee.ID>()
210
+
211
+ var body: some View {
212
+ NavigationSplitView {
213
+ List(model.departments, selection: $departmentId) { dept in
214
+ Text(dept.name)
215
+ }
216
+ } content: {
217
+ if let department = model.department(id: departmentId) {
218
+ List(department.employees, selection: $employeeIds) { emp in
219
+ Text(emp.name)
220
+ }
221
+ } else {
222
+ Text("Select a department")
223
+ }
224
+ } detail: {
225
+ EmployeeDetails(for: employeeIds)
226
+ }
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### Configuration
232
+
233
+ - **Column visibility**: `NavigationSplitView(columnVisibility: $visibility)` with `NavigationSplitViewVisibility` (`.detailOnly`, `.doubleColumn`, `.all`)
234
+ - **Column widths**: `.navigationSplitViewColumnWidth(min:ideal:max:)` on each column
235
+ - **Compact column**: `NavigationSplitView(preferredCompactColumn: $column)` to control which column shows on narrow devices
236
+ - **Style**: `.navigationSplitViewStyle(.balanced)` or `.prominentDetail` (default)
237
+
238
+ ### Platform Behavior
239
+
240
+ | Platform | Behavior |
241
+ |----------|----------|
242
+ | **macOS** | Columns always visible side-by-side; sidebar has translucent material; variable-width column resizing by dragging |
243
+ | **iPadOS (regular)** | Sidebar can overlay or push detail; supports column visibility toggle via toolbar button |
244
+ | **iOS / iPadOS (compact)** | Collapses into a single `NavigationStack`; sidebar items show disclosure chevrons; back button navigates between columns |
245
+ | **iPhone (all sizes)** | Always collapsed into a stack; sidebar appears as the root list; selections push detail onto the stack |
246
+ | **watchOS / tvOS** | Collapses into a single stack |
247
+
248
+ ## Inspector
249
+
250
+ > **Availability:** iOS 17.0+, macOS 14.0+
251
+
252
+ A trailing-edge panel for supplementary information.
253
+
254
+ On wider size classes (macOS, iPad landscape), it appears as a **trailing column**. On compact size classes (iPhone), it **adapts to a sheet** automatically.
255
+
256
+ ### Basic Inspector
257
+
258
+ ```swift
259
+ struct ShapeEditor: View {
260
+ @State private var showInspector = false
261
+
262
+ var body: some View {
263
+ MyEditorView()
264
+ .inspector(isPresented: $showInspector) {
265
+ InspectorContent()
266
+ }
267
+ .toolbar {
268
+ ToolbarItem {
269
+ Button {
270
+ showInspector.toggle()
271
+ } label: {
272
+ Label("Inspector", systemImage: "info.circle")
273
+ }
274
+ }
275
+ }
276
+ }
277
+ }
278
+ ```
279
+
280
+ ### Inspector with Column Width
281
+
282
+ ```swift
283
+ MyEditorView()
284
+ .inspector(isPresented: $showInspector) {
285
+ InspectorContent()
286
+ .inspectorColumnWidth(min: 200, ideal: 250, max: 400)
287
+ }
288
+ ```
289
+
290
+ ### Inspector with Fixed Width
291
+
292
+ ```swift
293
+ MyEditorView()
294
+ .inspector(isPresented: $showInspector) {
295
+ InspectorContent()
296
+ .inspectorColumnWidth(300)
297
+ }
298
+ ```
299
+
300
+ ### Platform Behavior
301
+
302
+ | Platform | Behavior |
303
+ |----------|----------|
304
+ | **macOS** | Trailing-edge sidebar panel; resizable by dragging edge; integrates with window toolbar |
305
+ | **iPadOS (regular)** | Trailing column alongside content; toggleable via toolbar button |
306
+ | **iOS / iPadOS (compact)** | Adapts to a sheet presentation; swipe-to-dismiss supported |
307
+ | **iPhone (all sizes)** | Always presented as a sheet (no trailing column); dismiss via swipe or button |
308
+
309
+ > **Tip:** Use `InspectorCommands` in your app's `.commands` to include the default inspector toggle keyboard shortcut.
310
+
311
+ ## Presentation Modifiers
312
+
313
+ ### Full Screen Cover
314
+
315
+ ```swift
316
+ struct ContentView: View {
317
+ @State private var showFullScreen = false
318
+
319
+ var body: some View {
320
+ Button("Show Full Screen") {
321
+ showFullScreen = true
322
+ }
323
+ .fullScreenCover(isPresented: $showFullScreen) {
324
+ FullScreenView()
325
+ }
326
+ }
327
+ }
328
+ ```
329
+
330
+ ### Popover
331
+
332
+ ```swift
333
+ struct ContentView: View {
334
+ @State private var showPopover = false
335
+
336
+ var body: some View {
337
+ Button("Show Popover") {
338
+ showPopover = true
339
+ }
340
+ .popover(isPresented: $showPopover) {
341
+ PopoverContentView()
342
+ .presentationCompactAdaptation(.popover) // Don't adapt to sheet on iPhone
343
+ }
344
+ }
345
+ }
346
+ ```
347
+
348
+ For `alert` and `confirmationDialog` API patterns, see `latest-apis.md`.
349
+
350
+ ## Summary Checklist
351
+
352
+ - [ ] Use `.sheet(item:)` for model-based sheets
353
+ - [ ] Sheets own their actions and dismiss internally
354
+ - [ ] Use `NavigationStack` with `navigationDestination(for:)` for type-safe navigation
355
+ - [ ] Use `NavigationPath` for programmatic navigation
356
+ - [ ] Use `NavigationSplitView` for sidebar-driven multi-column layouts
357
+ - [ ] Use `Inspector` for trailing-edge supplementary panels
358
+ - [ ] Set column widths with `navigationSplitViewColumnWidth(min:ideal:max:)` or `inspectorColumnWidth(min:ideal:max:)`
359
+ - [ ] Use appropriate presentation modifiers (sheet, fullScreenCover, popover)
360
+ - [ ] Alerts and confirmation dialogs use modern API with actions
361
+ - [ ] Avoid passing dismiss/save callbacks to sheets
362
+ - [ ] Use enum-based `Identifiable` type with `.sheet(item:)` when presenting multiple sheets
363
+ - [ ] Navigation state can be saved/restored when needed