Skip to content

Commit 09c6d39

Browse files
YoussefHennaneeds
andauthored
New Theming (#868)
* Move all current themeing to seperate package * Initial progress on new themeing system * Finalize initial theming package structure * Add tests for validators * Remove no longer used colors from palette * Initial proxy of theme object to allow breakpoint and platform selection * todo comment * Cleanup theming proxy * Add tests for theme values proxy * Move `createThemeValuesProxy` function to seperate file * Add new theme provider and hooks * Update theme references across repo to use new theme structure * Initial theming in example app * Fix some tests * Fix theme not working in portal * Fix incorrect error thrown * Adjust some components to use theme * Add a theme example screen * Use theme hook instead of `withTheme` when forward ref is used * Fix typoes Co-authored-by: needs <[email protected]> * Revert createMuiTheme usage * Fix screen container background * Add `useCallback` to changeTheme * add webview to core --------- Co-authored-by: needs <[email protected]>
1 parent 28a22f4 commit 09c6d39

File tree

129 files changed

+1749
-974
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+1749
-974
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ This is a lerna/monorepo setup that is split up into types, native, core and ui
3434
- packages/ui: pulls in everything from core and native and re-exports it. This is what any user will install to use this Library
3535
- packages/core: Non-native, javascript components go here. These are components that work perfectly across web, ios and android without any adjustments
3636
- packages/native: Native components that rely on expo/react-native modules likes `expo-av` and `@expo/vector-icons`. This houses our AudioPlayer and Icon components because the current version requires modifications to work well on Web
37-
- packages/types: Shared typescript types and SEED_DATA types which is how we build the translation layer for Draftbit
37+
- packages/theme: Draftbit's theming system
3838

3939
** Chances are, you'll spend most of your time in `packages/core` **
4040

deprecated-packages/web-maps/tsconfig.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"extends": "../../tsconfig.json",
3-
"references": [{ "path": "../types" }],
43
"compilerOptions": {
54
"outDir": "./lib/"
65
}

example/src/AccordionExample.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Section, { Container } from "./Section";
55

66
function AccordionExample({ theme }) {
77
return (
8-
<Container style={{ backgroundColor: theme.colors.background }}>
8+
<Container style={{ backgroundColor: theme.colors.background.brand }}>
99
<Section title="Basic accordion with no additional styles">
1010
<AccordionGroup label={"Basic"}>
1111
<Text>Item 1</Text>
@@ -14,9 +14,9 @@ function AccordionExample({ theme }) {
1414
</Section>
1515
<Section title="Expandable Accordion group">
1616
<AccordionGroup
17-
openColor={theme.colors.primary}
18-
closedColor={theme.colors.secondary}
19-
caretColor={theme.colors.medium}
17+
openColor={theme.colors.branding.primary}
18+
closedColor={theme.colors.branding.secondary}
19+
caretColor={theme.colors.text.medium}
2020
icon={"folder"}
2121
iconSize={26}
2222
style={{ fontWeight: "bold" }}
@@ -28,9 +28,9 @@ function AccordionExample({ theme }) {
2828
</Section>
2929
<Section title="Expanded Accordion group">
3030
<AccordionGroup
31-
openColor={theme.colors.primary}
32-
closedColor={theme.colors.secondary}
33-
caretColor={theme.colors.divider}
31+
openColor={theme.colors.branding.primary}
32+
closedColor={theme.colors.branding.secondary}
33+
caretColor={theme.colors.border.brand}
3434
icon={"folder"}
3535
iconSize={26}
3636
style={{ fontWeight: "normal" }}

example/src/ActionSheetExample.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function ActionSheetExample({ theme }) {
2020
}, []);
2121

2222
return (
23-
<Container style={{ backgroundColor: theme.colors.background }}>
23+
<Container style={{ backgroundColor: theme.colors.background.brand }}>
2424
<Section title="Action Sheet">
2525
<ButtonSolid title="Open Action Sheet" onPress={showActionSheet} />
2626
<ActionSheet visible={visible} onClose={hideActionSheet}>
@@ -30,7 +30,7 @@ function ActionSheetExample({ theme }) {
3030
you to show some long text message like this."
3131
/>
3232
<ActionSheetItem
33-
style={{ color: theme.colors.error }}
33+
style={{ color: theme.colors.text.danger }}
3434
onPress={hideActionSheet}
3535
label="Delete Draft"
3636
/>

example/src/App.tsx

Lines changed: 132 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ import {
1919
import { createDrawerNavigator } from "@react-navigation/drawer";
2020
import "react-native-gesture-handler";
2121

22-
import { Provider, DefaultTheme, ScreenContainer } from "@draftbit/ui";
22+
import {
23+
Provider,
24+
DefaultTheme,
25+
ScreenContainer,
26+
useTheme,
27+
createTheme,
28+
useChangeTheme,
29+
} from "@draftbit/ui";
2330
import {
2431
SafeAreaProvider,
2532
initialWindowMetrics,
@@ -65,8 +72,10 @@ import CircularProgressExample from "./CircularProgressExample";
6572
import VideoPlayerExample from "./VideoPlayerExample";
6673
import PinInputExample from "./PinInputExample";
6774
import KeyboardAvoidingViewExample from "./KeyboardAvoidingViewExample";
75+
import ThemeExample from "./ThemeExample";
6876

6977
const ROUTES = {
78+
Theme: ThemeExample,
7079
AudioPlayer: AudioPlayerExample,
7180
Layout: LayoutExample,
7281
Icon: IconExample,
@@ -123,10 +132,102 @@ type SplashScreenProviderProps = { image: ImageSourcePropType };
123132

124133
SplashScreen.preventAutoHideAsync().catch(() => {});
125134

135+
const themeBreakpoints = {
136+
mobile: 0,
137+
tablet: 480,
138+
laptop: 992,
139+
desktop: 1440,
140+
bigScreen: 1920,
141+
};
142+
143+
const BaseTheme = createTheme({
144+
breakpoints: themeBreakpoints,
145+
palettes: {},
146+
theme: {
147+
name: "BaseTheme",
148+
colors: {
149+
background: {
150+
platformTest: {
151+
default: "purple",
152+
ios: "blue",
153+
android: "green",
154+
},
155+
breakpointTest: {
156+
default: "purple",
157+
tablet: "yellow",
158+
laptop: "red",
159+
},
160+
},
161+
},
162+
typography: {},
163+
},
164+
baseTheme: DefaultTheme,
165+
});
166+
167+
const DarkTheme = createTheme({
168+
breakpoints: themeBreakpoints,
169+
palettes: {},
170+
theme: {
171+
name: "DarkTheme",
172+
colors: {
173+
background: {
174+
brand: "#404040",
175+
},
176+
text: {
177+
normal: "white",
178+
strong: "white",
179+
},
180+
},
181+
typography: {},
182+
},
183+
baseTheme: BaseTheme,
184+
});
185+
186+
const LightTheme = createTheme({
187+
breakpoints: themeBreakpoints,
188+
palettes: {},
189+
theme: {
190+
name: "LightTheme",
191+
colors: {},
192+
typography: {},
193+
},
194+
baseTheme: BaseTheme,
195+
});
196+
197+
const OtherTheme = createTheme({
198+
breakpoints: themeBreakpoints,
199+
palettes: {},
200+
theme: {
201+
name: "OtherTheme",
202+
colors: {
203+
branding: {
204+
primary: "#A91D3A",
205+
secondary: "#824D74",
206+
},
207+
background: {
208+
brand: "black",
209+
},
210+
text: {
211+
strong: "white",
212+
normal: "white",
213+
},
214+
border: {
215+
brand: "#FDAF7B",
216+
},
217+
},
218+
typography: {},
219+
},
220+
baseTheme: BaseTheme,
221+
});
222+
126223
export default function App() {
127224
return (
128225
<SplashScreenProvider image={splashImage}>
129-
<Provider theme={DefaultTheme}>
226+
<Provider
227+
themes={[LightTheme, DarkTheme, OtherTheme]}
228+
breakpoints={themeBreakpoints}
229+
initialThemeName={"LightTheme"}
230+
>
130231
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
131232
<Examples />
132233
</SafeAreaProvider>
@@ -228,15 +329,23 @@ const AnimatedSplashScreen: React.FC<
228329

229330
function Example({ title, children }: ExampleProps) {
230331
const navigation = useNavigation();
332+
const theme = useTheme();
333+
const changeTheme = useChangeTheme();
231334

232335
return (
233336
<ScreenContainer
234337
hasSafeArea={true}
235338
hasTopSafeArea={true}
236339
hasBottomSafeArea={true}
237340
scrollable={false}
341+
style={{ backgroundColor: theme.colors.background.brand }}
238342
>
239-
<View style={exampleStyles.headerStyle}>
343+
<View
344+
style={[
345+
exampleStyles.headerStyle,
346+
{ backgroundColor: theme.colors.branding.primary },
347+
]}
348+
>
240349
<TouchableOpacity
241350
style={exampleStyles.menuButtonStyle}
242351
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
@@ -248,6 +357,23 @@ function Example({ title, children }: ExampleProps) {
248357
</TouchableOpacity>
249358

250359
<Text style={[exampleStyles.headerTextStyle]}>{title}</Text>
360+
<TouchableOpacity
361+
style={exampleStyles.menuButtonStyle}
362+
onPress={() => {
363+
if (theme.name === "LightTheme") {
364+
changeTheme("DarkTheme");
365+
} else if (theme.name === "DarkTheme") {
366+
changeTheme("OtherTheme");
367+
} else {
368+
changeTheme("LightTheme");
369+
}
370+
}}
371+
>
372+
<Image
373+
style={exampleStyles.menuButtonImageStyle}
374+
source={require("./assets/images/theme.png")}
375+
/>
376+
</TouchableOpacity>
251377
</View>
252378
<ScreenContainer scrollable={true} hasSafeArea={false}>
253379
{children}
@@ -257,12 +383,13 @@ function Example({ title, children }: ExampleProps) {
257383
}
258384

259385
function Examples() {
386+
const theme = useTheme();
260387
return (
261388
<NavigationContainer>
262389
<Drawer.Navigator
263-
initialRouteName="Layout"
390+
initialRouteName="Theme"
264391
screenOptions={{
265-
drawerActiveTintColor: "rgba(90, 69, 255, 1)",
392+
drawerActiveTintColor: theme.colors.branding.primary,
266393
headerShown: false,
267394
}}
268395
>
@@ -290,7 +417,6 @@ const exampleStyles = StyleSheet.create({
290417
},
291418
headerStyle: {
292419
flexDirection: "row",
293-
backgroundColor: "rgba(90, 69, 255, 1)",
294420
alignItems: "center",
295421
justifyContent: "flex-start",
296422
height: "10%",

example/src/CheckboxExample.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@ import {
88
import * as React from "react";
99
import { StyleSheet, Text, View } from "react-native";
1010
import Section from "./Section";
11+
import { useTheme } from "@react-navigation/native";
1112

12-
const SingleCheckboxWrapper = ({ label, children }) => (
13-
<View style={styles.checkboxWrapper}>
14-
<View style={styles.checkboxLabel}>
15-
<Text>{label}</Text>
13+
const SingleCheckboxWrapper = ({ label, children }) => {
14+
const theme = useTheme();
15+
return (
16+
<View style={styles.checkboxWrapper}>
17+
<View style={styles.checkboxLabel}>
18+
<Text style={{ color: theme.colors.text.strong }}>{label}</Text>
19+
</View>
20+
<View>{children}</View>
1621
</View>
17-
<View>{children}</View>
18-
</View>
19-
);
22+
);
23+
};
2024

2125
const CheckboxExample = ({ theme }) => {
2226
const [checked, setChecked] = React.useState(true);
@@ -43,8 +47,8 @@ const CheckboxExample = ({ theme }) => {
4347
<Checkbox
4448
status={checked}
4549
onPress={handlePress}
46-
color={theme.colors.secondary}
47-
uncheckedColor={theme.colors.error}
50+
color={theme.colors.branding.secondary}
51+
uncheckedColor={theme.colors.text.danger}
4852
/>
4953
</SingleCheckboxWrapper>
5054
<SingleCheckboxWrapper label="Custom icons">

example/src/DatePickerExample.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function DatePickerExample({ theme }) {
1212
const [date3, setDate3] = React.useState(new Date());
1313

1414
return (
15-
<Container style={{ backgroundColor: theme.colors.background }}>
15+
<Container style={{ backgroundColor: theme.colors.background.brand }}>
1616
<Section title="Underline">
1717
<DatePicker
1818
label="Date (without date prop)"

example/src/MapViewDataDrivenExample.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const MapViewDataDrivenExample = ({ theme }) => {
3535
<MapMarker
3636
latitude={item.latitude}
3737
longitude={item.longitude}
38-
pinColor={theme.colors.secondary}
38+
pinColor={theme.colors.branding.secondary}
3939
>
4040
<MapCallout showTooltip>
4141
<Text>With Callout</Text>

example/src/MapViewExample.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ const MapViewExample = ({ theme }) => {
2828
<MapMarker
2929
latitude={40.741895}
3030
longitude={-73.989308}
31-
pinColor={theme.colors.primary}
31+
pinColor={theme.colors.branding.primary}
3232
title="Draftbit"
3333
description="A simple MapView example"
3434
/>
3535
<MapMarker
3636
latitude={40.741895}
3737
longitude={-73.979308}
38-
pinColor={theme.colors.secondary}
38+
pinColor={theme.colors.branding.secondary}
3939
>
4040
<MapCallout showTooltip>
4141
<Text>With Callout</Text>
@@ -45,14 +45,14 @@ const MapViewExample = ({ theme }) => {
4545
<MapMarker
4646
latitude={43.741895}
4747
longitude={-73.989308}
48-
pinColor={theme.colors.primary}
48+
pinColor={theme.colors.branding.primary}
4949
title="Draftbit"
5050
description="A simple MapView example"
5151
/>
5252
<MapMarker
5353
latitude={43.741895}
5454
longitude={-73.979308}
55-
pinColor={theme.colors.secondary}
55+
pinColor={theme.colors.branding.secondary}
5656
>
5757
<MapCallout showTooltip>
5858
<Text>With Callout</Text>

example/src/PickerExample.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ function PickerExample() {
3131
options={OPTIONS}
3232
value={value1}
3333
mode="dropdown"
34-
dropDownTextColor="red"
3534
onValueChange={(value) => setValue(value.toString())}
3635
style={{ marginBottom: 20 }}
3736
/>

0 commit comments

Comments
 (0)