├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
└── workflows
│ └── create-relaease.yml
├── .gitignore
├── CHANGELOG_CN.md
├── LICENSE
├── README.md
├── babel.config.js
├── build
└── webpack.config.js
├── example
├── App.vue
├── assets
│ └── icon
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.js
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ └── iconfont.woff
├── index.html
└── main.js
├── lib
└── ly-tab.common.js
├── package.json
├── src
├── index.js
├── tab-bar.vue
├── tab-item.vue
├── tabs.vue
└── utils
│ └── requestAnimationFrame.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = tab
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | lib
3 | node_modules
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | es2021: true
7 | },
8 | extends: [
9 | 'eslint:recommended',
10 | 'plugin:vue/recommended',
11 | 'plugin:prettier/recommended'
12 | ],
13 | // 规则覆盖
14 | rules: {
15 | 'prettier/prettier': [
16 | 'warn',
17 | {
18 | singleQuote: true, // 使用单引号
19 | useTabs: true, // 使用tab代替空格缩进
20 | // tabWidth: 2,
21 | trailingComma: 'none' // 尾部的逗号
22 | },
23 | {
24 | usePrettierrc: false // 不使用.prettierrc配置文件
25 | }
26 | ],
27 | 'implicit-arrow-linebreak': ['warn', 'beside'],
28 | 'vue/require-default-prop': 0
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/.github/workflows/create-relaease.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | tags:
4 | - 'v*' # Push events to matching tags starts with 'v', i.e. v1.0, v20.15.10
5 |
6 | name: Create Release
7 |
8 | jobs:
9 | build:
10 | name: Create Release
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout code
14 | uses: actions/checkout@v3
15 | - name: Create Release for Tag
16 | id: release_tag
17 | uses: yyx990803/release-tag@master # https://github.com/yyx990803/release-tag
18 | env:
19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 | with:
21 | tag_name: ${{ github.ref }}
22 | body: |
23 | 更新内容请参见 [CHANGELOG](https://github.com/ScoutYin/ly-tab/blob/master/CHANGELOG_CN.md)。
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | # lock file
4 | yarn.lock
--------------------------------------------------------------------------------
/CHANGELOG_CN.md:
--------------------------------------------------------------------------------
1 | ### 3.0.1 (2022-04-29)
2 |
3 | Fix:
4 |
5 | - 移除 babel-loader 生产依赖
6 |
7 | ### 3.0.0 (2022-04-29)
8 |
9 | Features:
10 |
11 | - LyTabs、LyTabItem、LyTabBar 组件
12 |
13 | ### 2.1.3 (2022-04-16)
14 |
15 | Fixed:
16 |
17 | - core 修复`ly-tabbar`组件销毁生命周期钩子名拼写错误(`destoryed` -> `destroyed`)
18 |
19 | ### 2.1.2 (2018-11-17)
20 |
21 | Fixed:
22 |
23 | - core 修复组件内部非点击修改selectId外部不更新的问题
24 | - core 修复lineWidth设置不生效的问题
25 |
26 | ### 2.1.1 (2018-9-22)
27 |
28 | Features:
29 |
30 | - core:支持ssr
31 |
32 | Fixed:
33 |
34 | - core:修复当默认选中item不在可视区时,tabbar未做位置调整使选中的item显示在可视区的bug
35 |
36 | ### 2.1.0 (2018-8-14)
37 |
38 | Features:
39 |
40 | - core:点击item时可触发ly-tab的change事件
41 | - core:可指定labelKey作为item数据中文字的字段名,不指定默认为label
42 | - style:优化组件样式
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 ScoutYin
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 | # Ly-Tab 3.x版本(非Vue3)
2 |
3 | 请注意,这个版本依然是 **Vue2** 版本。如果你想使用 **Vue3** 版本,请[点击这里](https://github.com/ScoutYin/fun-tab)。
4 |
5 | 当前的3.x版本和之前2.x版本存在使用方法及API上的不兼容,使用者如需升级,请参照3.x版本。**强烈建议**使用3.x版本,2.x版本将不再进行更新维护。
6 |
7 | ## 基本效果展示
8 |
9 | 
10 |
11 | ## 安装
12 |
13 | ```shell
14 | yarn add ly-tab
15 | # or
16 | npm i ly-tab
17 | ```
18 | ## 使用
19 |
20 | ### 全局注册
21 |
22 | ```js
23 | import LyTab from 'ly-tab';
24 |
25 | Vue.use(LyTab);
26 | ```
27 |
28 | ### 局部注册
29 |
30 | ```js
31 | import { LyTabs, LyTabBar, LyTabItem } from 'ly-tab';
32 |
33 | export default {
34 | components: {
35 | LyTabs,
36 | LyTabBar,
37 | LyTabItem
38 | }
39 | // ...
40 | }
41 | ```
42 |
43 | ## LyTabs
44 |
45 | ### 简单示例
46 |
47 | ```javascript
48 |
49 |
50 |
51 |
52 | ```
53 |
54 | ```javascript
55 | export default {
56 | data() {
57 | return {
58 | value: '1'
59 | }
60 | }
61 | }
62 | ```
63 |
64 | ### 属性
65 |
66 | | 属性 | 说明 | 类型 | 默认值 |
67 | | ---- | -----|---|----|
68 | | value | 当前激活的 `tab` 的 name 属性值 | `string \| number` | '' |
69 | | lineWidth | 当前激活 `tab` 下划线的宽度,单位 `px` | `number` | 30 |
70 | | lineHeight | 当前激活 `tab` 下划线的高度,单位 `px` | `number` | 3 |
71 | | activeColor | 激活状态下 `tab` 文案及下划线的颜色 | `string` | #1677ff |
72 | | additionalX | 近似等于超出边界时最大可拖动距离,单位 `px` | `number` | 50 |
73 | | reBoundExponent | 惯性回弹指数,值越大,惯性回弹距离越长 | `number` | 10 |
74 | | inertialDuration | 惯性滑动过程的持续时间,值越小,感知上阻力越大,可近似认为惯性滑动过程速度减为零所需的时间(ms) | `number` | 1000 |
75 | | reBoundingDuration | 回弹过程动画duration,单位 `ms` | `number` | 360 |
76 |
77 | ### 事件
78 |
79 | | 事件名 | 说明 | 回调参数 |
80 | | ----- | ---- | ----- |
81 | | change | 切换激活 tab 项的回调 | `name: string \| number` |
82 |
83 | ### 方法
84 |
85 | | 方法名 | 说明 | 参数 | 返回值 |
86 | | ----- | ---- | ---- | ---- |
87 | | resize | 外层元素大小或组件布局、尺寸变化时,可以调用此方法来进行重绘 | - | - |
88 |
89 | ### 插槽
90 |
91 | | 名称 | 说明 |
92 | | --- | ---- |
93 | | default | 默认插槽,放置 `LyTabItem` 组件 |
94 |
95 | ## LyTabItem
96 |
97 | ### 属性
98 |
99 | | 属性 | 说明 | 类型 | 默认值 |
100 | | ---- | -----|---|----|
101 | | title | 选项卡显示文字 | `string` | - |
102 | | name | 选项卡标识符 | `string \| number` | 选项卡索引 |
103 | | badge | 右上角徽标内容 | `string \| number` | - |
104 |
105 | ### 插槽
106 |
107 | | 名称 | 说明 |
108 | | --- | ---- |
109 | | default | 选项卡文字内容插槽,优先级高于传入的 `title` 属性 |
110 | | icon | 选项卡图标 |
111 |
112 | ## LyTabBar
113 |
114 | ### 简单示例
115 |
116 | ```javascript
117 |
118 |
119 |
120 |
121 | ```
122 |
123 | ```javascript
124 | export default {
125 | data() {
126 | return {
127 | value: '1'
128 | }
129 | }
130 | }
131 | ```
132 |
133 | ### 属性
134 |
135 | | 属性 | 说明 | 类型 | 默认值 |
136 | | ---- | -----|---|----|
137 | | value | 当前激活的 `tab` 的 name 属性值 | `string \| number` | '' |
138 | | activeColor | 激活状态下 `tab` 文案及icon的颜色 | `string` | #1677ff |
139 |
140 | ### 事件
141 |
142 | | 事件名 | 说明 | 回调参数 |
143 | | ----- | ---- | ----- |
144 | | change | 切换激活 tab 项的回调 | `name: string \| number` |
145 |
146 | ### 插槽
147 |
148 | | 名称 | 说明 |
149 | | --- | ---- |
150 | | default | 默认插槽,放置 `LyTabItem` 组件 |
151 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@babel/preset-env'],
3 | only: ['./src']
4 | };
5 |
--------------------------------------------------------------------------------
/build/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { merge } = require('webpack-merge');
2 | const path = require('path');
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 | const VueLoaderPlugin = require('vue-loader/lib/plugin');
5 |
6 | const rootDir = process.cwd();
7 |
8 | const devServerConfig = {
9 | port: 8081,
10 | historyApiFallback: true,
11 | static: {
12 | publicPath: '/'
13 | },
14 | client: {
15 | // 重连次数
16 | reconnect: 10
17 | },
18 | onListening() {
19 | console.log();
20 | console.log(
21 | `You application is running here http://localhost:${devServerConfig.port}`
22 | );
23 | }
24 | };
25 |
26 | const commonConfig = {
27 | module: {
28 | rules: [
29 | {
30 | test: /\.js$/,
31 | exclude: /node_modules/,
32 | use: 'babel-loader'
33 | },
34 | {
35 | test: /\.vue$/,
36 | use: 'vue-loader'
37 | },
38 | {
39 | test: /\.css/,
40 | use: ['vue-style-loader', 'css-loader']
41 | }
42 | ]
43 | },
44 | optimization: {
45 | minimize: false
46 | }
47 | };
48 |
49 | const devConfig = {
50 | mode: 'development',
51 | entry: path.resolve(rootDir, 'example/main.js'),
52 | output: {
53 | path: path.resolve(rootDir, 'dist'),
54 | filename: '[name].bundle.js'
55 | },
56 | devServer: devServerConfig,
57 | stats: 'errors-only',
58 |
59 | resolve: {
60 | extensions: ['.vue', '.js', '...'],
61 | alias: {
62 | vue$: 'vue/dist/vue.esm.js',
63 | 'ly-tab': path.resolve(rootDir, 'src/index.js')
64 | }
65 | },
66 |
67 | plugins: [
68 | new VueLoaderPlugin(),
69 | new HtmlWebpackPlugin({
70 | filename: 'index.html',
71 | inject: 'body',
72 | template: 'example/index.html'
73 | })
74 | ]
75 | };
76 |
77 | const prodConfig = {
78 | mode: 'production',
79 | entry: path.resolve(rootDir, 'src/index.js'),
80 | output: {
81 | path: path.resolve(rootDir, 'lib'),
82 | filename: 'ly-tab.common.js',
83 | library: {
84 | type: 'commonjs'
85 | }
86 | },
87 | resolve: {
88 | extensions: ['.vue', '.js', '...']
89 | },
90 | plugins: [new VueLoaderPlugin()]
91 | };
92 |
93 | module.exports = (env, args) => {
94 | if (args.mode === 'production') {
95 | return merge(commonConfig, prodConfig);
96 | } else {
97 | return merge(commonConfig, devConfig);
98 | }
99 | };
100 |
--------------------------------------------------------------------------------
/example/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
请使用移动端调试模式或者真机调试
14 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
94 |
95 |
116 |
--------------------------------------------------------------------------------
/example/assets/icon/iconfont.css:
--------------------------------------------------------------------------------
1 |
2 | @font-face {font-family: "ly-icon";
3 | src: url('iconfont.eot?t=1533392363195'); /* IE9*/
4 | src: url('iconfont.eot?t=1533392363195#iefix') format('embedded-opentype'), /* IE6-IE8 */
5 | url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),
6 | url('iconfont.ttf?t=1533392363195') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
7 | url('iconfont.svg?t=1533392363195#ly-icon') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .ly-icon {
11 | font-family:"ly-icon" !important;
12 | font-size:16px;
13 | font-style:normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .ly-icon-sousuo:before { content: "\e6a8"; }
19 |
20 | .ly-icon-wode:before { content: "\e67b"; }
21 |
22 | .ly-icon-icon--:before { content: "\e746"; }
23 |
24 | .ly-icon-home:before { content: "\e7c6"; }
25 |
26 |
--------------------------------------------------------------------------------
/example/assets/icon/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScoutYin/ly-tab/b472b0756f584526f3105864d0ab01ed8a493092/example/assets/icon/iconfont.eot
--------------------------------------------------------------------------------
/example/assets/icon/iconfont.js:
--------------------------------------------------------------------------------
1 | (function(window){var svgSprite='';var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window)
--------------------------------------------------------------------------------
/example/assets/icon/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
46 |
--------------------------------------------------------------------------------
/example/assets/icon/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScoutYin/ly-tab/b472b0756f584526f3105864d0ab01ed8a493092/example/assets/icon/iconfont.ttf
--------------------------------------------------------------------------------
/example/assets/icon/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScoutYin/ly-tab/b472b0756f584526f3105864d0ab01ed8a493092/example/assets/icon/iconfont.woff
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ly-tab使用demo
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/example/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue';
4 | import App from './App';
5 |
6 | Vue.config.productionTip = false;
7 |
8 | /* eslint-disable no-new */
9 | new Vue({
10 | el: '#app',
11 | components: { App },
12 | template: ''
13 | });
14 |
--------------------------------------------------------------------------------
/lib/ly-tab.common.js:
--------------------------------------------------------------------------------
1 | /******/ (function() { // webpackBootstrap
2 | /******/ var __webpack_modules__ = ({
3 |
4 | /***/ 696:
5 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
6 |
7 | "use strict";
8 | __webpack_require__.r(__webpack_exports__);
9 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81);
10 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);
11 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645);
12 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);
13 | // Imports
14 |
15 |
16 | var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
17 | // Module
18 | ___CSS_LOADER_EXPORT___.push([module.id, "\n.ly-tab-bar-wrap {\n\tdisplay: flex;\n\tflex-wrap: nowrap;\n\talign-items: stretch;\n\tmin-height: 50px;\n\tbackground: #fff;\n}\n.ly-tab-bar .ly-tab-item {\n\tflex: 1 1;\n\tfont-size: 12px;\n}\n.ly-tab-bar .ly-tab-item__badge {\n\ttop: 2px;\n\tright: 0;\n}\n", ""]);
19 | // Exports
20 | /* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___);
21 |
22 |
23 | /***/ }),
24 |
25 | /***/ 918:
26 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
27 |
28 | "use strict";
29 | __webpack_require__.r(__webpack_exports__);
30 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81);
31 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);
32 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645);
33 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);
34 | // Imports
35 |
36 |
37 | var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
38 | // Module
39 | ___CSS_LOADER_EXPORT___.push([module.id, "\n.ly-tab-item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: center;\n\talign-items: center;\n}\n.ly-tab-item__wrap {\n\tposition: relative;\n}\n.ly-tab-item__badge {\n\tposition: absolute;\n\ttop: 4px;\n\tright: -10px;\n\tpadding: 1px 4px;\n\tmin-width: 8px;\n\tfont-size: 9px;\n\tline-height: 12px;\n\tcolor: #fff;\n\tbackground: #ff411c;\n\twhite-space: nowrap;\n\tborder-radius: 100px;\n\ttransform: translate(50%, -50%);\n\ttext-align: center;\n}\n", ""]);
40 | // Exports
41 | /* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___);
42 |
43 |
44 | /***/ }),
45 |
46 | /***/ 374:
47 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
48 |
49 | "use strict";
50 | __webpack_require__.r(__webpack_exports__);
51 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81);
52 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);
53 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645);
54 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);
55 | // Imports
56 |
57 |
58 | var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
59 | // Module
60 | ___CSS_LOADER_EXPORT___.push([module.id, "\n.ly-tabs {\n\toverflow: hidden;\n\tposition: relative;\n\twidth: 100%;\n\tborder-bottom: 1px solid #eee;\n\tbackground: #fff;\n}\n.ly-tabs__tab-list {\n\tposition: relative;\n\tdisplay: flex;\n\tflex-wrap: nowrap;\n\tmin-width: 100%;\n\twidth: min-content;\n}\n.ly-tabs__active-line {\n\tposition: absolute;\n\tbottom: 3px;\n\tleft: 0;\n\twidth: 30px;\n\theight: 3px;\n\tborder-radius: 4px;\n}\n.ly-tabs .ly-tab-item {\n\tpadding: 10px 12px;\n\tflex: 1 1 auto;\n\tfont-size: 14px;\n\ttext-align: center;\n\twhite-space: nowrap;\n}\n", ""]);
61 | // Exports
62 | /* harmony default export */ __webpack_exports__["default"] = (___CSS_LOADER_EXPORT___);
63 |
64 |
65 | /***/ }),
66 |
67 | /***/ 645:
68 | /***/ (function(module) {
69 |
70 | "use strict";
71 |
72 |
73 | /*
74 | MIT License http://www.opensource.org/licenses/mit-license.php
75 | Author Tobias Koppers @sokra
76 | */
77 | module.exports = function (cssWithMappingToString) {
78 | var list = []; // return the list of modules as css string
79 |
80 | list.toString = function toString() {
81 | return this.map(function (item) {
82 | var content = "";
83 | var needLayer = typeof item[5] !== "undefined";
84 |
85 | if (item[4]) {
86 | content += "@supports (".concat(item[4], ") {");
87 | }
88 |
89 | if (item[2]) {
90 | content += "@media ".concat(item[2], " {");
91 | }
92 |
93 | if (needLayer) {
94 | content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {");
95 | }
96 |
97 | content += cssWithMappingToString(item);
98 |
99 | if (needLayer) {
100 | content += "}";
101 | }
102 |
103 | if (item[2]) {
104 | content += "}";
105 | }
106 |
107 | if (item[4]) {
108 | content += "}";
109 | }
110 |
111 | return content;
112 | }).join("");
113 | }; // import a list of modules into the list
114 |
115 |
116 | list.i = function i(modules, media, dedupe, supports, layer) {
117 | if (typeof modules === "string") {
118 | modules = [[null, modules, undefined]];
119 | }
120 |
121 | var alreadyImportedModules = {};
122 |
123 | if (dedupe) {
124 | for (var k = 0; k < this.length; k++) {
125 | var id = this[k][0];
126 |
127 | if (id != null) {
128 | alreadyImportedModules[id] = true;
129 | }
130 | }
131 | }
132 |
133 | for (var _k = 0; _k < modules.length; _k++) {
134 | var item = [].concat(modules[_k]);
135 |
136 | if (dedupe && alreadyImportedModules[item[0]]) {
137 | continue;
138 | }
139 |
140 | if (typeof layer !== "undefined") {
141 | if (typeof item[5] === "undefined") {
142 | item[5] = layer;
143 | } else {
144 | item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}");
145 | item[5] = layer;
146 | }
147 | }
148 |
149 | if (media) {
150 | if (!item[2]) {
151 | item[2] = media;
152 | } else {
153 | item[1] = "@media ".concat(item[2], " {").concat(item[1], "}");
154 | item[2] = media;
155 | }
156 | }
157 |
158 | if (supports) {
159 | if (!item[4]) {
160 | item[4] = "".concat(supports);
161 | } else {
162 | item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}");
163 | item[4] = supports;
164 | }
165 | }
166 |
167 | list.push(item);
168 | }
169 | };
170 |
171 | return list;
172 | };
173 |
174 | /***/ }),
175 |
176 | /***/ 81:
177 | /***/ (function(module) {
178 |
179 | "use strict";
180 |
181 |
182 | module.exports = function (i) {
183 | return i[1];
184 | };
185 |
186 | /***/ }),
187 |
188 | /***/ 923:
189 | /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
190 |
191 | // style-loader: Adds some css to the DOM by adding a
62 |
--------------------------------------------------------------------------------
/src/tab-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 | {{ title }}
11 |
12 |
13 | {{ badge }}
14 |
15 |
16 |
17 |
18 |
19 |
44 |
45 |
71 |
--------------------------------------------------------------------------------
/src/tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
395 |
396 |
430 |
--------------------------------------------------------------------------------
/src/utils/requestAnimationFrame.js:
--------------------------------------------------------------------------------
1 | export function windowInit() {
2 | var lastTime = 0;
3 | var vendors = ['webkit', 'moz'];
4 | for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
5 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
6 | window.cancelAnimationFrame =
7 | window[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit
8 | window[vendors[x] + 'CancelRequestAnimationFrame'];
9 | }
10 |
11 | if (!window.requestAnimationFrame) {
12 | window.requestAnimationFrame = function (callback) {
13 | var currTime = new Date().getTime();
14 | var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
15 | var interval = currTime - lastTime;
16 | var id = window.setTimeout(function () {
17 | callback(interval);
18 | }, timeToCall);
19 | lastTime = currTime + timeToCall;
20 | return id;
21 | };
22 | }
23 | if (!window.cancelAnimationFrame) {
24 | window.cancelAnimationFrame = function (id) {
25 | clearTimeout(id);
26 | };
27 | }
28 | }
29 |
--------------------------------------------------------------------------------