@antadesign/anta 0.3.33 → 0.3.35

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 (205) hide show
  1. package/LICENSE.md +14 -1
  2. package/README.md +9 -0
  3. package/dist/anta_helpers.d.ts +46 -30
  4. package/dist/anta_helpers.js +66 -25
  5. package/dist/bundle.css +1 -1
  6. package/dist/bundle.js +2 -1353
  7. package/dist/components/Banner.d.ts +25 -40
  8. package/dist/components/Banner.js +15 -17
  9. package/dist/components/Breadcrumbs.d.ts +0 -1
  10. package/dist/components/Breadcrumbs.js +0 -1
  11. package/dist/components/Button.d.ts +2 -3
  12. package/dist/components/Button.js +1 -0
  13. package/dist/components/ButtonCopy.js +3 -2
  14. package/dist/components/Calendar.js +13 -13
  15. package/dist/components/Card.d.ts +9 -17
  16. package/dist/components/Card.js +50 -46
  17. package/dist/components/Dialog.d.ts +1 -0
  18. package/dist/components/Dialog.js +16 -10
  19. package/dist/components/Expander.d.ts +6 -21
  20. package/dist/components/Expander.js +24 -23
  21. package/dist/components/Icon.d.ts +8 -14
  22. package/dist/components/Input.d.ts +77 -96
  23. package/dist/components/Input.js +23 -27
  24. package/dist/components/InputAutocomplete.d.ts +29 -10
  25. package/dist/components/InputAutocomplete.js +25 -8
  26. package/dist/components/InputDate.d.ts +0 -1
  27. package/dist/components/InputDate.js +2 -3
  28. package/dist/components/InputTime.d.ts +10 -4
  29. package/dist/components/InputTime.js +20 -16
  30. package/dist/components/Loader.d.ts +2 -2
  31. package/dist/components/Menu.d.ts +5 -4
  32. package/dist/components/Menu.js +13 -8
  33. package/dist/components/MenuItem.js +1 -14
  34. package/dist/components/MenuItemCopy.js +2 -2
  35. package/dist/components/Panel.d.ts +3 -1
  36. package/dist/components/Panel.js +17 -11
  37. package/dist/components/Progress.d.ts +21 -23
  38. package/dist/components/Progress.js +13 -9
  39. package/dist/components/RadioGroup.js +6 -8
  40. package/dist/components/{select-parts.css → Select.css} +1 -1
  41. package/dist/components/Select.d.ts +53 -36
  42. package/dist/components/Select.js +53 -98
  43. package/dist/components/SelectFaceted.d.ts +7 -4
  44. package/dist/components/SelectFaceted.js +21 -10
  45. package/dist/components/Slider.d.ts +28 -11
  46. package/dist/components/Slider.js +20 -20
  47. package/dist/components/Steps.css +1 -1
  48. package/dist/components/Steps.d.ts +0 -1
  49. package/dist/components/Steps.js +1 -12
  50. package/dist/components/Tabs.d.ts +17 -20
  51. package/dist/components/Tabs.js +7 -9
  52. package/dist/components/Text.d.ts +55 -36
  53. package/dist/components/Text.js +35 -22
  54. package/dist/components/Title.d.ts +19 -27
  55. package/dist/components/Title.js +2 -1
  56. package/dist/components/Toaster.js +9 -2
  57. package/dist/components/Tooltip.d.ts +10 -15
  58. package/dist/components/copy-props.d.ts +14 -3
  59. package/dist/components/copy-props.js +14 -3
  60. package/dist/components/select-tree.d.ts +24 -0
  61. package/dist/components/select-tree.js +35 -0
  62. package/dist/element-base.d.ts +10 -0
  63. package/dist/element-base.js +15 -0
  64. package/dist/elements/a-avatar.css +1 -1
  65. package/dist/elements/a-avatar.js +2 -28
  66. package/dist/elements/a-banner.css +1 -1
  67. package/dist/elements/a-banner.d.ts +4 -1
  68. package/dist/elements/a-banner.js +22 -112
  69. package/dist/elements/a-breadcrumbs.d.ts +1 -0
  70. package/dist/elements/a-breadcrumbs.js +1 -0
  71. package/dist/elements/a-button.css +1 -1
  72. package/dist/elements/a-button.d.ts +10 -7
  73. package/dist/elements/a-button.js +18 -1
  74. package/dist/elements/a-calendar.d.ts +14 -13
  75. package/dist/elements/a-calendar.js +29 -24
  76. package/dist/elements/a-card.css +1 -1
  77. package/dist/elements/a-card.d.ts +0 -9
  78. package/dist/elements/a-card.js +0 -184
  79. package/dist/elements/a-checkbox.css +1 -1
  80. package/dist/elements/a-copy.css +1 -1
  81. package/dist/elements/a-copy.d.ts +1 -5
  82. package/dist/elements/a-copy.js +129 -108
  83. package/dist/elements/a-dialog.css +1 -1
  84. package/dist/elements/a-dialog.d.ts +1 -1
  85. package/dist/elements/a-dialog.js +68 -194
  86. package/dist/elements/a-expander.css +1 -1
  87. package/dist/elements/a-expander.d.ts +4 -30
  88. package/dist/elements/a-expander.js +85 -344
  89. package/dist/elements/a-icon.d.ts +5 -23
  90. package/dist/elements/a-icon.js +1 -2
  91. package/dist/elements/a-input-date.d.ts +1 -0
  92. package/dist/elements/a-input-date.js +1 -0
  93. package/dist/elements/a-input-time.css +1 -1
  94. package/dist/elements/a-input-time.d.ts +2 -1
  95. package/dist/elements/a-input-time.js +101 -168
  96. package/dist/elements/a-input.css +1 -1
  97. package/dist/elements/a-input.d.ts +10 -8
  98. package/dist/elements/a-input.js +155 -230
  99. package/dist/elements/a-loader.d.ts +5 -8
  100. package/dist/elements/a-loader.js +1 -2
  101. package/dist/elements/a-menu-item.css +1 -1
  102. package/dist/elements/a-menu-item.d.ts +5 -3
  103. package/dist/elements/a-menu-item.js +5 -1
  104. package/dist/elements/a-menu.css +1 -1
  105. package/dist/elements/a-menu.d.ts +5 -7
  106. package/dist/elements/a-menu.js +383 -299
  107. package/dist/elements/a-panel.css +1 -1
  108. package/dist/elements/a-panel.js +19 -37
  109. package/dist/elements/a-progress.css +1 -1
  110. package/dist/elements/a-progress.d.ts +0 -22
  111. package/dist/elements/a-progress.js +0 -100
  112. package/dist/elements/a-radio-group.d.ts +1 -1
  113. package/dist/elements/a-radio-group.js +6 -4
  114. package/dist/elements/a-select-faceted.d.ts +1 -0
  115. package/dist/elements/a-select-faceted.js +1 -0
  116. package/dist/elements/a-select.d.ts +1 -0
  117. package/dist/elements/a-select.js +1 -0
  118. package/dist/elements/a-slider.css +1 -1
  119. package/dist/elements/a-slider.d.ts +11 -3
  120. package/dist/elements/a-slider.js +244 -242
  121. package/dist/elements/a-steps.d.ts +1 -0
  122. package/dist/elements/a-steps.js +1 -0
  123. package/dist/elements/a-switch.css +1 -1
  124. package/dist/elements/a-tab.css +1 -1
  125. package/dist/elements/a-tabpanel.d.ts +2 -2
  126. package/dist/elements/a-tabpanel.js +13 -3
  127. package/dist/elements/a-tabs.css +1 -1
  128. package/dist/elements/a-tabs.d.ts +1 -1
  129. package/dist/elements/a-tabs.js +6 -4
  130. package/dist/elements/a-tag.css +1 -1
  131. package/dist/elements/a-tag.d.ts +1 -0
  132. package/dist/elements/a-tag.js +1 -0
  133. package/dist/elements/a-text.css +1 -1
  134. package/dist/elements/a-text.d.ts +6 -43
  135. package/dist/elements/a-text.js +110 -193
  136. package/dist/elements/a-title.css +1 -1
  137. package/dist/elements/a-title.d.ts +1 -0
  138. package/dist/elements/a-title.js +1 -0
  139. package/dist/elements/a-toast.css +1 -1
  140. package/dist/elements/a-toast.d.ts +10 -45
  141. package/dist/elements/a-toast.js +80 -66
  142. package/dist/elements/a-toaster.css +1 -1
  143. package/dist/elements/a-toaster.js +9 -44
  144. package/dist/elements/a-tooltip.css +1 -1
  145. package/dist/elements/a-tooltip.d.ts +1 -1
  146. package/dist/elements/a-tooltip.js +142 -136
  147. package/dist/elements/copy-behavior.d.ts +1 -1
  148. package/dist/elements/copy-behavior.js +21 -21
  149. package/dist/elements/index.d.ts +9 -3
  150. package/dist/elements/index.js +6 -6
  151. package/dist/elements/input-focus-modality.d.ts +15 -0
  152. package/dist/elements/input-focus-modality.js +44 -0
  153. package/dist/elements/input-trailing-actions.d.ts +5 -0
  154. package/dist/elements/input-trailing-actions.js +38 -0
  155. package/dist/elements/shadow-aria.d.ts +2 -0
  156. package/dist/elements/shadow-aria.js +2 -1
  157. package/dist/elements/value-input.d.ts +3 -0
  158. package/dist/elements/value-input.js +12 -0
  159. package/dist/general_types.d.ts +103 -96
  160. package/dist/index.d.ts +1 -1
  161. package/dist/input-events.d.ts +4 -0
  162. package/dist/input-events.js +15 -0
  163. package/dist/jsx-runtime.d.ts +70 -23
  164. package/dist/jsx-runtime.js +26 -19
  165. package/dist/native-event-props.d.ts +2 -0
  166. package/dist/native-event-props.js +10 -0
  167. package/dist/reset.css +1 -1
  168. package/dist/theme-antithesis.css +10 -1
  169. package/dist/theme-antune.css +1 -1
  170. package/docs/accessibility.md +17 -3
  171. package/docs/changelog.md +384 -2
  172. package/docs/comparison.md +2 -2
  173. package/docs/components/avatar.md +5 -0
  174. package/docs/components/banner.md +117 -187
  175. package/docs/components/breadcrumbs.md +9 -6
  176. package/docs/components/button.md +22 -0
  177. package/docs/components/card.md +74 -28
  178. package/docs/components/checkbox.md +9 -10
  179. package/docs/components/dialog.md +83 -32
  180. package/docs/components/expander.md +198 -435
  181. package/docs/components/icon.md +11 -17
  182. package/docs/components/input-autocomplete.md +152 -52
  183. package/docs/components/input-date.md +175 -148
  184. package/docs/components/input-time.md +81 -38
  185. package/docs/components/input.md +343 -349
  186. package/docs/components/loader.md +2 -1
  187. package/docs/components/menu.md +35 -6
  188. package/docs/components/panel.md +18 -0
  189. package/docs/components/progress.md +83 -49
  190. package/docs/components/radio.md +39 -43
  191. package/docs/components/select-faceted.md +54 -7
  192. package/docs/components/select.md +390 -386
  193. package/docs/components/slider.md +136 -19
  194. package/docs/components/steps.md +6 -3
  195. package/docs/components/switch.md +8 -9
  196. package/docs/components/tabs.md +110 -104
  197. package/docs/components/text.md +110 -86
  198. package/docs/components/title.md +47 -33
  199. package/docs/components/toaster.md +242 -84
  200. package/docs/components/tooltip.md +204 -113
  201. package/docs/install-config.md +461 -96
  202. package/docs/packages/plot.md +228 -143
  203. package/docs/theming.md +29 -13
  204. package/package.json +43 -4
  205. package/theme-antithesis-license.md +66 -0
