claudecode-omc 5.6.7 → 5.6.8

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 (123) hide show
  1. package/.local/skills/THIRD_PARTY_LICENSES/AvdLee-SwiftUI-Agent-Skill.LICENSE +21 -0
  2. package/.local/skills/THIRD_PARTY_LICENSES/Dimillian-Skills.LICENSE +21 -0
  3. package/.local/skills/THIRD_PARTY_LICENSES/README.md +36 -0
  4. package/.local/skills/THIRD_PARTY_LICENSES/twostraws-swiftui-agent-skill.LICENSE +21 -0
  5. package/.local/skills/ios-debugger-agent/SKILL.md +51 -0
  6. package/.local/skills/ios-debugger-agent/agents/openai.yaml +4 -0
  7. package/.local/skills/swift-concurrency-expert/SKILL.md +105 -0
  8. package/.local/skills/swift-concurrency-expert/agents/openai.yaml +4 -0
  9. package/.local/skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
  10. package/.local/skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
  11. package/.local/skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
  12. package/.local/skills/swiftui-expert-skill/SKILL.md +162 -0
  13. package/.local/skills/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
  14. package/.local/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
  15. package/.local/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  16. package/.local/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  17. package/.local/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
  18. package/.local/skills/swiftui-expert-skill/references/charts.md +602 -0
  19. package/.local/skills/swiftui-expert-skill/references/focus-patterns.md +299 -0
  20. package/.local/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
  21. package/.local/skills/swiftui-expert-skill/references/latest-apis.md +488 -0
  22. package/.local/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
  23. package/.local/skills/swiftui-expert-skill/references/liquid-glass.md +423 -0
  24. package/.local/skills/swiftui-expert-skill/references/list-patterns.md +446 -0
  25. package/.local/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
  26. package/.local/skills/swiftui-expert-skill/references/macos-views.md +357 -0
  27. package/.local/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
  28. package/.local/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
  29. package/.local/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
  30. package/.local/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
  31. package/.local/skills/swiftui-expert-skill/references/state-management.md +388 -0
  32. package/.local/skills/swiftui-expert-skill/references/text-patterns.md +32 -0
  33. package/.local/skills/swiftui-expert-skill/references/trace-analysis.md +295 -0
  34. package/.local/skills/swiftui-expert-skill/references/trace-recording.md +134 -0
  35. package/.local/skills/swiftui-expert-skill/references/view-structure.md +780 -0
  36. package/.local/skills/swiftui-expert-skill/scripts/__pycache__/analyze_trace.cpython-313.pyc +0 -0
  37. package/.local/skills/swiftui-expert-skill/scripts/__pycache__/record_trace.cpython-313.pyc +0 -0
  38. package/.local/skills/swiftui-expert-skill/scripts/analyze_trace.py +301 -0
  39. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__init__.py +1 -0
  40. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/__init__.cpython-313.pyc +0 -0
  41. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/causes.cpython-313.pyc +0 -0
  42. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/correlate.cpython-313.pyc +0 -0
  43. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/events.cpython-313.pyc +0 -0
  44. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hangs.cpython-313.pyc +0 -0
  45. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hitches.cpython-313.pyc +0 -0
  46. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/summary.cpython-313.pyc +0 -0
  47. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/swiftui.cpython-313.pyc +0 -0
  48. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/time_profiler.cpython-313.pyc +0 -0
  49. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xctrace.cpython-313.pyc +0 -0
  50. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xml_utils.cpython-313.pyc +0 -0
  51. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/causes.py +187 -0
  52. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/correlate.py +179 -0
  53. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/events.py +291 -0
  54. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hangs.py +108 -0
  55. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hitches.py +145 -0
  56. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/summary.py +243 -0
  57. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/swiftui.py +195 -0
  58. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/time_profiler.py +135 -0
  59. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +117 -0
  60. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +224 -0
  61. package/.local/skills/swiftui-expert-skill/scripts/record_trace.py +252 -0
  62. package/.local/skills/swiftui-liquid-glass/SKILL.md +90 -0
  63. package/.local/skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
  64. package/.local/skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
  65. package/.local/skills/swiftui-performance-audit/SKILL.md +106 -0
  66. package/.local/skills/swiftui-performance-audit/agents/openai.yaml +4 -0
  67. package/.local/skills/swiftui-performance-audit/references/code-smells.md +150 -0
  68. package/.local/skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
  69. package/.local/skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
  70. package/.local/skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
  71. package/.local/skills/swiftui-performance-audit/references/report-template.md +47 -0
  72. package/.local/skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
  73. package/.local/skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
  74. package/.local/skills/swiftui-pro/SKILL.md +108 -0
  75. package/.local/skills/swiftui-pro/agents/openai.yaml +10 -0
  76. package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
  77. package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
  78. package/.local/skills/swiftui-pro/references/accessibility.md +13 -0
  79. package/.local/skills/swiftui-pro/references/api.md +39 -0
  80. package/.local/skills/swiftui-pro/references/data.md +43 -0
  81. package/.local/skills/swiftui-pro/references/design.md +32 -0
  82. package/.local/skills/swiftui-pro/references/hygiene.md +9 -0
  83. package/.local/skills/swiftui-pro/references/navigation.md +14 -0
  84. package/.local/skills/swiftui-pro/references/performance.md +46 -0
  85. package/.local/skills/swiftui-pro/references/swift.md +56 -0
  86. package/.local/skills/swiftui-pro/references/views.md +36 -0
  87. package/.local/skills/swiftui-ui-patterns/SKILL.md +95 -0
  88. package/.local/skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
  89. package/.local/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
  90. package/.local/skills/swiftui-ui-patterns/references/async-state.md +96 -0
  91. package/.local/skills/swiftui-ui-patterns/references/components-index.md +50 -0
  92. package/.local/skills/swiftui-ui-patterns/references/controls.md +57 -0
  93. package/.local/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
  94. package/.local/skills/swiftui-ui-patterns/references/focus.md +90 -0
  95. package/.local/skills/swiftui-ui-patterns/references/form.md +97 -0
  96. package/.local/skills/swiftui-ui-patterns/references/grids.md +71 -0
  97. package/.local/skills/swiftui-ui-patterns/references/haptics.md +71 -0
  98. package/.local/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  99. package/.local/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  100. package/.local/skills/swiftui-ui-patterns/references/list.md +86 -0
  101. package/.local/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  102. package/.local/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
  103. package/.local/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  104. package/.local/skills/swiftui-ui-patterns/references/media.md +73 -0
  105. package/.local/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
  106. package/.local/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
  107. package/.local/skills/swiftui-ui-patterns/references/overlay.md +45 -0
  108. package/.local/skills/swiftui-ui-patterns/references/performance.md +62 -0
  109. package/.local/skills/swiftui-ui-patterns/references/previews.md +48 -0
  110. package/.local/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  111. package/.local/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
  112. package/.local/skills/swiftui-ui-patterns/references/searchable.md +71 -0
  113. package/.local/skills/swiftui-ui-patterns/references/sheets.md +155 -0
  114. package/.local/skills/swiftui-ui-patterns/references/split-views.md +72 -0
  115. package/.local/skills/swiftui-ui-patterns/references/tabview.md +114 -0
  116. package/.local/skills/swiftui-ui-patterns/references/theming.md +71 -0
  117. package/.local/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
  118. package/.local/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
  119. package/.local/skills/swiftui-view-refactor/SKILL.md +202 -0
  120. package/.local/skills/swiftui-view-refactor/agents/openai.yaml +4 -0
  121. package/.local/skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
  122. package/bundled/manifest.json +1 -1
  123. package/package.json +1 -1
