@tremolo-ui/react 0.7.0 → 0.9.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.
- package/dist/index.cjs +666 -1171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +316 -315
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +316 -315
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +643 -1123
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/components/AnimationCanvas/index.tsx +4 -18
- package/src/components/DropZone/index.tsx +2 -1
- package/src/components/FileInput/index.tsx +11 -13
- package/src/components/Knob/ActiveLine.tsx +5 -3
- package/src/components/Knob/InactiveLine.tsx +6 -4
- package/src/components/Knob/SVGRoot.tsx +3 -3
- package/src/components/Knob/Thumb.tsx +21 -20
- package/src/components/Knob/context.tsx +3 -74
- package/src/components/Knob/index.tsx +99 -52
- package/src/components/NumberInput/InputField.tsx +20 -33
- package/src/components/NumberInput/Stepper.tsx +76 -100
- package/src/components/NumberInput/StepperButton.tsx +15 -8
- package/src/components/NumberInput/context.tsx +26 -3
- package/src/components/NumberInput/index.tsx +175 -91
- package/src/components/Piano/index.tsx +54 -144
- package/src/components/PointsEditor/Container.tsx +15 -26
- package/src/components/PointsEditor/Point.tsx +94 -110
- package/src/components/PointsEditor/context.tsx +8 -60
- package/src/components/PointsEditor/index.tsx +41 -324
- package/src/components/Slider/Marks.tsx +5 -6
- package/src/components/Slider/MarksOption.tsx +9 -19
- package/src/components/Slider/Thumb.tsx +20 -11
- package/src/components/Slider/Track.tsx +16 -13
- package/src/components/Slider/context.tsx +3 -3
- package/src/components/Slider/index.tsx +110 -72
- package/src/components/XYPad/Area.tsx +27 -49
- package/src/components/XYPad/Thumb.tsx +20 -8
- package/src/components/XYPad/context.tsx +2 -4
- package/src/components/XYPad/index.tsx +102 -83
- package/src/components/_util/VisuallyHiddenRangeInput.tsx +1 -1
- package/src/hooks/_internal/useChangeGesture.ts +93 -0
- package/src/hooks/_internal/useCheckSteps.ts +9 -146
- package/src/hooks/useAnimationFrame.ts +37 -15
- package/src/hooks/useEventListener.ts +93 -22
- package/src/hooks/useLongPress.ts +35 -51
- package/src/hooks/useMIDIAccess.ts +0 -8
- package/src/hooks/useMIDIInput.ts +0 -3
- package/src/hooks/useWheel.ts +4 -4
- package/src/index.ts +11 -32
- package/src/components/Piano/keyboard-shortcuts.ts +0 -61
- package/src/components/Slider/type.ts +0 -46
- package/src/components/_util/css-length.ts +0 -13
- package/src/components/_util/decimal-digits.ts +0 -23
- package/src/components/_util/visually-hidden.ts +0 -25
- package/src/hooks/useInterval.ts +0 -27
- package/src/input-event.ts +0 -32
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
CSSProperties,
|
|
4
4
|
forwardRef,
|
|
5
5
|
ReactNode,
|
|
6
|
-
|
|
6
|
+
Ref,
|
|
7
7
|
useEffect,
|
|
8
8
|
useImperativeHandle,
|
|
9
9
|
useMemo,
|
|
@@ -12,43 +12,23 @@ import {
|
|
|
12
12
|
} from 'react'
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
blackKeyWidth,
|
|
16
15
|
createPianoInput,
|
|
17
|
-
|
|
16
|
+
type KeyboardShortcuts,
|
|
17
|
+
type KeyboardShortcutsScope,
|
|
18
18
|
notePosition,
|
|
19
|
-
pianoWidth,
|
|
20
19
|
type NoteRange,
|
|
21
20
|
type PianoInputInstance,
|
|
22
21
|
type PianoLayout,
|
|
23
22
|
} from '@tremolo-ui/dom'
|
|
23
|
+
import {
|
|
24
|
+
blackKeyWidth,
|
|
25
|
+
fitWhiteKeyWidth,
|
|
26
|
+
getNoteRangeArray,
|
|
27
|
+
pianoWidth,
|
|
28
|
+
} from '@tremolo-ui/dom/internal'
|
|
24
29
|
import { isWhiteKey, noteKey } from '@tremolo-ui/functions'
|
|
25
30
|
|
|
26
|
-
import {
|
|
27
|
-
import { cssLength } from '../_util/css-length'
|
|
28
|
-
|
|
29
|
-
import { KeyboardShortcuts } from './keyboard-shortcuts'
|
|
30
|
-
|
|
31
|
-
import type { CSSVariables } from '../../css-variables'
|
|
32
|
-
|
|
33
|
-
type KeyboardShortcutsScope = 'root' | 'window'
|
|
34
|
-
|
|
35
|
-
function isEditableTarget(target: EventTarget | null) {
|
|
36
|
-
if (!(target instanceof HTMLElement)) return false
|
|
37
|
-
if (target.matches('input, textarea, select')) return true
|
|
38
|
-
|
|
39
|
-
for (let element: HTMLElement | null = target; element;) {
|
|
40
|
-
const contentEditable = element.getAttribute('contenteditable')
|
|
41
|
-
if (contentEditable !== null)
|
|
42
|
-
return contentEditable.toLowerCase() !== 'false'
|
|
43
|
-
element = element.parentElement
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return false
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function shortcutKey(event: KeyboardEvent) {
|
|
50
|
-
return event.code || event.key
|
|
51
|
-
}
|
|
31
|
+
import { useComposedRefs } from '../../compose-refs'
|
|
52
32
|
|
|
53
33
|
/**
|
|
54
34
|
* What {@link PianoProps.keyProps} may return for one key.
|
|
@@ -57,10 +37,8 @@ function shortcutKey(event: KeyboardEvent) {
|
|
|
57
37
|
* JSX syntax, not on an object type, and selecting on one is the usual way to
|
|
58
38
|
* mark a key out.
|
|
59
39
|
*/
|
|
60
|
-
export type KeyAttributes =
|
|
61
|
-
|
|
62
|
-
CSSVariables<'color' | 'bg' | 'active-color' | 'active-bg'>
|
|
63
|
-
} & Record<`data-${string}`, string | number | boolean | undefined>
|
|
40
|
+
export type KeyAttributes = ComponentPropsWithoutRef<'div'> &
|
|
41
|
+
Record<`data-${string}`, string | number | boolean | undefined>
|
|
64
42
|
|
|
65
43
|
/** What a key is, when {@link PianoProps.label} or `keyProps` is asked about it. */
|
|
66
44
|
export interface KeyState {
|
|
@@ -151,16 +129,9 @@ export interface PianoProps {
|
|
|
151
129
|
*/
|
|
152
130
|
blackKeyHeightRatio?: number
|
|
153
131
|
|
|
154
|
-
/**
|
|
155
|
-
* Height of the keyboard. Sets `--height`; when it is omitted, the height
|
|
156
|
-
* the theme gives stands, and the theme can tell `resizable` apart through
|
|
157
|
-
* `data-resizable`.
|
|
158
|
-
*/
|
|
159
|
-
height?: number | string
|
|
160
|
-
|
|
161
132
|
/**
|
|
162
133
|
* What to draw inside a key. `''`, `null` and `undefined` leave it bare, so
|
|
163
|
-
* a layout with gaps —
|
|
134
|
+
* a layout with gaps — `SHORTCUTS.HOME_ROW_NATURAL`, say — needs no
|
|
164
135
|
* special casing.
|
|
165
136
|
*/
|
|
166
137
|
label?: (note: number, state: KeyState) => ReactNode
|
|
@@ -190,7 +161,11 @@ export interface PianoProps {
|
|
|
190
161
|
/** Called once everything holding a note has let go of it. */
|
|
191
162
|
onStopNote?: (note: number) => void
|
|
192
163
|
|
|
193
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Receives `playNote` and `stopNote`, which press and release a key as the
|
|
166
|
+
* pointer or the keyboard would. `ref` reaches the root element itself.
|
|
167
|
+
*/
|
|
168
|
+
actionsRef?: Ref<PianoMethods>
|
|
194
169
|
}
|
|
195
170
|
|
|
196
171
|
export interface PianoMethods {
|
|
@@ -201,7 +176,7 @@ export interface PianoMethods {
|
|
|
201
176
|
type Props = PianoProps &
|
|
202
177
|
Omit<ComponentPropsWithoutRef<'div'>, keyof PianoProps>
|
|
203
178
|
|
|
204
|
-
export const Root = /* @__PURE__ */ forwardRef<
|
|
179
|
+
export const Root = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(
|
|
205
180
|
function Root(
|
|
206
181
|
{
|
|
207
182
|
noteRange,
|
|
@@ -214,7 +189,6 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
214
189
|
keyGap = 1,
|
|
215
190
|
blackKeyWidthRatio = 0.65,
|
|
216
191
|
blackKeyHeightRatio = 0.6,
|
|
217
|
-
height,
|
|
218
192
|
style,
|
|
219
193
|
className,
|
|
220
194
|
label,
|
|
@@ -222,6 +196,7 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
222
196
|
classes,
|
|
223
197
|
onPlayNote,
|
|
224
198
|
onStopNote,
|
|
199
|
+
actionsRef,
|
|
225
200
|
...props
|
|
226
201
|
},
|
|
227
202
|
forwardedRef,
|
|
@@ -234,10 +209,6 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
234
209
|
const [resizedKeyWidth, setResizedKeyWidth] = useState(whiteKeyWidth)
|
|
235
210
|
|
|
236
211
|
const notes = useMemo(() => getNoteRangeArray(noteRange), [noteRange])
|
|
237
|
-
const whiteKeyCount = useMemo(
|
|
238
|
-
() => notes.filter(isWhiteKey).length,
|
|
239
|
-
[notes],
|
|
240
|
-
)
|
|
241
212
|
|
|
242
213
|
const layout: PianoLayout = useMemo(
|
|
243
214
|
() => ({
|
|
@@ -264,21 +235,12 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
264
235
|
layout,
|
|
265
236
|
glissando,
|
|
266
237
|
midiMax,
|
|
238
|
+
keyboardShortcuts,
|
|
239
|
+
keyboardShortcutsScope,
|
|
267
240
|
onPlayNote,
|
|
268
241
|
onStopNote,
|
|
269
242
|
})
|
|
270
243
|
const instanceRef = useRef<PianoInputInstance | null>(null)
|
|
271
|
-
const shortcutNotes = useRef(
|
|
272
|
-
new Map<string, { note: number; source: string }>(),
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
const releaseShortcutNotes = useCallback(() => {
|
|
276
|
-
for (const { note, source } of shortcutNotes.current.values()) {
|
|
277
|
-
instanceRef.current?.noteOff(note, { source })
|
|
278
|
-
}
|
|
279
|
-
shortcutNotes.current.clear()
|
|
280
|
-
}, [])
|
|
281
|
-
|
|
282
244
|
useEffect(() => {
|
|
283
245
|
if (!node) return
|
|
284
246
|
|
|
@@ -286,6 +248,8 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
286
248
|
layout: latest.current.layout,
|
|
287
249
|
glissando: latest.current.glissando,
|
|
288
250
|
midiMax: latest.current.midiMax,
|
|
251
|
+
keyboardShortcuts: latest.current.keyboardShortcuts,
|
|
252
|
+
keyboardShortcutsScope: latest.current.keyboardShortcutsScope,
|
|
289
253
|
onPlayNote: (note, velocity) =>
|
|
290
254
|
latest.current.onPlayNote?.(note, velocity),
|
|
291
255
|
onStopNote: (note) => latest.current.onStopNote?.(note),
|
|
@@ -304,10 +268,27 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
304
268
|
|
|
305
269
|
// Runs after every render.
|
|
306
270
|
useEffect(() => {
|
|
307
|
-
latest.current = {
|
|
308
|
-
|
|
271
|
+
latest.current = {
|
|
272
|
+
layout,
|
|
273
|
+
glissando,
|
|
274
|
+
midiMax,
|
|
275
|
+
keyboardShortcuts,
|
|
276
|
+
keyboardShortcutsScope,
|
|
277
|
+
onPlayNote,
|
|
278
|
+
onStopNote,
|
|
279
|
+
}
|
|
280
|
+
instanceRef.current?.update({
|
|
281
|
+
layout,
|
|
282
|
+
glissando,
|
|
283
|
+
midiMax,
|
|
284
|
+
keyboardShortcuts,
|
|
285
|
+
keyboardShortcutsScope,
|
|
286
|
+
})
|
|
309
287
|
})
|
|
310
288
|
|
|
289
|
+
// By value, so that a range written inline does not reconnect the
|
|
290
|
+
// observer on every render.
|
|
291
|
+
const { first, last } = noteRange
|
|
311
292
|
useEffect(() => {
|
|
312
293
|
if (!resizable || !node) return
|
|
313
294
|
const parent = node.parentElement
|
|
@@ -315,92 +296,24 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
315
296
|
|
|
316
297
|
const resizeObserver = new ResizeObserver(() => {
|
|
317
298
|
setResizedKeyWidth(
|
|
318
|
-
node.clientWidth
|
|
299
|
+
fitWhiteKeyWidth(node.clientWidth, {
|
|
300
|
+
noteRange: { first, last },
|
|
301
|
+
keyGap,
|
|
302
|
+
blackKeyWidthRatio,
|
|
303
|
+
}),
|
|
319
304
|
)
|
|
320
305
|
})
|
|
321
306
|
resizeObserver.observe(parent)
|
|
322
307
|
return () => resizeObserver.disconnect()
|
|
323
|
-
}, [resizable, node,
|
|
324
|
-
|
|
325
|
-
const shortcutKeys = keyboardShortcuts?.keys
|
|
326
|
-
const hasShortcuts = shortcutKeys !== undefined
|
|
327
|
-
// What the held keys were started against, as a value rather than the
|
|
328
|
-
// identity of the array: a caller who writes the keys inline hands over a
|
|
329
|
-
// new array on every render, and releasing on that would stop a note as
|
|
330
|
-
// soon as anything else re-renders — including the state change that
|
|
331
|
-
// playing the note caused.
|
|
332
|
-
const shortcutMapping = shortcutKeys?.join('\u0000')
|
|
333
|
-
|
|
334
|
-
useEffect(
|
|
335
|
-
() => releaseShortcutNotes,
|
|
336
|
-
[
|
|
337
|
-
releaseShortcutNotes,
|
|
338
|
-
shortcutMapping,
|
|
339
|
-
keyboardShortcutsScope,
|
|
340
|
-
noteRange.first,
|
|
341
|
-
noteRange.last,
|
|
342
|
-
],
|
|
343
|
-
)
|
|
344
|
-
|
|
345
|
-
/** The note a shortcut key plays, or null when it has none. */
|
|
346
|
-
function shortcutNote(key: string) {
|
|
347
|
-
if (!shortcutKeys || key === '') return null
|
|
348
|
-
const index = shortcutKeys.indexOf(key)
|
|
349
|
-
const note = noteRange.first + index
|
|
350
|
-
return index === -1 || note > noteRange.last ? null : note
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const shortcutTarget = useMemo(
|
|
354
|
-
() => () => {
|
|
355
|
-
if (!hasShortcuts) return null
|
|
356
|
-
return keyboardShortcutsScope === 'window' ? globalThis.window : node
|
|
357
|
-
},
|
|
358
|
-
[hasShortcuts, keyboardShortcutsScope, node],
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
const focusOutTarget = useMemo(
|
|
362
|
-
() => () =>
|
|
363
|
-
hasShortcuts && keyboardShortcutsScope === 'root' ? node : null,
|
|
364
|
-
[hasShortcuts, keyboardShortcutsScope, node],
|
|
365
|
-
)
|
|
308
|
+
}, [resizable, node, first, last, keyGap, blackKeyWidthRatio])
|
|
366
309
|
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
310
|
+
const rootRefCallback = useComposedRefs<HTMLDivElement>(
|
|
311
|
+
forwardedRef,
|
|
312
|
+
setNode,
|
|
370
313
|
)
|
|
371
314
|
|
|
372
|
-
useEventListener(shortcutTarget, 'keydown', (e) => {
|
|
373
|
-
const key = shortcutKey(e)
|
|
374
|
-
if (e.repeat || shortcutNotes.current.has(key)) return
|
|
375
|
-
if (isEditableTarget(e.target)) return
|
|
376
|
-
|
|
377
|
-
const note = shortcutNote(e.key)
|
|
378
|
-
if (note === null) return
|
|
379
|
-
|
|
380
|
-
const source = `keyboard:${key}`
|
|
381
|
-
shortcutNotes.current.set(key, { note, source })
|
|
382
|
-
instanceRef.current?.noteOn(note, { source })
|
|
383
|
-
})
|
|
384
|
-
|
|
385
|
-
useEventListener(shortcutTarget, 'keyup', (e) => {
|
|
386
|
-
const key = shortcutKey(e)
|
|
387
|
-
const shortcut = shortcutNotes.current.get(key)
|
|
388
|
-
if (!shortcut) return
|
|
389
|
-
|
|
390
|
-
shortcutNotes.current.delete(key)
|
|
391
|
-
instanceRef.current?.noteOff(shortcut.note, { source: shortcut.source })
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
useEventListener(focusOutTarget, 'focusout', (e) => {
|
|
395
|
-
if (e.relatedTarget instanceof Node && node?.contains(e.relatedTarget))
|
|
396
|
-
return
|
|
397
|
-
releaseShortcutNotes()
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
useEventListener(windowBlurTarget, 'blur', releaseShortcutNotes)
|
|
401
|
-
|
|
402
315
|
useImperativeHandle(
|
|
403
|
-
|
|
316
|
+
actionsRef,
|
|
404
317
|
() => ({
|
|
405
318
|
playNote: (note, velocity) =>
|
|
406
319
|
instanceRef.current?.noteOn(note, { source: 'api', velocity }),
|
|
@@ -412,7 +325,7 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
412
325
|
|
|
413
326
|
return (
|
|
414
327
|
<div
|
|
415
|
-
ref={
|
|
328
|
+
ref={rootRefCallback}
|
|
416
329
|
className={className}
|
|
417
330
|
data-resizable={resizable ? '' : undefined}
|
|
418
331
|
role="group"
|
|
@@ -423,7 +336,6 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
423
336
|
{
|
|
424
337
|
// Computed from the layout rather than chosen, so it stays inline.
|
|
425
338
|
width: resizable ? '100%' : pianoWidth(layout),
|
|
426
|
-
'--height': cssLength(height),
|
|
427
339
|
// The keys inside are placed against this box.
|
|
428
340
|
position: 'relative',
|
|
429
341
|
...style,
|
|
@@ -492,5 +404,3 @@ export const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(
|
|
|
492
404
|
* Customizable piano component.
|
|
493
405
|
*/
|
|
494
406
|
export const Piano = { Root }
|
|
495
|
-
|
|
496
|
-
export { type KeyboardShortcuts, SHORTCUTS } from './keyboard-shortcuts'
|
|
@@ -1,40 +1,33 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, forwardRef } from 'react'
|
|
2
2
|
|
|
3
|
+
import { POINT_AXIS, wheelMove } from '@tremolo-ui/dom/internal'
|
|
4
|
+
|
|
3
5
|
import { useComposedRefs } from '../../compose-refs'
|
|
4
6
|
import { useDragValue } from '../../hooks/useDragValue'
|
|
5
7
|
import { useWheel } from '../../hooks/useWheel'
|
|
6
8
|
import { Placement } from '../_util/Placement'
|
|
7
9
|
|
|
8
10
|
import { usePointsEditorContext } from './context'
|
|
9
|
-
import { AXIS } from './Point'
|
|
10
11
|
|
|
11
12
|
type Props = ComponentPropsWithoutRef<'div'>
|
|
12
13
|
|
|
13
14
|
export const Container = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(
|
|
14
15
|
function Container({ children, className, style, ...props }, forwardedRef) {
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
disabled,
|
|
18
|
-
selectable,
|
|
19
|
-
isPointElement,
|
|
20
|
-
nudgeFocusedPoint,
|
|
21
|
-
beginSelectionBox,
|
|
22
|
-
moveSelectionBox,
|
|
23
|
-
endSelectionBox,
|
|
24
|
-
} = usePointsEditorContext()
|
|
16
|
+
const { containerRef, disabled, selectable, editor } =
|
|
17
|
+
usePointsEditorContext()
|
|
25
18
|
const { refCallback: dragRefCallback } = useDragValue<HTMLDivElement>({
|
|
26
|
-
axis:
|
|
19
|
+
axis: POINT_AXIS,
|
|
27
20
|
baseElementRef: containerRef,
|
|
28
21
|
// A press that landed on a point belongs to that point. Declining here
|
|
29
22
|
// rather than in onDragStart matters: by then the container would already
|
|
30
23
|
// have taken the pointer capture away from the point.
|
|
31
24
|
shouldStart: (event) =>
|
|
32
|
-
!disabled && !isPointElement(event.target as Element | null),
|
|
25
|
+
!disabled && !editor.isPointElement(event.target as Element | null),
|
|
33
26
|
onDragStart: ([x, y], state) => {
|
|
34
|
-
beginSelectionBox({ x, y }, state.event)
|
|
27
|
+
editor.beginSelectionBox({ x, y }, state.event)
|
|
35
28
|
},
|
|
36
|
-
onChange: ([x, y]) => moveSelectionBox({ x, y }),
|
|
37
|
-
onDragEnd: endSelectionBox,
|
|
29
|
+
onChange: ([x, y]) => editor.moveSelectionBox({ x, y }),
|
|
30
|
+
onDragEnd: () => editor.endSelectionBox(),
|
|
38
31
|
})
|
|
39
32
|
|
|
40
33
|
// One listener for the whole editor rather than one per point: a wheel
|
|
@@ -44,16 +37,12 @@ export const Container = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(
|
|
|
44
37
|
useWheel(
|
|
45
38
|
(event) => {
|
|
46
39
|
// Scrolling up moves the point towards y = 0; shift switches to x.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (delta === 0) return
|
|
54
|
-
const axis = horizontal || event.shiftKey ? 'x' : 'y'
|
|
55
|
-
const direction = delta < 0 ? -1 : 1
|
|
56
|
-
if (nudgeFocusedPoint(axis, direction, event)) event.preventDefault()
|
|
40
|
+
const move = wheelMove(event)
|
|
41
|
+
if (!move) return
|
|
42
|
+
const axis = move.axis === 0 ? 'x' : 'y'
|
|
43
|
+
if (editor.nudgeFocusedPoint(axis, move.direction, event)) {
|
|
44
|
+
event.preventDefault()
|
|
45
|
+
}
|
|
57
46
|
},
|
|
58
47
|
{ target: containerRef },
|
|
59
48
|
)
|