Skip to content

Commit

Permalink
feat: add support for pixel based media queries ios
Browse files Browse the repository at this point in the history
  • Loading branch information
jpudysz committed Nov 7, 2023
1 parent 78b3f3a commit bc74484
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 62 deletions.
24 changes: 10 additions & 14 deletions cxx/UnistylesRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,21 +223,17 @@ std::string UnistylesRuntime::getBreakpointFromScreenWidth(int width, const std:
}

void UnistylesRuntime::handleScreenSizeChange(int width, int height) {
if (width != this->screenWidth) {
this->screenWidth = width;
}

if (height != this->screenHeight) {
this->screenHeight = height;
}

std::string currentBreakpoint = this->breakpoint;
std::string nextBreakpoint = this->getBreakpointFromScreenWidth(width, this->sortedBreakpointPairs);
std::string breakpoint = this->getBreakpointFromScreenWidth(width, this->sortedBreakpointPairs);

this->breakpoint = breakpoint;
this->screenWidth = width;
this->screenHeight = height;

int orientation = width > height
? UnistylesOrientationLandscape
: UnistylesOrientationPortrait;

if (currentBreakpoint != nextBreakpoint) {
this->breakpoint = nextBreakpoint;
this->onBreakpointChange(nextBreakpoint);
}
this->onBreakpointChange(breakpoint, orientation, width, height);
}

