├── .eslintrc.js ├── .github ├── issue_template.md ├── pull_request_template.md └── workflows │ ├── docs.yml │ └── publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── .editorconfig ├── .gitignore ├── .prettierrc.js ├── package.json ├── src │ ├── .vuepress │ │ ├── components │ │ │ └── shared │ │ │ │ └── Footer.vue │ │ ├── config.js │ │ ├── enhanceApp.js │ │ ├── public │ │ │ └── logo.svg │ │ └── sidebar.js │ ├── guide │ │ ├── emits.md │ │ ├── index.md │ │ ├── props.md │ │ ├── sidebar.js │ │ └── slots.md │ └── index.md └── yarn.lock ├── index.html ├── package.json ├── plugins └── copyTypes.mjs ├── public └── logo.svg ├── src ├── App.vue ├── lib │ ├── components │ │ ├── Icons │ │ │ ├── ArrowDown.vue │ │ │ ├── ArrowRight.vue │ │ │ └── DeleteIcon.vue │ │ ├── Tree.vue │ │ └── TreeRow.vue │ ├── index.d.ts │ ├── index.js │ └── utils │ │ ├── expandNodeWithChilds.js │ │ ├── getNodeById.js │ │ ├── getParentNodeById.js │ │ ├── index.js │ │ ├── initNodes.js │ │ ├── removeNodeById.js │ │ ├── searchNodes.js │ │ ├── setNodeById.js │ │ ├── updateChildNodeStatus.js │ │ ├── updateNodeById.js │ │ └── updateNodes.js └── main.js ├── vite.config.js └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'vue-eslint-parser', 3 | env: { 4 | browser: true, 5 | node: true, 6 | }, 7 | extends: [ 8 | 'plugin:vue/vue3-recommended', 9 | ], 10 | rules: { 11 | // js 12 | 'eol-last': 'error', 13 | 'no-trailing-spaces': 'error', 14 | 'comma-style': ['error', 'last'], 15 | 'comma-dangle': ['error', 'always-multiline'], 16 | 'no-multi-spaces': 'error', 17 | quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }], 18 | camelcase: ['error', { properties: 'never' }], 19 | semi: ['error'], 20 | indent: ['error', 2, { SwitchCase: 1 }], 21 | 'object-curly-spacing': ['error', 'always'], 22 | 'arrow-parens': ['error', 'as-needed'], 23 | 'space-before-function-paren': ['error', 'never'], 24 | 'keyword-spacing': ['error', { 'before': true, 'after': true }], 25 | 'space-before-blocks': [2, 'always'], 26 | // vue 27 | 'vue/no-v-html': 'off', 28 | 'vue/singleline-html-element-content-newline': 'off', 29 | 'vue/html-self-closing': ['error', { 30 | html: { 31 | void: 'always', 32 | normal: 'always', 33 | component: 'always', 34 | }, 35 | }], 36 | 'vue/max-attributes-per-line': ['error', { 37 | singleline: 3, 38 | multiline: 1, 39 | }], 40 | 'vue/require-default-prop': 'off', 41 | 'vue/html-closing-bracket-spacing': 'error', 42 | }, 43 | }; 44 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | **Note: for support questions, please use stackoverflow**. This repository's issues are reserved for feature requests and bug reports. 2 | 3 | * **I'm submitting a ...** 4 | - [ ] bug report 5 | - [ ] feature request 6 | - [ ] support request => Please do not submit support request here, see note at the top of this template. 7 | 8 | 9 | * **Do you want to request a *feature* or report a *bug*?** 10 | 11 | 12 | 13 | * **What is the current behavior?** 14 | 15 | 16 | 17 | * **If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem** via 18 | https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5). 19 | 20 | 21 | 22 | * **What is the expected behavior?** 23 | 24 | 25 | 26 | * **What is the motivation / use case for changing the behavior?** 27 | 28 | 29 | 30 | * **Please tell us about your environment:** 31 | 32 | - Version: 2.0.0-beta.X 33 | - Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ] 34 | - Language: [all | TypeScript X.X | ES6/7 | ES5 | Dart] 35 | 36 | 37 | * **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc) -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | * **Please check if the PR fulfills these requirements** 2 | - [ ] The commit message follows our guidelines 3 | - [ ] Tests for the changes have been added (for bug fixes / features) 4 | - [ ] Docs have been added / updated (for bug fixes / features) 5 | 6 | 7 | * **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) 8 | 9 | 10 | 11 | * **What is the current behavior?** (You can also link to an open issue here) 12 | 13 | 14 | 15 | * **What is the new behavior (if this is a feature change)?** 16 | 17 | 18 | 19 | * **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) 20 | 21 | 22 | 23 | * **Other information**: -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | docs: 10 | runs-on: ubuntu-latest 11 | name: Docs 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | - name: Use Node.js 18 | uses: actions/setup-node@v2 19 | with: 20 | node-version: '14' 21 | - name: Install dependencies 22 | run: | 23 | cd docs 24 | yarn 25 | - name: Build VuePress site 26 | run: | 27 | cd docs 28 | yarn build 29 | - name: Deploy to GitHub Pages 30 | uses: crazy-max/ghaction-github-pages@v2 31 | with: 32 | target_branch: gh-pages 33 | build_dir: docs/src/.vuepress/dist 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | name: Publish 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v2 15 | - name: Use Node.js 16 | uses: actions/setup-node@v2 17 | with: 18 | node-version: '16' 19 | - name: Install dependencies 20 | run: npm install 21 | - name: Build app 22 | run: npm run build 23 | - name: Publish to npm 24 | uses: JS-DevTools/npm-publish@v1 25 | with: 26 | token: ${{ secrets.NPM_TOKEN }} 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | dist-ssr 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 seo.do 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 |

2 |

3 | 4 |

5 |

6 | vue3-tree 7 |

8 |

9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

17 |

vue3-tree - A Vue.js 3.0 Tree library

18 | ⚡️ Vue 3.0 Composition API 19 |

20 | 21 | A customizable vuejs tree viewer 22 | 23 | #### Example 24 | [![Edit vue3-tree](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/boring-leaf-v7b2s?file=/src/App.vue) 25 | 26 | #### How to use 27 | You can review the [document](https://teamseodo.github.io/vue3-tree/) for the use of the library. 28 | -------------------------------------------------------------------------------- /docs/.editorconfig: -------------------------------------------------------------------------------- 1 | indent_style = space 2 | indent_size = 2 -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src/.vuepress/.temp 3 | src/.vuepress/.cache -------------------------------------------------------------------------------- /docs/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | useTabs: false, 4 | tabWidth: 2, 5 | semi: true, 6 | singleQuote: true, 7 | trailingComma: 'all', 8 | bracketSpacing: true, 9 | jsxBracketSameLine: false, 10 | }; 11 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3-tree-docs", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "dev": "vuepress dev src", 6 | "build": "vuepress build src --clean-cache", 7 | "format": "prettier . --write" 8 | }, 9 | "main": "index.js", 10 | "license": "MIT", 11 | "private": false, 12 | "devDependencies": { 13 | "@vuepress/plugin-register-components": "^2.0.0-beta.26", 14 | "eslint-plugin-vue": "^7.16.0", 15 | "vuepress": "^2.0.0-beta.26" 16 | }, 17 | "dependencies": { 18 | "prettier": "^2.3.2", 19 | "vue3-tree": "^0.6.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/src/.vuepress/components/shared/Footer.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/src/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const { path } = require('@vuepress/utils'); 2 | const sidebar = require('./sidebar'); 3 | 4 | module.exports = { 5 | base: '/vue3-tree/', 6 | lang: 'en-US', 7 | title: 'vue3-tree', 8 | themeConfig: { 9 | logo: '/logo.svg', 10 | navbar: [ 11 | { text: 'Guide', link: '/guide/' }, 12 | { text: 'seo.do', link: 'https://seo.do', target:'_blank' }, 13 | ], 14 | sidebar, 15 | sidebarDepth: 2, 16 | repo: 'teamseodo/vue3-tree', 17 | }, 18 | plugins: [ 19 | [ 20 | '@vuepress/register-components', 21 | { 22 | components: { 23 | Footer: path.resolve(__dirname, './components/shared/Footer.vue'), 24 | Tree: path.resolve(__dirname, '../../node_modules/vue3-tree/src/lib/index.js'), 25 | }, 26 | }, 27 | ], 28 | ], 29 | }; 30 | -------------------------------------------------------------------------------- /docs/src/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Client app enhancement file. 3 | * 4 | * https://v1.vuepress.vuejs.org/guide/basic-config.html#app-level-enhancements 5 | */ 6 | 7 | export default ({ 8 | Vue, // the version of Vue being used in the VuePress app 9 | options, // the options for the root Vue instance 10 | router, // the router instance for the app 11 | siteData, // site metadata 12 | }) => { 13 | // ...apply enhancements for the site. 14 | }; 15 | -------------------------------------------------------------------------------- /docs/src/.vuepress/public/logo.svg: -------------------------------------------------------------------------------- 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 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /docs/src/.vuepress/sidebar.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '/guide/': require('../guide/sidebar'), 3 | }; 4 | -------------------------------------------------------------------------------- /docs/src/guide/emits.md: -------------------------------------------------------------------------------- 1 | # Emits 2 | 3 | You can access up-to-date data in the operations you perform for the tree with the `emit`'s we use in the package. 4 | 5 | ### `nodeClick` 6 | 7 | This emit is triggered when a node is clicked or selected. 8 | 9 | #### Usage 10 | 11 | ```vue 12 | 13 | ``` 14 | 15 | ```js 16 | const onNodeClick = (node) => { 17 | console.log(node); 18 | }; 19 | ``` 20 | 21 | ### `nodeExpanded` 22 | 23 | When you click on an item, you can use the emit "nodeExpanded" if you want to see the current values of that item and the data below it. This way you will only be able to access the data for that item. 24 | 25 | #### Usage 26 | 27 | ```vue 28 | 29 | ``` 30 | 31 | ```js 32 | const onNodeExpanded = (node, state) => { 33 | console.log('node: ', node); 34 | console.log('state: ', state); 35 | }; 36 | ``` 37 | 38 | ### `update:nodes` 39 | 40 | Returns the current data of the tree when a data is deleted or a checkbox is clicked in the tree. 41 | If you are considering to use `@update:nodes` for only updating data, you can also use `v-model:nodes` 42 | 43 | #### Usage 44 | 45 | ```vue 46 | 47 | ``` 48 | 49 | ```js 50 | const onUpdate = (nodes) => { 51 | console.log('nodes: ', nodes); 52 | }; 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/src/guide/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Installation 4 | 5 | Install the `vue3-tree` package: 6 | 7 | ```sh 8 | npm install vue3-tree 9 | ``` 10 | 11 | or 12 | 13 | ```sh 14 | yarn add vue3-tree 15 | ``` 16 | 17 | ## Quick Start 18 | 19 | After installiation, you need to **import** it in the component and define it in the **template** as shown below. If you want to see your own data in the tree structure, you can define your **data** here by adhering to certain parameters in the data. 20 | 21 | ```vue 22 | 25 | 26 | 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/src/guide/props.md: -------------------------------------------------------------------------------- 1 | # Props 2 | 3 | ### `nodes` 4 | 5 | **type:** Array 6 | 7 | **required:** `true` 8 | 9 | **description:** An array of nodes to show. Available properties of a node object: 10 | 11 | | Key | Type | Description | 12 | | ----------------------------------- | :--------------: | ------------------------------------------------------------------------------------- | 13 | | id **(required)** | number \| string | Used to identify the node within the tree. Its value must be unique in a nodes array. | 14 | | label **(required)** | string | Used to display the option. | 15 | | checked | boolean | Determines whether the node is selected. | 16 | | expanded | boolean | Determines whether the node is expanded. | 17 | | hidden | boolean | Determines whether the node is hidden. | 18 | | undeletable | boolean | Determines whether the node is undeletable when `useRowDelete` is `true`. | 19 | | nodes | Array | Array of node objects. | 20 | 21 | ### `indentSize` 22 | 23 | **type:** number 24 | 25 | **default:** `10` 26 | 27 | **description:** Indent size in pixels of tree nodes. 28 | 29 | ### `gap` 30 | 31 | **type:** number 32 | 33 | **default:** `10` 34 | 35 | **description:** Vertical space between tree nodes. 36 | 37 | ### `rowHoverBackground` 38 | 39 | **type:** string 40 | 41 | **default:** `#e0e0e0` 42 | 43 | **description:** The background style to apply on hover state. 44 | 45 | ### `useCheckbox` 46 | 47 | **type:** boolean 48 | 49 | **default:** `false` 50 | 51 | **description:** Checkbox availability state. 52 | 53 | ### `useIcon` 54 | 55 | **type:** boolean 56 | 57 | **default:** `true` 58 | 59 | **description:** Icon status used for parent nodes according to their extensibility state. 60 | 61 | ### `useRowDelete` 62 | 63 | **type:** boolean 64 | 65 | **default:** `false` 66 | 67 | **description:** It is used in cases where the ability to delete items in the tree will be added. 68 | 69 | ### `showChildCount` 70 | 71 | **type:** boolean 72 | 73 | **default:** `false` 74 | 75 | **description:** Value used to display the number of child items below the parent item. 76 | 77 | ### `expandable` 78 | 79 | **type:** boolean 80 | 81 | **default:** `true` 82 | 83 | **description:** Determines the extensibility of the items in the tree. 84 | 85 | ### `searchText` 86 | 87 | **type:** string 88 | 89 | **default:** `""` 90 | 91 | **description:** Filters tree by a given word. -------------------------------------------------------------------------------- /docs/src/guide/sidebar.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | title: 'Getting Started', 4 | collapsable: true, 5 | children: ['/guide/'], 6 | }, 7 | { 8 | title: 'Props', 9 | collapsable: true, 10 | children: ['/guide/props'], 11 | }, 12 | { 13 | title: 'Slots', 14 | collapsable: true, 15 | children: ['/guide/slots'], 16 | }, 17 | { 18 | title: 'Emits', 19 | collapsable: true, 20 | children: ['/guide/emits'], 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /docs/src/guide/slots.md: -------------------------------------------------------------------------------- 1 | # Slots 2 | 3 | Slots are a feature that we recursively add to the tree structure. 4 | - We added 5 | - 2 icons by default based on tree open or closed status. 6 | - 1 slot according to the deletion process. 7 | - 1 slot to customize the checkbox. 8 | - 1 slot to customize the child count. 9 | 10 | If you want to customize it, it is enough to put your own icons instead of these slots. 11 | 12 | ## Example 13 | 14 | ### Expanded Icon 15 | ```vue 16 | 19 | ``` 20 | ```vue 21 | 24 | ``` 25 | 26 | ### Delete Icon 27 | ```vue 28 | 31 | ``` 32 | ### Checkbox 33 | ```vue 34 | 41 | ``` 42 | 43 | ### Child Count 44 | ```vue 45 | 50 | ``` -------------------------------------------------------------------------------- /docs/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: logo.svg 4 | tagline: 5 | actionText: Quick Start → 6 | actionLink: /installation/ 7 | features: 8 | - title: Nested Search 9 | details: Apply filter on tree items 10 | - title: Checkbox Action 11 | details: Single & multiple select with nested options 12 | - title: Rich props & events 13 | details: A lot of props and events to make it more dynamic 14 | - title: Customizable 15 | details: Rich slot options & easily apply your style 16 | --- 17 | 18 |