Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/uniwind/src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isDefined = <T>(value: T): value is NonNullable<T> => value !== undefined && value !== null
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/ActivityIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ActivityIndicator as RNActivityIndicator, ActivityIndicatorProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const ActivityIndicator = copyComponentProperties(RNActivityIndicator, (props: ActivityIndicatorProps) => {
const style = useStyle(props.className, props)
const color = useStyle(props.colorClassName, props).accentColor
const color = useAccentColor(props.colorClassName, props)

return (
<RNActivityIndicator
Expand Down
4 changes: 2 additions & 2 deletions packages/uniwind/src/components/native/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Button as RNButton, ButtonProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useStyle } from './useStyle'
import { useAccentColor } from './useAccentColor'

export const Button = copyComponentProperties(RNButton, (props: ButtonProps) => {
const color = useStyle(props.colorClassName, props).accentColor
const color = useAccentColor(props.colorClassName, props)

return (
<RNButton
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/FlatList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FlatList as RNFlatList, FlatListProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const FlatList = copyComponentProperties(RNFlatList, (props: FlatListProps<unknown>) => {
Expand All @@ -8,7 +9,7 @@ export const FlatList = copyComponentProperties(RNFlatList, (props: FlatListProp
const styleContentContainer = useStyle(props.contentContainerClassName, props)
const styleListFooterComponent = useStyle(props.ListFooterComponentClassName, props)
const styleListHeaderComponent = useStyle(props.ListHeaderComponentClassName, props)
const endFillColor = useStyle(props.endFillColorClassName, props).accentColor
const endFillColor = useAccentColor(props.endFillColorClassName, props)
const hasSingleColumn = !('numColumns' in props) || props.numColumns === 1

return (
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Image as RNImage, ImageProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const Image = copyComponentProperties(RNImage, (props: ImageProps) => {
const style = useStyle(props.className, props)
const tintColor = useStyle(props.tintColorClassName, props).accentColor
const tintColor = useAccentColor(props.tintColorClassName, props)

return (
<RNImage
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/ImageBackground.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ImageBackground as RNImageBackground, ImageBackgroundProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const ImageBackground = copyComponentProperties(RNImageBackground, (props: ImageBackgroundProps) => {
const style = useStyle(props.className, props)
const imageStyle = useStyle(props.imageClassName, props)
const tintColor = useStyle(props.tintColorClassName, props).accentColor
const tintColor = useAccentColor(props.tintColorClassName, props)

return (
<RNImageBackground
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { ForwardedRef } from 'react'
import { InputAccessoryView as RNInputAccessoryView, InputAccessoryViewProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const InputAccessoryView = copyComponentProperties(
RNInputAccessoryView,
(props: InputAccessoryViewProps & { ref?: ForwardedRef<RNInputAccessoryView> }) => {
const style = useStyle(props.className, props)
const backgroundColor = useStyle(props.backgroundColorClassName, props).accentColor
const backgroundColor = useAccentColor(props.backgroundColorClassName, props)

return (
<RNInputAccessoryView
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Modal as RNModal, ModalProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const Modal = copyComponentProperties(RNModal, (props: ModalProps) => {
const style = useStyle(props.className, props)
const backdropColor = useStyle(props.backdropColorClassName, props).accentColor
const backdropColor = useAccentColor(props.backdropColorClassName, props)

return (
<RNModal
Expand Down
9 changes: 5 additions & 4 deletions packages/uniwind/src/components/native/RefreshControl.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { RefreshControl as RNRefreshControl, RefreshControlProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const RefreshControl = copyComponentProperties(RNRefreshControl, (props: RefreshControlProps) => {
const style = useStyle(props.className, props)
const color = useStyle(props.colorsClassName, props).accentColor
const tintColor = useStyle(props.tintColorClassName, props).accentColor
const titleColor = useStyle(props.titleColorClassName, props).accentColor
const progressBackgroundColor = useStyle(props.progressBackgroundColorClassName, props).accentColor
const color = useAccentColor(props.colorsClassName, props)
const tintColor = useAccentColor(props.tintColorClassName, props)
const titleColor = useAccentColor(props.titleColorClassName, props)
const progressBackgroundColor = useAccentColor(props.progressBackgroundColorClassName, props)

return (
<RNRefreshControl
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/ScrollView.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ScrollView as RNScrollView, ScrollViewProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const ScrollView = copyComponentProperties(RNScrollView, (props: ScrollViewProps) => {
const style = useStyle(props.className, props)
const contentContainerStyle = useStyle(props.contentContainerClassName, props)
const endFillColor = useStyle(props.endFillColorClassName, props).accentColor
const endFillColor = useAccentColor(props.endFillColorClassName, props)

return (
<RNScrollView
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/SectionList.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { SectionList as RNSectionList, SectionListProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const SectionList = copyComponentProperties(RNSectionList, (props: SectionListProps<unknown, unknown>) => {
const style = useStyle(props.className, props)
const contentContainerStyle = useStyle(props.contentContainerClassName, props)
const listFooterComponentStyle = useStyle(props.ListFooterComponentClassName, props)
const listHeaderComponentStyle = useStyle(props.ListHeaderComponentClassName, props)
const endFillColor = useStyle(props.endFillColorClassName, props).accentColor
const endFillColor = useAccentColor(props.endFillColorClassName, props)

return (
<RNSectionList
Expand Down
9 changes: 5 additions & 4 deletions packages/uniwind/src/components/native/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Switch as RNSwitch, SwitchProps } from 'react-native'
import { ComponentState } from '../../core/types'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const Switch = copyComponentProperties(RNSwitch, (props: SwitchProps) => {
const state = {
isDisabled: Boolean(props.disabled),
} satisfies ComponentState
const style = useStyle(props.className, props, state)
const trackColorOn = useStyle(props.trackColorOnClassName, props, state).accentColor
const trackColorOff = useStyle(props.trackColorOffClassName, props, state).accentColor
const thumbColor = useStyle(props.thumbColorClassName, props, state).accentColor
const ios_backgroundColor = useStyle(props.ios_backgroundColorClassName, props, state).accentColor
const trackColorOn = useAccentColor(props.trackColorOnClassName, props, state)
const trackColorOff = useAccentColor(props.trackColorOffClassName, props, state)
const thumbColor = useAccentColor(props.thumbColorClassName, props, state)
const ios_backgroundColor = useAccentColor(props.ios_backgroundColorClassName, props, state)

return (
<RNSwitch
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from 'react'
import { Text as RNText, TextProps } from 'react-native'
import { ComponentState } from '../../core/types'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

type StyleWithWebkitLineClamp = {
Expand All @@ -15,7 +16,7 @@ export const Text = copyComponentProperties(RNText, (props: TextProps) => {
isDisabled: Boolean(props.disabled),
} satisfies ComponentState
const style = useStyle(props.className, props, state)
const selectionColor = useStyle(props.selectionColorClassName, props, state).accentColor
const selectionColor = useAccentColor(props.selectionColorClassName, props, state)

return (
<RNText
Expand Down
11 changes: 6 additions & 5 deletions packages/uniwind/src/components/native/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from 'react'
import { TextInput as RNTextInput, TextInputProps } from 'react-native'
import { ComponentState } from '../../core/types'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const TextInput = copyComponentProperties(RNTextInput, (props: TextInputProps) => {
Expand All @@ -13,11 +14,11 @@ export const TextInput = copyComponentProperties(RNTextInput, (props: TextInputP
isPressed,
} satisfies ComponentState
const style = useStyle(props.className, props, state)
const cursorColor = useStyle(props.cursorColorClassName, props, state).accentColor
const selectionColor = useStyle(props.selectionColorClassName, props, state).accentColor
const placeholderTextColor = useStyle(props.placeholderTextColorClassName, props, state).accentColor
const selectionHandleColor = useStyle(props.selectionHandleColorClassName, props, state).accentColor
const underlineColorAndroid = useStyle(props.underlineColorAndroidClassName, props, state).accentColor
const cursorColor = useAccentColor(props.cursorColorClassName, props, state)
const selectionColor = useAccentColor(props.selectionColorClassName, props, state)
const placeholderTextColor = useAccentColor(props.placeholderTextColorClassName, props, state)
const selectionHandleColor = useAccentColor(props.selectionHandleColorClassName, props, state)
const underlineColorAndroid = useAccentColor(props.underlineColorAndroidClassName, props, state)

return (
<RNTextInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from 'react'
import { TouchableHighlight as RNTouchableHighlight, TouchableHighlightProps } from 'react-native'
import { ComponentState } from '../../core/types'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const TouchableHighlight = copyComponentProperties(RNTouchableHighlight, (props: TouchableHighlightProps) => {
Expand All @@ -13,7 +14,7 @@ export const TouchableHighlight = copyComponentProperties(RNTouchableHighlight,
isFocused,
} satisfies ComponentState
const style = useStyle(props.className, props, state)
const underlayColor = useStyle(props.underlayColorClassName, props, state).accentColor
const underlayColor = useAccentColor(props.underlayColorClassName, props, state)

return (
<RNTouchableHighlight
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/native/VirtualizedList.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { VirtualizedList as RNVirtualizedList, VirtualizedListProps } from 'react-native'
import { copyComponentProperties } from '../utils'
import { useAccentColor } from './useAccentColor'
import { useStyle } from './useStyle'

export const VirtualizedList = copyComponentProperties(RNVirtualizedList, (props: VirtualizedListProps<unknown>) => {
const style = useStyle(props.className, props)
const contentContainerStyle = useStyle(props.contentContainerClassName, props)
const listFooterComponentStyle = useStyle(props.ListFooterComponentClassName, props)
const listHeaderComponentStyle = useStyle(props.ListHeaderComponentClassName, props)
const endFillColor = useStyle(props.endFillColorClassName, props).accentColor
const endFillColor = useAccentColor(props.endFillColorClassName, props)

return (
<RNVirtualizedList
Expand Down
19 changes: 19 additions & 0 deletions packages/uniwind/src/components/native/useAccentColor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { isDefined } from '../../common/utils'
import { Logger } from '../../core/logger'
import { ComponentState } from '../../core/types'
import { useStyle } from './useStyle'

let warnedOnce = false

export const useAccentColor = (className: string | undefined, componentProps: Record<string, any>, state?: ComponentState) => {
const styles = useStyle(className, componentProps, state)

if (__DEV__ && !warnedOnce && isDefined(className) && className.trim() !== '' && styles.accentColor === undefined) {
warnedOnce = true
Logger.warn(
`className '${className}' was provided to extract accentColor but no color was found. Make sure the className includes a color utility (e.g., 'accent-red-500', 'accent-blue-600').`,
)
}

return styles.accentColor
}
2 changes: 1 addition & 1 deletion packages/uniwind/src/components/web/ActivityIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ActivityIndicator as RNActivityIndicator, ActivityIndicatorProps } from 'react-native'
import { useUniwindAccent } from '../../hooks'
import { copyComponentProperties } from '../utils'
import { generateDataSet } from './generateDataSet'
import { toRNWClassName } from './rnw'
import { useUniwindAccent } from './useUniwindAccent'

export const ActivityIndicator = copyComponentProperties(RNActivityIndicator, (props: ActivityIndicatorProps) => {
const color = useUniwindAccent(props.colorClassName)
Expand Down
2 changes: 1 addition & 1 deletion packages/uniwind/src/components/web/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button as RNButton, ButtonProps } from 'react-native'
import { useUniwindAccent } from '../../hooks'
import { copyComponentProperties } from '../utils'
import { generateDataSet } from './generateDataSet'
import { useUniwindAccent } from './useUniwindAccent'

export const Button = copyComponentProperties(RNButton, (props: ButtonProps) => {
const color = useUniwindAccent(props.colorClassName)
Expand Down
3 changes: 2 additions & 1 deletion packages/uniwind/src/components/web/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Image as RNImage, ImageProps } from 'react-native'
import { useResolveClassNames, useUniwindAccent } from '../../hooks'
import { useResolveClassNames } from '../../hooks'
import { copyComponentProperties } from '../utils'
import { generateDataSet } from './generateDataSet'
import { toRNWClassName } from './rnw'
import { useUniwindAccent } from './useUniwindAccent'

export const Image = copyComponentProperties(RNImage, (props: ImageProps) => {
const tintColor = useUniwindAccent(props.tintColorClassName)
Expand Down
2 changes: 1 addition & 1 deletion packages/uniwind/src/components/web/ImageBackground.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ImageBackground as RNImageBackground, ImageBackgroundProps } from 'react-native'
import { useUniwindAccent } from '../../hooks'
import { copyComponentProperties } from '../utils'
import { generateDataSet } from './generateDataSet'
import { toRNWClassName } from './rnw'
import { useUniwindAccent } from './useUniwindAccent'

export const ImageBackground = copyComponentProperties(RNImageBackground, (props: ImageBackgroundProps) => {
const tintColor = useUniwindAccent(props.tintColorClassName)
Expand Down
2 changes: 1 addition & 1 deletion packages/uniwind/src/components/web/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Switch as RNSwitch, SwitchProps } from 'react-native'
import { useUniwindAccent } from '../../hooks'
import { copyComponentProperties } from '../utils'
import { generateDataSet } from './generateDataSet'
import { toRNWClassName } from './rnw'
import { useUniwindAccent } from './useUniwindAccent'

export const Switch = copyComponentProperties(RNSwitch, (props: SwitchProps) => {
const trackColorOn = useUniwindAccent(props.trackColorOnClassName)
Expand Down
2 changes: 1 addition & 1 deletion packages/uniwind/src/components/web/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { TextInput as RNTextInput, TextInputProps } from 'react-native'
import { useUniwindAccent } from '../../hooks'
import { copyComponentProperties } from '../utils'
import { generateDataSet } from './generateDataSet'
import { toRNWClassName } from './rnw'
import { useUniwindAccent } from './useUniwindAccent'

export const TextInput = copyComponentProperties(RNTextInput, (props: TextInputProps) => {
const placeholderTextColor = useUniwindAccent(props.placeholderTextColorClassName)
Expand Down
2 changes: 1 addition & 1 deletion packages/uniwind/src/components/web/TouchableHighlight.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { TouchableHighlight as RNTouchableHighlight, TouchableHighlightProps } from 'react-native'
import { useUniwindAccent } from '../../hooks'
import { copyComponentProperties } from '../utils'
import { generateDataSet } from './generateDataSet'
import { toRNWClassName } from './rnw'
import { useUniwindAccent } from './useUniwindAccent'

export const TouchableHighlight = copyComponentProperties(RNTouchableHighlight, (props: TouchableHighlightProps) => {
const underlayColor = useUniwindAccent(props.underlayColorClassName)
Expand Down
21 changes: 21 additions & 0 deletions packages/uniwind/src/components/web/useUniwindAccent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { isDefined } from '../../common/utils'
import { Logger } from '../../core/logger'
import { formatColor } from '../../core/web/formatColor'
import { useResolveClassNames } from '../../hooks/useResolveClassNames'

let warnedOnce = false

export const useUniwindAccent = (className: string | undefined) => {
const styles = useResolveClassNames(className ?? '')

if (__DEV__ && !warnedOnce && isDefined(className) && className.trim() !== '' && styles.accentColor === undefined) {
warnedOnce = true
Logger.warn(
`className '${className}' was provided to extract accentColor but no color was found. Make sure the className includes a color utility (e.g., 'accent-red-500', 'accent-blue-600').`,
)
}

return styles.accentColor !== undefined
? formatColor(styles.accentColor)
: undefined
}
11 changes: 11 additions & 0 deletions packages/uniwind/src/hoc/withUniwind.native.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { ComponentProps, useLayoutEffect, useReducer } from 'react'
import { isDefined } from '../common/utils'
import { useUniwindContext } from '../core/context'
import { UniwindListener } from '../core/listener'
import { Logger } from '../core/logger'
import { UniwindStore } from '../core/native'
import { StyleDependency } from '../types'
import { AnyObject, Component, OptionMapping, WithUniwind } from './types'
import { classToColor, classToStyle, isClassProperty, isColorClassProperty, isStyleProperty } from './withUniwindUtils'

let warnedOnce = false

export const withUniwind: WithUniwind = <
TComponent extends Component,
TOptions extends Record<keyof ComponentProps<TComponent>, OptionMapping>,
Expand All @@ -28,6 +32,13 @@ const withAutoUniwind = (Component: Component<AnyObject>) => (props: AnyObject)

const { styles, dependencies } = UniwindStore.getStyles(propValue, props, undefined, uniwindContext)

if (__DEV__ && !warnedOnce && isDefined(propValue) && propValue.trim() !== '' && styles.accentColor === undefined) {
warnedOnce = true
Logger.warn(
`className '${propValue}' was provided to extract accentColor but no color was found. Make sure the className includes a color utility (e.g., 'accent-red-500', 'accent-blue-600').`,
)
}

acc.dependencies.push(...dependencies)
acc.generatedProps[colorProp] = styles.accentColor

Expand Down
Loading