Skip to content

Commit

Permalink
Merge pull request #419 from jpudysz/fix/pressable-web
Browse files Browse the repository at this point in the history
fix: pressable web
  • Loading branch information
jpudysz authored Dec 12, 2024
2 parents 87aafea + e327688 commit 3a3365d
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 88 deletions.
65 changes: 17 additions & 48 deletions src/components/native/Pressable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { forwardRef, useEffect, useRef } from 'react'
import React, { forwardRef, useRef } from 'react'
import { Pressable as NativePressableReactNative } from 'react-native'
import type { PressableProps as Props, View, ViewStyle } from 'react-native'
import { UnistylesShadowRegistry } from '../../specs'
Expand All @@ -23,15 +23,6 @@ const initialState: WebPressableState = {
focused: false
}

const events = {
'pointerdown': { pressed: true },
'pointerup': { pressed: false },
'pointerenter': { hovered: true },
'pointerleave': { hovered: false },
'focus': { focused: true },
'blur': { focused: false }
} satisfies Partial<Record<keyof HTMLElementEventMap, Partial<WebPressableState>>>

type UpdateStylesProps = {
ref: View | null,
style: WebPressableStyle,
Expand Down Expand Up @@ -67,55 +58,33 @@ const updateStyles = ({ ref, style, state, scopedTheme, variants }: UpdateStyles

export const Pressable = forwardRef<View, PressableProps>(({ style, ...props }, passedRef) => {
const storedRef = useRef<View | null>(null)
const state = useRef<WebPressableState>(initialState)
const styleRef = useRef(style)
const scopedTheme = UnistylesShadowRegistry.getScopedTheme()
const variants = UnistylesShadowRegistry.getVariants()

useEffect(() => {
styleRef.current = style
}, [style])

useEffect(() => {
const handler = (newState: Partial<WebPressableState>) => () => {
state.current = { ...state.current, ...newState }

updateStyles({
ref: storedRef.current,
style: styleRef.current as WebPressableStyle,
variants: variants as unknown as Variants,
scopedTheme,
state: state.current
})
}

if (!storedRef.current) {
return
}

// ref on the web is dom element
const ref = storedRef.current as unknown as HTMLDivElement

Object.entries(events).forEach(([event, state]) => {
ref.addEventListener(event, handler(state))
})

return () => {
Object.entries(events).forEach(([event, state]) => {
ref.removeEventListener(event, handler(state))
})
}
}, [])

return (
<NativePressableReactNative
{...props}
style={state => {
if (!storedRef.current) {
return {}
}

updateStyles({
ref: storedRef.current,
style: style as WebPressableStyle,
variants,
scopedTheme,
state: state as WebPressableState
})

return {}
}}
ref={ref => {
storedRef.current = ref
updateStyles({
ref,
style: style as WebPressableStyle,
variants: variants as unknown as Variants,
variants,
scopedTheme,
state: initialState
})
Expand Down
66 changes: 26 additions & 40 deletions src/web/shadowRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class UnistylesShadowRegistryBuilder {
// END MOCKS

private resultsMap = new Map<HTMLElement, UnistylesValues>()
private hashMap = new Map<HTMLElement, string>()
private classNamesMap = new Map<HTMLElement, Array<string>>()
private selectedVariants = new Map<string, string | boolean | undefined>()
private scopedTheme: UnistylesTheme | undefined = undefined
private disposeMap = new Map<HTMLElement, VoidFunction>()

add = (ref: any, styles: Array<Style>) => {
// Styles are not provided
Expand All @@ -40,6 +40,8 @@ class UnistylesShadowRegistryBuilder {

this.resultsMap.delete(ref)
this.classNamesMap.delete(ref)
this.disposeMap.get(ref)?.()
this.disposeMap.delete(ref)

if (oldResult) {
UnistylesRegistry.remove(oldResult)
Expand Down Expand Up @@ -76,29 +78,29 @@ class UnistylesShadowRegistryBuilder {
}

const { __uni__key, __uni__stylesheet, __uni__args = [], __uni__refs } = secrets
const newComputedStylesheet = UnistylesRegistry.getComputedStylesheet(__uni__stylesheet, scopedTheme)
const style = newComputedStylesheet[__uni__key] as (UnistylesValues | ((...args: any) => UnistylesValues))
const variants = Object.fromEntries(this.selectedVariants.entries())
const args = __uni__args
const result = typeof style === 'function'
? style(...args)
: style
const { variantsResult } = Object.fromEntries(getVariants({ variantsResult: result }, variants))
const resultWithVariants = deepMergeObjects(result, variantsResult ?? {})
const dependencies = extractUnistyleDependencies(resultWithVariants)

if (typeof __uni__stylesheet === 'function') {
// Add dependencies from dynamic styles to stylesheet
UnistylesRegistry.addDependenciesToStylesheet(__uni__stylesheet, dependencies)
}
const newComputedStylesheet = UnistylesRegistry.getComputedStylesheet(__uni__stylesheet, scopedTheme)
const style = newComputedStylesheet[__uni__key] as (UnistylesValues | ((...args: any) => UnistylesValues))
const args = __uni__args
const result = typeof style === 'function'
? style(...args)
: style
const { variantsResult } = Object.fromEntries(getVariants({ variantsResult: result }, variants))
const resultWithVariants = deepMergeObjects(result, variantsResult ?? {})
const dependencies = extractUnistyleDependencies(resultWithVariants)

if (typeof __uni__stylesheet === 'function') {
// Add dependencies from dynamic styles to stylesheet
UnistylesRegistry.addDependenciesToStylesheet(__uni__stylesheet, dependencies)
}

__uni__refs.add(ref)
__uni__refs.add(ref)

return resultWithVariants as UnistylesValues
return resultWithVariants as UnistylesValues
})
}

// Copy scoped theme to not use referenced value
const variants = this.getVariants()
const scopedTheme = this.scopedTheme
const parsedStyles = getParsedStyles()
const combinedStyles = deepMergeObjects(...parsedStyles)
Expand All @@ -119,35 +121,19 @@ class UnistylesShadowRegistryBuilder {
oldClassNames?.forEach(className => ref.classList.remove(className))
this.resultsMap.set(ref, combinedStyles)

const { hash, existingHash } = UnistylesRegistry.add(combinedStyles)
const { hash } = UnistylesRegistry.add(combinedStyles)
const injectedClassNames = combinedStyles?._web?._classNames ?? []
const newClassNames = (Array.isArray(injectedClassNames) ? injectedClassNames : [injectedClassNames]).concat(hash)
const dependencies = Array.from(new Set(parsedStyles.flatMap(style => extractUnistyleDependencies(style))))

if (!existingHash) {
const dispose = UnistylesListener.addListeners(dependencies, () => {
const hash = this.hashMap.get(ref)

// Dispose listener if there is no hash
if (!hash) {
dispose()

return
}

UnistylesRegistry.applyStyles(hash, deepMergeObjects(...getParsedStyles()))
})
}

this.disposeMap.get(ref)?.()
this.disposeMap.set(ref, UnistylesListener.addListeners(dependencies, () => {
UnistylesRegistry.applyStyles(hash, deepMergeObjects(...getParsedStyles()))
}))
this.classNamesMap.set(ref, newClassNames)
// Add new classnames to the ref
ref.classList.add(...newClassNames)

// If it is new hash add it to the map to use for the listener
if (!existingHash) {
this.hashMap.set(ref, hash)
}

return newClassNames
}

Expand All @@ -169,7 +155,7 @@ class UnistylesShadowRegistryBuilder {

getScopedTheme = () => this.scopedTheme

getVariants = () => this.selectedVariants
getVariants = () => Object.fromEntries(this.selectedVariants.entries())

remove = () => {}
}
Expand Down

0 comments on commit 3a3365d

Please sign in to comment.