react-msaview 9.1.1 → 9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/bundle/index.js +79 -79
  2. package/bundle/index.js.map +4 -4
  3. package/dist/components/DragHandle.js +2 -1
  4. package/dist/components/DragHandle.js.map +1 -1
  5. package/dist/components/MSAViewer.d.ts +31 -19
  6. package/dist/components/MSAViewer.js +2 -1
  7. package/dist/components/MSAViewer.js.map +1 -1
  8. package/dist/components/Track.js +2 -5
  9. package/dist/components/Track.js.map +1 -1
  10. package/dist/components/VerticalScrollbar.js +1 -1
  11. package/dist/components/VerticalScrollbar.js.map +1 -1
  12. package/dist/components/header/Header.js +2 -1
  13. package/dist/components/header/Header.js.map +1 -1
  14. package/dist/components/minimap/Minimap.js +1 -1
  15. package/dist/components/minimap/Minimap.js.map +1 -1
  16. package/dist/components/msa/MSACanvas.js +16 -27
  17. package/dist/components/msa/MSACanvas.js.map +1 -1
  18. package/dist/components/rowpanels/RowPanels.js +8 -6
  19. package/dist/components/rowpanels/RowPanels.js.map +1 -1
  20. package/dist/components/settings/SettingsPanel.js +2 -1
  21. package/dist/components/settings/SettingsPanel.js.map +1 -1
  22. package/dist/components/settings/TrackList.js +8 -5
  23. package/dist/components/settings/TrackList.js.map +1 -1
  24. package/dist/components/tracks/TrackTooltipContent.js +2 -1
  25. package/dist/components/tracks/TrackTooltipContent.js.map +1 -1
  26. package/dist/components/tracks/drawTracks.js +13 -6
  27. package/dist/components/tracks/drawTracks.js.map +1 -1
  28. package/dist/components/tree/TreeCanvas.js +8 -6
  29. package/dist/components/tree/TreeCanvas.js.map +1 -1
  30. package/dist/constants.d.ts +1 -0
  31. package/dist/constants.js +2 -0
  32. package/dist/constants.js.map +1 -1
  33. package/dist/element.d.ts +11 -7
  34. package/dist/element.js +46 -8
  35. package/dist/element.js.map +1 -1
  36. package/dist/featurePanels.d.ts +0 -7
  37. package/dist/featurePanels.js +1 -16
  38. package/dist/featurePanels.js.map +1 -1
  39. package/dist/ggplotPalettes.js +12 -1
  40. package/dist/ggplotPalettes.js.map +1 -1
  41. package/dist/groupKeys.d.ts +6 -0
  42. package/dist/groupKeys.js +52 -0
  43. package/dist/groupKeys.js.map +1 -0
  44. package/dist/index.d.ts +1 -1
  45. package/dist/model.d.ts +40 -17
  46. package/dist/model.js +123 -54
  47. package/dist/model.js.map +1 -1
  48. package/dist/scales.d.ts +114 -13
  49. package/dist/scales.js +154 -19
  50. package/dist/scales.js.map +1 -1
  51. package/dist/svgTestUtil.d.ts +22 -12
  52. package/dist/types.d.ts +30 -28
  53. package/dist/useDragScroll.d.ts +4 -3
  54. package/dist/useDragScroll.js +9 -6
  55. package/dist/useDragScroll.js.map +1 -1
  56. package/dist/useWheelScroll.d.ts +26 -8
  57. package/dist/useWheelScroll.js +108 -71
  58. package/dist/useWheelScroll.js.map +1 -1
  59. package/dist/version.d.ts +1 -1
  60. package/dist/version.js +1 -1
  61. package/dist/viewerSnapshot.js +2 -1
  62. package/dist/viewerSnapshot.js.map +1 -1
  63. package/package.json +3 -3
  64. package/src/components/DragHandle.tsx +2 -1
  65. package/src/components/MSAViewer.tsx +11 -8
  66. package/src/components/Track.tsx +2 -8
  67. package/src/components/VerticalScrollbar.tsx +1 -1
  68. package/src/components/header/Header.tsx +2 -1
  69. package/src/components/minimap/Minimap.tsx +1 -1
  70. package/src/components/msa/MSACanvas.tsx +14 -35
  71. package/src/components/rowpanels/RowPanels.tsx +8 -10
  72. package/src/components/settings/SettingsPanel.tsx +2 -1
  73. package/src/components/settings/TrackList.tsx +9 -4
  74. package/src/components/tracks/TrackTooltipContent.tsx +2 -1
  75. package/src/components/tracks/drawTracks.ts +15 -7
  76. package/src/components/tree/TreeCanvas.tsx +8 -10
  77. package/src/constants.ts +2 -0
  78. package/src/element.ts +53 -8
  79. package/src/featurePanels.ts +1 -25
  80. package/src/ggplotPalettes.ts +13 -1
  81. package/src/groupKeys.ts +54 -0
  82. package/src/index.ts +13 -2
  83. package/src/model.ts +174 -72
  84. package/src/scales.ts +268 -25
  85. package/src/types.ts +29 -26
  86. package/src/useDragScroll.ts +11 -8
  87. package/src/useWheelScroll.ts +124 -84
  88. package/src/version.ts +1 -1
  89. package/src/viewerSnapshot.ts +3 -1
