rege 0.2.0 → 0.4.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.
@@ -0,0 +1,447 @@
1
+ import { EventState, event } from 'reev/src'
2
+ import { PinchState } from './types'
3
+ import { vec2, addV, subV, cpV } from '../utils'
4
+ import { pinchDevice, touchDistanceAngle, pointerDistanceAngle, getCurrentTargetTouchIds, wheelPinchDelta, WebKitGestureEvent, DistanceAngle } from './utils'
5
+
6
+ export * from './types'
7
+
8
+ export const EVENT_FOR_PINCH = {
9
+ touch: {
10
+ start: 'touchstart',
11
+ move: 'touchmove',
12
+ end: 'touchend',
13
+ cancel: 'touchcancel',
14
+ },
15
+ pointer: {
16
+ start: 'pointerdown',
17
+ move: 'pointermove',
18
+ end: 'pointerup',
19
+ cancel: 'pointercancel',
20
+ },
21
+ gesture: {
22
+ start: 'gesturestart',
23
+ change: 'gesturechange',
24
+ end: 'gestureend',
25
+ },
26
+ }
27
+
28
+ export const pinchEvent = <El extends Element = Element>(config: Partial<PinchState<El>> = {}) => {
29
+ const initValues = () => {
30
+ vec2(0, 0, self.value)
31
+ vec2(0, 0, self._value)
32
+ vec2(0, 0, self.delta)
33
+ vec2(0, 0, self.movement)
34
+ }
35
+
36
+ const pinch = () => {
37
+ self.isPinchStart = self.active && !self._active
38
+ self.isPinching = self.active && self._active
39
+ self.isPinchEnd = !self.active && self._active
40
+ }
41
+
42
+ // ===== Common pinch handlers =====
43
+
44
+ const pinchStart = (e: Event, payload: DistanceAngle) => {
45
+ self.event = e
46
+ self.active = true
47
+
48
+ // Store initial values [distance, angle]
49
+ vec2(payload.distance, payload.angle, self.value)
50
+ vec2(payload.distance, payload.angle, self.initial)
51
+ cpV(payload.origin, self.origin)
52
+
53
+ self.scale = 1
54
+ self.turns = 0
55
+
56
+ self.pinch(self)
57
+ }
58
+
59
+ const pinching = (e: Event, payload: DistanceAngle) => {
60
+ if (!self.active) return
61
+
62
+ self.event = e
63
+ self._active = self.active
64
+
65
+ // Store previous values
66
+ cpV(self.value, self._value)
67
+
68
+ // Current values [distance, angle]
69
+ const prevAngle = self._value[1]
70
+ let newAngle = payload.angle
71
+
72
+ // Handle angle wrapping (for full rotations)
73
+ const deltaAngle = newAngle - prevAngle
74
+ if (Math.abs(deltaAngle) > 270) {
75
+ self.turns += Math.sign(deltaAngle)
76
+ newAngle -= 360 * Math.sign(deltaAngle)
77
+ }
78
+
79
+ vec2(payload.distance, newAngle, self.value)
80
+ cpV(payload.origin, self.origin)
81
+
82
+ // Calculate movement: [scaleRatio - 1, angleDelta]
83
+ // scaleRatio = currentDistance / initialDistance
84
+ const scaleRatio = self.value[0] / self.initial[0] - 1
85
+ const angleDelta = self.value[1] - self.initial[1]
86
+ vec2(scaleRatio, angleDelta, self.movement)
87
+
88
+ // Calculate delta from previous frame
89
+ subV(self.value, self._value, self.delta)
90
+ // Convert distance delta to scale delta for consistency
91
+ self.delta[0] = self._value[0] !== 0 ? self.value[0] / self._value[0] - 1 : 0
92
+
93
+ // Update offset (cumulative)
94
+ addV(self.offset, self.delta, self.offset)
95
+
96
+ // Update scale
97
+ self.scale = self.initial[0] !== 0 ? self.value[0] / self.initial[0] : 1
98
+
99
+ self.pinch(self)
100
+ }
101
+
102
+ const pinchEnd = (e: Event) => {
103
+ self.event = e
104
+ self._active = true
105
+ self.active = false
106
+ initValues()
107
+ self.pinch(self)
108
+ }
109
+
110
+ // ===== Touch event handlers =====
111
+
112
+ const touchStart = (e: TouchEvent) => {
113
+ const touchIds = getCurrentTargetTouchIds(e)
114
+
115
+ if (self.active) {
116
+ // Check if the touches that started the gesture are still present
117
+ if (self._touchIds.every((id) => touchIds.includes(id))) return
118
+ }
119
+
120
+ if (touchIds.length < 2) return
121
+
122
+ // Store the first two touch ids
123
+ self._touchIds = touchIds.slice(0, 2)
124
+
125
+ const payload = touchDistanceAngle(e, self._touchIds)
126
+ if (!payload) return
127
+
128
+ pinchStart(e, payload)
129
+ }
130
+
131
+ const touchMove = (e: TouchEvent) => {
132
+ if (!self.active) return
133
+
134
+ const payload = touchDistanceAngle(e, self._touchIds)
135
+ if (!payload) return
136
+
137
+ pinching(e, payload)
138
+ }
139
+
140
+ const touchEnd = (e: TouchEvent) => {
141
+ if (!self.active) return
142
+
143
+ // Check if any of our tracked touches ended
144
+ const currentTouchIds = Array.from(e.touches).map((t) => t.identifier)
145
+ if (self._touchIds.some((id) => !currentTouchIds.includes(id))) {
146
+ pinchEnd(e)
147
+ }
148
+ }
149
+
150
+ // ===== Pointer event handlers =====
151
+
152
+ const pointerStart = (e: PointerEvent) => {
153
+ // Only track left mouse button or touch
154
+ if (e.buttons != null && e.buttons % 2 !== 1) return
155
+
156
+ const _pointerEvents = self._pointerEvents
157
+
158
+ if (self.active) {
159
+ // Check if the pointers that started the gesture are still present
160
+ if (Array.from(_pointerEvents.keys()).every((id) => self._pointerEvents.has(id))) return
161
+ }
162
+
163
+ // Capture the pointer
164
+ try {
165
+ ;(e.target as HTMLElement).setPointerCapture(e.pointerId)
166
+ } catch {}
167
+
168
+ if (_pointerEvents.size < 2) {
169
+ _pointerEvents.set(e.pointerId, e)
170
+ }
171
+
172
+ if (_pointerEvents.size < 2) return
173
+
174
+ const payload = pointerDistanceAngle(_pointerEvents)
175
+ if (!payload) return
176
+
177
+ pinchStart(e, payload)
178
+ }
179
+
180
+ const pointerMove = (e: PointerEvent) => {
181
+ const _pointerEvents = self._pointerEvents
182
+
183
+ if (_pointerEvents.has(e.pointerId)) {
184
+ _pointerEvents.set(e.pointerId, e)
185
+ }
186
+
187
+ if (!self.active) return
188
+
189
+ const payload = pointerDistanceAngle(_pointerEvents)
190
+ if (!payload) return
191
+
192
+ pinching(e, payload)
193
+ }
194
+
195
+ const pointerEnd = (e: PointerEvent) => {
196
+ try {
197
+ ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)
198
+ } catch {}
199
+
200
+ const _pointerEvents = self._pointerEvents
201
+
202
+ if (_pointerEvents.has(e.pointerId)) {
203
+ _pointerEvents.delete(e.pointerId)
204
+ }
205
+
206
+ if (!self.active) return
207
+
208
+ if (_pointerEvents.size < 2) {
209
+ pinchEnd(e)
210
+ }
211
+ }
212
+
213
+ // ===== Safari Gesture event handlers =====
214
+
215
+ const gestureStart = (e: Event) => {
216
+ const ge = e as WebKitGestureEvent
217
+ if (e.cancelable) e.preventDefault()
218
+
219
+ if (self.active) return
220
+
221
+ self.event = e
222
+ self.active = true
223
+
224
+ // GestureEvent provides scale and rotation directly
225
+ vec2(ge.scale, ge.rotation, self.value)
226
+ vec2(ge.scale, ge.rotation, self.initial)
227
+ vec2(ge.clientX, ge.clientY, self.origin)
228
+
229
+ self.scale = 1
230
+ self.turns = 0
231
+
232
+ self.pinch(self)
233
+ }
234
+
235
+ const gestureChange = (e: Event) => {
236
+ const ge = e as WebKitGestureEvent
237
+ if (e.cancelable) e.preventDefault()
238
+
239
+ if (!self.active) return
240
+
241
+ self.event = e
242
+ self._active = self.active
243
+
244
+ cpV(self.value, self._value)
245
+
246
+ // GestureEvent gives us scale and rotation directly
247
+ vec2(ge.scale, ge.rotation, self.value)
248
+ vec2(ge.clientX, ge.clientY, self.origin)
249
+
250
+ // movement = [scale - 1, rotation]
251
+ vec2(ge.scale - 1, ge.rotation, self.movement)
252
+
253
+ // delta from previous
254
+ subV(self.value, self._value, self.delta)
255
+
256
+ // Update offset
257
+ addV(self.offset, self.delta, self.offset)
258
+
259
+ self.scale = ge.scale
260
+
261
+ self.pinch(self)
262
+ }
263
+
264
+ const gestureEnd = (e: Event) => {
265
+ if (!self.active) return
266
+ pinchEnd(e)
267
+ }
268
+
269
+ // ===== Wheel event handlers (trackpad pinch fallback) =====
270
+
271
+ const wheelStart = (e: WheelEvent) => {
272
+ self.event = e
273
+ self.active = true
274
+
275
+ // For wheel, we track scale change as value[0], rotation as value[1] (always 0)
276
+ vec2(1, 0, self.value)
277
+ vec2(1, 0, self.initial)
278
+ vec2(e.clientX, e.clientY, self.origin)
279
+
280
+ self.scale = 1
281
+ self.turns = 0
282
+
283
+ // Apply the initial wheel delta
284
+ const scaleDelta = wheelPinchDelta(e, self.offset[0] + 1)
285
+ self.delta[0] = scaleDelta
286
+ self.delta[1] = 0
287
+ self.value[0] += scaleDelta
288
+ addV(self.offset, self.delta, self.offset)
289
+ vec2(self.value[0] - 1, 0, self.movement)
290
+
291
+ self.scale = self.value[0]
292
+
293
+ self.pinch(self)
294
+ }
295
+
296
+ const wheeling = (e: WheelEvent) => {
297
+ // Set up timeout to detect wheel end
298
+ const id = setTimeout(() => wheelEnd(e), self.timeout)
299
+ self.clearTimeout()
300
+ self.clearTimeout = () => clearTimeout(id)
301
+
302
+ if (!self.active) {
303
+ wheelStart(e)
304
+ return
305
+ }
306
+
307
+ self.event = e
308
+ self._active = self.active
309
+
310
+ cpV(self.value, self._value)
311
+ vec2(e.clientX, e.clientY, self.origin)
312
+
313
+ // Calculate scale delta from wheel
314
+ const scaleDelta = wheelPinchDelta(e, self.offset[0] + 1)
315
+ self.delta[0] = scaleDelta
316
+ self.delta[1] = 0
317
+
318
+ self.value[0] += scaleDelta
319
+ addV(self.offset, self.delta, self.offset)
320
+ vec2(self.value[0] - 1, 0, self.movement)
321
+
322
+ self.scale = self.value[0]
323
+
324
+ self.pinch(self)
325
+ }
326
+
327
+ const wheelEnd = (e: Event) => {
328
+ if (!self.active) return
329
+ self.event = e
330
+ self._active = true
331
+ self.active = false
332
+ initValues()
333
+ self.pinch(self)
334
+ }
335
+
336
+ // ===== Lifecycle methods =====
337
+
338
+ const mount = (target: El) => {
339
+ self.target = target
340
+ const device = self.device
341
+
342
+ if (device === 'wheel') {
343
+ target.addEventListener('wheel', wheeling as EventListener, { passive: false })
344
+ } else if (device === 'gesture') {
345
+ const events = EVENT_FOR_PINCH.gesture
346
+ target.addEventListener(events.start, gestureStart)
347
+ target.addEventListener(events.change, gestureChange)
348
+ target.addEventListener(events.end, gestureEnd)
349
+ } else if (device === 'touch') {
350
+ const events = EVENT_FOR_PINCH.touch
351
+ target.addEventListener(events.start, touchStart as EventListener)
352
+ target.addEventListener(events.move, touchMove as EventListener)
353
+ target.addEventListener(events.end, touchEnd as EventListener)
354
+ target.addEventListener(events.cancel, touchEnd as EventListener)
355
+ } else if (device === 'pointer') {
356
+ const events = EVENT_FOR_PINCH.pointer
357
+ target.addEventListener(events.start, pointerStart as EventListener)
358
+ target.addEventListener(events.move, pointerMove as EventListener)
359
+ target.addEventListener(events.end, pointerEnd as EventListener)
360
+ target.addEventListener(events.cancel, pointerEnd as EventListener)
361
+ }
362
+ }
363
+
364
+ const clean = () => {
365
+ const target = self.target
366
+ if (!target) return
367
+ const device = self.device
368
+
369
+ if (device === 'wheel') {
370
+ target.removeEventListener('wheel', wheeling as EventListener)
371
+ } else if (device === 'gesture') {
372
+ const events = EVENT_FOR_PINCH.gesture
373
+ target.removeEventListener(events.start, gestureStart)
374
+ target.removeEventListener(events.change, gestureChange)
375
+ target.removeEventListener(events.end, gestureEnd)
376
+ } else if (device === 'touch') {
377
+ const events = EVENT_FOR_PINCH.touch
378
+ target.removeEventListener(events.start, touchStart as EventListener)
379
+ target.removeEventListener(events.move, touchMove as EventListener)
380
+ target.removeEventListener(events.end, touchEnd as EventListener)
381
+ target.removeEventListener(events.cancel, touchEnd as EventListener)
382
+ } else if (device === 'pointer') {
383
+ const events = EVENT_FOR_PINCH.pointer
384
+ target.removeEventListener(events.start, pointerStart as EventListener)
385
+ target.removeEventListener(events.move, pointerMove as EventListener)
386
+ target.removeEventListener(events.end, pointerEnd as EventListener)
387
+ target.removeEventListener(events.cancel, pointerEnd as EventListener)
388
+ }
389
+ }
390
+
391
+ const ref = (el: El | null) => {
392
+ self(config as PinchState<El>)
393
+ if (el) {
394
+ self.mount(el)
395
+ } else self.clean()
396
+ }
397
+
398
+ const self = event({
399
+ _active: false,
400
+ active: false,
401
+ device: pinchDevice(),
402
+ _value: vec2(0, 0),
403
+ value: vec2(0, 0),
404
+ delta: vec2(0, 0),
405
+ offset: vec2(0, 0),
406
+ movement: vec2(0, 0),
407
+ initial: vec2(0, 0),
408
+ origin: vec2(0, 0),
409
+ _touchIds: [] as number[],
410
+ _pointerEvents: new Map<number, PointerEvent>(),
411
+ scale: 1,
412
+ turns: 0,
413
+ target: null as unknown as El,
414
+ event: null as unknown as Event,
415
+ memo: {},
416
+ timeout: 100,
417
+ clearTimeout: () => {},
418
+ isPinchStart: false,
419
+ isPinching: false,
420
+ isPinchEnd: false,
421
+ pinch,
422
+ pinchStart: (e: Event) => {
423
+ // This is called externally, need to detect device and delegate
424
+ if (self.device === 'touch') touchStart(e as TouchEvent)
425
+ else if (self.device === 'pointer') pointerStart(e as PointerEvent)
426
+ else if (self.device === 'gesture') gestureStart(e)
427
+ else if (self.device === 'wheel') wheeling(e as WheelEvent)
428
+ },
429
+ pinching: (e: Event) => {
430
+ if (self.device === 'touch') touchMove(e as TouchEvent)
431
+ else if (self.device === 'pointer') pointerMove(e as PointerEvent)
432
+ else if (self.device === 'gesture') gestureChange(e)
433
+ else if (self.device === 'wheel') wheeling(e as WheelEvent)
434
+ },
435
+ pinchEnd: (e: Event) => {
436
+ if (self.device === 'touch') touchEnd(e as TouchEvent)
437
+ else if (self.device === 'pointer') pointerEnd(e as PointerEvent)
438
+ else if (self.device === 'gesture') gestureEnd(e)
439
+ else if (self.device === 'wheel') wheelEnd(e)
440
+ },
441
+ mount,
442
+ clean,
443
+ ref,
444
+ }) as EventState<PinchState<El>>
445
+
446
+ return self
447
+ }
@@ -0,0 +1,22 @@
1
+ import { useOnce, useMutable } from 'reev/src/react'
2
+ import { pinchEvent } from '.'
3
+ import { PinchArg, PinchState } from './types'
4
+ import { isF } from '../utils'
5
+ import type { ReactNode } from 'react'
6
+
7
+ export const usePinch = <El extends Element = Element>(arg?: PinchArg) => {
8
+ if (isF(arg)) arg = { pinch: arg }
9
+ const memo = useMutable(arg)
10
+ return useOnce(() => pinchEvent<El>(memo as any))
11
+ }
12
+
13
+ export default usePinch
14
+
15
+ export interface PinchProps<El extends Element = Element> extends Partial<PinchState<El>> {
16
+ children: (state: PinchState<El>) => ReactNode
17
+ }
18
+
19
+ export const Pinch = (props: PinchProps) => {
20
+ const { children, ...other } = props
21
+ return children(usePinch(other))
22
+ }
@@ -0,0 +1,63 @@
1
+ import { Vec2 } from '../utils'
2
+
3
+ export type PinchDevice = 'mouse' | 'pointer' | 'touch' | 'wheel' | 'gesture'
4
+
5
+ export interface PinchState<El extends Element = Element> {
6
+ device: PinchDevice
7
+
8
+ // Lifecycle flags
9
+ active: boolean
10
+ _active: boolean
11
+
12
+ // Pinch values: [distance, angle] for touch/pointer, [scale, rotation] for gesture
13
+ value: Vec2
14
+ _value: Vec2
15
+ delta: Vec2
16
+ offset: Vec2 // [cumulativeScale, cumulativeAngle]
17
+ movement: Vec2 // [scaleChange, angleChange] since start
18
+
19
+ // Initial values for computing relative changes
20
+ initial: Vec2
21
+
22
+ // Origin point (center between two fingers)
23
+ origin: Vec2
24
+
25
+ // Touch tracking
26
+ _touchIds: number[]
27
+
28
+ // Pointer tracking
29
+ _pointerEvents: Map<number, PointerEvent>
30
+
31
+ // Scale (derived from distance change)
32
+ scale: number
33
+
34
+ // Rotation turns (for tracking full rotations)
35
+ turns: number
36
+
37
+ // Element and event
38
+ target: El
39
+ event: Event | null
40
+ memo: Record<string, unknown>
41
+
42
+ // Timeout for wheel end detection
43
+ timeout: number
44
+ clearTimeout: () => void
45
+
46
+ // State flags
47
+ isPinchStart: boolean
48
+ isPinching: boolean
49
+ isPinchEnd: boolean
50
+
51
+ // Callbacks
52
+ pinch: (self: PinchState<El>) => void
53
+ pinchStart: (e: Event) => void
54
+ pinching: (e: Event) => void
55
+ pinchEnd: (e: Event) => void
56
+
57
+ // Lifecycle methods
58
+ mount: (target: El) => void
59
+ clean: () => void
60
+ ref: (el: El | null) => void
61
+ }
62
+
63
+ export type PinchArg<El extends Element = Element> = Partial<PinchState<El>> | PinchState<El>['pinch']
@@ -0,0 +1,106 @@
1
+ import { SUPPORT, Vec2, vec2 } from '../utils'
2
+
3
+ /**
4
+ * ref:
5
+ * https://github.com/pmndrs/use-gesture/blob/main/packages/core/src/config/pinchConfigResolver.ts
6
+ */
7
+ export const pinchDevice = (touch = false) => {
8
+ if (!SUPPORT.touch && SUPPORT.gesture) return 'gesture'
9
+ if (SUPPORT.touch && touch) return 'touch'
10
+ if (SUPPORT.touchscreen) {
11
+ if (SUPPORT.pointer) return 'pointer'
12
+ if (SUPPORT.touch) return 'touch'
13
+ }
14
+ return 'wheel'
15
+ }
16
+
17
+ /**
18
+ * Wheel delta normalization constants
19
+ * ref: https://github.com/facebookarchive/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js
20
+ */
21
+ const LINE_HEIGHT = 40
22
+ const PAGE_HEIGHT = 800
23
+ const PINCH_WHEEL_RATIO = 100
24
+
25
+ /**
26
+ * Calculate distance and angle between two touch/pointer points
27
+ * ref: https://github.com/pmndrs/use-gesture/blob/main/packages/core/src/utils/events.ts
28
+ */
29
+ export interface DistanceAngle {
30
+ distance: number
31
+ angle: number
32
+ origin: Vec2
33
+ }
34
+
35
+ export const distanceAngle = (p1: Touch | PointerEvent, p2: Touch | PointerEvent): DistanceAngle | null => {
36
+ try {
37
+ const dx = p2.clientX - p1.clientX
38
+ const dy = p2.clientY - p1.clientY
39
+ const cx = (p2.clientX + p1.clientX) / 2
40
+ const cy = (p2.clientY + p1.clientY) / 2
41
+
42
+ const distance = Math.hypot(dx, dy)
43
+ // Convert to degrees, negative to match natural gesture direction
44
+ const angle = -(Math.atan2(dx, dy) * 180) / Math.PI
45
+ const origin = vec2(cx, cy)
46
+
47
+ return { distance, angle, origin }
48
+ } catch {
49
+ return null
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Get touch distance and angle from touch event using stored touch ids
55
+ */
56
+ export const touchDistanceAngle = (event: TouchEvent, ids: number[]): DistanceAngle | null => {
57
+ const touches = Array.from(event.touches).filter((touch) => ids.includes(touch.identifier))
58
+ if (touches.length < 2) return null
59
+ return distanceAngle(touches[0], touches[1])
60
+ }
61
+
62
+ /**
63
+ * Get pointer distance and angle from pointer events map
64
+ */
65
+ export const pointerDistanceAngle = (pointerEvents: Map<number, PointerEvent>): DistanceAngle | null => {
66
+ const pointers = Array.from(pointerEvents.values())
67
+ if (pointers.length < 2) return null
68
+ return distanceAngle(pointers[0], pointers[1])
69
+ }
70
+
71
+ /**
72
+ * Get all touch identifiers for the current target
73
+ */
74
+ export const getCurrentTargetTouchIds = (event: TouchEvent): number[] => {
75
+ return Array.from(event.touches)
76
+ .filter((touch) => touch.target === event.currentTarget || (event.currentTarget as Node)?.contains?.(touch.target as Node))
77
+ .map((touch) => touch.identifier)
78
+ }
79
+
80
+ /**
81
+ * Normalize wheel values for pinch gesture (trackpad pinch)
82
+ * Returns scale delta based on wheel deltaY
83
+ */
84
+ export const wheelPinchDelta = (event: WheelEvent, currentScale: number): number => {
85
+ let { deltaY, deltaMode } = event
86
+
87
+ // Normalize wheel values
88
+ if (deltaMode === 1) {
89
+ deltaY *= LINE_HEIGHT
90
+ } else if (deltaMode === 2) {
91
+ deltaY *= PAGE_HEIGHT
92
+ }
93
+
94
+ // Convert to scale delta (negative because wheel down = zoom out)
95
+ return (-deltaY / PINCH_WHEEL_RATIO) * currentScale
96
+ }
97
+
98
+ /**
99
+ * WebKit gesture event type (Safari)
100
+ */
101
+ export interface WebKitGestureEvent extends UIEvent {
102
+ scale: number
103
+ rotation: number
104
+ clientX: number
105
+ clientY: number
106
+ }
package/src/react.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './drag/react'
2
+ export * from './hover/react'
3
+ export * from './key/react'
4
+ export * from './pinch/react'
5
+ export * from './resize/react'
6
+ export * from './scroll/react'
7
+ export * from './wheel/react'
@@ -0,0 +1,49 @@
1
+ import { EventState, event } from 'reev/src'
2
+ import { ResizeState } from './types'
3
+
4
+ export * from './types'
5
+
6
+ const DELAY = 100
7
+
8
+ type ResizeEventCallback = (entry: ResizeObserverEntry) => () => void
9
+
10
+ export const resizeEvent = <El extends Element = Element>(state: ResizeState) => {
11
+ const on: ResizeEventCallback = (entry) => () => {
12
+ // ???
13
+ }
14
+
15
+ const mount = (target: El) => {
16
+ const register = (entry: ResizeObserverEntry) => {
17
+ if (entry.target !== target) return
18
+ const id = setTimeout(on(entry), DELAY)
19
+ self.listener()
20
+ self.listener = () => clearTimeout(id)
21
+ }
22
+
23
+ self.observer = new ResizeObserver((entries) => {
24
+ entries.forEach(register)
25
+ })
26
+
27
+ self.observer.observe(target)
28
+ }
29
+
30
+ const clean = () => {}
31
+
32
+ const ref = (el: El) => {
33
+ self(state)
34
+ if (el) {
35
+ self.mount(el)
36
+ } else self.clean(null)
37
+ }
38
+
39
+ const self = event({
40
+ observer: null,
41
+ listener: () => {},
42
+ resize: () => {},
43
+ mount,
44
+ clean,
45
+ ref,
46
+ }) as EventState<ResizeState<El>>
47
+
48
+ return self
49
+ }