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,602 @@
1
+ # SwiftUI Charts Reference
2
+
3
+ ## Table of Contents
4
+
5
+ - [Overview](#overview)
6
+ - [Availability](#availability)
7
+ - [Core APIs](#core-apis)
8
+ - [Chart Types](#chart-types)
9
+ - [Axis Tweaks](#axis-tweaks)
10
+ - [Selection APIs](#selection-apis)
11
+ - [Annotations](#annotations)
12
+ - [ChartProxy and Custom Touch Handling](#chartproxy-and-custom-touch-handling)
13
+ - [Modifier Scope](#modifier-scope)
14
+ - [Styling and Visual Channels](#styling-and-visual-channels)
15
+ - [Composing Multiple Marks](#composing-multiple-marks)
16
+ - [Animating Chart Data](#animating-chart-data)
17
+ - [Best Practices](#best-practices)
18
+
19
+ ## Overview
20
+
21
+ Swift Charts is Apple's native charting framework for SwiftUI. Use `Chart` with one or more marks to build bar, line, area, point, rule, rectangle, and sector charts. This reference covers the standard 2D chart APIs, axis customization, built-in selection APIs, annotations, and custom touch handling.
22
+
23
+ ## Availability
24
+
25
+ Base `Chart`, custom axes, scales, and most marks require iOS 16 or later.
26
+
27
+ - `BarMark`, `LineMark`, `AreaMark`, `PointMark`, `RectangleMark`, and `RuleMark` are available on iOS 16+
28
+ - `SectorMark`, built-in selection, and scrollable chart axes require iOS 17+
29
+ - Data-driven plot types such as `BarPlot` and `LinePlot` require iOS 18+
30
+ - Chart3D and Z-axis APIs exist on iOS 26+; this reference is primarily about 2D `Chart`, with a dedicated Chart3D section below
31
+
32
+ ```swift
33
+ if #available(iOS 17, *) {
34
+ // Selection, SectorMark, scrollable axes
35
+ } else {
36
+ // Base Chart, axes, scales, and core marks
37
+ }
38
+ ```
39
+
40
+ ## Core APIs
41
+
42
+ ### Import the Framework
43
+
44
+ Always check that the file imports `Charts` before using `Chart`, `Chart3D`, `BarMark`, `SectorMark`, or `ChartProxy`.
45
+
46
+ ```swift
47
+ import SwiftUI
48
+ import Charts
49
+ ```
50
+
51
+ If chart types are unresolved, the first thing to verify is that `Charts` is imported in that file.
52
+
53
+ ### Chart Container
54
+
55
+ `Chart` is the root view. Add one or more marks inside it.
56
+
57
+ ```swift
58
+ Chart(sales) { item in
59
+ BarMark(
60
+ x: .value("Month", item.month),
61
+ y: .value("Revenue", item.revenue)
62
+ )
63
+ }
64
+ ```
65
+
66
+ ### Data Models Should Be Identifiable
67
+
68
+ Prefer `Identifiable` models for chart data so identity stays stable as data changes.
69
+
70
+ ```swift
71
+ struct SalesPoint: Identifiable {
72
+ let id: UUID
73
+ let month: String
74
+ let revenue: Double
75
+ }
76
+ ```
77
+
78
+ If your model cannot conform to `Identifiable`, provide an explicit id key path:
79
+
80
+ ```swift
81
+ Chart(sales, id: \.month) { item in
82
+ BarMark(
83
+ x: .value("Month", item.month),
84
+ y: .value("Revenue", item.revenue)
85
+ )
86
+ }
87
+ ```
88
+
89
+ ### Plottable Values
90
+
91
+ Use `.value(_, _)` to describe what each axis value means. Those labels are reused by axes, legends, and accessibility.
92
+
93
+ ```swift
94
+ LineMark(
95
+ x: .value("Day", entry.date),
96
+ y: .value("Steps", entry.count)
97
+ )
98
+ ```
99
+
100
+ ## Chart Types
101
+
102
+ ### BarMark
103
+
104
+ ```swift
105
+ BarMark(
106
+ x: .value("Product", product.name),
107
+ y: .value("Units", product.units)
108
+ )
109
+ ```
110
+
111
+ Stacking via `MarkStackingMethod`: `.standard`, `.normalized`, `.center`, `.unstacked`.
112
+
113
+ ### LineMark
114
+
115
+ ```swift
116
+ LineMark(
117
+ x: .value("Day", day.date),
118
+ y: .value("Steps", day.count)
119
+ )
120
+ .interpolationMethod(.monotone)
121
+ ```
122
+
123
+ Interpolation methods: `.linear`, `.monotone`, `.cardinal`, `.catmullRom`, `.stepStart`, `.stepCenter`, `.stepEnd`. Cardinal and Catmull-Rom accept optional tension/alpha parameters.
124
+
125
+ ### AreaMark
126
+
127
+ ```swift
128
+ AreaMark(
129
+ x: .value("Hour", sample.hour),
130
+ y: .value("Temperature", sample.value),
131
+ stacking: .unstacked
132
+ )
133
+ ```
134
+
135
+ Ranged areas use `yStart`/`yEnd` for bands like min/max or confidence intervals:
136
+
137
+ ```swift
138
+ AreaMark(
139
+ x: .value("Day", sample.day),
140
+ yStart: .value("Low", sample.low),
141
+ yEnd: .value("High", sample.high)
142
+ )
143
+ ```
144
+
145
+ ### PointMark
146
+
147
+ ```swift
148
+ PointMark(
149
+ x: .value("Time", measurement.time),
150
+ y: .value("Value", measurement.value)
151
+ )
152
+ ```
153
+
154
+ ### RectangleMark
155
+
156
+ ```swift
157
+ RectangleMark(
158
+ xStart: .value("Start Day", cell.startDay),
159
+ xEnd: .value("End Day", cell.endDay),
160
+ yStart: .value("Low", cell.low),
161
+ yEnd: .value("High", cell.high)
162
+ )
163
+ ```
164
+
165
+ ### RuleMark
166
+
167
+ ```swift
168
+ RuleMark(y: .value("Goal", 10_000))
169
+ .foregroundStyle(.red)
170
+ ```
171
+
172
+ ### SectorMark
173
+
174
+ Use `SectorMark` for pie and donut-style charts. `SectorMark` requires iOS 17 or later.
175
+
176
+ ```swift
177
+ Chart(expenses) { expense in
178
+ SectorMark(
179
+ angle: .value("Amount", expense.amount),
180
+ innerRadius: .ratio(0.6),
181
+ angularInset: 2
182
+ )
183
+ .foregroundStyle(by: .value("Category", expense.category))
184
+ }
185
+ ```
186
+
187
+ Use `innerRadius` to turn a pie chart into a donut chart, and `angularInset` to separate slices visually.
188
+
189
+ ### Plot Types (iOS 18+)
190
+
191
+ iOS 18 adds data-driven plot wrappers: `AreaPlot`, `BarPlot`, `LinePlot`, `PointPlot`, `RectanglePlot`, `RulePlot`, and `SectorPlot`.
192
+
193
+ `LinePlot` and `AreaPlot` also accept function closures for plotting mathematical functions without discrete data:
194
+
195
+ ```swift
196
+ if #available(iOS 18, *) {
197
+ Chart {
198
+ LinePlot(x: "x", y: "sin(x)") { x in
199
+ sin(x)
200
+ }
201
+ }
202
+ .chartXScale(domain: -Double.pi ... Double.pi)
203
+ .chartYScale(domain: -1.5 ... 1.5)
204
+ }
205
+ ```
206
+
207
+ Use plot types when you want a data-first API surface or need function plotting. The underlying chart families stay the same.
208
+
209
+ ### Chart3D (iOS 26+)
210
+
211
+ `Chart3D` is a separate API for 3D chart content. It supports 3D `PointMark`, `RectangleMark`, `RuleMark`, and `SurfacePlot`.
212
+
213
+ ```swift
214
+ if #available(iOS 26, *) {
215
+ Chart3D(points) { point in
216
+ PointMark(
217
+ x: .value("X", point.x),
218
+ y: .value("Y", point.y),
219
+ z: .value("Z", point.z)
220
+ )
221
+ }
222
+ .chart3DPose(.front)
223
+ .chart3DCameraProjection(.perspective)
224
+ }
225
+ ```
226
+
227
+ `SurfacePlot` visualizes mathematical surfaces by evaluating a two-variable function:
228
+
229
+ ```swift
230
+ if #available(iOS 26, *) {
231
+ Chart3D {
232
+ SurfacePlot(x: "x", y: "height", z: "z") { x, z in
233
+ sin(x) * cos(z)
234
+ }
235
+ }
236
+ .chartXScale(domain: -Double.pi ... Double.pi)
237
+ .chartZScale(domain: -Double.pi ... Double.pi)
238
+ }
239
+ ```
240
+
241
+ Camera and pose configuration:
242
+
243
+ - **Projection**: `.chart3DCameraProjection(.orthographic)` (default, precise measurements) or `.perspective` (depth effect)
244
+ - **Pose presets**: `.chart3DPose(.default)`, `.front`, `.back`, `.left`, `.right`
245
+ - **Custom pose**: `.chart3DPose(azimuth: .degrees(45), inclination: .degrees(30))`
246
+ - On visionOS, Chart3D supports natural 3D interaction gestures for rotation and exploration
247
+
248
+ **Always** gate `Chart3D` with `#available(iOS 26, *)` — it is not available on earlier OS versions.
249
+
250
+ ## Axis Tweaks
251
+
252
+ ### Axis Visibility and Labels
253
+
254
+ Use `chartXAxis`, `chartYAxis`, `chartXAxisLabel`, and `chartYAxisLabel` on the `Chart` container.
255
+ Axis visibility supports `.automatic`, `.visible`, and `.hidden`.
256
+
257
+ ```swift
258
+ Chart(data) { item in
259
+ BarMark(
260
+ x: .value("Month", item.month),
261
+ y: .value("Revenue", item.revenue)
262
+ )
263
+ }
264
+ .chartXAxis(.visible)
265
+ .chartYAxis(.hidden)
266
+ .chartXAxisLabel("Month")
267
+ .chartYAxisLabel("Revenue")
268
+ ```
269
+
270
+ ### Custom Axis Marks
271
+
272
+ Use `AxisMarks` to control tick placement, labels, and grid lines.
273
+
274
+ ```swift
275
+ Chart(steps) { day in
276
+ LineMark(
277
+ x: .value("Day", day.date),
278
+ y: .value("Steps", day.count)
279
+ )
280
+ }
281
+ .chartXAxis {
282
+ AxisMarks(
283
+ preset: .aligned,
284
+ position: .bottom,
285
+ values: .stride(by: .day)
286
+ ) {
287
+ AxisGridLine()
288
+ AxisTick(length: .label)
289
+ AxisValueLabel(format: .dateTime.weekday(.abbreviated))
290
+ }
291
+ }
292
+ ```
293
+
294
+ Useful `AxisMarks` inputs:
295
+
296
+ - `preset`: `.automatic`, `.extended`, `.aligned`, `.inset`
297
+ - `position`: `.automatic`, `.leading`, `.trailing`, `.top`, `.bottom`
298
+ - `values`: `.automatic`, `.automatic(desiredCount:)`, `.stride(by:)`, `.stride(by:count:)`, or an explicit array
299
+
300
+ ### Axis Components
301
+
302
+ Within `AxisMarks`, combine the built-in axis components as needed:
303
+
304
+ ```swift
305
+ AxisGridLine()
306
+ AxisTick()
307
+ AxisValueLabel()
308
+ ```
309
+
310
+ `AxisValueLabel` can be tuned for dense axes:
311
+
312
+ ```swift
313
+ AxisValueLabel(
314
+ collisionResolution: .greedy(minimumSpacing: 8),
315
+ orientation: .vertical
316
+ )
317
+ ```
318
+
319
+ Label orientations: `.automatic`, `.horizontal`, `.vertical`, `.verticalReversed`.
320
+
321
+ Collision strategies: `.automatic`, `.greedy`, `.greedy(priority:minimumSpacing:)`, `.truncate`, `.disabled`.
322
+
323
+ ### Axis Domains and Plot Area Tweaks
324
+
325
+ Use scales when you need explicit axis domains or plot area control.
326
+
327
+ ```swift
328
+ Chart(data) { item in
329
+ LineMark(
330
+ x: .value("Index", item.index),
331
+ y: .value("Score", item.score)
332
+ )
333
+ }
334
+ .chartXScale(domain: 0...30)
335
+ .chartYScale(domain: 0...100)
336
+ .chartPlotStyle { plotArea in
337
+ plotArea
338
+ .background(.gray.opacity(0.08))
339
+ }
340
+ ```
341
+
342
+ You can set one axis domain without forcing the other:
343
+
344
+ ```swift
345
+ .chartXScale(domain: startDate...endDate)
346
+ ```
347
+
348
+ ### Scrollable Axes (iOS 17+)
349
+
350
+ For larger datasets, make the plot area scroll and control the visible domain.
351
+
352
+ ```swift
353
+ @State private var scrollX = 7
354
+
355
+ Chart(data) { item in
356
+ BarMark(
357
+ x: .value("Day", item.day),
358
+ y: .value("Value", item.value)
359
+ )
360
+ }
361
+ .chartScrollableAxes(.horizontal)
362
+ .chartXVisibleDomain(length: 7)
363
+ .chartScrollPosition(x: $scrollX)
364
+ ```
365
+
366
+ ## Selection APIs
367
+
368
+ ### Single-Value Selection
369
+
370
+ Use `chartXSelection(value:)` or `chartYSelection(value:)` for one selected value.
371
+
372
+ ```swift
373
+ @State private var selectedDate: Date?
374
+
375
+ Chart(steps) { day in
376
+ LineMark(x: .value("Day", day.date), y: .value("Steps", day.count))
377
+
378
+ if let selectedDate {
379
+ RuleMark(x: .value("Selected Day", selectedDate))
380
+ .foregroundStyle(.secondary)
381
+ }
382
+ }
383
+ .chartXSelection(value: $selectedDate)
384
+ ```
385
+
386
+ ### Range Selection
387
+
388
+ Use `chartXSelection(range:)` or `chartYSelection(range:)` for a dragged range. Bind to a `ClosedRange` whose bound type matches the plotted axis value.
389
+
390
+ ```swift
391
+ @State private var selectedWeeks: ClosedRange<Int>?
392
+
393
+ Chart(weeks) { week in
394
+ BarMark(x: .value("Week", week.index), y: .value("Revenue", week.revenue))
395
+ }
396
+ .chartXSelection(range: $selectedWeeks)
397
+ ```
398
+
399
+ ### Choosing Single vs Range
400
+
401
+ - Use `value:` bindings when only one point or axis value should be selected.
402
+ - Use `range:` bindings when users should brush a span (for zoom windows, comparisons, or grouped summaries).
403
+
404
+ ### Angle Selection
405
+
406
+ Use `chartAngleSelection(value:)` with `SectorMark` charts. No built-in range overload for angle selection.
407
+
408
+ ```swift
409
+ @State private var selectedAmount: Double?
410
+
411
+ Chart(expenses) { expense in
412
+ SectorMark(angle: .value("Amount", expense.amount))
413
+ .foregroundStyle(by: .value("Category", expense.category))
414
+ }
415
+ .chartAngleSelection(value: $selectedAmount)
416
+ ```
417
+
418
+ **Important**: Selection bindings return the plottable axis value, not the full data element. Map back to your model if you need the selected record.
419
+
420
+ ## Annotations
421
+
422
+ Use `annotation(position:)` on a mark when you need labels, callouts, or highlighted values attached to the plotted content.
423
+
424
+ ```swift
425
+ BarMark(
426
+ x: .value("Month", item.month),
427
+ y: .value("Revenue", item.revenue)
428
+ )
429
+ .annotation(position: .top) {
430
+ Text(item.revenue.formatted())
431
+ }
432
+ ```
433
+
434
+ This is useful for selected values, thresholds, summaries, and direct labeling. Common positions include `.overlay`, `.top`, `.bottom`, `.leading`, and `.trailing`.
435
+
436
+ ## ChartProxy and Custom Touch Handling
437
+
438
+ Use `chartOverlay`/`chartBackground` (iOS 16+) or `chartGesture` (iOS 17+) with `ChartProxy` when built-in selection modifiers are not enough.
439
+
440
+ ```swift
441
+ .chartOverlay { proxy in
442
+ GeometryReader { geometry in
443
+ Rectangle().fill(.clear).contentShape(Rectangle())
444
+ .gesture(
445
+ DragGesture(minimumDistance: 0)
446
+ .onChanged { value in
447
+ guard let plotFrame = proxy.plotFrame else { return } // iOS 16: use proxy.plotAreaFrame
448
+ let frame = geometry[plotFrame]
449
+ let x = value.location.x - frame.origin.x
450
+ guard x >= 0, x <= frame.size.width else { return }
451
+ selectedDate = proxy.value(atX: x, as: Date.self)
452
+ }
453
+ .onEnded { _ in selectedDate = nil }
454
+ )
455
+ }
456
+ }
457
+ ```
458
+
459
+ Use `proxy.plotFrame` (iOS 17+) or `proxy.plotAreaFrame` (iOS 16) to get the plot area anchor.
460
+
461
+ `ChartProxy` gives you lower-level access to:
462
+
463
+ - `value(atX:as:)`, `value(atY:as:)`, and `value(at:as:)` for converting gesture coordinates into chart values
464
+ - `position(forX:)`, `position(forY:)`, and `position(for:)` for placing custom overlays or indicators
465
+ - `selectXValue(at:)`, `selectYValue(at:)`, `selectXRange(from:to:)`, and `selectYRange(from:to:)` for driving built-in selection from custom gestures
466
+ - `plotFrame` (iOS 17+) or `plotAreaFrame` (iOS 16) with `plotSize` for converting between gesture coordinates and the plot area
467
+
468
+ `select*` ChartProxy selection methods and `chartGesture` are available on iOS 17+.
469
+
470
+ ## Modifier Scope
471
+
472
+ Apply chart-wide modifiers to the `Chart` container and mark-specific modifiers to the individual mark.
473
+
474
+ ```swift
475
+ Chart(data) { item in
476
+ LineMark(
477
+ x: .value("Day", item.date),
478
+ y: .value("Value", item.value)
479
+ )
480
+ .interpolationMethod(.monotone) // Mark-level modifier
481
+ }
482
+ .chartXAxis { AxisMarks() } // Chart-level modifier
483
+ .chartYScale(domain: 0...100) // Chart-level modifier
484
+ .chartPlotStyle { $0.background(.thinMaterial) }
485
+ ```
486
+
487
+ ## Styling and Visual Channels
488
+
489
+ ### Categorical Coloring
490
+
491
+ Use `foregroundStyle(by: .value(...))` to color marks by a data property. Swift Charts generates a legend automatically.
492
+
493
+ ```swift
494
+ Chart(sales) { item in
495
+ BarMark(
496
+ x: .value("Month", item.month),
497
+ y: .value("Revenue", item.revenue)
498
+ )
499
+ .foregroundStyle(by: .value("Region", item.region))
500
+ }
501
+ ```
502
+
503
+ **Avoid** applying `.foregroundStyle(.red)` per mark for categorical data — this suppresses the automatic legend and breaks accessibility.
504
+
505
+ ### Custom Color Scales
506
+
507
+ Use `chartForegroundStyleScale` to control the mapping from data values to colors.
508
+
509
+ ```swift
510
+ .chartForegroundStyleScale([
511
+ "North": .blue,
512
+ "South": .orange,
513
+ "East": .green
514
+ ])
515
+ ```
516
+
517
+ For dynamic data where not all series appear at every point, use the mapping overload:
518
+
519
+ ```swift
520
+ .chartForegroundStyleScale(domain: regions, mapping: { region in
521
+ colorForRegion(region)
522
+ })
523
+ ```
524
+
525
+ ### Symbol and Size Channels
526
+
527
+ Use `symbol(by:)` and `symbolSize(by:)` to encode additional data dimensions on `PointMark` and `LineMark`.
528
+
529
+ ```swift
530
+ Chart(measurements) { item in
531
+ PointMark(
532
+ x: .value("Time", item.time),
533
+ y: .value("Value", item.value)
534
+ )
535
+ .foregroundStyle(by: .value("Category", item.category))
536
+ .symbol(by: .value("Category", item.category))
537
+ .symbolSize(by: .value("Weight", item.weight))
538
+ }
539
+ ```
540
+
541
+ ### Legend Control
542
+
543
+ ```swift
544
+ .chartLegend(.visible)
545
+ .chartLegend(.hidden)
546
+ .chartLegend(position: .bottom, alignment: .center)
547
+ ```
548
+
549
+ ## Composing Multiple Marks
550
+
551
+ Combine different mark types inside the same `Chart` closure:
552
+
553
+ ```swift
554
+ // Line with points
555
+ LineMark(x: .value("Day", day.date), y: .value("Steps", day.count))
556
+ .interpolationMethod(.monotone)
557
+ PointMark(x: .value("Day", day.date), y: .value("Steps", day.count))
558
+
559
+ // Bars with threshold line
560
+ BarMark(x: .value("Month", item.month), y: .value("Revenue", item.revenue))
561
+ RuleMark(y: .value("Target", 10_000))
562
+ .foregroundStyle(.red)
563
+ .lineStyle(StrokeStyle(dash: [5, 3]))
564
+ ```
565
+
566
+ ## Animating Chart Data
567
+
568
+ Chart marks animate automatically when data identity is stable and changes are wrapped in an animation.
569
+
570
+ ```swift
571
+ withAnimation(.easeInOut) {
572
+ chartData = updatedData
573
+ }
574
+ ```
575
+
576
+ **Always** use `Identifiable` models (or explicit `id:`) so Swift Charts can match old and new data points and animate transitions between them.
577
+
578
+ ## Best Practices
579
+
580
+ ### Do
581
+
582
+ - Use semantic `.value(_, _)` labels so axes and accessibility read clearly
583
+ - Prefer `Identifiable` models (or explicit `id:`) for stable chart data identity
584
+ - Use `foregroundStyle(by:)` for categorical series to get automatic legends and accessibility
585
+ - Use `RuleMark` for goals, thresholds, and selected-value indicators
586
+ - Use explicit `AxisMarks(values:)` when automatic tick generation gets crowded
587
+ - Use `chartXScale` and `chartYScale` when you need stable visual comparisons
588
+ - Use `chartXSelection(range:)` or `chartYSelection(range:)` for brushed selection
589
+ - Gate iOS 17+ APIs such as `SectorMark` and selection with `#available`
590
+
591
+ ### Don't
592
+
593
+ - Put chart-wide modifiers such as `chartXAxis` or `chartXSelection` on individual marks
594
+ - Apply manual `.foregroundStyle(.color)` per mark for categorical data — use `foregroundStyle(by:)` instead
595
+ - Rely on unstable identities when chart data can be inserted, removed, or reordered
596
+ - Use string values for naturally numeric or date-based axes unless you want categorical behavior
597
+ - Stack unrelated series by default just because `BarMark` and `AreaMark` allow it
598
+ - Force every tick label to display when collision handling or stride values would be clearer
599
+ - Assume selection returns a model object; it only returns the plottable axis value
600
+ - Forget that range selection is available only for X and Y axes, not angle selection
601
+
602
+ For chart accessibility (VoiceOver, Audio Graph, `AXChartDescriptorRepresentable`), fallback strategies, WWDC sessions, and a full summary checklist, see `charts-accessibility.md`.