├── .gitattributes ├── .gitignore ├── example ├── index.js ├── App.css └── App.vue ├── babel.config.js ├── .editorconfig ├── bili.config.ts ├── themes └── default.css ├── circle.yml ├── types └── vue-slim-tabs.d.ts ├── LICENSE ├── package.json ├── src └── index.js └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist/ 3 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(App) 7 | }) 8 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "poi/babel", 5 | { 6 | jsx: "vue" 7 | } 8 | ] 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /example/App.css: -------------------------------------------------------------------------------- 1 | #app { 2 | max-width: 600px; 3 | margin: 0 auto; 4 | } 5 | 6 | .fade { 7 | color: #999; 8 | font-size: 12px; 9 | } 10 | 11 | .enable-angular { 12 | user-select: none; 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /bili.config.ts: -------------------------------------------------------------------------------- 1 | import { Config } from 'bili' 2 | 3 | const config: Config = { 4 | output: { 5 | format: ['cjs', 'umd', 'esm'], 6 | fileName({ format }) { 7 | if (format === 'umd') { 8 | return 'vue-slim-tabs.js' 9 | } 10 | return 'vue-slim-tabs.[format].js' 11 | }, 12 | moduleName: 'VueSlimTabs' 13 | }, 14 | banner: true 15 | } 16 | 17 | export default config 18 | -------------------------------------------------------------------------------- /themes/default.css: -------------------------------------------------------------------------------- 1 | .vue-tablist { 2 | list-style: none; 3 | display: flex; 4 | padding-left: 0; 5 | border-bottom: 1px solid #e2e2e2; 6 | } 7 | 8 | .vue-tab { 9 | padding: 5px 10px; 10 | cursor: pointer; 11 | user-select: none; 12 | border: 1px solid transparent; 13 | border-bottom-color: #e2e2e2; 14 | border-radius: 3px 3px 0 0; 15 | background-color: white; 16 | position: relative; 17 | bottom: -1px; 18 | } 19 | 20 | .vue-tab[aria-selected="true"] { 21 | border-color: #e2e2e2; 22 | border-bottom-color: transparent; 23 | } 24 | 25 | .vue-tab[aria-disabled="true"] { 26 | cursor: not-allowed; 27 | color: #999; 28 | } 29 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: ~/repo 5 | docker: 6 | - image: circleci/node:latest 7 | branches: 8 | ignore: 9 | - gh-pages # list of branches to ignore 10 | - /release\/.*/ # or ignore regexes 11 | steps: 12 | - checkout 13 | - restore_cache: 14 | key: dependency-cache-{{ checksum "yarn.lock" }} 15 | - run: 16 | name: install dependences 17 | command: yarn 18 | - save_cache: 19 | key: dependency-cache-{{ checksum "yarn.lock" }} 20 | paths: 21 | - ./node_modules 22 | - run: 23 | name: test 24 | command: yarn test 25 | - run: 26 | name: release 27 | command: npx semantic-release 28 | -------------------------------------------------------------------------------- /types/vue-slim-tabs.d.ts: -------------------------------------------------------------------------------- 1 | import { PluginFunction, VueConstructor } from 'vue'; 2 | 3 | export const Tabs: TabsConstructor; 4 | export const Tab: TabConstructor; 5 | export const install: PluginFunction<{}>; 6 | 7 | export interface TabsProps { 8 | defaultIndex?: number; 9 | onSelect?: (val: any) => void; 10 | } 11 | 12 | export interface TabsData { 13 | selectedIndex: number; 14 | } 15 | 16 | export interface TabsMethods { 17 | switchTab: (e: Event, index: number, isDisabled: boolean) => void; 18 | } 19 | 20 | export interface TabProps { 21 | title?: string; 22 | titleSlot?: string; 23 | disabled?: boolean; 24 | } 25 | 26 | export interface TabsConstructor extends VueConstructor { 27 | props: TabsProps; 28 | data: () => TabsData; 29 | methods: TabsMethods; 30 | } 31 | 32 | export interface TabConstructor extends VueConstructor { 33 | props: TabProps; 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) egoist <0x142857@gmail.com> (https://egoistian.com) 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-slim-tabs", 3 | "version": "0.3.0", 4 | "description": "Simple tabs component for Vue.js", 5 | "repository": { 6 | "url": "egoist/vue-slim-tabs", 7 | "type": "git" 8 | }, 9 | "module": "dist/vue-slim-tabs.esm.js", 10 | "main": "dist/vue-slim-tabs.cjs.js", 11 | "unpkg": "dist/vue-slim-tabs.js", 12 | "jsdelivr": "dist/vue-slim-tabs.js", 13 | "cdn": "dist/vue-slim-tabs.js", 14 | "types": "types/vue-slim-tabs.d.ts", 15 | "poi": { 16 | "entry": "example/index.js", 17 | "output": { 18 | "dir": "example/dist" 19 | } 20 | }, 21 | "files": [ 22 | "dist", 23 | "themes", 24 | "types" 25 | ], 26 | "scripts": { 27 | "test": "echo 'no tests!' && npm run lint", 28 | "prepublish": "npm run build", 29 | "lint": "xo", 30 | "build": "bili", 31 | "build:example": "poi --prod", 32 | "dev": "poi -so" 33 | }, 34 | "author": "egoist <0x142857@gmail.com>", 35 | "license": "MIT", 36 | "dependencies": {}, 37 | "devDependencies": { 38 | "bili": "^4.8.0", 39 | "eslint-config-prettier": "^6.1.0", 40 | "eslint-config-rem": "^4.0.0", 41 | "eslint-plugin-prettier": "^3.1.0", 42 | "poi": "^12.6.10", 43 | "prettier": "^1.18.2", 44 | "vue": "^2.6.10", 45 | "vue-github-badge": "^1.0.0", 46 | "vue-template-compiler": "^2.6.10", 47 | "xo": "^0.24.0" 48 | }, 49 | "xo": { 50 | "extends": [ 51 | "rem", 52 | "plugin:prettier/recommended" 53 | ], 54 | "ignores": [ 55 | "example/**" 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export const Tabs = { 2 | name: "tabs", 3 | props: { 4 | defaultIndex: { 5 | default: 0, 6 | type: Number 7 | }, 8 | onSelect: { 9 | type: Function 10 | } 11 | }, 12 | data() { 13 | return { 14 | selectedIndex: this.defaultIndex 15 | }; 16 | }, 17 | methods: { 18 | switchTab(e, index, isDisabled) { 19 | if (!isDisabled) { 20 | this.selectedIndex = index; 21 | this.onSelect && this.onSelect(e, index); 22 | } 23 | } 24 | }, 25 | render() { 26 | const tabs = this.$slots.default.filter( 27 | component => component.componentOptions 28 | ); 29 | 30 | const tabList = []; 31 | tabs.forEach((child, index) => { 32 | const { title, titleSlot, disabled } = child.componentOptions.propsData; 33 | const content = titleSlot ? this.$slots[titleSlot] : title; 34 | const isDisabled = disabled === true || disabled === ""; 35 | 36 | tabList.push( 37 | 46 | ); 47 | }); 48 | 49 | return ( 50 |
51 | 56 | {tabs[this.selectedIndex]} 57 |
58 | ); 59 | } 60 | }; 61 | 62 | export const Tab = { 63 | name: "tab", 64 | props: ["title", "titleSlot", "disabled"], 65 | render() { 66 | return ( 67 |
68 | {this.$slots.default} 69 |
70 | ); 71 | } 72 | }; 73 | 74 | export function install(Vue) { 75 | Vue.component(Tabs.name, Tabs); 76 | Vue.component(Tab.name, Tab); 77 | } 78 | -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 73 | 74 | 75 | 76 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tabs 2 | 3 | [![NPM version](https://img.shields.io/npm/v/vue-slim-tabs.svg?style=flat)](https://npmjs.com/package/vue-slim-tabs) [![NPM downloads](https://img.shields.io/npm/dm/vue-slim-tabs.svg?style=flat)](https://npmjs.com/package/vue-slim-tabs) [![CircleCI](https://circleci.com/gh/egoist/vue-slim-tabs/tree/master.svg?style=shield)](https://circleci.com/gh/egoist/vue-slim-tabs/tree/master) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/egoist/donate) 4 | 5 | ## Install 6 | 7 | ```bash 8 | yarn add vue-slim-tabs 9 | ``` 10 | 11 | CDN: [UNPKG](https://unpkg.com/vue-slim-tabs/dist/) | [jsDelivr](https://cdn.jsdelivr.net/npm/vue-slim-tabs/dist/) 12 | 13 | ## Usage 14 | 15 | ```vue 16 | 29 | 30 | 39 | 40 | 41 | 42 | ``` 43 | 44 | You can use it as a plugin if you don't mind registering components globally: 45 | 46 | ```js 47 | import * as Tabs from 'vue-slim-tabs' 48 | 49 | Vue.use(Tabs) 50 | ``` 51 | 52 |
Use a slot as tab title
53 | 54 | ```vue 55 | 66 | ``` 67 |
68 | 69 | ## Props 70 | 71 | ### `` 72 | 73 | #### defaultIndex 74 | 75 | Type: `Number`
76 | Default: `0` 77 | 78 | Index of selected tab on the first render. 79 | 80 | #### onSelect 81 | 82 | Type: `function`
83 | Default: `undefined` 84 | 85 | The function to invoke as user selects a tab by clicking: 86 | 87 | ```js 88 | function onSelect(e, index) { 89 | // e: click event 90 | // index: index of selected tab 91 | } 92 | ``` 93 | 94 | ### `` 95 | 96 | #### title 97 | 98 | Type: `string` `vNode`
99 | Required: required unless `titleSlot` is set 100 | 101 | Use a string or vNode as tab title. 102 | 103 | #### titleSlot 104 | 105 | Type: `string` 106 | 107 | Use a slot as the tab title. 108 | 109 | #### disabled 110 | 111 | Type: `Boolean`
112 | Default: `undefined` 113 | 114 | Disable relevant tab, i.e. make it unselectable. 115 | 116 | ## Development 117 | 118 | Run the example with [Poi](https://poi.js.org): 119 | 120 | ```bash 121 | cd vue-slim-tabs 122 | yarn 123 | yarn dev 124 | ``` 125 | 126 | ## Contributing 127 | 128 | 1. Fork it! 129 | 2. Create your feature branch: `git checkout -b my-new-feature` 130 | 3. Commit your changes: `git commit -am 'Add some feature'` 131 | 4. Push to the branch: `git push origin my-new-feature` 132 | 5. Submit a pull request :D 133 | 134 | 135 | ## Author 136 | 137 | **vue-slim-tabs** © [egoist](https://github.com/egoist), Released under the [MIT](./LICENSE) License.
138 | Authored and maintained by egoist with help from contributors ([list](https://github.com/egoist/vue-slim-tabs/contributors)). 139 | 140 | > [egoist.moe](https://egoist.moe) · GitHub [@egoist](https://github.com/egoist) · Twitter [@_egoistlily](https://twitter.com/rem_rin_rin) 141 | --------------------------------------------------------------------------------