├── .prettierignore ├── .gitignore ├── src ├── favicon.png ├── ts │ ├── SlideMenu.legacy.ts │ ├── utils │ │ ├── polyfills.ts │ │ └── dom.ts │ └── SlideMenu.ts ├── dom.ie.d.ts ├── styles │ ├── slide-menu.scss │ └── demo.scss └── index.html ├── dist ├── favicon.png ├── slide-menu.css ├── demo.css ├── index.html ├── slide-menu.js └── slide-menu.ie.js ├── docs ├── favicon.png ├── slide-menu.css ├── demo.css ├── index.html ├── slide-menu.js └── slide-menu.ie.js ├── .prettierrc ├── postcss.config.js ├── tsconfig.json ├── .eslintrc.json ├── LICENSE ├── package.json ├── webpack.config.js └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | *.png 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules 3 | *.map 4 | -------------------------------------------------------------------------------- /src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grubersjoe/slide-menu/HEAD/src/favicon.png -------------------------------------------------------------------------------- /src/ts/SlideMenu.legacy.ts: -------------------------------------------------------------------------------- 1 | import './utils/polyfills'; 2 | import './SlideMenu'; 3 | -------------------------------------------------------------------------------- /dist/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grubersjoe/slide-menu/HEAD/dist/favicon.png -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grubersjoe/slide-menu/HEAD/docs/favicon.png -------------------------------------------------------------------------------- /src/dom.ie.d.ts: -------------------------------------------------------------------------------- 1 | interface Element { 2 | msMatchesSelector(selectors: string): boolean; 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "trailingComma": "all", 5 | "semi": true, 6 | "singleQuote": true 7 | } 8 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = () => ({ 2 | plugins: { 3 | autoprefixer: { 4 | remove: false, 5 | }, 6 | cssnano: { 7 | preset: 'default', 8 | }, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /src/ts/utils/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Polyfills for *drum roll* Internet Explorer 11 3 | */ 4 | 5 | import 'custom-event-polyfill'; 6 | 7 | if (!Element.prototype.matches) { 8 | Element.prototype.matches = Element.prototype.msMatchesSelector; 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es2019", 5 | "dom" 6 | ], 7 | "target": "ES6", 8 | "noImplicitReturns": true, 9 | "strict": true, 10 | }, 11 | "include": [ 12 | "./src/**/*" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /dist/slide-menu.css: -------------------------------------------------------------------------------- 1 | .slide-menu{position:fixed;width:320px;max-width:100%;height:100vh;top:0;right:0;display:none;overflow:hidden;box-sizing:border-box;transform:translateX(100%);overflow-y:auto;z-index:1000}.slide-menu,.slide-menu .slide-menu__slider{transition:transform .3s ease-in-out;will-change:transform}.slide-menu .slide-menu__slider{width:100%;transform:translateX(0)}.slide-menu ul{position:relative;width:100%;margin:0;padding-left:0;list-style:none}.slide-menu ul ul{position:absolute;top:0;left:100%;display:none}.slide-menu ul a{display:block}.slide-menu a{cursor:pointer} 2 | -------------------------------------------------------------------------------- /docs/slide-menu.css: -------------------------------------------------------------------------------- 1 | .slide-menu{position:fixed;width:320px;max-width:100%;height:100vh;top:0;right:0;display:none;overflow:hidden;box-sizing:border-box;transform:translateX(100%);overflow-y:auto;z-index:1000}.slide-menu,.slide-menu .slide-menu__slider{transition:transform .3s ease-in-out;will-change:transform}.slide-menu .slide-menu__slider{width:100%;transform:translateX(0)}.slide-menu ul{position:relative;width:100%;margin:0;padding-left:0;list-style:none}.slide-menu ul ul{position:absolute;top:0;left:100%;display:none}.slide-menu ul a{display:block}.slide-menu a{cursor:pointer} 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended" 9 | ], 10 | "parser": "@typescript-eslint/parser", 11 | "parserOptions": { 12 | "ecmaVersion": 2018, 13 | "project": "./tsconfig.json", 14 | "sourceType": "module" 15 | }, 16 | "plugins": [ 17 | "@typescript-eslint" 18 | ], 19 | "rules": { 20 | "@typescript-eslint/ban-ts-ignore": 0, 21 | "@typescript-eslint/explicit-function-return-type": [ 22 | 1, 23 | { 24 | "allowExpressions": true, 25 | "allowTypedFunctionExpressions": true 26 | } 27 | ], 28 | "@typescript-eslint/indent": 0, 29 | "@typescript-eslint/no-inferrable-types": 0, 30 | "semi": "error" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/styles/slide-menu.scss: -------------------------------------------------------------------------------- 1 | $sm-menu-width: 320px !default; 2 | $sm-transition-dur: 300ms !default; 3 | $sm-transition-easing: ease-in-out !default; 4 | 5 | .slide-menu { 6 | position: fixed; 7 | width: $sm-menu-width; 8 | max-width: 100%; 9 | height: 100vh; 10 | top: 0; 11 | right: 0; 12 | display: none; 13 | overflow: hidden; 14 | box-sizing: border-box; 15 | transition: transform $sm-transition-dur $sm-transition-easing; 16 | transform: translateX(100%); 17 | overflow-y: auto; 18 | will-change: transform; 19 | z-index: 1000; 20 | 21 | .slide-menu__slider { 22 | width: 100%; 23 | transition: transform $sm-transition-dur $sm-transition-easing; 24 | transform: translateX(0); 25 | will-change: transform; 26 | } 27 | 28 | ul { 29 | position: relative; 30 | width: 100%; 31 | margin: 0; 32 | padding-left: 0; 33 | list-style: none; 34 | 35 | ul { 36 | position: absolute; 37 | top: 0; 38 | left: 100%; 39 | display: none; 40 | } 41 | 42 | a { 43 | display: block; 44 | } 45 | } 46 | 47 | a { 48 | cursor: pointer; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jonathan Gruber 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 | -------------------------------------------------------------------------------- /src/ts/utils/dom.ts: -------------------------------------------------------------------------------- 1 | export function wrapElement(elem: HTMLElement, wrapper: HTMLElement): HTMLElement { 2 | if (elem.parentElement === null) { 3 | throw Error('`elem` has no parentElement'); 4 | } 5 | 6 | elem.parentElement.insertBefore(wrapper, elem); 7 | wrapper.appendChild(elem); 8 | 9 | return elem; 10 | } 11 | 12 | export function unwrapElement(elem: HTMLElement): void { 13 | const parent = elem.parentElement; 14 | 15 | if (parent === null) { 16 | throw Error('`elem` has no parentElement'); 17 | } 18 | 19 | while (elem.firstChild) { 20 | parent.insertBefore(elem.firstChild, elem); 21 | } 22 | parent.removeChild(elem); 23 | } 24 | 25 | export function parents(elem: Node | null, selector: string, limit?: number): HTMLElement[] { 26 | const matched: HTMLElement[] = []; 27 | 28 | while ( 29 | elem && 30 | elem.parentElement !== null && 31 | (limit === undefined ? true : matched.length < limit) 32 | ) { 33 | if (elem instanceof HTMLElement && elem.matches(selector)) { 34 | matched.push(elem); 35 | } 36 | 37 | elem = elem.parentElement; 38 | } 39 | 40 | return matched; 41 | } 42 | 43 | export function parentsOne(elem: Node, selector: string): HTMLElement | null { 44 | const matches = parents(elem, selector, 1); 45 | 46 | return matches.length ? matches[0] : null; 47 | } 48 | -------------------------------------------------------------------------------- /dist/demo.css: -------------------------------------------------------------------------------- 1 | :active,:focus{outline:none!important}html{font-size:20px}body{font-family:Lato,sans-serif;line-height:1.4;color:rgba(0,0,0,.94)}h1{font-size:1.8rem;font-weight:700}h1 small{margin-left:.3rem;color:rgba(0,0,0,.6);font-size:60%}h2{margin-top:1.5rem;margin-bottom:1rem;font-size:1rem}a{text-decoration:none;color:#336184}.btn,a{transition:background-color .15s ease-in-out;will-change:background-color}p{margin:0 0 .5rem}p:last-of-type{margin:0 0 2rem}footer{margin-top:2rem;font-size:90%}footer a{font-style:italic}footer path{fill:#9d252d}.btn{padding:.6rem .8rem .64rem;border:none;color:#fff;cursor:pointer;font-family:inherit;font-size:85%;line-height:1}.icon{height:.6rem;margin:0 .1rem}main{display:block;width:90%;margin:2.5rem auto}main .btn{width:100%;display:block;margin:0 .25rem .75rem 0;background-color:#2e4b61;border-radius:.2rem;font-size:70%;letter-spacing:.03em;text-transform:uppercase}@media (min-width:768px){main{max-width:40rem}main .btn{width:auto;display:inline-block}main .btn:hover{background-color:#213545}main .btn-danger{background-color:#9d252d}main .btn-danger:hover{background-color:#7c1d23}}main #events{font-family:monospace;font-size:80%}.slide-menu{width:340px;background-color:#213545}.slide-menu,.slide-menu a{font-size:.8rem;color:#fff}.slide-menu a{padding:.9rem 1.5rem;border-bottom:1px solid #14202a;text-decoration:none}.slide-menu a:hover{background-color:#172531}.slide-menu .controls{display:flex;margin-bottom:1rem}.slide-menu .btn{padding:.75rem 1.5rem;flex:1 0 auto;font-size:90%;color:#fff;background-color:#172531;text-transform:uppercase}.slide-menu .btn:first-of-type{text-align:left}.slide-menu .btn:first-of-type:before{content:"⮜";margin-right:.5rem}.slide-menu .btn:last-of-type{text-align:right}.slide-menu .btn:last-of-type:before{content:"✕";margin-right:.5rem}.slide-menu .slide-menu__backlink{text-transform:uppercase}#test-menu-left p{font-size:110%;padding-left:1.25rem;padding-right:1.25rem} 2 | -------------------------------------------------------------------------------- /docs/demo.css: -------------------------------------------------------------------------------- 1 | :active,:focus{outline:none!important}html{font-size:20px}body{font-family:Lato,sans-serif;line-height:1.4;color:rgba(0,0,0,.94)}h1{font-size:1.8rem;font-weight:700}h1 small{margin-left:.3rem;color:rgba(0,0,0,.6);font-size:60%}h2{margin-top:1.5rem;margin-bottom:1rem;font-size:1rem}a{text-decoration:none;color:#336184}.btn,a{transition:background-color .15s ease-in-out;will-change:background-color}p{margin:0 0 .5rem}p:last-of-type{margin:0 0 2rem}footer{margin-top:2rem;font-size:90%}footer a{font-style:italic}footer path{fill:#9d252d}.btn{padding:.6rem .8rem .64rem;border:none;color:#fff;cursor:pointer;font-family:inherit;font-size:85%;line-height:1}.icon{height:.6rem;margin:0 .1rem}main{display:block;width:90%;margin:2.5rem auto}main .btn{width:100%;display:block;margin:0 .25rem .75rem 0;background-color:#2e4b61;border-radius:.2rem;font-size:70%;letter-spacing:.03em;text-transform:uppercase}@media (min-width:768px){main{max-width:40rem}main .btn{width:auto;display:inline-block}main .btn:hover{background-color:#213545}main .btn-danger{background-color:#9d252d}main .btn-danger:hover{background-color:#7c1d23}}main #events{font-family:monospace;font-size:80%}.slide-menu{width:340px;background-color:#213545}.slide-menu,.slide-menu a{font-size:.8rem;color:#fff}.slide-menu a{padding:.9rem 1.5rem;border-bottom:1px solid #14202a;text-decoration:none}.slide-menu a:hover{background-color:#172531}.slide-menu .controls{display:flex;margin-bottom:1rem}.slide-menu .btn{padding:.75rem 1.5rem;flex:1 0 auto;font-size:90%;color:#fff;background-color:#172531;text-transform:uppercase}.slide-menu .btn:first-of-type{text-align:left}.slide-menu .btn:first-of-type:before{content:"⮜";margin-right:.5rem}.slide-menu .btn:last-of-type{text-align:right}.slide-menu .btn:last-of-type:before{content:"✕";margin-right:.5rem}.slide-menu .slide-menu__backlink{text-transform:uppercase}#test-menu-left p{font-size:110%;padding-left:1.25rem;padding-right:1.25rem} 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@grubersjoe/slide-menu", 3 | "version": "1.2.3", 4 | "author": "Jonathan Gruber ", 5 | "license": "MIT", 6 | "description": "A library agnostic multilevel page menu with a smooth slide effect based on CSS transitions", 7 | "browserslist": [ 8 | "> 1%" 9 | ], 10 | "keywords": [ 11 | "menu", 12 | "multi level", 13 | "navigation" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/grubersjoe/slide-menu.git" 18 | }, 19 | "bugs": "https://github.com/grubersjoe/slide-menu/issues", 20 | "main": "dist/slide-menu.js", 21 | "files": [ 22 | "./*", 23 | "dist/*", 24 | "src/*" 25 | ], 26 | "devDependencies": { 27 | "@babel/core": "^7.7.7", 28 | "@babel/preset-env": "^7.7.7", 29 | "@typescript-eslint/eslint-plugin": "^2.13.0", 30 | "@typescript-eslint/parser": "^2.13.0", 31 | "autoprefixer": "^9.7.3", 32 | "babel-loader": "^8.0.6", 33 | "core-js": "3.6.1", 34 | "css-loader": "3.4.0", 35 | "cssnano": "^4.1.10", 36 | "custom-event-polyfill": "^1.0.7", 37 | "eslint": "^6.8.0", 38 | "html-webpack-plugin": "^3.2.0", 39 | "mini-css-extract-plugin": "0.9.0", 40 | "node-sass": "^4.13.0", 41 | "postcss-loader": "^3.0.0", 42 | "prettier": "^1.19.1", 43 | "sass-loader": "^8.0.0", 44 | "ts-loader": "^6.2.1", 45 | "typescript": "~3.7.4", 46 | "webpack": "^4.41.4", 47 | "webpack-cli": "^3.3.10", 48 | "webpack-dev-server": "^3.10.1" 49 | }, 50 | "scripts": { 51 | "build": "yarn clean && webpack --mode production && rm -f dist/demo.js* && rm -r docs/ && cp -r dist/ docs/", 52 | "build:dev": "yarn clean && webpack --mode development", 53 | "clean": "rm -f ./dist/*", 54 | "format": "prettier --write 'src/**/*'", 55 | "lint": "eslint --max-warnings=0 'src/**/*.ts'", 56 | "start": "webpack-dev-server --mode production --host 0.0.0.0", 57 | "start:dev": "webpack-dev-server --mode development --host 0.0.0.0", 58 | "typecheck": "tsc" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/styles/demo.scss: -------------------------------------------------------------------------------- 1 | $color-primary: hsl(206, 36%, 20%); 2 | $color-danger: hsl(356, 62%, 38%); 3 | 4 | *:active, 5 | *:focus { 6 | outline: none !important; 7 | } 8 | 9 | html { 10 | font-size: 20px; 11 | } 12 | 13 | body { 14 | font-family: 'Lato', sans-serif; 15 | line-height: 1.4; 16 | color: fade_out(#000, 0.06); 17 | } 18 | 19 | h1 { 20 | font-size: 1.8rem; 21 | font-weight: bold; 22 | 23 | small { 24 | margin-left: 0.3rem; 25 | color: fade_out(#000, 0.4); 26 | font-size: 60%; 27 | } 28 | } 29 | 30 | h2 { 31 | margin-top: 1.5rem; 32 | margin-bottom: 1rem; 33 | font-size: 1rem; 34 | } 35 | 36 | a { 37 | text-decoration: none; 38 | color: saturate(lighten($color-primary, 16%), 8%); 39 | } 40 | 41 | a, 42 | .btn { 43 | transition: background-color 0.15s ease-in-out; 44 | will-change: background-color; 45 | } 46 | 47 | p { 48 | margin: 0 0 0.5rem; 49 | } 50 | 51 | p:last-of-type { 52 | margin: 0 0 2rem; 53 | } 54 | 55 | footer { 56 | margin-top: 2rem; 57 | font-size: 90%; 58 | 59 | a { 60 | font-style: italic; 61 | } 62 | 63 | path { 64 | fill: $color-danger; 65 | } 66 | } 67 | 68 | .btn { 69 | padding: 0.6rem 0.8rem 0.64rem 0.8rem; 70 | border: none; 71 | color: #fff; 72 | cursor: pointer; 73 | font-family: inherit; 74 | font-size: 85%; 75 | line-height: 1; 76 | } 77 | 78 | .icon { 79 | height: 0.6rem; 80 | margin: 0 0.1rem; 81 | } 82 | 83 | main { 84 | display: block; // IE11 85 | width: 90%; 86 | margin: 2.5rem auto; 87 | 88 | .btn { 89 | width: 100%; 90 | display: block; 91 | margin: 0 0.25rem 0.75rem 0; 92 | background-color: lighten($color-primary, 8%); 93 | border-radius: 0.2rem; 94 | font-size: 70%; 95 | letter-spacing: 0.03em; 96 | text-transform: uppercase; 97 | } 98 | 99 | @media (min-width: 768px) { 100 | max-width: 40rem; 101 | 102 | .btn { 103 | width: auto; 104 | display: inline-block; 105 | 106 | &:hover { 107 | background-color: $color-primary; 108 | } 109 | } 110 | 111 | .btn-danger { 112 | background-color: $color-danger; 113 | 114 | &:hover { 115 | background-color: darken($color-danger, 8%); 116 | } 117 | } 118 | } 119 | 120 | #events { 121 | font-family: monospace; 122 | font-size: 80%; 123 | } 124 | } 125 | 126 | .slide-menu { 127 | width: 340px; 128 | background-color: $color-primary; 129 | 130 | &, 131 | a { 132 | font-size: 0.8rem; 133 | color: #fff; 134 | } 135 | 136 | a { 137 | padding: 0.9rem 1.5rem; 138 | border-bottom: solid 1px darken($color-primary, 8%); 139 | text-decoration: none; 140 | 141 | &:hover { 142 | background-color: darken($color-primary, 6%); 143 | } 144 | } 145 | 146 | .controls { 147 | display: flex; 148 | margin-bottom: 1rem; 149 | } 150 | 151 | .btn { 152 | padding: 0.75rem 1.5rem; 153 | flex: 1 0 auto; 154 | font-size: 90%; 155 | color: #fff; 156 | background-color: darken($color-primary, 6%); 157 | text-transform: uppercase; 158 | 159 | &:first-of-type { 160 | text-align: left; 161 | 162 | &:before { 163 | content: '⮜'; 164 | margin-right: 0.5rem; 165 | } 166 | } 167 | 168 | &:last-of-type { 169 | text-align: right; 170 | 171 | &:before { 172 | content: '✕'; 173 | margin-right: 0.5rem; 174 | } 175 | } 176 | } 177 | 178 | .slide-menu__backlink { 179 | text-transform: uppercase; 180 | } 181 | } 182 | 183 | #test-menu-left p { 184 | font-size: 110%; 185 | padding-left: 1.25rem; 186 | padding-right: 1.25rem; 187 | } 188 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 5 | 6 | const packageMeta = require('./package.json'); 7 | 8 | module.exports = [ 9 | (env, options) => ({ 10 | entry: { 11 | 'slide-menu': './src/ts/SlideMenu.ts', 12 | demo: './src/styles/demo.scss', 13 | }, 14 | resolve: { 15 | extensions: ['.ts', '.js'], 16 | }, 17 | output: { 18 | path: `${__dirname}/dist`, 19 | filename: '[name].js', 20 | }, 21 | devServer: { 22 | contentBase: path.join(__dirname, 'dist'), 23 | compress: true, 24 | port: 9000, 25 | }, 26 | devtool: options.mode !== 'production' ? 'source-map' : false, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.ts$/, 31 | use: [ 32 | { 33 | loader: 'babel-loader', 34 | options: { 35 | presets: [ 36 | [ 37 | '@babel/env', 38 | { 39 | targets: { 40 | browsers: ['> 1%', 'not ie > 0'] 41 | }, 42 | useBuiltIns: 'usage', 43 | corejs: "3", 44 | } 45 | ], 46 | ], 47 | } 48 | }, 49 | { 50 | loader: 'ts-loader', 51 | } 52 | ], 53 | exclude: /node_modules/, 54 | }, 55 | { 56 | test: /\.scss$/, 57 | use: [ 58 | MiniCssExtractPlugin.loader, 59 | 'css-loader', 60 | ...(options.mode === 'production' ? ['postcss-loader'] : []), 61 | { 62 | loader: 'sass-loader', 63 | options: { 64 | sassOptions: { 65 | outputStyle: 'compressed', 66 | } 67 | } 68 | } 69 | ], 70 | }, 71 | ], 72 | }, 73 | plugins: [ 74 | new HtmlWebpackPlugin({ 75 | template: 'src/index.html', 76 | templateParameters: { 77 | version: packageMeta.version, 78 | title: `Slide Menu`, 79 | description: packageMeta.description, 80 | }, 81 | meta: { 82 | charset: 'utf-8', 83 | description: packageMeta.description, 84 | viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no', 85 | }, 86 | favicon: './src/favicon.png', 87 | }), 88 | new MiniCssExtractPlugin({ 89 | filename: '[name].css', 90 | }), 91 | ], 92 | }), 93 | 94 | // Build code for legacy browsers separately 95 | (env, options) => ({ 96 | entry: { 97 | 'slide-menu.ie': './src/ts/SlideMenu.legacy.ts', 98 | }, 99 | resolve: { 100 | extensions: ['.ts', '.js'], 101 | }, 102 | output: { 103 | path: `${__dirname}/dist`, 104 | filename: '[name].js', 105 | }, 106 | module: { 107 | rules: [ 108 | { 109 | test: /\.ts$/, 110 | use: [ 111 | { 112 | loader: 'babel-loader', 113 | options: { 114 | presets: [ 115 | [ 116 | '@babel/env', 117 | { 118 | targets: { 119 | browsers: ['> 1%', 'ie > 11'] 120 | }, 121 | useBuiltIns: 'usage', 122 | corejs: "3", 123 | } 124 | ], 125 | ], 126 | } 127 | }, 128 | { 129 | loader: 'ts-loader', 130 | } 131 | ], 132 | exclude: /node_modules/, 133 | }, 134 | { 135 | test: /\.scss$/, 136 | use: [ 137 | 'css-loader', 138 | ...(options.mode === 'production' ? ['postcss-loader'] : []), 139 | { 140 | loader: 'sass-loader', 141 | options: { 142 | sassOptions: { 143 | outputStyle: 'compressed', 144 | } 145 | } 146 | } 147 | ], 148 | }, 149 | ], 150 | }, 151 | }), 152 | ]; 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slide Menu 2 | 3 | > ⚠️ This project is unmaintained. Feel free to fork it. 4 | 5 | *A library agnostic multilevel page menu with a smooth slide effect based on CSS transitions and various options.* 6 | 7 | Support: All current browsers and IE11+ (if using `dist/slide-menu.ie.js`). 8 | 9 | **[Demo](https://grubersjoe.github.io/slide-menu)** 10 | 11 | ## Breaking changes 12 | 13 | Version 1.0 has been released and includes breaking changes: SlideMenu no longer depends on jQuery and the library has been rewritten in TypeScript. See below instructions how to use the current version. 14 | 15 | ## Install 16 | ```sh 17 | npm install @grubersjoe/slide-menu 18 | ``` 19 | 20 | Now import `dist/slide-menu.js` and `dist/slide-menu.css` in your bundler or build system of choice or use a 1998 ` 297 | 298 | 299 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Slide Menu (Demo) 6 | 7 | 8 | 9 |
10 |

11 | Slide Menu 12 | v1.2.3 13 |

14 |

A library agnostic multilevel page menu with a smooth slide effect based on CSS transitions.

15 |

16 | Read the documentation here. 17 |

18 | 19 |

Multi-purpose menu (left)

20 |
21 | 29 | 37 | 45 |
46 | 47 |

Navigation menu (right)

48 |
49 | 57 | 65 | 73 | 81 |
82 | 91 | 100 | 109 |
110 | 118 |
119 | 120 |

Events

121 | 122 | 123 |
124 | Made with 125 | 126 | 129 | 130 | by @grubersjoe 131 |
132 |
133 | 134 | 143 | 144 | 246 | 247 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Slide Menu (Demo) 6 | 7 | 8 | 9 |
10 |

11 | Slide Menu 12 | v1.2.3 13 |

14 |

A library agnostic multilevel page menu with a smooth slide effect based on CSS transitions.

15 |

16 | Read the documentation here. 17 |

18 | 19 |

Multi-purpose menu (left)

20 |
21 | 29 | 37 | 45 |
46 | 47 |

Navigation menu (right)

48 |
49 | 57 | 65 | 73 | 81 |
82 | 91 | 100 | 109 |
110 | 118 |
119 | 120 |

Events

121 | 122 | 123 |
124 | Made with 125 | 126 | 129 | 130 | by @grubersjoe 131 |
132 |
133 | 134 | 143 | 144 | 246 | 247 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /src/ts/SlideMenu.ts: -------------------------------------------------------------------------------- 1 | import '../styles/slide-menu.scss'; 2 | 3 | import { parents, parentsOne, unwrapElement, wrapElement } from './utils/dom'; 4 | 5 | interface MenuHTMLElement extends HTMLElement { 6 | _slideMenu: SlideMenu; 7 | } 8 | 9 | interface SlideMenuOptions { 10 | backLinkBefore: string; 11 | backLinkAfter: string; 12 | keyOpen: string; 13 | keyClose: string; 14 | position: MenuPosition; 15 | showBackLink: boolean; 16 | submenuLinkBefore: string; 17 | submenuLinkAfter: string; 18 | } 19 | 20 | enum Direction { 21 | Backward = -1, 22 | Forward = 1, 23 | } 24 | 25 | enum MenuPosition { 26 | Left = 'left', 27 | Right = 'right', 28 | } 29 | 30 | enum Action { 31 | Back = 'back', 32 | Close = 'close', 33 | Forward = 'forward', 34 | Navigate = 'navigate', 35 | Open = 'open', 36 | } 37 | 38 | const DEFAULT_OPTIONS = { 39 | backLinkAfter: '', 40 | backLinkBefore: '', 41 | keyClose: '', 42 | keyOpen: '', 43 | position: 'right', 44 | showBackLink: true, 45 | submenuLinkAfter: '', 46 | submenuLinkBefore: '', 47 | }; 48 | 49 | class SlideMenu { 50 | public static readonly NAMESPACE = 'slide-menu'; 51 | public static readonly CLASS_NAMES = { 52 | active: `${SlideMenu.NAMESPACE}__submenu--active`, 53 | backlink: `${SlideMenu.NAMESPACE}__backlink`, 54 | control: `${SlideMenu.NAMESPACE}__control`, 55 | decorator: `${SlideMenu.NAMESPACE}__decorator`, 56 | wrapper: `${SlideMenu.NAMESPACE}__slider`, 57 | }; 58 | 59 | private level: number = 0; 60 | private isOpen: boolean = false; 61 | private isAnimating: boolean = false; 62 | private lastAction: Action | null = null; 63 | 64 | private readonly options: SlideMenuOptions; 65 | 66 | private readonly menuElem: MenuHTMLElement; 67 | private readonly wrapperElem: HTMLElement; 68 | 69 | public constructor(elem: HTMLElement, options?: Partial) { 70 | if (elem === null) { 71 | throw new Error('Argument `elem` must be a valid HTML node'); 72 | } 73 | 74 | // (Create a new object for every instance) 75 | this.options = Object.assign({}, DEFAULT_OPTIONS, options); 76 | 77 | this.menuElem = elem as MenuHTMLElement; 78 | 79 | // Add wrapper (for the slide effect) 80 | this.wrapperElem = document.createElement('div'); 81 | this.wrapperElem.classList.add(SlideMenu.CLASS_NAMES.wrapper); 82 | 83 | const firstUl = this.menuElem.querySelector('ul'); 84 | if (firstUl) { 85 | wrapElement(firstUl, this.wrapperElem); 86 | } 87 | 88 | this.initMenu(); 89 | this.initSubmenus(); 90 | this.initEventHandlers(); 91 | 92 | // Save this instance in menu DOM node 93 | this.menuElem._slideMenu = this; 94 | } 95 | 96 | /** 97 | * Toggle the menu 98 | */ 99 | public toggle(show?: boolean, animate: boolean = true): void { 100 | let offset; 101 | 102 | if (show === undefined) { 103 | return this.isOpen ? this.close(animate) : this.open(animate); 104 | } else if (show) { 105 | offset = 0; 106 | } else { 107 | offset = this.options.position === MenuPosition.Left ? '-100%' : '100%'; 108 | } 109 | 110 | this.isOpen = show; 111 | 112 | if (animate) { 113 | this.moveSlider(this.menuElem, offset); 114 | } else { 115 | const action = this.moveSlider.bind(this, this.menuElem, offset); 116 | this.runWithoutAnimation(action); 117 | } 118 | } 119 | 120 | /** 121 | * Open the menu 122 | */ 123 | public open(animate: boolean = true): void { 124 | this.triggerEvent(Action.Open); 125 | this.toggle(true, animate); 126 | } 127 | 128 | /** 129 | * Close the menu 130 | */ 131 | public close(animate: boolean = true): void { 132 | this.triggerEvent(Action.Close); 133 | this.toggle(false, animate); 134 | } 135 | 136 | /** 137 | * Navigate one menu hierarchy back if possible 138 | */ 139 | public back(): void { 140 | // Event is triggered in navigate() 141 | this.navigate(Direction.Backward); 142 | } 143 | 144 | /** 145 | * Destroy the SlideMenu 146 | */ 147 | public destroy(): void { 148 | const { submenuLinkAfter, submenuLinkBefore, showBackLink } = this.options; 149 | 150 | // Remove link decorators 151 | if (submenuLinkAfter || submenuLinkBefore) { 152 | const linkDecorators = Array.from( 153 | this.wrapperElem.querySelectorAll(`.${SlideMenu.CLASS_NAMES.decorator}`), 154 | ) as HTMLElement[]; 155 | 156 | linkDecorators.forEach((decorator: HTMLElement) => { 157 | if (decorator.parentElement) { 158 | decorator.parentElement.removeChild(decorator); 159 | } 160 | }); 161 | } 162 | 163 | // Remove back links 164 | if (showBackLink) { 165 | const backLinks = Array.from( 166 | this.wrapperElem.querySelectorAll(`.${SlideMenu.CLASS_NAMES.control}`), 167 | ) as HTMLElement[]; 168 | 169 | backLinks.forEach((backlink: HTMLElement) => { 170 | const parentLi = parentsOne(backlink, 'li'); 171 | 172 | if (parentLi && parentLi.parentElement) { 173 | parentLi.parentElement.removeChild(parentLi); 174 | } 175 | }); 176 | } 177 | 178 | // Remove the wrapper element 179 | unwrapElement(this.wrapperElem); 180 | 181 | // Remove inline styles 182 | this.menuElem.style.cssText = ''; 183 | this.menuElem.querySelectorAll('ul').forEach((ul: HTMLElement) => (ul.style.cssText = '')); 184 | 185 | // Delete the reference to *this* instance 186 | // NOTE: Garbage collection is not possible, as long as other references to this object exist 187 | delete this.menuElem._slideMenu; 188 | } 189 | 190 | /** 191 | * Navigate to a specific link on any level (useful to open the correct hierarchy directly) 192 | */ 193 | public navigateTo(target: HTMLElement | string): void { 194 | this.triggerEvent(Action.Navigate); 195 | 196 | if (typeof target === 'string') { 197 | const elem = document.querySelector(target); 198 | if (elem instanceof HTMLElement) { 199 | target = elem; 200 | } else { 201 | throw new Error('Invalid parameter `target`. A valid query selector is required.'); 202 | } 203 | } 204 | 205 | // Hide other active menus 206 | const activeMenus = Array.from( 207 | this.wrapperElem.querySelectorAll(`.${SlideMenu.CLASS_NAMES.active}`), 208 | ) as HTMLElement[]; 209 | 210 | activeMenus.forEach(activeElem => { 211 | activeElem.style.display = 'none'; 212 | activeElem.classList.remove(SlideMenu.CLASS_NAMES.active); 213 | }); 214 | 215 | const parentUl = parents(target, 'ul'); 216 | const level = parentUl.length - 1; 217 | 218 | // Trigger the animation only if currently on different level 219 | if (level >= 0 && level !== this.level) { 220 | this.level = level; 221 | this.moveSlider(this.wrapperElem, -this.level * 100); 222 | } 223 | 224 | parentUl.forEach((ul: HTMLElement) => { 225 | ul.style.display = 'block'; 226 | ul.classList.add(SlideMenu.CLASS_NAMES.active); 227 | }); 228 | } 229 | 230 | /** 231 | * Set up all event handlers 232 | */ 233 | private initEventHandlers(): void { 234 | // Ordinary links inside the menu 235 | const anchors = Array.from(this.menuElem.querySelectorAll('a')); 236 | 237 | anchors.forEach((anchor: HTMLAnchorElement) => 238 | anchor.addEventListener('click', event => { 239 | const target = event.target as HTMLElement; 240 | const targetAnchor = target.matches('a') ? target : parentsOne(target, 'a'); 241 | 242 | if (targetAnchor) { 243 | this.navigate(Direction.Forward, targetAnchor); 244 | } 245 | }), 246 | ); 247 | 248 | // Handler for end of CSS transition 249 | this.menuElem.addEventListener('transitionend', this.onTransitionEnd.bind(this)); 250 | this.wrapperElem.addEventListener('transitionend', this.onTransitionEnd.bind(this)); 251 | 252 | this.initKeybindings(); 253 | this.initSubmenuVisibility(); 254 | } 255 | 256 | private onTransitionEnd(event: Event): void { 257 | // Ensure the transitionEnd event was fired by the correct element 258 | // (elements inside the menu might use CSS transitions as well) 259 | if (event.target !== this.menuElem && event.target !== this.wrapperElem) { 260 | return; 261 | } 262 | 263 | this.isAnimating = false; 264 | 265 | if (this.lastAction) { 266 | this.triggerEvent(this.lastAction, true); 267 | this.lastAction = null; 268 | } 269 | } 270 | 271 | private initKeybindings(): void { 272 | document.addEventListener('keydown', event => { 273 | switch (event.key) { 274 | case this.options.keyClose: 275 | this.close(); 276 | break; 277 | case this.options.keyOpen: 278 | this.open(); 279 | break; 280 | default: 281 | return; 282 | } 283 | 284 | event.preventDefault(); 285 | }); 286 | } 287 | 288 | private initSubmenuVisibility(): void { 289 | // Hide the lastly shown menu when navigating back (important for navigateTo) 290 | this.menuElem.addEventListener('sm.back-after', () => { 291 | const lastActiveSelector = `.${SlideMenu.CLASS_NAMES.active} `.repeat(this.level + 1); 292 | const lastActiveUl = this.menuElem.querySelector( 293 | `ul ${lastActiveSelector}`, 294 | ) as HTMLUListElement; 295 | 296 | if (lastActiveUl) { 297 | lastActiveUl.style.display = 'none'; 298 | lastActiveUl.classList.remove(SlideMenu.CLASS_NAMES.active); 299 | } 300 | }); 301 | } 302 | 303 | /** 304 | * Trigger a custom event to support callbacks 305 | */ 306 | private triggerEvent(action: Action, afterAnimation: boolean = false): void { 307 | this.lastAction = action; 308 | 309 | const name = `sm.${action}${afterAnimation ? '-after' : ''}`; 310 | const event = new CustomEvent(name); 311 | 312 | this.menuElem.dispatchEvent(event); 313 | } 314 | 315 | /** 316 | * Navigate the menu - that is slide it one step left or right 317 | */ 318 | private navigate(dir: Direction = Direction.Forward, anchor?: HTMLElement): void { 319 | if (this.isAnimating || (dir === Direction.Backward && this.level === 0)) { 320 | return; 321 | } 322 | 323 | const offset = (this.level + dir) * -100; 324 | 325 | if (anchor && anchor.parentElement !== null && dir === Direction.Forward) { 326 | const ul = anchor.parentElement.querySelector('ul'); 327 | 328 | if (!ul) { 329 | return; 330 | } 331 | 332 | ul.classList.add(SlideMenu.CLASS_NAMES.active); 333 | ul.style.display = 'block'; 334 | } 335 | 336 | const action = dir === Direction.Forward ? Action.Forward : Action.Back; 337 | this.triggerEvent(action); 338 | 339 | this.level = this.level + dir; 340 | this.moveSlider(this.wrapperElem, offset); 341 | } 342 | 343 | /** 344 | * Start the slide animation (the CSS transition) 345 | */ 346 | private moveSlider(elem: HTMLElement, offset: string | number): void { 347 | // Add percentage sign 348 | if (!offset.toString().includes('%')) { 349 | offset += '%'; 350 | } 351 | 352 | elem.style.transform = `translateX(${offset})`; 353 | this.isAnimating = true; 354 | } 355 | 356 | /** 357 | * Initialize the menu 358 | */ 359 | private initMenu(): void { 360 | this.runWithoutAnimation(() => { 361 | switch (this.options.position) { 362 | case MenuPosition.Left: 363 | Object.assign(this.menuElem.style, { 364 | left: 0, 365 | right: 'auto', 366 | transform: 'translateX(-100%)', 367 | }); 368 | break; 369 | default: 370 | Object.assign(this.menuElem.style, { 371 | left: 'auto', 372 | right: 0, 373 | }); 374 | break; 375 | } 376 | 377 | this.menuElem.style.display = 'block'; 378 | }); 379 | } 380 | 381 | /** 382 | * Pause the CSS transitions, to apply CSS changes directly without an animation 383 | */ 384 | private runWithoutAnimation(action: () => void): void { 385 | const transitionElems = [this.menuElem, this.wrapperElem]; 386 | transitionElems.forEach(elem => (elem.style.transition = 'none')); 387 | 388 | action(); 389 | 390 | this.menuElem.offsetHeight; // Trigger a reflow, flushing the CSS changes 391 | transitionElems.forEach(elem => elem.style.removeProperty('transition')); 392 | 393 | this.isAnimating = false; 394 | } 395 | 396 | /** 397 | * Enhance the markup of menu items which contain a submenu 398 | */ 399 | private initSubmenus(): void { 400 | this.menuElem.querySelectorAll('a').forEach((anchor: HTMLAnchorElement) => { 401 | if (anchor.parentElement === null) { 402 | return; 403 | } 404 | 405 | const submenu = anchor.parentElement.querySelector('ul'); 406 | 407 | if (!submenu) { 408 | return; 409 | } 410 | 411 | // Prevent default behaviour (use link just to navigate) 412 | anchor.addEventListener('click', event => { 413 | event.preventDefault(); 414 | }); 415 | 416 | const anchorText = anchor.textContent; 417 | this.addLinkDecorators(anchor); 418 | 419 | // Add back links 420 | if (this.options.showBackLink) { 421 | const { backLinkBefore, backLinkAfter } = this.options; 422 | 423 | const backLink = document.createElement('a'); 424 | backLink.innerHTML = backLinkBefore + anchorText + backLinkAfter; 425 | backLink.classList.add(SlideMenu.CLASS_NAMES.backlink, SlideMenu.CLASS_NAMES.control); 426 | backLink.setAttribute('data-action', Action.Back); 427 | 428 | const backLinkLi = document.createElement('li'); 429 | backLinkLi.appendChild(backLink); 430 | 431 | submenu.insertBefore(backLinkLi, submenu.firstChild); 432 | } 433 | }); 434 | } 435 | 436 | // Add `before` and `after` text 437 | private addLinkDecorators(anchor: HTMLAnchorElement): HTMLAnchorElement { 438 | const { submenuLinkBefore, submenuLinkAfter } = this.options; 439 | 440 | if (submenuLinkBefore) { 441 | const linkBeforeElem = document.createElement('span'); 442 | linkBeforeElem.classList.add(SlideMenu.CLASS_NAMES.decorator); 443 | linkBeforeElem.innerHTML = submenuLinkBefore; 444 | 445 | anchor.insertBefore(linkBeforeElem, anchor.firstChild); 446 | } 447 | 448 | if (submenuLinkAfter) { 449 | const linkAfterElem = document.createElement('span'); 450 | linkAfterElem.classList.add(SlideMenu.CLASS_NAMES.decorator); 451 | linkAfterElem.innerHTML = submenuLinkAfter; 452 | 453 | anchor.appendChild(linkAfterElem); 454 | } 455 | 456 | return anchor; 457 | } 458 | } 459 | 460 | // Link control buttons with the API 461 | document.addEventListener('click', event => { 462 | if (!(event.target instanceof HTMLElement)) { 463 | return; 464 | } 465 | 466 | const btn = event.target.className.includes(SlideMenu.CLASS_NAMES.control) 467 | ? event.target 468 | : parentsOne(event.target, `.${SlideMenu.CLASS_NAMES.control}`); 469 | 470 | if (!btn || !btn.className.includes(SlideMenu.CLASS_NAMES.control)) { 471 | return; 472 | } 473 | 474 | const target = btn.getAttribute('data-target'); 475 | const menu = 476 | !target || target === 'this' 477 | ? parentsOne(btn, `.${SlideMenu.NAMESPACE}`) 478 | : document.getElementById(target); // assumes #id 479 | 480 | if (!menu) { 481 | throw new Error(`Unable to find menu ${target}`); 482 | } 483 | 484 | const instance = (menu as MenuHTMLElement)._slideMenu; 485 | const method = btn.getAttribute('data-action'); 486 | const arg = btn.getAttribute('data-arg'); 487 | 488 | // @ts-ignore 489 | if (instance && method && typeof instance[method] === 'function') { 490 | // @ts-ignore 491 | arg ? instance[method](arg) : instance[method](); 492 | } 493 | }); 494 | 495 | // Expose SlideMenu to the global namespace 496 | // @ts-ignore 497 | window.SlideMenu = SlideMenu; 498 | -------------------------------------------------------------------------------- /dist/slide-menu.js: -------------------------------------------------------------------------------- 1 | !function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=59)}([function(t,e,n){(function(e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||Function("return this")()}).call(this,n(32))},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e,n){var r=n(1);t.exports=!r((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}))},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(3),o=n(18),i=n(13);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(4);t.exports=function(t){if(!r(t))throw TypeError(String(t)+" is not an object");return t}},function(t,e,n){var r=n(14),o=n(8);t.exports=function(t){return r(o(t))}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){var r=n(0),o=n(5);t.exports=function(t,e){try{o(r,t,e)}catch(n){r[t]=e}return e}},function(t,e,n){var r=n(0),o=n(11).f,i=n(5),c=n(19),s=n(9),a=n(38),u=n(46);t.exports=function(t,e){var n,l,f,p,h,m=t.target,d=t.global,v=t.stat;if(n=d?r:v?r[m]||s(m,{}):(r[m]||{}).prototype)for(l in e){if(p=e[l],f=t.noTargetGet?(h=o(n,l))&&h.value:n[l],!u(d?l:m+(v?".":"#")+l,t.forced)&&void 0!==f){if(typeof p==typeof f)continue;a(p,f)}(t.sham||f&&f.sham)&&i(p,"sham",!0),c(n,l,p,t)}}},function(t,e,n){var r=n(3),o=n(12),i=n(13),c=n(7),s=n(16),a=n(2),u=n(17),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=c(t),e=s(e,!0),u)try{return l(t,e)}catch(t){}if(a(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e,n){"use strict";var r={}.propertyIsEnumerable,o=Object.getOwnPropertyDescriptor,i=o&&!r.call({1:2},1);e.f=i?function(t){var e=o(this,t);return!!e&&e.enumerable}:r},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var r=n(1),o=n(15),i="".split;t.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?i.call(t,""):Object(t)}:Object},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(4);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(3),o=n(1),i=n(33);t.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},function(t,e,n){var r=n(3),o=n(17),i=n(6),c=n(16),s=Object.defineProperty;e.f=r?s:function(t,e,n){if(i(t),e=c(e,!0),i(n),o)try{return s(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){var r=n(0),o=n(5),i=n(2),c=n(9),s=n(20),a=n(34),u=a.get,l=a.enforce,f=String(String).split("String");(t.exports=function(t,e,n,s){var a=!!s&&!!s.unsafe,u=!!s&&!!s.enumerable,p=!!s&&!!s.noTargetGet;"function"==typeof n&&("string"!=typeof e||i(n,"name")||o(n,"name",e),l(n).source=f.join("string"==typeof e?e:"")),t!==r?(a?!p&&t[e]&&(u=!0):delete t[e],u?t[e]=n:o(t,e,n)):u?t[e]=n:c(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&u(this).source||s(this)}))},function(t,e,n){var r=n(21),o=Function.toString;"function"!=typeof r.inspectSource&&(r.inspectSource=function(t){return o.call(t)}),t.exports=r.inspectSource},function(t,e,n){var r=n(0),o=n(9),i=r["__core-js_shared__"]||o("__core-js_shared__",{});t.exports=i},function(t,e,n){var r=n(37),o=n(21);(t.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.1",mode:r?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++n+r).toString(36)}},function(t,e){t.exports={}},function(t,e,n){var r=n(2),o=n(7),i=n(43).indexOf,c=n(24);t.exports=function(t,e){var n,s=o(t),a=0,u=[];for(n in s)!r(c,n)&&r(s,n)&&u.push(n);for(;e.length>a;)r(s,n=e[a++])&&(~i(u,n)||u.push(n));return u}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e,n){var r=n(0),o=n(22),i=n(2),c=n(23),s=n(30),a=n(55),u=o("wks"),l=r.Symbol,f=a?l:l&&l.withoutSetter||c;t.exports=function(t){return i(u,t)||(s&&i(l,t)?u[t]=l[t]:u[t]=f("Symbol."+t)),u[t]}},function(t,e,n){var r=n(1);t.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())}))},function(t,e,n){var r=n(10),o=n(47);r({target:"Object",stat:!0,forced:Object.assign!==o},{assign:o})},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){var r=n(0),o=n(4),i=r.document,c=o(i)&&o(i.createElement);t.exports=function(t){return c?i.createElement(t):{}}},function(t,e,n){var r,o,i,c=n(35),s=n(0),a=n(4),u=n(5),l=n(2),f=n(36),p=n(24),h=s.WeakMap;if(c){var m=new h,d=m.get,v=m.has,g=m.set;r=function(t,e){return g.call(m,t,e),e},o=function(t){return d.call(m,t)||{}},i=function(t){return v.call(m,t)}}else{var E=f("state");p[E]=!0,r=function(t,e){return u(t,E,e),e},o=function(t){return l(t,E)?t[E]:{}},i=function(t){return l(t,E)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!a(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(0),o=n(20),i=r.WeakMap;t.exports="function"==typeof i&&/native code/.test(o(i))},function(t,e,n){var r=n(22),o=n(23),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,e){t.exports=!1},function(t,e,n){var r=n(2),o=n(39),i=n(11),c=n(18);t.exports=function(t,e){for(var n=o(e),s=c.f,a=i.f,u=0;ul;)if((s=a[l++])!=s)return!0}else for(;u>l;l++)if((t||l in a)&&a[l]===n)return t||l||0;return!t&&-1}};t.exports={includes:c(!0),indexOf:c(!1)}},function(t,e,n){var r=n(26),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(26),o=Math.max,i=Math.min;t.exports=function(t,e){var n=r(t);return n<0?o(n+e,0):i(n,e)}},function(t,e,n){var r=n(1),o=/#|\.prototype\./,i=function(t,e){var n=s[c(t)];return n==u||n!=a&&("function"==typeof e?r(e):!!e)},c=i.normalize=function(t){return String(t).replace(o,".").toLowerCase()},s=i.data={},a=i.NATIVE="N",u=i.POLYFILL="P";t.exports=i},function(t,e,n){"use strict";var r=n(3),o=n(1),i=n(48),c=n(28),s=n(12),a=n(49),u=n(14),l=Object.assign,f=Object.defineProperty;t.exports=!l||o((function(){if(r&&1!==l({b:1},l(f({},"a",{enumerable:!0,get:function(){f(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},n=Symbol();return t[n]=7,"abcdefghijklmnopqrst".split("").forEach((function(t){e[t]=t})),7!=l({},t)[n]||"abcdefghijklmnopqrst"!=i(l({},e)).join("")}))?function(t,e){for(var n=a(t),o=arguments.length,l=1,f=c.f,p=s.f;o>l;)for(var h,m=u(arguments[l++]),d=f?i(m).concat(f(m)):i(m),v=d.length,g=0;v>g;)h=d[g++],r&&!p.call(m,h)||(n[h]=m[h]);return n}:l},function(t,e,n){var r=n(25),o=n(27);t.exports=Object.keys||function(t){return r(t,o)}},function(t,e,n){var r=n(8);t.exports=function(t){return Object(r(t))}},function(t,e,n){"use strict";var r=n(19),o=n(6),i=n(1),c=n(51),s=RegExp.prototype,a=s.toString,u=i((function(){return"/a/b"!=a.call({source:"a",flags:"b"})})),l="toString"!=a.name;(u||l)&&r(RegExp.prototype,"toString",(function(){var t=o(this),e=String(t.source),n=t.flags;return"/"+e+"/"+String(void 0===n&&t instanceof RegExp&&!("flags"in s)?c.call(t):n)}),{unsafe:!0})},function(t,e,n){"use strict";var r=n(6);t.exports=function(){var t=r(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.dotAll&&(e+="s"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},function(t,e,n){"use strict";var r=n(10),o=n(53),i=n(8);r({target:"String",proto:!0,forced:!n(56)("includes")},{includes:function(t){return!!~String(i(this)).indexOf(o(t),arguments.length>1?arguments[1]:void 0)}})},function(t,e,n){var r=n(54);t.exports=function(t){if(r(t))throw TypeError("The method doesn't accept regular expressions");return t}},function(t,e,n){var r=n(4),o=n(15),i=n(29)("match");t.exports=function(t){var e;return r(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==o(t))}},function(t,e,n){var r=n(30);t.exports=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},function(t,e,n){var r=n(29)("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[r]=!1,"/./"[t](e)}catch(t){}}return!1}},function(t,e,n){},,function(t,e,n){"use strict";n.r(e);var r,o,i;n(31),n(50),n(52),n(57);function c(t,e,n){const r=[];for(;t&&null!==t.parentElement&&(void 0===n||r.length{t.parentElement&&t.parentElement.removeChild(t)})}if(n){Array.from(this.wrapperElem.querySelectorAll(".".concat(u.CLASS_NAMES.control))).forEach(t=>{const e=s(t,"li");e&&e.parentElement&&e.parentElement.removeChild(e)})}!function(t){const e=t.parentElement;if(null===e)throw Error("`elem` has no parentElement");for(;t.firstChild;)e.insertBefore(t.firstChild,t);e.removeChild(t)}(this.wrapperElem),this.menuElem.style.cssText="",this.menuElem.querySelectorAll("ul").forEach(t=>t.style.cssText=""),delete this.menuElem._slideMenu}navigateTo(t){if(this.triggerEvent(i.Navigate),"string"==typeof t){const e=document.querySelector(t);if(!(e instanceof HTMLElement))throw new Error("Invalid parameter `target`. A valid query selector is required.");t=e}Array.from(this.wrapperElem.querySelectorAll(".".concat(u.CLASS_NAMES.active))).forEach(t=>{t.style.display="none",t.classList.remove(u.CLASS_NAMES.active)});const e=c(t,"ul"),n=e.length-1;n>=0&&n!==this.level&&(this.level=n,this.moveSlider(this.wrapperElem,100*-this.level)),e.forEach(t=>{t.style.display="block",t.classList.add(u.CLASS_NAMES.active)})}initEventHandlers(){Array.from(this.menuElem.querySelectorAll("a")).forEach(t=>t.addEventListener("click",t=>{const e=t.target,n=e.matches("a")?e:s(e,"a");n&&this.navigate(r.Forward,n)})),this.menuElem.addEventListener("transitionend",this.onTransitionEnd.bind(this)),this.wrapperElem.addEventListener("transitionend",this.onTransitionEnd.bind(this)),this.initKeybindings(),this.initSubmenuVisibility()}onTransitionEnd(t){t.target!==this.menuElem&&t.target!==this.wrapperElem||(this.isAnimating=!1,this.lastAction&&(this.triggerEvent(this.lastAction,!0),this.lastAction=null))}initKeybindings(){document.addEventListener("keydown",t=>{switch(t.key){case this.options.keyClose:this.close();break;case this.options.keyOpen:this.open();break;default:return}t.preventDefault()})}initSubmenuVisibility(){this.menuElem.addEventListener("sm.back-after",()=>{const t=".".concat(u.CLASS_NAMES.active," ").repeat(this.level+1),e=this.menuElem.querySelector("ul ".concat(t));e&&(e.style.display="none",e.classList.remove(u.CLASS_NAMES.active))})}triggerEvent(t,e=!1){this.lastAction=t;const n="sm.".concat(t).concat(e?"-after":""),r=new CustomEvent(n);this.menuElem.dispatchEvent(r)}navigate(t=r.Forward,e){if(this.isAnimating||t===r.Backward&&0===this.level)return;const n=-100*(this.level+t);if(e&&null!==e.parentElement&&t===r.Forward){const t=e.parentElement.querySelector("ul");if(!t)return;t.classList.add(u.CLASS_NAMES.active),t.style.display="block"}const o=t===r.Forward?i.Forward:i.Back;this.triggerEvent(o),this.level=this.level+t,this.moveSlider(this.wrapperElem,n)}moveSlider(t,e){e.toString().includes("%")||(e+="%"),t.style.transform="translateX(".concat(e,")"),this.isAnimating=!0}initMenu(){this.runWithoutAnimation(()=>{switch(this.options.position){case o.Left:Object.assign(this.menuElem.style,{left:0,right:"auto",transform:"translateX(-100%)"});break;default:Object.assign(this.menuElem.style,{left:"auto",right:0})}this.menuElem.style.display="block"})}runWithoutAnimation(t){const e=[this.menuElem,this.wrapperElem];e.forEach(t=>t.style.transition="none"),t(),this.menuElem.offsetHeight,e.forEach(t=>t.style.removeProperty("transition")),this.isAnimating=!1}initSubmenus(){this.menuElem.querySelectorAll("a").forEach(t=>{if(null===t.parentElement)return;const e=t.parentElement.querySelector("ul");if(!e)return;t.addEventListener("click",t=>{t.preventDefault()});const n=t.textContent;if(this.addLinkDecorators(t),this.options.showBackLink){const{backLinkBefore:t,backLinkAfter:r}=this.options,o=document.createElement("a");o.innerHTML=t+n+r,o.classList.add(u.CLASS_NAMES.backlink,u.CLASS_NAMES.control),o.setAttribute("data-action",i.Back);const c=document.createElement("li");c.appendChild(o),e.insertBefore(c,e.firstChild)}})}addLinkDecorators(t){const{submenuLinkBefore:e,submenuLinkAfter:n}=this.options;if(e){const n=document.createElement("span");n.classList.add(u.CLASS_NAMES.decorator),n.innerHTML=e,t.insertBefore(n,t.firstChild)}if(n){const e=document.createElement("span");e.classList.add(u.CLASS_NAMES.decorator),e.innerHTML=n,t.appendChild(e)}return t}}u.NAMESPACE="slide-menu",u.CLASS_NAMES={active:"".concat(u.NAMESPACE,"__submenu--active"),backlink:"".concat(u.NAMESPACE,"__backlink"),control:"".concat(u.NAMESPACE,"__control"),decorator:"".concat(u.NAMESPACE,"__decorator"),wrapper:"".concat(u.NAMESPACE,"__slider")},document.addEventListener("click",t=>{if(!(t.target instanceof HTMLElement))return;const e=t.target.className.includes(u.CLASS_NAMES.control)?t.target:s(t.target,".".concat(u.CLASS_NAMES.control));if(!e||!e.className.includes(u.CLASS_NAMES.control))return;const n=e.getAttribute("data-target"),r=n&&"this"!==n?document.getElementById(n):s(e,".".concat(u.NAMESPACE));if(!r)throw new Error("Unable to find menu ".concat(n));const o=r._slideMenu,i=e.getAttribute("data-action"),c=e.getAttribute("data-arg");o&&i&&"function"==typeof o[i]&&(c?o[i](c):o[i]())}),window.SlideMenu=u}]); -------------------------------------------------------------------------------- /docs/slide-menu.js: -------------------------------------------------------------------------------- 1 | !function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=59)}([function(t,e,n){(function(e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||Function("return this")()}).call(this,n(32))},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e,n){var r=n(1);t.exports=!r((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}))},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(3),o=n(18),i=n(13);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(4);t.exports=function(t){if(!r(t))throw TypeError(String(t)+" is not an object");return t}},function(t,e,n){var r=n(14),o=n(8);t.exports=function(t){return r(o(t))}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){var r=n(0),o=n(5);t.exports=function(t,e){try{o(r,t,e)}catch(n){r[t]=e}return e}},function(t,e,n){var r=n(0),o=n(11).f,i=n(5),c=n(19),s=n(9),a=n(38),u=n(46);t.exports=function(t,e){var n,l,f,p,h,m=t.target,d=t.global,v=t.stat;if(n=d?r:v?r[m]||s(m,{}):(r[m]||{}).prototype)for(l in e){if(p=e[l],f=t.noTargetGet?(h=o(n,l))&&h.value:n[l],!u(d?l:m+(v?".":"#")+l,t.forced)&&void 0!==f){if(typeof p==typeof f)continue;a(p,f)}(t.sham||f&&f.sham)&&i(p,"sham",!0),c(n,l,p,t)}}},function(t,e,n){var r=n(3),o=n(12),i=n(13),c=n(7),s=n(16),a=n(2),u=n(17),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=c(t),e=s(e,!0),u)try{return l(t,e)}catch(t){}if(a(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e,n){"use strict";var r={}.propertyIsEnumerable,o=Object.getOwnPropertyDescriptor,i=o&&!r.call({1:2},1);e.f=i?function(t){var e=o(this,t);return!!e&&e.enumerable}:r},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var r=n(1),o=n(15),i="".split;t.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?i.call(t,""):Object(t)}:Object},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(4);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(3),o=n(1),i=n(33);t.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},function(t,e,n){var r=n(3),o=n(17),i=n(6),c=n(16),s=Object.defineProperty;e.f=r?s:function(t,e,n){if(i(t),e=c(e,!0),i(n),o)try{return s(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){var r=n(0),o=n(5),i=n(2),c=n(9),s=n(20),a=n(34),u=a.get,l=a.enforce,f=String(String).split("String");(t.exports=function(t,e,n,s){var a=!!s&&!!s.unsafe,u=!!s&&!!s.enumerable,p=!!s&&!!s.noTargetGet;"function"==typeof n&&("string"!=typeof e||i(n,"name")||o(n,"name",e),l(n).source=f.join("string"==typeof e?e:"")),t!==r?(a?!p&&t[e]&&(u=!0):delete t[e],u?t[e]=n:o(t,e,n)):u?t[e]=n:c(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&u(this).source||s(this)}))},function(t,e,n){var r=n(21),o=Function.toString;"function"!=typeof r.inspectSource&&(r.inspectSource=function(t){return o.call(t)}),t.exports=r.inspectSource},function(t,e,n){var r=n(0),o=n(9),i=r["__core-js_shared__"]||o("__core-js_shared__",{});t.exports=i},function(t,e,n){var r=n(37),o=n(21);(t.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.1",mode:r?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++n+r).toString(36)}},function(t,e){t.exports={}},function(t,e,n){var r=n(2),o=n(7),i=n(43).indexOf,c=n(24);t.exports=function(t,e){var n,s=o(t),a=0,u=[];for(n in s)!r(c,n)&&r(s,n)&&u.push(n);for(;e.length>a;)r(s,n=e[a++])&&(~i(u,n)||u.push(n));return u}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e,n){var r=n(0),o=n(22),i=n(2),c=n(23),s=n(30),a=n(55),u=o("wks"),l=r.Symbol,f=a?l:l&&l.withoutSetter||c;t.exports=function(t){return i(u,t)||(s&&i(l,t)?u[t]=l[t]:u[t]=f("Symbol."+t)),u[t]}},function(t,e,n){var r=n(1);t.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())}))},function(t,e,n){var r=n(10),o=n(47);r({target:"Object",stat:!0,forced:Object.assign!==o},{assign:o})},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){var r=n(0),o=n(4),i=r.document,c=o(i)&&o(i.createElement);t.exports=function(t){return c?i.createElement(t):{}}},function(t,e,n){var r,o,i,c=n(35),s=n(0),a=n(4),u=n(5),l=n(2),f=n(36),p=n(24),h=s.WeakMap;if(c){var m=new h,d=m.get,v=m.has,g=m.set;r=function(t,e){return g.call(m,t,e),e},o=function(t){return d.call(m,t)||{}},i=function(t){return v.call(m,t)}}else{var E=f("state");p[E]=!0,r=function(t,e){return u(t,E,e),e},o=function(t){return l(t,E)?t[E]:{}},i=function(t){return l(t,E)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!a(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(0),o=n(20),i=r.WeakMap;t.exports="function"==typeof i&&/native code/.test(o(i))},function(t,e,n){var r=n(22),o=n(23),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,e){t.exports=!1},function(t,e,n){var r=n(2),o=n(39),i=n(11),c=n(18);t.exports=function(t,e){for(var n=o(e),s=c.f,a=i.f,u=0;ul;)if((s=a[l++])!=s)return!0}else for(;u>l;l++)if((t||l in a)&&a[l]===n)return t||l||0;return!t&&-1}};t.exports={includes:c(!0),indexOf:c(!1)}},function(t,e,n){var r=n(26),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(26),o=Math.max,i=Math.min;t.exports=function(t,e){var n=r(t);return n<0?o(n+e,0):i(n,e)}},function(t,e,n){var r=n(1),o=/#|\.prototype\./,i=function(t,e){var n=s[c(t)];return n==u||n!=a&&("function"==typeof e?r(e):!!e)},c=i.normalize=function(t){return String(t).replace(o,".").toLowerCase()},s=i.data={},a=i.NATIVE="N",u=i.POLYFILL="P";t.exports=i},function(t,e,n){"use strict";var r=n(3),o=n(1),i=n(48),c=n(28),s=n(12),a=n(49),u=n(14),l=Object.assign,f=Object.defineProperty;t.exports=!l||o((function(){if(r&&1!==l({b:1},l(f({},"a",{enumerable:!0,get:function(){f(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},n=Symbol();return t[n]=7,"abcdefghijklmnopqrst".split("").forEach((function(t){e[t]=t})),7!=l({},t)[n]||"abcdefghijklmnopqrst"!=i(l({},e)).join("")}))?function(t,e){for(var n=a(t),o=arguments.length,l=1,f=c.f,p=s.f;o>l;)for(var h,m=u(arguments[l++]),d=f?i(m).concat(f(m)):i(m),v=d.length,g=0;v>g;)h=d[g++],r&&!p.call(m,h)||(n[h]=m[h]);return n}:l},function(t,e,n){var r=n(25),o=n(27);t.exports=Object.keys||function(t){return r(t,o)}},function(t,e,n){var r=n(8);t.exports=function(t){return Object(r(t))}},function(t,e,n){"use strict";var r=n(19),o=n(6),i=n(1),c=n(51),s=RegExp.prototype,a=s.toString,u=i((function(){return"/a/b"!=a.call({source:"a",flags:"b"})})),l="toString"!=a.name;(u||l)&&r(RegExp.prototype,"toString",(function(){var t=o(this),e=String(t.source),n=t.flags;return"/"+e+"/"+String(void 0===n&&t instanceof RegExp&&!("flags"in s)?c.call(t):n)}),{unsafe:!0})},function(t,e,n){"use strict";var r=n(6);t.exports=function(){var t=r(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.dotAll&&(e+="s"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},function(t,e,n){"use strict";var r=n(10),o=n(53),i=n(8);r({target:"String",proto:!0,forced:!n(56)("includes")},{includes:function(t){return!!~String(i(this)).indexOf(o(t),arguments.length>1?arguments[1]:void 0)}})},function(t,e,n){var r=n(54);t.exports=function(t){if(r(t))throw TypeError("The method doesn't accept regular expressions");return t}},function(t,e,n){var r=n(4),o=n(15),i=n(29)("match");t.exports=function(t){var e;return r(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==o(t))}},function(t,e,n){var r=n(30);t.exports=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},function(t,e,n){var r=n(29)("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[r]=!1,"/./"[t](e)}catch(t){}}return!1}},function(t,e,n){},,function(t,e,n){"use strict";n.r(e);var r,o,i;n(31),n(50),n(52),n(57);function c(t,e,n){const r=[];for(;t&&null!==t.parentElement&&(void 0===n||r.length{t.parentElement&&t.parentElement.removeChild(t)})}if(n){Array.from(this.wrapperElem.querySelectorAll(".".concat(u.CLASS_NAMES.control))).forEach(t=>{const e=s(t,"li");e&&e.parentElement&&e.parentElement.removeChild(e)})}!function(t){const e=t.parentElement;if(null===e)throw Error("`elem` has no parentElement");for(;t.firstChild;)e.insertBefore(t.firstChild,t);e.removeChild(t)}(this.wrapperElem),this.menuElem.style.cssText="",this.menuElem.querySelectorAll("ul").forEach(t=>t.style.cssText=""),delete this.menuElem._slideMenu}navigateTo(t){if(this.triggerEvent(i.Navigate),"string"==typeof t){const e=document.querySelector(t);if(!(e instanceof HTMLElement))throw new Error("Invalid parameter `target`. A valid query selector is required.");t=e}Array.from(this.wrapperElem.querySelectorAll(".".concat(u.CLASS_NAMES.active))).forEach(t=>{t.style.display="none",t.classList.remove(u.CLASS_NAMES.active)});const e=c(t,"ul"),n=e.length-1;n>=0&&n!==this.level&&(this.level=n,this.moveSlider(this.wrapperElem,100*-this.level)),e.forEach(t=>{t.style.display="block",t.classList.add(u.CLASS_NAMES.active)})}initEventHandlers(){Array.from(this.menuElem.querySelectorAll("a")).forEach(t=>t.addEventListener("click",t=>{const e=t.target,n=e.matches("a")?e:s(e,"a");n&&this.navigate(r.Forward,n)})),this.menuElem.addEventListener("transitionend",this.onTransitionEnd.bind(this)),this.wrapperElem.addEventListener("transitionend",this.onTransitionEnd.bind(this)),this.initKeybindings(),this.initSubmenuVisibility()}onTransitionEnd(t){t.target!==this.menuElem&&t.target!==this.wrapperElem||(this.isAnimating=!1,this.lastAction&&(this.triggerEvent(this.lastAction,!0),this.lastAction=null))}initKeybindings(){document.addEventListener("keydown",t=>{switch(t.key){case this.options.keyClose:this.close();break;case this.options.keyOpen:this.open();break;default:return}t.preventDefault()})}initSubmenuVisibility(){this.menuElem.addEventListener("sm.back-after",()=>{const t=".".concat(u.CLASS_NAMES.active," ").repeat(this.level+1),e=this.menuElem.querySelector("ul ".concat(t));e&&(e.style.display="none",e.classList.remove(u.CLASS_NAMES.active))})}triggerEvent(t,e=!1){this.lastAction=t;const n="sm.".concat(t).concat(e?"-after":""),r=new CustomEvent(n);this.menuElem.dispatchEvent(r)}navigate(t=r.Forward,e){if(this.isAnimating||t===r.Backward&&0===this.level)return;const n=-100*(this.level+t);if(e&&null!==e.parentElement&&t===r.Forward){const t=e.parentElement.querySelector("ul");if(!t)return;t.classList.add(u.CLASS_NAMES.active),t.style.display="block"}const o=t===r.Forward?i.Forward:i.Back;this.triggerEvent(o),this.level=this.level+t,this.moveSlider(this.wrapperElem,n)}moveSlider(t,e){e.toString().includes("%")||(e+="%"),t.style.transform="translateX(".concat(e,")"),this.isAnimating=!0}initMenu(){this.runWithoutAnimation(()=>{switch(this.options.position){case o.Left:Object.assign(this.menuElem.style,{left:0,right:"auto",transform:"translateX(-100%)"});break;default:Object.assign(this.menuElem.style,{left:"auto",right:0})}this.menuElem.style.display="block"})}runWithoutAnimation(t){const e=[this.menuElem,this.wrapperElem];e.forEach(t=>t.style.transition="none"),t(),this.menuElem.offsetHeight,e.forEach(t=>t.style.removeProperty("transition")),this.isAnimating=!1}initSubmenus(){this.menuElem.querySelectorAll("a").forEach(t=>{if(null===t.parentElement)return;const e=t.parentElement.querySelector("ul");if(!e)return;t.addEventListener("click",t=>{t.preventDefault()});const n=t.textContent;if(this.addLinkDecorators(t),this.options.showBackLink){const{backLinkBefore:t,backLinkAfter:r}=this.options,o=document.createElement("a");o.innerHTML=t+n+r,o.classList.add(u.CLASS_NAMES.backlink,u.CLASS_NAMES.control),o.setAttribute("data-action",i.Back);const c=document.createElement("li");c.appendChild(o),e.insertBefore(c,e.firstChild)}})}addLinkDecorators(t){const{submenuLinkBefore:e,submenuLinkAfter:n}=this.options;if(e){const n=document.createElement("span");n.classList.add(u.CLASS_NAMES.decorator),n.innerHTML=e,t.insertBefore(n,t.firstChild)}if(n){const e=document.createElement("span");e.classList.add(u.CLASS_NAMES.decorator),e.innerHTML=n,t.appendChild(e)}return t}}u.NAMESPACE="slide-menu",u.CLASS_NAMES={active:"".concat(u.NAMESPACE,"__submenu--active"),backlink:"".concat(u.NAMESPACE,"__backlink"),control:"".concat(u.NAMESPACE,"__control"),decorator:"".concat(u.NAMESPACE,"__decorator"),wrapper:"".concat(u.NAMESPACE,"__slider")},document.addEventListener("click",t=>{if(!(t.target instanceof HTMLElement))return;const e=t.target.className.includes(u.CLASS_NAMES.control)?t.target:s(t.target,".".concat(u.CLASS_NAMES.control));if(!e||!e.className.includes(u.CLASS_NAMES.control))return;const n=e.getAttribute("data-target"),r=n&&"this"!==n?document.getElementById(n):s(e,".".concat(u.NAMESPACE));if(!r)throw new Error("Unable to find menu ".concat(n));const o=r._slideMenu,i=e.getAttribute("data-action"),c=e.getAttribute("data-arg");o&&i&&"function"==typeof o[i]&&(c?o[i](c):o[i]())}),window.SlideMenu=u}]); -------------------------------------------------------------------------------- /dist/slide-menu.ie.js: -------------------------------------------------------------------------------- 1 | !function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=102)}([function(t,e,n){var r=n(1),o=n(35),i=n(3),a=n(36),c=n(43),u=n(62),s=o("wks"),f=r.Symbol,l=u?f:f&&f.withoutSetter||a;t.exports=function(t){return i(s,t)||(c&&i(f,t)?s[t]=f[t]:s[t]=l("Symbol."+t)),s[t]}},function(t,e,n){(function(e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||Function("return this")()}).call(this,n(54))},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(4);t.exports=function(t){if(!r(t))throw TypeError(String(t)+" is not an object");return t}},function(t,e,n){var r=n(1),o=n(28).f,i=n(7),a=n(14),c=n(21),u=n(56),s=n(61);t.exports=function(t,e){var n,f,l,p,v,h=t.target,d=t.global,m=t.stat;if(n=d?r:m?r[h]||c(h,{}):(r[h]||{}).prototype)for(f in e){if(p=e[f],l=t.noTargetGet?(v=o(n,f))&&v.value:n[f],!s(d?f:h+(m?".":"#")+f,t.forced)&&void 0!==l){if(typeof p==typeof l)continue;u(p,l)}(t.sham||l&&l.sham)&&i(p,"sham",!0),a(n,f,p,t)}}},function(t,e,n){var r=n(8),o=n(9),i=n(12);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(2);t.exports=!r((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}))},function(t,e,n){var r=n(8),o=n(30),i=n(5),a=n(20),c=Object.defineProperty;e.f=r?c:function(t,e,n){if(i(t),e=a(e,!0),i(n),o)try{return c(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){var r=n(10);t.exports=function(t){return Object(r(t))}},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(1),o=n(7),i=n(3),a=n(21),c=n(32),u=n(34),s=u.get,f=u.enforce,l=String(String).split("String");(t.exports=function(t,e,n,c){var u=!!c&&!!c.unsafe,s=!!c&&!!c.enumerable,p=!!c&&!!c.noTargetGet;"function"==typeof n&&("string"!=typeof e||i(n,"name")||o(n,"name",e),f(n).source=l.join("string"==typeof e?e:"")),t!==r?(u?!p&&t[e]&&(s=!0):delete t[e],s?t[e]=n:o(t,e,n)):s?t[e]=n:a(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&s(this).source||c(this)}))},function(t,e,n){var r=n(16),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e){t.exports={}},function(t,e,n){var r=n(19),o=n(10);t.exports=function(t){return r(o(t))}},function(t,e,n){var r=n(2),o=n(13),i="".split;t.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?i.call(t,""):Object(t)}:Object},function(t,e,n){var r=n(4);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(1),o=n(7);t.exports=function(t,e){try{o(r,t,e)}catch(n){r[t]=e}return e}},function(t,e,n){var r=n(35),o=n(36),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,e){t.exports=!1},function(t,e){t.exports={}},function(t,e,n){var r=n(58),o=n(1),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][e]||o[t]&&o[t][e]}},function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,e,n){var r={};r[n(0)("toStringTag")]="z",t.exports="[object z]"===String(r)},function(t,e,n){var r=n(8),o=n(29),i=n(12),a=n(18),c=n(20),u=n(3),s=n(30),f=Object.getOwnPropertyDescriptor;e.f=r?f:function(t,e){if(t=a(t),e=c(e,!0),s)try{return f(t,e)}catch(t){}if(u(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e,n){"use strict";var r={}.propertyIsEnumerable,o=Object.getOwnPropertyDescriptor,i=o&&!r.call({1:2},1);e.f=i?function(t){var e=o(this,t);return!!e&&e.enumerable}:r},function(t,e,n){var r=n(8),o=n(2),i=n(31);t.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},function(t,e,n){var r=n(1),o=n(4),i=r.document,a=o(i)&&o(i.createElement);t.exports=function(t){return a?i.createElement(t):{}}},function(t,e,n){var r=n(33),o=Function.toString;"function"!=typeof r.inspectSource&&(r.inspectSource=function(t){return o.call(t)}),t.exports=r.inspectSource},function(t,e,n){var r=n(1),o=n(21),i=r["__core-js_shared__"]||o("__core-js_shared__",{});t.exports=i},function(t,e,n){var r,o,i,a=n(55),c=n(1),u=n(4),s=n(7),f=n(3),l=n(22),p=n(24),v=c.WeakMap;if(a){var h=new v,d=h.get,m=h.has,y=h.set;r=function(t,e){return y.call(h,t,e),e},o=function(t){return d.call(h,t)||{}},i=function(t){return m.call(h,t)}}else{var g=l("state");p[g]=!0,r=function(t,e){return s(t,g,e),e},o=function(t){return f(t,g)?t[g]:{}},i=function(t){return f(t,g)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!u(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(23),o=n(33);(t.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.1",mode:r?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++n+r).toString(36)}},function(t,e,n){var r=n(3),o=n(18),i=n(38).indexOf,a=n(24);t.exports=function(t,e){var n,c=o(t),u=0,s=[];for(n in c)!r(a,n)&&r(c,n)&&s.push(n);for(;e.length>u;)r(c,n=e[u++])&&(~i(s,n)||s.push(n));return s}},function(t,e,n){var r=n(18),o=n(15),i=n(60),a=function(t){return function(e,n,a){var c,u=r(e),s=o(u.length),f=i(a,s);if(t&&n!=n){for(;s>f;)if((c=u[f++])!=c)return!0}else for(;s>f;f++)if((t||f in u)&&u[f]===n)return t||f||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e,n){var r=n(13);t.exports=Array.isArray||function(t){return"Array"==r(t)}},function(t,e,n){"use strict";var r=n(20),o=n(9),i=n(12);t.exports=function(t,e,n){var a=r(e);a in t?o.f(t,a,i(0,n)):t[a]=n}},function(t,e,n){var r=n(4),o=n(40),i=n(0)("species");t.exports=function(t,e){var n;return o(t)&&("function"!=typeof(n=t.constructor)||n!==Array&&!o(n.prototype)?r(n)&&null===(n=n[i])&&(n=void 0):n=void 0),new(void 0===n?Array:n)(0===e?0:e)}},function(t,e,n){var r=n(2);t.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())}))},function(t,e,n){var r,o,i=n(1),a=n(64),c=i.process,u=c&&c.versions,s=u&&u.v8;s?o=(r=s.split("."))[0]+r[1]:a&&(!(r=a.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=a.match(/Chrome\/(\d+)/))&&(o=r[1]),t.exports=o&&+o},function(t,e,n){var r=n(67);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r=n(27),o=n(13),i=n(0)("toStringTag"),a="Arguments"==o(function(){return arguments}());t.exports=r?o:function(t){var e,n,r;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),i))?n:a?o(e):"Object"==(r=o(e))&&"function"==typeof e.callee?"Arguments":r}},function(t,e,n){var r,o=n(5),i=n(74),a=n(26),c=n(24),u=n(75),s=n(31),f=n(22),l=f("IE_PROTO"),p=function(){},v=function(t){return"