void UnistylesRuntime::handleAppearanceChange(std::string colorScheme) {
Expand Down
7 changes: 5 additions & 2 deletions cxx/UnistylesRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

using namespace facebook;

const int UnistylesOrientationPortrait = 1;
const int UnistylesOrientationLandscape = 2;

const std::string UnistylesDarkScheme = "dark";
const std::string UnistylesLightScheme = "light";
const std::string UnistylesUnspecifiedScheme = "unspecified";
Expand All @@ -13,8 +16,8 @@ const std::string UnistylesErrorBreakpointsCannotBeEmpty = "UNISTYLES_ERROR_BREA
const std::string UnistylesErrorBreakpointsMustStartFromZero = "UNISTYLES_ERROR_BREAKPOINTS_MUST_START_FROM_ZER0";
const std::string UnistylesErrorThemesCannotBeEmpty = "UNISTYLES_ERROR_THEMES_CANNOT_BE_EMPTY";

typedef void(^UnistylesThemeChangeEvent)(std::string);
typedef void(^UnistylesBreakpointChangeEvent)(std::string);
typedef void(^UnistylesThemeChangeEvent)(std::string themeName);
typedef void(^UnistylesBreakpointChangeEvent)(std::string breakpoint, int layout, int screenWidth, int screenHeight);

class JSI_EXPORT UnistylesRuntime : public jsi::HostObject {
private:
Expand Down
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.MediaQueriesWidthHeight} component={Screens.MediaQueriesWidthHeight} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
Expand Down
6 changes: 4 additions & 2 deletions examples/expo/src/common/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export enum DemoNames {
MultipleThemes = 'MultipleThemes',
MultipleThemesAdaptive = 'MultipleThemesAdaptive',
NoBreakpoints = 'NoBreakpoints',
WithBreakpoints = 'WithBreakpoints'
WithBreakpoints = 'WithBreakpoints',
MediaQueriesWidthHeight = 'MediaQueriesWidthHeight',
}

export type DemoStackParams = {
Expand All @@ -21,7 +22,8 @@ export type DemoStackParams = {
[DemoNames.MultipleThemes]: undefined,
[DemoNames.MultipleThemesAdaptive]: undefined,
[DemoNames.NoBreakpoints]: undefined,
[DemoNames.WithBreakpoints]: undefined
[DemoNames.WithBreakpoints]: undefined,
[DemoNames.MediaQueriesWidthHeight]: undefined,
}

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

export const MediaQueriesWidthHeight: React.FunctionComponent = () => {
useLazyRegistryForDemo(() => {
UnistylesRegistry
.addThemes({
light: lightTheme,
dark: darkTheme,
premium: premiumTheme
})
.addBreakpoints(breakpoints)
})

useInitialTheme('light')

const { styles, theme } = useStyles(stylesheet)

return (
<DemoScreen>
<View style={styles.container}>
<Text style={styles.text}>
This demo has media queries for width and height
</Text>
<Text style={styles.text}>
Your window dimensions are: {UnistylesRuntime.screen.width}x{UnistylesRuntime.screen.height}
</Text>
<Text style={styles.text}>
For width up to 500, and height up to 1000 the background is {theme.colors.backgroundColor}
</Text>
<Text style={styles.text}>
For width above 900 the background is {theme.colors.aloes}
</Text>
<Text>
Rotate or resize the window to see the changes
</Text>
</View>
</DemoScreen>
)
}

const stylesheet = createStyleSheet(theme => ({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 20,
backgroundColor: {
':w[, 500]:h[, 1000]': theme.colors.backgroundColor,
':w[900]': theme.colors.aloes
},
rowGap: 20
},
text: {
textAlign: 'center',
color: theme.colors.typography
}
}))
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,3 +7,4 @@ export { MultipleThemesScreen } from './MultipleThemesScreen'
export { MultipleThemesAdaptiveScreen } from './MultipleThemesAdaptiveScreen'
export { NoBreakpointsScreen } from './NoBreakpointsScreen'
export { WithBreakpointsScreen } from './WithBreakpointsScreen'
export { MediaQueriesWidthHeight } from './MediaQueriesWidthHeight'
11 changes: 8 additions & 3 deletions ios/UnistylesModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,16 @@ void registerUnistylesHostObject(jsi::Runtime &runtime, UnistylesModule* weakSel

[weakSelf emitEvent:@"onChange" withBody:body];
};
UnistylesBreakpointChangeEvent onBreakpointChange = ^(std::string breakpoint) {
UnistylesBreakpointChangeEvent onBreakpointChange = ^(std::string breakpoint, int orientation, int width, int height) {
NSDictionary *body = @{
@"type": @"breakpoint",
@"type": @"layout",
@"payload": @{
@"breakpoint": cxxStringToNSString(breakpoint)
@"breakpoint": cxxStringToNSString(breakpoint),
@"orientation": @(orientation),
@"screen": @{
@"width": @(width),
@"height": @(height)
}
}
};

Expand Down
24 changes: 9 additions & 15 deletions src/types/cxx.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { UnistylesThemes, UnistylesBreakpoints } from '../global'
import type { ScreenSize } from './breakpoints'

export type Nullable<T> = T | null
export type ColorSchemeName = 'light' | 'dark' | undefined
Expand Down Expand Up @@ -34,33 +35,26 @@ export type UnistylesBridge = {

export enum CxxUnistylesEventTypes {
Theme = 'theme',
Size = 'size',
Breakpoint = 'breakpoint'
Layout = 'layout'
}

export type CxxUnistylesThemeEvent = {
export type UnistylesThemeEvent = {
type: CxxUnistylesEventTypes.Theme,
payload: {
themeName: keyof UnistylesThemes
}
}

export type CxxUnistylesSizeEvent = {
type: CxxUnistylesEventTypes.Size,
export type UnistylesMobileLayoutEvent = {
type: CxxUnistylesEventTypes.Layout,
payload: {
width: number,
height: number
screen: ScreenSize,
breakpoint: keyof UnistylesBreakpoints,
orientation: ScreenOrientation
}
}

export type CxxUnistylesBreakpointEvent = {
type: CxxUnistylesEventTypes.Breakpoint,
payload: {
breakpoint: keyof UnistylesBreakpoints
}
}

export type UnistylesEvents = CxxUnistylesThemeEvent | CxxUnistylesSizeEvent | CxxUnistylesBreakpointEvent
export type UnistylesEvents = UnistylesThemeEvent | UnistylesMobileLayoutEvent

export enum UnistylesError {
RuntimeUnavailable = 'UNISTYLES_ERROR_RUNTIME_UNAVAILABLE',
Expand Down
4 changes: 2 additions & 2 deletions src/useStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ export const useStyles = <ST extends CustomNamedStyles<ST>>(stylesheet?: ST | Cr
if (typeof value === 'function') {
return {
...acc,
[key]: proxifyFunction(value, breakpoint!, screenSize)
[key]: proxifyFunction(value, breakpoint, screenSize)
}
}

return StyleSheet.create({
...acc,
[key]: parseStyle<ST>(style, breakpoint!, screenSize)
[key]: parseStyle<ST>(style, breakpoint, screenSize)
})
}, {} as ST), [breakpoint, screenSize, parsedStyles])

Expand Down
36 changes: 12 additions & 24 deletions src/useUnistyles.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import { NativeEventEmitter, NativeModules } from 'react-native'
import { useEffect, useState } from 'react'
import type {
CxxUnistylesBreakpointEvent,
CxxUnistylesSizeEvent,
CxxUnistylesThemeEvent,
UnistylesEvents
} from './types'
import { CxxUnistylesEventTypes } from './types'
import type { UnistylesThemeEvent, UnistylesMobileLayoutEvent, UnistylesEvents } from './types'
import { CxxUnistylesEventTypes, ScreenOrientation } from './types'
import { unistyles } from './Unistyles'

const unistylesEvents = new NativeEventEmitter(NativeModules.Unistyles)

export const useUnistyles = () => {
const [orientation, setOrientation] = useState<ScreenOrientation>(unistyles.runtime.orientation)
const [theme, setTheme] = useState(unistyles.runtime.getTheme(unistyles.runtime.themeName))
const [breakpoint, setBreakpoint] = useState(unistyles.runtime.breakpoint)
const [screenSize, setScreenSize] = useState({
width: 0,
height: 0
width: unistyles.runtime.screen.width,
height: unistyles.runtime.screen.height
})

useEffect(() => {
Expand All @@ -25,27 +21,18 @@ export const useUnistyles = () => {
(event: UnistylesEvents) => {
switch (event.type) {
case CxxUnistylesEventTypes.Theme: {
const themeEvent = event as CxxUnistylesThemeEvent
const themeEvent = event as UnistylesThemeEvent

setTheme(unistyles.runtime.getTheme(themeEvent.payload.themeName))

return
}
// this event is not available on mobile
case CxxUnistylesEventTypes.Size: {
const sizeEvent = event as CxxUnistylesSizeEvent
case CxxUnistylesEventTypes.Layout: {
const layoutEvent = event as UnistylesMobileLayoutEvent

setScreenSize({
width: sizeEvent.payload.width,
height: sizeEvent.payload.height
})

return
}
case CxxUnistylesEventTypes.Breakpoint: {
const breakpointEvent = event as CxxUnistylesBreakpointEvent

setBreakpoint(breakpointEvent.payload.breakpoint)
setBreakpoint(layoutEvent.payload.breakpoint)
setOrientation(layoutEvent.payload.orientation)
setScreenSize(layoutEvent.payload.screen)

return
}
Expand All @@ -60,6 +47,7 @@ export const useUnistyles = () => {

return {
theme,
orientation,
breakpoint,
screenSize
}
Expand Down

0 comments on commit bc74484

Please sign in to comment.