@@ -0,0 +1,446 @@
1
+ # SwiftUI List Patterns Reference
2
+
3
+ ## Table of Contents
4
+
5
+ - [ForEach Identity and Stability](#foreach-identity-and-stability)
6
+ - [Enumerated Sequences](#enumerated-sequences)
7
+ - [List with Custom Styling](#list-with-custom-styling)
8
+ - [List with Pull-to-Refresh](#list-with-pull-to-refresh)
9
+ - [Empty States with ContentUnavailableView (iOS 17+)](#empty-states-with-contentunavailableview-ios-17)
10
+ - [Custom List Backgrounds](#custom-list-backgrounds)
11
+ - [Table](#table)
12
+ - [Summary Checklist](#summary-checklist)
13
+
14
+ ## ForEach Identity and Stability
15
+
16
+ **Always provide stable identity for `ForEach`.** Never use `.indices` for dynamic content.
17
+
18
+ ```swift
19
+ // Good - stable identity via Identifiable
20
+ extension User: Identifiable {
21
+ var id: String { userId }
22
+ }
23
+
24
+ ForEach(users) { user in
25
+ UserRow(user: user)
26
+ }
27
+
28
+ // Good - stable identity via keypath
29
+ ForEach(users, id: \.userId) { user in
30
+ UserRow(user: user)
31
+ }
32
+
33
+ // Wrong - indices create static content
34
+ ForEach(users.indices, id: \.self) { index in
35
+ UserRow(user: users[index]) // Can crash on removal!
36
+ }
37
+
38
+ // Wrong - unstable identity
39
+ ForEach(users, id: \.self) { user in
40
+ UserRow(user: user) // Only works if User is Hashable and stable
41
+ }
42
+ ```
43
+
44
+ **Critical**: Ensure **constant number of views per element** in `ForEach`:
45
+
46
+ ```swift
47
+ // Good - consistent view count
48
+ ForEach(items) { item in
49
+ ItemRow(item: item)
50
+ }
51
+
52
+ // Bad - variable view count breaks identity
53
+ ForEach(items) { item in
54
+ if item.isSpecial {
55
+ SpecialRow(item: item)
56
+ DetailRow(item: item)
57
+ } else {
58
+ RegularRow(item: item)
59
+ }
60
+ }
61
+ ```
62
+
63
+ **Avoid inline filtering:**
64
+
65
+ ```swift
66
+ // Bad - unstable identity, changes on every update
67
+ ForEach(items.filter { $0.isEnabled }) { item in
68
+ ItemRow(item: item)
69
+ }
70
+
71
+ // Good - prefilter and cache
72
+ @State private var enabledItems: [Item] = []
73
+
74
+ var body: some View {
75
+ ForEach(enabledItems) { item in
76
+ ItemRow(item: item)
77
+ }
78
+ .onChange(of: items) { _, newItems in
79
+ enabledItems = newItems.filter { $0.isEnabled }
80
+ }
81
+ }
82
+ ```
83
+
84
+ **Avoid `AnyView` in list rows:**
85
+
86
+ ```swift
87
+ // Bad - hides identity, increases cost
88
+ ForEach(items) { item in
89
+ AnyView(item.isSpecial ? SpecialRow(item: item) : RegularRow(item: item))
90
+ }
91
+
92
+ // Good - Create a unified row view
93
+ ForEach(items) { item in
94
+ ItemRow(item: item)
95
+ }
96
+
97
+ struct ItemRow: View {
98
+ let item: Item
99
+
100
+ var body: some View {
101
+ if item.isSpecial {
102
+ SpecialRow(item: item)
103
+ } else {
104
+ RegularRow(item: item)
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ **Why**: Stable identity is critical for performance and animations. Unstable identity causes excessive diffing, broken animations, and potential crashes.
111
+
112
+ ### Identifiable ID Must Be Truly Unique
113
+
114
+ Non-unique IDs cause SwiftUI to treat different items as identical, leading to duplicate rendering or missing views:
115
+
116
+ ```swift
117
+ // Bug -- two articles with the same URL show identical content
118
+ struct Article: Identifiable {
119
+ let title: String
120
+ let url: URL
121
+ var id: String { url.absoluteString } // Not unique if URLs repeat!
122
+ }
123
+
124
+ // Fix -- use a genuinely unique identifier
125
+ struct Article: Identifiable {
126
+ let id: UUID
127
+ let title: String
128
+ let url: URL
129
+ }
130
+ ```
131
+
132
+ **Classes get a default `ObjectIdentifier`-based `id`** when conforming to `Identifiable` without providing one. This is only unique for the object's lifetime and can be recycled after deallocation.
133
+
134
+ ## Enumerated Sequences
135
+
136
+ **Always convert enumerated sequences to arrays. To be able to use them in a ForEach.**
137
+
138
+ ```swift
139
+ let items = ["A", "B", "C"]
140
+
141
+ // Correct
142
+ ForEach(Array(items.enumerated()), id: \.offset) { index, item in
143
+ Text("\(index): \(item)")
144
+ }
145
+
146
+ // Wrong - Doesn't compile, enumerated() isn't an array
147
+ ForEach(items.enumerated(), id: \.offset) { index, item in
148
+ Text("\(index): \(item)")
149
+ }
150
+ ```
151
+
152
+ ## List with Custom Styling
153
+
154
+ ```swift
155
+ // Remove default background and separators
156
+ List(items) { item in
157
+ ItemRow(item: item)
158
+ .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
159
+ .listRowSeparator(.hidden)
160
+ }
161
+ .listStyle(.plain)
162
+ .scrollContentBackground(.hidden)
163
+ .background(Color.customBackground)
164
+ .environment(\.defaultMinListRowHeight, 1) // Allows custom row heights
165
+ ```
166
+
167
+ ## List with Pull-to-Refresh
168
+
169
+ ```swift
170
+ List(items) { item in
171
+ ItemRow(item: item)
172
+ }
173
+ .refreshable {
174
+ await loadItems()
175
+ }
176
+ ```
177
+
178
+ ## Empty States with ContentUnavailableView (iOS 17+)
179
+
180
+ Use `ContentUnavailableView` for empty list/search states. The built-in `.search` variant is auto-localized:
181
+
182
+ ```swift
183
+ List {
184
+ ForEach(searchResults) { item in
185
+ ItemRow(item: item)
186
+ }
187
+ }
188
+ .overlay {
189
+ if searchResults.isEmpty, !searchText.isEmpty {
190
+ ContentUnavailableView.search(text: searchText)
191
+ }
192
+ }
193
+ ```
194
+
195
+ For non-search empty states, use a custom instance:
196
+
197
+ ```swift
198
+ ContentUnavailableView(
199
+ "No Articles",
200
+ systemImage: "doc.richtext.fill",
201
+ description: Text("Articles you save will appear here.")
202
+ )
203
+ ```
204
+
205
+ ## Custom List Backgrounds
206
+
207
+ Use `.scrollContentBackground(.hidden)` to replace the default list background:
208
+
209
+ ```swift
210
+ List(items) { item in
211
+ ItemRow(item: item)
212
+ }
213
+ .scrollContentBackground(.hidden)
214
+ .background(Color.customBackground)
215
+ ```
216
+
217
+ Without `.scrollContentBackground(.hidden)`, a custom `.background()` has no visible effect on `List`.
218
+
219
+ ## Table
220
+
221
+ > **Availability:** iOS 16.0+, iPadOS 16.0+, visionOS 1.0+
222
+
223
+ A multi-column data container that presents rows of `Identifiable` data with sortable, selectable columns. On compact size classes (iPhone, iPad Slide Over), columns after the first are automatically hidden.
224
+
225
+ ### Basic Table
226
+
227
+ ```swift
228
+ struct Person: Identifiable {
229
+ let givenName: String
230
+ let familyName: String
231
+ let emailAddress: String
232
+ let id = UUID()
233
+ var fullName: String { givenName + " " + familyName }
234
+ }
235
+
236
+ struct PeopleTable: View {
237
+ @State private var people: [Person] = [ /* ... */ ]
238
+
239
+ var body: some View {
240
+ Table(people) {
241
+ TableColumn("Given Name", value: \.givenName)
242
+ TableColumn("Family Name", value: \.familyName)
243
+ TableColumn("E-Mail Address", value: \.emailAddress)
244
+ }
245
+ }
246
+ }
247
+ ```
248
+
249
+ ### Table with Selection
250
+
251
+ Bind to a single `ID` for single-selection, or a `Set<ID>` for multi-selection:
252
+
253
+ ```swift
254
+ struct SelectableTable: View {
255
+ @State private var people: [Person] = [ /* ... */ ]
256
+ @State private var selectedPeople = Set<Person.ID>()
257
+
258
+ var body: some View {
259
+ Table(people, selection: $selectedPeople) {
260
+ TableColumn("Given Name", value: \.givenName)
261
+ TableColumn("Family Name", value: \.familyName)
262
+ TableColumn("E-Mail Address", value: \.emailAddress)
263
+ }
264
+ Text("\(selectedPeople.count) people selected")
265
+ }
266
+ }
267
+ ```
268
+
269
+ ### Sortable Table
270
+
271
+ Provide a binding to `[KeyPathComparator]` and re-sort the data in `.onChange(of:)`:
272
+
273
+ ```swift
274
+ struct SortableTable: View {
275
+ @State private var people: [Person] = [ /* ... */ ]
276
+ @State private var sortOrder = [KeyPathComparator(\Person.givenName)]
277
+
278
+ var body: some View {
279
+ Table(people, sortOrder: $sortOrder) {
280
+ TableColumn("Given Name", value: \.givenName)
281
+ TableColumn("Family Name", value: \.familyName)
282
+ TableColumn("E-Mail Address", value: \.emailAddress)
283
+ }
284
+ .onChange(of: sortOrder) { _, newOrder in
285
+ people.sort(using: newOrder)
286
+ }
287
+ }
288
+ }
289
+ ```
290
+
291
+ **Important:** The table does **not** sort data itself — you must re-sort the collection when `sortOrder` changes.
292
+
293
+ ### Adaptive Table for Compact Size Classes
294
+
295
+ On iPhone or iPad in Slide Over, only the first column is shown. Customize it to display combined information:
296
+
297
+ ```swift
298
+ struct AdaptiveTable: View {
299
+ @Environment(\.horizontalSizeClass) private var horizontalSizeClass
300
+ private var isCompact: Bool { horizontalSizeClass == .compact }
301
+
302
+ @State private var people: [Person] = [ /* ... */ ]
303
+ @State private var sortOrder = [KeyPathComparator(\Person.givenName)]
304
+
305
+ var body: some View {
306
+ Table(people, sortOrder: $sortOrder) {
307
+ TableColumn("Given Name", value: \.givenName) { person in
308
+ VStack(alignment: .leading) {
309
+ Text(isCompact ? person.fullName : person.givenName)
310
+ if isCompact {
311
+ Text(person.emailAddress)
312
+ .foregroundStyle(.secondary)
313
+ }
314
+ }
315
+ }
316
+ TableColumn("Family Name", value: \.familyName)
317
+ TableColumn("E-Mail Address", value: \.emailAddress)
318
+ }
319
+ .onChange(of: sortOrder) { _, newOrder in
320
+ people.sort(using: newOrder)
321
+ }
322
+ }
323
+ }
324
+ ```
325
+
326
+ ### Table with Static Rows
327
+
328
+ Use `init(of:columns:rows:)` when rows are known at compile time:
329
+
330
+ ```swift
331
+ struct Purchase: Identifiable {
332
+ let price: Decimal
333
+ let id = UUID()
334
+ }
335
+
336
+ struct TipTable: View {
337
+ let currencyStyle = Decimal.FormatStyle.Currency(code: "USD")
338
+
339
+ var body: some View {
340
+ Table(of: Purchase.self) {
341
+ TableColumn("Base price") { purchase in
342
+ Text(purchase.price, format: currencyStyle)
343
+ }
344
+ TableColumn("With 15% tip") { purchase in
345
+ Text(purchase.price * 1.15, format: currencyStyle)
346
+ }
347
+ TableColumn("With 20% tip") { purchase in
348
+ Text(purchase.price * 1.2, format: currencyStyle)
349
+ }
350
+ } rows: {
351
+ TableRow(Purchase(price: 20))
352
+ TableRow(Purchase(price: 50))
353
+ TableRow(Purchase(price: 75))
354
+ }
355
+ }
356
+ }
357
+ ```
358
+
359
+ ### Table with Dynamic Number of Columns
360
+
361
+ > **Availability:** iOS 17.4+, iPadOS 17.4+, Mac Catalyst 17.4+, macOS 14.4+, visionOS 1.1+
362
+
363
+ If the number of columns is not known at runtime use `TableColumnForEach` to create columns based on a `RandomAccessCollection` of some data type. Either the collection’s elements must conform to `Identifiable` or you need to provide an id parameter to the `TableColumnForEach` initializer.
364
+
365
+ This can be mixed with static compile time known `TableColumn` usage.
366
+
367
+ ```swift
368
+ struct AudioChannel: Identifiable {
369
+ let name: String
370
+ let id: UUID
371
+ }
372
+
373
+ struct AudioSample: Identifiable {
374
+ let id: UUID
375
+ let timestamp: TimeInterval
376
+ func level(channel: AudioChannel.ID) -> Double {
377
+ 1
378
+ }
379
+ }
380
+
381
+ @Observable
382
+ class AudioSampleTrack {
383
+ let channels: [AudioChannel]
384
+ var samples: [AudioSample]
385
+ }
386
+
387
+ struct ContentView: View {
388
+ var track: AudioSampleTrack
389
+
390
+ var body: some View {
391
+ Table(track.samples) {
392
+ TableColumn("Timestamp (ms)") { sample in
393
+ Text(sample.timestamp, format: .number.scale(1000))
394
+ .monospacedDigit()
395
+ }
396
+ TableColumnForEach(track.channels) { channel in
397
+ TableColumn(channel.name) { sample in
398
+ Text(sample.level(channel: channel.id),
399
+ format: .number.precision(.fractionLength(2))
400
+ )
401
+ .monospacedDigit()
402
+ }
403
+ .width(ideal: 70)
404
+ .alignment(.numeric)
405
+ }
406
+ }
407
+ }
408
+ }
409
+ ```
410
+
411
+ ### Table Styles
412
+
413
+ ```swift
414
+ // Inset (no borders)
415
+ Table(people) { /* columns */ }
416
+ .tableStyle(.inset)
417
+
418
+ // Hide column headers
419
+ Table(people) { /* columns */ }
420
+ .tableColumnHeaders(.hidden)
421
+ ```
422
+
423
+ ### Platform Behavior
424
+
425
+ | Platform | Behavior |
426
+ |----------|----------|
427
+ | **iPadOS (regular)** | Full multi-column layout; headers and all columns visible |
428
+ | **iPadOS (compact)** | Only the first column shown; headers hidden |
429
+ | **iPhone (all sizes)** | Only the first column shown; headers hidden; list-like appearance |
430
+
431
+ > **Best Practice:** Prefer handling the compact size class by showing combined info in the first column. This provides a seamless transition when the size class changes (e.g., entering/exiting Slide Over on iPad).
432
+
433
+ ## Summary Checklist
434
+
435
+ - [ ] ForEach uses stable identity (never `.indices` for dynamic content)
436
+ - [ ] Identifiable IDs are truly unique across all items
437
+ - [ ] Constant number of views per ForEach element
438
+ - [ ] No inline filtering in ForEach (prefilter and cache instead)
439
+ - [ ] No `AnyView` in list rows
440
+ - [ ] Don't convert enumerated sequences to arrays
441
+ - [ ] Use `.refreshable` for pull-to-refresh
442
+ - [ ] Use `ContentUnavailableView` for empty states (iOS 17+)
443
+ - [ ] Use `.scrollContentBackground(.hidden)` for custom list backgrounds
444
+ - [ ] `Table` adapts for compact size classes (first column shows combined info)
445
+ - [ ] `Table` sorting re-sorts data in `.onChange(of: sortOrder)` (table doesn't sort itself)
446
+ - [ ] `Table` data conforms to `Identifiable`