├── .browserslistrc
├── .commitlintrc.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .huskyrc.js
├── .npmignore
├── .nvmrc
├── .prettierignore
├── .prettierrc.js
├── .stylelintignore
├── .stylelintrc.js
├── .vscode
├── extensions.json
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── babel.config.js
├── build
├── rollup.config.vue2.js
└── rollup.config.vue3.js
├── changelog.config.js
├── dev
├── vue2
│ ├── .nvmrc
│ ├── cdn_usage.html
│ ├── package.json
│ ├── serve.js
│ ├── serve.vue
│ └── yarn.lock
└── vue3
│ ├── .nvmrc
│ ├── cdn_usage.html
│ ├── package.json
│ ├── serve.js
│ ├── serve.vue
│ └── yarn.lock
├── dist
├── vue2
│ ├── index.js
│ ├── v-dropdown-menu.cjs
│ ├── v-dropdown-menu.css
│ ├── v-dropdown-menu.global.js
│ ├── v-dropdown-menu.global.min.js
│ ├── v-dropdown-menu.min.cjs
│ ├── v-dropdown-menu.min.mjs
│ ├── v-dropdown-menu.mjs
│ ├── v-dropdown-menu.umd.js
│ └── v-dropdown-menu.umd.min.js
└── vue3
│ ├── index.js
│ ├── v-dropdown-menu.cjs
│ ├── v-dropdown-menu.css
│ ├── v-dropdown-menu.global.js
│ ├── v-dropdown-menu.global.min.js
│ ├── v-dropdown-menu.min.cjs
│ ├── v-dropdown-menu.min.mjs
│ ├── v-dropdown-menu.mjs
│ ├── v-dropdown-menu.umd.js
│ └── v-dropdown-menu.umd.min.js
├── docs
├── .eslintignore
├── .eslintrc.cjs
├── .gitignore
├── .npmrc
├── .nvmrc
├── README.md
├── app.config.ts
├── components
│ ├── AppDropdown.vue
│ ├── AppDropdownAdvanced.vue
│ ├── AppDropdownWithCloser.vue
│ └── AppSpinner.vue
├── content
│ ├── 0.index.md
│ ├── 1.guide
│ │ ├── 0.index.md
│ │ ├── 1.registration
│ │ │ ├── 0.vue3.md
│ │ │ └── 1.vue2.md
│ │ ├── 2.usage.md
│ │ └── _dir.yml
│ └── 2.demo.md
├── nuxt.config.ts
├── package.json
├── public
│ ├── favicon.ico
│ └── media
│ │ ├── logo.png
│ │ └── preview.jpg
├── renovate.json
├── tokens.config.ts
├── tsconfig.json
└── yarn.lock
├── meta
├── logo.png
└── preview.jpg
├── package.json
├── shims-vue.d.ts
├── src
├── vue2
│ ├── entry.js
│ ├── v-dropdown-menu.scss
│ └── v-dropdown-menu.vue
└── vue3
│ ├── entry.js
│ ├── v-dropdown-menu.scss
│ └── v-dropdown-menu.vue
├── tsconfig.json
├── vue2
├── README.md
└── index.js
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | current node
2 | last 2 versions and > 2%
3 | ie > 10
4 |
--------------------------------------------------------------------------------
/.commitlintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["@commitlint/config-conventional"]
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | end_of_line = crlf
7 | charset = utf-8
8 | indent_size = 2
9 | tab_width = 2
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | /vue2
3 | /vue3
4 | /docs
5 | /meta
6 | coverage
7 | node_modules
8 | package.json
9 | package-lock.json
10 | yarn.lock
11 | pnpm-lock.yaml
12 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | jest: true
7 | },
8 | parser: 'vue-eslint-parser',
9 | parserOptions: {
10 | parser: '@typescript-eslint/parser',
11 | sourceType: 'module',
12 | ecmaFeatures: {
13 | legacyDecorators: true
14 | },
15 | warnOnUnsupportedTypeScriptVersion: false,
16 | templateTokenizer: {
17 | pug: 'vue-eslint-parser-template-tokenizer-pug'
18 | }
19 | },
20 | extends: ['plugin:vue/strongly-recommended', 'eslint-config-prettier', 'prettier'],
21 | plugins: ['@typescript-eslint', 'prettier'],
22 | rules: {
23 | 'prettier/prettier': [
24 | 'error',
25 | {
26 | endOfLine: 'crlf'
27 | }
28 | ],
29 | 'max-len': [
30 | 'error',
31 | {
32 | code: 150,
33 | ignoreComments: true,
34 | ignoreStrings: true,
35 | ignoreTemplateLiterals: true
36 | }
37 | ],
38 | 'no-multiple-empty-lines': [2, { max: 2 }],
39 | semi: ['error', 'never'],
40 | 'arrow-parens': ['error', 'as-needed'],
41 | 'no-extend-native': 'off',
42 | 'space-before-function-paren': 'off',
43 | camelcase: 'off',
44 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
45 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
46 | 'no-throw-literal': 'off',
47 | 'no-param-reassign': [
48 | 'error',
49 | {
50 | props: false
51 | }
52 | ],
53 | '@typescript-eslint/no-var-requires': 'off',
54 | 'vue/component-definition-name-casing': ['error', 'PascalCase'],
55 | 'vue/multi-word-component-names': 'off',
56 | 'vue/component-tags-order': ['error', { order: ['template', 'script', 'style', 'docs'] }],
57 | 'vue/padding-line-between-blocks': ['error'],
58 | 'vue/block-lang': [
59 | 'error',
60 | {
61 | script: {
62 | allowNoLang: true,
63 | lang: 'ts'
64 | },
65 | style: {
66 | allowNoLang: true,
67 | lang: 'scss'
68 | }
69 | }
70 | ],
71 | 'vue/no-empty-component-block': 'off',
72 | 'vue/valid-template-root': 'off',
73 | 'vue/no-static-inline-styles': 'off',
74 | 'vue/require-prop-types': ['error'],
75 | 'vue/require-default-prop': ['error'],
76 | 'vue/attribute-hyphenation': ['error', 'always'],
77 | 'vue/v-on-event-hyphenation': ['error', 'always'],
78 | 'vue/html-self-closing': 'off',
79 | 'vue/no-v-html': 'off',
80 | 'vue/order-in-components': ['error'],
81 | 'padding-line-between-statements': [
82 | 'error',
83 | { blankLine: 'always', prev: '*', next: 'return' },
84 | { blankLine: 'always', prev: '*', next: 'if' },
85 | { blankLine: 'always', prev: '*', next: 'switch' },
86 | { blankLine: 'always', prev: '*', next: 'for' },
87 | { blankLine: 'always', prev: '*', next: 'function' },
88 | { blankLine: 'never', prev: 'import', next: 'import' },
89 | { blankLine: 'always', prev: 'import', next: 'export' },
90 | { blankLine: 'always', prev: 'expression', next: 'export' },
91 | { blankLine: 'always', prev: 'import', next: 'expression' }
92 | ]
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # This file has been generated using '.gitattributes Generator'.
2 | # You can generate yours at http://ihopepeace.github.io/gitattributes_generator
3 |
4 | * text=auto
5 |
6 | # Explicitly declare text files that should be normalized and converted
7 | # to native line endings on checkout.
8 |
9 | # Declare files that should have CRLF line endings on checkout.
10 | *.js eol=crlf
11 | *.ts eol=crlf
12 | *.vue eol=crlf
13 | *.css eol=crlf
14 | *.scss eol=crlf
15 | *.json eol=crlf
16 |
17 | # Declare files that should have LF line endings on checkout.
18 |
19 | # Declare files that are truly binary and shouldn't be modified.
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Node template
2 | # Logs
3 | logs
4 | *.log
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 |
9 | # Runtime data
10 | pids
11 | *.pid
12 | *.seed
13 | *.pid.lock
14 |
15 | # Directory for instrumented libs generated by jscoverage/JSCover
16 | lib-cov
17 |
18 | # Coverage directory used by tools like istanbul
19 | coverage
20 |
21 | # nyc test coverage
22 | .nyc_output
23 |
24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
25 | .grunt
26 |
27 | # Bower dependency directory (https://bower.io/)
28 | bower_components
29 |
30 | # node-waf configuration
31 | .lock-wscript
32 |
33 | # Dependency directories
34 | node_modules/
35 | jspm_packages/
36 | package-lock.json
37 |
38 | # TypeScript v1 declaration files
39 | typings/
40 |
41 | # Optional npm cache directory
42 | .npm
43 |
44 | # Optional eslint cache
45 | .eslintcache
46 |
47 | # Optional REPL history
48 | .node_repl_history
49 |
50 | # Output of 'npm pack'
51 | *.tgz
52 |
53 | # Yarn Integrity file
54 | .yarn-integrity
55 |
56 | # dotenv environment variables file
57 | .env
58 |
59 | # parcel-bundler cache (https://parceljs.org/)
60 | .cache
61 |
62 | # next.js build output
63 | .next
64 |
65 | # nuxt.js build output
66 | .nuxt
67 |
68 | # vuepress build output
69 | .vuepress/dist
70 |
71 | # Serverless directories
72 | .serverless
73 |
74 | # IDE
75 | .idea
76 |
77 | # Service worker
78 | sw.*
79 |
80 | #misc
81 | demo/node_modules
82 |
--------------------------------------------------------------------------------
/.huskyrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | hooks: {
3 | 'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS',
4 | 'pre-commit': 'lint-staged'
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | ./demo
2 | ./dev
3 | ./docs
4 | .vscode
5 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v18.x.x
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | /vue2
3 | /vue3
4 | /docs
5 | /meta
6 | coverage
7 | node_modules
8 | package.json
9 | package-lock.json
10 | yarn.lock
11 | pnpm-lock.yaml
12 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | pugPrintWidth: 140,
3 | pugSingleQuote: false,
4 | pugAttributeSeparator: 'none',
5 | pugEmptyAttributes: 'none',
6 | singleQuote: true,
7 | printWidth: 140,
8 | trailingComma: 'none',
9 | tabWidth: 2,
10 | semi: false,
11 | bracketSpacing: true,
12 | arrowParens: 'avoid',
13 | pugSortAttributesBeginning: [
14 | '^cols$',
15 | '^v-else$',
16 | '^v-for$',
17 | '^:key$',
18 | '^v-if$',
19 | '^v-else-if$',
20 | '^v-on$',
21 | '^v-bind$',
22 | '^ref$',
23 | '^v-model',
24 | '^name$',
25 | '^:?type$',
26 | '^:value$',
27 | '^v-text$',
28 | '^:?label$',
29 | '^:headers$',
30 | '^:items$',
31 | '^:?item-text$',
32 | '^:?item-value$',
33 | '^:?item-disabled$',
34 | '^:?placeholder$',
35 | '^:?src$',
36 | '^:?color$',
37 | '^:?text-color$',
38 | '^:?icon$',
39 | '^:?small$'
40 | ],
41 | pugSortAttributesEnd: [
42 | '^:?hint$',
43 | '^:?persistent-hint$',
44 | '^prepend-',
45 | '^@click:prepend',
46 | '^append-',
47 | '^@click:append',
48 | '^:to$',
49 | '^exact$',
50 | '^:(?!(width|height|loading|disabled|data-))',
51 | '^target$',
52 | '^:?width$',
53 | '^:?height$',
54 | '^:loading$',
55 | '^:disabled$',
56 | '^:?data-',
57 | '^@click',
58 | '^@'
59 | ]
60 | }
61 |
--------------------------------------------------------------------------------
/.stylelintignore:
--------------------------------------------------------------------------------
1 | dist
2 | /vue2
3 | /docs
4 | /meta
5 | *.min.*
6 | assets/**/*/vendor
7 | static/
8 | public/
9 |
--------------------------------------------------------------------------------
/.stylelintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | //https://github.com/constverum/stylelint-config-rational-order
4 | 'stylelint-config-rational-order',
5 | // https://github.com/shannonmoeller/stylelint-config-prettier
6 | 'stylelint-config-prettier'
7 | ],
8 | overrides: [
9 | {
10 | customSyntax: 'postcss-scss',
11 | files: ['**/*.{css,sass,scss,less,stylus}']
12 | },
13 | {
14 | customSyntax: 'postcss-html',
15 | files: ['*.vue', '**/*.vue']
16 | }
17 | ],
18 | plugins: [
19 | // https://github.com/kristerkari/stylelint-scss#list-of-rules
20 | 'stylelint-scss',
21 | // https://github.com/hudochenkov/stylelint-order
22 | 'stylelint-order',
23 | 'stylelint-config-rational-order/plugin'
24 | ],
25 | rules: {
26 | indentation: [
27 | 2,
28 | {
29 | baseIndentLevel: 0
30 | }
31 | ],
32 | 'color-named': 'never',
33 | 'color-function-notation': 'legacy',
34 | 'at-rule-no-unknown': null,
35 | 'declaration-empty-line-before': [
36 | 'always',
37 | {
38 | except: ['after-declaration'],
39 | ignore: ['after-comment', 'first-nested', 'inside-single-line-block'],
40 | severity: 'warning'
41 | }
42 | ],
43 | 'rule-empty-line-before': [
44 | 'always',
45 | {
46 | ignore: ['after-comment', 'first-nested'],
47 | severity: 'warning'
48 | }
49 | ]
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "dbaeumer.vscode-eslint",
4 | "stylelint.vscode-stylelint",
5 | "editorconfig.editorconfig",
6 | "octref.vetur",
7 | "fallenmax.mithril-emmet"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "emmet.showAbbreviationSuggestions": true,
3 | "emmet.showExpandedAbbreviation": "always",
4 | "emmet.includeLanguages": {
5 | "vue-html": "html",
6 | "vue": "jade"
7 | },
8 | "files.insertFinalNewline": true,
9 | "editor.insertSpaces": true,
10 | "editor.detectIndentation": false,
11 | "css.validate": false,
12 | "less.validate": false,
13 | "scss.validate": false,
14 | "stylelint.validate": ["css", "scss", "html", "vue"],
15 | "editor.codeActionsOnSave": {
16 | "source.fixAll.stylelint": true,
17 | "source.fixAll.eslint": true
18 | },
19 | "editor.tabSize": 2,
20 | "explorer.compactFolders": false
21 | }
22 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v2.0.4
4 |
5 | [compare changes](https://github.com/selimdoyranli/v-dropdown-menu/compare/v2.0.3...v2.0.4)
6 |
7 |
8 | ### 🩹 Fixes
9 |
10 | - Css file export fix ([92f78c8](https://github.com/selimdoyranli/v-dropdown-menu/commit/92f78c8))
11 |
12 | ### ❤️ Contributors
13 |
14 | - Selimdoyranli ([@selimdoyranli](http://github.com/selimdoyranli))
15 |
16 | ## v2.0.3
17 |
18 | [compare changes](https://github.com/selimdoyranli/v-dropdown-menu/compare/e3f1570...v2.0.3)
19 |
20 |
21 | ### 🏡 Chore
22 |
23 | - Rebrand ([18c431f](https://github.com/selimdoyranli/v-dropdown-menu/commit/18c431f))
24 |
25 | ### ❤️ Contributors
26 |
27 | - Selimdoyranli ([@selimdoyranli](http://github.com/selimdoyranli))
28 |
29 | ## v2.0.2
30 |
31 | [compare changes](https://github.com/selimdoyranli/v-dropdown-menu/compare/v2.0.1...v2.0.2)
32 |
33 |
34 | ### 📖 Documentation
35 |
36 | - Update docs ([2976033](https://github.com/selimdoyranli/v-dropdown-menu/commit/2976033))
37 |
38 | ### 📦 Build
39 |
40 | - Update npm scripts ([a9a69a2](https://github.com/selimdoyranli/v-dropdown-menu/commit/a9a69a2))
41 |
42 | ### 🏡 Chore
43 |
44 | - Changelog rename ([ac3ac3b](https://github.com/selimdoyranli/v-dropdown-menu/commit/ac3ac3b))
45 | - Changelog rename ([2a925ea](https://github.com/selimdoyranli/v-dropdown-menu/commit/2a925ea))
46 |
47 | ### ❤️ Contributors
48 |
49 | - Selimdoyranli ([@selimdoyranli](http://github.com/selimdoyranli))
50 |
51 | ## v2.0.1
52 |
53 | [compare changes](https://github.com/selimdoyranli/v-dropdown-menu/compare/e3c1f82...v2.0.1)
54 |
55 |
56 | ### 💅 Refactors
57 |
58 | - **build:** Refactor build ([90590fd](https://github.com/selimdoyranli/v-dropdown-menu/commit/90590fd))
59 |
60 | ### ❤️ Contributors
61 |
62 | - Selimdoyranli ([@selimdoyranli](http://github.com/selimdoyranli))
63 |
64 | ## v2.0.0
65 |
66 | [compare changes](https://github.com/selimdoyranli/v-dropdown-menu/compare/1.3.1...v2.0.0)
67 |
68 |
69 | ### 🚀 Enhancements
70 |
71 | - Vue3 support ([095b053](https://github.com/selimdoyranli/v-dropdown-menu/commit/095b053))
72 |
73 | ### 🎨 Styles
74 |
75 | - Code formatting ([2a268c1](https://github.com/selimdoyranli/v-dropdown-menu/commit/2a268c1))
76 |
77 | ### ❤️ Contributors
78 |
79 | - Selimdoyranli ([@selimdoyranli](http://github.com/selimdoyranli))
80 |
81 | ## 1.3.2
82 |
83 | - Added isOpen prop watcher. You can use external trigger.
84 | ## 1.3.1
85 |
86 | - Doc updated
87 |
88 | ## 1.3.0
89 |
90 | - Transition feature
91 | - Css hover > vue modifier hover
92 | - Renames (menuZIndex prop name > containerZIndex)
93 | - Clean code
94 |
95 | ## 1.2.0
96 |
97 | - Dropup feature
98 | - Callbacks feature
99 | - dropdown-closer class > dropdown-closer attribute
100 | - Improved ux
101 |
102 | ## 1.1.2 >=
103 | Base developments.
104 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 selimdoyranli
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 | [![npm version][npm-version-src]][npm-version-href]
2 | [![npm downloads][npm-downloads-src]][npm-downloads-href]
3 | [![changelog][changelog-src]][changelog-href]
4 | [![License][license-src]][license-href]
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | v-dropdown-menu
14 |
15 |
16 |
17 | Customizable dropdown menu for vue 🟩🔽
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Website
32 |
33 |
34 |
39 |
40 | ## Features
41 | - ⚡️ Lightweight
42 | - 🎨 Interactive
43 | - 🛠️ Customizable
44 | - 👶🏻 Easy implementation
45 | - 📦 Vue2 & Vue3 support
46 | - 💉 SSR compatible
47 |
48 | ## Getting Started
49 |
50 | ### Try it Online ⚡️
51 |
52 | [DEMO](https://v-dropdown-menu.vercel.app/demo)
53 |
54 |
55 | ## Installation
56 |
57 | ```js
58 | yarn add v-dropdown-menu # or npm i v-dropdown-menu
59 | ```
60 |
61 | ### Vue3
62 |
63 | #### Global Register
64 |
65 | ```js
66 | import { createApp } from 'vue'
67 | import App from './App.vue'
68 | import DropdownMenu from 'v-dropdown-menu'
69 | import 'v-dropdown-menu/css'
70 |
71 | const app = createApp(App)
72 |
73 | app.use(DropdownMenu)
74 | app.mount('#app')
75 | ```
76 |
77 | #### Local Register
78 | ```html
79 |
83 | ```
84 | #### Via CDN
85 | ```js
86 |
87 |
88 |
89 |
90 |
96 | ```
97 |
98 | ### Vue2
99 |
100 | #### Global Register
101 |
102 | ```js
103 | import Vue from "vue"
104 | import DropdownMenu from "v-dropdown-menu/vue2"
105 | import 'v-dropdown-menu/vue2/css'
106 |
107 | Vue.use(DropdownMenu);
108 | ```
109 |
110 | #### Local Register
111 | ```js
112 | import DropdownMenu from "v-dropdown-menu/vue2"
113 | import 'v-dropdown-menu/vue2/css'
114 |
115 | export default {
116 | components: {
117 | DropdownMenu
118 | }
119 | }
120 | ```
121 | #### Via CDN
122 | ```js
123 |
124 |
125 |
126 |
127 |
134 | ```
135 |
136 |
137 | ### Usage
138 |
139 | ```html
140 |
141 |
142 |
143 |
144 |
145 | Dropdown Header
146 |
147 |
148 |
153 |
154 |
155 | Dropdown Footer
156 |
157 |
158 | ```
159 |
160 | #### Props
161 | | Name | Description | Type| Options| Default |
162 | |--|--|--|--|--|
163 | |isOpen|Show or hide for dropdown|Boolean|`true` , `false` | false
164 | |mode|Open variant|String|`click` , `hover` | click
165 | | dropup |Open the menu upwards | Boolean | `true` , `false` | false
166 | |direction|Menu container direction|String|`left` , `right` , `center` | left
167 | |closeOnClickOutside|closes dropdown menu when click outside|Booelan|`true` , `false` | true
168 | |withDropdownCloser| If there is an element in the menu with **dropdown-closer** attribute, clicking on it closes the menu.|Boolean|`true` , `false` | false
169 | |containerZIndex|z-index of menu container|String| .| 994
170 | |overlay|background overlay of dropdown menu (only for click mode) |Boolean| `true` , `false`| true
171 | |overlayBgColor|background-color of overlay |String| ex: `rgba(1, 35, 83, 0.8)`| rgba(0, 0, 0, 0.2)
172 | |overlayZIndex|z-index of overlay|String| .| 992
173 | |transition|custom vue transition for menu|String| .| default
174 |
175 | #### Slots
176 | |Name| Description |
177 | |--|--|
178 | |trigger|trigger for dropdown menu |
179 | |header|header of menu container (optional)|
180 | |body|content of menu (optional)|
181 | |footer|footer of menu container (optional)|
182 |
183 | #### Events (only for click mode)
184 | | |
185 | |--|
186 | | `@opened="dispatchEvent"`|
187 | | `@closed="dispatchEvent"`|
188 |
189 |
190 | ---
191 |
192 | ## Development
193 |
194 | ### Vue3
195 |
196 | ```bash
197 | yarn build:vue3 # build for vue3
198 | ```
199 |
200 | ```bash
201 | # Serve
202 |
203 | cd dev/vue3
204 |
205 | yarn install
206 | yarn serve
207 | ```
208 |
209 | ### Vue2
210 |
211 | ```bash
212 | yarn build:vue2 # build for vue2
213 | ```
214 |
215 | ```bash
216 | # Serve
217 |
218 | cd dev/vue2
219 |
220 | yarn install
221 | yarn serve
222 | ```
223 |
224 | ### Vue 2&3
225 |
226 | ```bash
227 | yarn build # build for vue2 and vue3
228 | ```
229 |
230 | #### Linter
231 |
232 | ```bash
233 | # run eslint
234 | yarn lint:eslint
235 |
236 | # run eslint fix
237 | yarn lint:eslint:fix
238 |
239 | # run stylelint
240 | yarn lint:stylelint
241 |
242 | # run stylelint fix
243 | yarn lint:stylelint:fix
244 |
245 | # run prettier
246 | yarn prettier
247 |
248 | ```
249 |
250 | ## Sponsorship
251 |
252 | You can sponsor me for the continuity of my projects:
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 | ## License
267 |
268 | [MIT License](./LICENSE)
269 |
270 | Copyright (c) selimdoyranli
271 |
272 |
273 | [npm-version-src]: https://img.shields.io/npm/v/v-dropdown-menu/latest.svg
274 | [npm-version-href]: https://npmjs.com/package/v-dropdown-menu
275 |
276 | [npm-downloads-src]: https://img.shields.io/npm/dt/v-dropdown-menu.svg
277 | [npm-downloads-href]: https://npmjs.com/package/v-dropdown-menu
278 |
279 | [codecov-src]: https://img.shields.io/codecov/c/github/selimdoyranli/v-dropdown-menu.svg
280 | [codecov-href]: https://codecov.io/gh/selimdoyranli/v-dropdown-menu
281 |
282 | [changelog-src]: https://img.shields.io/static/v1?label=%F0%9F%93%96&message=Release%20Notes%20|%20CHANGELOG&color=blue
283 | [changelog-href]: ./CHANGELOG.md
284 |
285 | [license-src]: https://img.shields.io/badge/License-MIT-blue.svg
286 | [license-href]: https://npmjs.com/package/v-dropdown-menu/LICENSE
287 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | const devPresets = ['@vue/babel-preset-app']
2 | const buildPresets = [
3 | [
4 | '@babel/preset-env',
5 | // Config for @babel/preset-env
6 | {
7 | // Example: Always transpile optional chaining/nullish coalescing
8 | // include: [
9 | // /(optional-chaining|nullish-coalescing)/
10 | // ],
11 | }
12 | ],
13 | '@babel/preset-typescript'
14 | ]
15 | module.exports = {
16 | presets: process.env.NODE_ENV === 'development' ? devPresets : buildPresets
17 | }
18 |
--------------------------------------------------------------------------------
/build/rollup.config.vue2.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs'
2 | import path from 'path'
3 | import vue from 'vue-prev-rollup-plugin-vue'
4 | import alias from '@rollup/plugin-alias'
5 | import commonjs from '@rollup/plugin-commonjs'
6 | import replace from '@rollup/plugin-replace'
7 | import babel from '@rollup/plugin-babel'
8 | import css from 'rollup-plugin-css-only'
9 | import { terser } from 'rollup-plugin-terser'
10 | import minimist from 'minimist'
11 |
12 | // Get browserslist config and remove ie from es build targets
13 | const esbrowserslist = fs
14 | .readFileSync('./.browserslistrc')
15 | .toString()
16 | .split('\n')
17 | .filter(entry => entry && entry.substring(0, 2) !== 'ie')
18 |
19 | const argv = minimist(process.argv.slice(2))
20 |
21 | const projectRoot = path.resolve(__dirname, '..')
22 |
23 | const baseConfig = {
24 | input: 'src/vue2/entry.js',
25 | plugins: {
26 | preVue: [
27 | alias({
28 | resolve: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
29 | entries: {
30 | '@': path.resolve(projectRoot, 'src')
31 | }
32 | })
33 | ],
34 | replace: {
35 | 'process.env.NODE_ENV': JSON.stringify('production'),
36 | 'process.env.ES_BUILD': JSON.stringify('false'),
37 | preventAssignment: true
38 | },
39 | css: {
40 | output: 'dist/vue2/v-dropdown-menu.css'
41 | },
42 | vue: {
43 | css: false,
44 | template: {
45 | isProduction: true
46 | }
47 | },
48 | babel: {
49 | exclude: 'node_modules/**',
50 | extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
51 | babelHelpers: 'bundled'
52 | },
53 | terser: {}
54 | }
55 | }
56 |
57 | // ESM/UMD/IIFE shared settings: externals
58 | // Refer to https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
59 | const external = [
60 | // list external dependencies, exactly the way it is written in the import statement.
61 | // eg. 'jquery'
62 | 'vue'
63 | ]
64 |
65 | // UMD/IIFE shared settings: output.globals
66 | // Refer to https://rollupjs.org/guide/en#output-globals for details
67 | const globals = {
68 | // Provide global variable names to replace your external imports
69 | // eg. jquery: '$'
70 | vue: 'Vue'
71 | }
72 |
73 | // Customize configs for individual targets
74 | const buildFormats = []
75 |
76 | if (!argv.format || argv.format === 'umd') {
77 | const umdConfig = {
78 | ...baseConfig,
79 | external,
80 | output: [
81 | {
82 | file: 'vue2/index.js',
83 | format: 'umd',
84 | exports: 'named',
85 | globals,
86 | name: 'DropdownMenu',
87 | plugins: [
88 | terser({
89 | ...baseConfig.plugins.terser
90 | })
91 | ]
92 | },
93 | {
94 | file: 'dist/vue2/index.js',
95 | format: 'umd',
96 | exports: 'named',
97 | globals,
98 | name: 'DropdownMenu',
99 | plugins: [
100 | terser({
101 | ...baseConfig.plugins.terser
102 | })
103 | ]
104 | },
105 | {
106 | file: 'dist/vue2/v-dropdown-menu.umd.js',
107 | format: 'umd',
108 | exports: 'named',
109 | globals,
110 | name: 'DropdownMenu'
111 | },
112 | {
113 | file: 'dist/vue2/v-dropdown-menu.umd.min.js',
114 | format: 'umd',
115 | exports: 'named',
116 | globals,
117 | name: 'DropdownMenu',
118 | plugins: [
119 | terser({
120 | ...baseConfig.plugins.terser
121 | })
122 | ]
123 | },
124 | {
125 | file: 'dist/vue2/v-dropdown-menu.global.js',
126 | format: 'umd',
127 | globals,
128 | name: 'DropdownMenu'
129 | },
130 | {
131 | file: 'dist/vue2/v-dropdown-menu.global.min.js',
132 | format: 'umd',
133 | globals,
134 | name: 'DropdownMenu',
135 | plugins: [
136 | terser({
137 | ...baseConfig.plugins.terser
138 | })
139 | ]
140 | }
141 | ],
142 | plugins: [
143 | replace({
144 | ...baseConfig.plugins.replace
145 | }),
146 | ...baseConfig.plugins.preVue,
147 | css({
148 | ...baseConfig.plugins.css
149 | }),
150 | vue({
151 | ...baseConfig.plugins.vue
152 | }),
153 | babel({
154 | ...baseConfig.plugins.babel,
155 | presets: [
156 | [
157 | '@babel/preset-env',
158 | {
159 | targets: esbrowserslist
160 | }
161 | ]
162 | ]
163 | }),
164 | commonjs()
165 | ]
166 | }
167 | buildFormats.push(umdConfig)
168 | }
169 |
170 | if (!argv.format || argv.format === 'es') {
171 | const esConfig = {
172 | ...baseConfig,
173 | external,
174 | output: [
175 | {
176 | file: 'dist/vue2/v-dropdown-menu.mjs',
177 | format: 'esm',
178 | exports: 'named'
179 | },
180 | {
181 | file: 'dist/vue2/v-dropdown-menu.min.mjs',
182 | format: 'esm',
183 | exports: 'named',
184 | plugins: [
185 | terser({
186 | ...baseConfig.plugins.terser
187 | })
188 | ]
189 | }
190 | ],
191 | plugins: [
192 | replace({
193 | ...baseConfig.plugins.replace,
194 | 'process.env.ES_BUILD': JSON.stringify('true')
195 | }),
196 | ...baseConfig.plugins.preVue,
197 | css({
198 | ...baseConfig.plugins.css
199 | }),
200 | vue({
201 | ...baseConfig.plugins.vue
202 | }),
203 | babel({
204 | ...baseConfig.plugins.babel,
205 | presets: [
206 | [
207 | '@babel/preset-env',
208 | {
209 | targets: esbrowserslist
210 | }
211 | ]
212 | ]
213 | }),
214 | commonjs()
215 | ]
216 | }
217 | buildFormats.push(esConfig)
218 | }
219 |
220 | if (!argv.format || argv.format === 'cjs') {
221 | const cjsConfig = {
222 | ...baseConfig,
223 | external,
224 | output: [
225 | {
226 | compact: true,
227 | file: 'dist/vue2/v-dropdown-menu.cjs',
228 | format: 'cjs',
229 | name: 'DropdownMenu',
230 | exports: 'named',
231 | globals
232 | },
233 | {
234 | compact: true,
235 | file: 'dist/vue2/v-dropdown-menu.min.cjs',
236 | format: 'cjs',
237 | name: 'DropdownMenu',
238 | exports: 'named',
239 | globals,
240 | plugins: [
241 | terser({
242 | ...baseConfig.plugins.terser
243 | })
244 | ]
245 | }
246 | ],
247 | plugins: [
248 | replace(baseConfig.plugins.replace),
249 | ...baseConfig.plugins.preVue,
250 | css({
251 | ...baseConfig.plugins.css
252 | }),
253 | vue({
254 | ...baseConfig.plugins.vue,
255 | template: {
256 | ...baseConfig.plugins.vue.template,
257 | optimizeSSR: true
258 | }
259 | }),
260 | babel(baseConfig.plugins.babel),
261 | commonjs()
262 | ]
263 | }
264 | buildFormats.push(cjsConfig)
265 | }
266 |
267 | // Export config
268 | export default buildFormats
269 |
--------------------------------------------------------------------------------
/build/rollup.config.vue3.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs'
2 | import path from 'path'
3 | import vue from 'vue-next-rollup-plugin-vue'
4 | import alias from '@rollup/plugin-alias'
5 | import commonjs from '@rollup/plugin-commonjs'
6 | import replace from '@rollup/plugin-replace'
7 | import babel from '@rollup/plugin-babel'
8 | import scss from 'rollup-plugin-scss'
9 | import css from 'rollup-plugin-css-only'
10 | import { terser } from 'rollup-plugin-terser'
11 | import minimist from 'minimist'
12 |
13 | // Get browserslist config and remove ie from es build targets
14 | const esbrowserslist = fs
15 | .readFileSync('./.browserslistrc')
16 | .toString()
17 | .split('\n')
18 | .filter(entry => entry && entry.substring(0, 2) !== 'ie')
19 |
20 | const argv = minimist(process.argv.slice(2))
21 |
22 | const projectRoot = path.resolve(__dirname, '..')
23 |
24 | const baseConfig = {
25 | input: 'src/vue3/entry.js',
26 | plugins: {
27 | preVue: [
28 | alias({
29 | resolve: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
30 | entries: {
31 | '@': path.resolve(projectRoot, 'src')
32 | }
33 | })
34 | ],
35 | replace: {
36 | 'process.env.NODE_ENV': JSON.stringify('production'),
37 | 'process.env.ES_BUILD': JSON.stringify('false'),
38 | preventAssignment: true
39 | },
40 | scss: {
41 | fileName: 'v-dropdown-menu.css',
42 | outputStyle: 'compressed'
43 | },
44 | css: {
45 | output: 'dist/vue3/v-dropdown-menu.css'
46 | },
47 | vue: {
48 | css: false,
49 | template: {
50 | isProduction: true
51 | }
52 | },
53 | babel: {
54 | exclude: 'node_modules/**',
55 | extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
56 | babelHelpers: 'bundled'
57 | },
58 | terser: {}
59 | }
60 | }
61 |
62 | // ESM/UMD/IIFE shared settings: externals
63 | // Refer to https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
64 | const external = [
65 | // list external dependencies, exactly the way it is written in the import statement.
66 | // eg. 'jquery'
67 | 'vue'
68 | ]
69 |
70 | // UMD/IIFE shared settings: output.globals
71 | // Refer to https://rollupjs.org/guide/en#output-globals for details
72 | const globals = {
73 | // Provide global variable names to replace your external imports
74 | // eg. jquery: '$'
75 | vue: 'Vue'
76 | }
77 |
78 | // Customize configs for individual targets
79 | const buildFormats = []
80 |
81 | if (!argv.format || argv.format === 'umd') {
82 | const umdConfig = {
83 | ...baseConfig,
84 | external,
85 | output: [
86 | {
87 | file: 'dist/vue3/index.js',
88 | format: 'umd',
89 | exports: 'named',
90 | globals,
91 | name: 'DropdownMenu',
92 | plugins: [
93 | terser({
94 | ...baseConfig.plugins.terser
95 | })
96 | ]
97 | },
98 | {
99 | file: 'dist/vue3/v-dropdown-menu.umd.js',
100 | format: 'umd',
101 | exports: 'named',
102 | globals,
103 | name: 'DropdownMenu'
104 | },
105 | {
106 | file: 'dist/vue3/v-dropdown-menu.umd.min.js',
107 | format: 'umd',
108 | exports: 'named',
109 | globals,
110 | name: 'DropdownMenu',
111 | plugins: [
112 | terser({
113 | ...baseConfig.plugins.terser
114 | })
115 | ]
116 | },
117 | {
118 | file: 'dist/vue3/v-dropdown-menu.global.js',
119 | format: 'umd',
120 | globals,
121 | name: 'DropdownMenu'
122 | },
123 | {
124 | file: 'dist/vue3/v-dropdown-menu.global.min.js',
125 | format: 'umd',
126 | globals,
127 | name: 'DropdownMenu',
128 | plugins: [
129 | terser({
130 | ...baseConfig.plugins.terser
131 | })
132 | ]
133 | }
134 | ],
135 | plugins: [
136 | replace({
137 | ...baseConfig.plugins.replace
138 | }),
139 | ...baseConfig.plugins.preVue,
140 | scss({
141 | ...baseConfig.plugins.scss
142 | }),
143 | css({
144 | ...baseConfig.plugins.css
145 | }),
146 | vue({
147 | ...baseConfig.plugins.vue
148 | }),
149 | babel({
150 | ...baseConfig.plugins.babel,
151 | presets: [
152 | [
153 | '@babel/preset-env',
154 | {
155 | targets: esbrowserslist
156 | }
157 | ]
158 | ]
159 | }),
160 | commonjs()
161 | ]
162 | }
163 | buildFormats.push(umdConfig)
164 | }
165 |
166 | if (!argv.format || argv.format === 'es') {
167 | const esConfig = {
168 | ...baseConfig,
169 | external,
170 | output: [
171 | {
172 | file: 'dist/vue3/v-dropdown-menu.mjs',
173 | format: 'esm',
174 | exports: 'named'
175 | },
176 | {
177 | file: 'dist/vue3/v-dropdown-menu.min.mjs',
178 | format: 'esm',
179 | exports: 'named',
180 | plugins: [
181 | terser({
182 | ...baseConfig.plugins.terser
183 | })
184 | ]
185 | }
186 | ],
187 | plugins: [
188 | replace({
189 | ...baseConfig.plugins.replace,
190 | 'process.env.ES_BUILD': JSON.stringify('true')
191 | }),
192 | ...baseConfig.plugins.preVue,
193 | scss({
194 | ...baseConfig.plugins.scss
195 | }),
196 | css({
197 | ...baseConfig.plugins.css
198 | }),
199 | vue({
200 | ...baseConfig.plugins.vue
201 | }),
202 | babel({
203 | ...baseConfig.plugins.babel,
204 | presets: [
205 | [
206 | '@babel/preset-env',
207 | {
208 | targets: esbrowserslist
209 | }
210 | ]
211 | ]
212 | }),
213 | commonjs()
214 | ]
215 | }
216 | buildFormats.push(esConfig)
217 | }
218 |
219 | if (!argv.format || argv.format === 'cjs') {
220 | const cjsConfig = {
221 | ...baseConfig,
222 | external,
223 | output: [
224 | {
225 | compact: true,
226 | file: 'dist/vue3/v-dropdown-menu.cjs',
227 | format: 'cjs',
228 | name: 'DropdownMenu',
229 | exports: 'named',
230 | globals
231 | },
232 | {
233 | compact: true,
234 | file: 'dist/vue3/v-dropdown-menu.min.cjs',
235 | format: 'cjs',
236 | name: 'DropdownMenu',
237 | exports: 'named',
238 | globals,
239 | plugins: [
240 | terser({
241 | ...baseConfig.plugins.terser
242 | })
243 | ]
244 | }
245 | ],
246 | plugins: [
247 | replace(baseConfig.plugins.replace),
248 | ...baseConfig.plugins.preVue,
249 | scss({
250 | ...baseConfig.plugins.scss
251 | }),
252 | css({
253 | ...baseConfig.plugins.css
254 | }),
255 | vue({
256 | ...baseConfig.plugins.vue,
257 | template: {
258 | ...baseConfig.plugins.vue.template,
259 | optimizeSSR: true
260 | }
261 | }),
262 | babel(baseConfig.plugins.babel),
263 | commonjs()
264 | ]
265 | }
266 | buildFormats.push(cjsConfig)
267 | }
268 |
269 | // Export config
270 | export default buildFormats
271 |
--------------------------------------------------------------------------------
/changelog.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | types: {
3 | feat: { title: '🚀 Enhancements', semver: 'minor' },
4 | perf: { title: '🔥 Performance', semver: 'patch' },
5 | fix: { title: '🩹 Fixes', semver: 'patch' },
6 | refactor: { title: '💅 Refactors', semver: 'patch' },
7 | docs: { title: '📖 Documentation', semver: 'patch' },
8 | build: { title: '📦 Build', semver: 'patch' },
9 | types: { title: '🌊 Types', semver: 'patch' },
10 | chore: { title: '🏡 Chore' },
11 | examples: { title: '🏀 Examples' },
12 | test: { title: '✅ Tests' },
13 | style: { title: '🎨 Styles' },
14 | ci: { title: '🤖 CI' }
15 | },
16 | cwd: null,
17 | from: '',
18 | to: '',
19 | output: 'CHANGELOG.md',
20 | scopeMap: {},
21 | tokens: {
22 | github: process.env.CHANGELOGEN_TOKENS_GITHUB || process.env.GITHUB_TOKEN || process.env.GH_TOKEN
23 | },
24 | templates: {
25 | commitMessage: 'chore(release): v{{newVersion}}',
26 | tagMessage: 'v{{newVersion}}',
27 | tagBody: 'v{{newVersion}}'
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/dev/vue2/.nvmrc:
--------------------------------------------------------------------------------
1 | v16.x.x
2 |
--------------------------------------------------------------------------------
/dev/vue2/cdn_usage.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Dropdown Header
20 |
21 |
22 |
27 |
28 |
29 | Dropdown Footer
30 |
31 |
32 |
33 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/dev/vue2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "v-dropdown-menu-vue2-serve",
3 | "scripts": {
4 | "serve": "vue-cli-service serve serve.js"
5 | },
6 | "dependencies": {},
7 | "devDependencies": {
8 | "@vue/cli-service": "^4.5.10",
9 | "vue": "^2.6.12"
10 | },
11 | "peerDependencies": {
12 | "vue": "^2.6.12"
13 | },
14 | "engines": {
15 | "node": ">=12"
16 | },
17 | "license": "MIT"
18 | }
19 |
--------------------------------------------------------------------------------
/dev/vue2/serve.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Dev from './serve.vue'
3 |
4 | Vue.config.productionTip = false
5 |
6 | new Vue({
7 | render: h => h(Dev)
8 | }).$mount('#app')
9 |
--------------------------------------------------------------------------------
/dev/vue2/serve.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Dropdown Header
9 |
10 |
11 |
16 |
17 |
18 | Dropdown Footer
19 |
20 |
21 |
22 |
23 |
34 |
--------------------------------------------------------------------------------
/dev/vue3/.nvmrc:
--------------------------------------------------------------------------------
1 | v16.x.x
2 |
--------------------------------------------------------------------------------
/dev/vue3/cdn_usage.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Dropdown Header
20 |
21 |
22 |
27 |
28 |
29 | Dropdown Footer
30 |
31 |
32 |
33 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/dev/vue3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "v-dropdown-menu-vue3-serve",
3 | "scripts": {
4 | "serve": "vue-cli-service serve serve.js"
5 | },
6 | "dependencies": {},
7 | "devDependencies": {
8 | "@vue/cli-service": "^4.5.10",
9 | "vue": "^3.0.0"
10 | },
11 | "peerDependencies": {
12 | "vue": "^3.0.0"
13 | },
14 | "engines": {
15 | "node": ">=12"
16 | },
17 | "license": "MIT"
18 | }
19 |
--------------------------------------------------------------------------------
/dev/vue3/serve.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import Dev from './serve.vue'
3 |
4 | const app = createApp(Dev)
5 | app.mount('#app')
6 |
--------------------------------------------------------------------------------
/dev/vue3/serve.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Dropdown Header
9 |
10 |
11 |
16 |
17 |
18 | Dropdown Footer
19 |
20 |
21 |
22 |
23 |
27 |
--------------------------------------------------------------------------------
/dist/vue2/index.js:
--------------------------------------------------------------------------------
1 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).DropdownMenu={})}(this,(function(e){"use strict";function n(e,n,t,o,i,s,r,d,l,a){"boolean"!=typeof r&&(l=d,d=r,r=!1);const u="function"==typeof t?t.options:t;let p;if(e&&e.render&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns,u._compiled=!0,i&&(u.functional=!0)),o&&(u._scopeId=o),s?(p=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,l(e)),e&&e._registeredComponents&&e._registeredComponents.add(s)},u._ssrRegister=p):n&&(p=r?function(e){n.call(this,a(e,this.$root.$options.shadowRoot))}:function(e){n.call(this,d(e))}),p)if(u.functional){const e=u.render;u.render=function(n,t){return p.call(t),e(n,t)}}else{const e=u.beforeCreate;u.beforeCreate=e?[].concat(e,p):[p]}return t}const t=n({render:function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",{ref:"rootRef",staticClass:"v-dropdown-menu",class:[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]},["click"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{click:function(n){n.preventDefault(),e.menu.isOpen=!e.menu.isOpen}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),"hover"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex},on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],ref:"overlayRef",staticClass:"v-dropdown-menu__overlay",style:{"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex},on:{mousedown:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}}):e._e()],2)},staticRenderFns:[]},undefined,{name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},data(){return{baseClassName:"v-dropdown-menu",menu:{isOpen:this.isOpen,mode:this.mode,dropup:this.dropup,direction:this.direction,closeOnClickOutside:this.closeOnClickOutside,withDropdownCloser:this.withDropdownCloser,containerZIndex:this.containerZIndex,overlay:this.overlay,overlayBgColor:this.overlayBgColor,overlayZIndex:this.overlayZIndex,transition:this.transition}}},computed:{activeClass(){return this.menu.isOpen?`${this.baseClassName}--active`:null},modeClass(){return"click"===this.menu.mode?`${this.baseClassName}--mode-click`:`${this.baseClassName}--mode-hover`},dropupClass(){return this.menu.dropup?`${this.baseClassName}--dropup`:null},directionClass(){let e=null;return e="left"===this.menu.direction?`${this.baseClassName}--direction-left`:"center"===this.menu.direction?`${this.baseClassName}--direction-center`:`${this.baseClassName}--direction-right`,e}},watch:{isOpen(e){"click"===this.menu.mode&&(e?setTimeout((()=>{this.show()}),1):setTimeout((()=>{this.hide()}),1))},"menu.isOpen"(e){"click"===this.menu.mode&&(e?this.$emit("opened",this.$props):this.$emit("closed",this.$props))}},mounted(){this.dropdownCloser(),this.$nextTick((()=>{this.menu.closeOnClickOutside&&this.registerCloseDropdownOnClickOutside()})),this.closeDropdownOnPopState()},beforeDestroy(){this.destroyCloseDropdownOnClickOutside(),this.destroyCloseDropdownOnPopState()},methods:{show(){this.menu.isOpen=!0},hide(){this.menu.isOpen=!1},registerCloseDropdownOnClickOutside(){window.addEventListener("click",this.closeDropdownOnClickOutside)},closeDropdownOnClickOutside(e){this.menu.isOpen&&(this.$refs.rootRef.contains(e.target)||(this.menu.isOpen=!1))},destroyCloseDropdownOnClickOutside(){this.menu.closeOnClickOutside&&window.removeEventListener("click",this.closeDropdownOnClickOutside)},dropdownCloser(){if(this.menu.withDropdownCloser){this.$refs.rootRef.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{this.menu.isOpen=!1}))}))}},closeDropdownOnPopState(){window.addEventListener("popstate",(()=>{this.menu.isOpen&&(this.menu.isOpen=!1)}))},destroyCloseDropdownOnPopState(){window.removeEventListener("popstate",this.closeDropdownOnPopState)}}},undefined,false,undefined,!1,void 0,void 0,void 0),o=function(e){o.installed||(o.installed=!0,e.component("DropdownMenu",t))},i={install:o};{let e=null;"undefined"!=typeof window?e=window.Vue:"undefined"!=typeof global&&(e=global.Vue),e&&e.use(i)}t.install=o,e.default=t,Object.defineProperty(e,"__esModule",{value:!0})}));
2 |
--------------------------------------------------------------------------------
/dist/vue2/v-dropdown-menu.css:
--------------------------------------------------------------------------------
1 | .v-dropdown-menu{position:relative;display:inline-block}.v-dropdown-menu__trigger{position:relative}.v-dropdown-menu__container{position:absolute;top:100%;bottom:auto;min-width:230px;max-width:100%;overflow:hidden;background-color:#fff;border:1px solid #ddd}.v-dropdown-menu--dropup .v-dropdown-menu__container{top:auto;bottom:100%}.v-dropdown-menu--direction-left .v-dropdown-menu__container{left:0}.v-dropdown-menu--direction-center .v-dropdown-menu__container{left:50%;transform:translateX(-50%) translateY(0)}.v-dropdown-menu--direction-right .v-dropdown-menu__container{right:0}.v-dropdown-menu__overlay{position:fixed;top:0;left:0;width:100%;height:100vh}.v-dropdown-menu .default-enter-active{transition:all .2s ease}.v-dropdown-menu .default-leave-active{transition:all .2s cubic-bezier(1,.5,.8,1)}.v-dropdown-menu .default-enter,.v-dropdown-menu .default-leave-to{transform:translateY(12px);opacity:0}.v-dropdown-menu--mode-hover .default-enter,.v-dropdown-menu--mode-hover .default-leave-active{transition-delay:.4s}.v-dropdown-menu--dropup .default-enter,.v-dropdown-menu--dropup .default-leave-to{transform:translateY(-12px)}.v-dropdown-menu--dropup.v-dropdown-menu--direction-center .default-enter,.v-dropdown-menu--dropup.v-dropdown-menu--direction-center .default-leave-to{transform:translateX(-50%) translateY(-12px)}.v-dropdown-menu--direction-center .default-enter,.v-dropdown-menu--direction-center .default-leave-to{transform:translateX(-50%) translateY(12px)}
--------------------------------------------------------------------------------
/dist/vue2/v-dropdown-menu.global.min.js:
--------------------------------------------------------------------------------
1 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).DropdownMenu=n()}(this,(function(){"use strict";function e(e,n,t,o,i,s,r,d,l,a){"boolean"!=typeof r&&(l=d,d=r,r=!1);const u="function"==typeof t?t.options:t;let p;if(e&&e.render&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns,u._compiled=!0,i&&(u.functional=!0)),o&&(u._scopeId=o),s?(p=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,l(e)),e&&e._registeredComponents&&e._registeredComponents.add(s)},u._ssrRegister=p):n&&(p=r?function(e){n.call(this,a(e,this.$root.$options.shadowRoot))}:function(e){n.call(this,d(e))}),p)if(u.functional){const e=u.render;u.render=function(n,t){return p.call(t),e(n,t)}}else{const e=u.beforeCreate;u.beforeCreate=e?[].concat(e,p):[p]}return t}const n=e({render:function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",{ref:"rootRef",staticClass:"v-dropdown-menu",class:[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]},["click"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{click:function(n){n.preventDefault(),e.menu.isOpen=!e.menu.isOpen}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),"hover"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex},on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],ref:"overlayRef",staticClass:"v-dropdown-menu__overlay",style:{"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex},on:{mousedown:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}}):e._e()],2)},staticRenderFns:[]},undefined,{name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},data(){return{baseClassName:"v-dropdown-menu",menu:{isOpen:this.isOpen,mode:this.mode,dropup:this.dropup,direction:this.direction,closeOnClickOutside:this.closeOnClickOutside,withDropdownCloser:this.withDropdownCloser,containerZIndex:this.containerZIndex,overlay:this.overlay,overlayBgColor:this.overlayBgColor,overlayZIndex:this.overlayZIndex,transition:this.transition}}},computed:{activeClass(){return this.menu.isOpen?`${this.baseClassName}--active`:null},modeClass(){return"click"===this.menu.mode?`${this.baseClassName}--mode-click`:`${this.baseClassName}--mode-hover`},dropupClass(){return this.menu.dropup?`${this.baseClassName}--dropup`:null},directionClass(){let e=null;return e="left"===this.menu.direction?`${this.baseClassName}--direction-left`:"center"===this.menu.direction?`${this.baseClassName}--direction-center`:`${this.baseClassName}--direction-right`,e}},watch:{isOpen(e){"click"===this.menu.mode&&(e?setTimeout((()=>{this.show()}),1):setTimeout((()=>{this.hide()}),1))},"menu.isOpen"(e){"click"===this.menu.mode&&(e?this.$emit("opened",this.$props):this.$emit("closed",this.$props))}},mounted(){this.dropdownCloser(),this.$nextTick((()=>{this.menu.closeOnClickOutside&&this.registerCloseDropdownOnClickOutside()})),this.closeDropdownOnPopState()},beforeDestroy(){this.destroyCloseDropdownOnClickOutside(),this.destroyCloseDropdownOnPopState()},methods:{show(){this.menu.isOpen=!0},hide(){this.menu.isOpen=!1},registerCloseDropdownOnClickOutside(){window.addEventListener("click",this.closeDropdownOnClickOutside)},closeDropdownOnClickOutside(e){this.menu.isOpen&&(this.$refs.rootRef.contains(e.target)||(this.menu.isOpen=!1))},destroyCloseDropdownOnClickOutside(){this.menu.closeOnClickOutside&&window.removeEventListener("click",this.closeDropdownOnClickOutside)},dropdownCloser(){if(this.menu.withDropdownCloser){this.$refs.rootRef.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{this.menu.isOpen=!1}))}))}},closeDropdownOnPopState(){window.addEventListener("popstate",(()=>{this.menu.isOpen&&(this.menu.isOpen=!1)}))},destroyCloseDropdownOnPopState(){window.removeEventListener("popstate",this.closeDropdownOnPopState)}}},undefined,false,undefined,!1,void 0,void 0,void 0),t=function(e){t.installed||(t.installed=!0,e.component("DropdownMenu",n))},o={install:t};{let e=null;"undefined"!=typeof window?e=window.Vue:"undefined"!=typeof global&&(e=global.Vue),e&&e.use(o)}return n.install=t,n}));
2 |
--------------------------------------------------------------------------------
/dist/vue2/v-dropdown-menu.min.cjs:
--------------------------------------------------------------------------------
1 | "use strict";function e(e,n,t,o,i,s,r,d,a,l){"boolean"!=typeof r&&(a=d,d=r,r=!1);const u="function"==typeof t?t.options:t;let c;if(e&&e.render&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns,u._compiled=!0,i&&(u.functional=!0)),o&&(u._scopeId=o),s?(c=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,a(e)),e&&e._registeredComponents&&e._registeredComponents.add(s)},u._ssrRegister=c):n&&(c=r?function(e){n.call(this,l(e,this.$root.$options.shadowRoot))}:function(e){n.call(this,d(e))}),c)if(u.functional){const e=u.render;u.render=function(n,t){return c.call(t),e(n,t)}}else{const e=u.beforeCreate;u.beforeCreate=e?[].concat(e,c):[c]}return t}Object.defineProperty(exports,"__esModule",{value:!0});var n=e({render:function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",{ref:"rootRef",staticClass:"v-dropdown-menu",class:[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]},["click"===e.menu.mode?[e._ssrNode('",[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),"hover"===e.menu.mode?[e._ssrNode('",[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex},on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),e._ssrNode(e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?'":"\x3c!----\x3e")],2)},staticRenderFns:[]},undefined,{name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},data:function(){return{baseClassName:"v-dropdown-menu",menu:{isOpen:this.isOpen,mode:this.mode,dropup:this.dropup,direction:this.direction,closeOnClickOutside:this.closeOnClickOutside,withDropdownCloser:this.withDropdownCloser,containerZIndex:this.containerZIndex,overlay:this.overlay,overlayBgColor:this.overlayBgColor,overlayZIndex:this.overlayZIndex,transition:this.transition}}},computed:{activeClass:function(){return this.menu.isOpen?"".concat(this.baseClassName,"--active"):null},modeClass:function(){return"click"===this.menu.mode?"".concat(this.baseClassName,"--mode-click"):"".concat(this.baseClassName,"--mode-hover")},dropupClass:function(){return this.menu.dropup?"".concat(this.baseClassName,"--dropup"):null},directionClass:function(){return"left"===this.menu.direction?"".concat(this.baseClassName,"--direction-left"):"center"===this.menu.direction?"".concat(this.baseClassName,"--direction-center"):"".concat(this.baseClassName,"--direction-right")}},watch:{isOpen:function(e){var n=this;"click"===this.menu.mode&&(e?setTimeout((function(){n.show()}),1):setTimeout((function(){n.hide()}),1))},"menu.isOpen":function(e){"click"===this.menu.mode&&(e?this.$emit("opened",this.$props):this.$emit("closed",this.$props))}},mounted:function(){var e=this;this.dropdownCloser(),this.$nextTick((function(){e.menu.closeOnClickOutside&&e.registerCloseDropdownOnClickOutside()})),this.closeDropdownOnPopState()},beforeDestroy:function(){this.destroyCloseDropdownOnClickOutside(),this.destroyCloseDropdownOnPopState()},methods:{show:function(){this.menu.isOpen=!0},hide:function(){this.menu.isOpen=!1},registerCloseDropdownOnClickOutside:function(){window.addEventListener("click",this.closeDropdownOnClickOutside)},closeDropdownOnClickOutside:function(e){this.menu.isOpen&&(this.$refs.rootRef.contains(e.target)||(this.menu.isOpen=!1))},destroyCloseDropdownOnClickOutside:function(){this.menu.closeOnClickOutside&&window.removeEventListener("click",this.closeDropdownOnClickOutside)},dropdownCloser:function(){var e=this;this.menu.withDropdownCloser&&this.$refs.rootRef.querySelectorAll("[dropdown-closer]").forEach((function(n){n.addEventListener("click",(function(){e.menu.isOpen=!1}))}))},closeDropdownOnPopState:function(){var e=this;window.addEventListener("popstate",(function(){e.menu.isOpen&&(e.menu.isOpen=!1)}))},destroyCloseDropdownOnPopState:function(){window.removeEventListener("popstate",this.closeDropdownOnPopState)}}},undefined,false,"data-v-cf2c3d36",!1,void 0,void 0,void 0),t=function(e){t.installed||(t.installed=!0,e.component("DropdownMenu",n))},o={install:t},i=null;"undefined"!=typeof window?i=window.Vue:"undefined"!=typeof global&&(i=global.Vue),i&&i.use(o),n.install=t,exports.default=n;
--------------------------------------------------------------------------------
/dist/vue2/v-dropdown-menu.min.mjs:
--------------------------------------------------------------------------------
1 | function e(e,t,n,o,s,i,r,d,a,l){"boolean"!=typeof r&&(a=d,d=r,r=!1);const u="function"==typeof n?n.options:n;let p;if(e&&e.render&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns,u._compiled=!0,s&&(u.functional=!0)),o&&(u._scopeId=o),i?(p=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),t&&t.call(this,a(e)),e&&e._registeredComponents&&e._registeredComponents.add(i)},u._ssrRegister=p):t&&(p=r?function(e){t.call(this,l(e,this.$root.$options.shadowRoot))}:function(e){t.call(this,d(e))}),p)if(u.functional){const e=u.render;u.render=function(t,n){return p.call(n),e(t,n)}}else{const e=u.beforeCreate;u.beforeCreate=e?[].concat(e,p):[p]}return n}const t=e({render:function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{ref:"rootRef",staticClass:"v-dropdown-menu",class:[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]},["click"===e.menu.mode?[n("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{click:function(t){t.preventDefault(),e.menu.isOpen=!e.menu.isOpen}}},[e._t("trigger")],2),n("transition",{attrs:{name:e.menu.transition}},[n("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex}},[n("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),n("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),n("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),"hover"===e.menu.mode?[n("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{mouseover:function(t){return t.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(t){return t.preventDefault(),e.hide.apply(null,arguments)}}},[e._t("trigger")],2),n("transition",{attrs:{name:e.menu.transition}},[n("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex},on:{mouseover:function(t){return t.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(t){return t.preventDefault(),e.hide.apply(null,arguments)}}},[n("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),n("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),n("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?n("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],ref:"overlayRef",staticClass:"v-dropdown-menu__overlay",style:{"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex},on:{mousedown:function(t){return t.preventDefault(),e.hide.apply(null,arguments)}}}):e._e()],2)},staticRenderFns:[]},undefined,{name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},data(){return{baseClassName:"v-dropdown-menu",menu:{isOpen:this.isOpen,mode:this.mode,dropup:this.dropup,direction:this.direction,closeOnClickOutside:this.closeOnClickOutside,withDropdownCloser:this.withDropdownCloser,containerZIndex:this.containerZIndex,overlay:this.overlay,overlayBgColor:this.overlayBgColor,overlayZIndex:this.overlayZIndex,transition:this.transition}}},computed:{activeClass(){return this.menu.isOpen?`${this.baseClassName}--active`:null},modeClass(){return"click"===this.menu.mode?`${this.baseClassName}--mode-click`:`${this.baseClassName}--mode-hover`},dropupClass(){return this.menu.dropup?`${this.baseClassName}--dropup`:null},directionClass(){let e=null;return e="left"===this.menu.direction?`${this.baseClassName}--direction-left`:"center"===this.menu.direction?`${this.baseClassName}--direction-center`:`${this.baseClassName}--direction-right`,e}},watch:{isOpen(e){"click"===this.menu.mode&&(e?setTimeout((()=>{this.show()}),1):setTimeout((()=>{this.hide()}),1))},"menu.isOpen"(e){"click"===this.menu.mode&&(e?this.$emit("opened",this.$props):this.$emit("closed",this.$props))}},mounted(){this.dropdownCloser(),this.$nextTick((()=>{this.menu.closeOnClickOutside&&this.registerCloseDropdownOnClickOutside()})),this.closeDropdownOnPopState()},beforeDestroy(){this.destroyCloseDropdownOnClickOutside(),this.destroyCloseDropdownOnPopState()},methods:{show(){this.menu.isOpen=!0},hide(){this.menu.isOpen=!1},registerCloseDropdownOnClickOutside(){window.addEventListener("click",this.closeDropdownOnClickOutside)},closeDropdownOnClickOutside(e){this.menu.isOpen&&(this.$refs.rootRef.contains(e.target)||(this.menu.isOpen=!1))},destroyCloseDropdownOnClickOutside(){this.menu.closeOnClickOutside&&window.removeEventListener("click",this.closeDropdownOnClickOutside)},dropdownCloser(){if(this.menu.withDropdownCloser){this.$refs.rootRef.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{this.menu.isOpen=!1}))}))}},closeDropdownOnPopState(){window.addEventListener("popstate",(()=>{this.menu.isOpen&&(this.menu.isOpen=!1)}))},destroyCloseDropdownOnPopState(){window.removeEventListener("popstate",this.closeDropdownOnPopState)}}},undefined,false,undefined,!1,void 0,void 0,void 0),n=function(e){n.installed||(n.installed=!0,e.component("DropdownMenu",t))};t.install=n;export{t as default};
2 |
--------------------------------------------------------------------------------
/dist/vue2/v-dropdown-menu.mjs:
--------------------------------------------------------------------------------
1 | //
2 | //
3 | //
4 | //
5 | //
6 | //
7 | //
8 | //
9 | //
10 | //
11 | //
12 | //
13 | //
14 | //
15 | //
16 | //
17 | //
18 | //
19 | //
20 | //
21 | //
22 | //
23 | //
24 | //
25 | //
26 | //
27 | //
28 | //
29 | //
30 | //
31 | //
32 | //
33 | //
34 | //
35 | //
36 | //
37 | //
38 | //
39 | //
40 | //
41 | //
42 | //
43 | //
44 |
45 | var script = {
46 | name: 'DropdownMenu',
47 | props: {
48 | isOpen: {
49 | type: Boolean,
50 | required: false,
51 | default: false
52 | },
53 | mode: {
54 | type: String,
55 | required: false,
56 | default: 'click'
57 | },
58 | dropup: {
59 | type: Boolean,
60 | required: false,
61 | default: false
62 | },
63 | direction: {
64 | type: String,
65 | required: false,
66 | default: 'left'
67 | },
68 | closeOnClickOutside: {
69 | type: Boolean,
70 | required: false,
71 | default: true
72 | },
73 | withDropdownCloser: {
74 | type: Boolean,
75 | required: false,
76 | default: false
77 | },
78 | containerZIndex: {
79 | type: String,
80 | required: false,
81 | default: '994'
82 | },
83 | overlay: {
84 | type: Boolean,
85 | required: false,
86 | default: true
87 | },
88 | overlayBgColor: {
89 | type: String,
90 | required: false,
91 | default: 'rgba(0, 0, 0, 0.2)'
92 | },
93 | overlayZIndex: {
94 | type: String,
95 | required: false,
96 | default: '992'
97 | },
98 | transition: {
99 | type: String,
100 | required: false,
101 | default: 'default'
102 | }
103 | },
104 | data() {
105 | return {
106 | baseClassName: 'v-dropdown-menu',
107 | menu: {
108 | isOpen: this.isOpen,
109 | mode: this.mode,
110 | dropup: this.dropup,
111 | direction: this.direction,
112 | closeOnClickOutside: this.closeOnClickOutside,
113 | withDropdownCloser: this.withDropdownCloser,
114 | containerZIndex: this.containerZIndex,
115 | overlay: this.overlay,
116 | overlayBgColor: this.overlayBgColor,
117 | overlayZIndex: this.overlayZIndex,
118 | transition: this.transition
119 | }
120 | };
121 | },
122 | computed: {
123 | activeClass() {
124 | return this.menu.isOpen ? `${this.baseClassName}--active` : null;
125 | },
126 | modeClass() {
127 | return this.menu.mode === 'click' ? `${this.baseClassName}--mode-click` : `${this.baseClassName}--mode-hover`;
128 | },
129 | dropupClass() {
130 | return this.menu.dropup ? `${this.baseClassName}--dropup` : null;
131 | },
132 | directionClass() {
133 | let menuDirection = null;
134 | if (this.menu.direction === 'left') {
135 | menuDirection = `${this.baseClassName}--direction-left`;
136 | } else if (this.menu.direction === 'center') {
137 | menuDirection = `${this.baseClassName}--direction-center`;
138 | } else {
139 | menuDirection = `${this.baseClassName}--direction-right`;
140 | }
141 | return menuDirection;
142 | }
143 | },
144 | watch: {
145 | isOpen(value) {
146 | if (this.menu.mode === 'click') {
147 | if (value) {
148 | setTimeout(() => {
149 | this.show();
150 | }, 1); // wait, bypass for closeOnClickOutside
151 | } else {
152 | setTimeout(() => {
153 | this.hide();
154 | }, 1); // wait, bypass for closeOnClickOutside
155 | }
156 | }
157 | },
158 |
159 | 'menu.isOpen'(value) {
160 | if (this.menu.mode === 'click') {
161 | if (value) {
162 | this.$emit('opened', this.$props);
163 | } else {
164 | this.$emit('closed', this.$props);
165 | }
166 | }
167 | }
168 | },
169 | mounted() {
170 | this.dropdownCloser();
171 | this.$nextTick(() => {
172 | if (this.menu.closeOnClickOutside) {
173 | this.registerCloseDropdownOnClickOutside();
174 | }
175 | });
176 | this.closeDropdownOnPopState();
177 | },
178 | beforeDestroy() {
179 | this.destroyCloseDropdownOnClickOutside();
180 | this.destroyCloseDropdownOnPopState();
181 | },
182 | methods: {
183 | show() {
184 | this.menu.isOpen = true;
185 | },
186 | hide() {
187 | this.menu.isOpen = false;
188 | },
189 | registerCloseDropdownOnClickOutside() {
190 | window.addEventListener('click', this.closeDropdownOnClickOutside);
191 | },
192 | closeDropdownOnClickOutside(e) {
193 | if (this.menu.isOpen) {
194 | if (!this.$refs.rootRef.contains(e.target)) {
195 | this.menu.isOpen = false;
196 | }
197 | }
198 | },
199 | destroyCloseDropdownOnClickOutside() {
200 | if (this.menu.closeOnClickOutside) {
201 | window.removeEventListener('click', this.closeDropdownOnClickOutside);
202 | }
203 | },
204 | dropdownCloser() {
205 | if (this.menu.withDropdownCloser) {
206 | const dropdown = this.$refs.rootRef;
207 | dropdown.querySelectorAll('[dropdown-closer]').forEach(element => {
208 | element.addEventListener('click', () => {
209 | this.menu.isOpen = false;
210 | });
211 | });
212 | }
213 | },
214 | closeDropdownOnPopState() {
215 | window.addEventListener('popstate', () => {
216 | if (this.menu.isOpen) {
217 | this.menu.isOpen = false;
218 | }
219 | });
220 | },
221 | destroyCloseDropdownOnPopState() {
222 | window.removeEventListener('popstate', this.closeDropdownOnPopState);
223 | }
224 | }
225 | };
226 |
227 | function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
228 | if (typeof shadowMode !== 'boolean') {
229 | createInjectorSSR = createInjector;
230 | createInjector = shadowMode;
231 | shadowMode = false;
232 | }
233 | // Vue.extend constructor export interop.
234 | const options = typeof script === 'function' ? script.options : script;
235 | // render functions
236 | if (template && template.render) {
237 | options.render = template.render;
238 | options.staticRenderFns = template.staticRenderFns;
239 | options._compiled = true;
240 | // functional template
241 | if (isFunctionalTemplate) {
242 | options.functional = true;
243 | }
244 | }
245 | // scopedId
246 | if (scopeId) {
247 | options._scopeId = scopeId;
248 | }
249 | let hook;
250 | if (moduleIdentifier) {
251 | // server build
252 | hook = function (context) {
253 | // 2.3 injection
254 | context =
255 | context || // cached call
256 | (this.$vnode && this.$vnode.ssrContext) || // stateful
257 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional
258 | // 2.2 with runInNewContext: true
259 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
260 | context = __VUE_SSR_CONTEXT__;
261 | }
262 | // inject component styles
263 | if (style) {
264 | style.call(this, createInjectorSSR(context));
265 | }
266 | // register component module identifier for async chunk inference
267 | if (context && context._registeredComponents) {
268 | context._registeredComponents.add(moduleIdentifier);
269 | }
270 | };
271 | // used by ssr in case component is cached and beforeCreate
272 | // never gets called
273 | options._ssrRegister = hook;
274 | }
275 | else if (style) {
276 | hook = shadowMode
277 | ? function (context) {
278 | style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
279 | }
280 | : function (context) {
281 | style.call(this, createInjector(context));
282 | };
283 | }
284 | if (hook) {
285 | if (options.functional) {
286 | // register for functional component in vue file
287 | const originalRender = options.render;
288 | options.render = function renderWithStyleInjection(h, context) {
289 | hook.call(context);
290 | return originalRender(h, context);
291 | };
292 | }
293 | else {
294 | // inject component registration as beforeCreate hook
295 | const existing = options.beforeCreate;
296 | options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
297 | }
298 | }
299 | return script;
300 | }
301 |
302 | /* script */
303 | const __vue_script__ = script;
304 | /* template */
305 | var __vue_render__ = function () {
306 | var _vm = this;
307 | var _h = _vm.$createElement;
308 | var _c = _vm._self._c || _h;
309 | return _c('div', {
310 | ref: "rootRef",
311 | staticClass: "v-dropdown-menu",
312 | class: [_vm.activeClass, _vm.modeClass, _vm.dropupClass, _vm.directionClass]
313 | }, [_vm.menu.mode === 'click' ? [_c('div', {
314 | ref: "triggerRef",
315 | staticClass: "v-dropdown-menu__trigger",
316 | on: {
317 | "click": function ($event) {
318 | $event.preventDefault();
319 | _vm.menu.isOpen = !_vm.menu.isOpen;
320 | }
321 | }
322 | }, [_vm._t("trigger")], 2), _c('transition', {
323 | attrs: {
324 | "name": _vm.menu.transition
325 | }
326 | }, [_c('div', {
327 | directives: [{
328 | name: "show",
329 | rawName: "v-show",
330 | value: _vm.menu.isOpen,
331 | expression: "menu.isOpen"
332 | }],
333 | staticClass: "v-dropdown-menu__container",
334 | style: {
335 | 'z-index': _vm.menu.containerZIndex
336 | }
337 | }, [_c('div', {
338 | staticClass: "v-dropdown-menu__header"
339 | }, [_vm._t("header")], 2), _c('div', {
340 | staticClass: "v-dropdown-menu__body"
341 | }, [_vm._t("body")], 2), _c('div', {
342 | staticClass: "v-dropdown-menu__footer"
343 | }, [_vm._t("footer")], 2)])])] : _vm._e(), _vm.menu.mode === 'hover' ? [_c('div', {
344 | ref: "triggerRef",
345 | staticClass: "v-dropdown-menu__trigger",
346 | on: {
347 | "mouseover": function ($event) {
348 | $event.preventDefault();
349 | return _vm.show.apply(null, arguments);
350 | },
351 | "mouseleave": function ($event) {
352 | $event.preventDefault();
353 | return _vm.hide.apply(null, arguments);
354 | }
355 | }
356 | }, [_vm._t("trigger")], 2), _c('transition', {
357 | attrs: {
358 | "name": _vm.menu.transition
359 | }
360 | }, [_c('div', {
361 | directives: [{
362 | name: "show",
363 | rawName: "v-show",
364 | value: _vm.menu.isOpen,
365 | expression: "menu.isOpen"
366 | }],
367 | staticClass: "v-dropdown-menu__container",
368 | style: {
369 | 'z-index': _vm.menu.containerZIndex
370 | },
371 | on: {
372 | "mouseover": function ($event) {
373 | $event.preventDefault();
374 | return _vm.show.apply(null, arguments);
375 | },
376 | "mouseleave": function ($event) {
377 | $event.preventDefault();
378 | return _vm.hide.apply(null, arguments);
379 | }
380 | }
381 | }, [_c('div', {
382 | staticClass: "v-dropdown-menu__header"
383 | }, [_vm._t("header")], 2), _c('div', {
384 | staticClass: "v-dropdown-menu__body"
385 | }, [_vm._t("body")], 2), _c('div', {
386 | staticClass: "v-dropdown-menu__footer"
387 | }, [_vm._t("footer")], 2)])])] : _vm._e(), _vm.menu.overlay && _vm.menu.closeOnClickOutside && _vm.menu.mode === 'click' ? _c('div', {
388 | directives: [{
389 | name: "show",
390 | rawName: "v-show",
391 | value: _vm.menu.isOpen,
392 | expression: "menu.isOpen"
393 | }],
394 | ref: "overlayRef",
395 | staticClass: "v-dropdown-menu__overlay",
396 | style: {
397 | 'background-color': _vm.menu.overlayBgColor,
398 | 'z-index': _vm.menu.overlayZIndex
399 | },
400 | on: {
401 | "mousedown": function ($event) {
402 | $event.preventDefault();
403 | return _vm.hide.apply(null, arguments);
404 | }
405 | }
406 | }) : _vm._e()], 2);
407 | };
408 | var __vue_staticRenderFns__ = [];
409 |
410 | /* style */
411 | const __vue_inject_styles__ = undefined;
412 | /* scoped */
413 | const __vue_scope_id__ = undefined;
414 | /* module identifier */
415 | const __vue_module_identifier__ = undefined;
416 | /* functional template */
417 | const __vue_is_functional_template__ = false;
418 | /* style inject */
419 |
420 | /* style inject SSR */
421 |
422 | /* style inject shadow dom */
423 |
424 | const __vue_component__ = /*#__PURE__*/normalizeComponent({
425 | render: __vue_render__,
426 | staticRenderFns: __vue_staticRenderFns__
427 | }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, false, undefined, undefined, undefined);
428 |
429 | // Import vue component
430 |
431 | // install function executed by Vue.use()
432 | const install = function installDropdownMenu(Vue) {
433 | if (install.installed) return;
434 | install.installed = true;
435 | Vue.component('DropdownMenu', __vue_component__);
436 | };
437 |
438 | // Inject install function into component - allows component
439 | // to be registered via Vue.use() as well as Vue.component()
440 | __vue_component__.install = install;
441 |
442 | // It's possible to expose named exports when writing components that can
443 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
444 | // export const RollupDemoDirective = component;
445 |
446 | export { __vue_component__ as default };
447 |
--------------------------------------------------------------------------------
/dist/vue2/v-dropdown-menu.umd.min.js:
--------------------------------------------------------------------------------
1 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).DropdownMenu={})}(this,(function(e){"use strict";function n(e,n,t,o,i,s,r,d,l,a){"boolean"!=typeof r&&(l=d,d=r,r=!1);const u="function"==typeof t?t.options:t;let p;if(e&&e.render&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns,u._compiled=!0,i&&(u.functional=!0)),o&&(u._scopeId=o),s?(p=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,l(e)),e&&e._registeredComponents&&e._registeredComponents.add(s)},u._ssrRegister=p):n&&(p=r?function(e){n.call(this,a(e,this.$root.$options.shadowRoot))}:function(e){n.call(this,d(e))}),p)if(u.functional){const e=u.render;u.render=function(n,t){return p.call(t),e(n,t)}}else{const e=u.beforeCreate;u.beforeCreate=e?[].concat(e,p):[p]}return t}const t=n({render:function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",{ref:"rootRef",staticClass:"v-dropdown-menu",class:[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]},["click"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{click:function(n){n.preventDefault(),e.menu.isOpen=!e.menu.isOpen}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),"hover"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex},on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],ref:"overlayRef",staticClass:"v-dropdown-menu__overlay",style:{"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex},on:{mousedown:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}}):e._e()],2)},staticRenderFns:[]},undefined,{name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},data(){return{baseClassName:"v-dropdown-menu",menu:{isOpen:this.isOpen,mode:this.mode,dropup:this.dropup,direction:this.direction,closeOnClickOutside:this.closeOnClickOutside,withDropdownCloser:this.withDropdownCloser,containerZIndex:this.containerZIndex,overlay:this.overlay,overlayBgColor:this.overlayBgColor,overlayZIndex:this.overlayZIndex,transition:this.transition}}},computed:{activeClass(){return this.menu.isOpen?`${this.baseClassName}--active`:null},modeClass(){return"click"===this.menu.mode?`${this.baseClassName}--mode-click`:`${this.baseClassName}--mode-hover`},dropupClass(){return this.menu.dropup?`${this.baseClassName}--dropup`:null},directionClass(){let e=null;return e="left"===this.menu.direction?`${this.baseClassName}--direction-left`:"center"===this.menu.direction?`${this.baseClassName}--direction-center`:`${this.baseClassName}--direction-right`,e}},watch:{isOpen(e){"click"===this.menu.mode&&(e?setTimeout((()=>{this.show()}),1):setTimeout((()=>{this.hide()}),1))},"menu.isOpen"(e){"click"===this.menu.mode&&(e?this.$emit("opened",this.$props):this.$emit("closed",this.$props))}},mounted(){this.dropdownCloser(),this.$nextTick((()=>{this.menu.closeOnClickOutside&&this.registerCloseDropdownOnClickOutside()})),this.closeDropdownOnPopState()},beforeDestroy(){this.destroyCloseDropdownOnClickOutside(),this.destroyCloseDropdownOnPopState()},methods:{show(){this.menu.isOpen=!0},hide(){this.menu.isOpen=!1},registerCloseDropdownOnClickOutside(){window.addEventListener("click",this.closeDropdownOnClickOutside)},closeDropdownOnClickOutside(e){this.menu.isOpen&&(this.$refs.rootRef.contains(e.target)||(this.menu.isOpen=!1))},destroyCloseDropdownOnClickOutside(){this.menu.closeOnClickOutside&&window.removeEventListener("click",this.closeDropdownOnClickOutside)},dropdownCloser(){if(this.menu.withDropdownCloser){this.$refs.rootRef.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{this.menu.isOpen=!1}))}))}},closeDropdownOnPopState(){window.addEventListener("popstate",(()=>{this.menu.isOpen&&(this.menu.isOpen=!1)}))},destroyCloseDropdownOnPopState(){window.removeEventListener("popstate",this.closeDropdownOnPopState)}}},undefined,false,undefined,!1,void 0,void 0,void 0),o=function(e){o.installed||(o.installed=!0,e.component("DropdownMenu",t))},i={install:o};{let e=null;"undefined"!=typeof window?e=window.Vue:"undefined"!=typeof global&&(e=global.Vue),e&&e.use(i)}t.install=o,e.default=t,Object.defineProperty(e,"__esModule",{value:!0})}));
2 |
--------------------------------------------------------------------------------
/dist/vue3/index.js:
--------------------------------------------------------------------------------
1 | !function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],o):o((e="undefined"!=typeof globalThis?globalThis:e||self).DropdownMenu={},e.Vue)}(this,(function(e,o){"use strict";var n=o.defineComponent({name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},setup(e,n){let{emit:t}=n;const r="v-dropdown-menu",i=o.ref(null),d=o.ref(null),l=o.ref(null),s=o.reactive({isOpen:e.isOpen,mode:e.mode,dropup:e.dropup,direction:e.direction,closeOnClickOutside:e.closeOnClickOutside,withDropdownCloser:e.withDropdownCloser,containerZIndex:e.containerZIndex,overlay:e.overlay,overlayBgColor:e.overlayBgColor,overlayZIndex:e.overlayZIndex,transition:e.transition}),a=o.computed((()=>s.isOpen?`${r}--active`:null)),c=o.computed((()=>"click"===s.mode?`${r}--mode-click`:`${r}--mode-hover`)),u=o.computed((()=>s.dropup?`${r}--dropup`:null)),p=o.computed((()=>{let e=null;return e="left"===s.direction?`${r}--direction-left`:"center"===s.direction?`${r}--direction-center`:`${r}--direction-right`,e}));o.watch((()=>e.isOpen),(e=>{"click"===s.mode&&(e?setTimeout((()=>{m()}),1):setTimeout((()=>{v()}),1))})),o.watch((()=>s.isOpen),(o=>{"click"===s.mode&&t(o?"opened":"closed",e)})),o.onMounted((()=>{h(),o.nextTick((()=>{s.closeOnClickOutside&&f()})),g()})),o.onBeforeUnmount((()=>{y(),O()}));const m=()=>{s.isOpen=!0},v=()=>{s.isOpen=!1},f=()=>{window.addEventListener("click",w)},w=e=>{s.isOpen&&(i.value.contains(e.target)||(s.isOpen=!1))},y=()=>{s.closeOnClickOutside&&window.removeEventListener("click",w)},h=()=>{if(s.withDropdownCloser){i.value.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{s.isOpen=!1}))}))}},g=()=>{window.addEventListener("popstate",(()=>{s.isOpen&&(s.isOpen=!1)}))},O=()=>{window.removeEventListener("popstate",g)};return{rootRef:i,triggerRef:d,overlayRef:l,menu:s,show:m,hide:v,activeClass:a,modeClass:c,dropupClass:u,directionClass:p}}});const t={class:"v-dropdown-menu__header"},r={class:"v-dropdown-menu__body"},i={class:"v-dropdown-menu__footer"},d={class:"v-dropdown-menu__header"},l={class:"v-dropdown-menu__body"},s={class:"v-dropdown-menu__footer"};n.render=function(e,n,a,c,u,p){return o.openBlock(),o.createElementBlock("div",{class:o.normalizeClass(["v-dropdown-menu",[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]]),ref:"rootRef"},["click"===e.menu.mode?(o.openBlock(),o.createElementBlock(o.Fragment,{key:0},[o.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onClick:n[0]||(n[0]=o.withModifiers((o=>e.menu.isOpen=!e.menu.isOpen),["prevent"]))},[o.renderSlot(e.$slots,"trigger")],512),o.createVNode(o.Transition,{mode:"out-in",name:e.menu.transition},{default:o.withCtx((()=>[o.withDirectives(o.createElementVNode("div",{class:"v-dropdown-menu__container",style:o.normalizeStyle({"z-index":e.menu.containerZIndex})},[o.createElementVNode("div",t,[o.renderSlot(e.$slots,"header")]),o.createElementVNode("div",r,[o.renderSlot(e.$slots,"body")]),o.createElementVNode("div",i,[o.renderSlot(e.$slots,"footer")])],4),[[o.vShow,e.menu.isOpen]])])),_:3},8,["name"])],64)):o.createCommentVNode("",!0),"hover"===e.menu.mode?(o.openBlock(),o.createElementBlock(o.Fragment,{key:1},[o.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onMouseover:n[1]||(n[1]=o.withModifiers((function(){return e.show&&e.show(...arguments)}),["prevent"])),onMouseleave:n[2]||(n[2]=o.withModifiers((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},[o.renderSlot(e.$slots,"trigger")],544),o.createVNode(o.Transition,{name:e.menu.transition},{default:o.withCtx((()=>[o.withDirectives(o.createElementVNode("div",{class:"v-dropdown-menu__container",style:o.normalizeStyle({"z-index":e.menu.containerZIndex}),onMouseover:n[3]||(n[3]=o.withModifiers((function(){return e.show&&e.show(...arguments)}),["prevent"])),onMouseleave:n[4]||(n[4]=o.withModifiers((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},[o.createElementVNode("div",d,[o.renderSlot(e.$slots,"header")]),o.createElementVNode("div",l,[o.renderSlot(e.$slots,"body")]),o.createElementVNode("div",s,[o.renderSlot(e.$slots,"footer")])],36),[[o.vShow,e.menu.isOpen]])])),_:3},8,["name"])],64)):o.createCommentVNode("",!0),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?o.withDirectives((o.openBlock(),o.createElementBlock("div",{key:2,class:"v-dropdown-menu__overlay",ref:"overlayRef",style:o.normalizeStyle({"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex}),onMousedown:n[5]||(n[5]=o.withModifiers((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},null,36)),[[o.vShow,e.menu.isOpen]]):o.createCommentVNode("",!0)],2)};var a=(()=>{const e=n;return e.install=o=>{o.component("DropdownMenu",e)},e})();e.default=a,Object.defineProperty(e,"__esModule",{value:!0})}));
2 |
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.cjs:
--------------------------------------------------------------------------------
1 | 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var vue=require('vue');var script = vue.defineComponent({
2 | name: 'DropdownMenu',
3 | props: {
4 | isOpen: {
5 | type: Boolean,
6 | required: false,
7 | default: false
8 | },
9 | mode: {
10 | type: String,
11 | required: false,
12 | default: 'click'
13 | },
14 | dropup: {
15 | type: Boolean,
16 | required: false,
17 | default: false
18 | },
19 | direction: {
20 | type: String,
21 | required: false,
22 | default: 'left'
23 | },
24 | closeOnClickOutside: {
25 | type: Boolean,
26 | required: false,
27 | default: true
28 | },
29 | withDropdownCloser: {
30 | type: Boolean,
31 | required: false,
32 | default: false
33 | },
34 | containerZIndex: {
35 | type: String,
36 | required: false,
37 | default: '994'
38 | },
39 | overlay: {
40 | type: Boolean,
41 | required: false,
42 | default: true
43 | },
44 | overlayBgColor: {
45 | type: String,
46 | required: false,
47 | default: 'rgba(0, 0, 0, 0.2)'
48 | },
49 | overlayZIndex: {
50 | type: String,
51 | required: false,
52 | default: '992'
53 | },
54 | transition: {
55 | type: String,
56 | required: false,
57 | default: 'default'
58 | }
59 | },
60 | setup: function setup(props, _ref) {
61 | var emit = _ref.emit;
62 | var baseClassName = 'v-dropdown-menu';
63 | var rootRef = vue.ref(null);
64 | var triggerRef = vue.ref(null);
65 | var overlayRef = vue.ref(null);
66 | var menu = vue.reactive({
67 | isOpen: props.isOpen,
68 | mode: props.mode,
69 | dropup: props.dropup,
70 | direction: props.direction,
71 | closeOnClickOutside: props.closeOnClickOutside,
72 | withDropdownCloser: props.withDropdownCloser,
73 | containerZIndex: props.containerZIndex,
74 | overlay: props.overlay,
75 | overlayBgColor: props.overlayBgColor,
76 | overlayZIndex: props.overlayZIndex,
77 | transition: props.transition
78 | });
79 | var activeClass = vue.computed(function () {
80 | return menu.isOpen ? "".concat(baseClassName, "--active") : null;
81 | });
82 | var modeClass = vue.computed(function () {
83 | return menu.mode === 'click' ? "".concat(baseClassName, "--mode-click") : "".concat(baseClassName, "--mode-hover");
84 | });
85 | var dropupClass = vue.computed(function () {
86 | return menu.dropup ? "".concat(baseClassName, "--dropup") : null;
87 | });
88 | var directionClass = vue.computed(function () {
89 | var menuDirection = null;
90 | if (menu.direction === 'left') {
91 | menuDirection = "".concat(baseClassName, "--direction-left");
92 | } else if (menu.direction === 'center') {
93 | menuDirection = "".concat(baseClassName, "--direction-center");
94 | } else {
95 | menuDirection = "".concat(baseClassName, "--direction-right");
96 | }
97 | return menuDirection;
98 | });
99 | vue.watch(function () {
100 | return props.isOpen;
101 | }, function (value) {
102 | if (menu.mode === 'click') {
103 | if (value) {
104 | setTimeout(function () {
105 | show();
106 | }, 1); // wait, bypass for closeOnClickOutside
107 | } else {
108 | setTimeout(function () {
109 | hide();
110 | }, 1); // wait, bypass for closeOnClickOutside
111 | }
112 | }
113 | });
114 |
115 | vue.watch(function () {
116 | return menu.isOpen;
117 | }, function (value) {
118 | if (menu.mode === 'click') {
119 | if (value) {
120 | emit('opened', props);
121 | } else {
122 | emit('closed', props);
123 | }
124 | }
125 | });
126 | vue.onMounted(function () {
127 | dropdownCloser();
128 | vue.nextTick(function () {
129 | if (menu.closeOnClickOutside) {
130 | registerCloseDropdownOnClickOutside();
131 | }
132 | });
133 | closeDropdownOnPopState();
134 | });
135 | vue.onBeforeUnmount(function () {
136 | destroyCloseDropdownOnClickOutside();
137 | destroyCloseDropdownOnPopState();
138 | });
139 |
140 | // Methods
141 | var show = function show() {
142 | menu.isOpen = true;
143 | };
144 | var hide = function hide() {
145 | menu.isOpen = false;
146 | };
147 | var registerCloseDropdownOnClickOutside = function registerCloseDropdownOnClickOutside() {
148 | window.addEventListener('click', closeDropdownOnClickOutside);
149 | };
150 | var closeDropdownOnClickOutside = function closeDropdownOnClickOutside(e) {
151 | if (menu.isOpen) {
152 | if (!rootRef.value.contains(e.target)) {
153 | menu.isOpen = false;
154 | }
155 | }
156 | };
157 | var destroyCloseDropdownOnClickOutside = function destroyCloseDropdownOnClickOutside() {
158 | if (menu.closeOnClickOutside) {
159 | window.removeEventListener('click', closeDropdownOnClickOutside);
160 | }
161 | };
162 | var dropdownCloser = function dropdownCloser() {
163 | if (menu.withDropdownCloser) {
164 | var dropdown = rootRef.value;
165 | dropdown.querySelectorAll('[dropdown-closer]').forEach(function (element) {
166 | element.addEventListener('click', function () {
167 | menu.isOpen = false;
168 | });
169 | });
170 | }
171 | };
172 | var closeDropdownOnPopState = function closeDropdownOnPopState() {
173 | window.addEventListener('popstate', function () {
174 | if (menu.isOpen) {
175 | menu.isOpen = false;
176 | }
177 | });
178 | };
179 | var destroyCloseDropdownOnPopState = function destroyCloseDropdownOnPopState() {
180 | window.removeEventListener('popstate', closeDropdownOnPopState);
181 | };
182 | return {
183 | rootRef: rootRef,
184 | triggerRef: triggerRef,
185 | overlayRef: overlayRef,
186 | menu: menu,
187 | show: show,
188 | hide: hide,
189 | activeClass: activeClass,
190 | modeClass: modeClass,
191 | dropupClass: dropupClass,
192 | directionClass: directionClass
193 | };
194 | }
195 | });var _hoisted_1 = {
196 | class: "v-dropdown-menu__header"
197 | };
198 | var _hoisted_2 = {
199 | class: "v-dropdown-menu__body"
200 | };
201 | var _hoisted_3 = {
202 | class: "v-dropdown-menu__footer"
203 | };
204 | var _hoisted_4 = {
205 | class: "v-dropdown-menu__header"
206 | };
207 | var _hoisted_5 = {
208 | class: "v-dropdown-menu__body"
209 | };
210 | var _hoisted_6 = {
211 | class: "v-dropdown-menu__footer"
212 | };
213 | function render(_ctx, _cache, $props, $setup, $data, $options) {
214 | return vue.openBlock(), vue.createElementBlock("div", {
215 | class: vue.normalizeClass(["v-dropdown-menu", [_ctx.activeClass, _ctx.modeClass, _ctx.dropupClass, _ctx.directionClass]]),
216 | ref: "rootRef"
217 | }, [_ctx.menu.mode === 'click' ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, {
218 | key: 0
219 | }, [vue.createElementVNode("div", {
220 | class: "v-dropdown-menu__trigger",
221 | ref: "triggerRef",
222 | onClick: _cache[0] || (_cache[0] = vue.withModifiers(function ($event) {
223 | return _ctx.menu.isOpen = !_ctx.menu.isOpen;
224 | }, ["prevent"]))
225 | }, [vue.renderSlot(_ctx.$slots, "trigger")], 512), vue.createVNode(vue.Transition, {
226 | mode: "out-in",
227 | name: _ctx.menu.transition
228 | }, {
229 | default: vue.withCtx(function () {
230 | return [vue.withDirectives(vue.createElementVNode("div", {
231 | class: "v-dropdown-menu__container",
232 | style: vue.normalizeStyle({
233 | 'z-index': _ctx.menu.containerZIndex
234 | })
235 | }, [vue.createElementVNode("div", _hoisted_1, [vue.renderSlot(_ctx.$slots, "header")]), vue.createElementVNode("div", _hoisted_2, [vue.renderSlot(_ctx.$slots, "body")]), vue.createElementVNode("div", _hoisted_3, [vue.renderSlot(_ctx.$slots, "footer")])], 4), [[vue.vShow, _ctx.menu.isOpen]])];
236 | }),
237 | _: 3
238 | }, 8, ["name"])], 64)) : vue.createCommentVNode("", true), _ctx.menu.mode === 'hover' ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, {
239 | key: 1
240 | }, [vue.createElementVNode("div", {
241 | class: "v-dropdown-menu__trigger",
242 | ref: "triggerRef",
243 | onMouseover: _cache[1] || (_cache[1] = vue.withModifiers(function () {
244 | return _ctx.show && _ctx.show.apply(_ctx, arguments);
245 | }, ["prevent"])),
246 | onMouseleave: _cache[2] || (_cache[2] = vue.withModifiers(function () {
247 | return _ctx.hide && _ctx.hide.apply(_ctx, arguments);
248 | }, ["prevent"]))
249 | }, [vue.renderSlot(_ctx.$slots, "trigger")], 544), vue.createVNode(vue.Transition, {
250 | name: _ctx.menu.transition
251 | }, {
252 | default: vue.withCtx(function () {
253 | return [vue.withDirectives(vue.createElementVNode("div", {
254 | class: "v-dropdown-menu__container",
255 | style: vue.normalizeStyle({
256 | 'z-index': _ctx.menu.containerZIndex
257 | }),
258 | onMouseover: _cache[3] || (_cache[3] = vue.withModifiers(function () {
259 | return _ctx.show && _ctx.show.apply(_ctx, arguments);
260 | }, ["prevent"])),
261 | onMouseleave: _cache[4] || (_cache[4] = vue.withModifiers(function () {
262 | return _ctx.hide && _ctx.hide.apply(_ctx, arguments);
263 | }, ["prevent"]))
264 | }, [vue.createElementVNode("div", _hoisted_4, [vue.renderSlot(_ctx.$slots, "header")]), vue.createElementVNode("div", _hoisted_5, [vue.renderSlot(_ctx.$slots, "body")]), vue.createElementVNode("div", _hoisted_6, [vue.renderSlot(_ctx.$slots, "footer")])], 36), [[vue.vShow, _ctx.menu.isOpen]])];
265 | }),
266 | _: 3
267 | }, 8, ["name"])], 64)) : vue.createCommentVNode("", true), _ctx.menu.overlay && _ctx.menu.closeOnClickOutside && _ctx.menu.mode === 'click' ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
268 | key: 2,
269 | class: "v-dropdown-menu__overlay",
270 | ref: "overlayRef",
271 | style: vue.normalizeStyle({
272 | 'background-color': _ctx.menu.overlayBgColor,
273 | 'z-index': _ctx.menu.overlayZIndex
274 | }),
275 | onMousedown: _cache[5] || (_cache[5] = vue.withModifiers(function () {
276 | return _ctx.hide && _ctx.hide.apply(_ctx, arguments);
277 | }, ["prevent"]))
278 | }, null, 36)), [[vue.vShow, _ctx.menu.isOpen]]) : vue.createCommentVNode("", true)], 2);
279 | }script.render = render;// Import vue component
280 |
281 | // Default export is installable instance of component.
282 | // IIFE injects install function into component, allowing component
283 | // to be registered via Vue.use() as well as Vue.component(),
284 | var entry = /*#__PURE__*/(function () {
285 | // Assign InstallableComponent type
286 | var installable = script;
287 |
288 | // Attach install function executed by Vue.use()
289 | installable.install = function (app) {
290 | app.component('DropdownMenu', installable);
291 | };
292 | return installable;
293 | })();
294 |
295 | // It's possible to expose named exports when writing components that can
296 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
297 | // export const RollupDemoDirective = directive;
298 | exports["default"]=entry;
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.css:
--------------------------------------------------------------------------------
1 | .v-dropdown-menu{position:relative;display:inline-block}.v-dropdown-menu__trigger{position:relative}.v-dropdown-menu__container{position:absolute;top:100%;bottom:auto;min-width:230px;max-width:100%;overflow:hidden;background-color:#fff;border:1px solid #ddd}.v-dropdown-menu--dropup .v-dropdown-menu__container{top:auto;bottom:100%}.v-dropdown-menu--direction-left .v-dropdown-menu__container{left:0}.v-dropdown-menu--direction-center .v-dropdown-menu__container{left:50%;transform:translateX(-50%) translateY(0)}.v-dropdown-menu--direction-right .v-dropdown-menu__container{right:0}.v-dropdown-menu__overlay{position:fixed;top:0;left:0;width:100%;height:100vh}.v-dropdown-menu .default-enter-active{transition:all .2s ease}.v-dropdown-menu .default-leave-active{transition:all .2s cubic-bezier(1, 0.5, 0.8, 1)}.v-dropdown-menu .default-enter-from,.v-dropdown-menu .default-leave-to{transform:translateY(12px);opacity:0}.v-dropdown-menu--mode-hover .default-enter-from,.v-dropdown-menu--mode-hover .default-leave-active{transition-delay:.4s}.v-dropdown-menu--dropup .default-enter-from,.v-dropdown-menu--dropup .default-leave-to{transform:translateY(-12px)}.v-dropdown-menu--dropup.v-dropdown-menu--direction-center .default-enter-from,.v-dropdown-menu--dropup.v-dropdown-menu--direction-center .default-leave-to{transform:translateX(-50%) translateY(-12px)}.v-dropdown-menu--direction-center .default-enter-from,.v-dropdown-menu--direction-center .default-leave-to{transform:translateX(-50%) translateY(12px)}
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.global.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('vue')) :
3 | typeof define === 'function' && define.amd ? define(['vue'], factory) :
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DropdownMenu = factory(global.Vue));
5 | })(this, (function (vue) { 'use strict';
6 |
7 | var script = vue.defineComponent({
8 | name: 'DropdownMenu',
9 | props: {
10 | isOpen: {
11 | type: Boolean,
12 | required: false,
13 | default: false
14 | },
15 | mode: {
16 | type: String,
17 | required: false,
18 | default: 'click'
19 | },
20 | dropup: {
21 | type: Boolean,
22 | required: false,
23 | default: false
24 | },
25 | direction: {
26 | type: String,
27 | required: false,
28 | default: 'left'
29 | },
30 | closeOnClickOutside: {
31 | type: Boolean,
32 | required: false,
33 | default: true
34 | },
35 | withDropdownCloser: {
36 | type: Boolean,
37 | required: false,
38 | default: false
39 | },
40 | containerZIndex: {
41 | type: String,
42 | required: false,
43 | default: '994'
44 | },
45 | overlay: {
46 | type: Boolean,
47 | required: false,
48 | default: true
49 | },
50 | overlayBgColor: {
51 | type: String,
52 | required: false,
53 | default: 'rgba(0, 0, 0, 0.2)'
54 | },
55 | overlayZIndex: {
56 | type: String,
57 | required: false,
58 | default: '992'
59 | },
60 | transition: {
61 | type: String,
62 | required: false,
63 | default: 'default'
64 | }
65 | },
66 | setup(props, _ref) {
67 | let {
68 | emit
69 | } = _ref;
70 | const baseClassName = 'v-dropdown-menu';
71 | const rootRef = vue.ref(null);
72 | const triggerRef = vue.ref(null);
73 | const overlayRef = vue.ref(null);
74 | const menu = vue.reactive({
75 | isOpen: props.isOpen,
76 | mode: props.mode,
77 | dropup: props.dropup,
78 | direction: props.direction,
79 | closeOnClickOutside: props.closeOnClickOutside,
80 | withDropdownCloser: props.withDropdownCloser,
81 | containerZIndex: props.containerZIndex,
82 | overlay: props.overlay,
83 | overlayBgColor: props.overlayBgColor,
84 | overlayZIndex: props.overlayZIndex,
85 | transition: props.transition
86 | });
87 | const activeClass = vue.computed(() => {
88 | return menu.isOpen ? `${baseClassName}--active` : null;
89 | });
90 | const modeClass = vue.computed(() => {
91 | return menu.mode === 'click' ? `${baseClassName}--mode-click` : `${baseClassName}--mode-hover`;
92 | });
93 | const dropupClass = vue.computed(() => {
94 | return menu.dropup ? `${baseClassName}--dropup` : null;
95 | });
96 | const directionClass = vue.computed(() => {
97 | let menuDirection = null;
98 | if (menu.direction === 'left') {
99 | menuDirection = `${baseClassName}--direction-left`;
100 | } else if (menu.direction === 'center') {
101 | menuDirection = `${baseClassName}--direction-center`;
102 | } else {
103 | menuDirection = `${baseClassName}--direction-right`;
104 | }
105 | return menuDirection;
106 | });
107 | vue.watch(() => props.isOpen, value => {
108 | if (menu.mode === 'click') {
109 | if (value) {
110 | setTimeout(() => {
111 | show();
112 | }, 1); // wait, bypass for closeOnClickOutside
113 | } else {
114 | setTimeout(() => {
115 | hide();
116 | }, 1); // wait, bypass for closeOnClickOutside
117 | }
118 | }
119 | });
120 |
121 | vue.watch(() => menu.isOpen, value => {
122 | if (menu.mode === 'click') {
123 | if (value) {
124 | emit('opened', props);
125 | } else {
126 | emit('closed', props);
127 | }
128 | }
129 | });
130 | vue.onMounted(() => {
131 | dropdownCloser();
132 | vue.nextTick(() => {
133 | if (menu.closeOnClickOutside) {
134 | registerCloseDropdownOnClickOutside();
135 | }
136 | });
137 | closeDropdownOnPopState();
138 | });
139 | vue.onBeforeUnmount(() => {
140 | destroyCloseDropdownOnClickOutside();
141 | destroyCloseDropdownOnPopState();
142 | });
143 |
144 | // Methods
145 | const show = () => {
146 | menu.isOpen = true;
147 | };
148 | const hide = () => {
149 | menu.isOpen = false;
150 | };
151 | const registerCloseDropdownOnClickOutside = () => {
152 | window.addEventListener('click', closeDropdownOnClickOutside);
153 | };
154 | const closeDropdownOnClickOutside = e => {
155 | if (menu.isOpen) {
156 | if (!rootRef.value.contains(e.target)) {
157 | menu.isOpen = false;
158 | }
159 | }
160 | };
161 | const destroyCloseDropdownOnClickOutside = () => {
162 | if (menu.closeOnClickOutside) {
163 | window.removeEventListener('click', closeDropdownOnClickOutside);
164 | }
165 | };
166 | const dropdownCloser = () => {
167 | if (menu.withDropdownCloser) {
168 | const dropdown = rootRef.value;
169 | dropdown.querySelectorAll('[dropdown-closer]').forEach(element => {
170 | element.addEventListener('click', () => {
171 | menu.isOpen = false;
172 | });
173 | });
174 | }
175 | };
176 | const closeDropdownOnPopState = () => {
177 | window.addEventListener('popstate', () => {
178 | if (menu.isOpen) {
179 | menu.isOpen = false;
180 | }
181 | });
182 | };
183 | const destroyCloseDropdownOnPopState = () => {
184 | window.removeEventListener('popstate', closeDropdownOnPopState);
185 | };
186 | return {
187 | rootRef,
188 | triggerRef,
189 | overlayRef,
190 | menu,
191 | show,
192 | hide,
193 | activeClass,
194 | modeClass,
195 | dropupClass,
196 | directionClass
197 | };
198 | }
199 | });
200 |
201 | const _hoisted_1 = {
202 | class: "v-dropdown-menu__header"
203 | };
204 | const _hoisted_2 = {
205 | class: "v-dropdown-menu__body"
206 | };
207 | const _hoisted_3 = {
208 | class: "v-dropdown-menu__footer"
209 | };
210 | const _hoisted_4 = {
211 | class: "v-dropdown-menu__header"
212 | };
213 | const _hoisted_5 = {
214 | class: "v-dropdown-menu__body"
215 | };
216 | const _hoisted_6 = {
217 | class: "v-dropdown-menu__footer"
218 | };
219 | function render(_ctx, _cache, $props, $setup, $data, $options) {
220 | return vue.openBlock(), vue.createElementBlock("div", {
221 | class: vue.normalizeClass(["v-dropdown-menu", [_ctx.activeClass, _ctx.modeClass, _ctx.dropupClass, _ctx.directionClass]]),
222 | ref: "rootRef"
223 | }, [_ctx.menu.mode === 'click' ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, {
224 | key: 0
225 | }, [vue.createElementVNode("div", {
226 | class: "v-dropdown-menu__trigger",
227 | ref: "triggerRef",
228 | onClick: _cache[0] || (_cache[0] = vue.withModifiers($event => _ctx.menu.isOpen = !_ctx.menu.isOpen, ["prevent"]))
229 | }, [vue.renderSlot(_ctx.$slots, "trigger")], 512), vue.createVNode(vue.Transition, {
230 | mode: "out-in",
231 | name: _ctx.menu.transition
232 | }, {
233 | default: vue.withCtx(() => [vue.withDirectives(vue.createElementVNode("div", {
234 | class: "v-dropdown-menu__container",
235 | style: vue.normalizeStyle({
236 | 'z-index': _ctx.menu.containerZIndex
237 | })
238 | }, [vue.createElementVNode("div", _hoisted_1, [vue.renderSlot(_ctx.$slots, "header")]), vue.createElementVNode("div", _hoisted_2, [vue.renderSlot(_ctx.$slots, "body")]), vue.createElementVNode("div", _hoisted_3, [vue.renderSlot(_ctx.$slots, "footer")])], 4), [[vue.vShow, _ctx.menu.isOpen]])]),
239 | _: 3
240 | }, 8, ["name"])], 64)) : vue.createCommentVNode("", true), _ctx.menu.mode === 'hover' ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, {
241 | key: 1
242 | }, [vue.createElementVNode("div", {
243 | class: "v-dropdown-menu__trigger",
244 | ref: "triggerRef",
245 | onMouseover: _cache[1] || (_cache[1] = vue.withModifiers(function () {
246 | return _ctx.show && _ctx.show(...arguments);
247 | }, ["prevent"])),
248 | onMouseleave: _cache[2] || (_cache[2] = vue.withModifiers(function () {
249 | return _ctx.hide && _ctx.hide(...arguments);
250 | }, ["prevent"]))
251 | }, [vue.renderSlot(_ctx.$slots, "trigger")], 544), vue.createVNode(vue.Transition, {
252 | name: _ctx.menu.transition
253 | }, {
254 | default: vue.withCtx(() => [vue.withDirectives(vue.createElementVNode("div", {
255 | class: "v-dropdown-menu__container",
256 | style: vue.normalizeStyle({
257 | 'z-index': _ctx.menu.containerZIndex
258 | }),
259 | onMouseover: _cache[3] || (_cache[3] = vue.withModifiers(function () {
260 | return _ctx.show && _ctx.show(...arguments);
261 | }, ["prevent"])),
262 | onMouseleave: _cache[4] || (_cache[4] = vue.withModifiers(function () {
263 | return _ctx.hide && _ctx.hide(...arguments);
264 | }, ["prevent"]))
265 | }, [vue.createElementVNode("div", _hoisted_4, [vue.renderSlot(_ctx.$slots, "header")]), vue.createElementVNode("div", _hoisted_5, [vue.renderSlot(_ctx.$slots, "body")]), vue.createElementVNode("div", _hoisted_6, [vue.renderSlot(_ctx.$slots, "footer")])], 36), [[vue.vShow, _ctx.menu.isOpen]])]),
266 | _: 3
267 | }, 8, ["name"])], 64)) : vue.createCommentVNode("", true), _ctx.menu.overlay && _ctx.menu.closeOnClickOutside && _ctx.menu.mode === 'click' ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
268 | key: 2,
269 | class: "v-dropdown-menu__overlay",
270 | ref: "overlayRef",
271 | style: vue.normalizeStyle({
272 | 'background-color': _ctx.menu.overlayBgColor,
273 | 'z-index': _ctx.menu.overlayZIndex
274 | }),
275 | onMousedown: _cache[5] || (_cache[5] = vue.withModifiers(function () {
276 | return _ctx.hide && _ctx.hide(...arguments);
277 | }, ["prevent"]))
278 | }, null, 36)), [[vue.vShow, _ctx.menu.isOpen]]) : vue.createCommentVNode("", true)], 2);
279 | }
280 |
281 | script.render = render;
282 |
283 | // Import vue component
284 |
285 | // Default export is installable instance of component.
286 | // IIFE injects install function into component, allowing component
287 | // to be registered via Vue.use() as well as Vue.component(),
288 | var entry = /*#__PURE__*/(() => {
289 | // Assign InstallableComponent type
290 | const installable = script;
291 |
292 | // Attach install function executed by Vue.use()
293 | installable.install = app => {
294 | app.component('DropdownMenu', installable);
295 | };
296 | return installable;
297 | })();
298 |
299 | // It's possible to expose named exports when writing components that can
300 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
301 | // export const RollupDemoDirective = directive;
302 |
303 | return entry;
304 |
305 | }));
306 |
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.global.min.js:
--------------------------------------------------------------------------------
1 | !function(e,o){"object"==typeof exports&&"undefined"!=typeof module?module.exports=o(require("vue")):"function"==typeof define&&define.amd?define(["vue"],o):(e="undefined"!=typeof globalThis?globalThis:e||self).DropdownMenu=o(e.Vue)}(this,(function(e){"use strict";var o=e.defineComponent({name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},setup(o,n){let{emit:t}=n;const r="v-dropdown-menu",i=e.ref(null),d=e.ref(null),l=e.ref(null),s=e.reactive({isOpen:o.isOpen,mode:o.mode,dropup:o.dropup,direction:o.direction,closeOnClickOutside:o.closeOnClickOutside,withDropdownCloser:o.withDropdownCloser,containerZIndex:o.containerZIndex,overlay:o.overlay,overlayBgColor:o.overlayBgColor,overlayZIndex:o.overlayZIndex,transition:o.transition}),a=e.computed((()=>s.isOpen?`${r}--active`:null)),c=e.computed((()=>"click"===s.mode?`${r}--mode-click`:`${r}--mode-hover`)),u=e.computed((()=>s.dropup?`${r}--dropup`:null)),p=e.computed((()=>{let e=null;return e="left"===s.direction?`${r}--direction-left`:"center"===s.direction?`${r}--direction-center`:`${r}--direction-right`,e}));e.watch((()=>o.isOpen),(e=>{"click"===s.mode&&(e?setTimeout((()=>{m()}),1):setTimeout((()=>{v()}),1))})),e.watch((()=>s.isOpen),(e=>{"click"===s.mode&&t(e?"opened":"closed",o)})),e.onMounted((()=>{h(),e.nextTick((()=>{s.closeOnClickOutside&&f()})),g()})),e.onBeforeUnmount((()=>{y(),k()}));const m=()=>{s.isOpen=!0},v=()=>{s.isOpen=!1},f=()=>{window.addEventListener("click",w)},w=e=>{s.isOpen&&(i.value.contains(e.target)||(s.isOpen=!1))},y=()=>{s.closeOnClickOutside&&window.removeEventListener("click",w)},h=()=>{if(s.withDropdownCloser){i.value.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{s.isOpen=!1}))}))}},g=()=>{window.addEventListener("popstate",(()=>{s.isOpen&&(s.isOpen=!1)}))},k=()=>{window.removeEventListener("popstate",g)};return{rootRef:i,triggerRef:d,overlayRef:l,menu:s,show:m,hide:v,activeClass:a,modeClass:c,dropupClass:u,directionClass:p}}});const n={class:"v-dropdown-menu__header"},t={class:"v-dropdown-menu__body"},r={class:"v-dropdown-menu__footer"},i={class:"v-dropdown-menu__header"},d={class:"v-dropdown-menu__body"},l={class:"v-dropdown-menu__footer"};return o.render=function(o,s,a,c,u,p){return e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["v-dropdown-menu",[o.activeClass,o.modeClass,o.dropupClass,o.directionClass]]),ref:"rootRef"},["click"===o.menu.mode?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onClick:s[0]||(s[0]=e.withModifiers((e=>o.menu.isOpen=!o.menu.isOpen),["prevent"]))},[e.renderSlot(o.$slots,"trigger")],512),e.createVNode(e.Transition,{mode:"out-in",name:o.menu.transition},{default:e.withCtx((()=>[e.withDirectives(e.createElementVNode("div",{class:"v-dropdown-menu__container",style:e.normalizeStyle({"z-index":o.menu.containerZIndex})},[e.createElementVNode("div",n,[e.renderSlot(o.$slots,"header")]),e.createElementVNode("div",t,[e.renderSlot(o.$slots,"body")]),e.createElementVNode("div",r,[e.renderSlot(o.$slots,"footer")])],4),[[e.vShow,o.menu.isOpen]])])),_:3},8,["name"])],64)):e.createCommentVNode("",!0),"hover"===o.menu.mode?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onMouseover:s[1]||(s[1]=e.withModifiers((function(){return o.show&&o.show(...arguments)}),["prevent"])),onMouseleave:s[2]||(s[2]=e.withModifiers((function(){return o.hide&&o.hide(...arguments)}),["prevent"]))},[e.renderSlot(o.$slots,"trigger")],544),e.createVNode(e.Transition,{name:o.menu.transition},{default:e.withCtx((()=>[e.withDirectives(e.createElementVNode("div",{class:"v-dropdown-menu__container",style:e.normalizeStyle({"z-index":o.menu.containerZIndex}),onMouseover:s[3]||(s[3]=e.withModifiers((function(){return o.show&&o.show(...arguments)}),["prevent"])),onMouseleave:s[4]||(s[4]=e.withModifiers((function(){return o.hide&&o.hide(...arguments)}),["prevent"]))},[e.createElementVNode("div",i,[e.renderSlot(o.$slots,"header")]),e.createElementVNode("div",d,[e.renderSlot(o.$slots,"body")]),e.createElementVNode("div",l,[e.renderSlot(o.$slots,"footer")])],36),[[e.vShow,o.menu.isOpen]])])),_:3},8,["name"])],64)):e.createCommentVNode("",!0),o.menu.overlay&&o.menu.closeOnClickOutside&&"click"===o.menu.mode?e.withDirectives((e.openBlock(),e.createElementBlock("div",{key:2,class:"v-dropdown-menu__overlay",ref:"overlayRef",style:e.normalizeStyle({"background-color":o.menu.overlayBgColor,"z-index":o.menu.overlayZIndex}),onMousedown:s[5]||(s[5]=e.withModifiers((function(){return o.hide&&o.hide(...arguments)}),["prevent"]))},null,36)),[[e.vShow,o.menu.isOpen]]):e.createCommentVNode("",!0)],2)},(()=>{const e=o;return e.install=o=>{o.component("DropdownMenu",e)},e})()}));
2 |
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.min.cjs:
--------------------------------------------------------------------------------
1 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),n=e.defineComponent({name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},setup:function(n,o){var t=o.emit,r="v-dropdown-menu",i=e.ref(null),d=e.ref(null),l=e.ref(null),c=e.reactive({isOpen:n.isOpen,mode:n.mode,dropup:n.dropup,direction:n.direction,closeOnClickOutside:n.closeOnClickOutside,withDropdownCloser:n.withDropdownCloser,containerZIndex:n.containerZIndex,overlay:n.overlay,overlayBgColor:n.overlayBgColor,overlayZIndex:n.overlayZIndex,transition:n.transition}),u=e.computed((function(){return c.isOpen?"".concat(r,"--active"):null})),a=e.computed((function(){return"click"===c.mode?"".concat(r,"--mode-click"):"".concat(r,"--mode-hover")})),s=e.computed((function(){return c.dropup?"".concat(r,"--dropup"):null})),p=e.computed((function(){return"left"===c.direction?"".concat(r,"--direction-left"):"center"===c.direction?"".concat(r,"--direction-center"):"".concat(r,"--direction-right")}));e.watch((function(){return n.isOpen}),(function(e){"click"===c.mode&&(e?setTimeout((function(){m()}),1):setTimeout((function(){f()}),1))})),e.watch((function(){return c.isOpen}),(function(e){"click"===c.mode&&t(e?"opened":"closed",n)})),e.onMounted((function(){h(),e.nextTick((function(){c.closeOnClickOutside&&v()})),O()})),e.onBeforeUnmount((function(){y(),g()}));var m=function(){c.isOpen=!0},f=function(){c.isOpen=!1},v=function(){window.addEventListener("click",w)},w=function(e){c.isOpen&&(i.value.contains(e.target)||(c.isOpen=!1))},y=function(){c.closeOnClickOutside&&window.removeEventListener("click",w)},h=function(){c.withDropdownCloser&&i.value.querySelectorAll("[dropdown-closer]").forEach((function(e){e.addEventListener("click",(function(){c.isOpen=!1}))}))},O=function(){window.addEventListener("popstate",(function(){c.isOpen&&(c.isOpen=!1)}))},g=function(){window.removeEventListener("popstate",O)};return{rootRef:i,triggerRef:d,overlayRef:l,menu:c,show:m,hide:f,activeClass:u,modeClass:a,dropupClass:s,directionClass:p}}}),o={class:"v-dropdown-menu__header"},t={class:"v-dropdown-menu__body"},r={class:"v-dropdown-menu__footer"},i={class:"v-dropdown-menu__header"},d={class:"v-dropdown-menu__body"},l={class:"v-dropdown-menu__footer"};n.render=function(n,c,u,a,s,p){return e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["v-dropdown-menu",[n.activeClass,n.modeClass,n.dropupClass,n.directionClass]]),ref:"rootRef"},["click"===n.menu.mode?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onClick:c[0]||(c[0]=e.withModifiers((function(e){return n.menu.isOpen=!n.menu.isOpen}),["prevent"]))},[e.renderSlot(n.$slots,"trigger")],512),e.createVNode(e.Transition,{mode:"out-in",name:n.menu.transition},{default:e.withCtx((function(){return[e.withDirectives(e.createElementVNode("div",{class:"v-dropdown-menu__container",style:e.normalizeStyle({"z-index":n.menu.containerZIndex})},[e.createElementVNode("div",o,[e.renderSlot(n.$slots,"header")]),e.createElementVNode("div",t,[e.renderSlot(n.$slots,"body")]),e.createElementVNode("div",r,[e.renderSlot(n.$slots,"footer")])],4),[[e.vShow,n.menu.isOpen]])]})),_:3},8,["name"])],64)):e.createCommentVNode("",!0),"hover"===n.menu.mode?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onMouseover:c[1]||(c[1]=e.withModifiers((function(){return n.show&&n.show.apply(n,arguments)}),["prevent"])),onMouseleave:c[2]||(c[2]=e.withModifiers((function(){return n.hide&&n.hide.apply(n,arguments)}),["prevent"]))},[e.renderSlot(n.$slots,"trigger")],544),e.createVNode(e.Transition,{name:n.menu.transition},{default:e.withCtx((function(){return[e.withDirectives(e.createElementVNode("div",{class:"v-dropdown-menu__container",style:e.normalizeStyle({"z-index":n.menu.containerZIndex}),onMouseover:c[3]||(c[3]=e.withModifiers((function(){return n.show&&n.show.apply(n,arguments)}),["prevent"])),onMouseleave:c[4]||(c[4]=e.withModifiers((function(){return n.hide&&n.hide.apply(n,arguments)}),["prevent"]))},[e.createElementVNode("div",i,[e.renderSlot(n.$slots,"header")]),e.createElementVNode("div",d,[e.renderSlot(n.$slots,"body")]),e.createElementVNode("div",l,[e.renderSlot(n.$slots,"footer")])],36),[[e.vShow,n.menu.isOpen]])]})),_:3},8,["name"])],64)):e.createCommentVNode("",!0),n.menu.overlay&&n.menu.closeOnClickOutside&&"click"===n.menu.mode?e.withDirectives((e.openBlock(),e.createElementBlock("div",{key:2,class:"v-dropdown-menu__overlay",ref:"overlayRef",style:e.normalizeStyle({"background-color":n.menu.overlayBgColor,"z-index":n.menu.overlayZIndex}),onMousedown:c[5]||(c[5]=e.withModifiers((function(){return n.hide&&n.hide.apply(n,arguments)}),["prevent"]))},null,36)),[[e.vShow,n.menu.isOpen]]):e.createCommentVNode("",!0)],2)};var c=function(){var e=n;return e.install=function(n){n.component("DropdownMenu",e)},e}();exports.default=c;
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.min.mjs:
--------------------------------------------------------------------------------
1 | import{defineComponent as e,ref as n,reactive as o,computed as r,watch as t,onMounted as i,nextTick as d,onBeforeUnmount as l,openBlock as s,createElementBlock as u,normalizeClass as a,Fragment as c,createElementVNode as p,withModifiers as v,renderSlot as m,createVNode as f,Transition as w,withCtx as y,withDirectives as O,normalizeStyle as g,vShow as h,createCommentVNode as _}from"vue";var C=e({name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},setup(e,s){let{emit:u}=s;const a="v-dropdown-menu",c=n(null),p=n(null),v=n(null),m=o({isOpen:e.isOpen,mode:e.mode,dropup:e.dropup,direction:e.direction,closeOnClickOutside:e.closeOnClickOutside,withDropdownCloser:e.withDropdownCloser,containerZIndex:e.containerZIndex,overlay:e.overlay,overlayBgColor:e.overlayBgColor,overlayZIndex:e.overlayZIndex,transition:e.transition}),f=r((()=>m.isOpen?`${a}--active`:null)),w=r((()=>"click"===m.mode?`${a}--mode-click`:`${a}--mode-hover`)),y=r((()=>m.dropup?`${a}--dropup`:null)),O=r((()=>{let e=null;return e="left"===m.direction?`${a}--direction-left`:"center"===m.direction?`${a}--direction-center`:`${a}--direction-right`,e}));t((()=>e.isOpen),(e=>{"click"===m.mode&&(e?setTimeout((()=>{g()}),1):setTimeout((()=>{h()}),1))})),t((()=>m.isOpen),(n=>{"click"===m.mode&&u(n?"opened":"closed",e)})),i((()=>{$(),d((()=>{m.closeOnClickOutside&&_()})),x()})),l((()=>{k(),q()}));const g=()=>{m.isOpen=!0},h=()=>{m.isOpen=!1},_=()=>{window.addEventListener("click",C)},C=e=>{m.isOpen&&(c.value.contains(e.target)||(m.isOpen=!1))},k=()=>{m.closeOnClickOutside&&window.removeEventListener("click",C)},$=()=>{if(m.withDropdownCloser){c.value.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{m.isOpen=!1}))}))}},x=()=>{window.addEventListener("popstate",(()=>{m.isOpen&&(m.isOpen=!1)}))},q=()=>{window.removeEventListener("popstate",x)};return{rootRef:c,triggerRef:p,overlayRef:v,menu:m,show:g,hide:h,activeClass:f,modeClass:w,dropupClass:y,directionClass:O}}});const k={class:"v-dropdown-menu__header"},$={class:"v-dropdown-menu__body"},x={class:"v-dropdown-menu__footer"},q={class:"v-dropdown-menu__header"},B={class:"v-dropdown-menu__body"},I={class:"v-dropdown-menu__footer"};C.render=function(e,n,o,r,t,i){return s(),u("div",{class:a(["v-dropdown-menu",[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]]),ref:"rootRef"},["click"===e.menu.mode?(s(),u(c,{key:0},[p("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onClick:n[0]||(n[0]=v((n=>e.menu.isOpen=!e.menu.isOpen),["prevent"]))},[m(e.$slots,"trigger")],512),f(w,{mode:"out-in",name:e.menu.transition},{default:y((()=>[O(p("div",{class:"v-dropdown-menu__container",style:g({"z-index":e.menu.containerZIndex})},[p("div",k,[m(e.$slots,"header")]),p("div",$,[m(e.$slots,"body")]),p("div",x,[m(e.$slots,"footer")])],4),[[h,e.menu.isOpen]])])),_:3},8,["name"])],64)):_("",!0),"hover"===e.menu.mode?(s(),u(c,{key:1},[p("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onMouseover:n[1]||(n[1]=v((function(){return e.show&&e.show(...arguments)}),["prevent"])),onMouseleave:n[2]||(n[2]=v((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},[m(e.$slots,"trigger")],544),f(w,{name:e.menu.transition},{default:y((()=>[O(p("div",{class:"v-dropdown-menu__container",style:g({"z-index":e.menu.containerZIndex}),onMouseover:n[3]||(n[3]=v((function(){return e.show&&e.show(...arguments)}),["prevent"])),onMouseleave:n[4]||(n[4]=v((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},[p("div",q,[m(e.$slots,"header")]),p("div",B,[m(e.$slots,"body")]),p("div",I,[m(e.$slots,"footer")])],36),[[h,e.menu.isOpen]])])),_:3},8,["name"])],64)):_("",!0),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?O((s(),u("div",{key:2,class:"v-dropdown-menu__overlay",ref:"overlayRef",style:g({"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex}),onMousedown:n[5]||(n[5]=v((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},null,36)),[[h,e.menu.isOpen]]):_("",!0)],2)};var Z=(()=>{const e=C;return e.install=n=>{n.component("DropdownMenu",e)},e})();export{Z as default};
2 |
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.mjs:
--------------------------------------------------------------------------------
1 | import { defineComponent, ref, reactive, computed, watch, onMounted, nextTick, onBeforeUnmount, openBlock, createElementBlock, normalizeClass, Fragment, createElementVNode, withModifiers, renderSlot, createVNode, Transition, withCtx, withDirectives, normalizeStyle, vShow, createCommentVNode } from 'vue';
2 |
3 | var script = defineComponent({
4 | name: 'DropdownMenu',
5 | props: {
6 | isOpen: {
7 | type: Boolean,
8 | required: false,
9 | default: false
10 | },
11 | mode: {
12 | type: String,
13 | required: false,
14 | default: 'click'
15 | },
16 | dropup: {
17 | type: Boolean,
18 | required: false,
19 | default: false
20 | },
21 | direction: {
22 | type: String,
23 | required: false,
24 | default: 'left'
25 | },
26 | closeOnClickOutside: {
27 | type: Boolean,
28 | required: false,
29 | default: true
30 | },
31 | withDropdownCloser: {
32 | type: Boolean,
33 | required: false,
34 | default: false
35 | },
36 | containerZIndex: {
37 | type: String,
38 | required: false,
39 | default: '994'
40 | },
41 | overlay: {
42 | type: Boolean,
43 | required: false,
44 | default: true
45 | },
46 | overlayBgColor: {
47 | type: String,
48 | required: false,
49 | default: 'rgba(0, 0, 0, 0.2)'
50 | },
51 | overlayZIndex: {
52 | type: String,
53 | required: false,
54 | default: '992'
55 | },
56 | transition: {
57 | type: String,
58 | required: false,
59 | default: 'default'
60 | }
61 | },
62 | setup(props, _ref) {
63 | let {
64 | emit
65 | } = _ref;
66 | const baseClassName = 'v-dropdown-menu';
67 | const rootRef = ref(null);
68 | const triggerRef = ref(null);
69 | const overlayRef = ref(null);
70 | const menu = reactive({
71 | isOpen: props.isOpen,
72 | mode: props.mode,
73 | dropup: props.dropup,
74 | direction: props.direction,
75 | closeOnClickOutside: props.closeOnClickOutside,
76 | withDropdownCloser: props.withDropdownCloser,
77 | containerZIndex: props.containerZIndex,
78 | overlay: props.overlay,
79 | overlayBgColor: props.overlayBgColor,
80 | overlayZIndex: props.overlayZIndex,
81 | transition: props.transition
82 | });
83 | const activeClass = computed(() => {
84 | return menu.isOpen ? `${baseClassName}--active` : null;
85 | });
86 | const modeClass = computed(() => {
87 | return menu.mode === 'click' ? `${baseClassName}--mode-click` : `${baseClassName}--mode-hover`;
88 | });
89 | const dropupClass = computed(() => {
90 | return menu.dropup ? `${baseClassName}--dropup` : null;
91 | });
92 | const directionClass = computed(() => {
93 | let menuDirection = null;
94 | if (menu.direction === 'left') {
95 | menuDirection = `${baseClassName}--direction-left`;
96 | } else if (menu.direction === 'center') {
97 | menuDirection = `${baseClassName}--direction-center`;
98 | } else {
99 | menuDirection = `${baseClassName}--direction-right`;
100 | }
101 | return menuDirection;
102 | });
103 | watch(() => props.isOpen, value => {
104 | if (menu.mode === 'click') {
105 | if (value) {
106 | setTimeout(() => {
107 | show();
108 | }, 1); // wait, bypass for closeOnClickOutside
109 | } else {
110 | setTimeout(() => {
111 | hide();
112 | }, 1); // wait, bypass for closeOnClickOutside
113 | }
114 | }
115 | });
116 |
117 | watch(() => menu.isOpen, value => {
118 | if (menu.mode === 'click') {
119 | if (value) {
120 | emit('opened', props);
121 | } else {
122 | emit('closed', props);
123 | }
124 | }
125 | });
126 | onMounted(() => {
127 | dropdownCloser();
128 | nextTick(() => {
129 | if (menu.closeOnClickOutside) {
130 | registerCloseDropdownOnClickOutside();
131 | }
132 | });
133 | closeDropdownOnPopState();
134 | });
135 | onBeforeUnmount(() => {
136 | destroyCloseDropdownOnClickOutside();
137 | destroyCloseDropdownOnPopState();
138 | });
139 |
140 | // Methods
141 | const show = () => {
142 | menu.isOpen = true;
143 | };
144 | const hide = () => {
145 | menu.isOpen = false;
146 | };
147 | const registerCloseDropdownOnClickOutside = () => {
148 | window.addEventListener('click', closeDropdownOnClickOutside);
149 | };
150 | const closeDropdownOnClickOutside = e => {
151 | if (menu.isOpen) {
152 | if (!rootRef.value.contains(e.target)) {
153 | menu.isOpen = false;
154 | }
155 | }
156 | };
157 | const destroyCloseDropdownOnClickOutside = () => {
158 | if (menu.closeOnClickOutside) {
159 | window.removeEventListener('click', closeDropdownOnClickOutside);
160 | }
161 | };
162 | const dropdownCloser = () => {
163 | if (menu.withDropdownCloser) {
164 | const dropdown = rootRef.value;
165 | dropdown.querySelectorAll('[dropdown-closer]').forEach(element => {
166 | element.addEventListener('click', () => {
167 | menu.isOpen = false;
168 | });
169 | });
170 | }
171 | };
172 | const closeDropdownOnPopState = () => {
173 | window.addEventListener('popstate', () => {
174 | if (menu.isOpen) {
175 | menu.isOpen = false;
176 | }
177 | });
178 | };
179 | const destroyCloseDropdownOnPopState = () => {
180 | window.removeEventListener('popstate', closeDropdownOnPopState);
181 | };
182 | return {
183 | rootRef,
184 | triggerRef,
185 | overlayRef,
186 | menu,
187 | show,
188 | hide,
189 | activeClass,
190 | modeClass,
191 | dropupClass,
192 | directionClass
193 | };
194 | }
195 | });
196 |
197 | const _hoisted_1 = {
198 | class: "v-dropdown-menu__header"
199 | };
200 | const _hoisted_2 = {
201 | class: "v-dropdown-menu__body"
202 | };
203 | const _hoisted_3 = {
204 | class: "v-dropdown-menu__footer"
205 | };
206 | const _hoisted_4 = {
207 | class: "v-dropdown-menu__header"
208 | };
209 | const _hoisted_5 = {
210 | class: "v-dropdown-menu__body"
211 | };
212 | const _hoisted_6 = {
213 | class: "v-dropdown-menu__footer"
214 | };
215 | function render(_ctx, _cache, $props, $setup, $data, $options) {
216 | return openBlock(), createElementBlock("div", {
217 | class: normalizeClass(["v-dropdown-menu", [_ctx.activeClass, _ctx.modeClass, _ctx.dropupClass, _ctx.directionClass]]),
218 | ref: "rootRef"
219 | }, [_ctx.menu.mode === 'click' ? (openBlock(), createElementBlock(Fragment, {
220 | key: 0
221 | }, [createElementVNode("div", {
222 | class: "v-dropdown-menu__trigger",
223 | ref: "triggerRef",
224 | onClick: _cache[0] || (_cache[0] = withModifiers($event => _ctx.menu.isOpen = !_ctx.menu.isOpen, ["prevent"]))
225 | }, [renderSlot(_ctx.$slots, "trigger")], 512), createVNode(Transition, {
226 | mode: "out-in",
227 | name: _ctx.menu.transition
228 | }, {
229 | default: withCtx(() => [withDirectives(createElementVNode("div", {
230 | class: "v-dropdown-menu__container",
231 | style: normalizeStyle({
232 | 'z-index': _ctx.menu.containerZIndex
233 | })
234 | }, [createElementVNode("div", _hoisted_1, [renderSlot(_ctx.$slots, "header")]), createElementVNode("div", _hoisted_2, [renderSlot(_ctx.$slots, "body")]), createElementVNode("div", _hoisted_3, [renderSlot(_ctx.$slots, "footer")])], 4), [[vShow, _ctx.menu.isOpen]])]),
235 | _: 3
236 | }, 8, ["name"])], 64)) : createCommentVNode("", true), _ctx.menu.mode === 'hover' ? (openBlock(), createElementBlock(Fragment, {
237 | key: 1
238 | }, [createElementVNode("div", {
239 | class: "v-dropdown-menu__trigger",
240 | ref: "triggerRef",
241 | onMouseover: _cache[1] || (_cache[1] = withModifiers(function () {
242 | return _ctx.show && _ctx.show(...arguments);
243 | }, ["prevent"])),
244 | onMouseleave: _cache[2] || (_cache[2] = withModifiers(function () {
245 | return _ctx.hide && _ctx.hide(...arguments);
246 | }, ["prevent"]))
247 | }, [renderSlot(_ctx.$slots, "trigger")], 544), createVNode(Transition, {
248 | name: _ctx.menu.transition
249 | }, {
250 | default: withCtx(() => [withDirectives(createElementVNode("div", {
251 | class: "v-dropdown-menu__container",
252 | style: normalizeStyle({
253 | 'z-index': _ctx.menu.containerZIndex
254 | }),
255 | onMouseover: _cache[3] || (_cache[3] = withModifiers(function () {
256 | return _ctx.show && _ctx.show(...arguments);
257 | }, ["prevent"])),
258 | onMouseleave: _cache[4] || (_cache[4] = withModifiers(function () {
259 | return _ctx.hide && _ctx.hide(...arguments);
260 | }, ["prevent"]))
261 | }, [createElementVNode("div", _hoisted_4, [renderSlot(_ctx.$slots, "header")]), createElementVNode("div", _hoisted_5, [renderSlot(_ctx.$slots, "body")]), createElementVNode("div", _hoisted_6, [renderSlot(_ctx.$slots, "footer")])], 36), [[vShow, _ctx.menu.isOpen]])]),
262 | _: 3
263 | }, 8, ["name"])], 64)) : createCommentVNode("", true), _ctx.menu.overlay && _ctx.menu.closeOnClickOutside && _ctx.menu.mode === 'click' ? withDirectives((openBlock(), createElementBlock("div", {
264 | key: 2,
265 | class: "v-dropdown-menu__overlay",
266 | ref: "overlayRef",
267 | style: normalizeStyle({
268 | 'background-color': _ctx.menu.overlayBgColor,
269 | 'z-index': _ctx.menu.overlayZIndex
270 | }),
271 | onMousedown: _cache[5] || (_cache[5] = withModifiers(function () {
272 | return _ctx.hide && _ctx.hide(...arguments);
273 | }, ["prevent"]))
274 | }, null, 36)), [[vShow, _ctx.menu.isOpen]]) : createCommentVNode("", true)], 2);
275 | }
276 |
277 | script.render = render;
278 |
279 | // Import vue component
280 |
281 | // Default export is installable instance of component.
282 | // IIFE injects install function into component, allowing component
283 | // to be registered via Vue.use() as well as Vue.component(),
284 | var entry = /*#__PURE__*/(() => {
285 | // Assign InstallableComponent type
286 | const installable = script;
287 |
288 | // Attach install function executed by Vue.use()
289 | installable.install = app => {
290 | app.component('DropdownMenu', installable);
291 | };
292 | return installable;
293 | })();
294 |
295 | // It's possible to expose named exports when writing components that can
296 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
297 | // export const RollupDemoDirective = directive;
298 |
299 | export { entry as default };
300 |
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.umd.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
3 | typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) :
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DropdownMenu = {}, global.Vue));
5 | })(this, (function (exports, vue) { 'use strict';
6 |
7 | var script = vue.defineComponent({
8 | name: 'DropdownMenu',
9 | props: {
10 | isOpen: {
11 | type: Boolean,
12 | required: false,
13 | default: false
14 | },
15 | mode: {
16 | type: String,
17 | required: false,
18 | default: 'click'
19 | },
20 | dropup: {
21 | type: Boolean,
22 | required: false,
23 | default: false
24 | },
25 | direction: {
26 | type: String,
27 | required: false,
28 | default: 'left'
29 | },
30 | closeOnClickOutside: {
31 | type: Boolean,
32 | required: false,
33 | default: true
34 | },
35 | withDropdownCloser: {
36 | type: Boolean,
37 | required: false,
38 | default: false
39 | },
40 | containerZIndex: {
41 | type: String,
42 | required: false,
43 | default: '994'
44 | },
45 | overlay: {
46 | type: Boolean,
47 | required: false,
48 | default: true
49 | },
50 | overlayBgColor: {
51 | type: String,
52 | required: false,
53 | default: 'rgba(0, 0, 0, 0.2)'
54 | },
55 | overlayZIndex: {
56 | type: String,
57 | required: false,
58 | default: '992'
59 | },
60 | transition: {
61 | type: String,
62 | required: false,
63 | default: 'default'
64 | }
65 | },
66 | setup(props, _ref) {
67 | let {
68 | emit
69 | } = _ref;
70 | const baseClassName = 'v-dropdown-menu';
71 | const rootRef = vue.ref(null);
72 | const triggerRef = vue.ref(null);
73 | const overlayRef = vue.ref(null);
74 | const menu = vue.reactive({
75 | isOpen: props.isOpen,
76 | mode: props.mode,
77 | dropup: props.dropup,
78 | direction: props.direction,
79 | closeOnClickOutside: props.closeOnClickOutside,
80 | withDropdownCloser: props.withDropdownCloser,
81 | containerZIndex: props.containerZIndex,
82 | overlay: props.overlay,
83 | overlayBgColor: props.overlayBgColor,
84 | overlayZIndex: props.overlayZIndex,
85 | transition: props.transition
86 | });
87 | const activeClass = vue.computed(() => {
88 | return menu.isOpen ? `${baseClassName}--active` : null;
89 | });
90 | const modeClass = vue.computed(() => {
91 | return menu.mode === 'click' ? `${baseClassName}--mode-click` : `${baseClassName}--mode-hover`;
92 | });
93 | const dropupClass = vue.computed(() => {
94 | return menu.dropup ? `${baseClassName}--dropup` : null;
95 | });
96 | const directionClass = vue.computed(() => {
97 | let menuDirection = null;
98 | if (menu.direction === 'left') {
99 | menuDirection = `${baseClassName}--direction-left`;
100 | } else if (menu.direction === 'center') {
101 | menuDirection = `${baseClassName}--direction-center`;
102 | } else {
103 | menuDirection = `${baseClassName}--direction-right`;
104 | }
105 | return menuDirection;
106 | });
107 | vue.watch(() => props.isOpen, value => {
108 | if (menu.mode === 'click') {
109 | if (value) {
110 | setTimeout(() => {
111 | show();
112 | }, 1); // wait, bypass for closeOnClickOutside
113 | } else {
114 | setTimeout(() => {
115 | hide();
116 | }, 1); // wait, bypass for closeOnClickOutside
117 | }
118 | }
119 | });
120 |
121 | vue.watch(() => menu.isOpen, value => {
122 | if (menu.mode === 'click') {
123 | if (value) {
124 | emit('opened', props);
125 | } else {
126 | emit('closed', props);
127 | }
128 | }
129 | });
130 | vue.onMounted(() => {
131 | dropdownCloser();
132 | vue.nextTick(() => {
133 | if (menu.closeOnClickOutside) {
134 | registerCloseDropdownOnClickOutside();
135 | }
136 | });
137 | closeDropdownOnPopState();
138 | });
139 | vue.onBeforeUnmount(() => {
140 | destroyCloseDropdownOnClickOutside();
141 | destroyCloseDropdownOnPopState();
142 | });
143 |
144 | // Methods
145 | const show = () => {
146 | menu.isOpen = true;
147 | };
148 | const hide = () => {
149 | menu.isOpen = false;
150 | };
151 | const registerCloseDropdownOnClickOutside = () => {
152 | window.addEventListener('click', closeDropdownOnClickOutside);
153 | };
154 | const closeDropdownOnClickOutside = e => {
155 | if (menu.isOpen) {
156 | if (!rootRef.value.contains(e.target)) {
157 | menu.isOpen = false;
158 | }
159 | }
160 | };
161 | const destroyCloseDropdownOnClickOutside = () => {
162 | if (menu.closeOnClickOutside) {
163 | window.removeEventListener('click', closeDropdownOnClickOutside);
164 | }
165 | };
166 | const dropdownCloser = () => {
167 | if (menu.withDropdownCloser) {
168 | const dropdown = rootRef.value;
169 | dropdown.querySelectorAll('[dropdown-closer]').forEach(element => {
170 | element.addEventListener('click', () => {
171 | menu.isOpen = false;
172 | });
173 | });
174 | }
175 | };
176 | const closeDropdownOnPopState = () => {
177 | window.addEventListener('popstate', () => {
178 | if (menu.isOpen) {
179 | menu.isOpen = false;
180 | }
181 | });
182 | };
183 | const destroyCloseDropdownOnPopState = () => {
184 | window.removeEventListener('popstate', closeDropdownOnPopState);
185 | };
186 | return {
187 | rootRef,
188 | triggerRef,
189 | overlayRef,
190 | menu,
191 | show,
192 | hide,
193 | activeClass,
194 | modeClass,
195 | dropupClass,
196 | directionClass
197 | };
198 | }
199 | });
200 |
201 | const _hoisted_1 = {
202 | class: "v-dropdown-menu__header"
203 | };
204 | const _hoisted_2 = {
205 | class: "v-dropdown-menu__body"
206 | };
207 | const _hoisted_3 = {
208 | class: "v-dropdown-menu__footer"
209 | };
210 | const _hoisted_4 = {
211 | class: "v-dropdown-menu__header"
212 | };
213 | const _hoisted_5 = {
214 | class: "v-dropdown-menu__body"
215 | };
216 | const _hoisted_6 = {
217 | class: "v-dropdown-menu__footer"
218 | };
219 | function render(_ctx, _cache, $props, $setup, $data, $options) {
220 | return vue.openBlock(), vue.createElementBlock("div", {
221 | class: vue.normalizeClass(["v-dropdown-menu", [_ctx.activeClass, _ctx.modeClass, _ctx.dropupClass, _ctx.directionClass]]),
222 | ref: "rootRef"
223 | }, [_ctx.menu.mode === 'click' ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, {
224 | key: 0
225 | }, [vue.createElementVNode("div", {
226 | class: "v-dropdown-menu__trigger",
227 | ref: "triggerRef",
228 | onClick: _cache[0] || (_cache[0] = vue.withModifiers($event => _ctx.menu.isOpen = !_ctx.menu.isOpen, ["prevent"]))
229 | }, [vue.renderSlot(_ctx.$slots, "trigger")], 512), vue.createVNode(vue.Transition, {
230 | mode: "out-in",
231 | name: _ctx.menu.transition
232 | }, {
233 | default: vue.withCtx(() => [vue.withDirectives(vue.createElementVNode("div", {
234 | class: "v-dropdown-menu__container",
235 | style: vue.normalizeStyle({
236 | 'z-index': _ctx.menu.containerZIndex
237 | })
238 | }, [vue.createElementVNode("div", _hoisted_1, [vue.renderSlot(_ctx.$slots, "header")]), vue.createElementVNode("div", _hoisted_2, [vue.renderSlot(_ctx.$slots, "body")]), vue.createElementVNode("div", _hoisted_3, [vue.renderSlot(_ctx.$slots, "footer")])], 4), [[vue.vShow, _ctx.menu.isOpen]])]),
239 | _: 3
240 | }, 8, ["name"])], 64)) : vue.createCommentVNode("", true), _ctx.menu.mode === 'hover' ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, {
241 | key: 1
242 | }, [vue.createElementVNode("div", {
243 | class: "v-dropdown-menu__trigger",
244 | ref: "triggerRef",
245 | onMouseover: _cache[1] || (_cache[1] = vue.withModifiers(function () {
246 | return _ctx.show && _ctx.show(...arguments);
247 | }, ["prevent"])),
248 | onMouseleave: _cache[2] || (_cache[2] = vue.withModifiers(function () {
249 | return _ctx.hide && _ctx.hide(...arguments);
250 | }, ["prevent"]))
251 | }, [vue.renderSlot(_ctx.$slots, "trigger")], 544), vue.createVNode(vue.Transition, {
252 | name: _ctx.menu.transition
253 | }, {
254 | default: vue.withCtx(() => [vue.withDirectives(vue.createElementVNode("div", {
255 | class: "v-dropdown-menu__container",
256 | style: vue.normalizeStyle({
257 | 'z-index': _ctx.menu.containerZIndex
258 | }),
259 | onMouseover: _cache[3] || (_cache[3] = vue.withModifiers(function () {
260 | return _ctx.show && _ctx.show(...arguments);
261 | }, ["prevent"])),
262 | onMouseleave: _cache[4] || (_cache[4] = vue.withModifiers(function () {
263 | return _ctx.hide && _ctx.hide(...arguments);
264 | }, ["prevent"]))
265 | }, [vue.createElementVNode("div", _hoisted_4, [vue.renderSlot(_ctx.$slots, "header")]), vue.createElementVNode("div", _hoisted_5, [vue.renderSlot(_ctx.$slots, "body")]), vue.createElementVNode("div", _hoisted_6, [vue.renderSlot(_ctx.$slots, "footer")])], 36), [[vue.vShow, _ctx.menu.isOpen]])]),
266 | _: 3
267 | }, 8, ["name"])], 64)) : vue.createCommentVNode("", true), _ctx.menu.overlay && _ctx.menu.closeOnClickOutside && _ctx.menu.mode === 'click' ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
268 | key: 2,
269 | class: "v-dropdown-menu__overlay",
270 | ref: "overlayRef",
271 | style: vue.normalizeStyle({
272 | 'background-color': _ctx.menu.overlayBgColor,
273 | 'z-index': _ctx.menu.overlayZIndex
274 | }),
275 | onMousedown: _cache[5] || (_cache[5] = vue.withModifiers(function () {
276 | return _ctx.hide && _ctx.hide(...arguments);
277 | }, ["prevent"]))
278 | }, null, 36)), [[vue.vShow, _ctx.menu.isOpen]]) : vue.createCommentVNode("", true)], 2);
279 | }
280 |
281 | script.render = render;
282 |
283 | // Import vue component
284 |
285 | // Default export is installable instance of component.
286 | // IIFE injects install function into component, allowing component
287 | // to be registered via Vue.use() as well as Vue.component(),
288 | var entry = /*#__PURE__*/(() => {
289 | // Assign InstallableComponent type
290 | const installable = script;
291 |
292 | // Attach install function executed by Vue.use()
293 | installable.install = app => {
294 | app.component('DropdownMenu', installable);
295 | };
296 | return installable;
297 | })();
298 |
299 | // It's possible to expose named exports when writing components that can
300 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
301 | // export const RollupDemoDirective = directive;
302 |
303 | exports["default"] = entry;
304 |
305 | Object.defineProperty(exports, '__esModule', { value: true });
306 |
307 | }));
308 |
--------------------------------------------------------------------------------
/dist/vue3/v-dropdown-menu.umd.min.js:
--------------------------------------------------------------------------------
1 | !function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],o):o((e="undefined"!=typeof globalThis?globalThis:e||self).DropdownMenu={},e.Vue)}(this,(function(e,o){"use strict";var n=o.defineComponent({name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},setup(e,n){let{emit:t}=n;const r="v-dropdown-menu",i=o.ref(null),d=o.ref(null),l=o.ref(null),s=o.reactive({isOpen:e.isOpen,mode:e.mode,dropup:e.dropup,direction:e.direction,closeOnClickOutside:e.closeOnClickOutside,withDropdownCloser:e.withDropdownCloser,containerZIndex:e.containerZIndex,overlay:e.overlay,overlayBgColor:e.overlayBgColor,overlayZIndex:e.overlayZIndex,transition:e.transition}),a=o.computed((()=>s.isOpen?`${r}--active`:null)),c=o.computed((()=>"click"===s.mode?`${r}--mode-click`:`${r}--mode-hover`)),u=o.computed((()=>s.dropup?`${r}--dropup`:null)),p=o.computed((()=>{let e=null;return e="left"===s.direction?`${r}--direction-left`:"center"===s.direction?`${r}--direction-center`:`${r}--direction-right`,e}));o.watch((()=>e.isOpen),(e=>{"click"===s.mode&&(e?setTimeout((()=>{m()}),1):setTimeout((()=>{v()}),1))})),o.watch((()=>s.isOpen),(o=>{"click"===s.mode&&t(o?"opened":"closed",e)})),o.onMounted((()=>{h(),o.nextTick((()=>{s.closeOnClickOutside&&f()})),g()})),o.onBeforeUnmount((()=>{y(),O()}));const m=()=>{s.isOpen=!0},v=()=>{s.isOpen=!1},f=()=>{window.addEventListener("click",w)},w=e=>{s.isOpen&&(i.value.contains(e.target)||(s.isOpen=!1))},y=()=>{s.closeOnClickOutside&&window.removeEventListener("click",w)},h=()=>{if(s.withDropdownCloser){i.value.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{s.isOpen=!1}))}))}},g=()=>{window.addEventListener("popstate",(()=>{s.isOpen&&(s.isOpen=!1)}))},O=()=>{window.removeEventListener("popstate",g)};return{rootRef:i,triggerRef:d,overlayRef:l,menu:s,show:m,hide:v,activeClass:a,modeClass:c,dropupClass:u,directionClass:p}}});const t={class:"v-dropdown-menu__header"},r={class:"v-dropdown-menu__body"},i={class:"v-dropdown-menu__footer"},d={class:"v-dropdown-menu__header"},l={class:"v-dropdown-menu__body"},s={class:"v-dropdown-menu__footer"};n.render=function(e,n,a,c,u,p){return o.openBlock(),o.createElementBlock("div",{class:o.normalizeClass(["v-dropdown-menu",[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]]),ref:"rootRef"},["click"===e.menu.mode?(o.openBlock(),o.createElementBlock(o.Fragment,{key:0},[o.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onClick:n[0]||(n[0]=o.withModifiers((o=>e.menu.isOpen=!e.menu.isOpen),["prevent"]))},[o.renderSlot(e.$slots,"trigger")],512),o.createVNode(o.Transition,{mode:"out-in",name:e.menu.transition},{default:o.withCtx((()=>[o.withDirectives(o.createElementVNode("div",{class:"v-dropdown-menu__container",style:o.normalizeStyle({"z-index":e.menu.containerZIndex})},[o.createElementVNode("div",t,[o.renderSlot(e.$slots,"header")]),o.createElementVNode("div",r,[o.renderSlot(e.$slots,"body")]),o.createElementVNode("div",i,[o.renderSlot(e.$slots,"footer")])],4),[[o.vShow,e.menu.isOpen]])])),_:3},8,["name"])],64)):o.createCommentVNode("",!0),"hover"===e.menu.mode?(o.openBlock(),o.createElementBlock(o.Fragment,{key:1},[o.createElementVNode("div",{class:"v-dropdown-menu__trigger",ref:"triggerRef",onMouseover:n[1]||(n[1]=o.withModifiers((function(){return e.show&&e.show(...arguments)}),["prevent"])),onMouseleave:n[2]||(n[2]=o.withModifiers((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},[o.renderSlot(e.$slots,"trigger")],544),o.createVNode(o.Transition,{name:e.menu.transition},{default:o.withCtx((()=>[o.withDirectives(o.createElementVNode("div",{class:"v-dropdown-menu__container",style:o.normalizeStyle({"z-index":e.menu.containerZIndex}),onMouseover:n[3]||(n[3]=o.withModifiers((function(){return e.show&&e.show(...arguments)}),["prevent"])),onMouseleave:n[4]||(n[4]=o.withModifiers((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},[o.createElementVNode("div",d,[o.renderSlot(e.$slots,"header")]),o.createElementVNode("div",l,[o.renderSlot(e.$slots,"body")]),o.createElementVNode("div",s,[o.renderSlot(e.$slots,"footer")])],36),[[o.vShow,e.menu.isOpen]])])),_:3},8,["name"])],64)):o.createCommentVNode("",!0),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?o.withDirectives((o.openBlock(),o.createElementBlock("div",{key:2,class:"v-dropdown-menu__overlay",ref:"overlayRef",style:o.normalizeStyle({"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex}),onMousedown:n[5]||(n[5]=o.withModifiers((function(){return e.hide&&e.hide(...arguments)}),["prevent"]))},null,36)),[[o.vShow,e.menu.isOpen]]):o.createCommentVNode("",!0)],2)};var a=(()=>{const e=n;return e.install=o=>{o.component("DropdownMenu",e)},e})();e.default=a,Object.defineProperty(e,"__esModule",{value:!0})}));
2 |
--------------------------------------------------------------------------------
/docs/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | .output
4 | .nuxt
--------------------------------------------------------------------------------
/docs/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@nuxt/eslint-config',
4 | rules: {
5 | 'vue/max-attributes-per-line': 'off',
6 | 'vue/multi-word-component-names': 'off'
7 | }
8 | }
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.iml
3 | .idea
4 | *.log*
5 | .nuxt
6 | .vscode
7 | .DS_Store
8 | coverage
9 | dist
10 | sw.*
11 | .env
12 | .output
13 |
14 | .vercel
15 |
--------------------------------------------------------------------------------
/docs/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 | strict-peer-dependencies=false
3 |
--------------------------------------------------------------------------------
/docs/.nvmrc:
--------------------------------------------------------------------------------
1 | v18.x.x
2 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Docus Starter
2 |
3 | Starter template for [Docus](https://docus.dev).
4 |
5 | ## Clone
6 |
7 | Clone the repository (using `nuxi`):
8 |
9 | ```bash
10 | npx nuxi init -t themes/docus
11 | ```
12 |
13 | ## Setup
14 |
15 | Install dependencies:
16 |
17 | ```bash
18 | yarn install
19 | ```
20 |
21 | ## Development
22 |
23 | ```bash
24 | yarn dev
25 | ```
26 |
27 | ## Edge Side Rendering
28 |
29 | Can be deployed to Vercel Functions, Netlify Functions, AWS, and most Node-compatible environments.
30 |
31 | Look at all the available presets [here](https://v3.nuxtjs.org/guide/deploy/presets).
32 |
33 | ```bash
34 | yarn build
35 | ```
36 |
37 | ## Static Generation
38 |
39 | Use the `generate` command to build your application.
40 |
41 | The HTML files will be generated in the .output/public directory and ready to be deployed to any static compatible hosting.
42 |
43 | ```bash
44 | yarn generate
45 | ```
46 |
47 | ## Preview build
48 |
49 | You might want to preview the result of your build locally, to do so, run the following command:
50 |
51 | ```bash
52 | yarn preview
53 | ```
54 |
55 | ---
56 |
57 | For a detailed explanation of how things work, check out [Docus](https://docus.dev).
58 |
--------------------------------------------------------------------------------
/docs/app.config.ts:
--------------------------------------------------------------------------------
1 | export default defineAppConfig({
2 | docus: {
3 | title: 'v-dropdown-menu',
4 | description: 'Customizable dropdown menu for vue 🟩🔽',
5 | image: '/media/preview.jpg',
6 | socials: {
7 | twitter: 'selimdoyranli',
8 | github: 'selimdoyranli/v-dropdown-menu'
9 | },
10 | aside: {
11 | level: 0,
12 | exclude: []
13 | },
14 | header: {
15 | logo: false,
16 | },
17 | footer: {
18 | iconLinks: [
19 | {
20 | href: 'https://github.com/sponsors/selimdoyranli',
21 | icon: 'simple-icons:githubsponsors'
22 | }
23 | ]
24 | }
25 | }
26 | })
27 |
--------------------------------------------------------------------------------
/docs/components/AppDropdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dropdown Header
8 |
9 |
10 |
15 |
16 |
17 | Dropdown Footer
18 |
19 |
20 |
21 |
25 |
26 |
36 |
--------------------------------------------------------------------------------
/docs/components/AppDropdownAdvanced.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Dropdown Header
9 |
10 |
11 |
16 |
17 |
18 | Dropdown Footer
19 |
20 |
21 |
22 |
23 |
35 |
36 |
118 |
--------------------------------------------------------------------------------
/docs/components/AppDropdownWithCloser.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dropdown Header
8 |
9 |
10 |
16 |
17 |
18 | Dropdown Footer
19 |
20 |
21 |
22 |
26 |
27 |
37 |
--------------------------------------------------------------------------------
/docs/components/AppSpinner.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
--------------------------------------------------------------------------------
/docs/content/0.index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: v-dropdown-menu
3 | navigation: false
4 | layout: page
5 | ---
6 |
7 | ::block-hero
8 | ---
9 | cta:
10 | - Get Started
11 | - /guide
12 | secondary:
13 | - Open on GitHub →
14 | - https://github.com/selimdoyranli/v-dropdown-menu
15 | snippet: npm install v-dropdown-menu
16 | ---
17 |
18 | #title
19 | v-dropdown-menu
20 |
21 | #description
22 | Customizable dropdown menu for vue 🟩🔽
23 | ::
24 |
25 | ::card-grid
26 | #title
27 | Features
28 |
29 | #root
30 | :ellipsis
31 |
32 | #default
33 | ::card
34 | #title
35 | 🛠️ Customizable
36 | #description
37 | Customize the appearance and functionality as you wish
38 | ::
39 | ::card
40 | #title
41 | 📦 Vue2 & Vue3
42 | #description
43 | You're ready for all versions with Vue2 and Vue3 support
44 | ::
45 | ::card
46 | #title
47 | 💉 SSR
48 | #description
49 | Compatible with your Vue Server side rendering projects and Nuxt SSR
50 | ::
51 | ::
52 |
--------------------------------------------------------------------------------
/docs/content/1.guide/0.index.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | Customizable dropdown menu for vue 🟩🔽
4 |
5 | {width="256"}
6 |
7 | ⚡️ Lightweight
8 | 🎨 Interactive
9 | 🛠️ Customizable
10 | 👶🏻 Easy implementation
11 | 📦 Vue2 & Vue3 support
12 | 💉 SSR compatible
13 |
14 |
15 | {width="320"}
16 |
17 | ## Installation
18 |
19 | Install the v-dropdown-menu
20 |
21 | ::code-group
22 |
23 | ```bash [npm]
24 | npm i v-dropdown-menu
25 | ```
26 |
27 | ```bash [yarn]
28 | yarn add v-dropdown-menu
29 | ```
30 |
31 | ::
32 |
33 | ::alert{type="success"}
34 | ✨ Well done! Ready for registration now
35 | ::
36 |
--------------------------------------------------------------------------------
/docs/content/1.guide/1.registration/0.vue3.md:
--------------------------------------------------------------------------------
1 | # Vue3
2 |
3 | #### Global Register
4 |
5 | ```js
6 | import { createApp } from 'vue'
7 | import App from './App.vue'
8 | import DropdownMenu from 'v-dropdown-menu'
9 | import 'v-dropdown-menu/css'
10 |
11 | const app = createApp(App)
12 |
13 | app.use(DropdownMenu)
14 | app.mount('#app')
15 | ```
16 |
17 | #### Local Register
18 | ```html
19 |
23 | ```
24 | #### Via CDN
25 | ```js
26 |
27 |
28 |
29 |
30 |
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/content/1.guide/1.registration/1.vue2.md:
--------------------------------------------------------------------------------
1 | # Vue2
2 |
3 | #### Global Register
4 |
5 | ```js
6 | import Vue from "vue"
7 | import DropdownMenu from "v-dropdown-menu/vue2"
8 | import 'v-dropdown-menu/vue2/css'
9 |
10 | Vue.use(DropdownMenu);
11 | ```
12 |
13 | #### Local Register
14 | ```js
15 | import DropdownMenu from "v-dropdown-menu/vue2"
16 | import 'v-dropdown-menu/vue2/css'
17 |
18 | export default {
19 | components: {
20 | DropdownMenu
21 | }
22 | }
23 | ```
24 | #### Via CDN
25 | ```js
26 |
27 |
28 |
29 |
30 |
37 | ```
38 |
--------------------------------------------------------------------------------
/docs/content/1.guide/2.usage.md:
--------------------------------------------------------------------------------
1 | # Usage
2 |
3 | ```html
4 |
5 |
6 |
7 |
8 |
9 | Dropdown Header
10 |
11 |
12 |
17 |
18 |
19 | Dropdown Footer
20 |
21 |
22 | ```
23 |
24 | #### Props
25 | | Name | Description | Type| Options| Default |
26 | |--|--|--|--|--|
27 | |isOpen|Show or hide for dropdown|Boolean|`true` , `false` | false
28 | |mode|Open variant|String|`click` , `hover` | click
29 | | dropup |Open the menu upwards | Boolean | `true` , `false` | false
30 | |direction|Menu container direction|String|`left` , `right` , `center` | left
31 | |closeOnClickOutside|closes dropdown menu when click outside|Booelan|`true` , `false` | true
32 | |withDropdownCloser| If there is an element in the menu with **dropdown-closer** attribute, clicking on it closes the menu.|Boolean|`true` , `false` | false
33 | |containerZIndex|z-index of menu container|String| .| 994
34 | |overlay|background overlay of dropdown menu (only for click mode) |Boolean| `true` , `false`| true
35 | |overlayBgColor|background-color of overlay |String| ex: `rgba(1, 35, 83, 0.8)`| rgba(0, 0, 0, 0.2)
36 | |overlayZIndex|z-index of overlay|String| .| 992
37 | |transition|custom vue transition for menu|String| .| default
38 |
39 | #### Slots
40 | |Name| Description |
41 | |--|--|
42 | |trigger|trigger for dropdown menu |
43 | |header|header of menu container (optional)|
44 | |body|content of menu (optional)|
45 | |footer|footer of menu container (optional)|
46 |
47 | #### Events (only for click mode)
48 | | |
49 | |--|
50 | | `@opened="dispatchEvent"`|
51 | | `@closed="dispatchEvent"`|
52 |
53 |
54 | ---
55 |
--------------------------------------------------------------------------------
/docs/content/1.guide/_dir.yml:
--------------------------------------------------------------------------------
1 | title: Guide
2 |
--------------------------------------------------------------------------------
/docs/content/2.demo.md:
--------------------------------------------------------------------------------
1 | # Demo
2 |
3 | #### Basic, no options
4 |
5 | ::code-group
6 |
7 | ::code-block{label="Preview" preview}
8 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
9 | ::div
10 | ::AppDropdown
11 | ::
12 | ::
13 |
14 | ```html [Template]
15 |
16 |
17 |
18 |
19 |
20 | Dropdown Header
21 |
22 |
23 |
28 |
29 |
30 | Dropdown Footer
31 |
32 | ```
33 | ::
34 |
35 | #### Default opened, no overlay
36 |
37 | ::code-group
38 |
39 | ::code-block{label="Preview" preview}
40 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
41 | ::div
42 | ::AppDropdown{:isOpen="true" :overlay="false"}
43 | ::
44 | ::
45 |
46 | ```html [Template]
47 |
48 |
49 |
50 |
51 |
52 | Dropdown Header
53 |
54 |
55 |
60 |
61 |
62 | Dropdown Footer
63 |
64 | ```
65 | ::
66 |
67 | #### Default opened, no overlay, no close when click the outside
68 |
69 | ::code-group
70 |
71 | ::code-block{label="Preview" preview}
72 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
73 | ::div
74 | ::AppDropdown{:isOpen="true" :overlay="false" :close-on-click-outside="false"}
75 | ::
76 | ::
77 |
78 | ```html [Template]
79 |
80 |
81 |
82 |
83 |
84 | Dropdown Header
85 |
86 |
87 |
92 |
93 |
94 | Dropdown Footer
95 |
96 | ```
97 | ::
98 |
99 | #### Hover mode
100 |
101 | ::code-group
102 |
103 | ::code-block{label="Preview" preview}
104 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
105 | ::div
106 | ::AppDropdown{mode="hover"}
107 | ::
108 | ::
109 |
110 | ```html [Template]
111 |
112 |
113 |
114 |
115 |
116 | Dropdown Header
117 |
118 |
119 |
124 |
125 |
126 | Dropdown Footer
127 |
128 | ```
129 | ::
130 |
131 | #### Dropup
132 |
133 | ::code-group
134 |
135 | ::code-block{label="Preview" preview}
136 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
137 | ::div
138 | ::AppDropdown{:dropup="true"}
139 | ::
140 | ::
141 |
142 | ```html [Template]
143 |
144 |
145 |
146 |
147 |
148 | Dropdown Header
149 |
150 |
151 |
156 |
157 |
158 | Dropdown Footer
159 |
160 | ```
161 | ::
162 |
163 | #### Direction right
164 |
165 | ::code-group
166 |
167 | ::code-block{label="Preview" preview}
168 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
169 | ::div
170 | ::AppDropdown{direction="right"}
171 | ::
172 | ::
173 |
174 | ```html [Template]
175 |
176 |
177 |
178 |
179 |
180 | Dropdown Header
181 |
182 |
183 |
188 |
189 |
190 | Dropdown Footer
191 |
192 | ```
193 | ::
194 |
195 | #### Direction center
196 |
197 | ::code-group
198 |
199 | ::code-block{label="Preview" preview}
200 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
201 | ::div
202 | ::AppDropdown{direction="center"}
203 | ::
204 | ::
205 |
206 | ```html [Template]
207 |
208 |
209 |
210 |
211 |
212 | Dropdown Header
213 |
214 |
215 |
220 |
221 |
222 | Dropdown Footer
223 |
224 | ```
225 | ::
226 |
227 | #### Custom background color for overlay
228 |
229 | ::code-group
230 |
231 | ::code-block{label="Preview" preview}
232 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
233 | ::div
234 | ::AppDropdown{overlay-bg-color="rgba(1, 35, 83, 0.8)"}
235 | ::
236 | ::
237 |
238 | ```html [Template]
239 |
240 |
241 |
242 |
243 |
244 | Dropdown Header
245 |
246 |
247 |
252 |
253 |
254 | Dropdown Footer
255 |
256 | ```
257 | ::
258 |
259 | #### With dropdown closer
260 |
261 | ::code-group
262 |
263 | ::code-block{label="Preview" preview}
264 | ::div{style="min-height: 50vh; display: grid; place-items: center;"}
265 | ::div
266 | ::AppDropdownWithCloser
267 | ::
268 | ::
269 |
270 | ```html [Template]
271 |
272 |
273 |
274 |
275 |
276 | Dropdown Header
277 |
278 |
279 |
285 |
286 |
287 | Dropdown Footer
288 |
289 | ```
290 | ::
291 |
292 | #### Customized style & callbacks
293 | `Check your browser console for callbacks`
294 |
295 | ::code-group
296 |
297 | ::code-block{label="Preview" preview}
298 | ::div{style="min-height: 90vh; display: grid; place-items: center;"}
299 | ::div
300 | ::AppDropdownAdvanced
301 | ::
302 | ::
303 |
304 | ```html [Template]
305 |
306 |
307 |
308 |
309 |
310 | Dropdown Header
311 |
312 |
313 |
318 |
319 |
320 | Dropdown Footer
321 |
322 | ```
323 |
324 | ```css [Style (Scss)]
325 | .v-dropdown-menu {
326 | $this: &;
327 |
328 | &.custom-style & {
329 | &__container {
330 | border: 0;
331 | border-radius: 5px;
332 | box-shadow: 0 0 24px 0 rgba(0, 0, 0, 0.12);
333 | transform: translateY(-50px);
334 | #{$this} {
335 | &__header {
336 | display: flex;
337 | justify-content: center;
338 | padding: 5px;
339 | background-color: #eee;
340 | }
341 |
342 | &__body {
343 | ul {
344 | margin: 0;
345 | padding: 0;
346 |
347 | li {
348 | list-style: none;
349 |
350 | a {
351 | display: flex;
352 | padding: 1rem;
353 | color: #666;
354 | font-size: 16px;
355 | text-decoration: none;
356 |
357 | &:hover {
358 | background-color: #f2f2f2;
359 | }
360 | }
361 | }
362 | }
363 | }
364 |
365 | &__footer {
366 | display: flex;
367 | justify-content: center;
368 | padding: 5px;
369 | color: #fff;
370 | background-color: #012353;
371 | }
372 | }
373 | }
374 | }
375 |
376 | &.custom-style {
377 | // Custom Transition - Zoom Effect
378 | .zoom-enter-active {
379 | transition: all 0.6s cubic-bezier(0.075, 0.82, 0.165, 1);
380 | }
381 |
382 | .zoom-enter-from,
383 | .zoom-leave-to {
384 | transform: translateY(50px) scale(0.5);
385 | transform-origin: center top;
386 | opacity: 0;
387 | }
388 | {$this}--mode-hover {
389 | .zoom-enter-from,
390 | .zoom-leave-to {
391 | transition-delay: 0.4s;
392 | }
393 | }
394 | }
395 | }
396 |
397 | ```
398 |
399 | ```js [Script]
400 |
409 | ```
410 | ::
411 |
--------------------------------------------------------------------------------
/docs/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import { createResolver } from '@nuxt/kit'
2 |
3 | const { resolve } = createResolver(import.meta.url)
4 |
5 | export default defineNuxtConfig({
6 | extends: '@nuxt-themes/docus',
7 | ssr: true,
8 | components: [
9 | {
10 | prefix: '',
11 | path: resolve('./components'),
12 | global: true
13 | },
14 | ]
15 | })
16 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docus-starter",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "nuxi dev",
7 | "build": "nuxi build",
8 | "generate": "nuxi generate",
9 | "preview": "nuxi preview",
10 | "lint": "eslint ."
11 | },
12 | "devDependencies": {
13 | "@nuxt-themes/docus": "^1.9.0",
14 | "@nuxt/eslint-config": "^0.1.1",
15 | "eslint": "^8.35.0",
16 | "nuxt": "3.3.3"
17 | },
18 | "dependencies": {
19 | "v-dropdown-menu": "^2.0.4"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/docs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/selimdoyranli/v-dropdown-menu/bea96f065f5ccc48776e5505637d195e3bbd7903/docs/public/favicon.ico
--------------------------------------------------------------------------------
/docs/public/media/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/selimdoyranli/v-dropdown-menu/bea96f065f5ccc48776e5505637d195e3bbd7903/docs/public/media/logo.png
--------------------------------------------------------------------------------
/docs/public/media/preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/selimdoyranli/v-dropdown-menu/bea96f065f5ccc48776e5505637d195e3bbd7903/docs/public/media/preview.jpg
--------------------------------------------------------------------------------
/docs/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "@nuxtjs"
4 | ],
5 | "lockFileMaintenance": {
6 | "enabled": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/tokens.config.ts:
--------------------------------------------------------------------------------
1 | import { defineTheme } from 'pinceau'
2 |
3 | export default defineTheme({
4 | color: {
5 | primary: {
6 | 50: "#E5F8E5",
7 | 100: "#CCF2CC",
8 | 200: "#99CC99",
9 | 300: "#66CC66",
10 | 400: "#33CC33",
11 | 500: "#00CC00",
12 | 600: "#008500",
13 | 700: "#006600",
14 | 800: "#004200",
15 | 900: "#002100",
16 | }
17 | }
18 | })
19 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.nuxt/tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/meta/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/selimdoyranli/v-dropdown-menu/bea96f065f5ccc48776e5505637d195e3bbd7903/meta/logo.png
--------------------------------------------------------------------------------
/meta/preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/selimdoyranli/v-dropdown-menu/bea96f065f5ccc48776e5505637d195e3bbd7903/meta/preview.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "v-dropdown-menu",
3 | "version": "2.0.4",
4 | "description": "Customizable dropdown menu for vue 🟩🔽",
5 | "keywords": [
6 | "vue dropdown",
7 | "vue dropdown menu",
8 | "vue3 dropdown",
9 | "vue2 dropdown"
10 | ],
11 | "author": "selimdoyranli",
12 | "contributors": [
13 | "selimdoyranli (https://selimdoyranli.com)"
14 | ],
15 | "bugs": "selimdoyranli@gmail.com",
16 | "homepage": "https://v-dropdown-menu.vercel.app",
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/selimdoyranli/v-dropdown-menu"
20 | },
21 | "main": "dist/vue3/index.js",
22 | "module": "dist/vue3/v-dropdown-menu.mjs",
23 | "browser": "dist/vue3/v-dropdown-menu.global.js",
24 | "unpkg": "dist/vue3/v-dropdown-menu.global.js",
25 | "exports": {
26 | ".": {
27 | "require": "./dist/vue3/v-dropdown-menu.cjs",
28 | "import": "./dist/vue3/index.js",
29 | "browser": "./dist/vue3/v-dropdown-menu.global.js",
30 | "umd": "./dist/vue3/v-dropdown-menu.umd.js",
31 | "unpkg": "./dist/vue3/v-dropdown-menu.global.js",
32 | "module": "./dist/vue3/v-dropdown-menu.mjs"
33 | },
34 | "./css": "./dist/vue3/v-dropdown-menu.css",
35 | "./vue2": "./dist/vue2/index.js",
36 | "./vue2/css": "./dist/vue2/v-dropdown-menu.css"
37 | },
38 | "files": [
39 | "dist",
40 | "vue2",
41 | "meta",
42 | "CHANGELOG.md"
43 | ],
44 | "sideEffects": false,
45 | "scripts": {
46 | "build:vue3": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue3.js",
47 | "build:umd:vue3": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue3.js --format umd",
48 | "build:es:vue3": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue3.js --format es",
49 | "build:cjs:vue3": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue3.js --format cjs",
50 | "build:vue2": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue2.js",
51 | "build:umd:vue2": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue2.js --format umd",
52 | "build:es:vue2": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue2.js --format es",
53 | "build:cjs:vue2": "cross-env NODE_ENV=production rollup --config build/rollup.config.vue2.js --format cjs",
54 | "build": "yarn build:vue3 && yarn build:vue2",
55 | "commit": "cz",
56 | "changelog": "changelogen",
57 | "lint:eslint": "eslint --ext .js,.ts,.json,.vue,.pug --ignore-path .gitignore --ignore-path .eslintignore .",
58 | "lint:eslint:fix": "eslint --fix --ext .js,.ts,.json,.vue,.pug --ignore-path .gitignore --ignore-path .eslintignore .",
59 | "lint:stylelint": "stylelint \"**/*.{css,sass,scss,less,stylus,vue}\" --ignore-path .stylelintignore",
60 | "lint:stylelint:fix": "stylelint --fix \"**/*.{css,sass,scss,less,stylus,vue}\" --ignore-path .stylelintignore",
61 | "prettier": "prettier --config ./.prettierrc.js --ignore-path ./.prettierignore --write \"**/*.{js,ts,json,css,scss,vue,html,pug}\" --end-of-line crlf"
62 | },
63 | "lint-staged": {
64 | "*.{ts,js,vue}": [
65 | "yarn lint:eslint",
66 | "yarn prettier"
67 | ],
68 | "**/*.{css,sass,scss,less,stylus,vue}": [
69 | "yarn lint:stylelint",
70 | "yarn prettier"
71 | ]
72 | },
73 | "dependencies": {},
74 | "devDependencies": {
75 | "@babel/core": "^7.12.10",
76 | "@babel/plugin-transform-modules-umd": "^7.12.1",
77 | "@babel/preset-env": "^7.12.10",
78 | "@babel/preset-typescript": "^7.21.5",
79 | "@commitlint/cli": "^17.6.3",
80 | "@commitlint/config-conventional": "^17.6.3",
81 | "@prettier/plugin-pug": "^2.4.1",
82 | "@rollup/plugin-alias": "^3.1.1",
83 | "@rollup/plugin-babel": "^6.0.3",
84 | "@rollup/plugin-commonjs": "^24.1.0",
85 | "@rollup/plugin-node-resolve": "^15.0.2",
86 | "@rollup/plugin-replace": "^5.0.2",
87 | "@types/node": "^18.13.0",
88 | "@types/stylelint": "14.0.0",
89 | "@typescript-eslint/eslint-plugin": "^5.59.2",
90 | "@typescript-eslint/parser": "^5.14.0",
91 | "@vue/compiler-sfc": "^3.0.4",
92 | "autoprefixer": "^10.1.0",
93 | "babel-core": "^7.0.0-bridge.0",
94 | "babel-plugin-rename-umd-globals": "^1.0.0",
95 | "changelogen": "^0.5.3",
96 | "commitizen": "^4.3.0",
97 | "cross-env": "^7.0.3",
98 | "cz-conventional-changelog": "^3.3.0",
99 | "eslint": "^8.34.0",
100 | "eslint-config-prettier": "^8.6.0",
101 | "eslint-loader": "^4.0.2",
102 | "eslint-plugin-prettier": "^4.2.1",
103 | "eslint-plugin-vue": "^9.9.0",
104 | "flush-promises": "^1.0.2",
105 | "husky": "4.2.5",
106 | "lint-staged": "^13.2.2",
107 | "postcss": "^8.2.1",
108 | "postcss-html": "^1.5.0",
109 | "postcss-scss": "^4.0.6",
110 | "prettier": "^2.8.4",
111 | "pug": "^3.0.2",
112 | "pug-plain-loader": "^1.1.0",
113 | "rollup": "^2.34.2",
114 | "rollup-plugin-css-only": "2.0.0",
115 | "rollup-plugin-postcss": "^4.0.0",
116 | "rollup-plugin-scss": "^4.0.0",
117 | "rollup-plugin-terser": "^7.0.2",
118 | "sass": "^1.58.0",
119 | "sass-loader": "10.1.1",
120 | "stylelint": "14.16.1",
121 | "stylelint-config-prettier": "^9.0.5",
122 | "stylelint-config-rational-order": "^0.1.2",
123 | "stylelint-order": "^6.0.2",
124 | "stylelint-scss": "^4.4.0",
125 | "typescript": "^4.1.2",
126 | "vue-eslint-parser": "^9.1.0",
127 | "vue-eslint-parser-template-tokenizer-pug": "^0.4.10",
128 | "vue-next": "npm:vue@^3.2.20",
129 | "vue-next-rollup-plugin-vue": "npm:rollup-plugin-vue@^6.0.0",
130 | "vue-prev": "npm:vue@^2.6.14",
131 | "vue-prev-composition-api": "npm:@vue/composition-api@^1.2.4",
132 | "vue-prev-rollup-plugin-vue": "npm:rollup-plugin-vue@^5.1.9",
133 | "vue-template-compiler": "^2.6.14"
134 | },
135 | "engines": {
136 | "node": ">=12"
137 | },
138 | "license": "MIT",
139 | "config": {
140 | "commitizen": {
141 | "path": "cz-conventional-changelog"
142 | }
143 | }
144 | }
--------------------------------------------------------------------------------
/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import { DefineComponent } from 'vue-next'
3 |
4 | const Component: DefineComponent<{}, {}, any>
5 | export default Component
6 | }
7 |
--------------------------------------------------------------------------------
/src/vue2/entry.js:
--------------------------------------------------------------------------------
1 | // Import vue component
2 | import component from './v-dropdown-menu.vue'
3 |
4 | // install function executed by Vue.use()
5 | const install = function installDropdownMenu(Vue) {
6 | if (install.installed) return
7 | install.installed = true
8 | Vue.component('DropdownMenu', component)
9 | }
10 |
11 | // Create module definition for Vue.use()
12 | const plugin = {
13 | install
14 | }
15 |
16 | // To auto-install on non-es builds, when vue is found
17 | // eslint-disable-next-line no-redeclare
18 | /* global window, global */
19 | if ('false' === process.env.ES_BUILD) {
20 | let GlobalVue = null
21 |
22 | if (typeof window !== 'undefined') {
23 | GlobalVue = window.Vue
24 | } else if (typeof global !== 'undefined') {
25 | GlobalVue = global.Vue
26 | }
27 |
28 | if (GlobalVue) {
29 | GlobalVue.use(plugin)
30 | }
31 | }
32 |
33 | // Inject install function into component - allows component
34 | // to be registered via Vue.use() as well as Vue.component()
35 | component.install = install
36 |
37 | // Export component by default
38 | export default component
39 |
40 | // It's possible to expose named exports when writing components that can
41 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
42 | // export const RollupDemoDirective = component;
43 |
--------------------------------------------------------------------------------
/src/vue2/v-dropdown-menu.scss:
--------------------------------------------------------------------------------
1 | .v-dropdown-menu {
2 | $this: &;
3 | $slide-offset: 12px;
4 |
5 | position: relative;
6 | display: inline-block;
7 |
8 | &__trigger {
9 | position: relative;
10 | }
11 |
12 | &__container {
13 | position: absolute;
14 | top: 100%;
15 | bottom: auto;
16 | min-width: 230px;
17 | max-width: 100%;
18 | overflow: hidden;
19 | background-color: #fff;
20 | border: 1px solid #ddd;
21 | }
22 |
23 | &--dropup & {
24 | &__container {
25 | top: auto;
26 | bottom: 100%;
27 | }
28 | }
29 |
30 | &--direction-left & {
31 | &__container {
32 | left: 0;
33 | }
34 | }
35 |
36 | &--direction-center & {
37 | &__container {
38 | left: 50%;
39 | transform: translateX(-50%) translateY(0);
40 | }
41 | }
42 |
43 | &--direction-right & {
44 | &__container {
45 | right: 0;
46 | }
47 | }
48 |
49 | &__overlay {
50 | position: fixed;
51 | top: 0;
52 | left: 0;
53 | width: 100%;
54 | height: 100vh;
55 | }
56 |
57 | // Default Transition
58 | .default-enter-active {
59 | transition: all 0.2s ease;
60 | }
61 |
62 | .default-leave-active {
63 | transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
64 | }
65 |
66 | .default-enter,
67 | .default-leave-to {
68 | transform: translateY($slide-offset);
69 | opacity: 0;
70 | }
71 |
72 | &--mode-hover {
73 | .default-enter,
74 | .default-leave-active {
75 | transition-delay: 0.4s;
76 | }
77 | }
78 |
79 | &--dropup {
80 | .default-enter,
81 | .default-leave-to {
82 | transform: translateY(-$slide-offset);
83 | }
84 | {$this}--direction-center {
85 | .default-enter,
86 | .default-leave-to {
87 | transform: translateX(-50%) translateY(-$slide-offset);
88 | }
89 | }
90 | }
91 |
92 | &--direction-center {
93 | .default-enter,
94 | .default-leave-to {
95 | transform: translateX(-50%) translateY($slide-offset);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/vue2/v-dropdown-menu.vue:
--------------------------------------------------------------------------------
1 |
2 | .v-dropdown-menu(ref="rootRef" :class="[activeClass, modeClass, dropupClass, directionClass]")
3 | // For Click Mode
4 | template(v-if="menu.mode === 'click'")
5 | .v-dropdown-menu__trigger(ref="triggerRef" @click.prevent="menu.isOpen = !menu.isOpen")
6 | slot(name="trigger")
7 | transition(:name="menu.transition")
8 | .v-dropdown-menu__container(v-show="menu.isOpen" :style="{ 'z-index': menu.containerZIndex }")
9 | .v-dropdown-menu__header
10 | slot(name="header")
11 | .v-dropdown-menu__body
12 | slot(name="body")
13 | .v-dropdown-menu__footer
14 | slot(name="footer")
15 |
16 | // For Hover Mode
17 | template(v-if="menu.mode === 'hover'")
18 | .v-dropdown-menu__trigger(ref="triggerRef" @mouseover.prevent="show" @mouseleave.prevent="hide")
19 | slot(name="trigger")
20 | transition(:name="menu.transition")
21 | .v-dropdown-menu__container(
22 | v-show="menu.isOpen"
23 | :style="{ 'z-index': menu.containerZIndex }"
24 | @mouseover.prevent="show"
25 | @mouseleave.prevent="hide"
26 | )
27 | .v-dropdown-menu__header
28 | slot(name="header")
29 | .v-dropdown-menu__body
30 | slot(name="body")
31 | .v-dropdown-menu__footer
32 | slot(name="footer")
33 |
34 | // Overlay
35 | .v-dropdown-menu__overlay(
36 | v-if="menu.overlay && menu.closeOnClickOutside && menu.mode === 'click'"
37 | ref="overlayRef"
38 | v-show="menu.isOpen"
39 | :style="{ 'background-color': menu.overlayBgColor, 'z-index': menu.overlayZIndex }"
40 | @mousedown.prevent="hide"
41 | )
42 |
43 |
44 |
229 |
230 |
231 |
--------------------------------------------------------------------------------
/src/vue3/entry.js:
--------------------------------------------------------------------------------
1 | // Import vue component
2 | import component from './v-dropdown-menu.vue'
3 |
4 | // Default export is installable instance of component.
5 | // IIFE injects install function into component, allowing component
6 | // to be registered via Vue.use() as well as Vue.component(),
7 | export default /*#__PURE__*/ (() => {
8 | // Assign InstallableComponent type
9 | const installable = component
10 |
11 | // Attach install function executed by Vue.use()
12 | installable.install = app => {
13 | app.component('DropdownMenu', installable)
14 | }
15 |
16 | return installable
17 | })()
18 |
19 | // It's possible to expose named exports when writing components that can
20 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo';
21 | // export const RollupDemoDirective = directive;
22 |
--------------------------------------------------------------------------------
/src/vue3/v-dropdown-menu.scss:
--------------------------------------------------------------------------------
1 | .v-dropdown-menu {
2 | $this: &;
3 | $slide-offset: 12px;
4 |
5 | position: relative;
6 | display: inline-block;
7 |
8 | &__trigger {
9 | position: relative;
10 | }
11 |
12 | &__container {
13 | position: absolute;
14 | top: 100%;
15 | bottom: auto;
16 | min-width: 230px;
17 | max-width: 100%;
18 | overflow: hidden;
19 | background-color: #fff;
20 | border: 1px solid #ddd;
21 | }
22 |
23 | &--dropup & {
24 | &__container {
25 | top: auto;
26 | bottom: 100%;
27 | }
28 | }
29 |
30 | &--direction-left & {
31 | &__container {
32 | left: 0;
33 | }
34 | }
35 |
36 | &--direction-center & {
37 | &__container {
38 | left: 50%;
39 | transform: translateX(-50%) translateY(0);
40 | }
41 | }
42 |
43 | &--direction-right & {
44 | &__container {
45 | right: 0;
46 | }
47 | }
48 |
49 | &__overlay {
50 | position: fixed;
51 | top: 0;
52 | left: 0;
53 | width: 100%;
54 | height: 100vh;
55 | }
56 |
57 | // Default Transition
58 | .default-enter-active {
59 | transition: all 0.2s ease;
60 | }
61 |
62 | .default-leave-active {
63 | transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
64 | }
65 |
66 | .default-enter-from,
67 | .default-leave-to {
68 | transform: translateY($slide-offset);
69 | opacity: 0;
70 | }
71 |
72 | &--mode-hover {
73 | .default-enter-from,
74 | .default-leave-active {
75 | transition-delay: 0.4s;
76 | }
77 | }
78 |
79 | &--dropup {
80 | .default-enter-from,
81 | .default-leave-to {
82 | transform: translateY(-$slide-offset);
83 | }
84 | {$this}--direction-center {
85 | .default-enter-from,
86 | .default-leave-to {
87 | transform: translateX(-50%) translateY(-$slide-offset);
88 | }
89 | }
90 | }
91 |
92 | &--direction-center {
93 | .default-enter-from,
94 | .default-leave-to {
95 | transform: translateX(-50%) translateY($slide-offset);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/vue3/v-dropdown-menu.vue:
--------------------------------------------------------------------------------
1 |
2 | .v-dropdown-menu(ref="rootRef" :class="[activeClass, modeClass, dropupClass, directionClass]")
3 | // For Click Mode
4 | template(v-if="menu.mode === 'click'")
5 | .v-dropdown-menu__trigger(ref="triggerRef" @click.prevent="menu.isOpen = !menu.isOpen")
6 | slot(name="trigger")
7 | Transition(mode="out-in" :name="menu.transition")
8 | .v-dropdown-menu__container(v-show="menu.isOpen" :style="{ 'z-index': menu.containerZIndex }")
9 | .v-dropdown-menu__header
10 | slot(name="header")
11 | .v-dropdown-menu__body
12 | slot(name="body")
13 | .v-dropdown-menu__footer
14 | slot(name="footer")
15 |
16 | // For Hover Mode
17 | template(v-if="menu.mode === 'hover'")
18 | .v-dropdown-menu__trigger(ref="triggerRef" @mouseover.prevent="show" @mouseleave.prevent="hide")
19 | slot(name="trigger")
20 | Transition(:name="menu.transition")
21 | .v-dropdown-menu__container(
22 | v-show="menu.isOpen"
23 | :style="{ 'z-index': menu.containerZIndex }"
24 | @mouseover.prevent="show"
25 | @mouseleave.prevent="hide"
26 | )
27 | .v-dropdown-menu__header
28 | slot(name="header")
29 | .v-dropdown-menu__body
30 | slot(name="body")
31 | .v-dropdown-menu__footer
32 | slot(name="footer")
33 |
34 | // Overlay
35 | .v-dropdown-menu__overlay(
36 | v-if="menu.overlay && menu.closeOnClickOutside && menu.mode === 'click'"
37 | ref="overlayRef"
38 | v-show="menu.isOpen"
39 | :style="{ 'background-color': menu.overlayBgColor, 'z-index': menu.overlayZIndex }"
40 | @mousedown.prevent="hide"
41 | )
42 |
43 |
44 |
265 |
266 |
267 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "declaration": true,
7 | "declarationDir": "dist/types",
8 | "noUnusedLocals": true,
9 | "noUnusedParameters": true,
10 | "importHelpers": true,
11 | "moduleResolution": "node",
12 | "experimentalDecorators": true,
13 | "esModuleInterop": true,
14 | "allowSyntheticDefaultImports": true,
15 | "sourceMap": true,
16 | "baseUrl": ".",
17 | "newLine": "crlf",
18 | "types": ["node", "@types/node", "vue-prev", "vue-next"],
19 | "paths": {
20 | "@/*": ["src/*"]
21 | },
22 | "plugins": [
23 | {
24 | "transform": "@zerollup/ts-transform-paths",
25 | "exclude": ["*"]
26 | }
27 | ],
28 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
29 | },
30 | "exclude": ["node_modules", "dist", "**/*.spec.ts"]
31 | }
32 |
--------------------------------------------------------------------------------
/vue2/README.md:
--------------------------------------------------------------------------------
1 | entry point for vue2 include
2 |
3 | ```js
4 | import DropdownMenu from 'v-dropdown-menu/vue2'
5 | ```
6 |
--------------------------------------------------------------------------------
/vue2/index.js:
--------------------------------------------------------------------------------
1 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).DropdownMenu={})}(this,(function(e){"use strict";function n(e,n,t,o,i,s,r,d,l,a){"boolean"!=typeof r&&(l=d,d=r,r=!1);const u="function"==typeof t?t.options:t;let p;if(e&&e.render&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns,u._compiled=!0,i&&(u.functional=!0)),o&&(u._scopeId=o),s?(p=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,l(e)),e&&e._registeredComponents&&e._registeredComponents.add(s)},u._ssrRegister=p):n&&(p=r?function(e){n.call(this,a(e,this.$root.$options.shadowRoot))}:function(e){n.call(this,d(e))}),p)if(u.functional){const e=u.render;u.render=function(n,t){return p.call(t),e(n,t)}}else{const e=u.beforeCreate;u.beforeCreate=e?[].concat(e,p):[p]}return t}const t=n({render:function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",{ref:"rootRef",staticClass:"v-dropdown-menu",class:[e.activeClass,e.modeClass,e.dropupClass,e.directionClass]},["click"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{click:function(n){n.preventDefault(),e.menu.isOpen=!e.menu.isOpen}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),"hover"===e.menu.mode?[t("div",{ref:"triggerRef",staticClass:"v-dropdown-menu__trigger",on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[e._t("trigger")],2),t("transition",{attrs:{name:e.menu.transition}},[t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],staticClass:"v-dropdown-menu__container",style:{"z-index":e.menu.containerZIndex},on:{mouseover:function(n){return n.preventDefault(),e.show.apply(null,arguments)},mouseleave:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}},[t("div",{staticClass:"v-dropdown-menu__header"},[e._t("header")],2),t("div",{staticClass:"v-dropdown-menu__body"},[e._t("body")],2),t("div",{staticClass:"v-dropdown-menu__footer"},[e._t("footer")],2)])])]:e._e(),e.menu.overlay&&e.menu.closeOnClickOutside&&"click"===e.menu.mode?t("div",{directives:[{name:"show",rawName:"v-show",value:e.menu.isOpen,expression:"menu.isOpen"}],ref:"overlayRef",staticClass:"v-dropdown-menu__overlay",style:{"background-color":e.menu.overlayBgColor,"z-index":e.menu.overlayZIndex},on:{mousedown:function(n){return n.preventDefault(),e.hide.apply(null,arguments)}}}):e._e()],2)},staticRenderFns:[]},undefined,{name:"DropdownMenu",props:{isOpen:{type:Boolean,required:!1,default:!1},mode:{type:String,required:!1,default:"click"},dropup:{type:Boolean,required:!1,default:!1},direction:{type:String,required:!1,default:"left"},closeOnClickOutside:{type:Boolean,required:!1,default:!0},withDropdownCloser:{type:Boolean,required:!1,default:!1},containerZIndex:{type:String,required:!1,default:"994"},overlay:{type:Boolean,required:!1,default:!0},overlayBgColor:{type:String,required:!1,default:"rgba(0, 0, 0, 0.2)"},overlayZIndex:{type:String,required:!1,default:"992"},transition:{type:String,required:!1,default:"default"}},data(){return{baseClassName:"v-dropdown-menu",menu:{isOpen:this.isOpen,mode:this.mode,dropup:this.dropup,direction:this.direction,closeOnClickOutside:this.closeOnClickOutside,withDropdownCloser:this.withDropdownCloser,containerZIndex:this.containerZIndex,overlay:this.overlay,overlayBgColor:this.overlayBgColor,overlayZIndex:this.overlayZIndex,transition:this.transition}}},computed:{activeClass(){return this.menu.isOpen?`${this.baseClassName}--active`:null},modeClass(){return"click"===this.menu.mode?`${this.baseClassName}--mode-click`:`${this.baseClassName}--mode-hover`},dropupClass(){return this.menu.dropup?`${this.baseClassName}--dropup`:null},directionClass(){let e=null;return e="left"===this.menu.direction?`${this.baseClassName}--direction-left`:"center"===this.menu.direction?`${this.baseClassName}--direction-center`:`${this.baseClassName}--direction-right`,e}},watch:{isOpen(e){"click"===this.menu.mode&&(e?setTimeout((()=>{this.show()}),1):setTimeout((()=>{this.hide()}),1))},"menu.isOpen"(e){"click"===this.menu.mode&&(e?this.$emit("opened",this.$props):this.$emit("closed",this.$props))}},mounted(){this.dropdownCloser(),this.$nextTick((()=>{this.menu.closeOnClickOutside&&this.registerCloseDropdownOnClickOutside()})),this.closeDropdownOnPopState()},beforeDestroy(){this.destroyCloseDropdownOnClickOutside(),this.destroyCloseDropdownOnPopState()},methods:{show(){this.menu.isOpen=!0},hide(){this.menu.isOpen=!1},registerCloseDropdownOnClickOutside(){window.addEventListener("click",this.closeDropdownOnClickOutside)},closeDropdownOnClickOutside(e){this.menu.isOpen&&(this.$refs.rootRef.contains(e.target)||(this.menu.isOpen=!1))},destroyCloseDropdownOnClickOutside(){this.menu.closeOnClickOutside&&window.removeEventListener("click",this.closeDropdownOnClickOutside)},dropdownCloser(){if(this.menu.withDropdownCloser){this.$refs.rootRef.querySelectorAll("[dropdown-closer]").forEach((e=>{e.addEventListener("click",(()=>{this.menu.isOpen=!1}))}))}},closeDropdownOnPopState(){window.addEventListener("popstate",(()=>{this.menu.isOpen&&(this.menu.isOpen=!1)}))},destroyCloseDropdownOnPopState(){window.removeEventListener("popstate",this.closeDropdownOnPopState)}}},undefined,false,undefined,!1,void 0,void 0,void 0),o=function(e){o.installed||(o.installed=!0,e.component("DropdownMenu",t))},i={install:o};{let e=null;"undefined"!=typeof window?e=window.Vue:"undefined"!=typeof global&&(e=global.Vue),e&&e.use(i)}t.install=o,e.default=t,Object.defineProperty(e,"__esModule",{value:!0})}));
2 |
--------------------------------------------------------------------------------