├── .babelrc
├── .editorconfig
├── .eslintrc
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── example
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── index.html
│ └── manifest.json
└── src
│ ├── App.js
│ ├── index.css
│ ├── index.js
│ └── sidebar.css
├── package-lock.json
├── package.json
├── rollup.config.js
└── src
├── .eslintrc
├── MenuButton.js
├── Sidebar.js
├── Tab.js
├── __snapshots__
└── test.js.snap
├── index.js
├── sidebar.css
└── test.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false
5 | }],
6 | "stage-0",
7 | "react"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "es6": true
9 | },
10 | "plugins": [
11 | "react"
12 | ],
13 | "parserOptions": {
14 | "sourceType": "module"
15 | },
16 | "rules": {
17 | // don't force es6 functions to include space before paren
18 | "space-before-function-paren": 0,
19 |
20 | // allow specifying true explicitly for boolean props
21 | "react/jsx-boolean-value": 0
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # See https://help.github.com/ignore-files/ for more about ignoring files.
3 |
4 | # dependencies
5 | node_modules
6 |
7 | # builds
8 | build
9 | dist
10 |
11 | # misc
12 | .DS_Store
13 | .env
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 9
4 | - 8
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Eyüp Ferhat GÜDÜCÜ
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 | # react-leaflet-sidetabs [(DEMO)](https://eferhatg.com/react-leaflet-sidetabs/)
2 |
3 | > A [react-leaflet](https://github.com/PaulLeCam/react-leaflet) plugin of [sidebar-v2](https://github.com/Turbo87/sidebar-v2)
4 |
5 | [](https://www.npmjs.com/package/react-leaflet-v2sidebar-v2) [](https://standardjs.com)
6 |
7 | inspired by [@condense/react-leaflet-sidebarv2](https://github.com/condense/react-leaflet-sidebarv2)
8 |
9 |
10 |
11 | ## Install
12 |
13 | ```bash
14 | npm install --save react-leaflet-sidetabs
15 | ```
16 |
17 | ## Usage
18 |
19 | Sidebar should be sibling of react-leaflet Map component.
20 |
21 | [react-icons](https://github.com/react-icons/react-icons) is used at the example below. Any other icon library can also be used by giving icon names as string to *icon* and *closeIcon* props.
22 |
23 | *onClose* and *onOpen* callbacks should be given as props to change state *collapsed* and *selected* especially.
24 |
25 | Sidebar is alignable to left and right with *position* prop. Also Tabs are alignable to bottom and top with *anchor* prop.
26 |
27 |
28 | ```jsx
29 | import React, { Component } from 'react'
30 | import { Map, TileLayer } from 'react-leaflet';
31 | import 'leaflet/dist/leaflet.css';
32 | import { Sidebar, Tab } from 'react-leaflet-sidetabs'
33 | import { FiHome, FiChevronRight, FiSearch, FiSettings } from "react-icons/fi";
34 |
35 | export default class App extends Component {
36 | constructor(props) {
37 | super(props);
38 | this.state = {
39 | collapsed: true,
40 | selected: 'home',
41 | };
42 | }
43 |
44 | onClose() {
45 | this.setState({collapsed: true});
46 | }
47 | onOpen(id) {
48 | this.setState({
49 | collapsed: false,
50 | selected: id,
51 | })
52 | }
53 |
54 | render () {
55 | return (
56 |
57 | }
62 | selected={this.state.selected}
63 | onOpen={this.onOpen.bind(this)}
64 | onClose={this.onClose.bind(this)}
65 | >
66 |
}>
67 |
No place like home!
68 |
69 |
}>
70 |
The noblest search is the search for excellence!
71 |
72 |
}>
73 |
We don't want privacy so much as privacy settings!
74 |
75 |
76 |
77 |
83 |
84 | )
85 | }
86 | }
87 | ```
88 |
89 | ## License
90 |
91 | MIT © [eferhatg](https://github.com/eferhatg)
92 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | Example Project
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-leaflet-sidetabs-example",
3 | "homepage": "https://eferhatg.github.io/react-leaflet-sidetabs",
4 | "version": "0.0.0",
5 | "license": "MIT",
6 | "private": true,
7 | "dependencies": {
8 | "leaflet": "^1.3.4",
9 | "prop-types": "^15.6.2",
10 | "react": "^16.4.1",
11 | "react-dom": "^16.4.1",
12 | "react-icons": "^3.1.0",
13 | "react-leaflet": "^2.0.1",
14 | "react-leaflet-sidetabs": "file:..",
15 | "react-scripts": "^1.1.4"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test --env=jsdom",
21 | "eject": "react-scripts eject"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | react-leaflet-sidetabs
11 |
12 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/example/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "react-leaflet-sidetabs",
3 | "name": "react-leaflet-sidetabs",
4 | "start_url": "./index.html",
5 | "display": "standalone",
6 | "theme_color": "#000000",
7 | "background_color": "#ffffff"
8 | }
9 |
--------------------------------------------------------------------------------
/example/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Map, TileLayer } from 'react-leaflet';
3 | import 'leaflet/dist/leaflet.css';
4 | import { Sidebar, Tab } from 'react-leaflet-sidetabs'
5 | import { FiHome, FiChevronRight, FiSearch, FiSettings } from "react-icons/fi";
6 |
7 | export default class App extends Component {
8 | constructor(props) {
9 | super(props);
10 | this.state = {
11 | collapsed: true,
12 | selected: 'home',
13 | };
14 | }
15 |
16 | onClose() {
17 | this.setState({collapsed: true});
18 | }
19 | onOpen(id) {
20 | this.setState({
21 | collapsed: false,
22 | selected: id,
23 | })
24 | }
25 |
26 | render () {
27 | return (
28 |
29 |
35 |
36 | }
40 | selected={this.state.selected}
41 | onOpen={this.onOpen.bind(this)}
42 | onClose={this.onClose.bind(this)}
43 | >
44 |
}>
45 |
No place like home!
46 |
47 |
}>
48 |
The noblest search is the search for excellence!
49 |
50 |
}>
51 |
We don't want privacy so much as privacy settings!
52 |
53 |
54 |
55 | )
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/example/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 |
8 | .mapStyle{
9 | width: 100%; height: 100%; position:fixed;left: 0px;
10 | top: 0px;
11 | }
--------------------------------------------------------------------------------
/example/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 |
4 | import './index.css'
5 | import App from './App'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
--------------------------------------------------------------------------------
/example/src/sidebar.css:
--------------------------------------------------------------------------------
1 | .sidebar{position:absolute;top:0;bottom:0;width:100%;overflow:hidden;z-index:2000;box-shadow:0 1px 5px rgba(0,0,0,.65)}.sidebar.collapsed{width:40px}@media (min-width:768px) and (max-width:991px){.sidebar{width:305px}.sidebar-pane{min-width:265px}}@media (min-width:992px) and (max-width:1199px){.sidebar{width:390px}}@media (min-width:1200px){.sidebar{width:460px}}.sidebar-left{left:0}.sidebar-right{right:0}@media (min-width:768px){.sidebar{top:10px;bottom:10px;transition:width .5s}.sidebar-left{left:10px}.sidebar-right{right:10px}}.sidebar-tabs{top:0;bottom:0;height:100%;background-color:#fff}.sidebar-left .sidebar-tabs{left:0}.sidebar-right .sidebar-tabs{right:0}.sidebar-tabs,.sidebar-tabs>ul{position:absolute;width:40px;margin:0;padding:0}.sidebar-tabs>li,.sidebar-tabs>ul>li{width:100%;height:40px;color:#333;font-size:12pt;overflow:hidden;transition:all 80ms}.sidebar-tabs>li:hover,.sidebar-tabs>ul>li:hover{color:#000;background-color:#eee}.sidebar-tabs>li.active,.sidebar-tabs>ul>li.active{color:#fff;background-color:#0074d9}.sidebar-tabs>li.disabled,.sidebar-tabs>ul>li.disabled{color:rgba(51,51,51,.4)}.sidebar-tabs>li.disabled:hover,.sidebar-tabs>ul>li.disabled:hover{background:0 0}.sidebar-tabs>li.disabled>a,.sidebar-tabs>ul>li.disabled>a{cursor:default}.sidebar-tabs>li>a,.sidebar-tabs>ul>li>a{display:block;width:100%;height:100%;line-height:40px;color:inherit;text-decoration:none;text-align:center}.sidebar-tabs>ul+ul{bottom:0}.sidebar-content{position:absolute;top:0;bottom:0;background-color:rgba(255,255,255,.95);overflow-x:hidden;overflow-y:auto}.sidebar-left .sidebar-content{left:40px;right:0}.sidebar-right .sidebar-content{left:0;right:40px}.sidebar.collapsed>.sidebar-content{overflow-y:hidden}.sidebar-pane{display:none;left:0;right:0;box-sizing:border-box;padding:10px 20px}.sidebar-pane.active{display:block}.sidebar-header{margin:-10px -20px 0;height:40px;padding:0 20px;line-height:40px;font-size:14.4pt;color:#fff;background-color:#0074d9}.sidebar-right .sidebar-header{padding-left:40px}.sidebar-close{position:absolute;top:0;width:40px;height:40px;text-align:center;cursor:pointer}.sidebar-left .sidebar-close{right:0}.sidebar-right .sidebar-close{left:0}.sidebar-left~.sidebar-map{margin-left:40px}.sidebar-right~.sidebar-map{margin-right:40px}.sidebar.leaflet-touch{box-shadow:none;border-right:2px solid rgba(0,0,0,.2)}@media (min-width:768px) and (max-width:991px){.sidebar-left~.sidebar-map .leaflet-left{left:315px}.sidebar-right~.sidebar-map .leaflet-right{right:315px}}@media (min-width:992px) and (max-width:1199px){.sidebar-pane{min-width:350px}.sidebar-left~.sidebar-map .leaflet-left{left:400px}.sidebar-right~.sidebar-map .leaflet-right{right:400px}}@media (min-width:1200px){.sidebar-pane{min-width:420px}.sidebar-left~.sidebar-map .leaflet-left{left:470px}.sidebar-right~.sidebar-map .leaflet-right{right:470px}}@media (min-width:768px){.sidebar-left~.sidebar-map{margin-left:0}.sidebar-right~.sidebar-map{margin-right:0}.sidebar{border-radius:4px}.sidebar.leaflet-touch{border:2px solid rgba(0,0,0,.2)}.sidebar-left~.sidebar-map .leaflet-left{transition:left .5s}.sidebar-left.collapsed~.sidebar-map .leaflet-left{left:50px}.sidebar-right~.sidebar-map .leaflet-right{transition:right .5s}.sidebar-right.collapsed~.sidebar-map .leaflet-right{right:50px}}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-leaflet-sidetabs",
3 | "version": "1.0.0",
4 | "description": "react-leaflet sidebar inspired by leaflet-sidebar-v2",
5 | "author": "eferhatg",
6 | "license": "MIT",
7 | "repository": "eferhatg/react-leaflet-sidetabs",
8 | "main": "dist/index.js",
9 | "module": "dist/index.es.js",
10 | "jsnext:main": "dist/index.es.js",
11 | "engines": {
12 | "node": ">=8",
13 | "npm": ">=5"
14 | },
15 | "scripts": {
16 | "test": "cross-env CI=1 react-scripts test --setupTestFrameworkScriptFile --env=jsdom",
17 | "test:watch": "react-scripts test --env=jsdom",
18 | "build": "rollup -c",
19 | "start": "rollup -c -w",
20 | "prepare": "npm run build",
21 | "predeploy": "cd example && npm install && npm run build",
22 | "deploy": "gh-pages -d example/build"
23 | },
24 | "peerDependencies": {
25 | "prop-types": "^15.5.4",
26 | "react": "^15.0.0 || ^16.0.0",
27 | "react-dom": "^15.0.0 || ^16.0.0"
28 | },
29 | "devDependencies": {
30 | "babel-core": "^6.26.3",
31 | "babel-eslint": "^8.2.5",
32 | "babel-plugin-external-helpers": "^6.22.0",
33 | "babel-preset-env": "^1.7.0",
34 | "babel-preset-react": "^6.24.1",
35 | "babel-preset-stage-0": "^6.24.1",
36 | "cross-env": "^5.1.4",
37 | "eslint": "^5.0.1",
38 | "eslint-config-standard": "^11.0.0",
39 | "eslint-config-standard-react": "^6.0.0",
40 | "eslint-plugin-import": "^2.13.0",
41 | "eslint-plugin-node": "^7.0.1",
42 | "eslint-plugin-promise": "^4.0.0",
43 | "eslint-plugin-react": "^7.10.0",
44 | "eslint-plugin-standard": "^3.1.0",
45 | "gh-pages": "^1.2.0",
46 | "react": "^16.4.1",
47 | "react-addons-test-utils": "^15.6.2",
48 | "react-dom": "^16.4.1",
49 | "react-scripts": "^1.1.4",
50 | "rollup": "^0.64.1",
51 | "rollup-plugin-babel": "^3.0.7",
52 | "rollup-plugin-commonjs": "^9.1.3",
53 | "rollup-plugin-node-resolve": "^3.3.0",
54 | "rollup-plugin-peer-deps-external": "^2.2.0",
55 | "rollup-plugin-postcss": "^1.6.2",
56 | "rollup-plugin-url": "^1.4.0"
57 | },
58 | "files": [
59 | "dist"
60 | ],
61 | "dependencies": {
62 | "leaflet": "^1.3.4",
63 | "prop-types": "^15.6.2",
64 | "react-leaflet": "^2.0.1"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel'
2 | import commonjs from 'rollup-plugin-commonjs'
3 | import external from 'rollup-plugin-peer-deps-external'
4 | import postcss from 'rollup-plugin-postcss'
5 | import resolve from 'rollup-plugin-node-resolve'
6 | import url from 'rollup-plugin-url'
7 |
8 | import pkg from './package.json'
9 |
10 | export default {
11 | input: 'src/index.js',
12 | output: [
13 | {
14 | file: pkg.main,
15 | format: 'cjs',
16 | sourcemap: true
17 | },
18 | {
19 | file: pkg.module,
20 | format: 'es',
21 | sourcemap: true
22 | }
23 | ],
24 | plugins: [
25 | external(),
26 | postcss({
27 | modules: false
28 | }),
29 | url(),
30 | babel({
31 | exclude: 'node_modules/**',
32 | plugins: [ 'external-helpers' ]
33 | }),
34 | resolve(),
35 | commonjs()
36 | ]
37 | }
38 |
--------------------------------------------------------------------------------
/src/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "jest": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/MenuButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { PropTypes } from 'prop-types'
3 |
4 | const MenuButton = props => {
5 | const icon =
6 | props.icon === 'string' ? : props.icon
7 | const active = props.id === props.selected && !props.collapsed ? ' active' : ''
8 | const disabled = props.disabled ? ' disabled' : ''
9 |
10 | return (
11 |
12 | props.disabled || (props.collapsed ? props.onOpen(props.id) : (
16 | props.selected === props.id ? props.onClose() : props.onOpen(props.id)
17 | ))}
18 | >{' '}{icon}
19 |
20 |
21 | )
22 | }
23 |
24 | MenuButton.propTypes = {
25 | id: PropTypes.string.isRequired,
26 | icon: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
27 | disabled: PropTypes.bool,
28 | selected: PropTypes.string,
29 | onOpen: PropTypes.func,
30 | onClose: PropTypes.func,
31 | collapsed: PropTypes.bool
32 | }
33 |
34 | export default MenuButton
35 |
--------------------------------------------------------------------------------
/src/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { PropTypes } from 'prop-types'
3 | import Tab from './Tab'
4 | import MenuButton from './MenuButton'
5 | import './sidebar.css'
6 |
7 | const { MapComponent } = require('react-leaflet')
8 |
9 | const TabType = PropTypes.shape({
10 | type: PropTypes.oneOf([Tab])
11 | })
12 |
13 | class Sidebar extends MapComponent {
14 | onClose(e) {
15 | e.preventDefault()
16 | e.stopPropagation()
17 | this.props.onClose && this.props.onClose(e)
18 | }
19 |
20 | onOpen(e, tabid) {
21 | e.preventDefault()
22 | e.stopPropagation()
23 | this.props.onOpen && this.props.onOpen(tabid)
24 | }
25 |
26 | renderPanes(children) {
27 | return React.Children.map(children, p =>
28 | React.cloneElement(p, {
29 | onClose: this.onClose.bind(this),
30 | closeIcon: this.props.closeIcon,
31 | active: p.props.id === this.props.selected,
32 | position: this.props.position || 'left'
33 | })
34 | )
35 | }
36 |
37 | render() {
38 | const position = ` sidebar-${this.props.position || 'left'}`
39 | const collapsed = this.props.collapsed ? ' collapsed' : ''
40 | const tabs = React.Children.toArray(this.props.children)
41 | const bottomtabs = tabs.filter(t => t.props.anchor === 'bottom')
42 | const toptabs = tabs.filter(t => t.props.anchor !== 'bottom')
43 |
44 | return (
45 | {
49 | this.rootElement = el
50 | }}
51 | >
52 |
53 |
54 | {toptabs.map(t =>
55 | )}
64 |
65 |
66 | {bottomtabs.map(t =>
67 | )}
76 |
77 |
78 |
79 | {this.renderPanes(this.props.children)}
80 |
81 |
82 | )
83 | }
84 | }
85 |
86 | Sidebar.propTypes = {
87 | id: PropTypes.string.isRequired,
88 | collapsed: PropTypes.bool,
89 | position: PropTypes.oneOf(['left', 'right']),
90 | selected: PropTypes.string,
91 | closeIcon: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
92 | onClose: PropTypes.func,
93 | onOpen: PropTypes.func,
94 | children: PropTypes.oneOfType([PropTypes.arrayOf(TabType), TabType])
95 | }
96 |
97 | export default Sidebar
98 |
--------------------------------------------------------------------------------
/src/Tab.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { PropTypes } from 'prop-types'
3 |
4 | const Tab = props => {
5 | const active = props.active ? ' active' : ''
6 | const closeIcon = closeIconSelector(props)
7 |
8 | return (
9 |
10 |
11 | {props.header}
12 |
{closeIcon}
17 |
18 |
19 | {props.children}
20 |
21 | )
22 | }
23 |
24 | const closeIconSelector = props => {
25 | switch (typeof props.closeIcon) {
26 | case 'string':
27 | return
28 | case 'object':
29 | return props.closeIcon
30 | default:
31 | return props.position === 'right' ? (
32 |
33 | ) : (
34 |
35 | )
36 | }
37 | }
38 |
39 | closeIconSelector.propTypes = {
40 | closeIcon: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
41 | position: PropTypes.oneOf(['left', 'right'])
42 | }
43 |
44 | Tab.propTypes = {
45 | id: PropTypes.string.isRequired,
46 | header: PropTypes.string.isRequired,
47 | children: PropTypes.oneOfType([PropTypes.func, PropTypes.element, PropTypes.object]).isRequired,
48 | onClose: PropTypes.func,
49 | active: PropTypes.bool
50 | }
51 |
52 | export default Tab
53 |
--------------------------------------------------------------------------------
/src/__snapshots__/test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`MenuButton has active class when selected equals id 1`] = `
4 |
7 |
12 |
13 | fa fa-home
14 |
15 |
16 | `;
17 |
18 | exports[`MenuButton has disabled class disabled equals true 1`] = `
19 |
22 |
27 |
28 | fa fa-home
29 |
30 |
31 | `;
32 |
33 | exports[`MenuButton has not active class when selected not equals id 1`] = `
34 |
37 |
42 |
43 | fa fa-home
44 |
45 |
46 | `;
47 |
48 | exports[`Tab has active class with active prop 1`] = `
49 |
53 |
56 | Home
57 |
62 |
65 |
66 |
67 |
68 | No place like home!
69 |
70 |
71 | `;
72 |
73 | exports[`Tab has not active class without active prop 1`] = `
74 |
78 |
81 | Home
82 |
87 |
90 |
91 |
92 |
93 | No place like home!
94 |
95 |
96 | `;
97 |
98 | exports[`Tab makes closeIcon fa fa-caret-left when position is left 1`] = `
99 |
103 |
106 | Home
107 |
112 |
115 |
116 |
117 |
118 | No place like home!
119 |
120 |
121 | `;
122 |
123 | exports[`Tab makes closeIcon fa fa-caret-right when position is right 1`] = `
124 |
128 |
131 | Home
132 |
137 |
140 |
141 |
142 |
143 | No place like home!
144 |
145 |
146 | `;
147 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Sidebar from './Sidebar'
2 | import Tab from './Tab'
3 | import MenuButton from './MenuButton'
4 |
5 | export { Sidebar, Tab, MenuButton }
6 |
--------------------------------------------------------------------------------
/src/sidebar.css:
--------------------------------------------------------------------------------
1 | .sidebar{position:absolute;top:0;bottom:0;width:100%;overflow:hidden;z-index:2000;box-shadow:0 1px 5px rgba(0,0,0,.65)}.sidebar.collapsed{width:40px}@media (min-width:768px) and (max-width:991px){.sidebar{width:305px}.sidebar-pane{min-width:265px}}@media (min-width:992px) and (max-width:1199px){.sidebar{width:390px}}@media (min-width:1200px){.sidebar{width:460px}}.sidebar-left{left:0}.sidebar-right{right:0}@media (min-width:768px){.sidebar{top:10px;bottom:10px;transition:width .5s}.sidebar-left{left:10px}.sidebar-right{right:10px}}.sidebar-tabs{top:0;bottom:0;height:100%;background-color:#fff}.sidebar-left .sidebar-tabs{left:0}.sidebar-right .sidebar-tabs{right:0}.sidebar-tabs,.sidebar-tabs>ul{position:absolute;width:40px;margin:0;padding:0}.sidebar-tabs>li,.sidebar-tabs>ul>li{width:100%;height:40px;color:#333;font-size:12pt;overflow:hidden;transition:all 80ms}.sidebar-tabs>li:hover,.sidebar-tabs>ul>li:hover{color:#000;background-color:#eee}.sidebar-tabs>li.active,.sidebar-tabs>ul>li.active{color:#fff;background-color:#0074d9}.sidebar-tabs>li.disabled,.sidebar-tabs>ul>li.disabled{color:rgba(51,51,51,.4)}.sidebar-tabs>li.disabled:hover,.sidebar-tabs>ul>li.disabled:hover{background:0 0}.sidebar-tabs>li.disabled>a,.sidebar-tabs>ul>li.disabled>a{cursor:default}.sidebar-tabs>li>a,.sidebar-tabs>ul>li>a{display:block;width:100%;height:100%;line-height:40px;color:inherit;text-decoration:none;text-align:center}.sidebar-tabs>ul+ul{bottom:0}.sidebar-content{position:absolute;top:0;bottom:0;background-color:rgba(255,255,255,.95);overflow-x:hidden;overflow-y:auto}.sidebar-left .sidebar-content{left:40px;right:0}.sidebar-right .sidebar-content{left:0;right:40px}.sidebar.collapsed>.sidebar-content{overflow-y:hidden}.sidebar-pane{display:none;left:0;right:0;box-sizing:border-box;padding:10px 20px}.sidebar-pane.active{display:block}.sidebar-header{margin:-10px -20px 0;height:40px;padding:0 20px;line-height:40px;font-size:14.4pt;color:#fff;background-color:#0074d9}.sidebar-right .sidebar-header{padding-left:40px}.sidebar-close{position:absolute;top:0;width:40px;height:40px;text-align:center;cursor:pointer}.sidebar-left .sidebar-close{right:0}.sidebar-right .sidebar-close{left:0}.sidebar-left~.sidebar-map{margin-left:40px}.sidebar-right~.sidebar-map{margin-right:40px}.sidebar.leaflet-touch{box-shadow:none;border-right:2px solid rgba(0,0,0,.2)}@media (min-width:768px) and (max-width:991px){.sidebar-left~.sidebar-map .leaflet-left{left:315px}.sidebar-right~.sidebar-map .leaflet-right{right:315px}}@media (min-width:992px) and (max-width:1199px){.sidebar-pane{min-width:350px}.sidebar-left~.sidebar-map .leaflet-left{left:400px}.sidebar-right~.sidebar-map .leaflet-right{right:400px}}@media (min-width:1200px){.sidebar-pane{min-width:420px}.sidebar-left~.sidebar-map .leaflet-left{left:470px}.sidebar-right~.sidebar-map .leaflet-right{right:470px}}@media (min-width:768px){.sidebar-left~.sidebar-map{margin-left:0}.sidebar-right~.sidebar-map{margin-right:0}.sidebar{border-radius:4px}.sidebar.leaflet-touch{border:2px solid rgba(0,0,0,.2)}.sidebar-left~.sidebar-map .leaflet-left{transition:left .5s}.sidebar-left.collapsed~.sidebar-map .leaflet-left{left:50px}.sidebar-right~.sidebar-map .leaflet-right{transition:right .5s}.sidebar-right.collapsed~.sidebar-map .leaflet-right{right:50px}}
--------------------------------------------------------------------------------
/src/test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import renderer from 'react-test-renderer'
3 | import MenuButton from './MenuButton'
4 | import Tab from './Tab'
5 | import Sidebar from './Sidebar'
6 | describe('MenuButton', () => {
7 | it('is truthy', () => {
8 | expect(MenuButton).toBeTruthy()
9 | })
10 |
11 | it('has not active class when selected not equals id', () => {
12 | const component = renderer.create(
13 | {}}
21 | onOpen={() => {}} />
22 | )
23 | let tree = component.toJSON()
24 | expect(tree).toMatchSnapshot()
25 | })
26 |
27 | it('has active class when selected equals id', () => {
28 | const component = renderer.create(
29 | {}}
37 | onOpen={() => {}} />
38 | )
39 | let tree = component.toJSON()
40 | expect(tree).toMatchSnapshot()
41 | })
42 |
43 | it('has disabled class disabled equals true', () => {
44 | const component = renderer.create(
45 | {}}
53 | onOpen={() => {}} />
54 | )
55 | let tree = component.toJSON()
56 | expect(tree).toMatchSnapshot()
57 | })
58 | })
59 |
60 | describe('Tab', () => {
61 | it('is truthy', () => {
62 | expect(Tab).toBeTruthy()
63 | })
64 |
65 | it('has not active class without active prop', () => {
66 | const component = renderer.create(
67 |
68 | No place like home!
69 | )
70 | let tree = component.toJSON()
71 | expect(tree).toMatchSnapshot()
72 | })
73 |
74 | it('has active class with active prop', () => {
75 | const component = renderer.create(
76 |
77 | No place like home!
78 | )
79 | let tree = component.toJSON()
80 | expect(tree).toMatchSnapshot()
81 | })
82 |
83 | it('makes closeIcon fa fa-caret-right when position is right', () => {
84 | const component = renderer.create(
85 |
86 | No place like home!
87 | )
88 | let tree = component.toJSON()
89 | expect(tree).toMatchSnapshot()
90 | })
91 |
92 | it('makes closeIcon fa fa-caret-left when position is left', () => {
93 | const component = renderer.create(
94 |
95 | No place like home!
96 | )
97 | let tree = component.toJSON()
98 | expect(tree).toMatchSnapshot()
99 | })
100 | })
101 |
102 | describe('Sidebar', () => {
103 | it('is truthy', () => {
104 | expect(Sidebar).toBeTruthy()
105 | })
106 | })
107 |
--------------------------------------------------------------------------------