├── example ├── .expo-shared │ ├── assets.json │ └── README.md ├── src │ ├── App.tsx │ ├── AppTheme.tsx │ └── Example.tsx ├── index.js ├── tsconfig.json ├── babel.config.js ├── app.json ├── package.json ├── webpack.config.js └── metro.config.js ├── .gitattributes ├── tsconfig.build.json ├── babel.config.js ├── .github └── screenshot.png ├── .yarnrc ├── .editorconfig ├── scripts └── bootstrap.js ├── tsconfig.json ├── .gitignore ├── LICENSE ├── src ├── __tests__ │ ├── createStyleSheet.test.ts │ └── makeStyles.test.tsx └── index.tsx ├── .circleci └── config.yml ├── package.json ├── README.md └── CONTRIBUTING.md /example/.expo-shared/assets.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": "./tsconfig", 4 | "exclude": ["example"] 5 | } 6 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /.github/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ef-eng/react-native-swag-styles/HEAD/.github/screenshot.png -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | 3 | yarn-path "scripts/bootstrap.js" 4 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Example } from './Example'; 3 | 4 | import { AppThemeProvider } from './AppTheme'; 5 | 6 | export const App = () => ( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import { registerRootComponent } from 'expo'; 2 | 3 | import { App } from './src/App'; 4 | 5 | // registerRootComponent calls AppRegistry.registerComponent('main', () => App); 6 | // It also ensures that whether you load the app in the Expo client or in a native build, 7 | // the environment is set up appropriately 8 | registerRootComponent(App); 9 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-native", 4 | "target": "esnext", 5 | "lib": [ 6 | "esnext" 7 | ], 8 | "allowJs": true, 9 | "skipLibCheck": true, 10 | "noEmit": true, 11 | "allowSyntheticDefaultImports": true, 12 | "resolveJsonModule": true, 13 | "esModuleInterop": true, 14 | "moduleResolution": "node" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/.expo-shared/README.md: -------------------------------------------------------------------------------- 1 | > Why do I have a folder named ".expo-shared" in my project? 2 | 3 | The ".expo-shared" folder is created when running commands that produce state that is intended to be shared with all developers on the project. For example, "npx expo-optimize". 4 | 5 | > What does the "assets.json" file contain? 6 | 7 | The "assets.json" file describes the assets that have been optimized through "expo-optimize" and do not need to be processed again. 8 | 9 | > Should I commit the ".expo-shared" folder? 10 | 11 | Yes, you should share the ".expo-shared" folder with your collaborators. 12 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = function (api) { 5 | api.cache(true); 6 | 7 | return { 8 | presets: ['babel-preset-expo'], 9 | plugins: [ 10 | [ 11 | 'module-resolver', 12 | { 13 | extensions: ['.tsx', '.ts', '.js', '.json'], 14 | alias: { 15 | // For development, we want to alias the library to the source 16 | [pak.name]: path.join(__dirname, '..', pak.source), 17 | }, 18 | }, 19 | ], 20 | ], 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-swag-styles-example", 3 | "displayName": "Example for react-native-swag-styles", 4 | "expo": { 5 | "name": "react-native-swag-styles-example", 6 | "slug": "react-native-swag-styles-example", 7 | "description": "Example app for react-native-swag-styles", 8 | "privacy": "public", 9 | "version": "1.0.0", 10 | "githubUrl": "https://github.com/ef-eng/react-native-swag-styles", 11 | "platforms": [ 12 | "ios", 13 | "android", 14 | "web" 15 | ], 16 | "userInterfaceStyle": "automatic", 17 | "ios": { 18 | "supportsTablet": true 19 | }, 20 | "assetBundlePatterns": [ 21 | "**/*" 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const child_process = require('child_process'); 3 | 4 | const root = path.resolve(__dirname, '..'); 5 | const args = process.argv.slice(2); 6 | const options = { 7 | cwd: process.cwd(), 8 | env: process.env, 9 | stdio: 'inherit', 10 | encoding: 'utf-8', 11 | }; 12 | 13 | let result; 14 | 15 | if (process.cwd() !== root || args.length) { 16 | // We're not in the root of the project, or additional arguments were passed 17 | // In this case, forward the command to `yarn` 18 | result = child_process.spawnSync('yarn', args, options); 19 | } else { 20 | // If `yarn` is run without arguments, perform bootstrap 21 | result = child_process.spawnSync('yarn', ['bootstrap'], options); 22 | } 23 | 24 | process.exitCode = result.status; 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "react-native-swag-styles": ["./src/index"] 6 | }, 7 | "allowUnreachableCode": false, 8 | "allowUnusedLabels": false, 9 | "esModuleInterop": true, 10 | "importsNotUsedAsValues": "error", 11 | "forceConsistentCasingInFileNames": true, 12 | "jsx": "react", 13 | "lib": ["esnext"], 14 | "module": "esnext", 15 | "moduleResolution": "node", 16 | "noFallthroughCasesInSwitch": true, 17 | "noImplicitReturns": true, 18 | "noImplicitUseStrict": false, 19 | "noStrictGenericChecks": false, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "resolveJsonModule": true, 23 | "skipLibCheck": true, 24 | "strict": true, 25 | "target": "esnext" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .idea 35 | .gradle 36 | local.properties 37 | android.iml 38 | 39 | # Cocoapods 40 | # 41 | example/ios/Pods 42 | 43 | # node.js 44 | # 45 | node_modules/ 46 | npm-debug.log 47 | yarn-debug.log 48 | yarn-error.log 49 | 50 | # BUCK 51 | buck-out/ 52 | \.buckd/ 53 | android/app/libs 54 | android/keystores/debug.keystore 55 | 56 | # Expo 57 | .expo/* 58 | 59 | # generated by bob 60 | lib/ 61 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-swag-styles-example", 3 | "description": "Example app for react-native-swag-styles", 4 | "version": "0.0.1", 5 | "private": true, 6 | "main": "index", 7 | "scripts": { 8 | "android": "expo start --android", 9 | "ios": "expo start --ios", 10 | "web": "expo start --web", 11 | "start": "expo start", 12 | "test": "jest" 13 | }, 14 | "dependencies": { 15 | "expo": "^40.0.0", 16 | "expo-splash-screen": "~0.8.1", 17 | "react": "16.13.1", 18 | "react-dom": "16.13.1", 19 | "react-native": "0.63.4", 20 | "react-native-unimodules": "~0.12.0", 21 | "react-native-web": "~0.14.9" 22 | }, 23 | "devDependencies": { 24 | "@babel/core": "~7.12.10", 25 | "@babel/runtime": "^7.9.6", 26 | "babel-plugin-module-resolver": "^4.0.0", 27 | "babel-preset-expo": "8.3.0", 28 | "expo-cli": "^4.0.13" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example/src/AppTheme.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useColorScheme } from 'react-native'; 3 | 4 | interface AppTheme { 5 | fgColor: string; 6 | bgColor: string; 7 | } 8 | 9 | const LIGHT_THEME: AppTheme = { 10 | fgColor: '#333', 11 | bgColor: '#FFF', 12 | }; 13 | 14 | const DARK_THEME: AppTheme = { 15 | fgColor: '#EEE', 16 | bgColor: '#222', 17 | }; 18 | 19 | const AppThemeContext = React.createContext(LIGHT_THEME); 20 | 21 | export const AppThemeProvider = ({ 22 | children, 23 | }: { 24 | children: React.ReactNode; 25 | }) => { 26 | const colorScheme = useColorScheme(); 27 | const theme = colorScheme === 'dark' ? DARK_THEME : LIGHT_THEME; 28 | return ( 29 | 30 | {children} 31 | 32 | ); 33 | }; 34 | 35 | export const useAppTheme = (): AppTheme => React.useContext(AppThemeContext); 36 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const createExpoWebpackConfigAsync = require('@expo/webpack-config'); 3 | const { resolver } = require('./metro.config'); 4 | 5 | const root = path.resolve(__dirname, '..'); 6 | const node_modules = path.join(__dirname, 'node_modules'); 7 | 8 | module.exports = async function (env, argv) { 9 | const config = await createExpoWebpackConfigAsync(env, argv); 10 | 11 | config.module.rules.push({ 12 | test: /\.(js|jsx|ts|tsx)$/, 13 | include: path.resolve(root, 'src'), 14 | use: 'babel-loader', 15 | }); 16 | 17 | // We need to make sure that only one version is loaded for peerDependencies 18 | // So we alias them to the versions in example's node_modules 19 | Object.assign(config.resolve.alias, { 20 | ...resolver.extraNodeModules, 21 | 'react-native-web': path.join(node_modules, 'react-native-web'), 22 | }); 23 | 24 | return config; 25 | }; 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 EF Education First 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 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const blacklist = require('metro-config/src/defaults/blacklist'); 3 | const escape = require('escape-string-regexp'); 4 | const pak = require('../package.json'); 5 | 6 | const root = path.resolve(__dirname, '..'); 7 | 8 | const modules = Object.keys({ 9 | ...pak.peerDependencies, 10 | }); 11 | 12 | module.exports = { 13 | projectRoot: __dirname, 14 | watchFolders: [root], 15 | 16 | // We need to make sure that only one version is loaded for peerDependencies 17 | // So we blacklist them at the root, and alias them to the versions in example's node_modules 18 | resolver: { 19 | blacklistRE: blacklist( 20 | modules.map( 21 | (m) => 22 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 23 | ) 24 | ), 25 | 26 | extraNodeModules: modules.reduce((acc, name) => { 27 | acc[name] = path.join(__dirname, 'node_modules', name); 28 | return acc; 29 | }, {}), 30 | }, 31 | 32 | transformer: { 33 | getTransformOptions: async () => ({ 34 | transform: { 35 | experimentalImportSupport: false, 36 | inlineRequires: true, 37 | }, 38 | }), 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /example/src/Example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Button, View, Text, useWindowDimensions } from 'react-native'; 3 | import { makeStyles } from 'react-native-swag-styles'; 4 | 5 | import { useAppTheme } from './AppTheme'; 6 | 7 | export const Example = () => { 8 | const [toggle, setToggle] = React.useState(false); 9 | const styles = useStyles(toggle); 10 | 11 | return ( 12 | 13 | 14 | Box 1 15 |