swift-code-reviewer-skill 1.2.0 → 1.3.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 (95) hide show
  1. package/CHANGELOG.md +43 -169
  2. package/README.md +43 -2
  3. package/SKILL.md +194 -711
  4. package/bin/install.js +1 -1
  5. package/package.json +2 -1
  6. package/references/agent-loop-feedback.md +148 -0
  7. package/references/companion-skills.md +70 -0
  8. package/references/spec-adherence.md +157 -0
  9. package/skills/README.md +43 -0
  10. package/skills/swift-concurrency/NOTICE.md +18 -0
  11. package/skills/swift-concurrency/SKILL.md +235 -0
  12. package/skills/swift-concurrency/references/actors.md +640 -0
  13. package/skills/swift-concurrency/references/async-await-basics.md +249 -0
  14. package/skills/swift-concurrency/references/async-sequences.md +635 -0
  15. package/skills/swift-concurrency/references/core-data.md +533 -0
  16. package/skills/swift-concurrency/references/glossary.md +96 -0
  17. package/skills/swift-concurrency/references/linting.md +38 -0
  18. package/skills/swift-concurrency/references/memory-management.md +542 -0
  19. package/skills/swift-concurrency/references/migration.md +721 -0
  20. package/skills/swift-concurrency/references/performance.md +574 -0
  21. package/skills/swift-concurrency/references/sendable.md +578 -0
  22. package/skills/swift-concurrency/references/tasks.md +604 -0
  23. package/skills/swift-concurrency/references/testing.md +565 -0
  24. package/skills/swift-concurrency/references/threading.md +452 -0
  25. package/skills/swift-expert/NOTICE.md +18 -0
  26. package/skills/swift-expert/SKILL.md +226 -0
  27. package/skills/swift-expert/references/async-concurrency.md +363 -0
  28. package/skills/swift-expert/references/memory-performance.md +380 -0
  29. package/skills/swift-expert/references/protocol-oriented.md +357 -0
  30. package/skills/swift-expert/references/swiftui-patterns.md +294 -0
  31. package/skills/swift-expert/references/testing-patterns.md +402 -0
  32. package/skills/swift-testing/NOTICE.md +18 -0
  33. package/skills/swift-testing/SKILL.md +295 -0
  34. package/skills/swift-testing/references/async-testing.md +245 -0
  35. package/skills/swift-testing/references/dump-snapshot-testing.md +265 -0
  36. package/skills/swift-testing/references/fixtures.md +193 -0
  37. package/skills/swift-testing/references/integration-testing.md +189 -0
  38. package/skills/swift-testing/references/migration-xctest.md +301 -0
  39. package/skills/swift-testing/references/parameterized-tests.md +171 -0
  40. package/skills/swift-testing/references/snapshot-testing.md +201 -0
  41. package/skills/swift-testing/references/test-doubles.md +243 -0
  42. package/skills/swift-testing/references/test-organization.md +231 -0
  43. package/skills/swiftui-expert-skill/NOTICE.md +18 -0
  44. package/skills/swiftui-expert-skill/SKILL.md +281 -0
  45. package/skills/swiftui-expert-skill/references/accessibility-patterns.md +151 -0
  46. package/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
  47. package/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  48. package/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  49. package/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
  50. package/skills/swiftui-expert-skill/references/charts.md +602 -0
  51. package/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
  52. package/skills/swiftui-expert-skill/references/latest-apis.md +464 -0
  53. package/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
  54. package/skills/swiftui-expert-skill/references/liquid-glass.md +414 -0
  55. package/skills/swiftui-expert-skill/references/list-patterns.md +394 -0
  56. package/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
  57. package/skills/swiftui-expert-skill/references/macos-views.md +357 -0
  58. package/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
  59. package/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
  60. package/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
  61. package/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
  62. package/skills/swiftui-expert-skill/references/state-management.md +417 -0
  63. package/skills/swiftui-expert-skill/references/view-structure.md +389 -0
  64. package/skills/swiftui-ui-patterns/NOTICE.md +18 -0
  65. package/skills/swiftui-ui-patterns/SKILL.md +95 -0
  66. package/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
  67. package/skills/swiftui-ui-patterns/references/async-state.md +96 -0
  68. package/skills/swiftui-ui-patterns/references/components-index.md +50 -0
  69. package/skills/swiftui-ui-patterns/references/controls.md +57 -0
  70. package/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
  71. package/skills/swiftui-ui-patterns/references/focus.md +90 -0
  72. package/skills/swiftui-ui-patterns/references/form.md +97 -0
  73. package/skills/swiftui-ui-patterns/references/grids.md +71 -0
  74. package/skills/swiftui-ui-patterns/references/haptics.md +71 -0
  75. package/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  76. package/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  77. package/skills/swiftui-ui-patterns/references/list.md +86 -0
  78. package/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  79. package/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
  80. package/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  81. package/skills/swiftui-ui-patterns/references/media.md +73 -0
  82. package/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
  83. package/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
  84. package/skills/swiftui-ui-patterns/references/overlay.md +45 -0
  85. package/skills/swiftui-ui-patterns/references/performance.md +62 -0
  86. package/skills/swiftui-ui-patterns/references/previews.md +48 -0
  87. package/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  88. package/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
  89. package/skills/swiftui-ui-patterns/references/searchable.md +71 -0
  90. package/skills/swiftui-ui-patterns/references/sheets.md +155 -0
  91. package/skills/swiftui-ui-patterns/references/split-views.md +72 -0
  92. package/skills/swiftui-ui-patterns/references/tabview.md +114 -0
  93. package/skills/swiftui-ui-patterns/references/theming.md +71 -0
  94. package/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
  95. package/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
