@tamagui/react-native-use-responder-events 1.0.1-beta.194

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 (48) hide show
  1. package/dist/cjs/PressResponder.js +373 -0
  2. package/dist/cjs/PressResponder.js.map +7 -0
  3. package/dist/cjs/ResponderSystem.js +365 -0
  4. package/dist/cjs/ResponderSystem.js.map +7 -0
  5. package/dist/cjs/ResponderTouchHistoryStore.js +184 -0
  6. package/dist/cjs/ResponderTouchHistoryStore.js.map +7 -0
  7. package/dist/cjs/createResponderEvent.js +152 -0
  8. package/dist/cjs/createResponderEvent.js.map +7 -0
  9. package/dist/cjs/index.js +19 -0
  10. package/dist/cjs/index.js.map +7 -0
  11. package/dist/cjs/types.js +98 -0
  12. package/dist/cjs/types.js.map +7 -0
  13. package/dist/cjs/useResponderEvents.js +76 -0
  14. package/dist/cjs/useResponderEvents.js.map +7 -0
  15. package/dist/cjs/utils.js +169 -0
  16. package/dist/cjs/utils.js.map +7 -0
  17. package/dist/esm/PressResponder.js +349 -0
  18. package/dist/esm/PressResponder.js.map +7 -0
  19. package/dist/esm/ResponderSystem.js +338 -0
  20. package/dist/esm/ResponderSystem.js.map +7 -0
  21. package/dist/esm/ResponderTouchHistoryStore.js +160 -0
  22. package/dist/esm/ResponderTouchHistoryStore.js.map +7 -0
  23. package/dist/esm/createResponderEvent.js +130 -0
  24. package/dist/esm/createResponderEvent.js.map +7 -0
  25. package/dist/esm/index.js +2 -0
  26. package/dist/esm/index.js.map +7 -0
  27. package/dist/esm/types.js +55 -0
  28. package/dist/esm/types.js.map +7 -0
  29. package/dist/esm/useResponderEvents.js +45 -0
  30. package/dist/esm/useResponderEvents.js.map +7 -0
  31. package/dist/esm/utils.js +137 -0
  32. package/dist/esm/utils.js.map +7 -0
  33. package/package.json +30 -0
  34. package/src/ResponderSystem.ts +531 -0
  35. package/src/ResponderTouchHistoryStore.ts +213 -0
  36. package/src/createResponderEvent.ts +187 -0
  37. package/src/index.ts +1 -0
  38. package/src/types.ts +78 -0
  39. package/src/useResponderEvents.ts +72 -0
  40. package/src/utils.ts +192 -0
  41. package/types/PressResponder.d.ts +92 -0
  42. package/types/ResponderSystem.d.ts +47 -0
  43. package/types/ResponderTouchHistoryStore.d.ts +37 -0
  44. package/types/createResponderEvent.d.ts +36 -0
  45. package/types/index.d.ts +2 -0
  46. package/types/types.d.ts +52 -0
  47. package/types/useResponderEvents.d.ts +9 -0
  48. package/types/utils.d.ts +38 -0
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import type { Touch, TouchEvent } from './types'
9
+ import { isEndish, isMoveish, isStartish } from './types'
10
+
11
+ type TouchRecord = {
12
+ currentPageX: number
13
+ currentPageY: number
14
+ currentTimeStamp: number
15
+ previousPageX: number
16
+ previousPageY: number
17
+ previousTimeStamp: number
18
+ startPageX: number
19
+ startPageY: number
20
+ startTimeStamp: number
21
+ touchActive: boolean
22
+ }
23
+
24
+ export type TouchHistory = {
25
+ indexOfSingleActiveTouch: number
26
+ mostRecentTimeStamp: number
27
+ numberActiveTouches: number
28
+ touchBank: Array<TouchRecord>
29
+ }
30
+
31
+ /**
32
+ * Tracks the position and time of each active touch by `touch.identifier`. We
33
+ * should typically only see IDs in the range of 1-20 because IDs get recycled
34
+ * when touches end and start again.
35
+ */
36
+
37
+ const MAX_TOUCH_BANK = 20
38
+
39
+ function timestampForTouch(touch: Touch): number {
40
+ // The legacy internal implementation provides "timeStamp", which has been
41
+ // renamed to "timestamp".
42
+ return touch['timeStamp'] || touch.timestamp
43
+ }
44
+
45
+ /**
46
+ * TODO: Instead of making gestures recompute filtered velocity, we could
47
+ * include a built in velocity computation that can be reused globally.
48
+ */
49
+ function createTouchRecord(touch: Touch): TouchRecord {
50
+ return {
51
+ touchActive: true,
52
+ startPageX: touch.pageX,
53
+ startPageY: touch.pageY,
54
+ startTimeStamp: timestampForTouch(touch),
55
+ currentPageX: touch.pageX,
56
+ currentPageY: touch.pageY,
57
+ currentTimeStamp: timestampForTouch(touch),
58
+ previousPageX: touch.pageX,
59
+ previousPageY: touch.pageY,
60
+ previousTimeStamp: timestampForTouch(touch),
61
+ }
62
+ }
63
+
64
+ function resetTouchRecord(touchRecord: TouchRecord, touch: Touch): void {
65
+ touchRecord.touchActive = true
66
+ touchRecord.startPageX = touch.pageX
67
+ touchRecord.startPageY = touch.pageY
68
+ touchRecord.startTimeStamp = timestampForTouch(touch)
69
+ touchRecord.currentPageX = touch.pageX
70
+ touchRecord.currentPageY = touch.pageY
71
+ touchRecord.currentTimeStamp = timestampForTouch(touch)
72
+ touchRecord.previousPageX = touch.pageX
73
+ touchRecord.previousPageY = touch.pageY
74
+ touchRecord.previousTimeStamp = timestampForTouch(touch)
75
+ }
76
+
77
+ function getTouchIdentifier({ identifier }: Touch): number {
78
+ if (identifier == null) {
79
+ // eslint-disable-next-line no-console
80
+ console.error('Touch object is missing identifier.')
81
+ }
82
+ if (process.env.NODE_ENV === 'development') {
83
+ if (identifier > MAX_TOUCH_BANK) {
84
+ // eslint-disable-next-line no-console
85
+ console.error(
86
+ 'Touch identifier %s is greater than maximum supported %s which causes ' +
87
+ 'performance issues backfilling array locations for all of the indices.',
88
+ identifier,
89
+ MAX_TOUCH_BANK
90
+ )
91
+ }
92
+ }
93
+ return identifier
94
+ }
95
+
96
+ function recordTouchStart(touch: Touch, touchHistory): void {
97
+ const identifier = getTouchIdentifier(touch)
98
+ const touchRecord = touchHistory.touchBank[identifier]
99
+ if (touchRecord) {
100
+ resetTouchRecord(touchRecord, touch)
101
+ } else {
102
+ touchHistory.touchBank[identifier] = createTouchRecord(touch)
103
+ }
104
+ touchHistory.mostRecentTimeStamp = timestampForTouch(touch)
105
+ }
106
+
107
+ function recordTouchMove(touch: Touch, touchHistory): void {
108
+ const touchRecord = touchHistory.touchBank[getTouchIdentifier(touch)]
109
+ if (touchRecord) {
110
+ touchRecord.touchActive = true
111
+ touchRecord.previousPageX = touchRecord.currentPageX
112
+ touchRecord.previousPageY = touchRecord.currentPageY
113
+ touchRecord.previousTimeStamp = touchRecord.currentTimeStamp
114
+ touchRecord.currentPageX = touch.pageX
115
+ touchRecord.currentPageY = touch.pageY
116
+ touchRecord.currentTimeStamp = timestampForTouch(touch)
117
+ touchHistory.mostRecentTimeStamp = timestampForTouch(touch)
118
+ } else {
119
+ console.warn(
120
+ 'Cannot record touch move without a touch start.\n',
121
+ `Touch Move: ${printTouch(touch)}\n`,
122
+ `Touch Bank: ${printTouchBank(touchHistory)}`
123
+ )
124
+ }
125
+ }
126
+
127
+ function recordTouchEnd(touch: Touch, touchHistory): void {
128
+ const touchRecord = touchHistory.touchBank[getTouchIdentifier(touch)]
129
+ if (touchRecord) {
130
+ touchRecord.touchActive = false
131
+ touchRecord.previousPageX = touchRecord.currentPageX
132
+ touchRecord.previousPageY = touchRecord.currentPageY
133
+ touchRecord.previousTimeStamp = touchRecord.currentTimeStamp
134
+ touchRecord.currentPageX = touch.pageX
135
+ touchRecord.currentPageY = touch.pageY
136
+ touchRecord.currentTimeStamp = timestampForTouch(touch)
137
+ touchHistory.mostRecentTimeStamp = timestampForTouch(touch)
138
+ } else {
139
+ console.warn(
140
+ 'Cannot record touch end without a touch start.\n',
141
+ `Touch End: ${printTouch(touch)}\n`,
142
+ `Touch Bank: ${printTouchBank(touchHistory)}`
143
+ )
144
+ }
145
+ }
146
+
147
+ function printTouch(touch: Touch): string {
148
+ return JSON.stringify({
149
+ identifier: touch.identifier,
150
+ pageX: touch.pageX,
151
+ pageY: touch.pageY,
152
+ timestamp: timestampForTouch(touch),
153
+ })
154
+ }
155
+
156
+ function printTouchBank(touchHistory): string {
157
+ const { touchBank } = touchHistory
158
+ let printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK))
159
+ if (touchBank.length > MAX_TOUCH_BANK) {
160
+ printed += ' (original size: ' + touchBank.length + ')'
161
+ }
162
+ return printed
163
+ }
164
+
165
+ export class ResponderTouchHistoryStore {
166
+ _touchHistory = {
167
+ touchBank: [], //Array<TouchRecord>
168
+ numberActiveTouches: 0,
169
+ // If there is only one active touch, we remember its location. This prevents
170
+ // us having to loop through all of the touches all the time in the most
171
+ // common case.
172
+ indexOfSingleActiveTouch: -1,
173
+ mostRecentTimeStamp: 0,
174
+ }
175
+
176
+ recordTouchTrack(topLevelType: string, nativeEvent: TouchEvent): void {
177
+ const touchHistory = this._touchHistory
178
+ if (isMoveish(topLevelType)) {
179
+ nativeEvent.changedTouches.forEach((touch) => recordTouchMove(touch, touchHistory))
180
+ } else if (isStartish(topLevelType)) {
181
+ nativeEvent.changedTouches.forEach((touch) => recordTouchStart(touch, touchHistory))
182
+ touchHistory.numberActiveTouches = nativeEvent.touches.length
183
+ if (touchHistory.numberActiveTouches === 1) {
184
+ touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier
185
+ }
186
+ } else if (isEndish(topLevelType)) {
187
+ nativeEvent.changedTouches.forEach((touch) => recordTouchEnd(touch, touchHistory))
188
+ touchHistory.numberActiveTouches = nativeEvent.touches.length
189
+ if (touchHistory.numberActiveTouches === 1) {
190
+ const { touchBank } = touchHistory
191
+ for (let i = 0; i < touchBank.length; i++) {
192
+ const touchTrackToCheck = touchBank[i]
193
+ // @ts-ignore
194
+ if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
195
+ touchHistory.indexOfSingleActiveTouch = i
196
+ break
197
+ }
198
+ }
199
+ if (process.env.NODE_ENV === 'development') {
200
+ const activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]
201
+ // @ts-ignore
202
+ if (!(activeRecord != null && activeRecord.touchActive)) {
203
+ console.error('Cannot find single active touch.')
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+
210
+ get touchHistory(): TouchHistory {
211
+ return this._touchHistory
212
+ }
213
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Copyright (c) Nicolas Gallagher
3
+ * This source code is licensed under the MIT license found in the
4
+ * LICENSE file in the root directory of this source tree.
5
+ */
6
+
7
+ import { ResponderTouchHistoryStore, TouchHistory } from './ResponderTouchHistoryStore'
8
+ import { getBoundingClientRect } from './utils'
9
+
10
+ export type ResponderEvent = {
11
+ bubbles: boolean
12
+ cancelable: boolean
13
+ currentTarget: any
14
+ defaultPrevented: boolean | null
15
+ dispatchConfig: {
16
+ registrationName?: string
17
+ phasedRegistrationNames?: {
18
+ bubbled: string
19
+ captured: string
20
+ }
21
+ }
22
+ eventPhase: number | null
23
+ isDefaultPrevented: () => boolean
24
+ isPropagationStopped: () => boolean
25
+ isTrusted: boolean | null
26
+ preventDefault: () => void
27
+ stopPropagation: () => void
28
+ nativeEvent: TouchEvent
29
+ persist: () => void
30
+ target: any | null
31
+ timeStamp: number
32
+ touchHistory: TouchHistory
33
+ }
34
+
35
+ const emptyFunction = () => {}
36
+ const emptyObject = {}
37
+ const emptyArray = []
38
+
39
+ /**
40
+ * Safari produces very large identifiers that would cause the `touchBank` array
41
+ * length to be so large as to crash the browser, if not normalized like this.
42
+ * In the future the `touchBank` should use an object/map instead.
43
+ */
44
+ function normalizeIdentifier(identifier) {
45
+ return identifier > 20 ? identifier % 20 : identifier
46
+ }
47
+
48
+ /**
49
+ * Converts a native DOM event to a ResponderEvent.
50
+ * Mouse events are transformed into fake touch events.
51
+ */
52
+ export default function createResponderEvent(
53
+ domEvent: any,
54
+ responderTouchHistoryStore: ResponderTouchHistoryStore
55
+ ): ResponderEvent {
56
+ let rect
57
+ let propagationWasStopped = false
58
+ let changedTouches
59
+ let touches
60
+
61
+ const domEventChangedTouches = domEvent.changedTouches
62
+ const domEventType = domEvent.type
63
+
64
+ const metaKey = domEvent.metaKey === true
65
+ const shiftKey = domEvent.shiftKey === true
66
+ const force = (domEventChangedTouches && domEventChangedTouches[0].force) || 0
67
+ const identifier = normalizeIdentifier(
68
+ (domEventChangedTouches && domEventChangedTouches[0].identifier) || 0
69
+ )
70
+ const clientX = (domEventChangedTouches && domEventChangedTouches[0].clientX) || domEvent.clientX
71
+ const clientY = (domEventChangedTouches && domEventChangedTouches[0].clientY) || domEvent.clientY
72
+ const pageX = (domEventChangedTouches && domEventChangedTouches[0].pageX) || domEvent.pageX
73
+ const pageY = (domEventChangedTouches && domEventChangedTouches[0].pageY) || domEvent.pageY
74
+ const preventDefault =
75
+ typeof domEvent.preventDefault === 'function'
76
+ ? domEvent.preventDefault.bind(domEvent)
77
+ : emptyFunction
78
+ const timestamp = domEvent.timeStamp
79
+
80
+ function normalizeTouches(touches) {
81
+ return Array.prototype.slice.call(touches).map((touch) => {
82
+ return {
83
+ force: touch.force,
84
+ identifier: normalizeIdentifier(touch.identifier),
85
+ get locationX() {
86
+ return locationX(touch.clientX)
87
+ },
88
+ get locationY() {
89
+ return locationY(touch.clientY)
90
+ },
91
+ pageX: touch.pageX,
92
+ pageY: touch.pageY,
93
+ target: touch.target,
94
+ timestamp,
95
+ }
96
+ })
97
+ }
98
+
99
+ if (domEventChangedTouches != null) {
100
+ changedTouches = normalizeTouches(domEventChangedTouches)
101
+ touches = normalizeTouches(domEvent.touches)
102
+ } else {
103
+ const emulatedTouches = [
104
+ {
105
+ force,
106
+ identifier,
107
+ get locationX() {
108
+ return locationX(clientX)
109
+ },
110
+ get locationY() {
111
+ return locationY(clientY)
112
+ },
113
+ pageX,
114
+ pageY,
115
+ target: domEvent.target,
116
+ timestamp,
117
+ },
118
+ ]
119
+ changedTouches = emulatedTouches
120
+ touches =
121
+ domEventType === 'mouseup' || domEventType === 'dragstart' ? emptyArray : emulatedTouches
122
+ }
123
+
124
+ const responderEvent = {
125
+ bubbles: true,
126
+ cancelable: true,
127
+ // `currentTarget` is set before dispatch
128
+ currentTarget: null,
129
+ defaultPrevented: domEvent.defaultPrevented,
130
+ dispatchConfig: emptyObject,
131
+ eventPhase: domEvent.eventPhase,
132
+ isDefaultPrevented() {
133
+ return domEvent.defaultPrevented
134
+ },
135
+ isPropagationStopped() {
136
+ return propagationWasStopped
137
+ },
138
+ isTrusted: domEvent.isTrusted,
139
+ nativeEvent: {
140
+ altKey: false,
141
+ ctrlKey: false,
142
+ metaKey,
143
+ shiftKey,
144
+ changedTouches,
145
+ force,
146
+ identifier,
147
+ get locationX() {
148
+ return locationX(clientX)
149
+ },
150
+ get locationY() {
151
+ return locationY(clientY)
152
+ },
153
+ pageX,
154
+ pageY,
155
+ target: domEvent.target,
156
+ timestamp,
157
+ touches,
158
+ type: domEventType,
159
+ },
160
+ persist: emptyFunction,
161
+ preventDefault,
162
+ stopPropagation() {
163
+ propagationWasStopped = true
164
+ },
165
+ target: domEvent.target,
166
+ timeStamp: timestamp,
167
+ touchHistory: responderTouchHistoryStore.touchHistory,
168
+ }
169
+
170
+ // Using getters and functions serves two purposes:
171
+ // 1) The value of `currentTarget` is not initially available.
172
+ // 2) Measuring the clientRect may cause layout jank and should only be done on-demand.
173
+ function locationX(x) {
174
+ rect = rect || getBoundingClientRect(responderEvent.currentTarget)
175
+ if (rect) {
176
+ return x - rect.left
177
+ }
178
+ }
179
+ function locationY(y) {
180
+ rect = rect || getBoundingClientRect(responderEvent.currentTarget)
181
+ if (rect) {
182
+ return y - rect.top
183
+ }
184
+ }
185
+
186
+ return responderEvent as any
187
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './useResponderEvents'
package/src/types.ts ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Copyright (c) Nicolas Gallagher
3
+ * This source code is licensed under the MIT license found in the
4
+ * LICENSE file in the root directory of this source tree.
5
+ */
6
+
7
+ export type Touch = {
8
+ force: number
9
+ identifier: number
10
+ // The locationX and locationY properties are non-standard additions
11
+ locationX: any
12
+ locationY: any
13
+ pageX: number
14
+ pageY: number
15
+ target: any
16
+ // Touches in a list have a timestamp property
17
+ timestamp: number
18
+ }
19
+
20
+ export type TouchEvent = {
21
+ altKey: boolean
22
+ ctrlKey: boolean
23
+ metaKey: boolean
24
+ shiftKey: boolean
25
+ // TouchList is an array in the Responder system
26
+ changedTouches: Array<Touch>
27
+ force: number
28
+ // React Native adds properties to the "nativeEvent that are usually only found on W3C Touches ‾\_(ツ)_/‾
29
+ identifier: number
30
+ locationX: any
31
+ locationY: any
32
+ pageX: number
33
+ pageY: number
34
+ target: any
35
+ // The timestamp has a lowercase "s" in the Responder system
36
+ timestamp: number
37
+ // TouchList is an array in the Responder system
38
+ touches: Array<Touch>
39
+ }
40
+
41
+ export const BLUR = 'blur'
42
+ export const CONTEXT_MENU = 'contextmenu'
43
+ export const FOCUS_OUT = 'focusout'
44
+ export const MOUSE_DOWN = 'mousedown'
45
+ export const MOUSE_MOVE = 'mousemove'
46
+ export const MOUSE_UP = 'mouseup'
47
+ export const MOUSE_CANCEL = 'dragstart'
48
+ export const TOUCH_START = 'touchstart'
49
+ export const TOUCH_MOVE = 'touchmove'
50
+ export const TOUCH_END = 'touchend'
51
+ export const TOUCH_CANCEL = 'touchcancel'
52
+ export const SCROLL = 'scroll'
53
+ export const SELECT = 'select'
54
+ export const SELECTION_CHANGE = 'selectionchange'
55
+
56
+ export function isStartish(eventType: unknown): boolean {
57
+ return eventType === TOUCH_START || eventType === MOUSE_DOWN
58
+ }
59
+
60
+ export function isMoveish(eventType: unknown): boolean {
61
+ return eventType === TOUCH_MOVE || eventType === MOUSE_MOVE
62
+ }
63
+
64
+ export function isEndish(eventType: unknown): boolean {
65
+ return eventType === TOUCH_END || eventType === MOUSE_UP || isCancelish(eventType)
66
+ }
67
+
68
+ export function isCancelish(eventType: unknown): boolean {
69
+ return eventType === TOUCH_CANCEL || eventType === MOUSE_CANCEL
70
+ }
71
+
72
+ export function isScroll(eventType: unknown): boolean {
73
+ return eventType === SCROLL
74
+ }
75
+
76
+ export function isSelectionChange(eventType: unknown): boolean {
77
+ return eventType === SELECT || eventType === SELECTION_CHANGE
78
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Copyright (c) Nicolas Gallagher
3
+ * This source code is licensed under the MIT license found in the
4
+ * LICENSE file in the root directory of this source tree.
5
+ */
6
+
7
+ import * as React from 'react'
8
+
9
+ import * as ResponderSystem from './ResponderSystem'
10
+
11
+ export * from './utils'
12
+
13
+ const emptyObject = {}
14
+
15
+ export function useResponderEvents(
16
+ hostRef: any,
17
+ config: ResponderSystem.ResponderConfig = emptyObject
18
+ ) {
19
+ const id = React.useId()
20
+ const isAttachedRef = React.useRef(false)
21
+
22
+ // This is a separate effects so it doesn't run when the config changes.
23
+ // On initial mount, attach global listeners if needed.
24
+ // On unmount, remove node potentially attached to the Responder System.
25
+ React.useEffect(() => {
26
+ ResponderSystem.attachListeners()
27
+ return () => {
28
+ ResponderSystem.removeNode(id)
29
+ }
30
+ }, [id])
31
+
32
+ // Register and unregister with the Responder System as necessary
33
+ React.useEffect(() => {
34
+ const {
35
+ onMoveShouldSetResponder,
36
+ onMoveShouldSetResponderCapture,
37
+ onScrollShouldSetResponder,
38
+ onScrollShouldSetResponderCapture,
39
+ onSelectionChangeShouldSetResponder,
40
+ onSelectionChangeShouldSetResponderCapture,
41
+ onStartShouldSetResponder,
42
+ onStartShouldSetResponderCapture,
43
+ } = config
44
+
45
+ const requiresResponderSystem =
46
+ onMoveShouldSetResponder != null ||
47
+ onMoveShouldSetResponderCapture != null ||
48
+ onScrollShouldSetResponder != null ||
49
+ onScrollShouldSetResponderCapture != null ||
50
+ onSelectionChangeShouldSetResponder != null ||
51
+ onSelectionChangeShouldSetResponderCapture != null ||
52
+ onStartShouldSetResponder != null ||
53
+ onStartShouldSetResponderCapture != null
54
+
55
+ const node = hostRef.current
56
+
57
+ if (requiresResponderSystem) {
58
+ ResponderSystem.addNode(id, node, config)
59
+ isAttachedRef.current = true
60
+ } else if (isAttachedRef.current) {
61
+ ResponderSystem.removeNode(id)
62
+ isAttachedRef.current = false
63
+ }
64
+ }, [config, hostRef, id])
65
+
66
+ if (process.env.NODE_ENV === 'development') {
67
+ React.useDebugValue({
68
+ isResponder: hostRef.current === ResponderSystem.getResponderNode(),
69
+ })
70
+ React.useDebugValue(config)
71
+ }
72
+ }