Skip to content

Commit

Permalink
feat: implement orientations for mobile, add demo
Browse files Browse the repository at this point in the history
  • Loading branch information
jpudysz committed Nov 7, 2023
1 parent bc74484 commit 2b3ede7
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 5 deletions.
1 change: 1 addition & 0 deletions examples/expo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const App: React.FunctionComponent = () => (
<Stack.Screen name={DemoNames.MultipleThemesAdaptive} component={Screens.MultipleThemesAdaptiveScreen} />
<Stack.Screen name={DemoNames.NoBreakpoints} component={Screens.NoBreakpointsScreen} />
<Stack.Screen name={DemoNames.WithBreakpoints} component={Screens.WithBreakpointsScreen} />
<Stack.Screen name={DemoNames.OrientationBreakpoints} component={Screens.OrientationBreakpoints} />
<Stack.Screen name={DemoNames.MediaQueriesWidthHeight} component={Screens.MediaQueriesWidthHeight} />
</Stack.Navigator>
</NavigationContainer>
Expand Down
2 changes: 2 additions & 0 deletions examples/expo/src/common/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum DemoNames {
NoBreakpoints = 'NoBreakpoints',
WithBreakpoints = 'WithBreakpoints',
MediaQueriesWidthHeight = 'MediaQueriesWidthHeight',
OrientationBreakpoints = 'OrientationBreakpoints'
}

export type DemoStackParams = {
Expand All @@ -24,6 +25,7 @@ export type DemoStackParams = {
[DemoNames.NoBreakpoints]: undefined,
[DemoNames.WithBreakpoints]: undefined,
[DemoNames.MediaQueriesWidthHeight]: undefined,
[DemoNames.OrientationBreakpoints]: undefined
}

export type NavigationProps<S extends DemoNames = DemoNames.Home> = NavigationProp<DemoStackParams, S>
4 changes: 4 additions & 0 deletions examples/expo/src/examples/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ export const HomeScreen = () => {
description="With breakpoints"
onPress={() => navigation.navigate(DemoNames.WithBreakpoints)}
/>
<DemoLink
description="With orientation breakpoints"
onPress={() => navigation.navigate(DemoNames.OrientationBreakpoints)}
/>
</DemoGroup>
<DemoGroup title="Media queries">
<DemoLink
Expand Down
77 changes: 77 additions & 0 deletions examples/expo/src/examples/OrientationBreakpoints.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react'
import { Text, View } from 'react-native'
import { createStyleSheet, useStyles, UnistylesRegistry, UnistylesRuntime, ScreenOrientation } from 'react-native-unistyles'
import { DemoScreen } from '../components'
import { darkTheme, lightTheme, premiumTheme } from '../styles'
import { useLazyRegistryForDemo } from '../hooks'

export const OrientationBreakpoints: React.FunctionComponent = () => {
useLazyRegistryForDemo(() => {
UnistylesRegistry
.addThemes({
light: lightTheme,
dark: darkTheme,
premium: premiumTheme
})
.addConfig({
adaptiveThemes: true
})
})

const { styles } = useStyles(stylesheet)

return (
<DemoScreen>
<View style={styles.container}>
<Text style={styles.text}>
This demo has no registered breakpoints. On mobile Unistyles will provide you two breakpoints:
</Text>
<Text>
landscape and portrait
</Text>
<Text style={styles.text}>
The current orientation is: {UnistylesRuntime.orientation === ScreenOrientation.Portrait ? 'portrait' : 'landscape'}
</Text>
<Text style={styles.text}>
You should see circles on portrait and rectangles on landscape
</Text>
<View style={styles.objectContainer}>
{Array.from(new Array(10)).map((_, index) => (
<View
key={index}
style={styles.object}
/>
))}
</View>
</View>
</DemoScreen>
)
}

const stylesheet = createStyleSheet(theme => ({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 20,
backgroundColor: theme.colors.backgroundColor,
rowGap: 20
},
text: {
textAlign: 'center',
color: theme.colors.typography
},
objectContainer: {
flexDirection: 'row',
columnGap: 10
},
object: {
width: 40,
height: 40,
backgroundColor: theme.colors.accent,
borderRadius: {
portrait: undefined,
landscape: 20
}
}
}))
1 change: 1 addition & 0 deletions examples/expo/src/examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export { MultipleThemesScreen } from './MultipleThemesScreen'
export { MultipleThemesAdaptiveScreen } from './MultipleThemesAdaptiveScreen'
export { NoBreakpointsScreen } from './NoBreakpointsScreen'
export { WithBreakpointsScreen } from './WithBreakpointsScreen'
export { OrientationBreakpoints } from './OrientationBreakpoints'
export { MediaQueriesWidthHeight } from './MediaQueriesWidthHeight'
3 changes: 2 additions & 1 deletion src/global.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface UnistylesThemes {}
export interface UnistylesBreakpoints {
default?: 0
landscape?: number,
portrait?: number,
}
20 changes: 17 additions & 3 deletions src/utils/breakpoints.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { unistyles } from '../Unistyles'
import { throwError } from './common'
import { isMobile, Orientation, throwError } from './common'
import type { ScreenSize, MediaQueries } from '../types'
import { ScreenOrientation } from '../types'
import { getKeyForCustomMediaQuery, isMediaQuery } from './mediaQueries'
import type { UnistylesBreakpoints } from '../global'

Expand Down Expand Up @@ -118,7 +119,20 @@ export const getValueForBreakpoint = (
return value[customMediaQueryKey]
}

// if no custom media query, or didn't match, proceed with defined breakpoints
// at this point user didn't use custom media queries (:w, :h)
// check if user defined any breakpoints
const hasBreakpoints = unistyles.runtime.sortedBreakpoints.length > 0

// if not then we can fallback to horizontal and portrait (mobile only)
if (!hasBreakpoints && isMobile && (Orientation.Landscape in value || Orientation.Portrait in value)) {
return value[
unistyles.runtime.orientation === ScreenOrientation.Portrait
? Orientation.Portrait
: Orientation.Landscape
]
}

// if user defined breakpoints, then we look for the valid one
const unifiedKey = breakpoint?.toLowerCase() as keyof typeof value
const directBreakpoint = value[unifiedKey]

Expand All @@ -127,7 +141,7 @@ export const getValueForBreakpoint = (
return directBreakpoint
}

// there is no direct hit for breakpoint nor media-query, so let's simulate CSS cascading
// there is no direct hit for breakpoint nor media-query, let's simulate CSS cascading
const breakpointPairs = unistyles.runtime.sortedBreakpoints
const currentBreakpoint = breakpointPairs
.findIndex(([key]) => key === unifiedKey)
Expand Down
6 changes: 6 additions & 0 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,11 @@ export const warn = (message: string) => {
console.warn(`🦄 [react-native-unistyles]: ${message}`)
}

export const isMobile = Platform.OS === 'android' || Platform.OS === 'ios'
export const isWeb = Platform.OS === 'web'
export const isServer = typeof window === 'undefined'

export const Orientation = {
Landscape: 'landscape',
Portrait: 'portrait'
} as const
2 changes: 1 addition & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export { normalizeStyles } from './normalizeStyles'
export * from './normalizer'
export { getBreakpointFromScreenWidth, sortAndValidateBreakpoints, getValueForBreakpoint } from './breakpoints'
export { proxifyFunction, parseStyle } from './styles'
export { isServer } from './common'
export { isServer, Orientation } from './common'
export {
extractValues,
getKeyForCustomMediaQuery,
Expand Down

0 comments on commit 2b3ede7

Please sign in to comment.