@@ -0,0 +1,326 @@
1
+ # SwiftUI Transitions
2
+
3
+ Transitions for view insertion/removal, custom transitions, and the Animatable protocol.
4
+
5
+ ## Table of Contents
6
+ - [Property Animations vs Transitions](#property-animations-vs-transitions)
7
+ - [Basic Transitions](#basic-transitions)
8
+ - [Asymmetric Transitions](#asymmetric-transitions)
9
+ - [Custom Transitions](#custom-transitions)
10
+ - [Identity and Transitions](#identity-and-transitions)
11
+ - [The Animatable Protocol](#the-animatable-protocol)
12
+
13
+ ---
14
+
15
+ ## Property Animations vs Transitions
16
+
17
+ **Property animations**: Interpolate values on views that exist before AND after state change.
18
+
19
+ **Transitions**: Animate views being inserted or removed from the render tree.
20
+
21
+ ```swift
22
+ // Property animation - same view, different properties
23
+ Rectangle()
24
+ .frame(width: isExpanded ? 200 : 100, height: 50)
25
+ .animation(.spring, value: isExpanded)
26
+
27
+ // Transition - view inserted/removed
28
+ if showDetail {
29
+ DetailView()
30
+ .transition(.scale)
31
+ }
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Basic Transitions
37
+
38
+ ### Critical: Transitions Require Animation Context
39
+
40
+ ```swift
41
+ // GOOD - animation outside conditional
42
+ VStack {
43
+ Button("Toggle") { showDetail.toggle() }
44
+ if showDetail {
45
+ DetailView()
46
+ .transition(.slide)
47
+ }
48
+ }
49
+ .animation(.spring, value: showDetail)
50
+
51
+ // GOOD - explicit animation
52
+ Button("Toggle") {
53
+ withAnimation(.spring) {
54
+ showDetail.toggle()
55
+ }
56
+ }
57
+ if showDetail {
58
+ DetailView()
59
+ .transition(.scale.combined(with: .opacity))
60
+ }
61
+
62
+ // BAD - animation inside conditional (removed with view!)
63
+ if showDetail {
64
+ DetailView()
65
+ .transition(.slide)
66
+ .animation(.spring, value: showDetail) // Won't work on removal!
67
+ }
68
+
69
+ // BAD - no animation context
70
+ Button("Toggle") {
71
+ showDetail.toggle() // No animation
72
+ }
73
+ if showDetail {
74
+ DetailView()
75
+ .transition(.slide) // Ignored - just appears/disappears
76
+ }
77
+ ```
78
+
79
+ ### Built-in Transitions
80
+
81
+ | Transition | Effect |
82
+ |------------|--------|
83
+ | `.opacity` | Fade in/out (default) |
84
+ | `.scale` | Scale up/down |
85
+ | `.slide` | Slide from leading edge |
86
+ | `.move(edge:)` | Move from specific edge |
87
+ | `.offset(x:y:)` | Move by offset amount |
88
+
89
+ ### Combining Transitions
90
+
91
+ ```swift
92
+ // Parallel - both simultaneously
93
+ .transition(.slide.combined(with: .opacity))
94
+
95
+ // Chained
96
+ .transition(.scale.combined(with: .opacity).combined(with: .offset(y: 20)))
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Asymmetric Transitions
102
+
103
+ Different animations for insertion vs removal.
104
+
105
+ ```swift
106
+ // GOOD - different animations for insert/remove
107
+ if showCard {
108
+ CardView()
109
+ .transition(
110
+ .asymmetric(
111
+ insertion: .scale.combined(with: .opacity),
112
+ removal: .move(edge: .bottom).combined(with: .opacity)
113
+ )
114
+ )
115
+ }
116
+
117
+ // BAD - same transition when different behaviors needed
118
+ if showCard {
119
+ CardView()
120
+ .transition(.slide) // Same both ways - may feel awkward
121
+ }
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Custom Transitions
127
+
128
+ ### Pre-iOS 17
129
+
130
+ ```swift
131
+ struct BlurModifier: ViewModifier {
132
+ var radius: CGFloat
133
+ func body(content: Content) -> some View {
134
+ content.blur(radius: radius)
135
+ }
136
+ }
137
+
138
+ extension AnyTransition {
139
+ static func blur(radius: CGFloat) -> AnyTransition {
140
+ .modifier(
141
+ active: BlurModifier(radius: radius),
142
+ identity: BlurModifier(radius: 0)
143
+ )
144
+ }
145
+ }
146
+
147
+ // Usage
148
+ .transition(.blur(radius: 10))
149
+ ```
150
+
151
+ ### iOS 17+ (Transition Protocol)
152
+
153
+ ```swift
154
+ struct BlurTransition: Transition {
155
+ var radius: CGFloat
156
+
157
+ func body(content: Content, phase: TransitionPhase) -> some View {
158
+ content
159
+ .blur(radius: phase.isIdentity ? 0 : radius)
160
+ .opacity(phase.isIdentity ? 1 : 0)
161
+ }
162
+ }
163
+
164
+ // Usage
165
+ .transition(BlurTransition(radius: 10))
166
+ ```
167
+
168
+ ### Good vs Bad Custom Transitions
169
+
170
+ ```swift
171
+ // GOOD - reusable transition
172
+ if showContent {
173
+ ContentView()
174
+ .transition(BlurTransition(radius: 10))
175
+ }
176
+
177
+ // BAD - inline logic (won't animate on removal!)
178
+ if showContent {
179
+ ContentView()
180
+ .blur(radius: showContent ? 0 : 10) // Not a transition
181
+ .opacity(showContent ? 1 : 0)
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Identity and Transitions
188
+
189
+ View identity changes trigger transitions, not property animations.
190
+
191
+ ```swift
192
+ // Triggers transition - different branches have different identities
193
+ if isExpanded {
194
+ Rectangle().frame(width: 200, height: 50)
195
+ } else {
196
+ Rectangle().frame(width: 100, height: 50)
197
+ }
198
+
199
+ // Triggers transition - .id() changes identity
200
+ Rectangle()
201
+ .id(flag) // Different identity when flag changes
202
+ .transition(.scale)
203
+
204
+ // Property animation - same view, same identity
205
+ Rectangle()
206
+ .frame(width: isExpanded ? 200 : 100, height: 50)
207
+ .animation(.spring, value: isExpanded)
208
+ ```
209
+
210
+ ---
211
+
212
+ ## The Animatable Protocol
213
+
214
+ Enables custom property interpolation during animations.
215
+
216
+ ### Protocol Definition
217
+
218
+ ```swift
219
+ protocol Animatable {
220
+ associatedtype AnimatableData: VectorArithmetic
221
+ var animatableData: AnimatableData { get set }
222
+ }
223
+ ```
224
+
225
+ ### Basic Implementation
226
+
227
+ ```swift
228
+ // GOOD - explicit animatableData
229
+ struct ShakeModifier: ViewModifier, Animatable {
230
+ var shakeCount: Double
231
+
232
+ var animatableData: Double {
233
+ get { shakeCount }
234
+ set { shakeCount = newValue }
235
+ }
236
+
237
+ func body(content: Content) -> some View {
238
+ content.offset(x: sin(shakeCount * .pi * 2) * 10)
239
+ }
240
+ }
241
+
242
+ extension View {
243
+ func shake(count: Int) -> some View {
244
+ modifier(ShakeModifier(shakeCount: Double(count)))
245
+ }
246
+ }
247
+
248
+ // Usage
249
+ Button("Shake") { shakeCount += 3 }
250
+ .shake(count: shakeCount)
251
+ .animation(.default, value: shakeCount)
252
+
253
+ // BAD - missing animatableData (silent failure!)
254
+ struct BadShakeModifier: ViewModifier {
255
+ var shakeCount: Double
256
+ // Missing animatableData! Uses EmptyAnimatableData
257
+
258
+ func body(content: Content) -> some View {
259
+ content.offset(x: sin(shakeCount * .pi * 2) * 10)
260
+ }
261
+ }
262
+ // Animation jumps to final value instead of interpolating
263
+ ```
264
+
265
+ ### Multiple Properties with AnimatablePair
266
+
267
+ ```swift
268
+ // GOOD - AnimatablePair for two properties
269
+ struct ComplexModifier: ViewModifier, Animatable {
270
+ var scale: CGFloat
271
+ var rotation: Double
272
+
273
+ var animatableData: AnimatablePair<CGFloat, Double> {
274
+ get { AnimatablePair(scale, rotation) }
275
+ set {
276
+ scale = newValue.first
277
+ rotation = newValue.second
278
+ }
279
+ }
280
+
281
+ func body(content: Content) -> some View {
282
+ content
283
+ .scaleEffect(scale)
284
+ .rotationEffect(.degrees(rotation))
285
+ }
286
+ }
287
+
288
+ // GOOD - nested AnimatablePair for 3+ properties
289
+ struct ThreePropertyModifier: ViewModifier, Animatable {
290
+ var x: CGFloat
291
+ var y: CGFloat
292
+ var rotation: Double
293
+
294
+ var animatableData: AnimatablePair<AnimatablePair<CGFloat, CGFloat>, Double> {
295
+ get { AnimatablePair(AnimatablePair(x, y), rotation) }
296
+ set {
297
+ x = newValue.first.first
298
+ y = newValue.first.second
299
+ rotation = newValue.second
300
+ }
301
+ }
302
+
303
+ func body(content: Content) -> some View {
304
+ content
305
+ .offset(x: x, y: y)
306
+ .rotationEffect(.degrees(rotation))
307
+ }
308
+ }
309
+ ```
310
+
311
+ ---
312
+
313
+ ## Quick Reference
314
+
315
+ ### Do
316
+ - Place transitions outside conditional structures
317
+ - Use `withAnimation` or `.animation` outside the `if`
318
+ - Implement `animatableData` explicitly for custom Animatable
319
+ - Use `AnimatablePair` for multiple animated properties
320
+ - Use asymmetric transitions when insert/remove need different effects
321
+
322
+ ### Don't
323
+ - Put animation modifiers inside conditionals for transitions
324
+ - Forget `animatableData` implementation (silent failure)
325
+ - Use inline blur/opacity instead of proper transitions
326
+ - Expect property animation when view identity changes
@@ -0,0 +1,135 @@
1
+ # Swift Charts Accessibility, Fallback, and Resources
2
+
3
+ ## Table of Contents
4
+
5
+ - [Accessibility](#accessibility)
6
+ - [Meaningful Labels](#meaningful-labels)
7
+ - [Custom Audio Graphs](#custom-audio-graphs)
8
+ - [Composite Example](#composite-example)
9
+ - [Fallback Strategies](#fallback-strategies)
10
+ - [Version Breakdown](#version-breakdown)
11
+ - [WWDC Sessions](#wwdc-sessions)
12
+ - [Summary Checklist](#summary-checklist)
13
+
14
+ ---
15
+
16
+ ## Accessibility
17
+
18
+ Swift Charts provides built-in accessibility support. VoiceOver users get three rotor actions automatically:
19
+
20
+ - **Describe Chart** — overview of axes and data series
21
+ - **Audio Graph** — sonification where pitch represents data values
22
+ - **Chart Detail** — interactive mode for exploring individual data points
23
+
24
+ ### Meaningful Labels
25
+
26
+ **Always** use clear, descriptive strings in `.value(_, _)` calls. These labels are read by VoiceOver and used in the Audio Graph.
27
+
28
+ ```swift
29
+ // Good — descriptive labels
30
+ LineMark(
31
+ x: .value("Date", entry.date),
32
+ y: .value("Daily Steps", entry.count)
33
+ )
34
+
35
+ // Bad — generic labels
36
+ LineMark(
37
+ x: .value("X", entry.date),
38
+ y: .value("Y", entry.count)
39
+ )
40
+ ```
41
+
42
+ ### Custom Audio Graphs
43
+
44
+ For advanced accessibility, conform your chart view to `AXChartDescriptorRepresentable` and implement `makeChartDescriptor()`. Attach it with `.accessibilityChartDescriptor(self)`.
45
+
46
+ ```swift
47
+ struct StepsChart: View, AXChartDescriptorRepresentable {
48
+ let steps: [DailySteps]
49
+
50
+ var body: some View {
51
+ Chart(steps) { day in
52
+ LineMark(x: .value("Date", day.date), y: .value("Steps", day.count))
53
+ }
54
+ .accessibilityChartDescriptor(self)
55
+ }
56
+
57
+ func makeChartDescriptor() -> AXChartDescriptor {
58
+ guard let first = steps.first, let last = steps.last else {
59
+ return AXChartDescriptor(title: "Daily Step Count", summary: nil,
60
+ xAxis: AXNumericDataAxisDescriptor(title: "Date", range: 0...1, gridlinePositions: []) { "\($0)" },
61
+ yAxis: AXNumericDataAxisDescriptor(title: "Steps", range: 0...1, gridlinePositions: []) { "\($0)" },
62
+ additionalAxes: [], series: [])
63
+ }
64
+ let xAxis = AXDateDataAxisDescriptor(
65
+ title: "Date", range: first.date...last.date, gridlinePositions: [])
66
+ let yAxis = AXNumericDataAxisDescriptor(
67
+ title: "Steps", range: 0...Double(steps.map(\.count).max() ?? 0),
68
+ gridlinePositions: []) { "\(Int($0)) steps" }
69
+ let series = AXDataSeriesDescriptor(
70
+ name: "Daily Steps", isContinuous: true,
71
+ dataPoints: steps.map { .init(x: $0.date, y: Double($0.count)) })
72
+ return AXChartDescriptor(title: "Daily Step Count", summary: nil,
73
+ xAxis: xAxis, yAxis: yAxis, additionalAxes: [], series: [series])
74
+ }
75
+ }
76
+ ```
77
+
78
+ ## Composite Example
79
+
80
+ A scrollable bar chart with range selection combining multiple iOS 17+ APIs:
81
+
82
+ ```swift
83
+ @State private var selectedRange: ClosedRange<Int>?
84
+
85
+ Chart(weeklyRevenue) { week in
86
+ BarMark(x: .value("Week", week.index), y: .value("Revenue", week.revenue))
87
+ .foregroundStyle(by: .value("Region", week.region))
88
+ }
89
+ .chartScrollableAxes(.horizontal)
90
+ .chartXVisibleDomain(length: 8)
91
+ .chartXSelection(range: $selectedRange)
92
+ .chartXAxis {
93
+ AxisMarks(values: .stride(by: 1)) {
94
+ AxisGridLine()
95
+ AxisValueLabel { Text("W\($0.as(Int.self) ?? 0)") }
96
+ }
97
+ }
98
+ ```
99
+
100
+ ## Fallback Strategies
101
+
102
+ Gate advanced APIs with `#available` and provide a fallback chart without the gated features. Because chart modifiers like `.chartXSelection` change the return type, you must duplicate the entire `Chart` — you cannot conditionally apply the modifier:
103
+
104
+ ### Version Breakdown
105
+
106
+ - iOS 16+: `Chart`, custom axes, scales, `BarMark`, `LineMark`, `AreaMark`, `PointMark`, `RectangleMark`, `RuleMark`, `ChartProxy`, `chartOverlay`, `chartBackground`
107
+ - iOS 17+: `SectorMark`, `chartXSelection`, `chartYSelection`, `chartAngleSelection`, `chartScrollableAxes`, visible-domain scrolling APIs, `chartGesture`
108
+ - iOS 18+: `AreaPlot`, `BarPlot`, `LinePlot`, `PointPlot`, `RectanglePlot`, `RulePlot`, `SectorPlot`, function plotting
109
+ - iOS 26+: `Chart3D`, `SurfacePlot`, Z-axis marks, 3D camera and pose APIs
110
+
111
+ ## WWDC Sessions
112
+
113
+ - [Hello Swift Charts](https://developer.apple.com/videos/play/wwdc2022/10136/) (WWDC 2022) — introduction to the framework
114
+ - [Swift Charts: Raise the bar](https://developer.apple.com/videos/play/wwdc2022/10137/) (WWDC 2022) — marks, composition, customization
115
+ - [Design an effective chart](https://developer.apple.com/videos/play/wwdc2022/110340/) (WWDC 2022) — chart design principles
116
+ - [Design app experiences with charts](https://developer.apple.com/videos/play/wwdc2022/110342/) (WWDC 2022) — integrating charts into app UX
117
+ - [Explore pie charts and interactivity in Swift Charts](https://developer.apple.com/videos/play/wwdc2023/10037/) (WWDC 2023) — SectorMark, selection, scrolling
118
+ - [Swift Charts: Vectorized and function plots](https://developer.apple.com/videos/play/wwdc2024/10155/) (WWDC 2024) — LinePlot, AreaPlot, function plotting
119
+ - [Bring Swift Charts to the third dimension](https://developer.apple.com/videos/play/wwdc2025/313/) (WWDC 2025) — Chart3D, SurfacePlot, 3D marks
120
+
121
+ ## Summary Checklist
122
+
123
+ - [ ] `import Charts` is present in files using chart types
124
+ - [ ] Deployment target matches the APIs used (`Chart` on iOS 16+, selection and `SectorMark` on iOS 17+, plot types on iOS 18+, `Chart3D` on iOS 26+)
125
+ - [ ] Chart data models use `Identifiable` (or `Chart(data, id:)` is provided)
126
+ - [ ] All chart families are represented with the correct mark type
127
+ - [ ] Axes use `AxisMarks` when default ticks are too dense or unclear
128
+ - [ ] `chartXScale` or `chartYScale` is set when fixed domains matter
129
+ - [ ] Chart-wide modifiers are applied to `Chart`, not individual marks
130
+ - [ ] `foregroundStyle(by:)` used for categorical series (not manual per-mark colors)
131
+ - [ ] Single-value selection uses `chartXSelection(value:)` or `chartYSelection(value:)`
132
+ - [ ] Range selection uses `chartXSelection(range:)` or `chartYSelection(range:)`
133
+ - [ ] `SectorMark` selection uses `chartAngleSelection(value:)`
134
+ - [ ] iOS 17+, iOS 18+, and iOS 26+ APIs are guarded with `#available`
135
+ - [ ] `.value()` labels are descriptive for VoiceOver and Audio Graph accessibility