@tamagui/web 1.85.3 → 1.85.5
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/createComponent.js +86 -111
- package/dist/cjs/createComponent.js.map +2 -2
- package/dist/cjs/createComponent.native.js +78 -106
- package/dist/cjs/createComponent.native.js.map +2 -2
- package/dist/cjs/helpers/ThemeManager.js +2 -3
- package/dist/cjs/helpers/ThemeManager.js.map +1 -1
- package/dist/cjs/helpers/ThemeManager.native.js +2 -3
- package/dist/cjs/helpers/ThemeManager.native.js.map +1 -1
- package/dist/cjs/helpers/createShallowSetState.js +4 -4
- package/dist/cjs/helpers/createShallowSetState.js.map +1 -1
- package/dist/cjs/helpers/createShallowSetState.native.js +4 -4
- package/dist/cjs/helpers/createShallowSetState.native.js.map +1 -1
- package/dist/cjs/helpers/getSplitStyles.js +12 -31
- package/dist/cjs/helpers/getSplitStyles.js.map +1 -1
- package/dist/cjs/helpers/getSplitStyles.native.js +7 -12
- package/dist/cjs/helpers/getSplitStyles.native.js.map +1 -1
- package/dist/cjs/helpers/getStylesAtomic.js +5 -11
- package/dist/cjs/helpers/getStylesAtomic.js.map +1 -1
- package/dist/cjs/helpers/insertStyleRule.js +2 -1
- package/dist/cjs/helpers/insertStyleRule.js.map +1 -1
- package/dist/cjs/helpers/insertStyleRule.native.js +2 -1
- package/dist/cjs/helpers/insertStyleRule.native.js.map +1 -1
- package/dist/cjs/helpers/pseudoDescriptors.js +1 -1
- package/dist/cjs/helpers/pseudoDescriptors.native.js +1 -1
- package/dist/cjs/hooks/useTheme.js +1 -1
- package/dist/cjs/hooks/useTheme.js.map +1 -1
- package/dist/cjs/hooks/useTheme.native.js +1 -1
- package/dist/cjs/hooks/useTheme.native.js.map +1 -1
- package/dist/cjs/views/TamaguiProvider.js +6 -6
- package/dist/cjs/views/TamaguiProvider.js.map +1 -1
- package/dist/cjs/views/TamaguiProvider.native.js +6 -6
- package/dist/cjs/views/TamaguiProvider.native.js.map +1 -1
- package/dist/cjs/views/Theme.js +1 -1
- package/dist/cjs/views/Theme.native.js +1 -1
- package/dist/esm/createComponent.js +75 -103
- package/dist/esm/createComponent.js.map +2 -2
- package/dist/esm/createComponent.native.js +67 -97
- package/dist/esm/createComponent.native.js.map +2 -2
- package/dist/esm/helpers/ThemeManager.js +2 -3
- package/dist/esm/helpers/ThemeManager.js.map +1 -1
- package/dist/esm/helpers/ThemeManager.native.js +2 -3
- package/dist/esm/helpers/ThemeManager.native.js.map +1 -1
- package/dist/esm/helpers/createShallowSetState.js +4 -4
- package/dist/esm/helpers/createShallowSetState.js.map +1 -1
- package/dist/esm/helpers/createShallowSetState.native.js +4 -4
- package/dist/esm/helpers/createShallowSetState.native.js.map +1 -1
- package/dist/esm/helpers/getSplitStyles.js +12 -31
- package/dist/esm/helpers/getSplitStyles.js.map +1 -1
- package/dist/esm/helpers/getSplitStyles.native.js +7 -12
- package/dist/esm/helpers/getSplitStyles.native.js.map +1 -1
- package/dist/esm/helpers/getStylesAtomic.js +5 -11
- package/dist/esm/helpers/getStylesAtomic.js.map +1 -1
- package/dist/esm/helpers/insertStyleRule.js +2 -1
- package/dist/esm/helpers/insertStyleRule.js.map +1 -1
- package/dist/esm/helpers/insertStyleRule.native.js +2 -1
- package/dist/esm/helpers/insertStyleRule.native.js.map +1 -1
- package/dist/esm/helpers/pseudoDescriptors.js +1 -1
- package/dist/esm/helpers/pseudoDescriptors.native.js +1 -1
- package/dist/esm/hooks/useTheme.js +1 -1
- package/dist/esm/hooks/useTheme.js.map +1 -1
- package/dist/esm/hooks/useTheme.native.js +1 -1
- package/dist/esm/hooks/useTheme.native.js.map +1 -1
- package/dist/esm/views/TamaguiProvider.js +6 -6
- package/dist/esm/views/TamaguiProvider.js.map +1 -1
- package/dist/esm/views/TamaguiProvider.native.js +6 -6
- package/dist/esm/views/TamaguiProvider.native.js.map +1 -1
- package/dist/esm/views/Theme.js +1 -1
- package/dist/esm/views/Theme.native.js +1 -1
- package/package.json +10 -10
- package/src/createComponent.tsx +169 -207
- package/src/helpers/ThemeManager.tsx +5 -12
- package/src/helpers/createShallowSetState.tsx +19 -4
- package/src/helpers/getSplitStyles.tsx +21 -57
- package/src/helpers/getStylesAtomic.ts +8 -9
- package/src/helpers/insertStyleRule.tsx +3 -5
- package/src/helpers/pseudoDescriptors.ts +2 -1
- package/src/hooks/useTheme.tsx +1 -1
- package/src/setupHooks.ts +2 -1
- package/src/types.tsx +0 -2
- package/src/views/TamaguiProvider.tsx +13 -10
- package/src/views/Theme.tsx +1 -1
- package/types/createComponent.d.ts.map +1 -1
- package/types/helpers/ThemeManager.d.ts.map +1 -1
- package/types/helpers/createShallowSetState.d.ts +3 -2
- package/types/helpers/createShallowSetState.d.ts.map +1 -1
- package/types/helpers/getSplitStyles.d.ts.map +1 -1
- package/types/helpers/getStylesAtomic.d.ts.map +1 -1
- package/types/helpers/insertStyleRule.d.ts.map +1 -1
- package/types/helpers/pseudoDescriptors.d.ts +1 -0
- package/types/helpers/pseudoDescriptors.d.ts.map +1 -1
- package/types/setupHooks.d.ts +1 -1
- package/types/setupHooks.d.ts.map +1 -1
- package/types/types.d.ts +0 -2
- package/types/types.d.ts.map +1 -1
- package/types/views/TamaguiProvider.d.ts.map +1 -1
package/src/createComponent.tsx
CHANGED
|
@@ -8,7 +8,6 @@ import React, {
|
|
|
8
8
|
createElement,
|
|
9
9
|
forwardRef,
|
|
10
10
|
memo,
|
|
11
|
-
useCallback,
|
|
12
11
|
useContext,
|
|
13
12
|
useEffect,
|
|
14
13
|
useId,
|
|
@@ -33,7 +32,6 @@ import {
|
|
|
33
32
|
import { useSplitStyles } from './helpers/getSplitStyles'
|
|
34
33
|
import { log } from './helpers/log'
|
|
35
34
|
import { mergeProps } from './helpers/mergeProps'
|
|
36
|
-
import { proxyThemeVariables } from './helpers/proxyThemeVariables'
|
|
37
35
|
import { themeable } from './helpers/themeable'
|
|
38
36
|
import { mediaKeyMatch, setMediaShouldUpdate, useMedia } from './hooks/useMedia'
|
|
39
37
|
import { useThemeWithState } from './hooks/useTheme'
|
|
@@ -75,7 +73,6 @@ process.env.TAMAGUI_TARGET
|
|
|
75
73
|
* All things that need one-time setup after createTamagui is called
|
|
76
74
|
*/
|
|
77
75
|
let tamaguiConfig: TamaguiInternalConfig
|
|
78
|
-
let initialTheme: any
|
|
79
76
|
let time: any
|
|
80
77
|
|
|
81
78
|
let debugKeyListeners: Set<Function> | undefined
|
|
@@ -147,33 +144,20 @@ export function createComponent<
|
|
|
147
144
|
Ref = TamaguiElement,
|
|
148
145
|
BaseProps = never,
|
|
149
146
|
>(staticConfig: StaticConfig) {
|
|
147
|
+
const { componentName } = staticConfig
|
|
148
|
+
|
|
150
149
|
let config: TamaguiInternalConfig | null = null
|
|
151
150
|
let defaultProps = staticConfig.defaultProps
|
|
152
151
|
|
|
153
152
|
onConfiguredOnce((conf) => {
|
|
154
153
|
config = conf
|
|
155
154
|
|
|
156
|
-
if (
|
|
157
|
-
const defaultForComponent = conf.defaultProps?.[
|
|
155
|
+
if (componentName) {
|
|
156
|
+
const defaultForComponent = conf.defaultProps?.[componentName]
|
|
158
157
|
if (defaultForComponent) {
|
|
159
158
|
defaultProps = { ...defaultForComponent, ...defaultProps }
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
|
-
|
|
163
|
-
// one time only setup
|
|
164
|
-
if (!tamaguiConfig) {
|
|
165
|
-
tamaguiConfig = conf
|
|
166
|
-
|
|
167
|
-
if (!initialTheme) {
|
|
168
|
-
const next = conf.themes[Object.keys(conf.themes)[0]]
|
|
169
|
-
initialTheme = proxyThemeVariables(next)
|
|
170
|
-
if (process.env.NODE_ENV === 'development') {
|
|
171
|
-
if (!initialTheme) {
|
|
172
|
-
log('Warning: Missing theme')
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
161
|
})
|
|
178
162
|
|
|
179
163
|
const {
|
|
@@ -185,11 +169,9 @@ export function createComponent<
|
|
|
185
169
|
variants = {},
|
|
186
170
|
} = staticConfig
|
|
187
171
|
|
|
188
|
-
const defaultComponentClassName = `is_${staticConfig.componentName}`
|
|
189
|
-
|
|
190
172
|
if (process.env.NODE_ENV === 'development' && staticConfig.defaultProps?.['debug']) {
|
|
191
173
|
if (process.env.IS_STATIC !== 'is_static') {
|
|
192
|
-
log(`🐛 [${
|
|
174
|
+
log(`🐛 [${componentName || 'Component'}]`, {
|
|
193
175
|
staticConfig,
|
|
194
176
|
defaultProps,
|
|
195
177
|
defaultPropsKeyOrder: defaultProps ? Object.keys(defaultProps) : [],
|
|
@@ -198,6 +180,7 @@ export function createComponent<
|
|
|
198
180
|
}
|
|
199
181
|
|
|
200
182
|
const component = forwardRef<Ref, ComponentPropTypes>((propsIn, forwardedRef) => {
|
|
183
|
+
// HOOK
|
|
201
184
|
const internalID = process.env.NODE_ENV === 'development' ? useId() : ''
|
|
202
185
|
|
|
203
186
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -227,6 +210,7 @@ export function createComponent<
|
|
|
227
210
|
}
|
|
228
211
|
}
|
|
229
212
|
|
|
213
|
+
// HOOK
|
|
230
214
|
const componentContext = useContext(ComponentContext)
|
|
231
215
|
|
|
232
216
|
// set variants through context
|
|
@@ -237,6 +221,7 @@ export function createComponent<
|
|
|
237
221
|
const { context } = staticConfig
|
|
238
222
|
|
|
239
223
|
if (context) {
|
|
224
|
+
// HOOK 3 (-1 if production)
|
|
240
225
|
contextValue = useContext(context)
|
|
241
226
|
const { inverseShorthands } = getConfig()
|
|
242
227
|
for (const key in context.props) {
|
|
@@ -280,6 +265,7 @@ export function createComponent<
|
|
|
280
265
|
const componentName = props.componentName || staticConfig.componentName
|
|
281
266
|
|
|
282
267
|
if (process.env.NODE_ENV === 'development' && isClient) {
|
|
268
|
+
// HOOK
|
|
283
269
|
useEffect(() => {
|
|
284
270
|
let overlay: HTMLSpanElement | null = null
|
|
285
271
|
|
|
@@ -339,18 +325,19 @@ export function createComponent<
|
|
|
339
325
|
}
|
|
340
326
|
if (process.env.NODE_ENV === 'development' && time) time`start (ignore)`
|
|
341
327
|
|
|
342
|
-
const isHydrated = config?.disableSSR ? true : useDidFinishSSR()
|
|
343
|
-
|
|
344
328
|
if (process.env.NODE_ENV === 'development' && time) time`did-finish-ssr`
|
|
345
329
|
|
|
346
330
|
// conditional but if ever true stays true
|
|
347
331
|
// [animated, inversed]
|
|
332
|
+
// HOOK
|
|
348
333
|
const stateRef = useRef(
|
|
349
334
|
{} as any as {
|
|
335
|
+
willHydrate?: boolean
|
|
350
336
|
hasMeasured?: boolean
|
|
351
337
|
hasAnimated?: boolean
|
|
352
338
|
themeShallow?: boolean
|
|
353
339
|
isListeningToTheme?: boolean
|
|
340
|
+
unPress?: Function
|
|
354
341
|
group?: {
|
|
355
342
|
listeners: Set<GroupStateListener>
|
|
356
343
|
emit: GroupStateListener
|
|
@@ -362,6 +349,7 @@ export function createComponent<
|
|
|
362
349
|
if (process.env.NODE_ENV === 'development' && time) time`stateref`
|
|
363
350
|
|
|
364
351
|
// TODO can remove and fold into stateRef
|
|
352
|
+
// HOOK
|
|
365
353
|
const hostRef = useRef<TamaguiElement>(null)
|
|
366
354
|
|
|
367
355
|
/**
|
|
@@ -377,43 +365,99 @@ export function createComponent<
|
|
|
377
365
|
|
|
378
366
|
// disable for now still ssr issues
|
|
379
367
|
const supportsCSSVars = animationsConfig?.supportsCSSVars
|
|
368
|
+
const curState = stateRef.current
|
|
380
369
|
|
|
381
|
-
const
|
|
382
|
-
if (isServer && !supportsCSSVars) return false
|
|
383
|
-
const curState = stateRef.current
|
|
370
|
+
const willBeAnimatedClient = (() => {
|
|
384
371
|
const next = !!(hasAnimationProp && !isHOC && useAnimations)
|
|
385
372
|
return Boolean(next || curState.hasAnimated)
|
|
386
373
|
})()
|
|
387
374
|
|
|
388
|
-
const
|
|
389
|
-
|
|
375
|
+
const willBeAnimated = !isServer && willBeAnimatedClient
|
|
376
|
+
|
|
377
|
+
// once animated, always animated to preserve hooks / vdom structure
|
|
378
|
+
if (willBeAnimated && !curState.hasAnimated) {
|
|
379
|
+
curState.hasAnimated = true
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// HOOK
|
|
383
|
+
const isHydrated = config?.disableSSR ? true : useDidFinishSSR()
|
|
384
|
+
|
|
385
|
+
// HOOK
|
|
386
|
+
const presence = (willBeAnimated && animationsConfig?.usePresence?.()) || null
|
|
387
|
+
const presenceState = presence?.[2]
|
|
388
|
+
const enterExitVariant = presenceState?.enterExitVariant
|
|
389
|
+
const enterVariant = enterExitVariant ?? presenceState?.enterVariant
|
|
390
390
|
|
|
391
391
|
const hasEnterStyle = !!props.enterStyle
|
|
392
|
-
|
|
392
|
+
// finish animated logic, avoid isAnimated when unmounted
|
|
393
|
+
const hasRNAnimation = hasAnimationProp && animationsConfig?.isReactNative
|
|
394
|
+
const isReactNative = staticConfig.isReactNative
|
|
395
|
+
|
|
396
|
+
// only web server + initial client render run this when not hydrated:
|
|
397
|
+
let isAnimated = willBeAnimated
|
|
398
|
+
if (!isReactNative && hasRNAnimation && !isHOC && !isHydrated) {
|
|
399
|
+
isAnimated = false
|
|
400
|
+
curState.willHydrate = true
|
|
401
|
+
}
|
|
393
402
|
|
|
394
403
|
if (process.env.NODE_ENV === 'development' && time) time`pre-use-state`
|
|
395
404
|
|
|
396
|
-
const initialState =
|
|
397
|
-
|
|
398
|
-
?
|
|
399
|
-
|
|
400
|
-
|
|
405
|
+
const initialState =
|
|
406
|
+
hasEnterStyle || enterVariant
|
|
407
|
+
? !isHydrated
|
|
408
|
+
? defaultComponentStateShouldEnter
|
|
409
|
+
: defaultComponentState
|
|
410
|
+
: defaultComponentStateMounted
|
|
401
411
|
|
|
412
|
+
// HOOK
|
|
402
413
|
const states = useState<TamaguiComponentState>(initialState)
|
|
403
414
|
|
|
404
|
-
const state =
|
|
405
|
-
? { ...states[0], [
|
|
415
|
+
const state = props.forceStyle
|
|
416
|
+
? { ...states[0], [props.forceStyle]: true }
|
|
406
417
|
: states[0]
|
|
418
|
+
|
|
407
419
|
const setState = states[1]
|
|
420
|
+
let setStateShallow = createShallowSetState(setState, debugProp)
|
|
421
|
+
|
|
422
|
+
if (isHydrated && state.unmounted === 'should-enter') {
|
|
423
|
+
state.unmounted = true
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// set enter/exit variants onto our new props object
|
|
427
|
+
if (presenceState && isAnimated && isHydrated) {
|
|
428
|
+
const isExiting = !presenceState.isPresent
|
|
429
|
+
const exitVariant = enterExitVariant ?? presenceState.exitVariant
|
|
430
|
+
|
|
431
|
+
if (state.unmounted && enterVariant) {
|
|
432
|
+
if (process.env.NODE_ENV === 'development' && debugProp === 'verbose') {
|
|
433
|
+
console.warn(`Animating presence ENTER "${enterVariant}"`)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
props[enterVariant] = true
|
|
437
|
+
} else if (isExiting && exitVariant) {
|
|
438
|
+
if (process.env.NODE_ENV === 'development' && debugProp === 'verbose') {
|
|
439
|
+
console.warn(`Animating presence EXIT "${enterVariant}"`)
|
|
440
|
+
}
|
|
408
441
|
|
|
409
|
-
|
|
442
|
+
props[exitVariant] = enterExitVariant ? false : true
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const shouldAvoidClasses = Boolean(
|
|
447
|
+
!isWeb ||
|
|
448
|
+
(isAnimated && !supportsCSSVars) ||
|
|
449
|
+
!staticConfig.acceptsClassName ||
|
|
450
|
+
propsIn.disableClassName
|
|
451
|
+
)
|
|
452
|
+
const shouldForcePseudo = !!propsIn.forceStyle
|
|
453
|
+
const noClassNames = shouldAvoidClasses || shouldForcePseudo
|
|
410
454
|
|
|
411
455
|
const groupName = props.group as any as string
|
|
412
456
|
const groupClassName = groupName ? `t_group_${props.group}` : ''
|
|
413
457
|
|
|
414
|
-
if (groupName && !
|
|
458
|
+
if (groupName && !curState.group) {
|
|
415
459
|
const listeners = new Set<GroupStateListener>()
|
|
416
|
-
|
|
460
|
+
curState.group = {
|
|
417
461
|
listeners,
|
|
418
462
|
emit(name, state) {
|
|
419
463
|
listeners.forEach((l) => l(name, state))
|
|
@@ -433,7 +477,7 @@ export function createComponent<
|
|
|
433
477
|
const og = setStateShallow
|
|
434
478
|
setStateShallow = (state) => {
|
|
435
479
|
og(state)
|
|
436
|
-
|
|
480
|
+
curState.group!.emit(groupName, {
|
|
437
481
|
pseudo: state,
|
|
438
482
|
})
|
|
439
483
|
// and mutate the current since its concurrent safe (children throw it in useState on mount)
|
|
@@ -447,26 +491,9 @@ export function createComponent<
|
|
|
447
491
|
|
|
448
492
|
if (process.env.NODE_ENV === 'development' && time) time`use-state`
|
|
449
493
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
if (!presence && isHydrated) {
|
|
454
|
-
if (isServer || state.unmounted === true) {
|
|
455
|
-
isAnimated = false
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// once animated, always animated to preserve hooks
|
|
461
|
-
if (willBeAnimated && !stateRef.current.hasAnimated) {
|
|
462
|
-
stateRef.current.hasAnimated = true
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const componentClassName = props.asChild
|
|
466
|
-
? ''
|
|
467
|
-
: props.componentName
|
|
468
|
-
? `is_${props.componentName}`
|
|
469
|
-
: defaultComponentClassName
|
|
494
|
+
const componentNameFinal = props.componentName || componentName
|
|
495
|
+
const componentClassName =
|
|
496
|
+
props.asChild || !componentNameFinal ? '' : `is_${componentNameFinal}`
|
|
470
497
|
|
|
471
498
|
const hasTextAncestor = !!(isWeb && isText ? componentContext.inText : false)
|
|
472
499
|
const isDisabled = props.disabled ?? props.accessibilityState?.disabled
|
|
@@ -481,45 +508,11 @@ export function createComponent<
|
|
|
481
508
|
const BaseViewComponent = BaseView || element || (hasTextAncestor ? 'span' : 'div')
|
|
482
509
|
|
|
483
510
|
let elementType = isText ? BaseTextComponent : BaseViewComponent
|
|
484
|
-
if (animationsConfig && willBeAnimated) {
|
|
485
|
-
elementType = animationsConfig[isText ? 'Text' : 'View'] || elementType
|
|
486
|
-
}
|
|
487
511
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const presenceState = presence[2]
|
|
491
|
-
if (presenceState) {
|
|
492
|
-
const isEntering = state.unmounted
|
|
493
|
-
const isExiting = !presenceState.isPresent
|
|
494
|
-
const enterExitVariant = presenceState.enterExitVariant
|
|
495
|
-
const enterVariant = enterExitVariant ?? presenceState.enterVariant
|
|
496
|
-
const exitVariant = enterExitVariant ?? presenceState.exitVariant
|
|
497
|
-
|
|
498
|
-
if (isEntering && enterVariant) {
|
|
499
|
-
if (process.env.NODE_ENV === 'development' && debugProp === 'verbose') {
|
|
500
|
-
console.warn(`Animating presence ENTER "${enterVariant}"`)
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
props[enterVariant] = true
|
|
504
|
-
} else if (isExiting && exitVariant) {
|
|
505
|
-
if (process.env.NODE_ENV === 'development' && debugProp === 'verbose') {
|
|
506
|
-
console.warn(`Animating presence EXIT "${enterVariant}"`)
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
props[exitVariant] = enterExitVariant ? false : true
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
+
if (animationsConfig && isAnimated) {
|
|
513
|
+
elementType = animationsConfig[isText ? 'Text' : 'View'] || elementType
|
|
512
514
|
}
|
|
513
515
|
|
|
514
|
-
const isAnimatedReactNative = hasAnimationProp && animationsConfig?.isReactNative
|
|
515
|
-
const isReactNative = Boolean(staticConfig.isReactNative || isAnimatedReactNative)
|
|
516
|
-
const shouldAvoidClasses = Boolean(
|
|
517
|
-
!isWeb || isAnimated || !staticConfig.acceptsClassName || propsIn.disableClassName
|
|
518
|
-
)
|
|
519
|
-
|
|
520
|
-
const shouldForcePseudo = !!propsIn.forceStyle
|
|
521
|
-
const noClassNames = shouldAvoidClasses || shouldForcePseudo
|
|
522
|
-
|
|
523
516
|
// internal use only
|
|
524
517
|
const disableThemeProp =
|
|
525
518
|
process.env.TAMAGUI_TARGET === 'native' ? false : props['data-disable-theme']
|
|
@@ -528,19 +521,19 @@ export function createComponent<
|
|
|
528
521
|
if (process.env.NODE_ENV === 'development' && time) time`theme-props`
|
|
529
522
|
|
|
530
523
|
if (props.themeShallow) {
|
|
531
|
-
|
|
524
|
+
curState.themeShallow = true
|
|
532
525
|
}
|
|
533
526
|
|
|
534
527
|
const themeStateProps: UseThemeWithStateProps = {
|
|
535
528
|
name: props.theme,
|
|
536
529
|
componentName,
|
|
537
530
|
disable: disableTheme,
|
|
538
|
-
shallow:
|
|
531
|
+
shallow: curState.themeShallow,
|
|
539
532
|
inverse: props.themeInverse,
|
|
540
533
|
debug: debugProp,
|
|
541
534
|
}
|
|
542
535
|
|
|
543
|
-
if (typeof
|
|
536
|
+
if (typeof curState.isListeningToTheme === 'boolean') {
|
|
544
537
|
themeStateProps.shouldUpdate = () => stateRef.current.isListeningToTheme
|
|
545
538
|
}
|
|
546
539
|
|
|
@@ -553,45 +546,35 @@ export function createComponent<
|
|
|
553
546
|
|
|
554
547
|
if (process.env.NODE_ENV === 'development') {
|
|
555
548
|
if (debugProp && debugProp !== 'profile') {
|
|
556
|
-
// prettier-ignore
|
|
557
549
|
const name = `${
|
|
558
550
|
componentName ||
|
|
559
551
|
Component?.displayName ||
|
|
560
552
|
Component?.name ||
|
|
561
553
|
'[Unnamed Component]'
|
|
562
554
|
}`
|
|
563
|
-
const type =
|
|
555
|
+
const type =
|
|
556
|
+
(hasEnterStyle ? '(hasEnter)' : '') +
|
|
557
|
+
(isAnimated ? '(animated)' : '') +
|
|
558
|
+
(isReactNative ? '(rnw)' : '')
|
|
564
559
|
const dataIs = propsIn['data-is'] || ''
|
|
565
|
-
const banner = `${name}${dataIs ? ` ${dataIs}` : ''} ${type}
|
|
560
|
+
const banner = `${internalID} ${name}${dataIs ? ` ${dataIs}` : ''} ${type}`
|
|
566
561
|
console.group(
|
|
567
|
-
`%c ${banner} (unmounted: ${state.unmounted})
|
|
568
|
-
presence ? ` (presence: ${presence[0]})` : ''
|
|
569
|
-
} ${isHydrated ? '💦' : '🏜️'}`,
|
|
562
|
+
`%c ${banner} (hydrated: ${isHydrated}) (unmounted: ${state.unmounted})`,
|
|
570
563
|
'background: green; color: white;'
|
|
571
564
|
)
|
|
572
565
|
if (!isServer) {
|
|
566
|
+
// if strict mode or something messes with our nesting this fixes:
|
|
567
|
+
console.groupEnd()
|
|
568
|
+
console.groupEnd()
|
|
569
|
+
|
|
573
570
|
console.groupCollapsed(
|
|
574
571
|
`Info (collapsed): ${state.press || state.pressIn ? 'PRESSED ' : ''}${
|
|
575
572
|
state.hover ? 'HOVERED ' : ''
|
|
576
573
|
}${state.focus ? 'FOCUSED' : ' '}`
|
|
577
574
|
)
|
|
578
|
-
|
|
579
|
-
log({
|
|
580
|
-
|
|
581
|
-
props,
|
|
582
|
-
state,
|
|
583
|
-
staticConfig,
|
|
584
|
-
elementType,
|
|
585
|
-
themeStateProps,
|
|
586
|
-
styledContext: { contextProps: styledContextProps, overriddenContextProps },
|
|
587
|
-
presence,
|
|
588
|
-
isAnimated,
|
|
589
|
-
isHOC,
|
|
590
|
-
hasAnimationProp,
|
|
591
|
-
useAnimations,
|
|
592
|
-
propsInOrder: Object.keys(propsIn),
|
|
593
|
-
propsOrder: Object.keys(props),
|
|
594
|
-
})
|
|
575
|
+
log({ propsIn, props, state, staticConfig, elementType, themeStateProps })
|
|
576
|
+
log({ contextProps: styledContextProps, overriddenContextProps })
|
|
577
|
+
log({ presence, isAnimated, isHOC, hasAnimationProp, useAnimations })
|
|
595
578
|
console.groupEnd()
|
|
596
579
|
}
|
|
597
580
|
}
|
|
@@ -599,6 +582,7 @@ export function createComponent<
|
|
|
599
582
|
|
|
600
583
|
if (process.env.NODE_ENV === 'development' && time) time`pre-theme-media`
|
|
601
584
|
|
|
585
|
+
// HOOK 10-13 (-1 if no animation, -1 if disableSSR, -1 if no context, -1 if production)
|
|
602
586
|
const [themeState, theme] = useThemeWithState(themeStateProps)
|
|
603
587
|
|
|
604
588
|
elementType = Component || elementType
|
|
@@ -606,6 +590,7 @@ export function createComponent<
|
|
|
606
590
|
|
|
607
591
|
if (process.env.NODE_ENV === 'development' && time) time`theme`
|
|
608
592
|
|
|
593
|
+
// HOOK 14 (-1 if no animation, -1 if disableSSR, -1 if no context, -1 if production)
|
|
609
594
|
const mediaState = useMedia(stateRef, componentContext)
|
|
610
595
|
|
|
611
596
|
if (process.env.NODE_ENV === 'development' && time) time`media`
|
|
@@ -619,18 +604,15 @@ export function createComponent<
|
|
|
619
604
|
? 'value'
|
|
620
605
|
: 'auto'
|
|
621
606
|
|
|
622
|
-
// temp: once we fix above we can disable this
|
|
623
|
-
const keepStyleSSR = willBeAnimated && animationsConfig?.keepStyleSSR
|
|
624
|
-
|
|
625
607
|
const styleProps = {
|
|
626
608
|
mediaState,
|
|
627
609
|
noClassNames,
|
|
628
610
|
resolveValues,
|
|
629
611
|
isExiting,
|
|
630
612
|
isAnimated,
|
|
631
|
-
keepStyleSSR,
|
|
632
613
|
} as const
|
|
633
614
|
|
|
615
|
+
// HOOK 15 (-1 if no animation, -1 if disableSSR, -1 if no context, -1 if production)
|
|
634
616
|
const splitStyles = useSplitStyles(
|
|
635
617
|
props,
|
|
636
618
|
staticConfig,
|
|
@@ -645,13 +627,13 @@ export function createComponent<
|
|
|
645
627
|
)
|
|
646
628
|
|
|
647
629
|
// hide strategy will set this opacity = 0 until measured
|
|
648
|
-
if (props.group && props.untilMeasured === 'hide' && !
|
|
630
|
+
if (props.group && props.untilMeasured === 'hide' && !curState.hasMeasured) {
|
|
649
631
|
splitStyles.style.opacity = 0
|
|
650
632
|
}
|
|
651
633
|
|
|
652
634
|
if (process.env.NODE_ENV === 'development' && time) time`split-styles`
|
|
653
635
|
|
|
654
|
-
|
|
636
|
+
curState.isListeningToTheme = splitStyles.dynamicThemeAccess
|
|
655
637
|
|
|
656
638
|
// only listen for changes if we are using raw theme values or media space, or dynamic media (native)
|
|
657
639
|
// array = space media breakpoints
|
|
@@ -667,34 +649,6 @@ export function createComponent<
|
|
|
667
649
|
keys: mediaListeningKeys,
|
|
668
650
|
})
|
|
669
651
|
|
|
670
|
-
// animation setup
|
|
671
|
-
const isAnimatedReactNativeWeb = hasAnimationProp && isReactNative
|
|
672
|
-
|
|
673
|
-
if (process.env.NODE_ENV === 'development') {
|
|
674
|
-
if (!process.env.TAMAGUI_TARGET) {
|
|
675
|
-
console.error(
|
|
676
|
-
`No process.env.TAMAGUI_TARGET set, please set it to "native" or "web".`
|
|
677
|
-
)
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
if (debugProp && debugProp !== 'profile') {
|
|
681
|
-
console.groupCollapsed('>>>')
|
|
682
|
-
|
|
683
|
-
log('props in', propsIn, 'mapped to', props, 'in order', Object.keys(props))
|
|
684
|
-
log('splitStyles', splitStyles)
|
|
685
|
-
log('media', { shouldListenForMedia, isMediaArray, mediaListeningKeys })
|
|
686
|
-
log('className', Object.values(splitStyles.classNames))
|
|
687
|
-
if (isClient) {
|
|
688
|
-
log('ref', hostRef, '(click to view)')
|
|
689
|
-
}
|
|
690
|
-
console.groupEnd()
|
|
691
|
-
if (debugProp === 'break') {
|
|
692
|
-
// biome-ignore lint/suspicious/noDebugger: ok
|
|
693
|
-
debugger
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
652
|
const {
|
|
699
653
|
viewProps: viewPropsIn,
|
|
700
654
|
pseudos,
|
|
@@ -708,12 +662,17 @@ export function createComponent<
|
|
|
708
662
|
// once you set animation prop don't remove it, you can set to undefined/false
|
|
709
663
|
// reason is animations are heavy - no way around it, and must be run inline here (🙅 loading as a sub-component)
|
|
710
664
|
let animationStyles: any
|
|
711
|
-
if (
|
|
665
|
+
if (
|
|
666
|
+
// if it supports css vars we run it on server too to get matching initial style
|
|
667
|
+
(supportsCSSVars ? willBeAnimatedClient : willBeAnimated) &&
|
|
668
|
+
useAnimations &&
|
|
669
|
+
!isHOC
|
|
670
|
+
) {
|
|
671
|
+
// HOOK 16... (depends on driver) (-1 if no animation, -1 if disableSSR, -1 if no context, -1 if production)
|
|
712
672
|
const animations = useAnimations({
|
|
713
673
|
props: propsWithAnimation,
|
|
714
674
|
// if hydrating, send empty style
|
|
715
675
|
style: splitStylesStyle,
|
|
716
|
-
// style: splitStylesStyle,
|
|
717
676
|
presence,
|
|
718
677
|
componentState: state,
|
|
719
678
|
styleProps,
|
|
@@ -723,7 +682,7 @@ export function createComponent<
|
|
|
723
682
|
staticConfig,
|
|
724
683
|
})
|
|
725
684
|
|
|
726
|
-
if (isAnimated && animations) {
|
|
685
|
+
if ((isAnimated || supportsCSSVars) && animations) {
|
|
727
686
|
animationStyles = animations.style
|
|
728
687
|
}
|
|
729
688
|
|
|
@@ -803,13 +762,16 @@ export function createComponent<
|
|
|
803
762
|
)
|
|
804
763
|
}
|
|
805
764
|
|
|
806
|
-
//
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
765
|
+
// HOOKS (0-4 more):
|
|
766
|
+
viewProps =
|
|
767
|
+
hooks.usePropsTransform?.(
|
|
768
|
+
elementType,
|
|
769
|
+
nonTamaguiProps,
|
|
770
|
+
hostRef,
|
|
771
|
+
curState.willHydrate
|
|
772
|
+
) ?? nonTamaguiProps
|
|
812
773
|
|
|
774
|
+
// HOOK (1 more):
|
|
813
775
|
const composedRef = useComposedRefs(hostRef as any, forwardedRef)
|
|
814
776
|
viewProps.ref = composedRef
|
|
815
777
|
|
|
@@ -828,33 +790,24 @@ export function createComponent<
|
|
|
828
790
|
|
|
829
791
|
if (process.env.NODE_ENV === 'development' && time) time`events-hooks`
|
|
830
792
|
|
|
831
|
-
let unPress = () =>
|
|
832
|
-
setStateShallow({
|
|
833
|
-
press: false,
|
|
834
|
-
pressIn: false,
|
|
835
|
-
})
|
|
836
|
-
|
|
837
|
-
if (process.env.TAMAGUI_TARGET === 'web') {
|
|
838
|
-
// needs to be referentially stable for web as we add to mouseUps
|
|
839
|
-
unPress = useCallback(unPress, [])
|
|
840
|
-
}
|
|
841
|
-
|
|
842
793
|
// combined multiple effects into one for performance so be careful with logic
|
|
843
794
|
// should not be a layout effect because otherwise it wont render the initial state
|
|
844
795
|
// for example css driver needs to render once with the first styles, then again with the next
|
|
845
796
|
// if its a layout effect it will just skip that first <render >output
|
|
846
|
-
const shouldSetMounted = needsMount && state.unmounted
|
|
847
797
|
const { pseudoGroups, mediaGroups } = splitStyles
|
|
848
798
|
|
|
799
|
+
// TODO if you add a group prop setStateShallow changes identity...
|
|
800
|
+
if (!curState.unPress) {
|
|
801
|
+
curState.unPress = () => setStateShallow({ press: false, pressIn: false })
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const unPress = curState.unPress!
|
|
805
|
+
const shouldEnter = state.unmounted
|
|
806
|
+
|
|
849
807
|
useEffect(() => {
|
|
850
|
-
if (
|
|
851
|
-
|
|
852
|
-
state.unmounted === true && hasEnterStyle ? 'should-enter' : false
|
|
853
|
-
setStateShallow({
|
|
854
|
-
unmounted,
|
|
855
|
-
})
|
|
808
|
+
if (shouldEnter) {
|
|
809
|
+
setStateShallow({ unmounted: false })
|
|
856
810
|
return
|
|
857
|
-
// no need for mouseUp removal effect if its not even mounted yet
|
|
858
811
|
}
|
|
859
812
|
|
|
860
813
|
// parent group pseudo listening
|
|
@@ -896,14 +849,11 @@ export function createComponent<
|
|
|
896
849
|
mouseUps.delete(unPress)
|
|
897
850
|
}
|
|
898
851
|
}, [
|
|
899
|
-
|
|
900
|
-
state.unmounted,
|
|
852
|
+
shouldEnter,
|
|
901
853
|
pseudoGroups ? Object.keys([...pseudoGroups]).join('') : 0,
|
|
902
854
|
mediaGroups ? Object.keys([...mediaGroups]).join('') : 0,
|
|
903
855
|
])
|
|
904
856
|
|
|
905
|
-
const avoidAnimationStyle = keepStyleSSR && state.unmounted === true
|
|
906
|
-
|
|
907
857
|
let fontFamily = isText
|
|
908
858
|
? splitStyles.fontFamily || staticConfig.defaultProps?.fontFamily
|
|
909
859
|
: null
|
|
@@ -912,9 +862,7 @@ export function createComponent<
|
|
|
912
862
|
}
|
|
913
863
|
const fontFamilyClassName = fontFamily ? `font_${fontFamily}` : ''
|
|
914
864
|
|
|
915
|
-
const style =
|
|
916
|
-
? splitStyles.style
|
|
917
|
-
: animationStyles || splitStyles.style
|
|
865
|
+
const style = animationStyles || splitStyles.style
|
|
918
866
|
|
|
919
867
|
let className: string | undefined
|
|
920
868
|
|
|
@@ -931,10 +879,9 @@ export function createComponent<
|
|
|
931
879
|
|
|
932
880
|
className = classList.join(' ')
|
|
933
881
|
|
|
934
|
-
if (
|
|
882
|
+
if (isAnimated && !supportsCSSVars && isReactNative) {
|
|
935
883
|
viewProps.style = style
|
|
936
884
|
} else if (isReactNative) {
|
|
937
|
-
// TODO these shouldn't really return from getSplitStyles when in Native mode
|
|
938
885
|
const cnStyles = { $$css: true }
|
|
939
886
|
for (const name of className.split(' ')) {
|
|
940
887
|
cnStyles[name] = name
|
|
@@ -1168,14 +1115,20 @@ export function createComponent<
|
|
|
1168
1115
|
|
|
1169
1116
|
// needs to reset the presence state for nested children
|
|
1170
1117
|
const ResetPresence = config?.animations?.ResetPresence
|
|
1171
|
-
if (
|
|
1118
|
+
if (
|
|
1119
|
+
willBeAnimated &&
|
|
1120
|
+
hasEnterStyle &&
|
|
1121
|
+
ResetPresence &&
|
|
1122
|
+
content &&
|
|
1123
|
+
typeof content !== 'string'
|
|
1124
|
+
) {
|
|
1172
1125
|
content = <ResetPresence>{content}</ResetPresence>
|
|
1173
1126
|
}
|
|
1174
1127
|
|
|
1175
1128
|
if (process.env.NODE_ENV === 'development' && time) time`create-element`
|
|
1176
1129
|
|
|
1177
1130
|
// must override context so siblings don't clobber initial state
|
|
1178
|
-
const groupState =
|
|
1131
|
+
const groupState = curState.group
|
|
1179
1132
|
const subGroupContext = useMemo(() => {
|
|
1180
1133
|
if (!groupState || !groupName) return
|
|
1181
1134
|
groupState.listeners.clear()
|
|
@@ -1186,7 +1139,7 @@ export function createComponent<
|
|
|
1186
1139
|
state: {
|
|
1187
1140
|
...componentContext.groups.state,
|
|
1188
1141
|
[groupName]: {
|
|
1189
|
-
pseudo:
|
|
1142
|
+
pseudo: defaultComponentStateMounted,
|
|
1190
1143
|
// capture just initial width and height if they exist
|
|
1191
1144
|
// will have top, left, width, height (not x, y)
|
|
1192
1145
|
layout: {
|
|
@@ -1226,11 +1179,17 @@ export function createComponent<
|
|
|
1226
1179
|
}
|
|
1227
1180
|
|
|
1228
1181
|
if (process.env.TAMAGUI_TARGET === 'web') {
|
|
1229
|
-
if (isReactNative) {
|
|
1182
|
+
if (isReactNative && !asChild && !isHOC) {
|
|
1230
1183
|
content = (
|
|
1231
1184
|
<span
|
|
1232
|
-
|
|
1233
|
-
|
|
1185
|
+
{...(!isHydrated
|
|
1186
|
+
? {
|
|
1187
|
+
className: `_dsp_contents`,
|
|
1188
|
+
}
|
|
1189
|
+
: {
|
|
1190
|
+
className: `_dsp_contents`,
|
|
1191
|
+
...(events && getWebEvents(events)),
|
|
1192
|
+
})}
|
|
1234
1193
|
>
|
|
1235
1194
|
{content}
|
|
1236
1195
|
</span>
|
|
@@ -1264,19 +1223,19 @@ export function createComponent<
|
|
|
1264
1223
|
console.groupCollapsed(`render <${element} /> (${internalID}) with props`)
|
|
1265
1224
|
try {
|
|
1266
1225
|
log('viewProps', viewProps)
|
|
1267
|
-
log('viewPropsOrder', Object.keys(viewProps))
|
|
1268
|
-
for (const key in viewProps) {
|
|
1269
|
-
log(' - ', key, viewProps[key])
|
|
1270
|
-
}
|
|
1271
1226
|
log('children', content)
|
|
1272
1227
|
if (typeof window !== 'undefined') {
|
|
1228
|
+
log('props in', propsIn, 'mapped to', props, 'in order', Object.keys(props))
|
|
1273
1229
|
log({
|
|
1230
|
+
shouldListenForMedia,
|
|
1231
|
+
mediaListeningKeys,
|
|
1232
|
+
isMediaArray,
|
|
1274
1233
|
viewProps,
|
|
1234
|
+
hostRef,
|
|
1275
1235
|
state,
|
|
1276
1236
|
styleProps,
|
|
1277
1237
|
themeState,
|
|
1278
1238
|
isAnimated,
|
|
1279
|
-
isAnimatedReactNativeWeb,
|
|
1280
1239
|
defaultProps,
|
|
1281
1240
|
splitStyles,
|
|
1282
1241
|
animationStyles,
|
|
@@ -1303,7 +1262,10 @@ export function createComponent<
|
|
|
1303
1262
|
// RN can run into PayloadTooLargeError: request entity too large
|
|
1304
1263
|
}
|
|
1305
1264
|
console.groupEnd()
|
|
1306
|
-
|
|
1265
|
+
if (debugProp === 'break') {
|
|
1266
|
+
// biome-ignore lint/suspicious/noDebugger: ok
|
|
1267
|
+
debugger
|
|
1268
|
+
}
|
|
1307
1269
|
}
|
|
1308
1270
|
}
|
|
1309
1271
|
|