Skip to content

Commit 3282c29

Browse files
committed
Initial commit
0 parents  commit 3282c29

12 files changed

+1072
-0
lines changed

.babelrc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"presets": [
3+
["env", { "modules": false }],
4+
"react"
5+
],
6+
"plugins": [
7+
"transform-class-properties"
8+
]
9+
}

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lib
2+
node_modules

LICENSE.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018-present Giuseppe Gurgone
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.

README.md

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# 📚 React Layers Manager
2+
3+
Manage layers and `z-index` in React applications effectively.
4+
5+
No more
6+
7+
```css
8+
z-index: 10000;
9+
z-index: 10001;
10+
z-index: 999;
11+
z-index: 99999;
12+
```
13+
14+
That's right 👦
15+
16+
## 👩‍🏫 The issue with z-index: 9999
17+
18+
Some [CSS properties create stacking contextes](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context).
19+
20+
Within a stacking context, child elements are stacked according to [some rules](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/Adding_z-index) and in general one on top of each other based on their z-index value.
21+
22+
The problem though is that elements cannot escape their parent stackig context.
23+
24+
What this means in practice is that an element with `z-index: 9999` inside of a stacking context with `z-index: 1` will always be below a stacking context sibling of the latter with `z-index: 2` for example:
25+
26+
```html
27+
<div style="position: absolute; z-index: 2; top: 0;">
28+
I am on top and I don't care about your 9999
29+
</div>
30+
31+
<div style="position: absolute; z-index: 1; top: 0;">
32+
<div style="position: absolute; z-index: 9999;">
33+
I want to be in front of you
34+
</div>
35+
</div>
36+
```
37+
38+
`react-layers-manager` solves this issue.
39+
40+
## 💪 How it works
41+
42+
`react-layers-manager` leverages the power of the new React Context API introduced in React 16.3 and Portals to render your layers as siblings of your application root.
43+
44+
This way layers are guaranteed to always be on top of your application!
45+
46+
## Installation
47+
48+
```
49+
npm i react-layers-manager
50+
```
51+
52+
## Usage
53+
54+
`react-layers-manager` exposes two components:
55+
56+
* `LayersManager` that is just a wrapper for your app
57+
* `Layer` to be used contextually in your components when you want to render something in a layer
58+
59+
```jsx
60+
import React from 'react'
61+
import ReactDOM from 'react-dom'
62+
import { LayersManager, Layer } from 'react-layers-manager'
63+
64+
const SampleModal = () => (
65+
<Layer>
66+
<Modal>We have updated our privacy policy :trollface:</Modal>
67+
</Layer>
68+
)
69+
70+
const App = () => (
71+
<h1>Hello folks</h1>
72+
<SampleModal />
73+
<SampleModal />
74+
)
75+
76+
ReactDOM.render(
77+
<LayersManager>
78+
<App />
79+
</LayersManager>,
80+
document.getElementById('root')
81+
)
82+
```
83+
84+
### Layer
85+
86+
The `Layer` component accepts a few optional `props`:
87+
88+
```js
89+
type Props = {
90+
// Renders a layer at a specific index.
91+
// By default layers are appended to the layers manager container.
92+
index?: number,
93+
94+
// Invoked when the layer mounts with the app element.
95+
// This is useful to set aria-hidden="true" for example when showing a modal
96+
// or disable scrolling.
97+
onMount?: (root: HTMLElement) => void,
98+
99+
// Invoked when the layer unmounts with the app element.
100+
onUnmount?: (root: HTMLElement) => void,
101+
}
102+
```

index.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
exports = module.exports = require('./lib')
2+
exports.default = exports
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
})

package.json

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "react-layers-manager",
3+
"version": "0.1.0",
4+
"main": "./index.js",
5+
"files": [
6+
"index.js",
7+
"lib",
8+
"README.md",
9+
"LICENSE.md"
10+
],
11+
"description": "Manage layers and z-index in React applications effectively",
12+
"keywords": [
13+
"react",
14+
"z-index",
15+
"zIndex",
16+
"layers",
17+
"modal",
18+
"tooltip"
19+
],
20+
"author": "Giuseppe Gurgone",
21+
"license": "MIT",
22+
"devDependencies": {
23+
"babel-core": "^6.26.3",
24+
"babel-plugin-transform-class-properties": "^6.24.1",
25+
"babel-preset-env": "^1.7.0",
26+
"babel-preset-react": "^6.24.1",
27+
"rollup": "^0.60.1",
28+
"rollup-plugin-babel": "^3.0.4"
29+
},
30+
"peerDependencies": {
31+
"react": ">= 16.3.x"
32+
},
33+
"scripts": {
34+
"prepublish": "rollup -c"
35+
}
36+
}

rollup.config.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import babel from 'rollup-plugin-babel'
2+
3+
export default {
4+
input: './src/index.js',
5+
output: {
6+
file: './lib/index.js',
7+
format: 'cjs'
8+
},
9+
plugins: [
10+
babel({
11+
exclude: 'node_modules/**'
12+
})
13+
],
14+
external: ['react', 'react-dom']
15+
};

src/Layer.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from "react"
2+
import { createPortal } from "react-dom"
3+
import { Consumer } from "./context"
4+
5+
const Layer = props => (
6+
<Consumer>
7+
{({ host, root }) =>
8+
host && root && <LayerImpl {...props} host={host} root={root} />
9+
}
10+
</Consumer>
11+
)
12+
export default Layer
13+
14+
class LayerImpl extends React.Component {
15+
state = { container: null }
16+
componentDidMount() {
17+
const { host, index, onMount, root } = this.props
18+
const container = host.ownerDocument.createElement("div")
19+
const sibling = typeof index === "number" && host.children[index]
20+
sibling
21+
? host.insertBefore(container, sibling)
22+
: host.appendChild(container)
23+
this.setState({ container }, () => {
24+
root && onMount && onMount(root)
25+
})
26+
}
27+
componentWillUnmount() {
28+
const { container } = this.state
29+
const { root, host, onUnmount } = this.props
30+
root && onUnmount && onUnmount(root)
31+
host && host.removeChild(container)
32+
}
33+
render() {
34+
const { container } = this.state
35+
return container && createPortal(this.props.children, container)
36+
}
37+
}

src/LayersManager.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from "react"
2+
import { Provider } from "./context"
3+
4+
export default class LayersManager extends React.Component {
5+
root = React.createRef()
6+
host = React.createRef()
7+
componentDidMount() {
8+
this.forceUpdate()
9+
}
10+
render() {
11+
return (
12+
<Provider value={{ root: this.root.current, host: this.host.current }}>
13+
<div ref={this.root} style={{ isolation: "isolate" }}>
14+
{this.props.children}
15+
</div>
16+
<div ref={this.host} style={{ isolation: "isolate" }} />
17+
</Provider>
18+
)
19+
}
20+
}

src/context.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { createContext } from "react"
2+
export const { Provider, Consumer } = createContext()

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as LayersManager } from "./LayersManager"
2+
export { default as Layer } from "./Layer"

0 commit comments

Comments
 (0)