@@ -24,7 +24,7 @@ Combine multiple series in one plot to compare values, show trends, and add cont
24
24
 
25
25
 
26
26
  ```ts
27
- import { area, line, rule, scatter, type PlotArgs, type Series } from '@antadesign/plot'
27
+ import { area, line, rule, scatter, type PlotArgs } from '@antadesign/plot'
28
28
  import '@antadesign/plot/elements/a-plot'
29
29
  import type { APlotElement } from '@antadesign/plot/browser'
30
30
 
@@ -52,8 +52,8 @@ function overviewExample(): PlotArgs<Node> {
52
52
 
53
53
  const meanExpected = forecast.reduce((sum, point) => sum + point.expected, 0) / forecast.length
54
54
 
55
- const series: Series<Node>[] = [
56
- area<Node>({
55
+ const series: PlotArgs<Node>['series'] = [
56
+ area({
57
57
  data: forecast,
58
58
  x: 'hour',
59
59
  y: 'high',
@@ -61,14 +61,14 @@ function overviewExample(): PlotArgs<Node> {
61
61
  color: { light: '#ede9fe', dark: '#30274e' },
62
62
  hoverable: false,
63
63
  }),
64
- rule<Node>({
64
+ rule({
65
65
  y: meanExpected,
66
66
  color: { light: '#d97706', dark: '#fbbf24' },
67
67
  width: 2,
68
68
  dash: [8, 4],
69
69
  hoverable: false,
70
70
  }),
71
- line<Node>({
71
+ line({
72
72
  data: forecast,
73
73
  x: 'hour',
74
74
  y: 'expected',
@@ -77,7 +77,7 @@ function overviewExample(): PlotArgs<Node> {
77
77
  dash: [5, 5],
78
78
  tooltip: ({ x, y }) => document.createTextNode('Forecast at ' + x + 'h: ' + Math.round(Number(y)) + ' requests/s'),
79
79
  }),
80
- line<Node>({
80
+ line({
81
81
  data: trend,
82
82
  x: 'hour',
83
83
  y: 'average',
@@ -85,7 +85,7 @@ function overviewExample(): PlotArgs<Node> {
85
85
  width: 3,
86
86
  tooltip: ({ x, y }) => document.createTextNode('Trend at ' + x + 'h: ' + Math.round(Number(y)) + ' requests/s'),
87
87
  }),
88
- scatter<Node>({
88
+ scatter({
89
89
  data: observations.filter(point => !point.outside),
90
90
  x: 'hour',
91
91
  y: 'actual',
@@ -93,7 +93,7 @@ function overviewExample(): PlotArgs<Node> {
93
93
  size: 4,
94
94
  tooltip: ({ x, y }) => document.createTextNode('Observed at ' + x + 'h: ' + y + ' requests/s'),
95
95
  }),
96
- scatter<Node>({
96
+ scatter({
97
97
  data: observations.filter(point => point.outside),
98
98
  x: 'hour',
99
99
  y: 'actual',
@@ -126,7 +126,7 @@ function overviewExample(): PlotArgs<Node> {
126
126
 
127
127
  const grid = false
128
128
 
129
- const zoom_pan = { x: true, y: true, modifier: false }
129
+ const zoom_pan = { x: true, y: true }
130
130
 
131
131
  // Replace the object to apply a change; Plot does not observe in-place mutation.
132
132
  const plotArgs: PlotArgs<Node> = { ...options, series, axis, margin, grid, zoom_pan }
@@ -165,11 +165,11 @@ function energyExample(): PlotArgs<Node> {
165
165
  ]
166
166
  return {
167
167
  series: [
168
- bar<Node>({ data, y: ['solar', 'wind'],
168
+ bar({ data, y: ['solar', 'wind'],
169
169
  color: [{ light: '#fbbf24', dark: '#d97706' }, { light: '#2dd4bf', dark: '#0d9488' }],
170
170
  inset: 5, border_radius: 3,
171
171
  tooltip: ({ x, y, label }) => document.createTextNode('Site ' + x + ' · ' + label + ': ' + y + ' kW') }),
172
- scatter<Node>({ data, y: 'demand', mark: 'diamond', size: 7,
172
+ scatter({ data, y: 'demand', mark: 'diamond', size: 7,
173
173
  tooltip: ({ x, y }) => document.createTextNode('Site ' + x + ' · Demand: ' + y + ' kW'),
174
174
  color: { light: '#7c3aed', dark: '#c4b5fd' },
175
175
  stroke: { color: { light: '#ffffff', dark: '#151b28' }, width: 1.5 } }),
@@ -210,12 +210,12 @@ function latencyExample(): PlotArgs<Node> {
210
210
  const curve = Array.from({ length: 121 }, (_, i) => ({ x: i * 2, y: density(i * 2) }))
211
211
  return {
212
212
  series: [
213
- area<Node>({ data: curve, y2: 0, color: { light: '#fce7f3', dark: '#452039' }, hoverable: false }),
214
- rect<Node>({ data: bins, color: { light: '#f472b6', dark: '#be185d' },
213
+ area({ data: curve, y2: 0, color: { light: '#fce7f3', dark: '#452039' }, hoverable: false }),
214
+ rect({ data: bins, color: { light: '#f472b6', dark: '#be185d' },
215
215
  tooltip: ({ row, y }) => document.createTextNode(
216
216
  (Number(row.x) - 1) + '–' + (Number(row.x2) + 1) + ' ms · ' + Math.round(Number(y)) + ' requests',
217
217
  ) }),
218
- line<Node>({ data: curve, color: { light: '#9d174d', dark: '#fbcfe8' }, width: 2.5,
218
+ line({ data: curve, color: { light: '#9d174d', dark: '#fbcfe8' }, width: 2.5,
219
219
  tooltip: ({ x, y }) => document.createTextNode('Distribution at ' + x + ' ms: ' + Number(y).toFixed(1) + ' requests') }),
220
220
 
221
221
  ],
@@ -279,24 +279,24 @@ function mixedExample(): PlotArgs<Node> {
279
279
  ]
280
280
  return {
281
281
  series: [
282
- area<Node>({ data: Array.from({ length: 81 }, (_, i) => {
282
+ area({ data: Array.from({ length: 81 }, (_, i) => {
283
283
  const x = i * 1.25
284
284
  const center = 50 + 7 * Math.sin(i / 9) + 3 * Math.cos(i / 4)
285
285
  const spread = 3 + 1.5 * Math.sin(i / 11) ** 2
286
286
  return { x, y: center + spread, y2: center - spread }
287
287
  }), color: { light: '#99f6e4', dark: '#115e59' },
288
288
  stroke: { color: { light: '#14b8a6', dark: '#5eead4' }, width: 1 } }),
289
- ...points.map((point, i) => scatter<Node>({ data: [point], size: [7, 12, 21, 10, 15, 9, 26, 13, 11, 8, 14][i],
289
+ ...points.map((point, i) => scatter({ data: [point], size: [7, 12, 21, 10, 15, 9, 26, 13, 11, 8, 14][i],
290
290
  mark: 'circle', color: colors[i % colors.length],
291
291
  tooltip: ({ x, y }) => document.createTextNode('Point ' + (i + 1) + ' · (' + x + ', ' + y + ')'),
292
292
  stroke: { color: { light: '#ffffff', dark: '#151b28' }, width: 1.5 } })),
293
- rect<Node>({ data: [{ x: 32, x2: 44, y: 31, y2: 47 }],
293
+ rect({ data: [{ x: 32, x2: 44, y: 31, y2: 47 }],
294
294
  color: { light: '#ddd6fe', dark: '#5b21b6' },
295
295
  stroke: { color: { light: '#8b5cf6', dark: '#c4b5fd' }, width: 1.5 } }),
296
- rect<Node>({ data: [{ x: 76, x2: 97, y: 76, y2: 96 }],
296
+ rect({ data: [{ x: 76, x2: 97, y: 76, y2: 96 }],
297
297
  color: { light: 'rgba(254, 215, 170, 0.55)', dark: 'rgba(154, 52, 18, 0.55)' },
298
298
  stroke: { color: { light: '#f97316', dark: '#fdba74' }, width: 1.5 } }),
299
- ...smoothPaths.map((data, i) => line<Node>({ data, width: 2.5, dash: i === 1 ? [7, 5] : [],
299
+ ...smoothPaths.map((data, i) => line({ data, width: 2.5, dash: i === 1 ? [7, 5] : [],
300
300
  tooltip: ({ x, y }) => document.createTextNode(
301
301
  'Line ' + (i + 1) + ' · (' + Number(x).toFixed(1) + ', ' + Number(y).toFixed(1) + ')',
302
302
  ),
@@ -304,7 +304,7 @@ function mixedExample(): PlotArgs<Node> {
304
304
  : { light: '#f97316', dark: '#fdba74' },
305
305
  })),
306
306
 
307
- rule<Node>({ y: 10, color: { light: '#0284c7', dark: '#7dd3fc' }, width: 1.5, dash: [6, 4] }),
307
+ rule({ y: 10, color: { light: '#0284c7', dark: '#7dd3fc' }, width: 1.5, dash: [6, 4] }),
308
308
  ],
309
309
  axis: { x: { min: 0, max: 100, label: '' }, y: { min: 0, max: 100, label: '' } },
310
310
  background: { light: '#ffffff', dark: '#151b28' },
@@ -394,7 +394,7 @@ const examplePoints = [
394
394
 
395
395
  function presentation(): PlotArgs<Node> {
396
396
  return {
397
- series: [scatter<Node>({ data: examplePoints, size: 3,
397
+ series: [scatter({ data: examplePoints, size: 3,
398
398
  color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
399
399
  title: { text: 'Plot title', font: { size: 16, color: { light: '#374151', dark: '#e5e7eb' } } },
400
400
  height: 260,
@@ -429,7 +429,7 @@ const examplePoints = [
429
429
 
430
430
  function spacing(): PlotArgs<Node> {
431
431
  return {
432
- series: [scatter<Node>({ data: examplePoints, size: 3,
432
+ series: [scatter({ data: examplePoints, size: 3,
433
433
  color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
434
434
  height: 260,
435
435
  margin: { top: 40, right: 40, bottom: 68, left: 88 },
@@ -461,12 +461,15 @@ document.body.append(plot)
461
461
  | [`chrome_color?`](#theme-colors) | `string \| { light, dark }` | Theme defaults | Color for axis lines, tick marks, grid lines, and the plot border. Text colors are configured separately. |
462
462
  | [`background?`](#theme-colors) | `boolean \| string \| { light, dark }` | White | Plot fill. `false` paints none; `true` and an absent value use `#fff`. |
