@tamagui/web 1.129.12 → 1.129.14
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/cjs/contexts/ComponentContext.cjs +1 -6
- package/dist/cjs/contexts/ComponentContext.js +1 -6
- package/dist/cjs/contexts/ComponentContext.js.map +1 -1
- package/dist/cjs/contexts/ComponentContext.native.js +1 -6
- package/dist/cjs/contexts/ComponentContext.native.js.map +2 -2
- package/dist/cjs/contexts/GroupContext.cjs +27 -0
- package/dist/cjs/contexts/GroupContext.js +22 -0
- package/dist/cjs/contexts/GroupContext.js.map +6 -0
- package/dist/cjs/contexts/GroupContext.native.js +26 -0
- package/dist/cjs/contexts/GroupContext.native.js.map +6 -0
- package/dist/cjs/createComponent.cjs +130 -89
- package/dist/cjs/createComponent.js +139 -93
- package/dist/cjs/createComponent.js.map +2 -2
- package/dist/cjs/createComponent.native.js +153 -105
- package/dist/cjs/createComponent.native.js.map +2 -2
- package/dist/cjs/helpers/createStyledContext.js.map +1 -1
- package/dist/cjs/helpers/createStyledContext.native.js.map +1 -1
- package/dist/cjs/helpers/getSplitStyles.cjs +68 -49
- package/dist/cjs/helpers/getSplitStyles.js +64 -55
- package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
- package/dist/cjs/helpers/getSplitStyles.native.js +82 -63
- package/dist/cjs/helpers/getSplitStyles.native.js.map +2 -2
- package/dist/cjs/helpers/pseudoDescriptors.cjs +12 -12
- package/dist/cjs/helpers/pseudoDescriptors.js +12 -12
- package/dist/cjs/helpers/pseudoDescriptors.js.map +1 -1
- package/dist/cjs/helpers/pseudoDescriptors.native.js +12 -12
- package/dist/cjs/helpers/pseudoDescriptors.native.js.map +1 -1
- package/dist/cjs/helpers/subscribeToContextGroup.cjs +48 -31
- package/dist/cjs/helpers/subscribeToContextGroup.js +36 -20
- package/dist/cjs/helpers/subscribeToContextGroup.js.map +1 -1
- package/dist/cjs/helpers/subscribeToContextGroup.native.js +48 -20
- package/dist/cjs/helpers/subscribeToContextGroup.native.js.map +2 -2
- package/dist/cjs/hooks/useComponentState.cjs +1 -40
- package/dist/cjs/hooks/useComponentState.js +1 -30
- package/dist/cjs/hooks/useComponentState.js.map +2 -2
- package/dist/cjs/hooks/useComponentState.native.js +3 -45
- package/dist/cjs/hooks/useComponentState.native.js.map +2 -2
- package/dist/cjs/hooks/useConfiguration.cjs +1 -17
- package/dist/cjs/hooks/useConfiguration.js +2 -9
- package/dist/cjs/hooks/useConfiguration.js.map +1 -1
- package/dist/cjs/hooks/useConfiguration.native.js +2 -7
- package/dist/cjs/hooks/useConfiguration.native.js.map +2 -2
- package/dist/cjs/hooks/useMedia.cjs +4 -3
- package/dist/cjs/hooks/useMedia.js +3 -3
- package/dist/cjs/hooks/useMedia.js.map +1 -1
- package/dist/cjs/hooks/useMedia.native.js +3 -3
- package/dist/cjs/hooks/useMedia.native.js.map +2 -2
- package/dist/cjs/hooks/useProps.cjs +7 -6
- package/dist/cjs/hooks/useProps.js +13 -11
- package/dist/cjs/hooks/useProps.js.map +1 -1
- package/dist/cjs/hooks/useProps.native.js +11 -10
- package/dist/cjs/hooks/useProps.native.js.map +2 -2
- package/dist/cjs/hooks/useThemeState.cjs +2 -2
- package/dist/cjs/hooks/useThemeState.js +2 -2
- package/dist/cjs/hooks/useThemeState.js.map +1 -1
- package/dist/cjs/hooks/useThemeState.native.js +2 -2
- package/dist/cjs/hooks/useThemeState.native.js.map +1 -1
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index.native.js +2 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/views/TamaguiProvider.js.map +1 -1
- package/dist/cjs/views/TamaguiProvider.native.js.map +1 -1
- package/dist/esm/contexts/ComponentContext.js +1 -6
- package/dist/esm/contexts/ComponentContext.js.map +1 -1
- package/dist/esm/contexts/ComponentContext.mjs +1 -6
- package/dist/esm/contexts/ComponentContext.mjs.map +1 -1
- package/dist/esm/contexts/ComponentContext.native.js +1 -6
- package/dist/esm/contexts/ComponentContext.native.js.map +1 -1
- package/dist/esm/contexts/GroupContext.js +6 -0
- package/dist/esm/contexts/GroupContext.js.map +6 -0
- package/dist/esm/contexts/GroupContext.mjs +4 -0
- package/dist/esm/contexts/GroupContext.mjs.map +1 -0
- package/dist/esm/contexts/GroupContext.native.js +4 -0
- package/dist/esm/contexts/GroupContext.native.js.map +1 -0
- package/dist/esm/createComponent.js +140 -92
- package/dist/esm/createComponent.js.map +2 -2
- package/dist/esm/createComponent.mjs +130 -89
- package/dist/esm/createComponent.mjs.map +1 -1
- package/dist/esm/createComponent.native.js +148 -101
- package/dist/esm/createComponent.native.js.map +1 -1
- package/dist/esm/helpers/createStyledContext.js.map +1 -1
- package/dist/esm/helpers/createStyledContext.mjs.map +1 -1
- package/dist/esm/helpers/createStyledContext.native.js.map +1 -1
- package/dist/esm/helpers/getSplitStyles.js +68 -56
- package/dist/esm/helpers/getSplitStyles.js.map +2 -2
- package/dist/esm/helpers/getSplitStyles.mjs +68 -49
- package/dist/esm/helpers/getSplitStyles.mjs.map +1 -1
- package/dist/esm/helpers/getSplitStyles.native.js +72 -53
- package/dist/esm/helpers/getSplitStyles.native.js.map +1 -1
- package/dist/esm/helpers/pseudoDescriptors.js +12 -12
- package/dist/esm/helpers/pseudoDescriptors.js.map +1 -1
- package/dist/esm/helpers/pseudoDescriptors.mjs +12 -12
- package/dist/esm/helpers/pseudoDescriptors.mjs.map +1 -1
- package/dist/esm/helpers/pseudoDescriptors.native.js +12 -12
- package/dist/esm/helpers/pseudoDescriptors.native.js.map +1 -1
- package/dist/esm/helpers/subscribeToContextGroup.js +36 -20
- package/dist/esm/helpers/subscribeToContextGroup.js.map +1 -1
- package/dist/esm/helpers/subscribeToContextGroup.mjs +47 -30
- package/dist/esm/helpers/subscribeToContextGroup.mjs.map +1 -1
- package/dist/esm/helpers/subscribeToContextGroup.native.js +64 -36
- package/dist/esm/helpers/subscribeToContextGroup.native.js.map +1 -1
- package/dist/esm/hooks/useComponentState.js +1 -30
- package/dist/esm/hooks/useComponentState.js.map +2 -2
- package/dist/esm/hooks/useComponentState.mjs +1 -40
- package/dist/esm/hooks/useComponentState.mjs.map +1 -1
- package/dist/esm/hooks/useComponentState.native.js +4 -48
- package/dist/esm/hooks/useComponentState.native.js.map +1 -1
- package/dist/esm/hooks/useConfiguration.js +1 -9
- package/dist/esm/hooks/useConfiguration.js.map +1 -1
- package/dist/esm/hooks/useConfiguration.mjs +1 -17
- package/dist/esm/hooks/useConfiguration.mjs.map +1 -1
- package/dist/esm/hooks/useConfiguration.native.js +1 -15
- package/dist/esm/hooks/useConfiguration.native.js.map +1 -1
- package/dist/esm/hooks/useMedia.js +3 -3
- package/dist/esm/hooks/useMedia.js.map +1 -1
- package/dist/esm/hooks/useMedia.mjs +4 -3
- package/dist/esm/hooks/useMedia.mjs.map +1 -1
- package/dist/esm/hooks/useMedia.native.js +4 -3
- package/dist/esm/hooks/useMedia.native.js.map +1 -1
- package/dist/esm/hooks/useProps.js +13 -10
- package/dist/esm/hooks/useProps.js.map +1 -1
- package/dist/esm/hooks/useProps.mjs +7 -6
- package/dist/esm/hooks/useProps.mjs.map +1 -1
- package/dist/esm/hooks/useProps.native.js +7 -6
- package/dist/esm/hooks/useProps.native.js.map +1 -1
- package/dist/esm/hooks/useThemeState.js +2 -2
- package/dist/esm/hooks/useThemeState.js.map +1 -1
- package/dist/esm/hooks/useThemeState.mjs +2 -2
- package/dist/esm/hooks/useThemeState.mjs.map +1 -1
- package/dist/esm/hooks/useThemeState.native.js +2 -2
- package/dist/esm/hooks/useThemeState.native.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +1 -0
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/views/TamaguiProvider.js.map +1 -1
- package/dist/esm/views/TamaguiProvider.mjs.map +1 -1
- package/dist/esm/views/TamaguiProvider.native.js.map +1 -1
- package/package.json +12 -12
- package/src/contexts/ComponentContext.tsx +0 -5
- package/src/contexts/GroupContext.tsx +4 -0
- package/src/createComponent.tsx +247 -108
- package/src/helpers/createStyledContext.tsx +1 -1
- package/src/helpers/getSplitStyles.tsx +77 -56
- package/src/helpers/pseudoDescriptors.ts +15 -19
- package/src/helpers/subscribeToContextGroup.tsx +70 -34
- package/src/hooks/useComponentState.ts +5 -49
- package/src/hooks/useConfiguration.tsx +1 -9
- package/src/hooks/useMedia.tsx +4 -2
- package/src/hooks/useProps.tsx +15 -10
- package/src/hooks/useThemeState.ts +2 -2
- package/src/index.ts +1 -0
- package/src/interfaces/TamaguiComponentState.tsx +4 -3
- package/src/types.tsx +32 -36
- package/src/views/TamaguiProvider.tsx +1 -0
- package/types/contexts/ComponentContext.d.ts.map +1 -1
- package/types/contexts/GroupContext.d.ts +3 -0
- package/types/contexts/GroupContext.d.ts.map +1 -0
- package/types/createComponent.d.ts +1 -1
- package/types/createComponent.d.ts.map +1 -1
- package/types/helpers/getSplitStyles.d.ts +2 -2
- package/types/helpers/getSplitStyles.d.ts.map +1 -1
- package/types/helpers/pseudoDescriptors.d.ts +14 -13
- package/types/helpers/pseudoDescriptors.d.ts.map +1 -1
- package/types/helpers/subscribeToContextGroup.d.ts +7 -6
- package/types/helpers/subscribeToContextGroup.d.ts.map +1 -1
- package/types/hooks/useComponentState.d.ts +3 -3
- package/types/hooks/useComponentState.d.ts.map +1 -1
- package/types/hooks/useConfiguration.d.ts +1 -121
- package/types/hooks/useConfiguration.d.ts.map +1 -1
- package/types/hooks/useMedia.d.ts +2 -2
- package/types/hooks/useMedia.d.ts.map +1 -1
- package/types/hooks/useProps.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/interfaces/TamaguiComponentState.d.ts +2 -2
- package/types/interfaces/TamaguiComponentState.d.ts.map +1 -1
- package/types/types.d.ts +21 -33
- package/types/types.d.ts.map +1 -1
- package/types/views/TamaguiProvider.d.ts.map +1 -1
package/src/createComponent.tsx
CHANGED
|
@@ -8,11 +8,13 @@ import {
|
|
|
8
8
|
useIsomorphicLayoutEffect,
|
|
9
9
|
} from '@tamagui/constants'
|
|
10
10
|
import { composeEventHandlers, validStyles } from '@tamagui/helpers'
|
|
11
|
-
import
|
|
11
|
+
import { isEqualShallow } from '@tamagui/is-equal-shallow'
|
|
12
|
+
import React, { type RefObject, useEffect, useId, useMemo } from 'react'
|
|
12
13
|
import { devConfig, onConfiguredOnce } from './config'
|
|
13
14
|
import { stackDefaultStyles } from './constants/constants'
|
|
14
15
|
import { isDevTools } from './constants/isDevTools'
|
|
15
16
|
import { ComponentContext } from './contexts/ComponentContext'
|
|
17
|
+
import { GroupContext } from './contexts/GroupContext'
|
|
16
18
|
import { didGetVariableValue, setDidGetVariableValue } from './createVariable'
|
|
17
19
|
import { defaultComponentStateMounted } from './defaultComponentState'
|
|
18
20
|
import { getShorthandValue } from './helpers/getShorthandValue'
|
|
@@ -31,19 +33,24 @@ import type { TamaguiComponentState } from './interfaces/TamaguiComponentState'
|
|
|
31
33
|
import type { WebOnlyPressEvents } from './interfaces/WebOnlyPressEvents'
|
|
32
34
|
import { hooks } from './setupHooks'
|
|
33
35
|
import type {
|
|
34
|
-
|
|
36
|
+
ComponentGroupEmitter,
|
|
37
|
+
ComponentGroupState,
|
|
35
38
|
DebugProp,
|
|
39
|
+
AllGroupContexts,
|
|
40
|
+
GroupStateListener,
|
|
36
41
|
LayoutEvent,
|
|
42
|
+
PseudoGroupState,
|
|
37
43
|
SizeTokens,
|
|
38
44
|
SpaceDirection,
|
|
39
|
-
SpaceValue,
|
|
40
45
|
SpacerProps,
|
|
41
46
|
SpacerStyleProps,
|
|
47
|
+
SpaceValue,
|
|
42
48
|
StackNonStyleProps,
|
|
43
49
|
StackProps,
|
|
44
50
|
StaticConfig,
|
|
45
51
|
StyleableOptions,
|
|
46
52
|
TamaguiComponent,
|
|
53
|
+
TamaguiComponentStateRef,
|
|
47
54
|
TamaguiElement,
|
|
48
55
|
TamaguiInternalConfig,
|
|
49
56
|
TextProps,
|
|
@@ -51,6 +58,7 @@ import type {
|
|
|
51
58
|
UseAnimationProps,
|
|
52
59
|
UseStyleEmitter,
|
|
53
60
|
UseThemeWithStateProps,
|
|
61
|
+
SingleGroupContext,
|
|
54
62
|
} from './types'
|
|
55
63
|
import { Slot } from './views/Slot'
|
|
56
64
|
import { getThemedChildren } from './views/Theme'
|
|
@@ -59,6 +67,7 @@ import { getThemedChildren } from './views/Theme'
|
|
|
59
67
|
* All things that need one-time setup after createTamagui is called
|
|
60
68
|
*/
|
|
61
69
|
let time: any
|
|
70
|
+
const NextState = new WeakMap<any, TamaguiComponentState | undefined>()
|
|
62
71
|
|
|
63
72
|
let debugKeyListeners: Set<Function> | undefined
|
|
64
73
|
let startVisualizer: Function | undefined
|
|
@@ -66,6 +75,16 @@ let startVisualizer: Function | undefined
|
|
|
66
75
|
type ComponentSetState = React.Dispatch<React.SetStateAction<TamaguiComponentState>>
|
|
67
76
|
|
|
68
77
|
export const componentSetStates = new Set<ComponentSetState>()
|
|
78
|
+
const avoidReRenderKeys = new Set([
|
|
79
|
+
'hover',
|
|
80
|
+
'press',
|
|
81
|
+
'pressIn',
|
|
82
|
+
'group',
|
|
83
|
+
'focus',
|
|
84
|
+
'focusWithin',
|
|
85
|
+
'media',
|
|
86
|
+
'group',
|
|
87
|
+
])
|
|
69
88
|
|
|
70
89
|
if (process.env.TAMAGUI_TARGET !== 'native' && typeof window !== 'undefined') {
|
|
71
90
|
const cancelTouches = () => {
|
|
@@ -92,7 +111,10 @@ if (process.env.TAMAGUI_TARGET !== 'native' && typeof window !== 'undefined') {
|
|
|
92
111
|
if (process.env.NODE_ENV === 'development') {
|
|
93
112
|
startVisualizer = () => {
|
|
94
113
|
const devVisualizerConfig = devConfig?.visualizer
|
|
95
|
-
|
|
114
|
+
|
|
115
|
+
if (devVisualizerConfig && !globalThis.__tamaguiDevVisualizer) {
|
|
116
|
+
globalThis.__tamaguiDevVisualizer = true
|
|
117
|
+
|
|
96
118
|
debugKeyListeners = new Set()
|
|
97
119
|
let tm
|
|
98
120
|
let isShowing = false
|
|
@@ -144,15 +166,21 @@ let BaseView: any
|
|
|
144
166
|
let hasSetupBaseViews = false
|
|
145
167
|
|
|
146
168
|
const lastInteractionWasKeyboard = { value: false }
|
|
147
|
-
if (isWeb &&
|
|
169
|
+
if (isWeb && typeof document !== 'undefined') {
|
|
148
170
|
document.addEventListener('keydown', () => {
|
|
149
|
-
lastInteractionWasKeyboard.value
|
|
171
|
+
if (!lastInteractionWasKeyboard.value) {
|
|
172
|
+
lastInteractionWasKeyboard.value = true
|
|
173
|
+
}
|
|
150
174
|
})
|
|
151
175
|
document.addEventListener('mousedown', () => {
|
|
152
|
-
lastInteractionWasKeyboard.value
|
|
176
|
+
if (lastInteractionWasKeyboard.value) {
|
|
177
|
+
lastInteractionWasKeyboard.value = false
|
|
178
|
+
}
|
|
153
179
|
})
|
|
154
180
|
document.addEventListener('mousemove', () => {
|
|
155
|
-
lastInteractionWasKeyboard.value
|
|
181
|
+
if (lastInteractionWasKeyboard.value) {
|
|
182
|
+
lastInteractionWasKeyboard.value = false
|
|
183
|
+
}
|
|
156
184
|
})
|
|
157
185
|
}
|
|
158
186
|
|
|
@@ -222,8 +250,6 @@ export function createComponent<
|
|
|
222
250
|
}
|
|
223
251
|
}
|
|
224
252
|
|
|
225
|
-
const componentContext = React.useContext(ComponentContext)
|
|
226
|
-
|
|
227
253
|
// set variants through context
|
|
228
254
|
// order is after default props but before props
|
|
229
255
|
let styledContextProps: Object | undefined
|
|
@@ -294,7 +320,7 @@ export function createComponent<
|
|
|
294
320
|
let overlay: HTMLSpanElement | null = null
|
|
295
321
|
|
|
296
322
|
const debugVisualizerHandler = (show = false) => {
|
|
297
|
-
const node =
|
|
323
|
+
const node = stateRef.current.host as HTMLElement
|
|
298
324
|
if (!node) return
|
|
299
325
|
|
|
300
326
|
if (show) {
|
|
@@ -338,21 +364,19 @@ export function createComponent<
|
|
|
338
364
|
}, [componentName])
|
|
339
365
|
}
|
|
340
366
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
*/
|
|
367
|
+
const componentContext = React.useContext(ComponentContext)
|
|
368
|
+
const groupContextParent = React.useContext(GroupContext)
|
|
344
369
|
const animationDriver = componentContext.animationDriver
|
|
345
370
|
const useAnimations = animationDriver?.useAnimations as UseAnimationHook | undefined
|
|
346
371
|
|
|
347
372
|
const componentState = useComponentState(
|
|
348
373
|
props,
|
|
349
|
-
|
|
374
|
+
animationDriver,
|
|
350
375
|
staticConfig,
|
|
351
376
|
config!
|
|
352
377
|
)
|
|
353
378
|
|
|
354
379
|
const {
|
|
355
|
-
curStateRef,
|
|
356
380
|
disabled,
|
|
357
381
|
groupName,
|
|
358
382
|
hasAnimationProp,
|
|
@@ -372,6 +396,60 @@ export function createComponent<
|
|
|
372
396
|
startedUnhydrated,
|
|
373
397
|
} = componentState
|
|
374
398
|
|
|
399
|
+
if (hasAnimationProp && animationDriver?.avoidReRenders) {
|
|
400
|
+
useIsomorphicLayoutEffect(() => {
|
|
401
|
+
const pendingState = NextState.get(stateRef)
|
|
402
|
+
if (pendingState) {
|
|
403
|
+
setStateShallow(pendingState)
|
|
404
|
+
NextState.set(stateRef, undefined)
|
|
405
|
+
}
|
|
406
|
+
})
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// create new context with groups, or else sublings will grab the same one
|
|
410
|
+
const allGroupContexts = useMemo((): AllGroupContexts | null => {
|
|
411
|
+
if (!groupName) {
|
|
412
|
+
return groupContextParent
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// TODO this shouldn't be in useMemo
|
|
416
|
+
stateRef.current.group?.listeners.clear()
|
|
417
|
+
const listeners = new Set<GroupStateListener>()
|
|
418
|
+
stateRef.current.group = {
|
|
419
|
+
listeners,
|
|
420
|
+
emit(state) {
|
|
421
|
+
listeners.forEach((l) => l(state))
|
|
422
|
+
},
|
|
423
|
+
subscribe(cb) {
|
|
424
|
+
listeners.add(cb)
|
|
425
|
+
if (listeners.size === 1) {
|
|
426
|
+
setStateShallow({ hasDynGroupChildren: true })
|
|
427
|
+
}
|
|
428
|
+
return () => {
|
|
429
|
+
listeners.delete(cb)
|
|
430
|
+
if (listeners.size === 0) {
|
|
431
|
+
setStateShallow({ hasDynGroupChildren: false })
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
...groupContextParent,
|
|
439
|
+
[groupName]: {
|
|
440
|
+
state: {
|
|
441
|
+
pseudo: defaultComponentStateMounted,
|
|
442
|
+
},
|
|
443
|
+
subscribe: (listener) => {
|
|
444
|
+
const dispose = stateRef.current.group?.subscribe(listener)
|
|
445
|
+
return () => {
|
|
446
|
+
dispose?.()
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
}
|
|
451
|
+
}, [stateRef, groupName, groupContextParent])
|
|
452
|
+
|
|
375
453
|
// if our animation driver supports noReRender, we'll replace this below with
|
|
376
454
|
// a version that essentially uses an internall emitter rather than setting state
|
|
377
455
|
// but still stores the current state and applies if it it needs to during render
|
|
@@ -412,13 +490,13 @@ export function createComponent<
|
|
|
412
490
|
if (process.env.NODE_ENV === 'development' && time) time`theme-props`
|
|
413
491
|
|
|
414
492
|
if (props.themeShallow) {
|
|
415
|
-
|
|
493
|
+
stateRef.current.themeShallow = true
|
|
416
494
|
}
|
|
417
495
|
|
|
418
496
|
const themeStateProps: UseThemeWithStateProps = {
|
|
419
497
|
componentName,
|
|
420
498
|
disable: disableTheme,
|
|
421
|
-
shallow:
|
|
499
|
+
shallow: stateRef.current.themeShallow,
|
|
422
500
|
debug: debugProp,
|
|
423
501
|
}
|
|
424
502
|
|
|
@@ -430,7 +508,7 @@ export function createComponent<
|
|
|
430
508
|
if ('theme' in props) {
|
|
431
509
|
themeStateProps.name = props.theme
|
|
432
510
|
}
|
|
433
|
-
if (typeof
|
|
511
|
+
if (typeof stateRef.current.isListeningToTheme === 'boolean') {
|
|
434
512
|
themeStateProps.needsUpdate = () => !!stateRef.current.isListeningToTheme
|
|
435
513
|
}
|
|
436
514
|
// on native we optimize theme changes if fastSchemeChange is enabled, otherwise deopt
|
|
@@ -482,7 +560,11 @@ export function createComponent<
|
|
|
482
560
|
log('props in:', propsIn)
|
|
483
561
|
log('final props:', props)
|
|
484
562
|
log({ state, staticConfig, elementType, themeStateProps })
|
|
485
|
-
log({
|
|
563
|
+
log({
|
|
564
|
+
contextProps: styledContextProps,
|
|
565
|
+
overriddenContextProps,
|
|
566
|
+
componentContext,
|
|
567
|
+
})
|
|
486
568
|
log({ presence, isAnimated, isHOC, hasAnimationProp, useAnimations })
|
|
487
569
|
console.groupEnd()
|
|
488
570
|
}
|
|
@@ -535,26 +617,87 @@ export function createComponent<
|
|
|
535
617
|
styleProps,
|
|
536
618
|
null,
|
|
537
619
|
componentContext,
|
|
620
|
+
allGroupContexts,
|
|
538
621
|
elementType,
|
|
539
622
|
startedUnhydrated,
|
|
540
623
|
debugProp
|
|
541
624
|
)
|
|
542
625
|
|
|
626
|
+
const groupContext = groupName ? allGroupContexts?.[groupName] || null : null
|
|
627
|
+
|
|
628
|
+
// one tiny mutation 🙏 get width/height optimistically from raw values if possible
|
|
629
|
+
// if set hardcoded it avoids extra renders
|
|
630
|
+
if (groupContext) {
|
|
631
|
+
const groupState = groupContext?.state
|
|
632
|
+
if (groupState && groupState.layout === undefined) {
|
|
633
|
+
if (splitStyles.style?.width || splitStyles.style?.height) {
|
|
634
|
+
groupState.layout = {
|
|
635
|
+
width: fromPx(splitStyles.style.width),
|
|
636
|
+
height: fromPx(splitStyles.style.height),
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
543
642
|
// avoids re-rendering if animation driver supports it
|
|
544
643
|
// TODO believe we need to set some sort of "pendingState" in case it re-renders
|
|
545
|
-
if (hasAnimationProp && animationDriver?.avoidReRenders) {
|
|
644
|
+
if ((hasAnimationProp || groupName) && animationDriver?.avoidReRenders) {
|
|
546
645
|
const styleListener = stateRef.current.useStyleListener
|
|
547
646
|
const ogSetStateShallow = setStateShallow
|
|
548
|
-
|
|
647
|
+
|
|
648
|
+
stateRef.current.setStateShallow = (nextOrGetNext) => {
|
|
649
|
+
const prev = NextState.get(stateRef) || state
|
|
650
|
+
const next =
|
|
651
|
+
typeof nextOrGetNext === 'function' ? nextOrGetNext(prev) : nextOrGetNext
|
|
652
|
+
|
|
653
|
+
if (next === prev || isEqualShallow(prev, next)) {
|
|
654
|
+
return
|
|
655
|
+
}
|
|
656
|
+
|
|
549
657
|
// one thing we have to handle here and where it gets a bit more complex is group styles
|
|
550
|
-
// but i think we can just emit to the group too?
|
|
551
|
-
const avoidReRenderKeys = new Set(['hover', 'press', 'pressIn'])
|
|
552
658
|
const canAvoidReRender = Object.keys(next).every((key) =>
|
|
553
659
|
avoidReRenderKeys.has(key)
|
|
554
660
|
)
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
661
|
+
|
|
662
|
+
if (canAvoidReRender) {
|
|
663
|
+
const updatedState = {
|
|
664
|
+
...prev,
|
|
665
|
+
...next,
|
|
666
|
+
}
|
|
667
|
+
NextState.set(stateRef, updatedState)
|
|
668
|
+
|
|
669
|
+
if (
|
|
670
|
+
process.env.NODE_ENV === 'development' &&
|
|
671
|
+
debugProp &&
|
|
672
|
+
debugProp !== 'profile'
|
|
673
|
+
) {
|
|
674
|
+
console.groupCollapsed(`[⚡️] avoid setState`, next, { updatedState, props })
|
|
675
|
+
console.info(stateRef.current.host)
|
|
676
|
+
console.groupEnd()
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
const {
|
|
680
|
+
group,
|
|
681
|
+
hasDynGroupChildren,
|
|
682
|
+
unmounted,
|
|
683
|
+
animation,
|
|
684
|
+
...childrenGroupState
|
|
685
|
+
} = updatedState
|
|
686
|
+
|
|
687
|
+
// update before getting styles
|
|
688
|
+
if (groupContext) {
|
|
689
|
+
notifyGroupSubscribers(
|
|
690
|
+
groupContext,
|
|
691
|
+
stateRef.current.group || null,
|
|
692
|
+
childrenGroupState
|
|
693
|
+
)
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// we just emit and return for group without animation ^
|
|
697
|
+
if (!hasAnimationProp || !styleListener) {
|
|
698
|
+
return
|
|
699
|
+
}
|
|
700
|
+
|
|
558
701
|
const nextStyles = getSplitStyles(
|
|
559
702
|
props,
|
|
560
703
|
staticConfig,
|
|
@@ -564,26 +707,42 @@ export function createComponent<
|
|
|
564
707
|
styleProps,
|
|
565
708
|
null,
|
|
566
709
|
componentContext,
|
|
710
|
+
allGroupContexts,
|
|
567
711
|
elementType,
|
|
568
712
|
startedUnhydrated,
|
|
569
713
|
debugProp
|
|
570
714
|
)
|
|
715
|
+
|
|
571
716
|
styleListener(nextStyles.style as any)
|
|
572
717
|
} else {
|
|
718
|
+
if (
|
|
719
|
+
process.env.NODE_ENV === 'development' &&
|
|
720
|
+
debugProp &&
|
|
721
|
+
debugProp !== 'profile'
|
|
722
|
+
) {
|
|
723
|
+
console.info(`[🐌] re-render`, { canAvoidReRender, next })
|
|
724
|
+
}
|
|
573
725
|
ogSetStateShallow(next)
|
|
574
726
|
}
|
|
575
727
|
}
|
|
728
|
+
|
|
729
|
+
// needs to capture latest props (it's called from memoized `events`)
|
|
730
|
+
setStateShallow = (state) => {
|
|
731
|
+
stateRef.current.setStateShallow?.(state)
|
|
732
|
+
}
|
|
576
733
|
}
|
|
577
734
|
|
|
578
735
|
if (process.env.NODE_ENV === 'development' && time) time`split-styles`
|
|
579
736
|
|
|
580
737
|
// hide strategy will set this opacity = 0 until measured
|
|
581
|
-
if (props.group && props.untilMeasured === 'hide' && !
|
|
738
|
+
if (props.group && props.untilMeasured === 'hide' && !stateRef.current.hasMeasured) {
|
|
582
739
|
splitStyles.style ||= {}
|
|
583
740
|
splitStyles.style.opacity = 0
|
|
584
741
|
}
|
|
585
742
|
|
|
586
|
-
|
|
743
|
+
if (splitStyles.dynamicThemeAccess != null) {
|
|
744
|
+
stateRef.current.isListeningToTheme = splitStyles.dynamicThemeAccess
|
|
745
|
+
}
|
|
587
746
|
|
|
588
747
|
// only listen for changes if we are using raw theme values or media space, or dynamic media (native)
|
|
589
748
|
// array = space media breakpoints
|
|
@@ -710,16 +869,16 @@ export function createComponent<
|
|
|
710
869
|
|
|
711
870
|
if (process.env.NODE_ENV === 'development' && time) time`destructure`
|
|
712
871
|
|
|
713
|
-
if (
|
|
872
|
+
if (groupContext) {
|
|
714
873
|
nonTamaguiProps.onLayout = composeEventHandlers(
|
|
715
874
|
nonTamaguiProps.onLayout,
|
|
716
875
|
(e: LayoutEvent) => {
|
|
876
|
+
// one off update here
|
|
717
877
|
const layout = e.nativeEvent.layout
|
|
718
|
-
|
|
719
|
-
stateRef.current.group
|
|
878
|
+
groupContext.state.layout = layout
|
|
879
|
+
stateRef.current.group?.emit({
|
|
720
880
|
layout,
|
|
721
881
|
})
|
|
722
|
-
|
|
723
882
|
// force re-render if measure strategy is hide
|
|
724
883
|
if (!stateRef.current.hasMeasured && props.untilMeasured === 'hide') {
|
|
725
884
|
setState((prev) => ({ ...prev }))
|
|
@@ -735,11 +894,11 @@ export function createComponent<
|
|
|
735
894
|
elementType,
|
|
736
895
|
nonTamaguiProps,
|
|
737
896
|
stateRef,
|
|
738
|
-
|
|
897
|
+
stateRef.current.willHydrate
|
|
739
898
|
) || nonTamaguiProps
|
|
740
899
|
|
|
741
|
-
if (!
|
|
742
|
-
|
|
900
|
+
if (!stateRef.current.composedRef) {
|
|
901
|
+
stateRef.current.composedRef = composeRefs<TamaguiElement>(
|
|
743
902
|
(x) => (stateRef.current.host = x as TamaguiElement),
|
|
744
903
|
forwardedRef,
|
|
745
904
|
setElementProps,
|
|
@@ -747,7 +906,7 @@ export function createComponent<
|
|
|
747
906
|
)
|
|
748
907
|
}
|
|
749
908
|
|
|
750
|
-
viewProps.ref =
|
|
909
|
+
viewProps.ref = stateRef.current.composedRef
|
|
751
910
|
|
|
752
911
|
if (process.env.NODE_ENV === 'development') {
|
|
753
912
|
if (!isReactNative && !isText && isWeb && !isHOC) {
|
|
@@ -822,44 +981,34 @@ export function createComponent<
|
|
|
822
981
|
}
|
|
823
982
|
|
|
824
983
|
// Only subscribe to context group if not disabled
|
|
825
|
-
const dispose =
|
|
826
|
-
!disabled && (pseudoGroups || mediaGroups)
|
|
827
|
-
? subscribeToContextGroup({
|
|
828
|
-
componentContext,
|
|
829
|
-
setStateShallow,
|
|
830
|
-
state,
|
|
831
|
-
mediaGroups,
|
|
832
|
-
pseudoGroups,
|
|
833
|
-
})
|
|
834
|
-
: null
|
|
835
984
|
|
|
836
985
|
return () => {
|
|
837
|
-
dispose?.()
|
|
838
986
|
componentSetStates.delete(setState)
|
|
839
987
|
}
|
|
988
|
+
}, [state.unmounted, disabled])
|
|
989
|
+
|
|
990
|
+
useIsomorphicLayoutEffect(() => {
|
|
991
|
+
if (disabled) return
|
|
992
|
+
if (!pseudoGroups && !mediaGroups) return
|
|
993
|
+
if (!allGroupContexts) return
|
|
994
|
+
return subscribeToContextGroup({
|
|
995
|
+
groupContext: allGroupContexts,
|
|
996
|
+
setStateShallow,
|
|
997
|
+
mediaGroups,
|
|
998
|
+
pseudoGroups,
|
|
999
|
+
})
|
|
840
1000
|
}, [
|
|
841
|
-
|
|
1001
|
+
allGroupContexts,
|
|
842
1002
|
disabled,
|
|
843
1003
|
pseudoGroups ? Object.keys([...pseudoGroups]).join('') : 0,
|
|
844
1004
|
mediaGroups ? Object.keys([...mediaGroups]).join('') : 0,
|
|
845
1005
|
])
|
|
846
1006
|
|
|
1007
|
+
const groupEmitter = stateRef.current.group
|
|
847
1008
|
useIsomorphicLayoutEffect(() => {
|
|
848
|
-
if (!
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
layout: curStateRef.group?.layout,
|
|
852
|
-
})
|
|
853
|
-
const groupContextState = componentContext?.groups
|
|
854
|
-
if (groupContextState) {
|
|
855
|
-
// and mutate the current since its concurrent safe (children throw it in useState on mount)
|
|
856
|
-
const next = {
|
|
857
|
-
...groupContextState[groupName],
|
|
858
|
-
...state,
|
|
859
|
-
}
|
|
860
|
-
groupContextState[groupName] = next
|
|
861
|
-
}
|
|
862
|
-
}, [groupName, state])
|
|
1009
|
+
if (!groupContext || !groupEmitter) return
|
|
1010
|
+
notifyGroupSubscribers(groupContext, groupEmitter, state)
|
|
1011
|
+
}, [groupContext, groupEmitter, state])
|
|
863
1012
|
|
|
864
1013
|
// if its a group its gotta listen for pseudos to emit them to children
|
|
865
1014
|
|
|
@@ -889,6 +1038,7 @@ export function createComponent<
|
|
|
889
1038
|
onClick ||
|
|
890
1039
|
pseudos?.focusVisibleStyle
|
|
891
1040
|
)
|
|
1041
|
+
|
|
892
1042
|
const runtimeHoverStyle = !disabled && noClass && pseudos?.hoverStyle
|
|
893
1043
|
const needsHoverState = Boolean(hasDynamicGroupChildren || runtimeHoverStyle)
|
|
894
1044
|
const attachHover =
|
|
@@ -958,10 +1108,8 @@ export function createComponent<
|
|
|
958
1108
|
next.hover = false
|
|
959
1109
|
}
|
|
960
1110
|
if (needsPressState) {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
next.pressIn = false
|
|
964
|
-
}
|
|
1111
|
+
next.press = false
|
|
1112
|
+
next.pressIn = false
|
|
965
1113
|
}
|
|
966
1114
|
setStateShallow(next)
|
|
967
1115
|
onHoverOut?.(e)
|
|
@@ -1004,22 +1152,20 @@ export function createComponent<
|
|
|
1004
1152
|
}),
|
|
1005
1153
|
...(attachFocus && {
|
|
1006
1154
|
onFocus: (e) => {
|
|
1155
|
+
const next: Partial<typeof state> = {}
|
|
1007
1156
|
if (componentContext.setParentFocusState) {
|
|
1008
|
-
|
|
1157
|
+
next.focusWithin = true
|
|
1009
1158
|
}
|
|
1010
1159
|
if (pseudos?.focusVisibleStyle) {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}, 0)
|
|
1160
|
+
if (lastInteractionWasKeyboard.value) {
|
|
1161
|
+
next.focusVisible = true
|
|
1162
|
+
} else {
|
|
1163
|
+
next.focus = true
|
|
1164
|
+
}
|
|
1017
1165
|
} else {
|
|
1018
|
-
|
|
1019
|
-
focus: true,
|
|
1020
|
-
focusVisible: false,
|
|
1021
|
-
})
|
|
1166
|
+
next.focus = true
|
|
1022
1167
|
}
|
|
1168
|
+
setStateShallow(next)
|
|
1023
1169
|
onFocus?.(e)
|
|
1024
1170
|
},
|
|
1025
1171
|
onBlur: (e) => {
|
|
@@ -1029,6 +1175,7 @@ export function createComponent<
|
|
|
1029
1175
|
setStateShallow({
|
|
1030
1176
|
focus: false,
|
|
1031
1177
|
focusVisible: false,
|
|
1178
|
+
focusWithin: false,
|
|
1032
1179
|
})
|
|
1033
1180
|
onBlur?.(e)
|
|
1034
1181
|
},
|
|
@@ -1132,38 +1279,10 @@ export function createComponent<
|
|
|
1132
1279
|
|
|
1133
1280
|
if (process.env.NODE_ENV === 'development' && time) time`create-element`
|
|
1134
1281
|
|
|
1135
|
-
|
|
1136
|
-
const groupState = curStateRef.group
|
|
1137
|
-
const subGroupContext = React.useMemo(() => {
|
|
1138
|
-
if (!groupState || !groupName) return
|
|
1139
|
-
groupState.listeners.clear()
|
|
1140
|
-
// change reference so context value updates
|
|
1141
|
-
|
|
1142
|
-
return {
|
|
1143
|
-
...componentContext.groups,
|
|
1144
|
-
// change reference so as we mutate it doesn't affect siblings etc
|
|
1145
|
-
state: {
|
|
1146
|
-
...componentContext.groups.state,
|
|
1147
|
-
[groupName]: {
|
|
1148
|
-
pseudo: defaultComponentStateMounted,
|
|
1149
|
-
// capture just initial width and height if they exist
|
|
1150
|
-
// will have top, left, width, height (not x, y)
|
|
1151
|
-
layout: {
|
|
1152
|
-
width: fromPx(splitStyles.style?.width),
|
|
1153
|
-
height: fromPx(splitStyles.style?.height),
|
|
1154
|
-
},
|
|
1155
|
-
},
|
|
1156
|
-
},
|
|
1157
|
-
emit: groupState.emit,
|
|
1158
|
-
subscribe: groupState.subscribe,
|
|
1159
|
-
} satisfies ComponentContextI['groups']
|
|
1160
|
-
}, [groupName])
|
|
1161
|
-
|
|
1162
|
-
if ('group' in props || propsIn.focusWithinStyle) {
|
|
1282
|
+
if ('focusWithinStyle' in propsIn) {
|
|
1163
1283
|
content = (
|
|
1164
1284
|
<ComponentContext.Provider
|
|
1165
1285
|
{...componentContext}
|
|
1166
|
-
groups={subGroupContext}
|
|
1167
1286
|
setParentFocusState={setStateShallow}
|
|
1168
1287
|
>
|
|
1169
1288
|
{content}
|
|
@@ -1171,6 +1290,12 @@ export function createComponent<
|
|
|
1171
1290
|
)
|
|
1172
1291
|
}
|
|
1173
1292
|
|
|
1293
|
+
if ('group' in props) {
|
|
1294
|
+
content = (
|
|
1295
|
+
<GroupContext.Provider value={allGroupContexts}>{content}</GroupContext.Provider>
|
|
1296
|
+
)
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1174
1299
|
if (process.env.NODE_ENV === 'development' && time) time`group-context`
|
|
1175
1300
|
|
|
1176
1301
|
content = disableTheme
|
|
@@ -1254,6 +1379,7 @@ export function createComponent<
|
|
|
1254
1379
|
log({
|
|
1255
1380
|
propsIn,
|
|
1256
1381
|
props,
|
|
1382
|
+
attachPress,
|
|
1257
1383
|
animationStyles,
|
|
1258
1384
|
classNames,
|
|
1259
1385
|
content,
|
|
@@ -1307,6 +1433,19 @@ export function createComponent<
|
|
|
1307
1433
|
return content
|
|
1308
1434
|
})
|
|
1309
1435
|
|
|
1436
|
+
function notifyGroupSubscribers(
|
|
1437
|
+
groupContext: SingleGroupContext | null,
|
|
1438
|
+
groupEmitter: ComponentGroupEmitter | null,
|
|
1439
|
+
pseudo: PseudoGroupState
|
|
1440
|
+
) {
|
|
1441
|
+
if (!groupContext || !groupEmitter) {
|
|
1442
|
+
return
|
|
1443
|
+
}
|
|
1444
|
+
const nextState = { ...groupContext.state, pseudo }
|
|
1445
|
+
groupEmitter.emit(nextState)
|
|
1446
|
+
groupContext.state = nextState
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1310
1449
|
// let hasLogged = false
|
|
1311
1450
|
|
|
1312
1451
|
if (staticConfig.componentName) {
|