├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── .travis.yml ├── LICENSE ├── README.md ├── ava.config.js ├── emotion.d.ts ├── example ├── api │ └── index.js ├── components │ ├── City │ │ ├── components │ │ │ ├── Image │ │ │ │ ├── index.js │ │ │ │ └── styles.js │ │ │ └── Refresh │ │ │ │ ├── index.js │ │ │ │ └── styles.js │ │ └── index.js │ ├── Countries │ │ ├── index.js │ │ └── utils.js │ ├── Header │ │ ├── index.js │ │ └── styles.js │ ├── Layout │ │ ├── index.js │ │ └── styles.css │ └── Widget │ │ ├── index.js │ │ └── styles.css ├── pages │ ├── [name].js │ └── index.js ├── public │ └── images │ │ ├── amesbury.png │ │ ├── amsterdam.png │ │ ├── arrow.svg │ │ ├── athens.png │ │ ├── bali.png │ │ ├── barcelona.png │ │ ├── beijing.png │ │ ├── berlin.png │ │ ├── brussels.png │ │ ├── budapest.png │ │ ├── cairo.png │ │ ├── cancun.png │ │ ├── dubai.png │ │ ├── fuji.png │ │ ├── hanga-roa.png │ │ ├── istanbul.png │ │ ├── johannesburg.png │ │ ├── kuala-lumpur.png │ │ ├── kyoto.png │ │ ├── london.png │ │ ├── magelang.png │ │ ├── matsumoto.png │ │ ├── miyajima.png │ │ ├── moscow.png │ │ ├── munich.png │ │ ├── new-delhi.png │ │ ├── new-york.png │ │ ├── paris.png │ │ ├── patagonia.png │ │ ├── petra.png │ │ ├── phuket.png │ │ ├── pisa.png │ │ ├── refresh.svg │ │ ├── rio-de-janeiro.png │ │ ├── rome.png │ │ ├── saint-petersburg.png │ │ ├── san-francisco.png │ │ ├── seattle.png │ │ ├── seoul.png │ │ ├── siem-reap.png │ │ ├── singapore.png │ │ ├── sydney.png │ │ ├── venice.png │ │ └── washington-dc.png └── utils │ └── index.js ├── helpers ├── browser-env.js └── enzyme.js ├── index.d.ts ├── material-ui.d.ts ├── media ├── logo.png ├── logo.psd └── screenshot.png ├── next.config.js ├── package.json ├── rollup.config.js ├── src ├── core │ └── index.js ├── emotion-ssr │ └── index.js ├── emotion │ └── index.js ├── hooks │ └── index.js ├── index.js ├── index.test.js ├── material-ui │ └── index.js ├── styled-components │ └── index.js └── utils.js ├── styled-components.d.ts └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | [ 4 | "@babel/plugin-transform-runtime", 5 | { 6 | "regenerator": true, 7 | } 8 | ] 9 | ], 10 | "presets": ["@babel/preset-env", "@babel/preset-react"] 11 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .history 2 | dist/ 3 | example/js/build.js -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "prettier", 6 | "plugin:react/recommended", 7 | "prettier/standard" 8 | ], 9 | "plugins": ["react"], 10 | "rules": { 11 | "react/react-in-jsx-scope": "off", 12 | "react/display-name": "off" 13 | }, 14 | "settings": { 15 | "react": { 16 | "version": "detect" 17 | } 18 | }, 19 | "env": { 20 | "es2020": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # npm 2 | node_modules/ 3 | yarn-error.log 4 | 5 | # build 6 | dist/ 7 | 8 | # next 9 | example/.next/ 10 | example/react-shadow.js 11 | 12 | # coverage 13 | .nyc_output/ 14 | 15 | #now 16 | .now 17 | 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .history 2 | .travis.yml 3 | .now 4 | .nyc_output 5 | example/ 6 | helpers/ 7 | media/ 8 | src/ 9 | 10 | .prettierignore 11 | .babelrc 12 | .eslintignore 13 | .eslintrc 14 | ava.config.js 15 | next.config.js 16 | rollup.config.js 17 | yarn-error.log 18 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .history/ 2 | dist/ 3 | example/.next/ 4 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "printWidth": 80, 4 | "singleQuote": true, 5 | "trailingComma": "all" 6 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | script:language: node_js 4 | node_js: 16 5 | script: 6 | - yarn 7 | - yarn test 8 | - yarn build 9 | 10 | after_success: yarn coverage 11 | 12 | deploy: 13 | provider: heroku 14 | api_key: 15 | secure: YcqMNYNZ7y6uC5BJ5JBUQX783PxmvewXBP+5F2oQzCrdvvB3+EJR4+FvS+/+6v6klXenCbwkqx+XwExWLH4c/3JyZVRyITfIKRPOPr20QclYel0lmyK1jVzLjyYAiKpK5wP6wuFZrKYVCqHUllS1wYv0zwuskhKyaLkW2JAvZMo= 16 | app: react-shadow 17 | on: 18 | repo: Wildhoney/ReactShadow 19 | skip_cleanup: true 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adam Timberlake 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![ReactShadow](media/logo.png) 2 | 3 | > Utilise Shadow DOM in React with all the benefits of style encapsulation. 4 | 5 | ![Travis](http://img.shields.io/travis/Wildhoney/ReactShadow.svg?style=flat-square) 6 |   7 | ![Coveralls](https://img.shields.io/coveralls/Wildhoney/ReactShadow.svg?style=flat-square) 8 |   9 | ![npm](http://img.shields.io/npm/v/react-shadow.svg?style=flat-square) 10 |   11 | ![License MIT](https://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat-square) 12 | 13 | - **npm**: `npm i react-shadow` 14 | - **yarn**: `yarn add react-shadow` 15 | - **Heroku**: [https://react-shadow.herokuapp.com/](https://react-shadow.herokuapp.com) ([alternative](https://react-shadow-2.herokuapp.com)) 16 | 17 | ![Screenshot](media/screenshot.png) 18 | 19 | --- 20 | 21 | ## Getting Started 22 | 23 | Creating the [shadow root](https://www.w3.org/TR/shadow-dom/) is as simple as using the default export to construct a shadow root using the node name provided – for example `root.div` would create a `div` as the host element, and a shadow root as its immediate descendant — all of the child elements would then be descendants of the shadow boundary. 24 | 25 | ```jsx 26 | import root from 'react-shadow'; 27 | import styles from './styles.css'; 28 | 29 | export default function Quote() { 30 | return ( 31 | 32 | There is strong shadow where there is much light. 33 | ― Johann Wolfgang von Goethe. 34 | 35 | 36 | ); 37 | } 38 | ``` 39 | 40 | [![Edit react-shadow](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-shadow-by6bo?fontsize=14) 41 | 42 | Applying styles requires either applying the styles directly to the component as a string, or importing the CSS documents as a string as part of your build process. You can then append the `style` component directly to your shadow boundary via your component's tree. In [the example](https://github.com/Wildhoney/ReactShadow/tree/master/example) we use the following Webpack configuration to import CSS documents as strings. 43 | 44 | ```javascript 45 | { 46 | test: /\.css$/, 47 | loader: ['to-string-loader', 'css-loader'] 48 | } 49 | ``` 50 | 51 | Alternatively you can use [`styled-components`](https://www.styled-components.com/) normally, as each time a shadow boundary is created, a new `StyleSheetManager` context is also created which will encapsulate all related styles in their corresponding shadow root — to use this `import react-shadow/styled-components` instead of `import react-shadow`, likewise if you'd like to use [`emotion`](https://emotion.sh/docs/styled) you can `import react-shadow/emotion`. 52 | 53 | ```javascript 54 | import root from 'react-shadow/styled-components'; 55 | import root from 'react-shadow/emotion'; 56 | 57 | // ... 58 | 59 | ; 60 | ``` 61 | 62 | You may pass any props you like to the `root.*` component which will be applied directly to the host element, including event handlers and class names. There are also a handful of options that are used for the `attachShadow` invocation. 63 | 64 | ```javascript 65 | ShadowRoot.propTypes = { 66 | mode: PropTypes.oneOf(['open', 'closed']), 67 | delegatesFocus: PropTypes.bool, 68 | styleSheets: PropTypes.arrayOf( 69 | PropTypes.instanceOf(globalThis.CSSStyleSheet), 70 | ), 71 | children: PropTypes.node, 72 | }; 73 | 74 | ShadowRoot.defaultProps = { 75 | mode: 'open', 76 | delegatesFocus: false, 77 | styleSheets: [], 78 | children: null, 79 | }; 80 | ``` 81 | 82 | In cases where you need the underlying element and its associated shadow boundary, you can use a standard `ref` which will be invoked with the host element – from that you can use `shadowRoot` to access its shadow root if the `mode` has been set to the default `open` value. 83 | 84 | ```javascript 85 | const node = useRef(null); 86 | 87 | // ... 88 | 89 | ; 90 | ``` 91 | 92 | Recently and at long last there has been some movement in introducing a [declarative shadow DOM](https://tomalec.github.io/declarative-shadow-dom/) which `react-shadow` _tentatively_ supports – as it's experimental, open to sudden spec changes, and React finds it difficult to rehydrate – by using the `ssr` prop. 93 | 94 | ```javascript 95 | const node = useRef(null); 96 | 97 | // ... 98 | 99 | ; 100 | ``` 101 | -------------------------------------------------------------------------------- /ava.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | require: [ 3 | '@babel/register', 4 | '@babel/polyfill', 5 | './helpers/enzyme.js', 6 | './helpers/browser-env.js', 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /emotion.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-shadow/emotion' { 2 | import * as React from 'react'; 3 | 4 | interface IProps { 5 | mode?: 'open' | 'closed'; 6 | delegatesFocus?: boolean; 7 | styleSheets?: CSSStyleSheet[]; 8 | ssr?: boolean; 9 | children?: React.ReactNode; 10 | } 11 | 12 | type Root = { 13 | [name: string]: React.ComponentType< 14 | React.HTMLProps & IProps 15 | >; 16 | }; 17 | 18 | const ReactShadowRoot: Root; 19 | 20 | export default ReactShadowRoot; 21 | } 22 | -------------------------------------------------------------------------------- /example/api/index.js: -------------------------------------------------------------------------------- 1 | import { get } from 'axios'; 2 | import { camelizeKeys } from 'humps'; 3 | 4 | export const places = [ 5 | { city: 'Amesbury', country: 'UK' }, 6 | { city: 'Amsterdam', country: 'NL' }, 7 | { city: 'Athens', country: 'GR' }, 8 | { city: 'Bali', country: 'ID' }, 9 | { city: 'Barcelona', country: 'ES' }, 10 | { city: 'Berlin', country: 'DE' }, 11 | { city: 'Brussels', country: 'BE' }, 12 | { city: 'Budapest', country: 'HU' }, 13 | { city: 'Beijing', country: 'CN' }, 14 | { city: 'Seoul', country: 'KR' }, 15 | { city: 'Kyoto', country: 'JP' }, 16 | { city: 'Cairo', country: 'EG' }, 17 | { city: 'Cancun', country: 'MX' }, 18 | { city: 'Fuji', country: 'JP' }, 19 | { city: 'Dubai', country: 'AE' }, 20 | { city: 'Johannesburg', country: 'ZA' }, 21 | { city: 'Saint Petersburg', country: 'RU' }, 22 | { city: 'Singapore', country: 'SG' }, 23 | { city: 'Hanga Roa', country: 'CL' }, 24 | { city: 'Istanbul', country: 'TR' }, 25 | { city: 'Miyajima', country: 'JP' }, 26 | { city: 'Petra', country: 'JO' }, 27 | { city: 'London', country: 'UK' }, 28 | { city: 'Kuala Lumpur', country: 'MY' }, 29 | { city: 'Washington DC', country: 'US' }, 30 | { city: 'Matsumoto', country: 'JP' }, 31 | { city: 'Magelang', country: 'ID' }, 32 | { city: 'Moscow', country: 'RU' }, 33 | { city: 'Munich', country: 'DE' }, 34 | { city: 'New Delhi', country: 'IN' }, 35 | { city: 'New York', country: 'US' }, 36 | { city: 'Paris', country: 'FR' }, 37 | { city: 'Patagonia', country: 'AR' }, 38 | { city: 'Phuket', country: 'TH' }, 39 | { city: 'Pisa', country: 'IT' }, 40 | { city: 'Rio de Janeiro', country: 'BR' }, 41 | { city: 'Rome', country: 'IT' }, 42 | { city: 'San Francisco', country: 'US' }, 43 | { city: 'Seattle', country: 'US' }, 44 | { city: 'Siem Reap', country: 'KH' }, 45 | { city: 'Sydney', country: 'AU' }, 46 | { city: 'Venice', country: 'IT' }, 47 | ]; 48 | 49 | const apiKey = '07b72c930f0d226f7c6866cc753a678c'; 50 | 51 | export const fetch = async (country) => { 52 | const slug = country.replace(/-/g, '+'); 53 | const url = `https://api.openweathermap.org/data/2.5/weather?q=${slug}&appid=${apiKey}&units=metric`; 54 | const { data } = await get(url); 55 | return camelizeKeys(data); 56 | }; 57 | -------------------------------------------------------------------------------- /example/components/City/components/Image/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as e from './styles'; 3 | 4 | export default function Image(props) { 5 | return ; 6 | } 7 | -------------------------------------------------------------------------------- /example/components/City/components/Image/styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Image = styled.img` 4 | width: 30vmin; 5 | height: 30vmin; 6 | 7 | @media (max-width: 600px) { 8 | width: 25vmin; 9 | height: 25vmin; 10 | } 11 | 12 | @media (max-width: 285px) { 13 | width: 20vmin; 14 | height: 20vmin; 15 | } 16 | 17 | @media (max-width: 190px) { 18 | display: none; 19 | } 20 | `; 21 | -------------------------------------------------------------------------------- /example/components/City/components/Refresh/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Link from 'next/link'; 4 | import root from 'react-shadow/material-ui'; 5 | import * as utils from '../../../../utils'; 6 | import * as e from './styles'; 7 | 8 | export default function Refresh({ name }) { 9 | return ( 10 | 11 | 12 | Refresh 13 | 14 | 15 | ); 16 | } 17 | 18 | Refresh.propTypes = { name: PropTypes.string.isRequired }; 19 | -------------------------------------------------------------------------------- /example/components/City/components/Refresh/styles.js: -------------------------------------------------------------------------------- 1 | import { withStyles } from '@material-ui/core'; 2 | import IconButton_ from '@material-ui/core/IconButton'; 3 | 4 | export const IconButton = withStyles({ 5 | root: { 6 | border: 'none', 7 | width: '2vmax', 8 | height: '2vmax', 9 | textIndent: '-10000px', 10 | position: 'absolute', 11 | outline: 'none', 12 | cursor: 'pointer', 13 | opacity: 0.25, 14 | top: '20px', 15 | right: '20px', 16 | backgroundImage: "url('/images/refresh.svg')", 17 | backgroundSize: '2vmax', 18 | transition: 'opacity 0.25s, transform 0.25s', 19 | 20 | '&:hover': { 21 | opacity: 0.5, 22 | }, 23 | 24 | '&:focus': { 25 | transform: 'scale(1.5)', 26 | }, 27 | }, 28 | })(IconButton_); 29 | -------------------------------------------------------------------------------- /example/components/City/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import * as utils from '../../utils'; 4 | import Countries from '../Countries'; 5 | import Image from './components/Image'; 6 | import Refresh from './components/Refresh'; 7 | 8 | export default function City({ name, cities, weather }) { 9 | const { title, label, fahrenheit, timezone, date } = utils.formatWeather( 10 | name, 11 | weather, 12 | ); 13 | 14 | return ( 15 | 16 | 17 | 18 |
19 | {name} 20 | 21 |

22 | {title} at{' '} 23 | {timezone 24 | ? date.add(timezone, 'seconds').format('HH:mm:ss') 25 | : String.fromCharCode(8212)} 26 |

27 | 28 |

{label}

29 | 30 | 31 |
32 |
33 | ); 34 | } 35 | 36 | City.propTypes = { 37 | weather: PropTypes.object.isRequired, 38 | name: PropTypes.string.isRequired, 39 | cities: PropTypes.array.isRequired, 40 | }; 41 | -------------------------------------------------------------------------------- /example/components/Countries/index.js: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { useRouter } from 'next/router'; 4 | import Link from 'next/link'; 5 | import * as utils from '../../utils'; 6 | import Header from '../Header'; 7 | import { getCities } from './utils'; 8 | 9 | export default function Cities({ name, cities }) { 10 | const router = useRouter(); 11 | 12 | const handleChange = useCallback( 13 | (event) => { 14 | router.push('/[name]', `/${event.target.value}`); 15 | }, 16 | [cities], 17 | ); 18 | 19 | return ( 20 | <> 21 |
Weather for:
22 | 23 | 34 | 35 | 42 | 43 | ); 44 | } 45 | 46 | Cities.propTypes = { 47 | name: PropTypes.string.isRequired, 48 | cities: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, 49 | }; 50 | -------------------------------------------------------------------------------- /example/components/Countries/utils.js: -------------------------------------------------------------------------------- 1 | import * as utils from '../../utils'; 2 | 3 | export const getCities = (countries) => 4 | countries 5 | .sort((a, b) => a.localeCompare(b)) 6 | .map((name) => ({ 7 | name, 8 | slug: utils.toSlug(name), 9 | href: `/${utils.toSlug(name)}`, 10 | })); 11 | -------------------------------------------------------------------------------- /example/components/Header/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import root from 'react-shadow/emotion'; 4 | import * as e from './styles'; 5 | 6 | export default function Header({ children }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | 14 | Header.propTypes = { children: PropTypes.node.isRequired }; 15 | -------------------------------------------------------------------------------- /example/components/Header/styles.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | 3 | export const H3 = styled.h3` 4 | font-family: Lato, Arial, Tahoma, Helvetica, sans-serif; 5 | font-size: 2vmin; 6 | color: rgba(0, 0, 0, 0.5); 7 | `; 8 | -------------------------------------------------------------------------------- /example/components/Layout/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Widget from '../../components/Widget'; 3 | import styles from './styles.css'; 4 | 5 | export default function Layout(props) { 6 | return ( 7 |
8 | 9 | 10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /example/components/Layout/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | overflow: hidden; 5 | } 6 | 7 | body { 8 | background-color: rgba(0, 0, 0, 0.05); 9 | } 10 | 11 | #__next { 12 | width: 100%; 13 | height: 100%; 14 | } 15 | 16 | section.container { 17 | width: 100%; 18 | height: 100%; 19 | position: absolute; 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | 25 | section.weather { 26 | transition: all 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275); 27 | } 28 | -------------------------------------------------------------------------------- /example/components/Widget/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import root from 'react-shadow/styled-components'; 3 | import City from '../City'; 4 | import styles from './styles.css'; 5 | 6 | export default function Widget(props) { 7 | return ( 8 | 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /example/components/Widget/styles.css: -------------------------------------------------------------------------------- 1 | :host { 2 | all: initial; 3 | background-color: rgba(0, 0, 0, 0.05); 4 | border-radius: 5px; 5 | display: block; 6 | } 7 | 8 | section.weather { 9 | all: initial; 10 | background-color: rgba(0, 0, 0, 0.05); 11 | border-radius: 5px; 12 | display: block; 13 | } 14 | 15 | * { 16 | padding: 0; 17 | margin: 0; 18 | } 19 | 20 | span { 21 | justify-content: center; 22 | align-items: center; 23 | display: flex; 24 | flex-direction: column; 25 | position: relative; 26 | width: 75vmin; 27 | height: 75vmin; 28 | } 29 | 30 | main { 31 | text-align: center; 32 | } 33 | 34 | h1 { 35 | font-family: Times, 'Times New Roman', serif; 36 | font-weight: normal; 37 | font-size: 2vmin; 38 | margin-top: 2vmin; 39 | font-style: italic; 40 | } 41 | 42 | h2 { 43 | font-family: Lato, Arial, Tahoma, Helvetica, sans-serif; 44 | font-size: 10vmin; 45 | margin-top: 2vmin; 46 | text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.15); 47 | height: 12vmin; 48 | } 49 | 50 | ul { 51 | font-family: Lato, Arial, Tahoma, Helvetica, sans-serif; 52 | font-size: 1.25vmin; 53 | margin-top: 2vmin; 54 | display: grid; 55 | grid-template-columns: repeat(6, 1fr); 56 | grid-gap: 5px 10px; 57 | } 58 | 59 | @media (max-width: 600px) { 60 | ul { 61 | grid-template-columns: repeat(5, 1fr); 62 | } 63 | } 64 | 65 | ul li { 66 | display: inline-block; 67 | text-align: justify; 68 | border-left: 2px solid rgba(0, 0, 0, 0.15); 69 | padding-left: 5px; 70 | } 71 | 72 | ul li a { 73 | padding: 0 0.25vmin; 74 | color: black; 75 | transition: color 0.5s; 76 | cursor: pointer; 77 | } 78 | 79 | ul li.title { 80 | color: rgba(0, 0, 0, 0.35); 81 | padding-right: 2px; 82 | } 83 | 84 | ul li a:hover { 85 | color: black; 86 | } 87 | 88 | ul li a.active { 89 | color: deeppink; 90 | } 91 | 92 | select { 93 | margin-top: 10px; 94 | outline: none; 95 | display: none; 96 | -o-appearance: none; 97 | -moz-appearance: none; 98 | -webkit-appearance: none; 99 | appearance: none; 100 | padding: 5px 10px; 101 | background: white url('/public/images/arrow.svg') no-repeat right 10px 102 | center; 103 | background-size: 10px; 104 | border: 1px solid rgba(0, 0, 0, 0.25); 105 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 106 | border-radius: 3px; 107 | font-size: 16px; 108 | } 109 | 110 | @media (max-width: 450px) { 111 | ul { 112 | display: none; 113 | } 114 | 115 | select { 116 | display: initial; 117 | } 118 | } 119 | 120 | @media (max-width: 190px) { 121 | button { 122 | display: none; 123 | } 124 | 125 | select { 126 | padding: 5px 5px; 127 | background-size: 8px; 128 | font-size: 11px; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /example/pages/[name].js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Layout from '../components/Layout'; 3 | import * as api from '../api'; 4 | import * as utils from '../utils'; 5 | 6 | export default function City(props) { 7 | return ; 8 | } 9 | 10 | City.getInitialProps = async ({ query }) => { 11 | const place = api.places.find( 12 | ({ city }) => utils.toSlug(city) === query.name, 13 | ); 14 | 15 | return place 16 | ? { 17 | name: place.city, 18 | cities: api.places.map(({ city }) => city), 19 | weather: await api.fetch(`${place.city}, ${place.country}`), 20 | } 21 | : { name: query.name }; 22 | }; 23 | -------------------------------------------------------------------------------- /example/pages/index.js: -------------------------------------------------------------------------------- 1 | import * as api from '../api'; 2 | import * as utils from '../utils'; 3 | 4 | export default function Index() { 5 | return null; 6 | } 7 | 8 | Index.getInitialProps = async (context) => { 9 | const place = utils.pickPlace(api.places); 10 | utils.redirectPath(utils.toSlug(place.city), context); 11 | }; 12 | -------------------------------------------------------------------------------- /example/public/images/amesbury.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/amesbury.png -------------------------------------------------------------------------------- /example/public/images/amsterdam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/amsterdam.png -------------------------------------------------------------------------------- /example/public/images/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /example/public/images/athens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/athens.png -------------------------------------------------------------------------------- /example/public/images/bali.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/bali.png -------------------------------------------------------------------------------- /example/public/images/barcelona.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/barcelona.png -------------------------------------------------------------------------------- /example/public/images/beijing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/beijing.png -------------------------------------------------------------------------------- /example/public/images/berlin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/berlin.png -------------------------------------------------------------------------------- /example/public/images/brussels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/brussels.png -------------------------------------------------------------------------------- /example/public/images/budapest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/budapest.png -------------------------------------------------------------------------------- /example/public/images/cairo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/cairo.png -------------------------------------------------------------------------------- /example/public/images/cancun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/cancun.png -------------------------------------------------------------------------------- /example/public/images/dubai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/dubai.png -------------------------------------------------------------------------------- /example/public/images/fuji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/fuji.png -------------------------------------------------------------------------------- /example/public/images/hanga-roa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/hanga-roa.png -------------------------------------------------------------------------------- /example/public/images/istanbul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/istanbul.png -------------------------------------------------------------------------------- /example/public/images/johannesburg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/johannesburg.png -------------------------------------------------------------------------------- /example/public/images/kuala-lumpur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/kuala-lumpur.png -------------------------------------------------------------------------------- /example/public/images/kyoto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/kyoto.png -------------------------------------------------------------------------------- /example/public/images/london.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/london.png -------------------------------------------------------------------------------- /example/public/images/magelang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/magelang.png -------------------------------------------------------------------------------- /example/public/images/matsumoto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/matsumoto.png -------------------------------------------------------------------------------- /example/public/images/miyajima.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/miyajima.png -------------------------------------------------------------------------------- /example/public/images/moscow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/moscow.png -------------------------------------------------------------------------------- /example/public/images/munich.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/munich.png -------------------------------------------------------------------------------- /example/public/images/new-delhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/new-delhi.png -------------------------------------------------------------------------------- /example/public/images/new-york.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/new-york.png -------------------------------------------------------------------------------- /example/public/images/paris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/paris.png -------------------------------------------------------------------------------- /example/public/images/patagonia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/patagonia.png -------------------------------------------------------------------------------- /example/public/images/petra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/petra.png -------------------------------------------------------------------------------- /example/public/images/phuket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/phuket.png -------------------------------------------------------------------------------- /example/public/images/pisa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/pisa.png -------------------------------------------------------------------------------- /example/public/images/refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /example/public/images/rio-de-janeiro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/rio-de-janeiro.png -------------------------------------------------------------------------------- /example/public/images/rome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/rome.png -------------------------------------------------------------------------------- /example/public/images/saint-petersburg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/saint-petersburg.png -------------------------------------------------------------------------------- /example/public/images/san-francisco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/san-francisco.png -------------------------------------------------------------------------------- /example/public/images/seattle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/seattle.png -------------------------------------------------------------------------------- /example/public/images/seoul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/seoul.png -------------------------------------------------------------------------------- /example/public/images/siem-reap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/siem-reap.png -------------------------------------------------------------------------------- /example/public/images/singapore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/singapore.png -------------------------------------------------------------------------------- /example/public/images/sydney.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/sydney.png -------------------------------------------------------------------------------- /example/public/images/venice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/venice.png -------------------------------------------------------------------------------- /example/public/images/washington-dc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/example/public/images/washington-dc.png -------------------------------------------------------------------------------- /example/utils/index.js: -------------------------------------------------------------------------------- 1 | import capitalise from 'capitalize'; 2 | import moment from 'moment'; 3 | import router from 'next/router'; 4 | 5 | export const toSlug = (name) => { 6 | return name.replace(/ /g, '-'); 7 | }; 8 | 9 | export const fromSlug = (name) => { 10 | return name.replace(/-/g, ' '); 11 | }; 12 | 13 | export const getFilename = (country) => { 14 | return `/images/${toSlug(country).toLowerCase()}.png`; 15 | }; 16 | 17 | export const pickPlace = (places) => 18 | places[Math.floor(Math.random() * places.length)]; 19 | 20 | export const formatWeather = (name, model) => { 21 | const tempature = model ? Math.round(model.main.temp) : null; 22 | 23 | return { 24 | ...model, 25 | country: fromSlug(name), 26 | title: `${capitalise.words(model.weather[0].description)} in ${fromSlug( 27 | name, 28 | )}`, 29 | label: `${tempature}${String.fromCharCode(8451)}`, 30 | fahrenheit: `${(tempature * 9) / 5 + 32}${String.fromCharCode(8457)}`, 31 | date: model ? moment(model.date).utc() : null, 32 | }; 33 | }; 34 | 35 | export function redirectPath(path, context = null) { 36 | if (context && context.res) { 37 | context.res.writeHead(302, { 38 | Location: path, 39 | }); 40 | context.res.end(); 41 | } else router.push(path); 42 | } 43 | -------------------------------------------------------------------------------- /helpers/browser-env.js: -------------------------------------------------------------------------------- 1 | import browserEnv from 'browser-env'; 2 | 3 | browserEnv(); 4 | -------------------------------------------------------------------------------- /helpers/enzyme.js: -------------------------------------------------------------------------------- 1 | import Enzyme from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | 4 | Enzyme.configure({ adapter: new Adapter() }); 5 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-shadow' { 2 | import * as React from 'react'; 3 | 4 | interface IProps { 5 | mode?: 'open' | 'closed'; 6 | delegatesFocus?: boolean; 7 | styleSheets?: CSSStyleSheet[]; 8 | ssr?: boolean; 9 | children?: React.ReactNode; 10 | } 11 | 12 | type Root = { 13 | [name: string]: React.ComponentType< 14 | React.HTMLProps & IProps 15 | >; 16 | }; 17 | 18 | type CreateProxyFn = ( 19 | target: unknown, 20 | id: string, 21 | render: ({ 22 | children, 23 | }: { 24 | children: React.ReactNode; 25 | ssr: boolean; 26 | root: ShadowRoot; 27 | }) => React.ReactNode, 28 | ) => Root; 29 | 30 | const createProxy: CreateProxyFn; 31 | const ReactShadowRoot: Root; 32 | const useShadowRoot: () => ShadowRoot; 33 | 34 | export default ReactShadowRoot; 35 | 36 | export { createProxy, useShadowRoot }; 37 | export type { Root }; 38 | } 39 | -------------------------------------------------------------------------------- /material-ui.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-shadow/material-ui' { 2 | import * as React from 'react'; 3 | 4 | interface IProps { 5 | mode?: 'open' | 'closed'; 6 | delegatesFocus?: boolean; 7 | styleSheets?: CSSStyleSheet[]; 8 | ssr?: boolean; 9 | children?: React.ReactNode; 10 | } 11 | 12 | type Root = { 13 | [name: string]: React.ComponentType< 14 | React.HTMLProps & IProps 15 | >; 16 | }; 17 | 18 | const ReactShadowRoot: Root; 19 | 20 | export default ReactShadowRoot; 21 | } 22 | -------------------------------------------------------------------------------- /media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/media/logo.png -------------------------------------------------------------------------------- /media/logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/media/logo.psd -------------------------------------------------------------------------------- /media/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wildhoney/ReactShadow/6b028c0f9a31562422c5d370d067b468db4b9772/media/screenshot.png -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const aliases = [{ module: 'react-shadow', path: 'src/' }]; 4 | 5 | module.exports = { 6 | target: 'serverless', 7 | webpack: (config, options) => { 8 | config.module.rules.push({ 9 | test: /\.svg$/, 10 | loader: 'svg-inline-loader', 11 | }); 12 | 13 | config.module.rules.push({ 14 | test: /\.css$/, 15 | loader: ['css-loader'], 16 | }); 17 | 18 | config.module.rules.push({ 19 | test: /\.(js|jsx)$/, 20 | include: [path.resolve(__dirname, './src')], 21 | use: [options.defaultLoaders.babel], 22 | }); 23 | 24 | aliases.forEach((alias) => { 25 | config.resolve.alias[alias.module] = path.join( 26 | __dirname, 27 | alias.path, 28 | ); 29 | }); 30 | 31 | return config; 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-shadow", 3 | "version": "20.6.0", 4 | "description": "Utilise Shadow DOM in React with all the benefits of style encapsulation.", 5 | "main": "react-shadow.js", 6 | "module": "react-shadow.esm.js", 7 | "types": "index.d.ts", 8 | "repository": "git@github.com:Wildhoney/ReactShadow.git", 9 | "author": "Adam Timberlake ", 10 | "contributors": [ 11 | "Chris Trevino " 12 | ], 13 | "license": "MIT", 14 | "scripts": { 15 | "build": "yarn run build-core && yarn run build-emotion && yarn run build-styled-components && yarn run build-material-ui && next build ./example", 16 | "build-core": "rollup -c --environment input:index,output:react-shadow", 17 | "build-emotion": "rollup -c --environment input:emotion/index,output:emotion && yarn build-emotion-ssr", 18 | "build-emotion-ssr": "rollup -c --environment input:emotion-ssr/index,output:emotion-ssr", 19 | "build-styled-components": "rollup -c --environment input:styled-components/index,output:styled-components", 20 | "build-material-ui": "rollup -c --environment input:material-ui/index,output:material-ui", 21 | "test": "yarn spec && yarn lint", 22 | "spec": "ava --verbose", 23 | "lint": "eslint '**/**.js'", 24 | "coverage": "nyc ava && nyc report --reporter=text-lcov | coveralls", 25 | "format": "NODE_ENV=production prettier --write '**/**.{js,html,mjs,css,ts}'", 26 | "start": "next ./example -p ${PORT:-3000}", 27 | "deploy": "now", 28 | "prepublishOnly": "mv dist/* ./", 29 | "postpublish": "mv {react-shadow,emotion,emotion-ssr,styled-components,material-ui}{.js,.js.map,.esm.js,.esm.js.map} ./dist" 30 | }, 31 | "husky": { 32 | "hooks": { 33 | "pre-commit": "yarn format && yarn test", 34 | "pre-push": "yarn format && yarn test" 35 | } 36 | }, 37 | "peerDependencies": { 38 | "prop-types": "^15.0.0", 39 | "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", 40 | "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" 41 | }, 42 | "dependencies": { 43 | "humps": "^2.0.1" 44 | }, 45 | "devDependencies": { 46 | "@babel/core": "^7.11.1", 47 | "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", 48 | "@babel/plugin-transform-runtime": "^7.11.0", 49 | "@babel/polyfill": "^7.10.4", 50 | "@babel/preset-env": "^7.11.0", 51 | "@babel/preset-react": "^7.10.4", 52 | "@babel/register": "^7.10.5", 53 | "@babel/runtime": "^7.11.2", 54 | "@emotion/cache": "^11.0.0", 55 | "@emotion/css": "^11.0.0", 56 | "@emotion/react": "^11.0.0", 57 | "@emotion/server": "^11.0.0", 58 | "@emotion/styled": "^11.0.0", 59 | "@material-ui/core": "^4.11.0", 60 | "ava": "^3.11.1", 61 | "axios": "^0.21.1", 62 | "babel-eslint": "^10.1.0", 63 | "browser-env": "^3.3.0", 64 | "capitalize": "^2.0.3", 65 | "concurrently": "^5.3.0", 66 | "core-js": "^3.6.5", 67 | "coveralls": "^3.1.0", 68 | "css-loader": "^4.2.1", 69 | "delay": "^4.4.0", 70 | "emotion": "^10.0.27", 71 | "emotion-server": "^10.0.27", 72 | "enzyme": "^3.11.0", 73 | "enzyme-adapter-react-16": "^1.15.3", 74 | "eslint": "^7.7.0", 75 | "eslint-config-prettier": "^6.11.0", 76 | "eslint-config-standard": "^14.1.1", 77 | "eslint-plugin-import": "^2.22.0", 78 | "eslint-plugin-node": "^11.1.0", 79 | "eslint-plugin-promise": "^4.2.1", 80 | "eslint-plugin-react": "^7.20.6", 81 | "eslint-plugin-standard": "^4.0.1", 82 | "husky": "^4.3.0", 83 | "moment": "^2.27.0", 84 | "next": "^9.5.2", 85 | "nyc": "^15.1.0", 86 | "prettier": "^2.0.5", 87 | "prop-types": "^15.7.2", 88 | "ramda": "^0.27.1", 89 | "react": "^16.13.1", 90 | "react-dom": "^16.13.1", 91 | "rollup": "^2.26.0", 92 | "rollup-plugin-babel": "^4.4.0", 93 | "rollup-plugin-commonjs": "^10.1.0", 94 | "rollup-plugin-node-resolve": "^5.2.0", 95 | "rollup-plugin-terser": "^7.0.0", 96 | "sinon": "^9.0.3", 97 | "styled-components": "^5.1.1", 98 | "svg-inline-loader": "^0.8.2" 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve'; 2 | import commonjs from 'rollup-plugin-commonjs'; 3 | import babel from 'rollup-plugin-babel'; 4 | import { terser } from 'rollup-plugin-terser'; 5 | 6 | module.exports = { 7 | input: `src/${process.env.input}.js`, 8 | external: [ 9 | 'react', 10 | 'react-dom', 11 | 'react-dom/server', 12 | 'prop-types', 13 | 'styled-components', 14 | '@emotion/react', 15 | '@emotion/cache', 16 | '@emotion/server', 17 | '@material-ui/styles', 18 | 'jss', 19 | ], 20 | output: [ 21 | { 22 | file: `dist/${process.env.output}.esm.js`, 23 | format: 'esm', 24 | sourcemap: true, 25 | exports: 'named', 26 | }, 27 | { 28 | file: `dist/${process.env.output}.js`, 29 | format: 'cjs', 30 | sourcemap: true, 31 | exports: 'named', 32 | }, 33 | ], 34 | plugins: [ 35 | resolve(), 36 | babel({ 37 | exclude: 'node_modules/**', 38 | runtimeHelpers: true, 39 | }), 40 | commonjs({ 41 | namedExports: { 42 | include: 'node_modules/**', 43 | 'node_modules/react/index.js': [ 44 | 'cloneElement', 45 | 'createContext', 46 | 'Component', 47 | 'createElement', 48 | 'useRef', 49 | 'useState', 50 | 'useCallback', 51 | 'useContext', 52 | 'useEffect', 53 | ], 54 | 'node_modules/react-is/index.js': [ 55 | 'isElement', 56 | 'isValidElementType', 57 | 'ForwardRef', 58 | 'Memo', 59 | ], 60 | 'node_modules/styled-components/dist/styled-components.esm.js': [ 61 | 'createContext', 62 | ], 63 | 'node_modules/humps/humps.js': ['decamelize'], 64 | 'node_modules/react-dom/server.js': ['renderToString'], 65 | }, 66 | }), 67 | terser(), 68 | ], 69 | }; 70 | -------------------------------------------------------------------------------- /src/core/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useLayoutEffect, forwardRef } from 'react'; 2 | import { useEnsuredForwardedRef } from '../hooks'; 3 | import { createPortal } from 'react-dom'; 4 | import { renderToString } from 'react-dom/server'; 5 | import PropTypes from 'prop-types'; 6 | import * as utils from '../utils'; 7 | 8 | function Template({ children = '', ...attrs }) { 9 | if (typeof children !== 'string') { 10 | children = renderToString(children); 11 | } 12 | 13 | return ( 14 |