463
463
  | [`theme_invert?`](#theme-colors) | `boolean` | Automatic | Forces dark-mode inversion on or off. Absent means invert unless a series color or the background is a `{ light, dark }` pair. |
464
- | [`zoom_pan?`](#zoom-and-pan) | `boolean \| { x?, y?, modifier? }` | Both axes, Ctrl required | Require Ctrl for zoom and pan by default. Set `modifier: false` to allow gestures without Ctrl. Set both axes to `false` to disable zoom and pan. |
464
+ | [`zoom_pan?`](#zoom-and-pan) | `boolean \| { x?, y?, menu_zoom_step? }` | Both continuous axes | Scroll to zoom and drag to pan. Scroll or drag on an axis to affect only that axis. Set both axes to `false` to disable zoom and pan. |
465
465
  | [`viewport?`](#viewport) | `{ x?, y?, key? }` | Full domain | Requested starting window per axis. Applied at mount and on each `key` change, clamped to the full domain. |
466
466
  | [`on_viewport_change?`](#viewport-changes) | `(change: ViewportChange) => void` | None | Fires with each axis's current window and full extent after a gesture or reset. |
467
467
 
468
- A zoomed plot shows a **Reset zoom** button in the plot area; it
469
- disappears once the view is back to its full extent.
468
+ Right-click the plot for **Reset Zoom**, **Zoom Out**, and **Zoom In**.
469
+ Unavailable actions stay visible and disabled. Reset restores the full viewport;
470
+ double-clicking does not reset. Focus the plot zoom controls and press Shift+F10
471
+ or the Context Menu key to open the menu from the keyboard. Ctrl-primary click
472
+ is reserved for rectangle zoom on macOS too; use a secondary click for the menu.
470
473
 
471
474
  ### Axes
472
475
 
@@ -491,7 +494,7 @@ const examplePoints = [
491
494
  function logarithmic(): PlotArgs<Node> {
492
495
  const data = examplePoints.map(({ x, y }) => ({ x, y: 10 ** (y / 20 - 1) }))
493
496
  return {
494
- series: [scatter<Node>({ data, size: 3,
497
+ series: [scatter({ data, size: 3,
495
498
  color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
496
499
  height: 260,
497
500
  margin: { top: 12, right: 14, bottom: 44, left: 80 },
@@ -531,7 +534,7 @@ function timeAxis(): PlotArgs<Node> {
531
534
  const start = Date.UTC(2026, 0, 12)
532
535
  const data = examplePoints.map(({ x, y }) => ({ x: start + x / 100 * 86400000, y }))
533
536
  return {
534
- series: [scatter<Node>({ data, size: 3,
537
+ series: [scatter({ data, size: 3,
535
538
  color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
536
539
  height: 260,
537
540
  margin: { top: 12, right: 16, bottom: 44, left: 76 },
@@ -680,7 +683,7 @@ Scatter arguments
680
683
  | `x?` | [`FieldArg`](#data-fields) | `'x'` | Horizontal field name or accessor. |
681
684
  | `y?` | [`FieldArg`](#data-fields) | `'y'` | Vertical field name or accessor. |
682
685
  | `color?` | [`ColorArg`](#series-colors) | Black | Series color; theme pairs provide separate light and dark colors. |
683
- | `size?` | `number \| ((row, index) => number)` | `5` | Mark diameter in pixels, or a per-row accessor. A row’s `size` takes precedence. |
686
+ | `size?` | `number \| ((row, index, viewport) => number)` | `5` | [Mark diameter](#size) in pixels, or a per-row accessor. A row’s `size` takes precedence. |
684
687
  | [`mark?`](#mark-shapes) | `MarkShape` | `'circle'` | Mark shape: circle, square, diamond, or triangle. |
685
688
  | [`stroke?`](#strokes) | `StrokeArg` | None | Outline color and optional width. |
686
689
  | [`tooltip?`](#tooltips) | `TooltipArg` | None | Use `true` for the default tooltip, or a callback for custom content. |
@@ -731,7 +734,7 @@ const data = Array.from({ length: 97 }, (_, i) => ({
731
734
 
732
735
  plot.plotArgs = {
733
736
  series: [
734
- line<Node>({
737
+ line({
735
738
  data,
736
739
  y: 'expected',
737
740
  color: { light: '#c2410c', dark: '#fdba74' },
@@ -739,7 +742,7 @@ plot.plotArgs = {
739
742
  dash: [7, 5],
740
743
  tooltip: ({ y }) => document.createTextNode('Expected: ' + Math.round(Number(y))),
741
744
  }),
742
- line<Node>({
745
+ line({
743
746
  data,
744
747
  y: 'measured',
745
748
  color: { light: '#0891b2', dark: '#67e8f9' },
@@ -776,7 +779,7 @@ const data = Array.from({ length: 13 }, (_, i) => ({
776
779
  }))
777
780
 
778
781
  plot.plotArgs = {
779
- series: [line<Node>({
782
+ series: [line({
780
783
  data,
781
784
  color: { light: '#7c3aed', dark: '#c4b5fd' },
782
785
  width: 3,
@@ -864,7 +867,7 @@ const data = [
864
867
  ]
865
868
 
866
869
  plot.plotArgs = {
867
- series: [bar<Node>({
870
+ series: [bar({
868
871
  data,
869
872
  x: 'day',
870
873
  y: 'requests',
@@ -908,7 +911,7 @@ const data = [
908
911
  ]
909
912
 
910
913
  plot.plotArgs = {
911
- series: [bar<Node>({
914
+ series: [bar({
912
915
  data,
913
916
  x: 'requests',
914
917
  y: 'service',
@@ -952,7 +955,7 @@ const data = [
952
955
  ]
953
956
 
954
957
  plot.plotArgs = {
955
- series: [bar<Node>({
958
+ series: [bar({
956
959
  data,
957
960
  x: 'month',
958
961
  y: 'change',
@@ -991,7 +994,7 @@ function categoryOrder(): PlotArgs<Node> {
991
994
  { severity: 'Critical', count: 12 }, { severity: 'Medium', count: 35 },
992
995
  ]
993
996
  return {
994
- series: [bar<Node>({ data, x: 'severity', y: 'count', inset: 10, border_radius: 3,
997
+ series: [bar({ data, x: 'severity', y: 'count', inset: 10, border_radius: 3,
995
998
  color: { light: '#64748b', dark: '#94a3b8' },
996
999
  tooltip: ({ x, y }) => document.createTextNode(x + ': ' + y + ' issues'),
997
1000
  })],
@@ -1078,7 +1081,7 @@ const data = [
1078
1081
  ]
1079
1082
 
1080
1083
  plot.plotArgs = {
1081
- series: [bar<Node>({
1084
+ series: [bar({
1082
1085
  data,
1083
1086
  x: 'day',
1084
1087
  y: ['network', 'compute', 'storage'],
@@ -1120,7 +1123,7 @@ function stackedHorizontal(): PlotArgs<Node> {
1120
1123
  { service: 'Export', network: 12, compute: 36, storage: 18 },
1121
1124
  ]
1122
1125
  return {
1123
- series: [bar<Node>({ data, x: ['network', 'compute', 'storage'], y: 'service',
1126
+ series: [bar({ data, x: ['network', 'compute', 'storage'], y: 'service',
1124
1127
  color: [
1125
1128
  { light: '#0d9488', dark: '#5eead4' },
1126
1129
  { light: '#6366f1', dark: '#a5b4fc' },
@@ -1163,7 +1166,7 @@ function stackedDiverging(): PlotArgs<Node> {
1163
1166
  { month: 'May', new: 32, expansion: 10, churn: -12, contraction: -8 },
1164
1167
  ]
1165
1168
  return {
1166
- series: [bar<Node>({ data, x: 'month', y: ['new', 'expansion', 'churn', 'contraction'],
1169
+ series: [bar({ data, x: 'month', y: ['new', 'expansion', 'churn', 'contraction'],
1167
1170
  color: [
1168
1171
  { light: '#0d9488', dark: '#2dd4bf' },
1169
1172
  { light: '#5eead4', dark: '#99f6e4' },
@@ -1208,7 +1211,7 @@ function stackedTooltip(): PlotArgs<Node> {
1208
1211
  ]
1209
1212
 
1210
1213
  return {
1211
- series: [bar<Node>({
1214
+ series: [bar({
1212
1215
  data,
1213
1216
  x: 'day',
1214
1217
  y: ['network', 'compute', 'storage'],
@@ -1222,7 +1225,8 @@ function stackedTooltip(): PlotArgs<Node> {
1222
1225
  hover_span_y: false,
1223
1226
  tooltip: ({ label, row }) => {
1224
1227
  const content = document.createElement('div')
1225
- for (const field of ['network', 'compute', 'storage']) {
1228
+ const fields: (keyof typeof row)[] = ['network', 'compute', 'storage']
1229
+ for (const field of fields) {
1226
1230
  const entry = document.createElement('div')
1227
1231
  const value = document.createElement(field === label ? 'strong' : 'span')
1228
1232
  value.textContent = field + ': ' + row[field] + ' ms'
@@ -1295,7 +1299,7 @@ const data = Array.from({ length: 97 }, (_, i) => ({
1295
1299
 
1296
1300
  plot.plotArgs = {
1297
1301
  series: [
1298
- area<Node>({
1302
+ area({
1299
1303
  data,
1300
1304
  y2: 0,
1301
1305
  color: { light: '#99f6e4', dark: '#134e4a' },
@@ -1334,7 +1338,7 @@ const data = Array.from({ length: 81 }, (_, i) => {
1334
1338
 
1335
1339
  plot.plotArgs = {
1336
1340
  series: [
1337
- area<Node>({
1341
+ area({
1338
1342
  data,
1339
1343
  y: 'high',
1340
1344
  y2: 'low',
@@ -1376,21 +1380,21 @@ const data = Array.from({ length: 97 }, (_, i) => {
1376
1380
 
1377
1381
  plot.plotArgs = {
1378
1382
  series: [
1379
- area<Node>({
1383
+ area({
1380
1384
  data,
1381
1385
  y: 'first',
1382
1386
  y2: 0,
1383
1387
  color: { light: '#2dd4bf', dark: '#0d9488' },
1384
1388
  tooltip: ({ row }) => document.createTextNode('Network: ' + Math.round(Number(row.first))),
1385
1389
  }),
1386
- area<Node>({
1390
+ area({
1387
1391
  data,
1388
1392
  y: 'second',
1389
1393
  y2: 'first',
1390
1394
  color: { light: '#a5b4fc', dark: '#6366f1' },
1391
1395
  tooltip: ({ row }) => document.createTextNode('Compute: ' + Math.round(Number(row.second) - Number(row.first))),
1392
1396
  }),
1393
- area<Node>({
1397
+ area({
1394
1398
  data,
1395
1399
  y: 'total',
1396
1400
  y2: 'second',
@@ -1429,7 +1433,7 @@ const data = Array.from({ length: 81 }, (_, i) => {
1429
1433
 
1430
1434
  plot.plotArgs = {
1431
1435
  series: [
1432
- area<Node>({
1436
+ area({
1433
1437
  data,
1434
1438
  x: 'low',
1435
1439
  x2: 'high',
@@ -1528,7 +1532,7 @@ const data = days.flatMap((day, d) => hours.map((hour, h) => ({
1528
1532
 
1529
1533
  plot.plotArgs = {
1530
1534
  series: [
1531
- rect<Node>({
1535
+ rect({
1532
1536
  data,
1533
1537
  x: 'hour',
1534
1538
  y: 'day',
@@ -1573,7 +1577,7 @@ const data = [
1573
1577
 
1574
1578
  plot.plotArgs = {
1575
1579
  series: [
1576
- rect<Node>({
1580
+ rect({
1577
1581
  data,
1578
1582
  x: 'start',
1579
1583
  x2: 'end',
@@ -1616,7 +1620,7 @@ const data = Array.from({ length: 32 }, (_, i) => ({
1616
1620
 
1617
1621
  plot.plotArgs = {
1618
1622
  series: [
1619
- rect<Node>({
1623
+ rect({
1620
1624
  data,
1621
1625
  size: { width: 16, height: 9 },
1622
1626
  color: row => Number(row.value) > 65
@@ -1658,7 +1662,7 @@ const data = Array.from({ length: 36 }, (_, i) => ({
1658
1662
 
1659
1663
  plot.plotArgs = {
1660
1664
  series: [
1661
- rect<Node>({
1665
+ rect({
1662
1666
  data: data.filter(row => row.lane === 'Passed'),
1663
1667
  x: 'end_ms',
1664
1668
  y: 'lane',
@@ -1669,7 +1673,7 @@ plot.plotArgs = {
1669
1673
  stroke: { color: { light: '#ffffff', dark: '#151b28' }, width: 0.5 },
1670
1674
  tooltip: ({ row }) => document.createTextNode('Run ' + row.run + ': ' + row.lane),
1671
1675
  }),
1672
- rect<Node>({
1676
+ rect({
1673
1677
  data: data.filter(row => row.lane === 'Failed'),
1674
1678
  x: 'end_ms',
1675
1679
  y: 'lane',
@@ -1814,19 +1818,19 @@ const data = Array.from({ length: 97 }, (_, i) => ({
1814
1818
 
1815
1819
  plot.plotArgs = {
1816
1820
  series: [
1817
- line<Node>({
1821
+ line({
1818
1822
  data,
1819
1823
  color: { light: '#0891b2', dark: '#67e8f9' },
1820
1824
  width: 2,
1821
1825
  }),
1822
- rule<Node>({
1826
+ rule({
1823
1827
  y: 60,
1824
1828
  color: { light: '#7c3aed', dark: '#c4b5fd' },
1825
1829
  width: 1,
1826
1830
  dash: [7, 4],
1827
1831
  tooltip: () => document.createTextNode('Target: 60 ms'),
1828
1832
  }),
1829
- rule<Node>({
1833
+ rule({
1830
1834
  y: 90,
1831
1835
  color: { light: '#c2410c', dark: '#fdba74' },
1832
1836
  width: 4,
@@ -1869,19 +1873,19 @@ const events = [
1869
1873
 
1870
1874
  plot.plotArgs = {
1871
1875
  series: [
1872
- line<Node>({
1876
+ line({
1873
1877
  data,
1874
1878
  color: { light: '#6366f1', dark: '#a5b4fc' },
1875
1879
  width: 2,
1876
1880
  }),
1877
- rule<Node>({
1881
+ rule({
1878
1882
  data: events.filter(event => !event.recovery),
1879
1883
  x: 'hour',
1880
1884
  color: { light: '#c2410c', dark: '#fdba74' },
1881
1885
  width: 3,
1882
1886
  tooltip: ({ row }) => document.createTextNode(row?.name + ' at hour ' + row?.hour),
1883
1887
  }),
1884
- rule<Node>({
1888
+ rule({
1885
1889
  data: events.filter(event => event.recovery),
1886
1890
  x: 'hour',
1887
1891
  color: { light: '#0d9488', dark: '#5eead4' },
@@ -1982,7 +1986,7 @@ const points = groups.flatMap((group, g) => Array.from({ length: 80 }, (_, i) =>
1982
1986
 
1983
1987
  plot.plotArgs = {
1984
1988
  series: [
1985
- scatter<Node>({
1989
+ scatter({
1986
1990
  data: points,
1987
1991
  size: 3,
1988
1992
  color: row => Number(row.group) === 0
@@ -1990,7 +1994,7 @@ plot.plotArgs = {
1990
1994
  : { light: '#7c3aed', dark: '#c4b5fd' },
1991
1995
  tooltip: ({ x, y }) => document.createTextNode(Number(x).toFixed(1) + ', ' + Number(y).toFixed(1)),
1992
1996
  }),
1993
- custom<Node>({
1997
+ custom({
1994
1998
  data: groups,
1995
1999
  x: 'x', y: 'y',
1996
2000
  color: (_, i) => i === 0
@@ -2068,7 +2072,7 @@ const groups = matrix.map((row, i) => {
2068
2072
  })
2069
2073
 
2070
2074
  plot.plotArgs = {
2071
- series: [custom<Node>({
2075
+ series: [custom({
2072
2076
  data: groups,
2073
2077
  color: (_, i) => [
2074
2078
  { light: '#0d9488', dark: '#5eead4' },
@@ -2213,7 +2217,7 @@ const data = Array.from({ length: 6 }, (_, i) => {
2213
2217
  const peak = Math.max(...data.flatMap(row => row.density.map(point => point.density)))
2214
2218
 
2215
2219
  plot.plotArgs = {
2216
- series: [custom<Node>({
2220
+ series: [custom({
2217
2221
  data,
2218
2222
  y: 'group',
2219
2223
  color: (_, i) => ({ light: 'hsl(' + (175 + i * 15) + ', 55%, 55%)', dark: 'hsl(' + (175 + i * 15) + ', 50%, 45%)' }),
@@ -2320,7 +2324,7 @@ const data = distributions()
2320
2324
  const peak = Math.max(...data.flatMap(row => row.density.map(point => point.density)))
2321
2325
 
2322
2326
  plot.plotArgs = {
2323
- series: [custom<Node>({
2327
+ series: [custom({
2324
2328
  data,
2325
2329
  x: 'group',
2326
2330
  color: (_, i) => [
@@ -2400,13 +2404,14 @@ Without `highlight_renderer`, Anta calls `renderer` on the overlay with a single
2400
2404
  For connected geometry or a different highlight, supply `highlight_renderer(series, point_index, context)`. It receives the full composed series, the original hovered index, and the normal render helpers plus `highlight_color_at(index)`. Anta handles DPR, clearing, clipping, and canvas-state isolation. Set `highlight: false` to disable either path. Both paths require data and hit testing.
2401
2405
 
2402
2406
  ```ts
2403
- import { custom, type CustomRendererFn, type CustomHitTestFn, type CustomHighlightRendererFn } from '@antadesign/plot'
2407
+ import { custom, type PlotArgs, type CustomRendererFn, type CustomHitTestFn, type CustomHighlightRendererFn } from '@antadesign/plot'
2404
2408
  import type { APlotElement } from '@antadesign/plot/browser'
2405
2409
  import '@antadesign/plot/elements/a-plot'
2406
2410
 
2407
2411
  const plot = document.createElement('a-plot') as APlotElement
2408
- function highlights() {
2409
- const renderer: CustomRendererFn<Node> = (series, { ctx, resolve_x, resolve_y, color_at }) => {
2412
+ function highlights(): PlotArgs<Node> {
2413
+ type Point = { x: number; y: number }
2414
+ const renderer: CustomRendererFn<Point> = (series, { ctx, resolve_x, resolve_y, color_at }) => {
2410
2415
  for (let i = 0; i < series.x.length; i++) {
2411
2416
  const x = resolve_x(i), y = resolve_y(i)
2412
2417
  if (x === undefined || y === undefined) continue
@@ -2416,14 +2421,14 @@ function highlights() {
2416
2421
  ctx.fill()
2417
2422
  }
2418
2423
  }
2419
- const hit_test: CustomHitTestFn<Node> = (series, { cursor, resolve_x, resolve_y }) => {
2424
+ const hit_test: CustomHitTestFn<Point> = (series, { cursor, resolve_x, resolve_y }) => {
2420
2425
  for (let i = series.x.length - 1; i >= 0; i--) {
2421
2426
  const x = resolve_x(i), y = resolve_y(i)
2422
2427
  if (x !== undefined && y !== undefined && Math.hypot(cursor.x - x, cursor.y - y) <= 16) return i
2423
2428
  }
2424
2429
  return null
2425
2430
  }
2426
- const highlight_renderer: CustomHighlightRendererFn<Node> = (series, i, { ctx, resolve_x, resolve_y, highlight_color_at }) => {
2431
+ const highlight_renderer: CustomHighlightRendererFn<Point> = (series, i, { ctx, resolve_x, resolve_y, highlight_color_at }) => {
2427
2432
  const x = resolve_x(i), y = resolve_y(i)
2428
2433
  if (x === undefined || y === undefined) return
2429
2434
  ctx.strokeStyle = highlight_color_at(i)
@@ -2438,15 +2443,15 @@ function highlights() {
2438
2443
  margin: { top: 12, right: 12, bottom: 28, left: 32 },
2439
2444
  grid: false, zoom_pan: false,
2440
2445
  series: [
2441
- custom<Node>({
2446
+ custom({
2442
2447
  data: [{ x: 20, y: 35 }, { x: 20, y: 65 }], x: 'x', y: 'y', renderer, hit_test,
2443
2448
  color: 'color-mix(in oklch, teal 40%, transparent)', tooltip: true,
2444
2449
  }),
2445
- custom<Node>({
2450
+ custom({
2446
2451
  data: [{ x: 50, y: 35 }, { x: 50, y: 65 }], x: 'x', y: 'y', renderer, hit_test, highlight_renderer,
2447
2452
  color: { light: '#7c3aed', dark: '#c4b5fd' }, tooltip: true,
2448
2453
  }),
2449
- custom<Node>({
2454
+ custom({
2450
2455
  data: [{ x: 80, y: 35 }, { x: 80, y: 65 }], x: 'x', y: 'y', renderer, hit_test,
2451
2456
  color: '#94a3b8', highlight: false, tooltip: true,
2452
2457
  }),
@@ -2556,23 +2561,23 @@ const data = [
2556
2561
 
2557
2562
  plot.plotArgs = {
2558
2563
  series: [
2559
- bar<Node>({
2564
+ bar({
2560
2565
  data: data.slice(0, 2), inset: 7, border_radius: 4,
2561
2566
  color: { light: 'rgba(13, 148, 136, 0.35)', dark: 'rgba(94, 234, 212, 0.35)' },
2562
2567
  }),
2563
- bar<Node>({
2568
+ bar({
2564
2569
  data: data.slice(2, 4), inset: 7, border_radius: 4,
2565
2570
  color: { light: '#0d9488', dark: '#5eead4' },
2566
2571
  highlight_color: row => row.x === 'C'
2567
2572
  ? { light: '#f97316', dark: '#fdba74' }
2568
2573
  : 'color-mix(in oklch, magenta 50%, transparent)',
2569
2574
  }),
2570
- bar<Node>({
2575
+ bar({
2571
2576
  data: data.slice(4, 5), inset: 7, border_radius: 4,
2572
2577
  color: { light: '#7c3aed', dark: '#c4b5fd' },
2573
2578
  highlight: false,
2574
2579
  }),
2575
- bar<Node>({
2580
+ bar({
2576
2581
  data: data.slice(5), inset: 7, border_radius: 4,
2577
2582
  color: { light: '#94a3b8', dark: '#64748b' },
2578
2583
  hoverable: false,
@@ -2593,14 +2598,14 @@ document.body.append(plot)
2593
2598
 
2594
2599
  #### Custom hit testing
2595
2600
 
2596
- `CustomHitTestFn<TooltipContent>` receives the composed custom series and a
2601
+ `CustomHitTestFn<Row>` receives a `CustomSeriesView<Row>` and a
2597
2602
  `HitContext`. Return the matching row index or `null` when there is no hit.
2598
2603
  Custom series need this callback for tooltips and selection.
2599
2604
 
2600
2605
  ```ts
2601
- import type { ComposedCustom, HitContext } from '@antadesign/plot'
2606
+ import type { CustomSeriesView, HitContext } from '@antadesign/plot'
2602
2607
 
2603
- type HitTest = (series: ComposedCustom, context: HitContext) => number | null
2608
+ type HitTest<Row> = (series: CustomSeriesView<Row>, context: HitContext) => number | null
2604
2609
  ```
2605
2610
 
2606
2611
  | Context field | Type | Description |
@@ -2631,13 +2636,13 @@ const data = [
2631
2636
 
2632
2637
  plot.plotArgs = {
2633
2638
  series: [
2634
- rect<Node>({
2639
+ rect({
2635
2640
  data,
2636
2641
  color: { light: 'rgba(13, 148, 136, 0.45)', dark: 'rgba(94, 234, 212, 0.45)' },
2637
2642
  stroke: { color: { light: '#0d9488', dark: '#5eead4' }, width: 2 },
2638
2643
  tooltip: true,
2639
2644
  }),
2640
- rect<Node>({
2645
+ rect({
2641
2646
  data: data.map(row => ({
2642
2647
  ...row, x: row.x + 12, x2: row.x2 + 8, y: row.y + 12, y2: row.y2 + 10,
2643
2648
  })),
@@ -2695,6 +2700,16 @@ Hover the overlapping rectangles to compare baseline and current bounds under on
2695
2700
  import { rect, type APlotElement } from '@antadesign/plot/browser'
2696
2701
  import '@antadesign/plot/elements/a-plot'
2697
2702
 
2703
+ function windowRow(row: unknown) {
2704
+ if (typeof row !== 'object' || row === null) return undefined
2705
+ if (!('name' in row) || typeof row.name !== 'string'
2706
+ || !('x' in row) || typeof row.x !== 'number'
2707
+ || !('x2' in row) || typeof row.x2 !== 'number'
2708
+ || !('y' in row) || typeof row.y !== 'number'
2709
+ || !('y2' in row) || typeof row.y2 !== 'number') return undefined
2710
+ return row
2711
+ }
2712
+
2698
2713
  const plot = document.createElement('a-plot') as APlotElement
2699
2714
  const data = [
2700
2715
  { x: 8, x2: 38, y: 15, y2: 48, name: 'Window A' },
@@ -2726,8 +2741,8 @@ plot.plotArgs = {
2726
2741
  }),
2727
2742
  ],
2728
2743
  tooltip: ([baseline_hit, current_hit]) => {
2729
- const baseline = baseline_hit?.data.row
2730
- const current = current_hit?.data.row
2744
+ const baseline = windowRow(baseline_hit?.data.row)
2745
+ const current = windowRow(current_hit?.data.row)
2731
2746
  const content = document.createElement('div')
2732
2747
  const title = document.createElement('strong')
2733
2748
  title.textContent = String((current ?? baseline)?.name ?? 'Window comparison')
@@ -2740,7 +2755,10 @@ plot.plotArgs = {
2740
2755
  header.append(cell)
2741
2756
  }
2742
2757
  const body = table.createTBody()
2743
- for (const [field, label] of [['x', 'X start'], ['x2', 'X end'], ['y', 'Y start'], ['y2', 'Y end']]) {
2758
+ const bounds: ['x' | 'x2' | 'y' | 'y2', string][] = [
2759
+ ['x', 'X start'], ['x2', 'X end'], ['y', 'Y start'], ['y2', 'Y end'],
2760
+ ]
2761
+ for (const [field, label] of bounds) {
2744
2762
  const before = baseline?.[field]
2745
2763
  const after = current?.[field]
2746
2764
  const delta = typeof before === 'number' && typeof after === 'number' ? after - before : undefined
@@ -2797,7 +2815,7 @@ const data = Array.from({ length: 24 }, (_, i) => ({
2797
2815
 
2798
2816
  plot.plotArgs = {
2799
2817
  series: [
2800
- scatter<Node>({
2818
+ scatter({
2801
2819
  data, size: 13,
2802
2820
  color: { light: '#0891b2', dark: '#67e8f9' },
2803
2821
  tooltip: true,
@@ -2848,11 +2866,15 @@ the same fields with an optional `row`.
2848
2866
 
2849
2867
  ### Zoom and pan
2850
2868
 
2851
- Zoom continuous axes with the scroll wheel and pan by dragging. The reset control restores the full extent after the view changes. Categorical axes do not zoom. See [Zoom and pan options](#zoom-and-pan-options).
2869
+ Zoom continuous axes with the scroll wheel and pan by dragging. Reset Zoom in the context menu restores the full extent after the view changes. Categorical axes do not zoom. See [Zoom and pan options](#zoom-and-pan-options).
2870
+
2871
+ Zoom and pan in the plot
2872
+
2873
+ Scroll to zoom around the pointer, or drag to pan. Plain wheel zoom activates after the pointer settles over the plot; Ctrl-wheel and pinch activate immediately. Horizontal scrolling does not change the viewport. Hold Ctrl and drag inside the plot to draw a zoom rectangle. Releasing fits the viewport to the rectangle, subject to each enabled axis's limits.
2852
2874
 
2853
- Zoom with a modifier
2875
+ Ctrl-wheel and pinch share the same browser signal. Small samples use higher sensitivity, while each sample is capped at a 1.2× change to keep physical mouse-wheel notches manageable. Switching between pinch and ordinary scrolling preserves the existing pointer dwell.
2854
2876
 
2855
- Hold Ctrl and scroll to zoom around the pointer, or hold Ctrl and drag to pan. The modifier leaves ordinary scrolling available for navigating the page.
2877
+ Right-click for **Reset Zoom**, **Zoom Out**, and **Zoom In**. Menu zoom anchors at the context-click position and applies the same factor to both enabled axes, with independent limits. Set `zoom_pan: { menu_zoom_step: 1.5 }` to change that factor from its default of `2`. Zoom In divides each span by the factor; Zoom Out multiplies it. The value must be finite and greater than 1. It affects only menu actions; wheel and drag sensitivity stay fixed.
2856
2878
 
2857
2879
  ```ts
2858
2880
  import { line, type APlotElement } from '@antadesign/plot/browser'
@@ -2862,7 +2884,7 @@ const plot = document.createElement('a-plot') as APlotElement
2862
2884
  const output = document.createElement('output')
2863
2885
  output.setAttribute('aria-live', 'polite')
2864
2886
  output.style.display = 'block'
2865
- output.textContent = 'Hold Ctrl and scroll to zoom, or Ctrl-drag to pan.'
2887
+ output.textContent = 'Scroll to zoom, drag to pan, or Ctrl-drag to zoom to a rectangle.'
2866
2888
 
2867
2889
  const data = Array.from({ length: 201 }, (_, i) => ({
2868
2890
  x: i / 2,
@@ -2871,20 +2893,20 @@ const data = Array.from({ length: 201 }, (_, i) => ({
2871
2893
 
2872
2894
  plot.plotArgs = {
2873
2895
  series: [
2874
- line<Node>({
2896
+ line({
2875
2897
  data, width: 2,
2876
2898
  color: { light: '#6366f1', dark: '#a5b4fc' },
2877
2899
  tooltip: true,
2878
2900
  }),
2879
2901
  ],
2880
- height: 260,
2902
+ height: 420,
2881
2903
  margin: { top: 8, right: 12, bottom: 24, left: 32 },
2882
2904
  axis: { x: { min: 0, max: 100, label: '' }, y: { min: 0, max: 100, label: '' } },
2883
2905
  background: { light: '#ffffff', dark: '#151b28' },
2884
2906
  chrome_color: { light: '#e2e8f0', dark: '#334155' },
2885
2907
  grid: false,
2886
2908
  border: false,
2887
- zoom_pan: { x: true, y: true, modifier: true },
2909
+ zoom_pan: { x: true, y: true },
2888
2910
  on_viewport_change: ({ x, y }) => {
2889
2911
  const format = (axis: { window: number[] } | null) => axis
2890
2912
  ? axis.window.map(value => value.toFixed(1)).join('–') : 'full extent'
@@ -2895,9 +2917,9 @@ plot.plotArgs = {
2895
2917
  document.body.append(plot, output)
2896
2918
  ```
2897
2919
 
2898
- Zoom without a modifier
2920
+ Navigate an axis
2899
2921
 
2900
- Scroll over the plot to zoom, or drag to pan. Set `modifier: false` when the plot should own these gestures without requiring Ctrl.
2922
+ Scroll over an axis to zoom around the pointer, or drag on the axis to zoom around the value where the drag started. No modifier is needed. Enabled continuous axes show directional arrows on hover. Drag inside the plot to pan. Drag right on x or up on y to zoom in; drag the other way to zoom out. Moving a quarter of the full axis length halves or doubles the starting span, subject to zoom limits. The other axis keeps its viewport.
2901
2923
 
2902
2924
  ```ts
2903
2925
  import { line, type APlotElement } from '@antadesign/plot/browser'
@@ -2907,7 +2929,7 @@ const plot = document.createElement('a-plot') as APlotElement
2907
2929
  const output = document.createElement('output')
2908
2930
  output.setAttribute('aria-live', 'polite')
2909
2931
  output.style.display = 'block'
2910
- output.textContent = 'Scroll to zoom, or drag to pan.'
2932
+ output.textContent = 'Scroll to zoom, drag to pan, or Ctrl-drag to zoom to a rectangle.'
2911
2933
 
2912
2934
  const data = Array.from({ length: 201 }, (_, i) => ({
2913
2935
  x: i / 2,
@@ -2916,7 +2938,7 @@ const data = Array.from({ length: 201 }, (_, i) => ({
2916
2938
 
2917
2939
  plot.plotArgs = {
2918
2940
  series: [
2919
- line<Node>({
2941
+ line({
2920
2942
  data, width: 2,
2921
2943
  color: { light: '#6366f1', dark: '#a5b4fc' },
2922
2944
  tooltip: true,
@@ -2929,7 +2951,7 @@ plot.plotArgs = {
2929
2951
  chrome_color: { light: '#e2e8f0', dark: '#334155' },
2930
2952
  grid: false,
2931
2953
  border: false,
2932
- zoom_pan: { x: true, y: true, modifier: false },
2954
+ zoom_pan: { x: true, y: true },
2933
2955
  on_viewport_change: ({ x, y }) => {
2934
2956
  const format = (axis: { window: number[] } | null) => axis
2935
2957
  ? axis.window.map(value => value.toFixed(1)).join('–') : 'full extent'
@@ -2942,7 +2964,7 @@ document.body.append(plot, output)
2942
2964
 
2943
2965
  Zoom on one axis
2944
2966
 
2945
- Hold Ctrl and scroll or drag. Only the horizontal window changes; the vertical range stays fixed. Set `x: false, y: true` for vertical-only navigation.
2967
+ Scroll to zoom or drag to pan. Only the horizontal window changes; the vertical range stays fixed. Set `x: false, y: true` for vertical-only navigation.
2946
2968
 
2947
2969
  ```ts
2948
2970
  import { line, type APlotElement } from '@antadesign/plot/browser'
@@ -2952,7 +2974,7 @@ const plot = document.createElement('a-plot') as APlotElement
2952
2974
  const output = document.createElement('output')
2953
2975
  output.setAttribute('aria-live', 'polite')
2954
2976
  output.style.display = 'block'
2955
- output.textContent = 'Hold Ctrl and scroll to zoom, or Ctrl-drag to pan.'
2977
+ output.textContent = 'Scroll to zoom, drag to pan, or Ctrl-drag to zoom to a rectangle.'
2956
2978
 
2957
2979
  const data = Array.from({ length: 201 }, (_, i) => ({
2958
2980
  x: i / 2,
@@ -2961,7 +2983,7 @@ const data = Array.from({ length: 201 }, (_, i) => ({
2961
2983
 
2962
2984
  plot.plotArgs = {
2963
2985
  series: [
2964
- line<Node>({
2986
+ line({
2965
2987
  data, width: 2,
2966
2988
  color: { light: '#6366f1', dark: '#a5b4fc' },
2967
2989
  tooltip: true,
@@ -2974,7 +2996,7 @@ plot.plotArgs = {
2974
2996
  chrome_color: { light: '#e2e8f0', dark: '#334155' },
2975
2997
  grid: false,
2976
2998
  border: false,
2977
- zoom_pan: { x: true, y: false, modifier: true },
2999
+ zoom_pan: { x: true, y: false },
2978
3000
  on_viewport_change: ({ x, y }) => {
2979
3001
  const format = (axis: { window: number[] } | null) => axis
2980
3002
  ? axis.window.map(value => value.toFixed(1)).join('–') : 'full extent'
@@ -2993,13 +3015,13 @@ document.body.append(plot, output)
2993
3015
  |---|---|---|---|
2994
3016
  | `x?` | `boolean` | `true` | Enable horizontal zoom and pan on a continuous axis. |
2995
3017
  | `y?` | `boolean` | `true` | Enable vertical zoom and pan on a continuous axis. |
2996
- | `modifier?` | `boolean` | `true` | Require Ctrl for gestures. Set `false` to allow gestures without a modifier. |
3018
+ | `menu_zoom_step?` | `number` | `2` | Multiplicative menu zoom factor. Must be finite and greater than 1; does not affect wheel or drag sensitivity. |
2997
3019
 
2998
3020
  Setting both axes to `false` disables zoom and pan. Categorical axes do not zoom.
2999
3021
 
3000
3022
  ### Controlling the viewport
3001
3023
 
3002
- Use the buttons to focus on a range or restore the full extent. You can still zoom and pan horizontally with Ctrl after a button sets the view.
3024
+ Use the buttons to focus on a range or restore the full extent. You can still zoom and pan horizontally after a button sets the view.
3003
3025
 
3004
3026
  Set `viewport` to control the visible range. Increment its `key` to apply a new request after the user zooms or pans. See [Viewport](#viewport) for initialization and reset behavior.
3005
3027
 
@@ -3014,7 +3036,7 @@ const plot = document.createElement('a-plot') as APlotElement
3014
3036
  const output = document.createElement('output')
3015
3037
  output.setAttribute('aria-live', 'polite')
3016
3038
  output.style.display = 'block'
3017
- output.textContent = 'Hold Ctrl and scroll to zoom, or Ctrl-drag to pan.'
3039
+ output.textContent = 'Scroll to zoom, drag to pan, or Ctrl-drag to zoom to a rectangle.'
3018
3040
 
3019
3041
  const data = Array.from({ length: 201 }, (_, i) => ({
3020
3042
  x: i / 2,
@@ -3023,7 +3045,7 @@ const data = Array.from({ length: 201 }, (_, i) => ({
3023
3045
 
3024
3046
  plot.plotArgs = {
3025
3047
  series: [
3026
- line<Node>({
3048
+ line({
3027
3049
  data, width: 2,
3028
3050
  color: { light: '#6366f1', dark: '#a5b4fc' },
3029
3051
  tooltip: true,
@@ -3036,7 +3058,7 @@ plot.plotArgs = {
3036
3058
  chrome_color: { light: '#e2e8f0', dark: '#334155' },
3037
3059
  grid: false,
3038
3060
  border: false,
3039
- zoom_pan: { x: true, y: false, modifier: true },
3061
+ zoom_pan: { x: true, y: false },
3040
3062
  viewport: { x: [20, 45], y: null, key: 0 },
3041
3063
  on_viewport_change: ({ x, y }) => {
3042
3064
  const format = (axis: { window: number[] } | null) => axis
@@ -3086,6 +3108,7 @@ to continuous axes.
3086
3108
  |---|---|---|
3087
3109
  | `x` | `AxisViewport \| null` | Current horizontal viewport, or `null` for a categorical axis. |
3088
3110
  | `y` | `AxisViewport \| null` | Current vertical viewport, or `null` for a categorical axis. |
3111
+ | `zoom_factor` | `{ x: number; y: number }` | Per-axis gesture magnification, initially 1; preserved during pan, resize, and data-domain changes. |
3089
3112
 
3090
3113
  Each `AxisViewport` contains:
3091
3114
 
@@ -3096,6 +3119,68 @@ Each `AxisViewport` contains:
3096
3119
 
3097
3120
  ## Configuration details
3098
3121
 
3122
+ ### Size
3123
+
3124
+ Scatter `size` accepts a fixed pixel diameter or a pure accessor returning a number.
3125
+ The accessor receives `(row, index, viewport)`, so you can combine data and viewport
3126
+ without storing zoom in application state.
3127
+
3128
+ Scroll near **50**. The first series stays at 4px. The other series
3129
+ alternate between 2px and 4px based on their data, then grow with horizontal zoom,
3130
+ at different rates, up to 16px. Drag to pan; **Reset Zoom** in the context menu restores
3131
+ the starting sizes.
3132
+
3133
+ ```ts
3134
+ import { scatter, type PlotArgs } from '@antadesign/plot'
3135
+ import '@antadesign/plot/elements/a-plot'
3136
+ import type { APlotElement } from '@antadesign/plot/browser'
3137
+
3138
+ export function viewportSizes(): PlotArgs<Node> {
3139
+ const labels = ['Fixed 4px', 'Data + gradual zoom', 'Data + faster zoom']
3140
+ const positions = [0, 10, 25, 40, 45, 48, 49, 49.5, 49.75, 50, 50.25, 50.5, 51, 52, 55, 60, 75, 90, 100]
3141
+ const rows = (label: string) => positions.map((x, i) => ({ x, y: label, weight: i % 2 ? 4 : 2 }))
3142
+ return {
3143
+ height: 260,
3144
+ margin: { top: 24, right: 20, bottom: 48, left: 160 },
3145
+ axis: { x: { min: 0, max: 100, label: 'Zoom near 50' }, y: { categories: labels, label: '' } },
3146
+ background: { light: '#ffffff', dark: '#202124' },
3147
+ chrome_color: { light: '#64748b', dark: '#cbd5e1' },
3148
+ grid: false,
3149
+ zoom_pan: { x: true, y: false },
3150
+ series: [
3151
+ scatter({ data: rows(labels[0]), size: 4,
3152
+ color: { light: '#64748b', dark: '#cbd5e1' }, tooltip: true }),
3153
+ scatter({ data: rows(labels[1]),
3154
+ size: (row, index, viewport) => Math.min(16, Number(row.weight) * viewport.zoom_factor.x ** 0.25),
3155
+ color: { light: '#7c3aed', dark: '#c4b5fd' }, tooltip: true }),
3156
+ scatter({ data: rows(labels[2]),
3157
+ size: (row, index, viewport) => Math.min(16, Number(row.weight) * viewport.zoom_factor.x ** 0.5),
3158
+ color: { light: '#c2410c', dark: '#fdba74' }, tooltip: true }),
3159
+ ],
3160
+ }
3161
+ }
3162
+
3163
+ const plot = document.createElement('a-plot') as APlotElement
3164
+ plot.plotArgs = viewportSizes()
3165
+ document.body.append(plot)
3166
+ ```
3167
+
3168
+ `viewport` has the same shape as [Viewport changes](#viewport-changes): `x` and `y`
3169
+ contain visible and full domains (`null` for a categorical axis), and `zoom_factor.x` and
3170
+ `zoom_factor.y` contain gesture magnification. Each starts at 1. Panning, resizing, and
3171
+ data-domain changes preserve magnification. Reset and new keyed viewport requests
3172
+ establish factor 1 on their affected axes. Zooming out beyond a requested initial
3173
+ window can yield factors below 1. Use `Math.max(viewport.zoom_factor.x, viewport.zoom_factor.y)`
3174
+ to follow the more magnified axis.
3175
+
3176
+ Size accessors run during composition, including zoom and pan, rather than when
3177
+ the series is constructed. Keep them pure and inexpensive. Existing accessors
3178
+ that only read the row or index remain valid. Returned sizes must be finite and
3179
+ non-negative; invalid results report a composition error and retain the previous
3180
+ plot. Numeric row `size` fields take precedence, and the index stays tied to the
3181
+ original input row after category filtering. Drawing, hit testing, and highlights
3182
+ reuse the composed sizes. Other series' size options and font sizes remain numeric.
3183
+
3099
3184
  ### Font
3100
3185
 
3101
3186
  `font` on the plot supplies shared text settings. `title.font`,
@@ -3140,7 +3225,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3140
3225
 
3141
3226
  function base(): PlotArgs<Node> {
3142
3227
  return {
3143
- series: [scatter<Node>({ data: [
3228
+ series: [scatter({ data: [
3144
3229
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3145
3230
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3146
3231
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3192,7 +3277,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3192
3277
 
3193
3278
  function base(): PlotArgs<Node> {
3194
3279
  return {
3195
- series: [scatter<Node>({ data: [
3280
+ series: [scatter({ data: [
3196
3281
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3197
3282
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3198
3283
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3248,7 +3333,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3248
3333
 
3249
3334
  function base(): PlotArgs<Node> {
3250
3335
  return {
3251
- series: [scatter<Node>({ data: [
3336
+ series: [scatter({ data: [
3252
3337
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3253
3338
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3254
3339
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3291,7 +3376,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3291
3376
 
3292
3377
  function base(): PlotArgs<Node> {
3293
3378
  return {
3294
- series: [scatter<Node>({ data: [
3379
+ series: [scatter({ data: [
3295
3380
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3296
3381
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3297
3382
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3344,7 +3429,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3344
3429
 
3345
3430
  function base(): PlotArgs<Node> {
3346
3431
  return {
3347
- series: [scatter<Node>({ data: [
3432
+ series: [scatter({ data: [
3348
3433
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3349
3434
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3350
3435
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3362,7 +3447,7 @@ function base(): PlotArgs<Node> {
3362
3447
  function grid(): PlotArgs<Node> {
3363
3448
  const categories = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
3364
3449
  return { ...base(), height: 160, margin: { top: 10, right: 10, bottom: 10, left: 10 },
3365
- series: [scatter<Node>({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3450
+ series: [scatter({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3366
3451
  size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
3367
3452
  axis: { x: { categories, label: '', tick_mark: false, tick_label: { format: () => '' } },
3368
3453
  y: { min: 0, max: 100, label: '', tick_mark: false, tick_label: { format: () => '' } } },
@@ -3383,7 +3468,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3383
3468
 
3384
3469
  function base(): PlotArgs<Node> {
3385
3470
  return {
3386
- series: [scatter<Node>({ data: [
3471
+ series: [scatter({ data: [
3387
3472
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3388
3473
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3389
3474
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3401,7 +3486,7 @@ function base(): PlotArgs<Node> {
3401
3486
  function grid(): PlotArgs<Node> {
3402
3487
  const categories = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
3403
3488
  return { ...base(), height: 160, margin: { top: 10, right: 10, bottom: 10, left: 10 },
3404
- series: [scatter<Node>({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3489
+ series: [scatter({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3405
3490
  size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
3406
3491
  axis: { x: { categories, label: '', tick_mark: false, tick_label: { format: () => '' } },
3407
3492
  y: { min: 0, max: 100, label: '', tick_mark: false, tick_label: { format: () => '' } } },
@@ -3426,7 +3511,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3426
3511
 
3427
3512
  function base(): PlotArgs<Node> {
3428
3513
  return {
3429
- series: [scatter<Node>({ data: [
3514
+ series: [scatter({ data: [
3430
3515
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3431
3516
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3432
3517
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3444,7 +3529,7 @@ function base(): PlotArgs<Node> {
3444
3529
  function grid(): PlotArgs<Node> {
3445
3530
  const categories = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
3446
3531
  return { ...base(), height: 160, margin: { top: 10, right: 10, bottom: 10, left: 10 },
3447
- series: [scatter<Node>({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3532
+ series: [scatter({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3448
3533
  size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
3449
3534
  axis: { x: { categories, label: '', tick_mark: false, tick_label: { format: () => '' } },
3450
3535
  y: { min: 0, max: 100, label: '', tick_mark: false, tick_label: { format: () => '' } } },
@@ -3469,7 +3554,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3469
3554
 
3470
3555
  function base(): PlotArgs<Node> {
3471
3556
  return {
3472
- series: [scatter<Node>({ data: [
3557
+ series: [scatter({ data: [
3473
3558
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3474
3559
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3475
3560
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3487,7 +3572,7 @@ function base(): PlotArgs<Node> {
3487
3572
  function grid(): PlotArgs<Node> {
3488
3573
  const categories = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
3489
3574
  return { ...base(), height: 160, margin: { top: 10, right: 10, bottom: 10, left: 10 },
3490
- series: [scatter<Node>({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3575
+ series: [scatter({ data: categories.map((x, i) => ({ x, y: 20 + i * 9 })),
3491
3576
  size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
3492
3577
  axis: { x: { categories, label: '', tick_mark: false, tick_label: { format: () => '' } },
3493
3578
  y: { min: 0, max: 100, label: '', tick_mark: false, tick_label: { format: () => '' } } },
@@ -3521,7 +3606,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3521
3606
 
3522
3607
  function base(): PlotArgs<Node> {
3523
3608
  return {
3524
- series: [scatter<Node>({ data: [
3609
+ series: [scatter({ data: [
3525
3610
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3526
3611
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3527
3612
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3537,7 +3622,7 @@ function base(): PlotArgs<Node> {
3537
3622
  }
3538
3623
 
3539
3624
  function themeColors(): PlotArgs<Node> {
3540
- return { ...base(), series: [scatter<Node>({
3625
+ return { ...base(), series: [scatter({
3541
3626
  data: [{ x: 20, y: 30 }, { x: 50, y: 65 }, { x: 80, y: 45 }],
3542
3627
  size: 18, color: { light: 'tomato', dark: 'lightskyblue' }, hoverable: false,
3543
3628
  })] }
@@ -3572,7 +3657,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3572
3657
 
3573
3658
  function base(): PlotArgs<Node> {
3574
3659
  return {
3575
- series: [scatter<Node>({ data: [
3660
+ series: [scatter({ data: [
3576
3661
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3577
3662
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3578
3663
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3589,7 +3674,7 @@ function base(): PlotArgs<Node> {
3589
3674
 
3590
3675
  function scales(): PlotArgs<Node> {
3591
3676
  return { ...base(),
3592
- series: [scatter<Node>({ data: [1, 10, 100, 1000, 10000].map((y, i) => ({ x: 10 + i * 20, y })),
3677
+ series: [scatter({ data: [1, 10, 100, 1000, 10000].map((y, i) => ({ x: 10 + i * 20, y })),
3593
3678
  size: 4, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
3594
3679
  axis: { x: { scale: 'linear', min: 0, max: 100, label: 'Linear' },
3595
3680
  y: { scale: 'log', min: 1, max: 10000, label: 'Logarithmic',
@@ -3612,7 +3697,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3612
3697
 
3613
3698
  function base(): PlotArgs<Node> {
3614
3699
  return {
3615
- series: [scatter<Node>({ data: [
3700
+ series: [scatter({ data: [
3616
3701
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3617
3702
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3618
3703
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3630,7 +3715,7 @@ function base(): PlotArgs<Node> {
3630
3715
  function timeCategory(): PlotArgs<Node> {
3631
3716
  const start = new Date(2026, 0, 12).getTime()
3632
3717
  return { ...base(),
3633
- series: [scatter<Node>({ data: [
3718
+ series: [scatter({ data: [
3634
3719
  { x: start, y: 'Alpha' }, { x: start + 3600000, y: 'Beta' },
3635
3720
  { x: start + 7200000, y: 'Alpha' }, { x: start + 10800000, y: 'Gamma' },
3636
3721
  { x: start + 14400000, y: 'Beta' },
@@ -3674,7 +3759,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3674
3759
 
3675
3760
  function base(): PlotArgs<Node> {
3676
3761
  return {
3677
- series: [scatter<Node>({ data: [
3762
+ series: [scatter({ data: [
3678
3763
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3679
3764
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3680
3765
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3710,7 +3795,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3710
3795
 
3711
3796
  function base(): PlotArgs<Node> {
3712
3797
  return {
3713
- series: [scatter<Node>({ data: [
3798
+ series: [scatter({ data: [
3714
3799
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3715
3800
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3716
3801
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3758,7 +3843,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3758
3843
 
3759
3844
  function base(): PlotArgs<Node> {
3760
3845
  return {
3761
- series: [scatter<Node>({ data: [
3846
+ series: [scatter({ data: [
3762
3847
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3763
3848
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3764
3849
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3803,7 +3888,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3803
3888
 
3804
3889
  function base(): PlotArgs<Node> {
3805
3890
  return {
3806
- series: [scatter<Node>({ data: [
3891
+ series: [scatter({ data: [
3807
3892
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3808
3893
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3809
3894
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3819,7 +3904,7 @@ function base(): PlotArgs<Node> {
3819
3904
  }
3820
3905
 
3821
3906
  function seriesColors(): PlotArgs<Node> {
3822
- return { ...base(), series: [scatter<Node>({
3907
+ return { ...base(), series: [scatter({
3823
3908
  data: [{ x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 }, { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 }],
3824
3909
  size: 8, color: row => Number(row.y) >= 60
3825
3910
  ? { light: '#c2410c', dark: '#fdba74' } : { light: '#64748b', dark: '#94a3b8' },
@@ -3838,12 +3923,12 @@ and custom series accept it; line and area use one `ThemeColor` per series.
3838
3923
  | Form | Type | Description |
3839
3924
  |---|---|---|
3840
3925
  | Shared color | [`ThemeColor`](#theme-colors) | Apply one color or theme pair to the series. |
3841
- | Accessor | [`(row: Record<string, unknown>, index: number) => ThemeColor`](#theme-colors) | Choose a color or theme pair for each row. |
3926
+ | Accessor | [`(row: Row, index: number) => ThemeColor`](#theme-colors) | Choose a color or theme pair for each row. |
3842
3927
 
3843
3928
  ```ts
3844
3929
  import type { ColorArg } from '@antadesign/plot'
3845
3930
 
3846
- const color: ColorArg = (row) => Number(row.value) >= 10 ? 'coral' : 'steelblue'
3931
+ const color: ColorArg<{ value: number }> = (row) => row.value >= 10 ? 'coral' : 'steelblue'
3847
3932
  ```
3848
3933
 
3849
3934
  For these series, a valid `color` on a data row takes precedence over the
@@ -3861,7 +3946,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3861
3946
 
3862
3947
  function base(): PlotArgs<Node> {
3863
3948
  return {
3864
- series: [scatter<Node>({ data: [
3949
+ series: [scatter({ data: [
3865
3950
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3866
3951
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3867
3952
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3878,7 +3963,7 @@ function base(): PlotArgs<Node> {
3878
3963
 
3879
3964
  function markShapes(): PlotArgs<Node> {
3880
3965
  const marks = ['circle', 'square', 'diamond', 'triangle'] as const
3881
- return { ...base(), series: marks.map((mark, i) => scatter<Node>({
3966
+ return { ...base(), series: marks.map((mark, i) => scatter({
3882
3967
  data: [{ x: mark, y: 40 + i * 10 }], mark, size: 12,
3883
3968
  color: [
3884
3969
  { light: '#7c3aed', dark: '#c4b5fd' }, { light: '#db2777', dark: '#f9a8d4' },
@@ -3916,7 +4001,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
3916
4001
 
3917
4002
  function base(): PlotArgs<Node> {
3918
4003
  return {
3919
- series: [scatter<Node>({ data: [
4004
+ series: [scatter({ data: [
3920
4005
  { x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
3921
4006
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 },
3922
4007
  ], size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false })],
@@ -3932,7 +4017,7 @@ function base(): PlotArgs<Node> {
3932
4017
  }
3933
4018
 
3934
4019
  function strokes(): PlotArgs<Node> {
3935
- return { ...base(), series: [1, 3, 5].map((width, i) => scatter<Node>({
4020
+ return { ...base(), series: [1, 3, 5].map((width, i) => scatter({
3936
4021
  data: [{ x: 25 + i * 25, y: 50 }], size: 18,
3937
4022
  color: { light: '#f0abfc', dark: '#c026d3' },
3938
4023
  stroke: { color: { light: '#7e22ce', dark: '#f5d0fe' }, width }, hoverable: false,
@@ -3968,25 +4053,26 @@ such as `x` and `y`, or for a second boundary where the series supports one.
3968
4053
 
3969
4054
  | Form | Type | Description |
3970
4055
  |---|---|---|
3971
- | Field name | `string` | Read the named property from each row. |
3972
- | Accessor | `(row: Record<string, unknown>, index: number) => number \| string` | Compute a value from the row and its zero-based index. Return numbers for continuous axes or strings for categories. |
4056
+ | Field name | `keyof Row & string` | Read the named property from each row. |
4057
+ | Accessor | `(row: Row, index: number) => number \| string` | Compute a value from the row and its zero-based index. Return numbers for continuous axes or strings for categories. |
3973
4058
 
3974
4059
  ```ts
3975
4060
  import type { FieldArg } from '@antadesign/plot'
3976
4061
 
3977
- const x: FieldArg = 'elapsed_ms'
3978
- const y: FieldArg = (row) => Number(row.duration_ms) / 1000
4062
+ type Timing = { elapsed_ms: number; duration_ms: number }
4063
+ const x: FieldArg<Timing> = 'elapsed_ms'
4064
+ const y: FieldArg<Timing> = (row) => row.duration_ms / 1000
3979
4065
  ```
3980
4066
 
3981
4067
  ### Custom rendering
3982
4068
 
3983
- `CustomRendererFn<TooltipContent>` receives the composed custom series and
4069
+ `CustomRendererFn<Row>` receives a `CustomSeriesView<Row>` and
3984
4070
  its drawing context:
3985
4071
 
3986
4072
  ```ts
3987
- import type { ComposedCustom, CustomRenderContext } from '@antadesign/plot'
4073
+ import type { CustomSeriesView, CustomRenderContext } from '@antadesign/plot'
3988
4074
 
3989
- type Renderer = (series: ComposedCustom, context: CustomRenderContext) => void
4075
+ type Renderer<Row> = (series: CustomSeriesView<Row>, context: CustomRenderContext) => void
3990
4076
  ```
3991
4077
 
3992
4078
  The composed series contains resolved `x` and `y` columns, source `rows` when
@@ -4052,7 +4138,7 @@ import type { APlotElement } from '@antadesign/plot/browser'
4052
4138
 
4053
4139
  function stylingExample(): PlotArgs<Node> {
4054
4140
  return {
4055
- series: [scatter<Node>({
4141
+ series: [scatter({
4056
4142
  data: [{ x: 12, y: 18 }, { x: 30, y: 42 }, { x: 48, y: 35 },
4057
4143
  { x: 58, y: 64 }, { x: 76, y: 58 }, { x: 88, y: 82 }],
4058
4144
  size: 3, color: { light: '#9ca3af', dark: '#6b7280' }, hoverable: false,
@@ -4121,5 +4207,4 @@ Set text colors separately with `title.font.color`, `axis.x.label.font.color`,
4121
4207
 
4122
4208
  With the JSX `Plot` component, return content supported by your renderer from a
4123
4209
  series’ [`tooltip`](#tooltips) callback and style it like other markup. Anta’s
4124
- `Tooltip` renders that content in the component tree. The reset control is an Anta `Button` and
4125
- follows the application’s theme.
4210
+ `Tooltip` renders that content in the component tree. The zoom context menu uses Anta `Menu` and follows the application’s theme.