├── .gitignore ├── LICENSE ├── README.md ├── TODO.txt ├── babel.config.js ├── docs ├── .nojekyll ├── README.md ├── _coverpage.md ├── _media │ ├── examples │ │ └── single-style-example.gif │ ├── getting-started-example.jpg │ ├── react-native-reflect-twitter-banner-01.jpg │ ├── reflect-logo-color-circle.jpg │ ├── reflect-logo-color-circle.svg │ ├── reflect-logo-color.svg │ └── reflect-logo.svg ├── index.html ├── theme-custom.css └── typedoc │ ├── assets │ ├── css │ │ └── main.css │ ├── images │ │ ├── icons.png │ │ ├── icons@2x.png │ │ ├── widgets.png │ │ └── widgets@2x.png │ └── js │ │ ├── main.js │ │ └── search.json │ └── index.html ├── examples ├── .expo-shared │ └── assets.json ├── .gitignore ├── App.tsx ├── README.md ├── app.json ├── assets │ ├── icon.png │ └── splash.png ├── babel.config.js ├── package.json ├── screens │ ├── GettingStarted.tsx │ ├── MultipleStyles.tsx │ ├── MultipleStylesHook.tsx │ ├── PlatformResponsiveProps.tsx │ ├── PlatformSpecificProps.tsx │ ├── ResponsiveProps.tsx │ ├── ResponsivePropsHook.tsx │ ├── SingleStyle.tsx │ ├── SingleStyleHook.tsx │ └── index.tsx └── tsconfig.json ├── package.json ├── rollup.config.js ├── src ├── __mocks__ │ └── utils.js ├── __tests__ │ ├── __snapshots__ │ │ ├── processAttrs.spec.web.ts.snap.web │ │ ├── styled.spec.web.tsx.snap.web │ │ └── useStyled.spec.web.tsx.snap.web │ ├── os.spec.universal.ts │ ├── processAttrs.spec.web.ts │ ├── processStyle.spec.web.ts │ ├── processStyles.spec.web.ts │ ├── styled.spec.web.tsx │ └── useStyled.spec.web.tsx ├── __type_tests__ │ ├── index.d.ts │ ├── misc.typeTest.tsx │ ├── styled.typeTest.tsx │ ├── theme.typeTest.tsx │ ├── tsconfig.json │ ├── tslint.json │ ├── typeTests.tsx │ ├── useStyled.typeTest.tsx │ └── utils.typeTest.tsx ├── index.d.ts ├── index.js ├── processAttrs.js ├── processStyles.js ├── styled.d.ts ├── styled.js ├── testsUtils.d.ts ├── testsUtils.js ├── theme.d.ts ├── theme.js ├── types.d.ts ├── types.js ├── useStyled.d.ts ├── useStyled.js ├── utils.d.ts └── utils.js ├── tsconfig.json └── typedoc.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | lib/ 4 | yarn-debug.log* 5 | yarn-error.log* 6 | yarn.lock 7 | .vscode 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Santiago Ferreira 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | logo 2 | 3 | # React Native Reflect 4 | 5 | Responsive, theme-based style system for React Native and React Native Web 6 | https://sntx.github.io/react-native-reflect 7 | 8 | [![spectrum-badge][]][spectrum] 9 | ![MIT License][license] 10 | [![Types](https://img.shields.io/npm/types/scrub-js.svg)](https://www.npmjs.com/package/react-native-reflect) 11 | 12 | [spectrum-badge]: https://badgen.net/badge/spectrum/community/cyan 13 | [spectrum]: https://spectrum.chat/react-native-reflect 14 | [license]: https://badgen.net/badge/license/MIT/blue 15 | 16 | ```sh 17 | npm i react-native-reflect 18 | ``` 19 | 20 | ## Description 21 | 22 | **Reflect makes it easy to create universal React Native applications for Native and Web** by providing tools for **responsive styles and props**, a **theme system** and other utilities. 23 | 24 | Reflect is an alternative to libraries such as Styled Components and Styled System, built from the ground up for React Native and React Native Web. It provides exports such as: **styled()**, **useStyled()** and **ThemeProvider**, with an API that is **React Native friendly**. 25 | 26 | The library is also minimal, has no dependencies on other styling libraries and it is designed to be used alone or with other React Native UI libraries such as React Native Elements. Use it to define styling for a whole application, as the building blocks for creating your own UI library, or just as needed, to handle different screen sizes or platforms. 27 | 28 | # Getting Started 29 | 30 | The following example shows how to use Reflect to create theme-based responsive components. The components created will display as a single column on small screens and as two columns on larger screens. 31 | 32 | ![Getting Started Example](https://github.com/sntx/react-native-reflect/raw/master/docs/_media/getting-started-example.jpg "Getting Started Example") 33 | 34 | ## Installation 35 | 36 | Create an Expo project and install Reflect: 37 | 38 | ```bash 39 | expo init my-reflect-app 40 | cd my-reflect-app 41 | 42 | # with yarn 43 | yarn add react-native-reflect 44 | 45 | # with npm 46 | npm i react-native-reflect 47 | ``` 48 | 49 | ## Usage 50 | 51 | Replace contents of App.js or App.tsx with the code below: 52 | 53 | ```javascript 54 | import React from "react"; 55 | import { View, SafeAreaView } from "react-native"; 56 | import { styled, ThemeProvider, defaultTheme } from "react-native-reflect"; 57 | 58 | // (1) Define your theme 59 | const theme = { 60 | ...defaultTheme, 61 | colors: { 62 | red: "#FF4B48", 63 | blue: "#2AB7CA", 64 | yellow: "#FFD766", 65 | grey: "#E6E6EA", 66 | }, 67 | }; 68 | 69 | // (2) Define your theme-based, responsive components 70 | const Flex = styled(View, { 71 | display: "flex", 72 | flexDirection: "row", 73 | flexWrap: "wrap", 74 | }); 75 | 76 | const Box = styled(View, { 77 | // Responsive -> 100% on smaller screens, 50% on larger screens 78 | width: ["100%", "50%"], 79 | // Theme based values -> height: 6 = theme.size[6] = 96 80 | height: 6, 81 | }); 82 | 83 | // (3) Create variations of your components 84 | const RedBox = styled(Box, { backgroundColor: "red" }); 85 | const BlueBox = styled(Box, { backgroundColor: "blue" }); 86 | const YellowBox = styled(Box, { backgroundColor: "yellow" }); 87 | const GreyBox = styled(Box, { backgroundColor: "grey" }); 88 | 89 | // (4) Enjoy a fully responsive native/web UI with a clean markup! 90 | export default function App() { 91 | return ( 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | ); 103 | } 104 | ``` 105 | 106 | Start Expo app and run it on a web browser and on a simulator. From the command line: "Press a for Android emulator, or i for iOS simulator, or w to run on web." 107 | 108 | ```bash 109 | # with yarn 110 | yarn start 111 | 112 | # with npm 113 | npm run start 114 | ``` 115 | 116 | # Docs 117 | 118 | - [Getting Started](https://sntx.github.io/react-native-reflect/#/?id=getting-started) 119 | - [styled()](https://sntx.github.io/react-native-reflect/#/?id=styled) 120 | - [useStyled()](https://sntx.github.io/react-native-reflect/#/?id=usestyled) 121 | - [os()](https://sntx.github.io/react-native-reflect/#/?id=os) 122 | - [Theme](https://sntx.github.io/react-native-reflect/#/?id=theme) 123 | - [API / TypeScript](https://sntx.github.io/react-native-reflect/#/?id=api-typescript) 124 | 125 | # Tutorials 126 | 127 | - [Responsive UX Design with React Native Reflect (Part 1)](https://dev.to/sntx/build-a-responsive-react-native-photo-album-part-1-4doe) 128 | - [Responsive UX Design with React Native Reflect (Part 2)](https://dev.to/sntx/responsive-ux-design-with-react-native-reflect-part-2-m24) 129 | - [Responsive UX Design with React Native Reflect (Part 3)](https://dev.to/sntx/responsive-ux-design-with-react-native-reflect-part-3-2i6f) -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | Fix warnings on iOS simulator, etc. 2 | 3 | Add docs page title and icon, right now the title is "Document" 4 | 5 | Add radii to default theme 6 | 7 | Fix types for styled(FlatList, {}, {}) with react-native FlatList 8 | 9 | Fix types for styled(Image, {}) with react-native Image 10 | 11 | Add variants, , 12 | 13 | Make better defaultTheme and use it in a more complete example in examples app 14 | Add color arrays (look at ui kitten colors: https://akveo.github.io/react-native-ui-kitten/docs/design-system/eva-light-theme) 15 | material ui colors are also good 16 | 17 | Add decimal points for theme indices, for example: 1.5 18 | 19 | Final touches to Reflect logo, docsify home page, etc. 20 | Better looking animated gif showing reflect in action in multiple screens and devices 21 | - rotating phone 22 | - tablets 23 | - desktop 24 | - etc 25 | 26 | Include only used methods from lodash with rollup 27 | https://rollupjs.org/guide/en/#tree-shaking 28 | https://lodash.com/per-method-packages 29 | or remove lodash alltogether? 30 | 31 | Add example app to snack 32 | https://snack.expo.io/@sntx/b5d446 33 | 34 | Create attr() method 35 | Add attr() method to docs and mention in styled() sections as alternative 36 | 37 | Add more badges 38 | https://flat.badgen.net/ 39 | - minizip size without types? (only lib/rn.js should be included) 40 | 41 | Add array last argument to styled() 42 | Styled = styled(Comp, ["space"]) adds 43 | Styled = styled(Comp, { ... }, ["space"]) 44 | Styled = styled(Comp, { ... }, { ... }, ["space"]) 45 | 46 | Add types for remaining methods (the ones that are not exported) 47 | so unit tests types work 48 | 49 | Add function as props? 50 | 51 | styled(TouchableOpacity, ({ active }) => { 52 | padding: 5, 53 | backgroundColor: active ? "red" : null, 54 | }) 55 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sntx/react-native-reflect/41a6f45ffcfb067ebc104ad0a3c0947abcabea7f/docs/.nojekyll -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | logo 2 | 3 | # React Native Reflect 4 | 5 | Responsive, theme-based style system for React Native and React Native Web 6 | 7 | [![spectrum-badge][]][spectrum] 8 | ![MIT License][license] 9 | [![Types](https://img.shields.io/npm/types/scrub-js.svg)](https://www.npmjs.com/package/react-native-reflect) 10 | 11 | [spectrum-badge]: https://badgen.net/badge/spectrum/community/cyan 12 | [spectrum]: https://spectrum.chat/react-native-reflect 13 | [license]: https://badgen.net/badge/license/MIT/blue 14 | 15 | ```sh 16 | npm i react-native-reflect 17 | ``` 18 | 19 | ## Description 20 | 21 | **Reflect makes it easy to create universal React Native applications for Native and Web** by providing tools for **responsive styles and props**, a **theme system** and other utilities. 22 | 23 | Reflect is an alternative to libraries such as Styled Components and Styled System, built from the ground up for React Native and React Native Web. It provides exports such as: **styled()**, **useStyled()** and **ThemeProvider**, with an API that is **React Native friendly**. 24 | 25 | The library is also minimal, has no dependencies on other styling libraries and it is designed to be used alone or with other React Native UI libraries such as React Native Elements. Use it to define styling for a whole application, as the building blocks for creating your own UI library, or just as needed, to handle different screen sizes or platforms. 26 | 27 | ## Features 28 | 29 | - Built from the ground up for React Native and React Native Web 30 | - Quickly create theme-based, responsive styles (fontSize, margin, etc.) 31 | - Easily make any prop responsive and platform conditional 32 | - Integrates nicely with other UI Libraries, such as React Native Elements 33 | - Provides similar functionality to Styled Components and Styled System 34 | - Thoroughly unit tested 35 | 36 | # Getting Started 37 | 38 | The following example shows how to use Reflect to create theme-based responsive components. The components created will display as a single column on small screens and as two columns on larger screens. 39 | 40 | ![Getting Started Example](https://github.com/sntx/react-native-reflect/raw/master/docs/_media/getting-started-example.jpg "Getting Started Example") 41 | 42 | ## Installation 43 | 44 | Create an Expo project and install Reflect: 45 | 46 | ```bash 47 | expo init my-reflect-app 48 | cd my-reflect-app 49 | 50 | # with yarn 51 | yarn add react-native-reflect 52 | 53 | # with npm 54 | npm i react-native-reflect 55 | ``` 56 | 57 | ## Usage 58 | 59 | Replace contents of App.js or App.tsx with the code below: 60 | 61 | ```javascript 62 | import React from "react"; 63 | import { View, SafeAreaView } from "react-native"; 64 | import { styled, ThemeProvider, defaultTheme } from "react-native-reflect"; 65 | 66 | // (1) Define your theme 67 | const theme = { 68 | ...defaultTheme, 69 | colors: { 70 | red: "#FF4B48", 71 | blue: "#2AB7CA", 72 | yellow: "#FFD766", 73 | grey: "#E6E6EA", 74 | }, 75 | }; 76 | 77 | // (2) Define your theme-based, responsive components 78 | const Flex = styled(View, { 79 | display: "flex", 80 | flexDirection: "row", 81 | flexWrap: "wrap", 82 | }); 83 | 84 | const Box = styled(View, { 85 | // Responsive -> 100% on smaller screens, 50% on larger screens 86 | width: ["100%", "50%"], 87 | // Theme based values -> height: 6 = theme.size[6] = 96 88 | height: 6, 89 | }); 90 | 91 | // (3) Create variations of your components 92 | const RedBox = styled(Box, { backgroundColor: "red" }); 93 | const BlueBox = styled(Box, { backgroundColor: "blue" }); 94 | const YellowBox = styled(Box, { backgroundColor: "yellow" }); 95 | const GreyBox = styled(Box, { backgroundColor: "grey" }); 96 | 97 | // (4) Enjoy a fully responsive native/web UI with a clean markup! 98 | export default function App() { 99 | return ( 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | ); 111 | } 112 | ``` 113 | 114 | All examples are included in the [Reflect Examples Expo App](https://github.com/sntx/react-native-reflect/blob/master/examples) 115 | 116 | Start Expo app and run it on a web browser and on a simulator. From the command line: "Press a for Android emulator, or i for iOS simulator, or w to run on web." 117 | 118 | ```bash 119 | # with yarn 120 | yarn start 121 | 122 | # with npm 123 | npm run start 124 | ``` 125 | 126 | # styled() 127 | 128 | `styled(Component, StyleSheet)` 129 | 130 | `styled(Component, MultipleStyleSheets)` 131 | 132 | `styled(Component, StyleSheets, Props)` 133 | 134 | `styled(Component, MultipleStyleSheets, Props)` 135 | 136 | Use **styled()** to create theme-based, responsive components. StyleSheets are React Native style sheets with some extra value types such as arrays. An array value is a shorthand for responsive values. Look at the examples below for more. 137 | 138 | ## Single Style 139 | 140 | `styled(Component, StyleSheet)` 141 | 142 | Calling styled() with a single style sheet creates a styled component with a single responsive style prop. 143 | 144 | ```javascript 145 | const Title = styled(Text, { 146 | textAlign: "center", 147 | fontSize: [3, 4], // 3, 4 are values from theme.fontSizes[3], 148 | // and theme.fontSizes[4] 149 | }); 150 | ``` 151 | 152 | --- 153 | 154 | The example below demonstrates how theme-based responsive style sheets work. Run the [Reflect Examples Expo App](https://github.com/sntx/react-native-reflect/blob/master/examples) and follow the comments in the code: 155 | 156 | ```javascript 157 | import * as React from "react"; 158 | import { View, Text } from "react-native"; 159 | import { styled, defaultTheme } from "react-native-reflect"; 160 | 161 | // (1) Look at defaultTheme output in the console. 162 | // 163 | // - defaultTheme.breakpoints determine the device's width ranges for 164 | // responsive behavior. breakpoints contain 4 165 | // values which will generate 5 breakpoints (xs, 166 | // sm, md, lg, xl) 167 | // 168 | // - defaultTheme.fontSizes are the list of font sizes our theme is using 169 | // 170 | // - defaultTheme.space are the theme's list of spacing values used for 171 | // margin, padding, etc. 172 | // 173 | console.log(defaultTheme); 174 | 175 | // (2) Margin themed values are taken from theme.space, for example: 176 | // 177 | // - marginLeft: 4 = defaultTheme.space[4] = 24 178 | // 179 | const Container = styled(View, { 180 | marginLeft: 4, 181 | marginTop: 4, 182 | }); 183 | 184 | // (3) Array values are responsive, resize browser window to test how values 185 | // change based on window width. 186 | // 187 | // - color and fontSize change on every breakpoint (xs, sm, md, lg, xl) 188 | // - marginTop changes at the middle of breakpoints (<= sm, >= md) 189 | // - fontWeight changes as follows: (<= sm, md, >= lg) 190 | // 191 | const Title = styled(Text, { 192 | color: ["primary", "secondary", "success", "error", "warning"], 193 | fontSize: [3, 4, 5, 6, 7], 194 | marginTop: [5, 6], 195 | fontWeight: ["normal", "medium", "bold"], 196 | textAlign: "center", 197 | }); 198 | 199 | const SingleStyle = ({ navigation }) => { 200 | return ( 201 | 202 | Single Style Example 203 | 204 | ); 205 | }; 206 | 207 | export default SingleStyle; 208 | ``` 209 | 210 | Run all examples by installing the [Reflect Examples Expo App](https://github.com/sntx/react-native-reflect/blob/master/examples) 211 | 212 | ## Multiple Styles 213 | 214 | `styled(Component, MultipleStyleSheets)` 215 | 216 | Calling styled() with multiple style sheet objects creates a styled component with multiple responsive style props. 217 | 218 | ```javascript 219 | import { Button } from "react-native-elements"; 220 | import { styled } from "react-native-reflect"; 221 | 222 | const MyButton = styled(Button, { 223 | containerStyle: { 224 | // 100% on smaller screens, 140 pixels on larger screens 225 | width: ["100%", 140], 226 | }, 227 | buttonStyle: { 228 | // theme.space[3] on smaller screens, 229 | // theme.space[4] on larger screens 230 | padding: [3, 4], 231 | backgroundColor: "primary", 232 | }, 233 | }); 234 | ``` 235 | 236 | --- 237 | 238 | The example below demonstrates how to define multiple theme-based, responsive style props. Run the [Reflect Examples Expo App](https://github.com/sntx/react-native-reflect/blob/master/examples) and follow the comments in the code: 239 | 240 | ```javascript 241 | import * as React from "react"; 242 | import { View } from "react-native"; 243 | import { styled } from "react-native-reflect"; 244 | import { Button } from "react-native-elements"; 245 | 246 | const Container = styled(View, { 247 | margin: 4, 248 | }); 249 | 250 | // Many UI libraries such as React Native Elements provide multiple style props 251 | // to style components. To style this kind of components, add each style prop 252 | // as a nested object as shown below: 253 | const MyButton = styled(Button, { 254 | containerStyle: { 255 | // 100% on smaller screens, 140 pixels on larger screens 256 | width: ["100%", 140], 257 | }, 258 | buttonStyle: { 259 | // theme.space[3] on smaller screens, 260 | // theme.space[4] on larger screens 261 | padding: [3, 4], 262 | backgroundColor: "primary", 263 | width: "100%", 264 | }, 265 | titleStyle: { 266 | fontWeight: "bold", 267 | }, 268 | }); 269 | 270 | const MultipleStyles = () => { 271 | return ( 272 | 273 | 274 | 275 | ); 276 | }; 277 | 278 | export default MultipleStyles; 279 | ``` 280 | 281 | Run all examples with the [Reflect Examples Expo App](https://github.com/sntx/react-native-reflect/blob/master/examples) 282 | 283 | ## Responsive Props 284 | 285 | `styled(Component, StyleSheets, Props)` 286 | 287 | The third optional argument of styled() is used to make any prop of a component responsive. 288 | 289 | ```javascript 290 | import { Button } from "react-native-elements"; 291 | import { styled } from "react-native-reflect"; 292 | 293 | const MyButton = styled( 294 | Button, 295 | {}, 296 | { 297 | // "solid" on smaller screens, "clear" on larger screens 298 | type: ["solid", "clear"], 299 | } 300 | ); 301 | ``` 302 | 303 | Run the example above and all other example with the [Reflect Examples Expo App](https://github.com/sntx/react-native-reflect/blob/master/examples) 304 | 305 | # useStyled() 306 | 307 | `useStyled({ style, styles, attrs })` 308 | 309 | Return value: 310 | 311 | `{ style, styles, attrs, breakpoint, theme }` 312 | 313 | Responsive styles and props can also be created by using the `usedStyled()` hook. This approach could be useful for adding responsive functionality to some props of an existing component without having to create components with `styled()`. It also allows the creation of more complex components, since the return values of useStyled() can be further processed inside the component. 314 | 315 | ## Single Style Hook 316 | 317 | `useStyled({ style })` 318 | 319 | In the example below, we're using a single style with responsive font sizes and dynamically getting the breakpoint index. Resize the browser's screen or test in different devices to see the changing breakpoint index the font size. 320 | 321 | ```javascript 322 | import { useStyled } from "react-native-reflect"; 323 | 324 | const MyComp = () => { 325 | const { style, breakpoint } = useStyled({ 326 | style: { 327 | // xs, sm -> theme.fontSizes[3] 328 | // md -> theme.fontSizes[4] 329 | // lg, xl -> theme.fontSizes[5] 330 | fontSize: [3, 4, 5], 331 | }, 332 | }); 333 | 334 | return {`Breakpoint Index: ${breakpoint}`}; 335 | }; 336 | ``` 337 | 338 | Run the example above and all other example with the [Reflect Examples Expo App](https://github.com/sntx/react-native-reflect/blob/master/examples) 339 | 340 | ## Multiple Styles Hook 341 | 342 | `useStyled({ styles })` 343 | 344 | The following example shows how to use useStyled() hook for creating multiple responsive style sheets. 345 | 346 | ```javascript 347 | import { Button } from "react-native-elements"; 348 | import { useStyled } from "react-native-reflect"; 349 | 350 | const MyButton = () => { 351 | const { styles, breakpoint } = useStyled({ 352 | styles: { 353 | containerStyle: { 354 | // 100% on smaller screens, 200 pixels on larger screens 355 | width: ["100%", 200], 356 | }, 357 | buttonStyle: { 358 | backgroundColor: "primary", 359 | }, 360 | }, 361 | }); 362 | 363 | return ( 364 |