@flowgram-vue/core 0.2.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 (133) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +0 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +0 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +63 -0
  8. package/src/common/config-entity.ts +80 -0
  9. package/src/common/entity-data.ts +171 -0
  10. package/src/common/entity-manager-contribution.ts +12 -0
  11. package/src/common/entity-manager.ts +475 -0
  12. package/src/common/entity.ts +482 -0
  13. package/src/common/index.ts +22 -0
  14. package/src/common/playground-context.ts +35 -0
  15. package/src/common/playground-decorator-helper.ts +113 -0
  16. package/src/common/playground-decorators.ts +85 -0
  17. package/src/common/playground-schedule.ts +30 -0
  18. package/src/common/protect-wheel-area.ts +11 -0
  19. package/src/common/schema/index.ts +14 -0
  20. package/src/common/schema/node.ts +15 -0
  21. package/src/common/schema/opacity-schema.ts +19 -0
  22. package/src/common/schema/origin-schema.ts +35 -0
  23. package/src/common/schema/position-schema.ts +35 -0
  24. package/src/common/schema/rotation-schema.ts +19 -0
  25. package/src/common/schema/scale-schema.ts +35 -0
  26. package/src/common/schema/size-schema.ts +42 -0
  27. package/src/common/schema/skew-schema.ts +35 -0
  28. package/src/common/schema/transform-schema.ts +613 -0
  29. package/src/common/utils/bounds.spec.ts +229 -0
  30. package/src/common/utils/bounds.ts +176 -0
  31. package/src/common/utils/index.ts +6 -0
  32. package/src/composables/index.ts +16 -0
  33. package/src/composables/use-config-entity.ts +31 -0
  34. package/src/composables/use-entities.ts +26 -0
  35. package/src/composables/use-entity-data-from-context.ts +34 -0
  36. package/src/composables/use-entity-from-context.ts +31 -0
  37. package/src/composables/use-listen-events.ts +22 -0
  38. package/src/composables/use-playground-container.ts +16 -0
  39. package/src/composables/use-playground-context.ts +15 -0
  40. package/src/composables/use-playground-drag.ts +31 -0
  41. package/src/composables/use-playground.ts +16 -0
  42. package/src/composables/use-refresh.ts +6 -0
  43. package/src/composables/use-service.ts +17 -0
  44. package/src/core/index.ts +8 -0
  45. package/src/core/layer/config/editor-state-config-entity.ts +180 -0
  46. package/src/core/layer/config/index.ts +7 -0
  47. package/src/core/layer/config/playground-config-entity.ts +604 -0
  48. package/src/core/layer/index.ts +8 -0
  49. package/src/core/layer/layer.ts +248 -0
  50. package/src/core/layer/playground-layer.ts +547 -0
  51. package/src/core/pipeline/index.ts +10 -0
  52. package/src/core/pipeline/pipeline-entities-selector.ts +200 -0
  53. package/src/core/pipeline/pipeline-entities.ts +230 -0
  54. package/src/core/pipeline/pipeline-registry.ts +344 -0
  55. package/src/core/pipeline/pipeline-renderer.ts +248 -0
  56. package/src/core/pipeline/pipeline-vue-utils.ts +96 -0
  57. package/src/core/pipeline/pipeline.ts +28 -0
  58. package/src/core/utils/index.ts +12 -0
  59. package/src/core/utils/inject-provider-decorators.ts +27 -0
  60. package/src/core/utils/lazy-inject-decorators.ts +38 -0
  61. package/src/core/utils/mouse-touch-event.ts +120 -0
  62. package/src/core/utils/playground-drag.ts +511 -0
  63. package/src/core/utils/playground-gesture.spec.ts +135 -0
  64. package/src/core/utils/playground-gesture.ts +118 -0
  65. package/src/core/utils/tween.ts +156 -0
  66. package/src/core/utils/use-gesture/core/Controller.ts +212 -0
  67. package/src/core/utils/use-gesture/core/EventStore.ts +46 -0
  68. package/src/core/utils/use-gesture/core/TimeoutStore.ts +28 -0
  69. package/src/core/utils/use-gesture/core/actions.ts +63 -0
  70. package/src/core/utils/use-gesture/core/config/commonConfigResolver.ts +86 -0
  71. package/src/core/utils/use-gesture/core/config/coordinatesConfigResolver.ts +48 -0
  72. package/src/core/utils/use-gesture/core/config/dragConfigResolver.ts +140 -0
  73. package/src/core/utils/use-gesture/core/config/hoverConfigResolver.ts +11 -0
  74. package/src/core/utils/use-gesture/core/config/moveConfigResolver.ts +11 -0
  75. package/src/core/utils/use-gesture/core/config/pinchConfigResolver.ts +59 -0
  76. package/src/core/utils/use-gesture/core/config/resolver.ts +70 -0
  77. package/src/core/utils/use-gesture/core/config/scrollConfigResolver.ts +8 -0
  78. package/src/core/utils/use-gesture/core/config/sharedConfigResolver.ts +28 -0
  79. package/src/core/utils/use-gesture/core/config/support.ts +52 -0
  80. package/src/core/utils/use-gesture/core/config/wheelConfigResolver.ts +8 -0
  81. package/src/core/utils/use-gesture/core/engines/CoordinatesEngine.ts +78 -0
  82. package/src/core/utils/use-gesture/core/engines/DragEngine.ts +403 -0
  83. package/src/core/utils/use-gesture/core/engines/Engine.ts +406 -0
  84. package/src/core/utils/use-gesture/core/engines/HoverEngine.ts +43 -0
  85. package/src/core/utils/use-gesture/core/engines/MoveEngine.ts +52 -0
  86. package/src/core/utils/use-gesture/core/engines/PinchEngine.ts +345 -0
  87. package/src/core/utils/use-gesture/core/engines/ScrollEngine.ts +42 -0
  88. package/src/core/utils/use-gesture/core/engines/WheelEngine.ts +48 -0
  89. package/src/core/utils/use-gesture/core/index.ts +7 -0
  90. package/src/core/utils/use-gesture/core/parser.ts +92 -0
  91. package/src/core/utils/use-gesture/core/types/action.ts +19 -0
  92. package/src/core/utils/use-gesture/core/types/config.ts +255 -0
  93. package/src/core/utils/use-gesture/core/types/handlers.ts +73 -0
  94. package/src/core/utils/use-gesture/core/types/index.ts +11 -0
  95. package/src/core/utils/use-gesture/core/types/internalConfig.ts +80 -0
  96. package/src/core/utils/use-gesture/core/types/state.ts +275 -0
  97. package/src/core/utils/use-gesture/core/types/utils.ts +204 -0
  98. package/src/core/utils/use-gesture/core/types.ts +8 -0
  99. package/src/core/utils/use-gesture/core/utils/events.ts +158 -0
  100. package/src/core/utils/use-gesture/core/utils/fn.ts +32 -0
  101. package/src/core/utils/use-gesture/core/utils/maths.ts +63 -0
  102. package/src/core/utils/use-gesture/core/utils/state.ts +24 -0
  103. package/src/core/utils/use-gesture/core/utils.ts +8 -0
  104. package/src/core/utils/use-gesture/index.ts +6 -0
  105. package/src/core/utils/use-gesture/vanilla/DragGesture.ts +27 -0
  106. package/src/core/utils/use-gesture/vanilla/Gesture.ts +45 -0
  107. package/src/core/utils/use-gesture/vanilla/HoverGesture.ts +27 -0
  108. package/src/core/utils/use-gesture/vanilla/MoveGesture.ts +27 -0
  109. package/src/core/utils/use-gesture/vanilla/PinchGesture.ts +27 -0
  110. package/src/core/utils/use-gesture/vanilla/Recognizer.ts +43 -0
  111. package/src/core/utils/use-gesture/vanilla/ScrollGesture.ts +27 -0
  112. package/src/core/utils/use-gesture/vanilla/WheelGesture.ts +27 -0
  113. package/src/core/utils/use-gesture/vanilla/createGesture.ts +18 -0
  114. package/src/core/utils/use-gesture/vanilla/index.ts +18 -0
  115. package/src/env.d.ts +10 -0
  116. package/src/index.ts +17 -0
  117. package/src/playground-config.ts +70 -0
  118. package/src/playground-container.ts +129 -0
  119. package/src/playground-contribution.ts +81 -0
  120. package/src/playground-mock-tools.ts +143 -0
  121. package/src/playground.ts +401 -0
  122. package/src/plugin/index.ts +6 -0
  123. package/src/plugin/plugin.ts +226 -0
  124. package/src/services/clipboard-service.ts +40 -0
  125. package/src/services/context-menu-service.ts +25 -0
  126. package/src/services/index.ts +10 -0
  127. package/src/services/logger-service.ts +49 -0
  128. package/src/services/selection-service.ts +54 -0
  129. package/src/services/storage-service.ts +65 -0
  130. package/src/vue/index.ts +8 -0
  131. package/src/vue/playground-vue-context.ts +22 -0
  132. package/src/vue/playground-vue-provider.ts +115 -0
  133. package/src/vue/playground-vue-renderer.vue +44 -0
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { V } from '../utils/maths';
7
+ import { pointerId, getPointerType, pointerValues } from '../utils/events';
8
+ import { Vector2 } from '../types';
9
+ import { coordinatesConfigResolver } from '../config/coordinatesConfigResolver';
10
+ import { CoordinatesEngine } from './CoordinatesEngine';
11
+
12
+ const KEYS_DELTA_MAP = {
13
+ ArrowRight: (displacement: number, factor: number = 1) => [displacement * factor, 0],
14
+ ArrowLeft: (displacement: number, factor: number = 1) => [-1 * displacement * factor, 0],
15
+ ArrowUp: (displacement: number, factor: number = 1) => [0, -1 * displacement * factor],
16
+ ArrowDown: (displacement: number, factor: number = 1) => [0, displacement * factor],
17
+ };
18
+
19
+ export class DragEngine extends CoordinatesEngine<'drag'> {
20
+ ingKey = 'dragging' as const;
21
+
22
+ // superseeds generic Engine reset call
23
+ reset(this: DragEngine) {
24
+ super.reset();
25
+ const state = this.state;
26
+ state._pointerId = undefined;
27
+ state._pointerActive = false;
28
+ state._keyboardActive = false;
29
+ state._preventScroll = false;
30
+ state._delayed = false;
31
+ state.swipe = [0, 0];
32
+ state.tap = false;
33
+ state.canceled = false;
34
+ state.cancel = this.cancel.bind(this);
35
+ }
36
+
37
+ setup() {
38
+ const state = this.state;
39
+
40
+ if (state._bounds instanceof HTMLElement) {
41
+ const boundRect = state._bounds.getBoundingClientRect();
42
+ const targetRect = (state.currentTarget as HTMLElement).getBoundingClientRect();
43
+ const _bounds = {
44
+ left: boundRect.left - targetRect.left + state.offset[0],
45
+ right: boundRect.right - targetRect.right + state.offset[0],
46
+ top: boundRect.top - targetRect.top + state.offset[1],
47
+ bottom: boundRect.bottom - targetRect.bottom + state.offset[1],
48
+ };
49
+ state._bounds = coordinatesConfigResolver.bounds(_bounds) as [Vector2, Vector2];
50
+ }
51
+ }
52
+
53
+ cancel() {
54
+ const state = this.state;
55
+ if (state.canceled) return;
56
+ state.canceled = true;
57
+ state._active = false;
58
+ setTimeout(() => {
59
+ // we run compute with no event so that kinematics won't be computed
60
+ this.compute();
61
+ this.emit();
62
+ }, 0);
63
+ }
64
+
65
+ setActive() {
66
+ this.state._active = this.state._pointerActive || this.state._keyboardActive;
67
+ }
68
+
69
+ // superseeds Engine clean function
70
+ clean() {
71
+ this.pointerClean();
72
+ this.state._pointerActive = false;
73
+ this.state._keyboardActive = false;
74
+ super.clean();
75
+ }
76
+
77
+ pointerDown(event: PointerEvent) {
78
+ const config = this.config;
79
+ const state = this.state;
80
+
81
+ if (
82
+ event.buttons != null &&
83
+ // If the user submits an array as pointer.buttons, don't start the drag
84
+ // if event.buttons isn't included inside that array.
85
+ (Array.isArray(config.pointerButtons)
86
+ ? !config.pointerButtons.includes(event.buttons)
87
+ : // If the user submits a number as pointer.buttons, refuse the drag if
88
+ // config.pointerButtons is different than `-1` and if event.buttons
89
+ // doesn't match the combination.
90
+ config.pointerButtons !== -1 && config.pointerButtons !== event.buttons)
91
+ )
92
+ return;
93
+
94
+ const ctrlIds = this.ctrl.setEventIds(event);
95
+ // We need to capture all pointer ids so that we can keep track of them when
96
+ // they're released off the target
97
+ if (config.pointerCapture) {
98
+ (event.target as HTMLElement).setPointerCapture(event.pointerId);
99
+ }
100
+
101
+ if (
102
+ // in some situations (https://github.com/pmndrs/use-gesture/issues/494#issuecomment-1127584116)
103
+ // like when a new browser tab is opened during a drag gesture, the drag
104
+ // can be interrupted mid-way, and can stall. This happens because the
105
+ // pointerId that initiated the gesture is lost, and since the drag
106
+ // persists until that pointerId is lifted with pointerup, it never ends.
107
+ //
108
+ // Therefore, when we detect that only one pointer is pressing the screen,
109
+ // we consider that the gesture can proceed.
110
+ ctrlIds &&
111
+ ctrlIds.size > 1 &&
112
+ state._pointerActive
113
+ )
114
+ return;
115
+
116
+ this.start(event);
117
+ this.setupPointer(event);
118
+
119
+ state._pointerId = pointerId(event);
120
+ state._pointerActive = true;
121
+
122
+ this.computeValues(pointerValues(event));
123
+ this.computeInitial();
124
+
125
+ if (config.preventScrollAxis && getPointerType(event) !== 'mouse') {
126
+ // when preventScrollAxis is set we don't consider the gesture active
127
+ // until it's deliberate
128
+ state._active = false;
129
+ this.setupScrollPrevention(event);
130
+ } else if (config.delay > 0) {
131
+ this.setupDelayTrigger(event);
132
+ // makes sure we emit all events when `triggerAllEvents` flag is `true`
133
+ if (config.triggerAllEvents) {
134
+ this.compute(event);
135
+ this.emit();
136
+ }
137
+ } else {
138
+ this.startPointerDrag(event);
139
+ }
140
+ }
141
+
142
+ startPointerDrag(event: PointerEvent) {
143
+ const state = this.state;
144
+ state._active = true;
145
+ state._preventScroll = true;
146
+ state._delayed = false;
147
+
148
+ this.compute(event);
149
+ this.emit();
150
+ }
151
+
152
+ pointerMove(event: PointerEvent) {
153
+ const state = this.state;
154
+ const config = this.config;
155
+
156
+ if (!state._pointerActive) return;
157
+
158
+ const id = pointerId(event);
159
+ if (state._pointerId !== undefined && id !== state._pointerId) return;
160
+ const _values = pointerValues(event);
161
+
162
+ if (document.pointerLockElement === event.target) {
163
+ state._delta = [event.movementX, event.movementY];
164
+ } else {
165
+ state._delta = V.sub(_values, state._values);
166
+ this.computeValues(_values);
167
+ }
168
+
169
+ V.addTo(state._movement, state._delta);
170
+ this.compute(event);
171
+
172
+ // if the gesture is delayed but deliberate, then we can start it
173
+ // immediately.
174
+ if (state._delayed && state.intentional) {
175
+ this.timeoutStore.remove('dragDelay');
176
+ // makes sure `first` is still true when moving for the first time after a
177
+ // delay.
178
+ state.active = false;
179
+ this.startPointerDrag(event);
180
+ return;
181
+ }
182
+
183
+ if (config.preventScrollAxis && !state._preventScroll) {
184
+ if (state.axis) {
185
+ if (state.axis === config.preventScrollAxis || config.preventScrollAxis === 'xy') {
186
+ state._active = false;
187
+ this.clean();
188
+ return;
189
+ } else {
190
+ this.timeoutStore.remove('startPointerDrag');
191
+ this.startPointerDrag(event);
192
+ return;
193
+ }
194
+ } else {
195
+ return;
196
+ }
197
+ }
198
+
199
+ this.emit();
200
+ }
201
+
202
+ pointerUp(event: PointerEvent) {
203
+ this.ctrl.setEventIds(event);
204
+ // We release the pointer id if it has pointer capture
205
+ try {
206
+ if (
207
+ this.config.pointerCapture &&
208
+ (event.target as HTMLElement).hasPointerCapture(event.pointerId)
209
+ ) {
210
+ // this shouldn't be necessary as it should be automatic when releasing the pointer
211
+ (event.target as HTMLElement).releasePointerCapture(event.pointerId);
212
+ }
213
+ } catch {
214
+ if (process.env.NODE_ENV === 'development') {
215
+ // eslint-disable-next-line no-console
216
+ console.warn(
217
+ `[@use-gesture]: If you see this message, it's likely that you're using an outdated version of \`@react-three/fiber\`. \n\nPlease upgrade to the latest version.`,
218
+ );
219
+ }
220
+ }
221
+
222
+ const state = this.state;
223
+ const config = this.config;
224
+
225
+ if (!state._active || !state._pointerActive) return;
226
+
227
+ const id = pointerId(event);
228
+ if (state._pointerId !== undefined && id !== state._pointerId) return;
229
+
230
+ this.state._pointerActive = false;
231
+ this.setActive();
232
+ this.compute(event);
233
+
234
+ const [dx, dy] = state._distance;
235
+ state.tap = dx <= config.tapsThreshold && dy <= config.tapsThreshold;
236
+
237
+ if (state.tap && config.filterTaps) {
238
+ state._force = true;
239
+ } else {
240
+ const [_dx, _dy] = state._delta;
241
+ const [_mx, _my] = state._movement;
242
+ const [svx, svy] = config.swipe.velocity;
243
+ const [sx, sy] = config.swipe.distance;
244
+ const sdt = config.swipe.duration;
245
+
246
+ if (state.elapsedTime < sdt) {
247
+ const _vx = Math.abs(_dx / state.timeDelta);
248
+ const _vy = Math.abs(_dy / state.timeDelta);
249
+
250
+ if (_vx > svx && Math.abs(_mx) > sx) state.swipe[0] = Math.sign(_dx);
251
+ if (_vy > svy && Math.abs(_my) > sy) state.swipe[1] = Math.sign(_dy);
252
+ }
253
+ }
254
+
255
+ this.emit();
256
+ }
257
+
258
+ pointerClick(event: MouseEvent) {
259
+ // event.detail indicates the number of buttons being pressed. When it's
260
+ // null, it's likely to be a keyboard event from the Enter Key that could
261
+ // be used for accessibility, and therefore shouldn't be prevented.
262
+ // See https://github.com/pmndrs/use-gesture/issues/530
263
+ if (!this.state.tap && event.detail > 0) {
264
+ event.preventDefault();
265
+ event.stopPropagation();
266
+ }
267
+ }
268
+
269
+ setupPointer(event: PointerEvent) {
270
+ const config = this.config;
271
+ const device = config.device;
272
+
273
+ if (process.env.NODE_ENV === 'development') {
274
+ try {
275
+ if (device === 'pointer' && config.preventScrollDelay === undefined) {
276
+ const currentTarget =
277
+ // @ts-ignore (warning for r3f)
278
+ 'uv' in event ? event.sourceEvent.currentTarget : event.currentTarget;
279
+ const style = window.getComputedStyle(currentTarget);
280
+ if (style.touchAction === 'auto') {
281
+ // eslint-disable-next-line no-console
282
+ console.warn(
283
+ `[@use-gesture]: The drag target has its \`touch-action\` style property set to \`auto\`. It is recommended to add \`touch-action: 'none'\` so that the drag gesture behaves correctly on touch-enabled devices. For more information read this: https://use-gesture.netlify.app/docs/extras/#touch-action.\n\nThis message will only show in development mode. It won't appear in production. If this is intended, you can ignore it.`,
284
+ currentTarget,
285
+ );
286
+ }
287
+ }
288
+ } catch {}
289
+ }
290
+
291
+ if (config.pointerLock) {
292
+ (event.currentTarget as HTMLElement).requestPointerLock();
293
+ }
294
+
295
+ if (!config.pointerCapture) {
296
+ this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this));
297
+ this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this));
298
+ this.eventStore.add(this.sharedConfig.window, device, 'cancel', this.pointerUp.bind(this));
299
+ }
300
+ }
301
+
302
+ pointerClean() {
303
+ if (this.config.pointerLock && document.pointerLockElement === this.state.currentTarget) {
304
+ document.exitPointerLock();
305
+ }
306
+ }
307
+
308
+ preventScroll(event: PointerEvent) {
309
+ if (this.state._preventScroll && event.cancelable) {
310
+ event.preventDefault();
311
+ }
312
+ }
313
+
314
+ setupScrollPrevention(event: PointerEvent) {
315
+ // fixes https://github.com/pmndrs/use-gesture/issues/497
316
+ this.state._preventScroll = false;
317
+ persistEvent(event);
318
+ // we add window listeners that will prevent the scroll when the user has started dragging
319
+ const remove = this.eventStore.add(
320
+ this.sharedConfig.window,
321
+ 'touch',
322
+ 'change',
323
+ this.preventScroll.bind(this),
324
+ {
325
+ passive: false,
326
+ },
327
+ );
328
+ this.eventStore.add(this.sharedConfig.window, 'touch', 'end', remove);
329
+ this.eventStore.add(this.sharedConfig.window, 'touch', 'cancel', remove);
330
+ this.timeoutStore.add(
331
+ 'startPointerDrag',
332
+ this.startPointerDrag.bind(this),
333
+ this.config.preventScrollDelay!,
334
+ event,
335
+ );
336
+ }
337
+
338
+ setupDelayTrigger(event: PointerEvent) {
339
+ this.state._delayed = true;
340
+ this.timeoutStore.add(
341
+ 'dragDelay',
342
+ () => {
343
+ // forces drag to start no matter the threshold when delay is reached
344
+ this.state._step = [0, 0];
345
+ this.startPointerDrag(event);
346
+ },
347
+ this.config.delay,
348
+ );
349
+ }
350
+
351
+ keyDown(event: KeyboardEvent) {
352
+ // @ts-ignore
353
+ const deltaFn = KEYS_DELTA_MAP[event.key];
354
+ if (deltaFn) {
355
+ const state = this.state;
356
+ const factor = event.shiftKey ? 10 : event.altKey ? 0.1 : 1;
357
+
358
+ this.start(event);
359
+
360
+ state._delta = deltaFn(this.config.keyboardDisplacement, factor);
361
+ state._keyboardActive = true;
362
+ V.addTo(state._movement, state._delta);
363
+
364
+ this.compute(event);
365
+ this.emit();
366
+ }
367
+ }
368
+
369
+ keyUp(event: KeyboardEvent) {
370
+ if (!(event.key in KEYS_DELTA_MAP)) return;
371
+
372
+ this.state._keyboardActive = false;
373
+ this.setActive();
374
+ this.compute(event);
375
+ this.emit();
376
+ }
377
+
378
+ bind(bindFunction: any) {
379
+ const device = this.config.device;
380
+
381
+ bindFunction(device, 'start', this.pointerDown.bind(this));
382
+
383
+ if (this.config.pointerCapture) {
384
+ bindFunction(device, 'change', this.pointerMove.bind(this));
385
+ bindFunction(device, 'end', this.pointerUp.bind(this));
386
+ bindFunction(device, 'cancel', this.pointerUp.bind(this));
387
+ bindFunction('lostPointerCapture', '', this.pointerUp.bind(this));
388
+ }
389
+
390
+ if (this.config.keys) {
391
+ bindFunction('key', 'down', this.keyDown.bind(this));
392
+ bindFunction('key', 'up', this.keyUp.bind(this));
393
+ }
394
+ if (this.config.filterTaps) {
395
+ bindFunction('click', '', this.pointerClick.bind(this), { capture: true, passive: false });
396
+ }
397
+ }
398
+ }
399
+
400
+ function persistEvent(event: PointerEvent) {
401
+ // @ts-ignore
402
+ 'persist' in event && typeof event.persist === 'function' && event.persist();
403
+ }