package/src/scales.ts CHANGED
@@ -1,12 +1,42 @@
1
+ import { colord } from 'colord'
2
+
1
3
  import { createPaletteMap } from './createPaletteMap.ts'
2
4
  import { paletteNamed } from './ggplotPalettes.ts'
5
+ import { compareGroupKeys } from './groupKeys.ts'
3
6
 
4
- import type { LegendEntry } from './types.ts'
7
+ import type {
8
+ ColorScheme,
9
+ ColumnTrackSpec,
10
+ Encoding,
11
+ LegendEntry,
12
+ RowPanelSpec,
13
+ } from './types.ts'
5
14
 
6
- /** how a channel reads a field: a palette by name, or a color per value */
7
- export interface ScaleSpec {
8
- palette?: string
9
- map?: Record<string, string>
15
+ /**
16
+ * The color object: the scale a channel reads its field through, the members
17
+ * jbrowse-components' displays declare (its ADR-151). The values the field
18
+ * takes are the scale's domain, `range` holds the colors they map onto, and
19
+ * the legend is the guide listing each value with its color.
20
+ *
21
+ * - `scale`: the kind, `categorical` when unset and the only kind so far
22
+ * - `domain`: values in legend order, each taking the `range` color at its own
23
+ * index; the field's other values follow in natural order
24
+ * - `range`: a palette name (`ggplot`, `set1`, `dark2`, `okabeito`, `tableau`)
25
+ * or a list of colors, which colors as many values as it holds
26
+ * - `title`: the legend's title, the field when unset
27
+ *
28
+ * Records declaring the same members, `title` included, share one scale.
29
+ */
30
+ export interface ColorSpec {
31
+ scale?: 'categorical'
32
+ domain?: string[]
33
+ range?: string | string[]
34
+ title?: string
35
+ }
36
+
37
+ /** a channel record: a field read through a color object */
38
+ export interface ColorChannel extends ColorSpec {
39
+ field: string
10
40
  }
11
41
 
12
42
  export interface ResolvedScale {
@@ -16,32 +46,245 @@ export interface ResolvedScale {
16
46
  }
17
47
 
18
48
  /**
19
- * The scale a channel reads its field through. `values` are the field's values,
20
- * in any order and with repeats; the domain is their distinct values sorted, so
21
- * a value keeps its color when rows are re-ordered, collapsed or filtered.
49
+ * The colors a `range` lists, read the way jbrowse-components'
50
+ * `paletteFromSpec` reads a string: a palette name gives undefined here, and a
51
+ * comma-separated list of colors gives the list
52
+ */
53
+ function rangeList(range: ColorSpec['range']) {
54
+ if (typeof range !== 'string') {
55
+ return range
56
+ }
57
+ if (paletteNamed(range)) {
58
+ return undefined
59
+ }
60
+ const colors = range.split(/,(?![^(]*\))/).map(c => c.trim())
61
+ return colors.every(c => colord(c).isValid()) ? colors : undefined
62
+ }
63
+
64
+ function rangeColors(range: ColorSpec['range'], order: string[]) {
65
+ const list = rangeList(range)
66
+ return list
67
+ ? new Map(order.slice(0, list.length).map((value, i) => [value, list[i]!]))
68
+ : new Map(
69
+ Object.entries(
70
+ createPaletteMap(
71
+ order,
72
+ paletteNamed(typeof range === 'string' ? range : undefined),
73
+ ),
74
+ ),
75
+ )
76
+ }
77
+
78
+ /**
79
+ * The scale a channel reads its field through. `values` are the field's
80
+ * values, in any order and with repeats. The domain lists the values `domain`
81
+ * names first, then the rest in natural order, so a value keeps its color when
82
+ * rows are re-ordered, collapsed or filtered.
22
83
  *
23
- * `{map}` colors the values the producer named and leaves the rest uncolored.
24
- * `{palette}` takes the colors of a named palette, and a spec with neither
25
- * takes the ggplot palette of the domain's size. Every scale is categorical
26
- * today; a continuous one waits for a caller.
84
+ * A palette name, or no `range` at all, colors every value: past the end of
85
+ * the palette each takes an evenly spaced hue. A list of colors leaves the
86
+ * values past its end uncolored, so `{domain, range}` colors the values it
87
+ * names and no others.
27
88
  */
28
89
  export function resolveScale(
29
- spec: ScaleSpec | undefined,
90
+ spec: ColorSpec | undefined,
30
91
  values: Iterable<string>,
31
92
  ): ResolvedScale {
32
- const domain = [...new Set(values)].sort((a, b) => a.localeCompare(b))
33
- const { map, palette } = spec ?? {}
34
- const colors = map ?? createPaletteMap(domain, paletteNamed(palette))
35
- const present = new Set(domain)
36
- const labels = map ? Object.keys(map).filter(v => present.has(v)) : domain
93
+ const present = new Set(values)
94
+ const listed = new Set(spec?.domain)
95
+ const order = [
96
+ ...listed,
97
+ ...[...present].filter(v => !listed.has(v)).sort(compareGroupKeys),
98
+ ]
99
+ const colors = rangeColors(spec?.range, order)
37
100
  return {
38
101
  kind: 'categorical',
39
- colorOf: (value: string) => colors[value],
40
- // a categorical value is its own label, and the id a legend keys on
41
- legend: labels.map(value => ({
42
- id: value,
43
- label: value,
44
- color: colors[value]!,
45
- })),
102
+ colorOf: (value: string) => colors.get(value),
103
+ legend: order
104
+ .filter(value => present.has(value) && colors.has(value))
105
+ .map(value => ({ id: value, label: value, color: colors.get(value)! })),
46
106
  }
47
107
  }
108
+
109
+ /** which table a record's field is read from */
110
+ export type ScaleTable = 'rows' | 'features'
111
+
112
+ /**
113
+ * One record's use of a color object: the values its field takes in its
114
+ * table, and for the feature table the values the drawn features carry, which
115
+ * the legend lists
116
+ */
117
+ export interface ScaleUse {
118
+ spec: ColorSpec
119
+ field: string
120
+ table: ScaleTable
121
+ values: string[]
122
+ shown?: string[]
123
+ }
124
+
125
+ export interface SharedScale extends ResolvedScale {
126
+ key: string
127
+ title: string
128
+ }
129
+
130
+ /**
131
+ * The key records share a scale under: the table and the members as declared,
132
+ * with `title` standing in for the field. Two strips over one palette with no
133
+ * title read two fields and list two legends; naming one title gives them one
134
+ * scale and one legend.
135
+ */
136
+ export function declarationKey({
137
+ spec,
138
+ field,
139
+ table,
140
+ }: Pick<ScaleUse, 'spec' | 'field' | 'table'>) {
141
+ const { scale = 'categorical', domain, range, title = field } = spec
142
+ return JSON.stringify([table, scale, domain, range, title])
143
+ }
144
+
145
+ /**
146
+ * Resolves each declaration once over the union of its records' values, so a
147
+ * value two fields share takes one color in both
148
+ */
149
+ export function resolveShared(uses: ScaleUse[]) {
150
+ const groups = new Map<string, ScaleUse[]>()
151
+ for (const use of uses) {
152
+ const key = declarationKey(use)
153
+ groups.set(key, [...(groups.get(key) ?? []), use])
154
+ }
155
+ return new Map(
156
+ [...groups].map(([key, group]) => {
157
+ const { spec, field } = group[0]!
158
+ const resolved = resolveScale(
159
+ spec,
160
+ group.flatMap(u => u.values),
161
+ )
162
+ const shown = group[0]!.shown
163
+ ? new Set(group.flatMap(u => u.shown ?? []))
164
+ : undefined
165
+ const scale: SharedScale = {
166
+ ...resolved,
167
+ key,
168
+ title: spec.title ?? field,
169
+ legend: shown
170
+ ? resolved.legend.filter(entry => shown.has(entry.id))
171
+ : resolved.legend,
172
+ }
173
+ return [key, scale] as const
174
+ }),
175
+ )
176
+ }
177
+
178
+ /** the spelling a color object had before ADR-151's: `{palette}` or `{map}` */
179
+ export interface LegacyScale {
180
+ palette?: string
181
+ map?: Record<string, string>
182
+ }
183
+
184
+ /** a record as an older snapshot, R or Python may write it */
185
+ export type LegacyColor<T extends ColorSpec> = Omit<T, 'scale'> & {
186
+ scale?: ColorSpec['scale'] | LegacyScale
187
+ legend?: string
188
+ }
189
+
190
+ /**
191
+ * Lifts the earlier spelling onto the color object: `{palette: p}` reads as
192
+ * `{range: p}`, `{map: m}` as `{domain: keys(m), range: values(m)}`, and a
193
+ * strip's `legend` as `title`. A member written in the new spelling wins.
194
+ */
195
+ export function readColor<T extends ColorSpec>(record: LegacyColor<T>): T {
196
+ const { scale, legend, ...rest } = record
197
+ if (typeof scale !== 'object' && legend === undefined) {
198
+ return record as T
199
+ }
200
+ const lifted: ColorSpec =
201
+ typeof scale !== 'object'
202
+ ? scale === undefined
203
+ ? {}
204
+ : { scale }
205
+ : scale.map
206
+ ? { domain: Object.keys(scale.map), range: Object.values(scale.map) }
207
+ : scale.palette === undefined
208
+ ? {}
209
+ : { range: scale.palette }
210
+ return {
211
+ ...(legend === undefined ? {} : { title: legend }),
212
+ ...lifted,
213
+ ...rest,
214
+ } as unknown as T
215
+ }
216
+
217
+ export type LegacyEncoding = LegacyColor<Encoding>
218
+
219
+ export function readEncoding(encoding: Encoding | LegacyEncoding) {
220
+ return readColor<Encoding>(encoding)
221
+ }
222
+
223
+ export type LegacyRowPanel =
224
+ | LegacyColor<Extract<RowPanelSpec, { kind: 'strip' }>>
225
+ | (Omit<Extract<RowPanelSpec, { kind: 'features' }>, 'encoding'> & {
226
+ encoding?: {
227
+ color?: LegacyColor<ColorChannel>
228
+ label?: string
229
+ }
230
+ })
231
+
232
+ export function readRowPanel(panel: RowPanelSpec | LegacyRowPanel) {
233
+ if (panel.kind === 'strip') {
234
+ return readColor<Extract<RowPanelSpec, { kind: 'strip' }>>(panel)
235
+ }
236
+ const color = panel.encoding?.color
237
+ return (
238
+ color
239
+ ? { ...panel, encoding: { ...panel.encoding, color: readColor(color) } }
240
+ : panel
241
+ ) as RowPanelSpec
242
+ }
243
+
244
+ export type LegacyColumnTrack = ColumnTrackSpec & {
245
+ max?: number
246
+ colors?: Record<string, string>
247
+ }
248
+
249
+ /**
250
+ * Lifts a column track's `colors` onto `encoding.color` and its `max` onto
251
+ * `scales.y.domainMax`
252
+ */
253
+ export function readColumnTrack(track: LegacyColumnTrack): ColumnTrackSpec {
254
+ const { max, colors, ...rest } = track
255
+ if (max === undefined && colors === undefined) {
256
+ return track
257
+ }
258
+ return {
259
+ ...(colors
260
+ ? {
261
+ encoding: {
262
+ color: {
263
+ domain: Object.keys(colors),
264
+ range: Object.values(colors),
265
+ },
266
+ },
267
+ }
268
+ : {}),
269
+ ...(max === undefined ? {} : { scales: { y: { domainMax: max } } }),
270
+ ...rest,
271
+ }
272
+ }
273
+
274
+ /**
275
+ * The color a color object gives each value listed, for a reader that keys
276
+ * colors by value, such as the residue letters of a scheme or a text track
277
+ */
278
+ export function colorTable(spec: ColorSpec, values: Iterable<string>) {
279
+ return Object.fromEntries(
280
+ resolveScale(spec, values).legend.map(e => [e.id, e.color]),
281
+ )
282
+ }
283
+
284
+ /**
285
+ * The letter-to-color table an object `colorScheme` gives, `{domain, range}`
286
+ * or the earlier `{map}`
287
+ */
288
+ export function letterColors(scheme: Exclude<ColorScheme, string>) {
289
+ return 'map' in scheme ? scheme.map : colorTable(scheme, scheme.domain ?? [])
290
+ }
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ResolvedScale, ScaleSpec } from './scales.ts'
1
+ import type { ColorChannel, ColorSpec, SharedScale } from './scales.ts'
2
2
  import type { Annotation } from 'msa-parsers'
3
3
 
4
4
  export interface Accession {
@@ -8,7 +8,7 @@ export interface Accession {
8
8
  }
9
9
  // every kind draws into the same per-column space; drawTracks.ts dispatches on
10
10
  // it to pick the draw function
11
- export type TrackKind = 'text' | 'bar' | 'logo' | 'arc' | 'ruler'
11
+ export type TrackKind = 'text' | 'bar' | 'logo' | 'arc' | 'ruler' | 'reference'
12
12
 
13
13
  /**
14
14
  * Which channel the color scheme paints. `fill` colors the cell a residue sits
@@ -18,11 +18,17 @@ export type TrackKind = 'text' | 'bar' | 'logo' | 'arc' | 'ruler'
18
18
  export type ResidueEncoding = 'fill' | 'color'
19
19
 
20
20
  /**
21
- * The residue colors: a scheme name from the built-in table, or a scale's
22
- * `{map}` of letter to color, which leaves every letter it does not list
23
- * uncolored
21
+ * The residue colors: a scheme name from the built-in table, or a color object
22
+ * over residue letters, `{domain: ['K', 'R'], range: ['#1f77b4', '#1f77b4']}`,
23
+ * which leaves every letter it does not list uncolored
24
24
  */
25
- export type ColorScheme = string | Required<Pick<ScaleSpec, 'map'>>
25
+ export type ColorScheme =
26
+ | string
27
+ | Pick<ColorSpec, 'domain' | 'range'>
28
+ | {
29
+ /** @deprecated the earlier spelling of `{domain, range}` */
30
+ map: Record<string, string>
31
+ }
26
32
 
27
33
  export interface BasicTrackModel {
28
34
  id: string
@@ -75,7 +81,8 @@ export interface ArcSpec {
75
81
  // a track supplied as data in the snapshot rather than computed from the
76
82
  // alignment. `values` (bar) or `data` (text) index alignment columns, or the
77
83
  // 1-based residues of `row` when it names one; `arcs` (arc) name two such
78
- // positions each
84
+ // positions each. `scales.y.domainMax` is the bar value drawn at full height,
85
+ // and a text track's `encoding.color` colors its characters
79
86
  export interface ColumnTrackSpec {
80
87
  id: string
81
88
  name: string
@@ -83,32 +90,29 @@ export interface ColumnTrackSpec {
83
90
  values?: number[]
84
91
  data?: string
85
92
  arcs?: ArcSpec[]
86
- max?: number
87
93
  color?: string
88
- colors?: Record<string, string>
94
+ encoding?: { color?: ColorSpec }
95
+ scales?: { y?: { domainMax?: number } }
89
96
  row?: string
90
97
  height?: number
91
98
  }
92
99
 
93
100
  /**
94
- * A strip panel: one cell per row, colored from a `rowData` field through
95
- * `scale`, which is ggtree's `gheatmap`. `width` is in pixels and defaults to
96
- * the row height, and `header` labels the column and defaults to the field.
97
- * `legend` titles the strip's legend and defaults to the field, and strips
98
- * naming one title share one legend.
101
+ * A strip panel: one cell per row, colored from a `rowData` field through the
102
+ * color object's members, which is ggtree's `gheatmap`. `width` is in pixels
103
+ * and defaults to the row height, and `header` labels the column and defaults
104
+ * to the field. Strips declaring the same members and `title` share one scale
105
+ * and one legend.
99
106
  */
100
- export interface RowStripSpec {
107
+ export interface RowStripSpec extends ColorChannel {
101
108
  kind: 'strip'
102
- field: string
103
- scale?: ScaleSpec
104
109
  width?: number
105
110
  header?: string
106
- legend?: string
107
111
  }
108
112
 
109
113
  /** the channels a `features` panel reads off the feature table */
110
114
  export interface FeatureEncodingSpec {
111
- color?: { field: string; scale?: ScaleSpec }
115
+ color?: ColorChannel
112
116
  label?: string
113
117
  }
114
118
 
@@ -150,7 +154,8 @@ interface ResolvedPanelBase {
150
154
  width: number
151
155
  offsetX: number
152
156
  legend: LegendEntry[]
153
- /** the legend this panel's entries go under; absent means the domain key */
157
+ /** the scale this panel's entries list under; absent means the domain key */
158
+ legendKey?: string
154
159
  legendTitle?: string
155
160
  }
156
161
 
@@ -497,17 +502,15 @@ export type EncodingChannel =
497
502
  | 'featureLabel'
498
503
 
499
504
  /**
500
- * A channel, the field feeding it, and the scale it reads that field through.
501
- * See docs/layers.md
505
+ * A channel, the field feeding it, and the color object's members it reads
506
+ * that field through. See docs/layers.md
502
507
  */
503
- export interface Encoding {
508
+ export interface Encoding extends ColorChannel {
504
509
  channel: EncodingChannel
505
- field: string
506
- scale?: ScaleSpec
507
510
  }
508
511
 
509
512
  /** an Encoding with its scale resolved against the values in the table */
510
- export type ResolvedEncoding = Encoding & ResolvedScale
513
+ export type ResolvedEncoding = Encoding & SharedScale
511
514
 
512
515
  /** a Highlight resolved to visible column indices and row indices */
513
516
  export interface ResolvedHighlight {
@@ -1,8 +1,9 @@
1
1
  import { useEffect, useRef, useState } from 'react'
2
2
 
3
3
  /**
4
- * Tracks a mouse drag along a single axis and reports the scroll delta on each
5
- * animation frame. Shared by the horizontal Minimap and the VerticalScrollbar.
4
+ * Tracks a pointer drag along a single axis and reports the scroll delta on
5
+ * each animation frame. Shared by the horizontal Minimap, the VerticalScrollbar
6
+ * and the dividers.
6
7
  *
7
8
  * `onScroll` is invoked with the pixel delta since drag start and the scroll
8
9
  * offset captured when the drag began. Memoize it (useCallback) so the document
@@ -21,7 +22,7 @@ export function useDragScroll(
21
22
  useEffect(() => {
22
23
  if (mouseDown !== undefined) {
23
24
  const { client: startClient, startScroll } = mouseDown
24
- function onMove(event: MouseEvent) {
25
+ function onMove(event: PointerEvent) {
25
26
  if (!scheduled.current) {
26
27
  scheduled.current = true
27
28
  requestAnimationFrame(() => {
@@ -34,18 +35,20 @@ export function useDragScroll(
34
35
  function onUp() {
35
36
  setMouseDown(undefined)
36
37
  }
37
- document.addEventListener('mousemove', onMove)
38
- document.addEventListener('mouseup', onUp)
38
+ document.addEventListener('pointermove', onMove)
39
+ document.addEventListener('pointerup', onUp)
40
+ document.addEventListener('pointercancel', onUp)
39
41
  return () => {
40
- document.removeEventListener('mousemove', onMove)
41
- document.removeEventListener('mouseup', onUp)
42
+ document.removeEventListener('pointermove', onMove)
43
+ document.removeEventListener('pointerup', onUp)
44
+ document.removeEventListener('pointercancel', onUp)
42
45
  }
43
46
  }
44
47
  }, [axis, onScroll, mouseDown])
45
48
 
46
49
  return {
47
50
  dragging: mouseDown !== undefined,
48
- startDrag: (event: React.MouseEvent, startScroll: number) => {
51
+ startDrag: (event: React.PointerEvent, startScroll: number) => {
49
52
  setMouseDown({
50
53
  client: axis === 'x' ? event.clientX : event.clientY,
51
54
  startScroll,