├── .babelrc ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── CHANGELOG.en-US.md ├── CHANGELOG.zh-CN.md ├── LICENSE ├── README.md ├── build ├── component │ ├── buildComponent.js │ ├── config.js │ ├── devComponent.js │ └── webpack.config.prod.js ├── config.js ├── locale.js ├── webpack.config.locale.js ├── webpack.config.prod.js └── webpack.config.test.js ├── example ├── app.vue ├── index.html ├── index.js ├── pages │ ├── box │ │ └── box.vue │ ├── button │ │ └── button.vue │ ├── cascader │ │ ├── cascader.vue │ │ └── data.js │ ├── checkbox │ │ └── checkbox.vue │ ├── datepicker │ │ └── datepicker.vue │ ├── drawer │ │ ├── drawer.vue │ │ └── test.vue │ ├── form │ │ └── form.vue │ ├── icon │ │ └── icon.vue │ ├── input │ │ └── input.vue │ ├── pagination │ │ └── pagination.vue │ ├── poptip │ │ └── poptip.vue │ ├── progress │ │ └── progress.vue │ ├── radio │ │ └── radio.vue │ ├── select │ │ └── select.vue │ ├── spin │ │ └── spin.vue │ ├── switch │ │ └── switch.vue │ ├── table │ │ └── table.vue │ ├── timepicker │ │ └── timepicker.vue │ └── tooltip │ │ └── tooltip.vue ├── router │ └── index.js └── sass │ └── index.scss ├── lib ├── ans-ui.min.css ├── ans-ui.min.js ├── font │ ├── iconfont.eot │ ├── iconfont.ttf │ └── iconfont.woff ├── images │ └── iconfont.svg └── locale │ ├── en.js │ ├── en.js.map │ ├── zh-CN.js │ └── zh-CN.js.map ├── package.json ├── packages ├── vue-box │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── base │ │ ├── Box.vue │ │ ├── BoxManager.vue │ │ └── index.js │ │ └── layer │ │ ├── message │ │ └── message.js │ │ ├── modal │ │ └── modal.js │ │ └── notice │ │ └── notice.js ├── vue-button │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Button.vue │ │ └── ButtonGroup.vue ├── vue-cascader │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── data.js │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Cascader.vue │ │ └── Caspanel.vue ├── vue-checkbox │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Checkbox.vue │ │ └── CheckboxGroup.vue ├── vue-datepicker │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── base │ │ ├── confirm.vue │ │ ├── day.vue │ │ ├── time.vue │ │ └── years.vue │ │ ├── datepicker.vue │ │ ├── panel │ │ ├── date.vue │ │ ├── daterange.vue │ │ ├── month.vue │ │ ├── time.vue │ │ └── year.vue │ │ └── util │ │ ├── date.js │ │ ├── isType.js │ │ ├── isValid.js │ │ ├── ishms.js │ │ └── toDate.js ├── vue-drawer │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ ├── index.js │ │ └── test.vue │ └── src │ │ ├── index.js │ │ └── source │ │ └── drawer.js ├── vue-form │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Form.vue │ │ └── FormItem.vue ├── vue-input │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Input.vue │ │ └── util │ │ └── calcTextareaHeight.js ├── vue-pagination │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ └── Page.vue ├── vue-poptip │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Poptip.vue │ │ └── directive.js ├── vue-progress │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ └── Progress.vue ├── vue-radio │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Radio.vue │ │ └── RadioGroup.vue ├── vue-scroller │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── HorizontalScrollbar.vue │ │ ├── Scroller.vue │ │ └── VerticalScrollbar.vue ├── vue-select │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── async.vue │ │ ├── dynamic.vue │ │ ├── index.html │ │ ├── index.js │ │ ├── manual.vue │ │ └── navigation.vue │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Option.vue │ │ ├── OptionGroup.vue │ │ ├── Select.vue │ │ └── SelectDropdown.vue ├── vue-spin │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ ├── Spin.vue │ │ ├── directive.js │ │ └── service.js ├── vue-switch │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ └── Switch.vue ├── vue-table │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── array.vue │ │ ├── dynamic.vue │ │ ├── index.html │ │ ├── index.js │ │ ├── indexs.json │ │ ├── paging.vue │ │ ├── restrict.vue │ │ ├── sort.vue │ │ └── tree.vue │ └── src │ │ ├── index.js │ │ └── source │ │ ├── CellRenderer.vue │ │ ├── Table.vue │ │ ├── TableBody.vue │ │ ├── TableColumn.vue │ │ ├── TableHeader.vue │ │ ├── TableTd.vue │ │ ├── TableTh.vue │ │ ├── layout.js │ │ ├── layoutObserver.js │ │ ├── store.js │ │ └── util.js ├── vue-timepicker │ ├── README.md │ ├── example │ │ ├── app.vue │ │ ├── index.html │ │ └── index.js │ └── src │ │ ├── index.js │ │ └── source │ │ └── Timepicker.vue └── vue-tooltip │ ├── README.md │ ├── example │ ├── app.vue │ ├── index.html │ └── index.js │ └── src │ ├── index.js │ └── source │ ├── Tooltip.vue │ ├── directive.js │ └── factory.js ├── src ├── index.js ├── locale │ ├── format.js │ ├── index.js │ └── lang │ │ ├── en.js │ │ └── zh-CN.js ├── style │ ├── animation │ │ ├── attentionSeekers.scss │ │ ├── bouncingEntrances.scss │ │ ├── bouncingExits.scss │ │ ├── fadingEntrances.scss │ │ ├── fadingExits.scss │ │ ├── flippers.scss │ │ ├── index.scss │ │ ├── lightspeed.scss │ │ ├── rotatingEntrances.scss │ │ ├── rotatingExits.scss │ │ ├── slidingEntrances.scss │ │ ├── slidingExits.scss │ │ ├── specials.scss │ │ ├── zoomEntrances.scss │ │ └── zoomExits.scss │ ├── common.scss │ ├── components │ │ ├── box │ │ │ ├── box.scss │ │ │ ├── message.scss │ │ │ ├── modal.scss │ │ │ └── notice.scss │ │ ├── button │ │ │ ├── button.scss │ │ │ └── mixin.scss │ │ ├── cascader │ │ │ └── cascader.scss │ │ ├── checkbox │ │ │ └── checkbox.scss │ │ ├── datepicker │ │ │ └── datepicker.scss │ │ ├── drawer │ │ │ └── drawer.scss │ │ ├── form │ │ │ └── form.scss │ │ ├── index.scss │ │ ├── input │ │ │ └── input.scss │ │ ├── pagination │ │ │ └── pagination.scss │ │ ├── poptip │ │ │ └── poptip.scss │ │ ├── progress │ │ │ └── progress.scss │ │ ├── radio │ │ │ └── radio.scss │ │ ├── scroller │ │ │ └── scroller.scss │ │ ├── select │ │ │ └── select.scss │ │ ├── spin │ │ │ └── spin.scss │ │ ├── switch │ │ │ └── switch.scss │ │ ├── table │ │ │ └── table.scss │ │ └── tooltip │ │ │ └── tooltip.scss │ ├── font.scss │ ├── font │ │ ├── iconfont.eot │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ ├── index.scss │ └── vars.scss └── util │ ├── assist.js │ ├── constants.js │ ├── customRenderer.js │ ├── directives │ ├── clickOutside.js │ ├── index.js │ └── mousewheel.js │ ├── dom │ ├── animatedScroll.js │ ├── class.js │ ├── index.js │ ├── limitedLoop.js │ ├── scrollIntoView.js │ ├── scrollbarWidth.js │ └── style.js │ ├── event.js │ ├── index.js │ ├── lang.js │ └── mixins │ ├── emitter.js │ ├── index.js │ ├── locale.js │ └── popper.js ├── test └── unit │ ├── .eslintrc.js │ ├── index.js │ ├── karma.conf.js │ ├── specs │ ├── button.spec.js │ ├── input.spec.js │ ├── page.spec.js │ └── select.spec.js │ └── util.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "loose": true, 5 | "debug": false, 6 | "useBuiltIns": true, 7 | "targets": { 8 | "browsers": [ "ie > 8", "last 2 version", "safari >= 9" ] 9 | } 10 | }] 11 | ], 12 | "plugins": [ 13 | [ "transform-runtime", { 14 | "helpers": false, 15 | "polyfill": false, 16 | "regenerator": true } ], 17 | [ "transform-class-properties", { "spec": true } ], 18 | [ "transform-object-rest-spread", { "useBuiltIns": true } ], 19 | [ "transform-vue-jsx" ], 20 | [ "syntax-dynamic-import" ] 21 | ], 22 | "comments": false, 23 | "env": { 24 | "production": { 25 | "plugins": ["transform-remove-console"] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": [ 7 | "plugin:vue/essential", 8 | "standard" 9 | ], 10 | "globals": { 11 | "Atomics": "readonly", 12 | "SharedArrayBuffer": "readonly" 13 | }, 14 | "parserOptions": { 15 | "ecmaVersion": 2018, 16 | "sourceType": "module" 17 | }, 18 | "plugins": [ 19 | "vue" 20 | ], 21 | "rules": { 22 | "vue/valid-v-for": 0 23 | } 24 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | .nyc_output 5 | coverage 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | 25 | .cache 26 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | build/ 2 | example/ 3 | test/ 4 | .cache 5 | .babelrc 6 | .eslintrc.json 7 | yarn.lock -------------------------------------------------------------------------------- /CHANGELOG.en-US.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | ### 1.1.7 4 | 5 | *2019-12-20* 6 | 7 | - Add some icons 8 | 9 | ### 1.1.6 10 | 11 | *2019-12-19* 12 | 13 | - Add some icons 14 | 15 | ### 1.1.5 16 | 17 | *2019-12-17* 18 | 19 | - Add some icons 20 | 21 | ### 1.1.4 22 | 23 | *2019-11-28* 24 | 25 | - Cascader 26 | - Add only-show-last prop 27 | - Page 28 | - Add on-size-change event 29 | 30 | ### 1.1.3 31 | 32 | *2019-11-25* 33 | 34 | - Datepicker 35 | - Fix the selected date not highlighted 36 | 37 | ### 1.1.0 38 | 39 | *2019-11-22* 40 | 41 | #### New features 42 | 43 | - Select 44 | - Add ignore-case prop 45 | - Table 46 | - Add hide-expand-icon prop 47 | - TableColumn add min-width prop 48 | - Tooltip 49 | - Add new option manual for triggerEvent 50 | - Add reveal prop 51 | - Timepicker 52 | - Add step prop 53 | - Add input-props prop 54 | - Datepicker 55 | - Add input-props prop 56 | - Form 57 | - Add vertical prop 58 | - Input 59 | - Add validator-icon prop 60 | 61 | #### Bug fixes 62 | 63 | - Table 64 | - Fix index error that occurred when both data cutting and multilevel headers were used 65 | - Fix dispaly error that table header was not displayed when there was no data 66 | - Fix abnormal display after vertical scrolling in some cases 67 | - Datepicker 68 | - Fix week i18n 69 | - Timepicker 70 | - Fix on-change event 71 | 72 | #### Optimization 73 | 74 | - Tooltip 75 | - Change maxWidth default value to 370px 76 | - Scroller 77 | - Change left/top to translate 78 | - Table 79 | - Optimize sort click experience 80 | -------------------------------------------------------------------------------- /CHANGELOG.zh-CN.md: -------------------------------------------------------------------------------- 1 | ## 更新日志 2 | 3 | 4 | ### 1.1.7 5 | 6 | *2019-12-20* 7 | 8 | - 新增若干图标 9 | 10 | ### 1.1.6 11 | 12 | *2019-12-19* 13 | 14 | - 新增若干图标 15 | 16 | ### 1.1.5 17 | 18 | *2019-12-17* 19 | 20 | - 新增若干图标 21 | 22 | ### 1.1.4 23 | 24 | *2019-11-28* 25 | 26 | - Cascader 27 | - 新增 only-show-last 属性 28 | - Page 29 | - 新增 on-size-change 事件 30 | 31 | ### 1.1.3 32 | 33 | *2019-11-25* 34 | 35 | - Datepicker 36 | - 修复选中日期未高亮的 bug 37 | 38 | ### 1.1.0 39 | 40 | *2019-11-22* 41 | 42 | #### 新特性 43 | 44 | - Select 45 | - 新增 ignore-case 属性 46 | - Table 47 | - 新增 hide-expand-icon 属性 48 | - TableColumn 新增 min-width 属性 49 | - Tooltip 50 | - triggerEvent 新增可选值 manual 51 | - 新增 reveal 属性 52 | - Timepicker 53 | - 新增 step 属性 54 | - 新增 input-props 属性 55 | - Datepicker 56 | - 新增 input-props 属性 57 | - Form 58 | - 新增 vertical 属性 59 | - Input 60 | - 新增 validator-icon 属性 61 | 62 | #### Bug 修复 63 | 64 | - Table 65 | - 修复多级表头时数据切割索引不对的 bug 66 | - 修复无数据时不能显示表头的 bug 67 | - 修复某些情况下垂直滚动之后显示异常的 bug 68 | - Datepicker 69 | - 修复星期显示国际化失效的 bug 70 | - Timepicker 71 | - 修复 on-change 事件无效的 bug 72 | 73 | #### 优化 74 | 75 | - Tooltip 76 | - maxWidth 的默认值改为 370px 77 | - Scroller 78 | - 将 left/top 替换为 translate 变换 79 | - Table 80 | - 优化排序点击体验 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ans UI 2 | 3 | > A Vue-based UI component library for analysys 4 | 5 | [Documentation](https://analysys.github.io/ans-ui_docs/#/) 6 | 7 | ## Installation 8 | 9 | ```sh 10 | yarn add ans-ui 11 | # or 12 | npm i ans-ui 13 | ``` 14 | 15 | ## Usage 16 | 17 | Import all components 18 | 19 | ```javascript 20 | import Vue from 'vue' 21 | import AnsUI from 'ans-ui' 22 | import 'ans-ui/lib/ans-ui.min.css' 23 | 24 | Vue.use(AnsUI) 25 | ``` 26 | 27 | Or import specified component 28 | 29 | ```javascript 30 | import Vue from 'vue' 31 | import { xButton } from 'ans-ui' 32 | import 'ans-ui/lib/ans-ui.min.css' 33 | 34 | Vue.use(xButton) 35 | ``` 36 | 37 | ## Development 38 | 39 | Install parcel-bundler globally 40 | 41 | ```sh 42 | yarn global add parcel-bundler 43 | # or 44 | npm i -g parcel-bundler 45 | ``` 46 | 47 | Then 48 | 49 | ```sh 50 | yarn dev 51 | # or 52 | npm run dev 53 | ``` 54 | 55 | ## License 56 | 57 | MIT -------------------------------------------------------------------------------- /build/component/buildComponent.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process') 2 | const path = require('path') 3 | const fs = require('fs') 4 | const inquirer = require('inquirer') 5 | 6 | const componentName = process.argv[2] 7 | 8 | if (!componentName) { 9 | fs.readdir(path.resolve('./packages'), (err, files) => { 10 | if (err) { 11 | console.log(err) 12 | process.exit(1) 13 | } 14 | inquirer.prompt([ 15 | { 16 | type: 'list', 17 | message: '请选择组件', 18 | name: 'name', 19 | choices: files 20 | } 21 | ]).then(answers => { 22 | process.env.COMPONENT_NAME = answers.name 23 | run() 24 | }) 25 | }) 26 | } else { 27 | const indexPath = `./packages/vue-${componentName}` 28 | if (!fs.existsSync(path.resolve(indexPath))) { 29 | console.log('请输入正确的组件名称! Please input right component name!') 30 | process.exit(1) 31 | } 32 | process.env.COMPONENT_NAME = `vue-${componentName}` 33 | run() 34 | } 35 | 36 | function run () { 37 | process.env.NODE_ENV = 'production' 38 | spawn('webpack', ['--config', './build/component/webpack.config.prod.js'], { 39 | stdio: 'inherit', 40 | // 仅在当前运行环境为 Windows 时,才使用 shell 41 | shell: process.platform === 'win32' 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /build/component/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const glob = require('globby') 3 | 4 | const isProduction = process.env.NODE_ENV !== 'development' 5 | const componentName = process.env.COMPONENT_NAME 6 | const resolve = dir => path.join(__dirname, `../../packages/${componentName}`, dir) 7 | const assetsDir = resolve('src') 8 | const distDir = resolve('dist') 9 | 10 | const baseConfig = { 11 | entry: { 12 | index: glob.sync(['index.js'], { cwd: assetsDir }) 13 | }, 14 | output: { 15 | path: distDir 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.js$/, 21 | exclude: file => ( 22 | /node_modules/.test(file) && 23 | !/\.vue\.js/.test(file) 24 | ), 25 | use: [ 26 | { 27 | loader: 'babel-loader', 28 | options: { 29 | cacheDirectory: true, 30 | cacheIdentifier: true 31 | } 32 | } 33 | ] 34 | } 35 | ] 36 | }, 37 | resolve: { 38 | modules: [ 39 | assetsDir, 40 | 'node_modules' 41 | ], 42 | extensions: ['.js', '.json', '.vue', '.scss'] 43 | }, 44 | externals: { 45 | vue: { 46 | commonjs: 'vue', 47 | commonjs2: 'vue', 48 | amd: 'vue', 49 | root: 'Vue' 50 | }, 51 | 'popper.js': { 52 | commonjs: 'popper.js', 53 | commonjs2: 'popper.js', 54 | amd: 'popper.js', 55 | root: 'Popper' 56 | } 57 | } 58 | } 59 | 60 | module.exports = { 61 | isProduction, 62 | assetsDir, 63 | distDir, 64 | baseConfig 65 | } 66 | -------------------------------------------------------------------------------- /build/component/devComponent.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process') 2 | const path = require('path') 3 | const fs = require('fs') 4 | const inquirer = require('inquirer') 5 | 6 | const componentName = process.argv[2] 7 | let indexPath 8 | 9 | if (!componentName) { 10 | fs.readdir(path.resolve('./packages'), (err, files) => { 11 | if (err) { 12 | console.log(err) 13 | process.exit(1) 14 | } 15 | inquirer.prompt([ 16 | { 17 | type: 'list', 18 | message: '请选择组件', 19 | name: 'name', 20 | choices: files 21 | } 22 | ]).then(answers => { 23 | indexPath = `./packages/${answers.name}/example/index.html` 24 | run() 25 | }) 26 | }) 27 | } else { 28 | indexPath = `./packages/vue-${componentName}/example/index.html` 29 | if (!fs.existsSync(path.resolve(indexPath))) { 30 | console.log('请输入正确的组件名称! Please input right component name!') 31 | process.exit(1) 32 | } 33 | run() 34 | } 35 | 36 | function run () { 37 | console.log(`parcel ${indexPath} -p 3000`) 38 | 39 | spawn('parcel', [indexPath, '-p', '3000'], { 40 | stdio: 'inherit', 41 | // 仅在当前运行环境为 Windows 时,才使用 shell 42 | shell: process.platform === 'win32' 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /build/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { smart } = require('webpack-merge') 3 | 4 | const resolve = dir => path.resolve(__dirname, '..', dir) 5 | 6 | const baseConfig = { 7 | entry: { 8 | 'ans-ui': './src/index.js' 9 | }, 10 | output: { 11 | path: resolve('lib'), 12 | filename: '[name].js', 13 | libraryTarget: 'umd', 14 | library: 'ans', 15 | umdNamedDefine: true 16 | }, 17 | performance: { 18 | hints: 'warning' 19 | }, 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.js$/, 24 | exclude: /(node_modules|bower_components)/, 25 | use: [ 26 | { 27 | loader: 'babel-loader', 28 | options: { 29 | cacheDirectory: true, 30 | cacheIdentifier: true 31 | } 32 | } 33 | ] 34 | }, 35 | { 36 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 37 | loader: 'url-loader', 38 | options: { 39 | limit: 10000, 40 | name: 'font/[name].[ext]' 41 | } 42 | }, 43 | { 44 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 45 | loader: 'file-loader', 46 | options: { 47 | name: 'images/[name].[ext]?[hash]' 48 | } 49 | } 50 | ] 51 | }, 52 | resolve: { 53 | modules: [ 54 | resolve('src'), 55 | resolve('node_modules') 56 | ], 57 | alias: { 58 | '@': resolve('src'), 59 | packages: resolve('packages') 60 | }, 61 | extensions: ['.js', '.json', '.vue', '.scss'] 62 | }, 63 | externals: { 64 | vue: { 65 | commonjs: 'vue', 66 | commonjs2: 'vue', 67 | amd: 'vue', 68 | root: 'Vue' 69 | } 70 | }, 71 | plugins: [] 72 | } 73 | 74 | module.exports = { 75 | baseConfig, 76 | resolve, 77 | smart 78 | } 79 | -------------------------------------------------------------------------------- /build/locale.js: -------------------------------------------------------------------------------- 1 | const readDir = require('fs').readdirSync 2 | const files = readDir('./src/locale/lang') 3 | const entry = {} 4 | files.forEach(file => { 5 | const name = file.split('.')[0] 6 | entry[name] = './src/locale/lang/' + file 7 | }) 8 | module.exports = entry 9 | -------------------------------------------------------------------------------- /build/webpack.config.locale.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const entry = require('./locale') 4 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 5 | 6 | process.env.NODE_ENV = 'production' 7 | 8 | module.exports = { 9 | devtool: 'source-map', 10 | entry, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.js$/, 15 | loader: 'babel-loader', 16 | options: { 17 | sourceMap: true 18 | }, 19 | exclude: /node_modules/ 20 | } 21 | ] 22 | }, 23 | output: { 24 | path: path.resolve(__dirname, '../lib/locale'), 25 | publicPath: '/lib/locale/', 26 | filename: '[name].js', 27 | library: 'ans-ui/locale', 28 | libraryTarget: 'umd', 29 | umdNamedDefine: true 30 | }, 31 | externals: { 32 | vue: { 33 | root: 'Vue', 34 | commonjs: 'vue', 35 | commonjs2: 'vue', 36 | amd: 'vue' 37 | } 38 | }, 39 | plugins: [ 40 | new webpack.DefinePlugin({ 41 | 'process.env': { 42 | NODE_ENV: '"production"' 43 | } 44 | }), 45 | new UglifyJsPlugin({ 46 | parallel: true, 47 | sourceMap: true 48 | }) 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /build/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const { baseConfig, smart } = require('./config') 3 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin') 5 | const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') 6 | const VueLoaderPlugin = require('vue-loader/lib/plugin') 7 | 8 | const outConfig = smart(baseConfig, { 9 | devtool: 'source-map', 10 | output: { 11 | filename: '[name].min.js' 12 | }, 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.vue$/, 17 | loader: 'vue-loader', 18 | options: { 19 | hotReload: false // 开启热重载 20 | } 21 | }, 22 | { 23 | test: /\.css$/, 24 | loader: ExtractTextPlugin.extract({ 25 | use: [ 26 | 'css-loader', 27 | { 28 | loader: 'postcss-loader', 29 | options: { 30 | plugins: (loader) => [ 31 | require('autoprefixer')({ 32 | browsers: ['ie > 8', 'last 2 version', 'safari >= 9'] 33 | }), 34 | require('cssnano') 35 | ] 36 | } 37 | } 38 | ], 39 | fallback: ['vue-style-loader'] 40 | }) 41 | }, 42 | { 43 | test: /\.scss$/, 44 | loader: ExtractTextPlugin.extract({ 45 | use: [ 46 | 'css-loader', 47 | { 48 | loader: 'postcss-loader', 49 | options: { 50 | plugins: (loader) => [ 51 | require('autoprefixer')({ 52 | browsers: ['ie > 8', 'last 2 version', 'safari >= 9'] 53 | }), 54 | require('cssnano') 55 | ] 56 | } 57 | }, 58 | 'sass-loader' 59 | ], 60 | fallback: ['vue-style-loader'] 61 | }) 62 | } 63 | ] 64 | }, 65 | plugins: [ 66 | new VueLoaderPlugin(), 67 | new ExtractTextPlugin({ filename: '[name].min.css', allChunks: true }), 68 | new webpack.optimize.OccurrenceOrderPlugin(), 69 | new UglifyJSPlugin({ 70 | parallel: true, 71 | sourceMap: false, 72 | uglifyOptions: { 73 | compress: { 74 | drop_console: true, 75 | drop_debugger: true 76 | }, 77 | comments: function (n, c) { 78 | /*! IMPORTANT: Please preserve 3rd-party library license info */ 79 | var text = c.value; var type = c.type 80 | if (type === 'comment2') { 81 | return /^!|@preserve|@license|@cc_on|MIT/i.test(text) 82 | } 83 | } 84 | } 85 | }), 86 | new OptimizeCssAssetsPlugin({ 87 | assetNameRegExp: /\.css$/g, 88 | cssProcessor: require('cssnano'), 89 | cssProcessorOptions: { discardComments: { removeAll: true } }, 90 | canPrint: true 91 | }) 92 | ] 93 | }) 94 | 95 | module.exports = outConfig 96 | -------------------------------------------------------------------------------- /build/webpack.config.test.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const { baseConfig, smart } = require('./config') 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin') 4 | 5 | const outConfig = smart(baseConfig, { 6 | devtool: 'eval-source-map', 7 | module: { 8 | rules: [ 9 | { 10 | test: /\.vue$/, 11 | loader: 'vue-loader', 12 | options: { 13 | loaders: { 14 | css: [ 15 | 'vue-style-loader', 16 | { 17 | loader: 'css-loader', 18 | options: { 19 | sourceMap: true 20 | } 21 | } 22 | ], 23 | scss: [ 24 | 'vue-style-loader', 25 | { 26 | loader: 'css-loader', 27 | options: { 28 | sourceMap: true 29 | } 30 | }, 31 | { 32 | loader: 'sass-loader', 33 | options: { 34 | sourceMap: true 35 | } 36 | } 37 | ] 38 | }, 39 | postLoaders: { 40 | html: 'babel-loader?sourceMap' 41 | }, 42 | sourceMap: true 43 | } 44 | }, 45 | { 46 | test: /\.js$/, 47 | loader: 'babel-loader', 48 | options: { 49 | sourceMap: true 50 | }, 51 | exclude: /node_modules/ 52 | }, 53 | { 54 | test: /\.css$/, 55 | loader: [ 56 | { 57 | loader: 'style-loader', 58 | options: { 59 | sourceMap: true 60 | } 61 | }, 62 | { 63 | loader: 'css-loader', 64 | options: { 65 | sourceMap: true 66 | } 67 | } 68 | ] 69 | }, 70 | { 71 | test: /\.scss$/, 72 | loader: [ 73 | { 74 | loader: 'style-loader', 75 | options: { 76 | sourceMap: true 77 | } 78 | }, 79 | { 80 | loader: 'css-loader', 81 | options: { 82 | sourceMap: true 83 | } 84 | }, 85 | { 86 | loader: 'sass-loader', 87 | options: { 88 | sourceMap: true 89 | } 90 | } 91 | ] 92 | } 93 | ] 94 | }, 95 | plugins: [ 96 | new VueLoaderPlugin(), 97 | new webpack.DefinePlugin({ 98 | 'process.env': { 99 | NODE_ENV: '"testing"' 100 | } 101 | }) 102 | ], 103 | resolve: { 104 | alias: { 105 | vue$: 'vue/dist/vue.esm.js' 106 | } 107 | } 108 | }) 109 | 110 | delete outConfig.externals 111 | 112 | module.exports = outConfig 113 | -------------------------------------------------------------------------------- /example/app.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 36 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ans-ui组件库 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './app.vue' 3 | import router from './router' 4 | import '../lib/ans-ui.min.css' 5 | import ans from '../lib/ans-ui.min.js' 6 | 7 | Vue.use(ans) 8 | 9 | new Vue({ 10 | el: '#app', 11 | router, 12 | render: h => h(App), 13 | mounted () { 14 | console.log('success') 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /example/pages/cascader/cascader.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 75 | 76 | -------------------------------------------------------------------------------- /example/pages/checkbox/checkbox.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 42 | 43 | 46 | -------------------------------------------------------------------------------- /example/pages/drawer/drawer.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /example/pages/drawer/test.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /example/pages/pagination/pagination.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /example/pages/poptip/poptip.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 86 | 87 | -------------------------------------------------------------------------------- /example/pages/radio/radio.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /example/pages/switch/switch.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /example/pages/timepicker/timepicker.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 41 | 42 | 45 | -------------------------------------------------------------------------------- /example/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | const router = new Router({ 7 | routes: [ 8 | { path: '/icon', name: 'icon', component: () => import('../pages/icon/icon') }, 9 | { path: '/spin', name: 'spin', component: () => import('../pages/spin/spin') }, 10 | { path: '/switch', name: 'switch', component: () => import('../pages/switch/switch') }, 11 | { path: '/radio', name: 'radio', component: () => import('../pages/radio/radio') }, 12 | { path: '/pagination', name: 'pagination', component: () => import('../pages/pagination/pagination') }, 13 | { path: '/checkbox', name: 'checkbox', component: () => import('../pages/checkbox/checkbox') }, 14 | { path: '/button', name: 'button', component: () => import('../pages/button/button') }, 15 | { path: '/tooltip', name: 'tooltip', component: () => import('../pages/tooltip/tooltip') }, 16 | { path: '/input', name: 'input', component: () => import('../pages/input/input') }, 17 | { path: '/select', name: 'select', component: () => import('../pages/select/select') }, 18 | { path: '/box', name: 'box', component: () => import('../pages/box/box') }, 19 | { path: '/datepicker', name: 'datepicker', component: () => import('../pages/datepicker/datepicker') }, 20 | { path: '/timepicker', name: 'timepicker', component: () => import('../pages/timepicker/timepicker') }, 21 | { path: '/poptip', name: 'poptip', component: () => import('../pages/poptip/poptip') }, 22 | { path: '/progress', name: 'progress', component: () => import('../pages/progress/progress') }, 23 | { path: '/cascader', name: 'cascader', component: () => import('../pages/cascader/cascader') }, 24 | { path: '/drawer', name: 'drawer', component: () => import('../pages/drawer/drawer') }, 25 | { path: '/table', name: 'table', component: () => import('../pages/table/table') }, 26 | { path: '/form', name: 'form', component: () => import('../pages/form/form') } 27 | ] 28 | }) 29 | 30 | export default router 31 | -------------------------------------------------------------------------------- /example/sass/index.scss: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | padding: 0 20px; 3 | .h2 { 4 | color: #999; 5 | border-bottom: 1px dashed #eee; 6 | padding: 20px 0; 7 | margin: 0; 8 | } 9 | .compo-list { 10 | border-bottom: 1px dashed #eee; 11 | .compo-ul { 12 | list-style-type: none; 13 | margin: 0; 14 | padding: 15px 0 0 0; 15 | &::after { 16 | display: block; 17 | content: ""; 18 | clear: both; 19 | } 20 | li { 21 | float: left; 22 | margin-right: 20px; 23 | margin-bottom: 15px; 24 | a { 25 | display: inline-block; 26 | padding: 5px 10px; 27 | border: 1px solid #eee; 28 | color: #333; 29 | text-decoration: none; 30 | border-radius: 4px; 31 | &:hover { 32 | color: #0097e0; 33 | } 34 | } 35 | } 36 | } 37 | } 38 | .demo-section { 39 | border: 1px solid #eee; 40 | border-radius: 4px; 41 | background-color: #fafafa; 42 | padding: 10px; 43 | margin: 20px 0; 44 | h4 { 45 | margin: 0; 46 | font-size: 13px; 47 | font-weight: normal; 48 | color: #999; 49 | margin-bottom: 10px; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /lib/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/lib/font/iconfont.eot -------------------------------------------------------------------------------- /lib/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/lib/font/iconfont.ttf -------------------------------------------------------------------------------- /lib/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/lib/font/iconfont.woff -------------------------------------------------------------------------------- /lib/locale/en.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("ans-ui/locale",[],t):"object"==typeof exports?exports["ans-ui/locale"]=t():e["ans-ui/locale"]=t()}("undefined"!=typeof self?self:this,function(){return function(e){var t={};function o(n){if(t[n])return t[n].exports;var a=t[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,o),a.l=!0,a.exports}return o.m=e,o.c=t,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="/lib/locale/",o(o.s=0)}([function(e,t,o){"use strict";t.__esModule=!0,t.default={ans:{modal:{confirm:"OK",cancel:"Cancel"},cascader:{placeholder:"Select",noMatch:"No matching data",noData:"No data"},datepicker:{placeholder:"Select date",cancel:"Cancel",confirm:"OK",year:"",month1:"January",month2:"February",month3:"March",month4:"April",month5:"May",month6:"June",month7:"July",month8:"August",month9:"September",month10:"October",month11:"November",month12:"December",weeks:{sun:"Sun",mon:"Mon",tue:"Tue",wed:"Wed",thu:"Thu",fri:"Fri",sat:"Sat"},selectTime:"Select time",startTime:"Start time",endTime:"End time"},input:{placeholder:"Please enter..."},page:{goto:"Go to",pagesize:"/page",total:"Total {total}",pageClassifier:""},poptip:{confirm:"OK",cancel:"Cancel"},select:{placeholder:"Select",noMatch:"No matching data",noData:"No data",search:"Keyword"},table:{emptyText:"No data"},timepicker:{clear:"Clear",confirm:"OK",placeholder:"Select"}}}}])}); 2 | //# sourceMappingURL=en.js.map -------------------------------------------------------------------------------- /lib/locale/zh-CN.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("ans-ui/locale",[],t):"object"==typeof exports?exports["ans-ui/locale"]=t():e["ans-ui/locale"]=t()}("undefined"!=typeof self?self:this,function(){return function(e){var t={};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}return o.m=e,o.c=t,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="/lib/locale/",o(o.s=1)}([,function(e,t,o){"use strict";t.__esModule=!0,t.default={ans:{modal:{confirm:"确定",cancel:"取消"},cascader:{placeholder:"请选择",noMatch:"搜索无结果",noData:"暂无数据"},datepicker:{placeholder:"请选择日期",cancel:"取消",confirm:"确定",year:"年",month1:"1 月",month2:"2 月",month3:"3 月",month4:"4 月",month5:"5 月",month6:"6 月",month7:"7 月",month8:"8 月",month9:"9 月",month10:"10 月",month11:"11 月",month12:"12 月",weeks:{sun:"日",mon:"一",tue:"二",wed:"三",thu:"四",fri:"五",sat:"六"},selectTime:"选择时间",startTime:"开始时间",endTime:"结束时间"},input:{placeholder:"请输入..."},page:{goto:"跳转至",pagesize:"条/页",total:"共 {total} 条",pageClassifier:"页"},poptip:{confirm:"确定",cancel:"取消"},select:{placeholder:"请选择",noMatch:"搜索无结果",noData:"暂无数据",search:"搜索"},table:{emptyText:"暂无数据"},timepicker:{clear:"清空",confirm:"确定",placeholder:"请选择时间"}}}}])}); 2 | //# sourceMappingURL=zh-CN.js.map -------------------------------------------------------------------------------- /packages/vue-box/README.md: -------------------------------------------------------------------------------- 1 | ## Box 2 | 3 | Box包含modal、message、notice三个组件。 4 | 5 | ### Modal options 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | title | 标题 | String / DOM | - | - 10 | content | 内容 | String / DOM | - | - 11 | width | 宽度 | Number / String | - | 520 12 | className | 自定义样式名称 | String | - | - 13 | closable | 是否显示关闭 | Boolean | - | true 14 | escClose | 是否按 esc 键关闭 | Boolean | - | false 15 | ok | 点击确定的回调 | Object | {show [Boolean] ,text [String], handle[Function]} | - 16 | cancel | 点击取消的回调 | Object | {show [Boolean] ,text [String], handle[Function]} | - 17 | render | 自定义内容 | Function | 使用时 content, title ,ok , cancel 失效 | - 18 | showMask | 是否显示遮罩 | Boolean | - | false 19 | maskClosable | 点击遮罩是否关闭 | Boolean | - | false 20 | i18n | 国际化对象 | VueI18n | - | - 21 | 22 | #### Modal 实例方法 23 | 24 | instance.remove() 销毁当前实例 25 | 26 | #### Modal 全局相关 27 | 28 | this.$modal.destroy() 全局销毁所有实例 29 | 30 | ### Message options 31 | 32 | 属性 | 说明 | 类型 | 可选值 | 默认值 33 | --- | --- | --- | --- | --- 34 | content | 内容 | String | - | - 35 | duration | 自动关闭的延时,单位秒,不关闭可以写 0 | Number | - | 1.5 36 | onClose | 关闭时的回调 | Function | - | - 37 | closable | 是否显示关闭图标 | Boolean | - | false 38 | i18n | 国际化对象 | VueI18n | - | - 39 | 40 | #### Message 全局相关 41 | 42 | this.$message.destroy() 全局销毁所有实例 43 | 44 | this.$message.config(options) 全局配置 45 | 46 | 属性 | 说明 | 类型 | 可选值 | 默认值 47 | --- | --- | --- | --- | --- 48 | top | 提示组件距离顶端的距离,单位像素 | Number | - | 60 49 | duration | 默认自动关闭的延时,单位秒 | Number | - | 1.5 50 | transitionName | 默认动画类名 | String | - | x-ani-move-in 51 | fixed | 显示是否固定位置 | String | Boolean | true 52 | 53 | ### Notice options 54 | 55 | 属性 | 说明 | 类型 | 可选值 | 默认值 56 | --- | --- | --- | --- | --- 57 | title | 标题 | String | - | - 58 | content | 内容 | String | - | - 59 | duration | 自动关闭的延时,单位秒,不关闭可以写 0 | Number | - | 1.5 60 | onClose | 关闭时的回调 | Function | - | - 61 | closable | 是否显示关闭图标 | Boolean | - | false 62 | i18n | 国际化对象 | VueI18n | - | - 63 | 64 | #### Notice 全局相关 65 | 66 | this.$notice.destroy() 全局销毁所有实例 67 | 68 | this.$notice.config(options) 全局配置 69 | 70 | 属性 | 说明 | 类型 | 可选值 | 默认值 71 | --- | --- | --- | --- | --- 72 | top | 提示组件距离顶端的距离,单位像素 | Number | - | 60 73 | right | 提示组件距离屏幕右侧的距离,单位像素 | Number | - | 20 74 | duration | 默认自动关闭的延时,单位秒 | Number | - | 1.5 75 | transitionName | 默认动画类名 | String | - | x-ani-move-right 76 | list | 显示是否以列表形式展示 | Boolean | - | true -------------------------------------------------------------------------------- /packages/vue-box/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-box/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-box/src/index.js: -------------------------------------------------------------------------------- 1 | import xMessage from './source/layer/message/message' 2 | import xModal from './source/layer/modal/modal' 3 | import xNotice from './source/layer/notice/notice' 4 | 5 | export { 6 | xMessage, 7 | xModal, 8 | xNotice 9 | } 10 | -------------------------------------------------------------------------------- /packages/vue-box/src/source/base/BoxManager.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 107 | -------------------------------------------------------------------------------- /packages/vue-box/src/source/base/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by tangwei on 17/8/25. 3 | */ 4 | import Vue from 'vue' 5 | import BoxManager from './BoxManager.vue' 6 | 7 | BoxManager.newInstance = properties => { 8 | const _props = properties || {} 9 | 10 | const Instance = new Vue({ 11 | data: _props, 12 | i18n: _props.i18n, 13 | render (h) { 14 | return h(BoxManager, { 15 | props: _props 16 | }) 17 | } 18 | }) 19 | 20 | const component = Instance.$mount() 21 | document.body.appendChild(component.$el) 22 | const notification = Instance.$children[0] 23 | 24 | return { 25 | notice (noticeProps) { 26 | notification.add(noticeProps) 27 | }, 28 | remove (name) { 29 | notification.close(name) 30 | }, 31 | component: notification, 32 | destroy (classname) { 33 | notification.closeAll() 34 | setTimeout(function () { 35 | document.body.removeChild(document.getElementsByClassName(classname)[0]) 36 | }, 500) 37 | } 38 | } 39 | } 40 | 41 | export default BoxManager 42 | -------------------------------------------------------------------------------- /packages/vue-button/README.md: -------------------------------------------------------------------------------- 1 | ## Button 2 | 3 | 常用的操作按钮 4 | 5 | ### Button props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | title | 标题 | String / DOM | - | - 10 | type | 类型 | String | primary、ghost、dashed、text、info、success、warning、error | - 11 | shape | 形状 | String | circle或者不设置 | - 12 | size | 大小 | String | large、small、default、xsmall | - 13 | loading | 是否为加载中状态 | Boolean | - | - 14 | disabled | 是否禁用 | Boolean | - | - 15 | visible | 在按钮组中,按钮是否显示 | Boolean | - | true 16 | html-type | 设置button原生的type | String | button、submit、reset | button 17 | icon | 按钮的图标类型 | String | - | - 18 | long | 开启后,长度为 100% | Boolean | - | false 19 | value | 按钮的值,可用于双向绑定 | any | - | - 20 | 21 | ButtonGroup props 22 | 23 | 属性 | 说明 | 类型 | 可选值 | 默认值 24 | --- | --- | --- | --- | --- 25 | size | 大小 | String | large、default、small、xsmall | - 26 | shape | 形状 | String | - | - 27 | vertical | 是否纵向排列按钮组 | Boolean | - | - 28 | value | 按钮的值,可用于双向绑定 | any | - | - 29 | -------------------------------------------------------------------------------- /packages/vue-button/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-button/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-button/src/index.js: -------------------------------------------------------------------------------- 1 | import xButton from './source/Button.vue' 2 | import xButtonGroup from './source/ButtonGroup.vue' 3 | 4 | export { 5 | xButton, 6 | xButtonGroup 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-cascader/README.md: -------------------------------------------------------------------------------- 1 | ## Cascader 2 | 3 | ### Cascader props 4 | 5 | | 属性 | 说明 | required | 类型 | 默认值 | 6 | | :----| :------| :--------| :---:| :------| 7 | | options | 可选项数据源,键名可通过 props 属性配置, 配置选项: { value, label, html, children, disabled } | Required | Array | - | 8 | | prop | N/A | Optional | Object | {...} | 9 | | value | 选中项绑定值 `v-model` | Optional | Array | {...} | 10 | | separator | N/A | Optional | String | / | 11 | | placeholder | N/A | Optional | String | 请选择 ... | 12 | | disabled | N/A | Optional | Any | - | 13 | | clearable | 是否支持清空选项 | Optional | Any | - | 14 | | change-on-select | 是否允许选择任意一级的选项 | Optional | Any | - | 15 | | popper-class | 自定义浮层类名 | Optional | Any | - | 16 | | expand-trigger | 次级菜单的展开方式 [ click / hover ] | Optional | String | click | 17 | | filterable | 是否可搜索选项 | Optional | Any | - | 18 | | no-data-text | 无数据提示 | Optional | String | 暂无数据 | 19 | | no-match-text | 搜索无结果提示 | Optional | String | 搜索无结果 | 20 | | multiple | 是否多选 | Optional | Boolean | false | 21 | | placement | 弹出位置 | Optional | String | bottom-start | 22 | | distance | 与参考元素距离,单位为 px | Optional | Number | 1 | 23 | | append-to-body | 弹出层是否插入 body | Optional | Boolean | false | 24 | | position-fixed | 弹出层是否 fixed 定位 | Boolean | — | false | 25 | | viewport | 弹出层是否基于 viewport 定位 | Boolean | — | false | 26 | | popper-options | Popper.js 的可选项 | Optional | Object | — | 27 | | only-show-last | 是否只展示最后一级的值 | Optional | Boolean | — | 28 | 29 | ### Cascader events 30 | 31 | - `on-change` Fired when the selected value is changed. 32 | 33 | --- 34 | -------------------------------------------------------------------------------- /packages/vue-cascader/example/app.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 77 | 78 | 84 | -------------------------------------------------------------------------------- /packages/vue-cascader/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-cascader/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-cascader/src/index.js: -------------------------------------------------------------------------------- 1 | import xCascader from './source/Cascader.vue' 2 | 3 | /* istanbul ignore next */ 4 | xCascader.install = function (Vue) { 5 | Vue.component(xCascader.name, xCascader) 6 | } 7 | 8 | export { xCascader } 9 | -------------------------------------------------------------------------------- /packages/vue-checkbox/README.md: -------------------------------------------------------------------------------- 1 | ## Checkbox 2 | 3 | 用于一组可选项多项选择,或者单独用于标记切换某种状态。 4 | 5 | ### Checkbox props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | value | 单独使用时有效,可用于v-model双向绑定 | String / Number / Boolean | - | - 10 | label | 组合使用时有效,指定当前选项value值 | String / Number / Boolean | - | - 11 | disabled | 是否禁用 | Boolean | - | false 12 | true-value | 自定义选中时的值 | String / Number / Boolean | - | true 13 | false-value | 自定义未选中时的值 | String / Number / Boolean | - | false 14 | indeterminate | 设置 indeterminate 状态,只负责样式控制 | Boolean | - | false 15 | 16 | ### Checkbox events 17 | 18 | 事件名称 | 说明 | 回调参数 19 | --- | --- | --- 20 | on-change | 在选项状态发生改变时触发,返回当前状态。通过修改外部的数据改变时不会触发 | 选中的 Checkbox value 值 21 | 22 | ### CheckboxGroup props 23 | 24 | 属性 | 说明 | 类型 | 可选值 | 默认值 25 | --- | --- | --- | --- | --- 26 | value | 当前选中的值,可用于v-model双向绑定 | Array | - | [] 27 | 28 | ### CheckboxGroup events 29 | 30 | 事件名称 | 说明 | 回调参数 31 | --- | --- | --- 32 | on-change | 在选项状态发生改变时触发,返回当前状态。通过修改外部的数据改变时不会触发 | 选中的 Checkbox label 值 -------------------------------------------------------------------------------- /packages/vue-checkbox/example/app.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 45 | 46 | 49 | -------------------------------------------------------------------------------- /packages/vue-checkbox/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-checkbox/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-checkbox/src/index.js: -------------------------------------------------------------------------------- 1 | import xCheckbox from './source/Checkbox.vue' 2 | import xCheckboxGroup from './source/CheckboxGroup.vue' 3 | 4 | export { 5 | xCheckbox, 6 | xCheckboxGroup 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-checkbox/src/source/CheckboxGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 65 | -------------------------------------------------------------------------------- /packages/vue-datepicker/README.md: -------------------------------------------------------------------------------- 1 | An component project 2 | 3 | ### Setup 4 | 5 | - 安装node > 8的LTS版本,https://nodejs.org/en/ 6 | 7 | - 增加npm本地仓库host,106.75.23.50 npm.analysys.cn 8 | 9 | - 没安装yarn的,可以忽略以下yarn命令 10 | 11 | ```sh 12 | # set registry 13 | npm config set registry http://registry.npm.analysys.cn 14 | 15 | # install parcel 16 | yarn global add parcel-bundler | npm i -g parcel-bundler 17 | 18 | # install dependencies 19 | yarn | npm i 20 | 21 | # startup development server (defaults to 3000) 22 | # -> http://localhost:3000 23 | yarn start | npm start 24 | ``` 25 | 26 | ### Lint 27 | ```sh 28 | yarn test | npm run test 29 | yarn lint:fix | npm run lint:fix 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/vue-datepicker/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-datepicker/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/index.js: -------------------------------------------------------------------------------- 1 | import xDatepicker from './source/datepicker.vue' 2 | import dateUtil from 'dayjs' 3 | 4 | export { xDatepicker, dateUtil } 5 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/base/confirm.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 70 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/panel/date.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 115 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/panel/month.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 42 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/panel/time.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/packages/vue-datepicker/src/source/panel/time.vue -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/panel/year.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/packages/vue-datepicker/src/source/panel/year.vue -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/util/isType.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 判断数据类型 4 | * 5 | */ 6 | 7 | function isType (value) { 8 | const type = Object.prototype.toString.call(value) 9 | return type.match(/\[object (.*?)\]/)[1].toLowerCase() 10 | } 11 | 12 | export default isType 13 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/util/isValid.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 验证日期是否合法 4 | * 5 | */ 6 | 7 | import moment from 'dayjs' 8 | 9 | export default (date) => { 10 | // return Date.parse(date) > 0 11 | return moment(date).isValid() 12 | } 13 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/util/ishms.js: -------------------------------------------------------------------------------- 1 | export default (fmt) => { 2 | if (/[HhmsS]/.test(fmt)) { 3 | return 'second' 4 | } 5 | 6 | if (/[Hhm]/.test(fmt)) { 7 | return 'minute' 8 | } 9 | 10 | if (/[Hh]/.test(fmt)) { 11 | return 'hour' 12 | } 13 | 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /packages/vue-datepicker/src/source/util/toDate.js: -------------------------------------------------------------------------------- 1 | 2 | export default () => { 3 | const date = new Date() 4 | return { 5 | year: date.getFullYear(), 6 | month: date.getMonth() + 1, 7 | today: date.getDate() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/vue-drawer/README.md: -------------------------------------------------------------------------------- 1 | ## Drawer 2 | 3 | 抽屉从父窗体边缘滑入,覆盖住部分父窗体内容。 4 | 5 | ### Drawer options 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | direction | 出现位置 | String | left / right / top / bottom | right 10 | className | 自定义样式名称 | String | - | - 11 | closable | 是否显示关闭 | Boolean | - | false 12 | escClose | 是否按 esc 键关闭 | Boolean | - | true 13 | transitionName | 动画类名 | String | - | - 14 | showMask | 是否显示遮罩 | Boolean | - | true 15 | maskClosable | 是否关闭遮罩 | Boolean | - | true 16 | i18n | 国际化对象 | VueI18n | - | - -------------------------------------------------------------------------------- /packages/vue-drawer/example/app.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 65 | 66 | 69 | -------------------------------------------------------------------------------- /packages/vue-drawer/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-drawer/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 | -------------------------------------------------------------------------------- /packages/vue-drawer/example/test.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /packages/vue-drawer/src/index.js: -------------------------------------------------------------------------------- 1 | import xDrawer from './source/drawer' 2 | 3 | export { 4 | xDrawer 5 | } 6 | -------------------------------------------------------------------------------- /packages/vue-drawer/src/source/drawer.js: -------------------------------------------------------------------------------- 1 | import { xModal } from '../../../vue-box/src' 2 | import { LIB_NAME } from '../../../../src/util/constants' 3 | 4 | const prefixCls = `${LIB_NAME}-drawer` 5 | const animationName = `${prefixCls}-animation` 6 | 7 | /** 8 | * @desc 推荐用 render 函数去创建 dom 在打开和关闭的 生命钩子函数由使用者自己通过事件的方式去实现 9 | * @desc 关闭的方法同 box 10 | * @param direction {String} ' left right top bottom | right' 11 | * @param className 12 | * @param showMask 13 | * @param maskClosable 14 | * @param escClose 15 | * @param render 16 | * */ 17 | const defaultOpt = { 18 | transitionName: animationName, 19 | className: prefixCls, 20 | closable: false, 21 | direction: 'right', 22 | showMask: true, 23 | maskClosable: true, 24 | escClose: true 25 | } 26 | 27 | export default function (opt) { 28 | const options = Object.assign({}, defaultOpt, opt) 29 | const direction = options.direction 30 | options.className = opt.className ? `${defaultOpt.className} ${prefixCls}-${direction} ${opt.className}` : `${defaultOpt.className} ${prefixCls}-${direction}` 31 | options.transitionName = `${options.transitionName}-${options.direction}` 32 | return xModal.dialog(options) 33 | } 34 | -------------------------------------------------------------------------------- /packages/vue-form/README.md: -------------------------------------------------------------------------------- 1 | ## Form 2 | 3 | 表单验证组件,基于`async-validator`开发。 4 | 5 | ### Form props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | model | 表单数据对象 | Object | - | - 10 | rules | 表单验证规则,详见`async-validator` | Object | - | - 11 | label-width | 表单域标签的的宽度 | Number / String | - | - 12 | label-height | 表单域标签的的高度 | Number / String | - | - 13 | vertical | 表单的标签和元素是否上下结构 | Boolean | - | false 14 | 15 | ### Form methods 16 | 17 | 方法名 | 说明 | 参数 18 | --- | --- | --- 19 | validate | 对整个表单进行校验,参数为检验完的回调,会返回一个 Boolean 表示成功与失败,支持 Promise | callback 20 | resetFields | 对整个表单进行重置,将所有字段值重置为空并移除校验结果 | — 21 | validateField | 对部分表单字段进行校验的方法,参数1为需校验的 prop,参数2为检验完回调,返回错误信息 | prop, callback 22 | 23 | ### FormItem props 24 | 25 | 属性 | 说明 | 类型 | 可选值 | 默认值 26 | --- | --- | --- | --- | --- 27 | prop | 对应表单域 model 里的字段 | String | - | - 28 | rules | 表单验证规则,会合并父级的规则 | Object / Array | - | - 29 | label | 标签文本 | String | - | - 30 | required | 是否必填,如不设置,则会根据校验规则自动生成 | Boolean | - | false 31 | label-width | 表单域标签的的宽度 | Number / String | - | - 32 | label-height | 表单域标签的的高度 | Number / String | - | - 33 | label-for | 指定原生的 label 标签的 for 属性 | String | - | - 34 | 35 | ### FormItem slots 36 | 37 | 名称 | 说明 | slot-scope 属性 38 | --- | --- | --- 39 | default | 内容 | - 40 | label | label内容 | - 41 | input | 使用原生input时用这个插入内容 | - 42 | select | 使用原生select时用这个插入内容 | - -------------------------------------------------------------------------------- /packages/vue-form/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-form/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-form/src/index.js: -------------------------------------------------------------------------------- 1 | import xForm from './source/Form' 2 | import xFormItem from './source/FormItem' 3 | 4 | export { 5 | xForm, 6 | xFormItem 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-form/src/source/Form.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 99 | -------------------------------------------------------------------------------- /packages/vue-input/README.md: -------------------------------------------------------------------------------- 1 | ## Input 2 | 3 | 基本表单组件,支持 input 和 textarea,并在原生控件基础上进行了功能扩展,可以组合使用。 4 | 5 | ### Input props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | type | 类型 | String | text、textarea 和其他原生 input 的 type 值 | text 10 | size | 尺寸,type="textarea" 时无效 | String | large / default / small | default 11 | value | 绑定值 | String / Number | — | — 12 | clearable | 是否可清空 | Boolean | — | false 13 | suffix-icon | 前置图标 | String | — | — 14 | prefix-icon | 后置图标 | String | — | — 15 | label | aria-label 属性 | String | — | — 16 | no-border | 是否无边框 | Boolean | — | false 17 | name | 原生属性 | String | — | — 18 | placeholder | 原生属性 | String | — | 请输入... 19 | disabled | 原生属性 | Boolean | — | false 20 | readonly | 原生属性 | Boolean | — | false 21 | autofocus | 原生属性 | Boolean | — | false 22 | autocomplete | 原生属性 | String | — | off 23 | maxlength | 原生属性 | Number | — | — 24 | minlength | 原生属性 | Number | — | — 25 | tabindex | 原生属性 | Number | — | — 26 | resize | 文本域是否可以拉伸 | String | — | — 27 | autosize | textarea 自适应,如 { minRows: 2, maxRows: 6 } | Boolean / Object | — | false 28 | rows | textarea 原生属性 | Number | — | 2 29 | validator-icon | 是否开启验证性的图标,在 form 表单中可开启 | Boolean | — | true 30 | 31 | ### Input slots 32 | 33 | 名称 | 说明 34 | --- | --- 35 | prefix | 前置图标插槽,插槽显示在输入框内 36 | suffix | 后置图标插槽,插槽显示在输入框内 37 | prepend | 前置内容插槽 38 | append | 后置内容插槽 39 | 40 | ### Input events 41 | 42 | 事件名称 | 说明 | 回调参数 43 | --- | --- | --- 44 | on-enterkey | 输入回车时触发 | event: Event 45 | on-click | 点击时触发 | event: Event 46 | on-blur | 失去焦点时触发 | event: Event 47 | on-focus | 获得焦点时触发 | event: Event 48 | on-change | 失去焦点并且输入值改变时触发 | value: String 49 | on-clear | 点击清空图标时触发 | — 50 | on-click-icon | 点击前置/后置图标时触发 | event: Event 51 | 52 | ### Input methods 53 | 54 | 方法名 | 说明 | 参数 55 | --- | --- | --- 56 | focus | 使 Input 组件获得焦点 | — 57 | blur | 使 Input 组件失去焦点 | — 58 | clear | 清空文本并且获得焦点 | — -------------------------------------------------------------------------------- /packages/vue-input/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-input/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-input/src/index.js: -------------------------------------------------------------------------------- 1 | import xInput from './source/Input.vue' 2 | 3 | export { 4 | xInput 5 | } 6 | -------------------------------------------------------------------------------- /packages/vue-pagination/README.md: -------------------------------------------------------------------------------- 1 | ## Pagination 2 | 3 | 当数据量过多时,使用分页分解数据。 4 | 5 | ### Pagination props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | current | 当前页 | Number | - | 1 10 | total | 总数据条数 | Number | - | 0 11 | page-size | 每页数据条数 | Number | - | 10 12 | page-size-options | 每页条数切换的配置 | Array | - | [10, 20, 30, 40, 50] 13 | pager-count | 页码按钮的数量,当总页数超过该值时会折叠(奇数) | Number | - | 7 14 | show-total | 是否显示总条数 | Boolean | - | false 15 | show-elevator | 是否显示跳转页 | Boolean | - | false 16 | show-sizer | 是否显示每页条数切换栏 | Boolean | - | false 17 | simple | 是否使用简洁版 | Boolean | - | false 18 | small | 是否显示迷你版 | Boolean | - | false 19 | 20 | #### Pagination events 21 | 22 | 事件名称 | 说明 | 返回值 23 | --- | --- | --- 24 | on-size-change | pageSize 改变时会触发 | 每页条数 25 | on-change | 页码切换时触发 | 返回当前页码 26 | -------------------------------------------------------------------------------- /packages/vue-pagination/example/app.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /packages/vue-pagination/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-pagination/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-pagination/src/index.js: -------------------------------------------------------------------------------- 1 | import xPage from './source/Page.vue' 2 | 3 | export { xPage } 4 | -------------------------------------------------------------------------------- /packages/vue-poptip/README.md: -------------------------------------------------------------------------------- 1 | ## Poptip 2 | 3 | 以卡片的形式承载了更多的内容,比如链接、表格、按钮等。 4 | 5 | ### Poptip props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | trigger | 触发方式 | String | hover, click, focus, 在 confirm 模式下,只有 click 有效 | click 10 | placement | 出现位置 | String | 详见popper.js文档 | top 11 | title | 标题 | String | — | — 12 | content | 显示的正文内容,只在非 confirm 模式下有效 | String | — | — 13 | disabled | 是否禁用 | Boolean | — | — 14 | width | 宽度 | Number | — | — 15 | visible-arrow | 是否显示箭头 | Boolean | — | true 16 | confirm | 是否开启对话框模式 | Boolean | — | false 17 | ok-text | 确定按钮的文字,只在 confirm 模式下有效 | String | — | 确定 18 | cancel-text | 取消按钮的文字,只在 confirm 模式下有效 | String | — | 取消 19 | distance | 弹出层与触发元素的距离 | Number | — | 5 20 | popper-class | 弹出层自定义样式 | String | — | — 21 | append-to-body | 弹出层是否插入 body | Boolean | — | false 22 | position-fixed | 弹出层是否 fixed 定位 | Boolean | — | false 23 | viewport | 弹出层是否基于 viewport 定位 | Boolean | — | false 24 | popper-options | Popper.js 的可选项 | Object | — | — 25 | 26 | ### Poptip slots 27 | 28 | 名称 | 说明 29 | --- | --- 30 | default | 内嵌 HTML 文本 31 | reference | 触发元素 32 | 33 | ### Poptip events 34 | 35 | 事件名称 | 说明 | 回调参数 36 | --- | --- | --- 37 | on-ok | 点击确定的回调 | — 38 | on-cancel | 点击取消的回调 | — -------------------------------------------------------------------------------- /packages/vue-poptip/example/app.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /packages/vue-poptip/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-poptip/example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './app.vue' 3 | import { xPoptip } from '../src' 4 | 5 | Vue.use(xPoptip) 6 | 7 | new Vue({ 8 | el: '#app', 9 | render: h => h(App), 10 | mounted () { 11 | console.log('success') 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /packages/vue-poptip/src/index.js: -------------------------------------------------------------------------------- 1 | import xPoptip from './source/Poptip.vue' 2 | import directive from './source/directive' 3 | 4 | xPoptip.directive = directive 5 | 6 | /* istanbul ignore next */ 7 | xPoptip.install = Vue => { 8 | Vue.directive('poptip', directive) 9 | } 10 | 11 | export { 12 | xPoptip 13 | } 14 | -------------------------------------------------------------------------------- /packages/vue-poptip/src/source/directive.js: -------------------------------------------------------------------------------- 1 | export default { 2 | bind (el, binding, vnode) { 3 | // vue 中 v-popover:argument 和 v-popover="variate || expression" 得到的 binding 数据是不同的。 4 | // 后者可以指向动态 popver 组件,可极大的增强popover指令的灵活程度。 5 | const ref = binding.expression ? binding.value : binding.arg 6 | ref && vnode.context.$refs[ref] && (vnode.context.$refs[ref].$refs.reference = el) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/vue-progress/README.md: -------------------------------------------------------------------------------- 1 | ## Progress 2 | 3 | 用于展示操作进度,告知用户当前状态和预期。 4 | 5 | ### Progress props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | percentage | 百分比,必选项 | Number | 0-100 | 0 10 | type | 进度条类型 | String | line / circle | line 11 | stroke-width | 进度条的宽度,单位 px | Number | — | 8 12 | status | 进度条当前状态 | String | success / exception | — 13 | color | 进度条背景色(会覆盖 status 状态颜色) | String | — | — 14 | width | 环形进度条宽度(只在 type=circle 时有效) | Number | — | 100 15 | show-inline-text | 是否显示进度条上(type=line 时)文字内容 | Boolean | — | false 16 | show-outside-text | 是否显示进度条右侧文字内容(只在 type=line 时有效) | Boolean | — | true 17 | show-circle-text | 是否显示环形进度条里面(type=circle 时)文字内容 | Boolean | — | true 18 | 19 | ### Progress slots 20 | 21 | 名称 | 说明 22 | --- | --- 23 | inline | type=line 时进度条上内容插槽 24 | outside | type=line 时进度条右侧的内容插槽 25 | circle | type=circle 时环形进度条里面的内容插槽 -------------------------------------------------------------------------------- /packages/vue-progress/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-progress/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-progress/src/index.js: -------------------------------------------------------------------------------- 1 | import xProgress from './source/Progress.vue' 2 | 3 | export { 4 | xProgress 5 | } 6 | -------------------------------------------------------------------------------- /packages/vue-radio/README.md: -------------------------------------------------------------------------------- 1 | ## Radio 2 | 3 | 用于一组可选项单项选择,或者单独用于切换到选中状态。 4 | 5 | ### Radio props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | value | 单独使用时有效,可用于v-model双向绑定 | Boolean | - | false 10 | name | 原生name属性 | String | - | - 11 | label | 组合使用时有效,指定当前选项value值 | String / Number | - | - 12 | disabled | 是否禁用 | Boolean | - | false 13 | size | 尺寸 | String | large / default / small | default 14 | true-value | 自定义选中时的值,当使用类似 1 和 0 来判断是否选中时会很有用 | String / Number / Boolean | - | true 15 | false-value | 自定义未选中时的值,当使用类似 1 和 0 来判断是否选中时会很有用 | String / Number / Boolean | - | false 16 | 17 | ### Radio events 18 | 19 | 事件名称 | 说明 | 返回值 20 | --- | --- | --- 21 | on-change | 在选项状态发生改变时触发,返回当前状态。通过修改外部的数据改变时不会触发 | 选中的 Radio value 值 22 | 23 | ### RadioGroup props 24 | 25 | 属性 | 说明 | 类型 | 可选值 | 默认值 26 | --- | --- | --- | --- | --- 27 | value | 当前选中的值,可用于v-model双向绑定 | String / Number / Boolean | - | - 28 | name | 原生name属性,优先级小于radio的 name 属性 | String | - | - 29 | size | 尺寸 | String | large、default、small | default 30 | vertical | 是否垂直显示 | Boolean | - | false 31 | 32 | ### RadioGroup events 33 | 34 | 事件名称 | 说明 | 返回值 35 | --- | --- | --- 36 | on-change | 在选项状态发生改变时触发,返回当前状态。通过修改外部的数据改变时不会触发 | 选中的 Radio label 值 -------------------------------------------------------------------------------- /packages/vue-radio/example/app.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 68 | 69 | 72 | -------------------------------------------------------------------------------- /packages/vue-radio/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-radio/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-radio/src/index.js: -------------------------------------------------------------------------------- 1 | import xRadio from './source/Radio.vue' 2 | import xRadioGroup from './source/RadioGroup.vue' 3 | 4 | export { 5 | xRadio, 6 | xRadioGroup 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-radio/src/source/RadioGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 75 | -------------------------------------------------------------------------------- /packages/vue-scroller/README.md: -------------------------------------------------------------------------------- 1 | ## Scroller 2 | 3 | 滚动视图 4 | 5 | ### Scroller props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | width | 视图宽度,当插槽内容宽度超过该值时出现水平滚动条 | String / Number | — | — 10 | max-width | 视图最大宽度,当插槽内容宽度超过该值时出现水平滚动条 | String / Number | — | — 11 | height | 视图高度,当插槽内容高度超过该值时出现垂直滚动条 | String / Number | — | — 12 | max-height | 视图最大高度,当插槽内容高度超过该值时出现垂直滚动条 | String / Number | — | — 13 | scrollbar-class | 滚动条自定义类 | String | — | — 14 | reverse-scroll-y | 是否反转 Y 轴滚轮,当该值为 true 时,滚动 Y 轴将控制水平方向的滚动 | Boolean | — | false 15 | show-scrollbar | 是否显示滚动条,当设置为`active`时,触发滚动或者鼠标移动到滚动条轨迹上时才会显示滚动条 | Boolean / String | true / false / 'active' | true 16 | check-on-mounted | 是否在 mounted 的时候递归调用 checkScrollable 方法,直到内容的宽度和高度不为 0 | Boolean | — | false 17 | bar-offset-left | 水平滚动条距离视图左侧的偏移 | Number | — | 0 18 | bar-offset-right | 水平滚动条距离视图右侧的偏移 | Number | — | 0 19 | bar-offset-top | 垂直滚动条距离视图顶部的偏移 | Number | — | 0 20 | bar-offset-bottom | 垂直滚动条距离视图底部的偏移 | Number | — | 0 21 | 22 | ### Scroller events 23 | 24 | 事件名称 | 说明 | 回调参数 25 | --- | --- | --- 26 | on-scroll-x | 水平滚动改变时触发 | 当前的 left 值,是否达到最左侧,是否达到最右侧 27 | on-scroll-y | 垂直滚动改变时触发 | 当前的 top 值,是否达到最顶部,是否达到最底部 28 | on-start-drag-bar | 开始拖动滚动条时触发 | 是否垂直滚动条 29 | on-end-drag-bar | 结束拖动滚动条时触发 | 是否垂直滚动条 30 | 31 | ### Scroller methods 32 | 33 | 方法名 | 说明 | 参数 34 | --- | --- | --- 35 | checkScrollable | 检查当前是否需要显示滚动条 | — 36 | setContentLeft | 设置内容区域的 left 值 | left: Number, transition: Boolean 37 | setContentTop | 设置内容区域的 top 值 | top: Number, transition: Boolean 38 | stickToBoundary | 将内容区域设置到指定边界 | vertical: Boolean, start: Boolean, transition: Boolean 39 | -------------------------------------------------------------------------------- /packages/vue-scroller/example/app.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 45 | -------------------------------------------------------------------------------- /packages/vue-scroller/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | demo 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/vue-scroller/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-scroller/src/index.js: -------------------------------------------------------------------------------- 1 | import xScroller from './source/Scroller.vue' 2 | 3 | export { 4 | xScroller 5 | } 6 | -------------------------------------------------------------------------------- /packages/vue-select/README.md: -------------------------------------------------------------------------------- 1 | ## Select 2 | 3 | 使用模拟的增强下拉选择器来代替浏览器原生的选择器。 4 | 5 | ### Select props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | value | 绑定值 | String / Number / Object / Array | — | — 10 | value-key | 当绑定值为对象或者对象数组时,通过该属性值判断 Option 是否被选中,否则将比较对象是否相等 | String | — | — 11 | name | select 组件中 input 的原生属性 | String | — | — 12 | placeholder | select 组件中 input 的原生属性 | String | — | 请选择 13 | input-props | select 组件中 input 组件的属性 | Object | — | — 14 | width | 下拉框的宽度,默认与触发元素的宽度相同 | String / Number | — | — 15 | height | 下拉框的高度,超出该高度出现滚动条 | String / Number | — | — 16 | max-height | 下拉框的最大高度,超出该高度出现滚动条 | String / Number | — | 300 17 | add-title | 是否在选项中增加 title 属性,显示超长的文本 | Boolean | — | false 18 | disabled | select 组件中 input 的原生属性 | Boolean | — | false 19 | clearable | 是否可清空已选项 | Boolean | — | false 20 | multiple | 是否开启多选 | Boolean | — | false 21 | filterable | 是否开启搜索功能 | Boolean | — | false 22 | filter-props | 当 option 的绑定值为对象时,搜索查找的对应属性列表 | Array | — | — 23 | no-data-text | 选项为空时显示的文字 | String | — | 暂无数据 24 | no-data-icon | 选项为空时显示的图标类名 | String | — | ans-icon-no-data 25 | highlight-matched-text | 搜索时是否高亮选项中匹配的文字 | Boolean | — | false 26 | ignore-case | 搜索时是否忽略大小写,可以和 filter-props 以及 highlight-matched-text 配合使用 | Boolean | — | false 27 | no-match-text | 搜索没有任何匹配项时显示的文字 | String | — | 搜索无结果 28 | no-match-icon | 搜索没有任何匹配项时显示的图标类名 | String | — | ans-icon-search-no-data 29 | has-arrow | 下拉框是否显示指示箭头 | Boolean | — | false 30 | append-to-body | 下拉框是否插入 body | Boolean | — | false 31 | position-fixed | 下拉框是否 fixed 定位 | Boolean | — | false 32 | viewport | 下拉框是否基于 viewport 定位 | Boolean | — | false 33 | popper-options | Popper.js 的可选项 | Object | — | — 34 | dropdown-class | 下拉框样式 | String | — | — 35 | scrollbar-class | 滚动条样式 | String | — | — 36 | drop-animation | 下拉框动画 | String | — | — 37 | 38 | ### Select events 39 | 40 | 事件名称 | 说明 | 回调参数 41 | --- | --- | --- 42 | on-change | 选中值发生变化时触发 | 目前的选中值,{ value: value, label: label } 43 | on-visible-change | 下拉框状态改变时触发 | 出现则为 true,隐藏则为 false 44 | on-keyword-change | 搜索关键字改变时触发 | keyword 45 | 46 | ### Select methods 47 | 48 | 方法名 | 说明 | 参数 49 | --- | --- | --- 50 | focus | 使 Input 组件获得焦点 | — 51 | blur | 使 input 失去焦点并且隐藏下拉框 | — 52 | search | 搜索 | keyword 53 | updateScrollbar | 更新下拉框内的滚动条 | — 54 | resetScrollbar | 将滚动条移回到顶部 | — 55 | setDropdownReference | 手动指定下拉框的触发元素 | dom 元素 56 | 57 | ### Select slots 58 | 59 | 名称 | 说明 | slot-scope 属性 60 | --- | --- | --- 61 | trigger | Select 组件触发元素的插槽 | selectedModel 62 | multiple | 开启多选时,控制 input 内如何显示的插槽 | selectedList 63 | header | 下拉框头部插槽,必须使用作用域插槽 | — 64 | footer | 下拉框底部插槽,必须使用作用域插槽 | — 65 | 66 | ### OptionGroup props 67 | 68 | 属性 | 说明 | 类型 | 可选值 | 默认值 69 | --- | --- | --- | --- | --- 70 | label | 分组类别名称 | String | — | — 71 | 72 | ### OptionGroup slots 73 | 74 | 名称 | 说明 75 | --- | --- 76 | content | 控制分组标签如何显示的插槽 77 | 78 | ### Option props 79 | 80 | 属性 | 说明 | 类型 | 可选值 | 默认值 81 | --- | --- | --- | --- | --- 82 | value | 绑定值,可以直接绑定对象,必选项 | String / Number / Object | — | — 83 | label | 选项文本,必选项 | String / Number | — | — 84 | disabled | 是否不可选 | Boolean | — | false 85 | click-handler | 覆盖默认的点击处理,使用该属性意味着需要自己处理选择逻辑 | Function(value, label) | — | — -------------------------------------------------------------------------------- /packages/vue-select/example/dynamic.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 74 | 75 | 129 | -------------------------------------------------------------------------------- /packages/vue-select/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-select/example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './navigation.vue' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(App), 7 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-select/example/navigation.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 52 | 53 | 107 | -------------------------------------------------------------------------------- /packages/vue-select/src/index.js: -------------------------------------------------------------------------------- 1 | import xSelect from './source/Select.vue' 2 | import xOption from './source/Option.vue' 3 | import xOptionGroup from './source/OptionGroup.vue' 4 | 5 | export { 6 | xSelect, 7 | xOption, 8 | xOptionGroup 9 | } 10 | -------------------------------------------------------------------------------- /packages/vue-select/src/source/OptionGroup.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 41 | -------------------------------------------------------------------------------- /packages/vue-spin/README.md: -------------------------------------------------------------------------------- 1 | ## Spin 2 | 3 | 加载数据时显示遮罩和提示。 4 | 5 | ### Spin 指令修饰符 6 | 7 | 修饰符 | 说明 8 | --- | --- 9 | fullscreen | 全屏 10 | lock | 锁定滚动,隐藏滚动条,仅在 fullscreen 为 true 时可用 11 | body | 指定 DOM 节点插入 body 中 12 | 13 | ### Spin 绑定元素属性 14 | 15 | 属性名称 | 说明 16 | --- | --- 17 | spin-text | 加载图标下方文字 18 | spin-background | 遮罩背景色 19 | spin-icon-class | 自定义加载图标类名 20 | spin-custom-class | spin 的自定义类名 21 | 22 | ### Spin 服务配置 23 | 24 | 属性 | 说明 | 类型 | 可选值 | 默认值 25 | --- | --- | --- | --- | --- 26 | target | spin 需要覆盖的 DOM 节点。可传入一个 DOM 对象或字符串;若传入字符串,则会将其作为参数传 document.querySelector 以获取到对应 DOM 节点 | Object / String | — | document.body 27 | body | 同 v-spin 指令中的 body 修饰符 | Boolean | — | false 28 | fullscreen | 同 v-spin 指令中的 fullscreen 修饰符 | Boolean | — | true 29 | lock | 同 v-spin 指令中的 lock 修饰符 | Boolean |— | false 30 | text | 加载图标下方文字 | String | — | — 31 | background | 遮罩背景色 | String | — | — 32 | iconClass | 自定义加载图标类名 | String | — | — 33 | customClass | spin 的自定义类名 | String | — | — -------------------------------------------------------------------------------- /packages/vue-spin/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-spin/example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './app.vue' 3 | import { xSpin } from '../src' 4 | 5 | Vue.use(xSpin) 6 | 7 | new Vue({ 8 | el: '#app', 9 | render: h => h(App), 10 | mounted () { 11 | console.log('success') 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /packages/vue-spin/src/index.js: -------------------------------------------------------------------------------- 1 | import xSpin from './source/Spin.vue' 2 | import directive from './source/directive' 3 | import { init, defaults } from './source/service' 4 | 5 | xSpin.init = init 6 | 7 | xSpin.install = (Vue, options = {}) => { 8 | const { directiveName = 'spin', text, background, iconClass, customClass } = options 9 | defaults.text = text 10 | defaults.background = background 11 | defaults.iconClass = iconClass 12 | defaults.customClass = customClass 13 | Vue.directive(directiveName, directive) 14 | Vue.prototype.$spin = xSpin.init 15 | } 16 | 17 | export { xSpin } 18 | -------------------------------------------------------------------------------- /packages/vue-spin/src/source/Spin.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 58 | -------------------------------------------------------------------------------- /packages/vue-spin/src/source/service.js: -------------------------------------------------------------------------------- 1 | import { addClass, removeClass, getStyle } from '../../../../src/util' 2 | import Vue from 'vue' 3 | import xSpin from './Spin.vue' 4 | 5 | const SpinConstructor = Vue.extend(xSpin) 6 | 7 | const defaults = { 8 | body: false, 9 | fullscreen: true, 10 | lock: false, 11 | text: null, 12 | background: null, 13 | iconClass: '', 14 | customClass: '' 15 | } 16 | 17 | let fullscreenLoading 18 | 19 | SpinConstructor.prototype.originalPosition = '' 20 | 21 | SpinConstructor.prototype.close = function () { 22 | if (this.fullscreen) { 23 | fullscreenLoading = undefined 24 | } 25 | this.visible = false 26 | } 27 | 28 | const addStyle = (options, parent, instance) => { 29 | if (options.fullscreen) { 30 | instance.originalPosition = getStyle(document.body, 'position') 31 | } else if (options.body) { 32 | instance.originalPosition = getStyle(document.body, 'position') 33 | const spinStyle = instance.$el.style 34 | ;['top', 'left'].forEach(property => { 35 | const scroll = property === 'top' ? 'scrollTop' : 'scrollLeft' 36 | spinStyle[property] = options.target.getBoundingClientRect()[property] + 37 | document.body[scroll] + 38 | document.documentElement[scroll] - 39 | parseInt(getStyle(document.body, `margin-${property}`), 10) + 'px' 40 | }) 41 | ;['height', 'width'].forEach(property => { 42 | spinStyle[property] = options.target.getBoundingClientRect()[property] + 'px' 43 | }) 44 | } else { 45 | instance.originalPosition = getStyle(parent, 'position') 46 | } 47 | } 48 | 49 | const init = (options = {}) => { 50 | options = Object.assign({}, defaults, options) 51 | if (typeof options.target === 'string') { 52 | options.target = document.querySelector(options.target) 53 | } 54 | options.target = options.target || document.body 55 | if (options.target !== document.body) { 56 | options.fullscreen = false 57 | } else { 58 | options.body = true 59 | } 60 | if (options.fullscreen && fullscreenLoading) { 61 | return fullscreenLoading 62 | } 63 | 64 | const parent = options.body ? document.body : options.target 65 | const instance = new SpinConstructor({ 66 | el: document.createElement('div'), 67 | data: options 68 | }) 69 | options.onAfterLeave = () => { 70 | removeClass(parent, 'spin-relative-parent') 71 | removeClass(parent, 'spin-lock-overflow') 72 | parent.removeChild(instance.$el) 73 | instance.$destroy() 74 | } 75 | 76 | addStyle(options, parent, instance) 77 | if (instance.originalPosition !== 'absolute' && instance.originalPosition !== 'fixed') { 78 | addClass(parent, 'spin-relative-parent') 79 | } 80 | if (options.fullscreen && options.lock) { 81 | addClass(parent, 'spin-lock-overflow') 82 | } 83 | parent.appendChild(instance.$el) 84 | Vue.nextTick(() => { 85 | instance.visible = true 86 | }) 87 | if (options.fullscreen) { 88 | fullscreenLoading = instance 89 | } 90 | return instance 91 | } 92 | 93 | export { 94 | init, 95 | defaults 96 | } 97 | -------------------------------------------------------------------------------- /packages/vue-switch/README.md: -------------------------------------------------------------------------------- 1 | ## Switch 2 | 3 | 在两种状态间切换时用到的开关选择器。 4 | 5 | ### Switch props 6 | 7 | 属性 | 说明 | 类型 | 可选值 | 默认值 8 | --- | --- | --- | --- | --- 9 | name | 表单原始name属性 | String / Number / Boolean | - | - 10 | value | 开关当前值 | Boolean | - | false 11 | text | 开关内显示的文本 | Object | {on: '',off: ''} | {on: '',off: ''} 12 | readonly | 只读状态 | Boolean | - | false 13 | disabled | 禁用状态 | Boolean | - | false 14 | size | 开关大小 | String | large / default / small | default 15 | true-value | 自定义选中时的值,当使用类似 1 和 0 来判断是否选中时会很有用 | String / Number / Boolean | - | true 16 | false-value | 自定义未选中时的值,当使用类似 1 和 0 来判断是否选中时会很有用 | String / Number / Boolean | - | false 17 | 18 | ### Switch events 19 | 20 | 事件名称 | 说明 | 回调参数 21 | --- | --- | --- 22 | on-click | 点击开关时触发 | 当前 value 值 23 | on-change | 开关变化时触发,显示当前状态 | 当前 value 值 -------------------------------------------------------------------------------- /packages/vue-switch/example/app.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /packages/vue-switch/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-switch/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-switch/src/index.js: -------------------------------------------------------------------------------- 1 | import xSwitch from './source/Switch.vue' 2 | 3 | export { xSwitch } 4 | -------------------------------------------------------------------------------- /packages/vue-switch/src/source/Switch.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 108 | -------------------------------------------------------------------------------- /packages/vue-table/example/array.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 32 | -------------------------------------------------------------------------------- /packages/vue-table/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | demo 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/vue-table/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-table/example/paging.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 84 | -------------------------------------------------------------------------------- /packages/vue-table/example/restrict.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 75 | -------------------------------------------------------------------------------- /packages/vue-table/example/sort.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 66 | -------------------------------------------------------------------------------- /packages/vue-table/example/tree.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 71 | -------------------------------------------------------------------------------- /packages/vue-table/src/index.js: -------------------------------------------------------------------------------- 1 | import xTable from './source/Table.vue' 2 | import xTableColumn from './source/TableColumn.vue' 3 | 4 | export { 5 | xTable, 6 | xTableColumn 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-table/src/source/CellRenderer.vue: -------------------------------------------------------------------------------- 1 | 52 | -------------------------------------------------------------------------------- /packages/vue-table/src/source/layoutObserver.js: -------------------------------------------------------------------------------- 1 | export default { 2 | created () { 3 | this.tableLayout.addObserver(this) 4 | }, 5 | 6 | destroyed () { 7 | this.tableLayout.removeObserver(this) 8 | }, 9 | 10 | computed: { 11 | tableLayout () { 12 | let layout = this.layout 13 | if (!layout && this.table) { 14 | layout = this.table.layout 15 | } 16 | if (!layout) { 17 | throw new Error('Layout Observer: Can\'t find table layout.') 18 | } 19 | return layout 20 | } 21 | }, 22 | 23 | methods: { 24 | onColumnsChange () { 25 | const cols = this.$el.querySelectorAll('colgroup > col') 26 | if (!cols.length) return 27 | const columnsMap = this.store.states.leafColumnMap 28 | for (let i = 0, j = cols.length; i < j; i++) { 29 | const col = cols[i] 30 | const name = col.getAttribute('name') 31 | const column = columnsMap[name] 32 | if (column) { 33 | col.setAttribute('width', column.currentWidth) 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/vue-timepicker/README.md: -------------------------------------------------------------------------------- 1 | An component project 2 | 3 | ### Setup 4 | 5 | - 安装node > 8的LTS版本,https://nodejs.org/en/ 6 | 7 | - 增加npm本地仓库host,106.75.23.50 npm.analysys.cn 8 | 9 | - 没安装yarn的,可以忽略以下yarn命令 10 | 11 | ```sh 12 | # set registry 13 | npm config set registry http://registry.npm.analysys.cn 14 | 15 | # install parcel 16 | yarn global add parcel-bundler | npm i -g parcel-bundler 17 | 18 | # install dependencies 19 | yarn | npm i 20 | 21 | # startup development server (defaults to 3000) 22 | # -> http://localhost:3000 23 | yarn start | npm start 24 | ``` 25 | 26 | ### Lint 27 | ```sh 28 | yarn test | npm run test 29 | yarn lint:fix | npm run lint:fix 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/vue-timepicker/example/app.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 41 | -------------------------------------------------------------------------------- /packages/vue-timepicker/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-timepicker/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 | mounted () { 8 | console.log('success') 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-timepicker/src/index.js: -------------------------------------------------------------------------------- 1 | import xTimepicker from './source/Timepicker.vue' 2 | 3 | export { xTimepicker } 4 | -------------------------------------------------------------------------------- /packages/vue-tooltip/README.md: -------------------------------------------------------------------------------- 1 | ## Tooltip 2 | 3 | 简单的文字提示工具,用于代替浏览器的 title 提示。 4 | 5 | ### Tooltip 指令修饰符 6 | 7 | 修饰符 | 说明 8 | --- | --- 9 | click | 点击触发提示 10 | top / bottom / left / right | 提示优先方向,分别对应上/下/左/右 11 | start / end | 提示位置,可与方向组合使用 12 | light / dark | 主题,默认为 dark 13 | fixed | 提示是否 fixed 定位 14 | viewport | 提示是否基于 viewport 定位 15 | large | 是否启用大号提示 16 | 17 | ### Tooltip 详细配置 18 | 19 | 属性 | 说明 | 类型 | 可选值 | 默认值 20 | --- | --- | --- | --- | --- 21 | text | 提示文本,支持标签 | String | — | — 22 | placement | 提示优先出现方位 | 详见popper.js文档 | top 23 | triggerEvent | 触发提示事件 | String | click / mouseenter / manual | mouseenter 24 | theme | 主题 | String | light / dark | dark 25 | maxWidth | 提示内容最大宽度,超过该宽度换行 | String | — | 200px 26 | positionFixed | 同 fixed 修饰符 | Boolean | — | false 27 | viewport | 同 viewport 修饰符 | Boolean | — | false 28 | large | 同 large 修饰符 | Boolean | — | false 29 | reveal | 当 triggerEvent 为 `manual` 的时候,控制 tooltip 是否显示 | Boolean | — | false 30 | 31 | ### Tooltip 方法 32 | 33 | tooltip 对应的 dom 节点可以调用 destroy 方法销毁组件,hide 方法隐藏提示 34 | -------------------------------------------------------------------------------- /packages/vue-tooltip/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | demo 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/vue-tooltip/example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './app.vue' 3 | import { xTooltip } from '../src' 4 | 5 | Vue.use(xTooltip) 6 | 7 | new Vue({ 8 | el: '#app', 9 | render: h => h(App), 10 | mounted () { 11 | console.log('success') 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /packages/vue-tooltip/src/index.js: -------------------------------------------------------------------------------- 1 | import xTooltip from './source/Tooltip.vue' 2 | import directive from './source/directive' 3 | 4 | xTooltip.install = (Vue, options = {}) => { 5 | const { directiveName = 'tooltip' } = options 6 | Vue.directive(directiveName, directive) 7 | } 8 | 9 | export { 10 | xTooltip 11 | } 12 | -------------------------------------------------------------------------------- /packages/vue-tooltip/src/source/Tooltip.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 82 | -------------------------------------------------------------------------------- /packages/vue-tooltip/src/source/directive.js: -------------------------------------------------------------------------------- 1 | import factory from './factory' 2 | 3 | const PLACEMENTS = ['top', 'bottom', 'left', 'right'] 4 | const POSITIONS = ['start', 'end'] 5 | 6 | export default { 7 | bind (el, binding) { 8 | // 移除事件 9 | removeListeners(el) 10 | // 是否点击触发,是否浅色主题 11 | const { click, light, fixed, viewport, large } = binding.modifiers 12 | // 位置使用第一个修饰符,不传则居中 13 | const positionModifiers = POSITIONS.filter(position => binding.modifiers[position]) 14 | const position = positionModifiers.length ? positionModifiers[0] : '' 15 | // 方向使用第一个修饰符,不传则默认为 top 16 | const placementModifiers = PLACEMENTS.filter(placement => binding.modifiers[placement]) 17 | let placement = placementModifiers.length ? placementModifiers[0] : 'top' 18 | placement = position ? `${placement}-${position}` : placement 19 | // 默认配置 20 | const defaultOptions = { 21 | placement, 22 | triggerEvent: click ? 'click' : 'mouseenter', 23 | theme: light ? 'light' : 'dark', 24 | maxWidth: '370px', 25 | positionFixed: !!fixed, 26 | viewport: !!viewport, 27 | large: !!large 28 | } 29 | // 可以绑定配置对象 30 | let options = typeof binding.value === 'object' ? binding.value : { text: binding.value } 31 | options = Object.assign({}, defaultOptions, options) 32 | options.el = el 33 | el._ttOptions = options 34 | // 绑定事件监听 35 | el._appearHandler = function appearHandler () { 36 | if (!this._ttInstance) { 37 | // 确保使用最新的配置 38 | this._ttInstance = factory(this._ttOptions) 39 | } 40 | if (this._ttOptions.text) { 41 | this._ttInstance.show() 42 | } 43 | } 44 | el._vanishHandler = function vanishHandler () { 45 | if (this._ttInstance) { 46 | this._ttInstance.hide() 47 | } 48 | } 49 | if (options.triggerEvent === 'manual') { 50 | el._ttInstance = factory(options) 51 | } else { 52 | el.addEventListener(options.triggerEvent, el._appearHandler) 53 | el.addEventListener('mouseleave', el._vanishHandler) 54 | } 55 | }, 56 | 57 | update (el, binding) { 58 | // 刷新配置 59 | let options = typeof binding.value === 'object' ? binding.value : { text: binding.value } 60 | options = Object.assign({}, el._ttOptions, options) 61 | options.el = el 62 | el._ttOptions = options 63 | if (el._ttInstance) { 64 | el._ttInstance.update(options) 65 | } 66 | }, 67 | 68 | unbind (el) { 69 | const instance = el._ttInstance 70 | if (instance && instance.$destroy) { 71 | instance.$destroy() 72 | } 73 | removeListeners(el) 74 | delete el._appearHandler 75 | delete el._vanishHandler 76 | delete el._ttInstance 77 | delete el._ttOptions 78 | } 79 | } 80 | 81 | function removeListeners (el) { 82 | if (el._appearHandler) { 83 | el.removeEventListener('click', el._appearHandler) 84 | el.removeEventListener('mouseenter', el._appearHandler) 85 | } 86 | if (el._vanishHandler) { 87 | el.removeEventListener('mouseleave', el._vanishHandler) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /packages/vue-tooltip/src/source/factory.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Tooltip from './Tooltip.vue' 3 | 4 | // 组件构造器 5 | const TooltipConstructor = Vue.extend(Tooltip) 6 | 7 | export default (options = {}) => { 8 | const { 9 | triggerEvent, 10 | text = '', 11 | placement, 12 | theme, 13 | maxWidth, 14 | el, 15 | positionFixed, 16 | viewport, 17 | large, 18 | reveal 19 | } = options 20 | const instance = new TooltipConstructor({ 21 | propsData: { 22 | triggerEvent, 23 | content: text, 24 | placement, 25 | theme, 26 | maxWidth, 27 | reference: el, 28 | positionFixed: positionFixed, 29 | viewport: viewport, 30 | large, 31 | reveal 32 | } 33 | }).$mount() 34 | document.body.appendChild(instance.$el) 35 | instance.$el.destroy = () => { 36 | instance.$destroy() 37 | } 38 | instance.$el.hide = () => { 39 | instance.hide() 40 | } 41 | return instance 42 | } 43 | -------------------------------------------------------------------------------- /src/locale/format.js: -------------------------------------------------------------------------------- 1 | const RE_NARGS = /(%|)\{([0-9a-zA-Z_]+)\}/g 2 | /** 3 | * String format template 4 | * - Inspired: 5 | * https://github.com/Matt-Esch/string-template/index.js 6 | */ 7 | export default function (Vue) { 8 | /** 9 | * template 10 | * 11 | * @param {String} string 12 | * @param {Array} ...args 13 | * @return {String} 14 | */ 15 | 16 | function template (string, ...args) { 17 | if (args.length === 1 && typeof args[0] === 'object') { 18 | args = args[0] 19 | } 20 | 21 | if (!args || !args.hasOwnProperty) { 22 | args = {} 23 | } 24 | 25 | return string.replace(RE_NARGS, (match, prefix, i, index) => { 26 | let result 27 | 28 | if (string[index - 1] === '{' && 29 | string[index + match.length] === '}') { 30 | return i 31 | } else { 32 | result = Object.prototype.hasOwnProperty.call(args, i) ? args[i] : null 33 | if (result === null || result === undefined) { 34 | return '' 35 | } 36 | 37 | return result 38 | } 39 | }) 40 | } 41 | 42 | return template 43 | } 44 | -------------------------------------------------------------------------------- /src/locale/index.js: -------------------------------------------------------------------------------- 1 | import defaultLang from './lang/zh-CN' 2 | import Vue from 'vue' 3 | import deepmerge from 'deepmerge' 4 | import Format from './format' 5 | 6 | const format = Format(Vue) 7 | let lang = defaultLang 8 | let merged = false 9 | let i18nHandler = function () { 10 | const vuei18n = Object.getPrototypeOf(this || Vue).$t 11 | if (typeof vuei18n === 'function' && !!Vue.locale) { 12 | if (!merged) { 13 | merged = true 14 | Vue.locale( 15 | Vue.config.lang, 16 | deepmerge(lang, Vue.locale(Vue.config.lang) || {}, { clone: true }) 17 | ) 18 | } 19 | return vuei18n.apply(this, arguments) 20 | } 21 | } 22 | 23 | export const t = function (path, options) { 24 | let value = i18nHandler.apply(this, arguments) 25 | if (value !== null && value !== undefined) return value 26 | 27 | const array = path.split('.') 28 | let current = lang 29 | 30 | for (let i = 0, j = array.length; i < j; i++) { 31 | const property = array[i] 32 | value = current[property] 33 | if (i === j - 1) return format(value, options) 34 | if (!value) return '' 35 | current = value 36 | } 37 | return '' 38 | } 39 | 40 | export const use = function (l) { 41 | lang = l || lang 42 | } 43 | 44 | export const i18n = function (fn) { 45 | i18nHandler = fn || i18nHandler 46 | } 47 | 48 | export default { use, t, i18n } 49 | -------------------------------------------------------------------------------- /src/locale/lang/en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | ans: { 3 | modal: { 4 | confirm: 'OK', 5 | cancel: 'Cancel' 6 | }, 7 | cascader: { 8 | placeholder: 'Select', 9 | noMatch: 'No matching data', 10 | noData: 'No data' 11 | }, 12 | datepicker: { 13 | placeholder: 'Select date', 14 | cancel: 'Cancel', 15 | confirm: 'OK', 16 | year: '', 17 | month1: 'January', 18 | month2: 'February', 19 | month3: 'March', 20 | month4: 'April', 21 | month5: 'May', 22 | month6: 'June', 23 | month7: 'July', 24 | month8: 'August', 25 | month9: 'September', 26 | month10: 'October', 27 | month11: 'November', 28 | month12: 'December', 29 | weeks: { 30 | sun: 'Sun', 31 | mon: 'Mon', 32 | tue: 'Tue', 33 | wed: 'Wed', 34 | thu: 'Thu', 35 | fri: 'Fri', 36 | sat: 'Sat' 37 | }, 38 | selectTime: 'Select time', 39 | startTime: 'Start time', 40 | endTime: 'End time' 41 | }, 42 | input: { 43 | placeholder: 'Please enter...' 44 | }, 45 | page: { 46 | goto: 'Go to', 47 | pagesize: '/page', 48 | total: 'Total {total}', 49 | pageClassifier: '' 50 | }, 51 | poptip: { 52 | confirm: 'OK', 53 | cancel: 'Cancel' 54 | }, 55 | select: { 56 | placeholder: 'Select', 57 | noMatch: 'No matching data', 58 | noData: 'No data', 59 | search: 'Keyword' 60 | }, 61 | table: { 62 | emptyText: 'No data' 63 | }, 64 | timepicker: { 65 | clear: 'Clear', 66 | confirm: 'OK', 67 | placeholder: 'Select' 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/locale/lang/zh-CN.js: -------------------------------------------------------------------------------- 1 | export default { 2 | ans: { 3 | modal: { 4 | confirm: '确定', 5 | cancel: '取消' 6 | }, 7 | cascader: { 8 | placeholder: '请选择', 9 | noMatch: '搜索无结果', 10 | noData: '暂无数据' 11 | }, 12 | datepicker: { 13 | placeholder: '请选择日期', 14 | cancel: '取消', 15 | confirm: '确定', 16 | year: '年', 17 | month1: '1 月', 18 | month2: '2 月', 19 | month3: '3 月', 20 | month4: '4 月', 21 | month5: '5 月', 22 | month6: '6 月', 23 | month7: '7 月', 24 | month8: '8 月', 25 | month9: '9 月', 26 | month10: '10 月', 27 | month11: '11 月', 28 | month12: '12 月', 29 | weeks: { 30 | sun: '日', 31 | mon: '一', 32 | tue: '二', 33 | wed: '三', 34 | thu: '四', 35 | fri: '五', 36 | sat: '六' 37 | }, 38 | selectTime: '选择时间', 39 | startTime: '开始时间', 40 | endTime: '结束时间' 41 | }, 42 | input: { 43 | placeholder: '请输入...' 44 | }, 45 | page: { 46 | goto: '跳转至', 47 | pagesize: '条/页', 48 | total: '共 {total} 条', 49 | pageClassifier: '页' 50 | }, 51 | poptip: { 52 | confirm: '确定', 53 | cancel: '取消' 54 | }, 55 | select: { 56 | placeholder: '请选择', 57 | noMatch: '搜索无结果', 58 | noData: '暂无数据', 59 | search: '搜索' 60 | }, 61 | table: { 62 | emptyText: '暂无数据' 63 | }, 64 | timepicker: { 65 | clear: '清空', 66 | confirm: '确定', 67 | placeholder: '请选择时间' 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/style/animation/index.scss: -------------------------------------------------------------------------------- 1 | @import "./fadingEntrances.scss"; 2 | @import "./fadingExits.scss"; 3 | 4 | .#{$animation-prefix}fade-enter-active { 5 | animation: fadeIn $animation-time; 6 | } 7 | .#{$animation-prefix}fade-leave-active { 8 | animation: fadeOut $animation-time; 9 | } 10 | 11 | // 弹出下拉框过渡,SelectDropDwon 12 | .#{$animation-prefix}drop-enter-active, 13 | .#{$animation-prefix}drop-leave-active { 14 | opacity: 1; 15 | transform: scaleY(1); 16 | transition: transform $animation-time cubic-bezier(0.23, 1, 0.32, 1), 17 | opacity $animation-time cubic-bezier(0.23, 1, 0.32, 1); 18 | } 19 | [x-placement^="top"] { 20 | &.#{$animation-prefix}drop-enter-active, 21 | &.#{$animation-prefix}drop-leave-active { 22 | transform-origin: center bottom; 23 | } 24 | } 25 | [x-placement^="bottom"] { 26 | &.#{$animation-prefix}drop-enter-active, 27 | &.#{$animation-prefix}drop-leave-active { 28 | transform-origin: center top; 29 | } 30 | } 31 | .#{$animation-prefix}drop-enter, 32 | .#{$animation-prefix}drop-leave-active { 33 | opacity: 0; 34 | transform: scaleY(0); 35 | } 36 | 37 | .animated { 38 | -webkit-animation-duration: 1s; 39 | animation-duration: 1s; 40 | -webkit-animation-fill-mode: both; 41 | animation-fill-mode: both; 42 | } 43 | .animated.infinite { 44 | -webkit-animation-iteration-count: infinite; 45 | animation-iteration-count: infinite; 46 | } 47 | .animated.delay-1s { 48 | -webkit-animation-delay: 1s; 49 | animation-delay: 1s; 50 | } 51 | .animated.delay-2s { 52 | -webkit-animation-delay: 2s; 53 | animation-delay: 2s; 54 | } 55 | .animated.delay-3s { 56 | -webkit-animation-delay: 3s; 57 | animation-delay: 3s; 58 | } 59 | .animated.delay-4s { 60 | -webkit-animation-delay: 4s; 61 | animation-delay: 4s; 62 | } 63 | .animated.delay-5s { 64 | -webkit-animation-delay: 5s; 65 | animation-delay: 5s; 66 | } 67 | .animated.fast { 68 | -webkit-animation-duration: 800ms; 69 | animation-duration: 800ms; 70 | } 71 | .animated.faster { 72 | -webkit-animation-duration: 500ms; 73 | animation-duration: 500ms; 74 | } 75 | .animated.slow { 76 | -webkit-animation-duration: 2s; 77 | animation-duration: 2s; 78 | } 79 | .animated.slower { 80 | -webkit-animation-duration: 3s; 81 | animation-duration: 3s; 82 | } 83 | @media (prefers-reduced-motion) { 84 | .animated { 85 | -webkit-animation: unset !important; 86 | animation: unset !important; 87 | -webkit-transition: none !important; 88 | transition: none !important; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/style/animation/lightspeed.scss: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes lightSpeedIn { 2 | from { 3 | -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); 4 | transform: translate3d(100%, 0, 0) skewX(-30deg); 5 | opacity: 0; 6 | } 7 | 60% { 8 | -webkit-transform: skewX(20deg); 9 | transform: skewX(20deg); 10 | opacity: 1; 11 | } 12 | 80% { 13 | -webkit-transform: skewX(-5deg); 14 | transform: skewX(-5deg); 15 | } 16 | to { 17 | -webkit-transform: translate3d(0, 0, 0); 18 | transform: translate3d(0, 0, 0); 19 | } 20 | } 21 | @keyframes lightSpeedIn { 22 | from { 23 | -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); 24 | transform: translate3d(100%, 0, 0) skewX(-30deg); 25 | opacity: 0; 26 | } 27 | 60% { 28 | -webkit-transform: skewX(20deg); 29 | transform: skewX(20deg); 30 | opacity: 1; 31 | } 32 | 80% { 33 | -webkit-transform: skewX(-5deg); 34 | transform: skewX(-5deg); 35 | } 36 | to { 37 | -webkit-transform: translate3d(0, 0, 0); 38 | transform: translate3d(0, 0, 0); 39 | } 40 | } 41 | .lightSpeedIn { 42 | -webkit-animation-name: lightSpeedIn; 43 | animation-name: lightSpeedIn; 44 | -webkit-animation-timing-function: ease-out; 45 | animation-timing-function: ease-out; 46 | } 47 | @-webkit-keyframes lightSpeedOut { 48 | from { 49 | opacity: 1; 50 | } 51 | to { 52 | -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); 53 | transform: translate3d(100%, 0, 0) skewX(30deg); 54 | opacity: 0; 55 | } 56 | } 57 | @keyframes lightSpeedOut { 58 | from { 59 | opacity: 1; 60 | } 61 | to { 62 | -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); 63 | transform: translate3d(100%, 0, 0) skewX(30deg); 64 | opacity: 0; 65 | } 66 | } 67 | .lightSpeedOut { 68 | -webkit-animation-name: lightSpeedOut; 69 | animation-name: lightSpeedOut; 70 | -webkit-animation-timing-function: ease-in; 71 | animation-timing-function: ease-in; 72 | } -------------------------------------------------------------------------------- /src/style/animation/slidingExits.scss: -------------------------------------------------------------------------------- 1 | @keyframes slideOutDown { 2 | from { 3 | -webkit-transform: translate3d(0, 0, 0); 4 | transform: translate3d(0, 0, 0); 5 | } 6 | to { 7 | visibility: hidden; 8 | -webkit-transform: translate3d(0, 100%, 0); 9 | transform: translate3d(0, 100%, 0); 10 | } 11 | } 12 | .slideOutDown { 13 | -webkit-animation-name: slideOutDown; 14 | animation-name: slideOutDown; 15 | } 16 | @-webkit-keyframes slideOutLeft { 17 | from { 18 | -webkit-transform: translate3d(0, 0, 0); 19 | transform: translate3d(0, 0, 0); 20 | } 21 | to { 22 | visibility: hidden; 23 | -webkit-transform: translate3d(-100%, 0, 0); 24 | transform: translate3d(-100%, 0, 0); 25 | } 26 | } 27 | @keyframes slideOutLeft { 28 | from { 29 | -webkit-transform: translate3d(0, 0, 0); 30 | transform: translate3d(0, 0, 0); 31 | } 32 | to { 33 | visibility: hidden; 34 | -webkit-transform: translate3d(-100%, 0, 0); 35 | transform: translate3d(-100%, 0, 0); 36 | } 37 | } 38 | .slideOutLeft { 39 | -webkit-animation-name: slideOutLeft; 40 | animation-name: slideOutLeft; 41 | } 42 | @-webkit-keyframes slideOutRight { 43 | from { 44 | -webkit-transform: translate3d(0, 0, 0); 45 | transform: translate3d(0, 0, 0); 46 | } 47 | to { 48 | visibility: hidden; 49 | -webkit-transform: translate3d(100%, 0, 0); 50 | transform: translate3d(100%, 0, 0); 51 | } 52 | } 53 | @keyframes slideOutRight { 54 | from { 55 | -webkit-transform: translate3d(0, 0, 0); 56 | transform: translate3d(0, 0, 0); 57 | } 58 | to { 59 | visibility: hidden; 60 | -webkit-transform: translate3d(100%, 0, 0); 61 | transform: translate3d(100%, 0, 0); 62 | } 63 | } 64 | .slideOutRight { 65 | -webkit-animation-name: slideOutRight; 66 | animation-name: slideOutRight; 67 | } 68 | @-webkit-keyframes slideOutUp { 69 | from { 70 | -webkit-transform: translate3d(0, 0, 0); 71 | transform: translate3d(0, 0, 0); 72 | } 73 | to { 74 | visibility: hidden; 75 | -webkit-transform: translate3d(0, -100%, 0); 76 | transform: translate3d(0, -100%, 0); 77 | } 78 | } 79 | @keyframes slideOutUp { 80 | from { 81 | -webkit-transform: translate3d(0, 0, 0); 82 | transform: translate3d(0, 0, 0); 83 | } 84 | to { 85 | visibility: hidden; 86 | -webkit-transform: translate3d(0, -100%, 0); 87 | transform: translate3d(0, -100%, 0); 88 | } 89 | } 90 | .slideOutUp { 91 | -webkit-animation-name: slideOutUp; 92 | animation-name: slideOutUp; 93 | } -------------------------------------------------------------------------------- /src/style/components/box/box.scss: -------------------------------------------------------------------------------- 1 | @import "./message.scss"; 2 | @import "./modal.scss"; 3 | @import "./notice.scss"; -------------------------------------------------------------------------------- /src/style/components/box/message.scss: -------------------------------------------------------------------------------- 1 | $prefixCls: $lib-name + "-message"; 2 | @keyframes #{$animation-prefix}move-in { 3 | 0% { 4 | transform: translateY(-100%); 5 | opacity: 0; 6 | } 7 | 100% { 8 | transform: translateY(0%); 9 | opacity: 1; 10 | } 11 | } 12 | 13 | .#{$animation-prefix}move-in-enter-active { 14 | animation: #{$animation-prefix}move-in $animation-time; 15 | } 16 | .#{$animation-prefix}move-in-leave-active { 17 | animation: #{$animation-prefix}move-in $animation-time reverse; 18 | } 19 | 20 | .#{$prefixCls}-wrapper { 21 | position: fixed; 22 | z-index: 120; 23 | .#{$prefixCls}-box { 24 | margin-bottom: 10px; 25 | .#{$prefixCls}-box-content { 26 | display: inline-block; 27 | transform: translateX(-50%); 28 | padding: 10px 16px; 29 | font-size: 14px; 30 | color: $title-color-light; 31 | background-color: $background-color-base; 32 | border-radius: 4px; 33 | border: 1px solid $border-color-base; 34 | box-sizing: border-box; 35 | box-shadow: $box-shadow-base; 36 | .#{$prefixCls}-box-content-text { 37 | display: inline-block; 38 | i { 39 | display: inline-block; 40 | line-height: 1; 41 | margin-right: 8px; 42 | font-size: 14px; 43 | &.info { 44 | color: $info-color; 45 | } 46 | &.success { 47 | color: $success-color; 48 | } 49 | &.warning { 50 | color: $warning-color; 51 | } 52 | &.error { 53 | color: $error-color; 54 | } 55 | &.loading { 56 | color: $sub-text-color-light; 57 | } 58 | } 59 | } 60 | .#{$prefixCls}-box-close { 61 | display: inline-block; 62 | margin-left: 20px; 63 | color: $sub-text-color-light; 64 | cursor: pointer; 65 | i { 66 | font-size: 12px; 67 | &:hover { 68 | color: $primary-color; 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | &.#{$prefixCls}-fixed { 76 | .#{$prefixCls}-box { 77 | position: absolute; 78 | top: 0; 79 | white-space: nowrap; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/style/components/box/modal.scss: -------------------------------------------------------------------------------- 1 | $prefixCls: $lib-name + "-modal"; 2 | 3 | @keyframes modal-down { 4 | 0% { 5 | opacity: 0; 6 | } 7 | 100% { 8 | opacity: 1; 9 | } 10 | } 11 | @keyframes modal-scale { 12 | 0% { 13 | transform: translate(-50%, -50%) scale(0.8); 14 | } 15 | 100% { 16 | transform: translate(-50%, -50%) scale(1); 17 | } 18 | } 19 | 20 | .#{$animation-prefix}modal-down-enter-active { 21 | animation: modal-down $animation-time; 22 | .#{$prefixCls}-box-content-wrapper { 23 | animation: modal-scale $animation-time; 24 | } 25 | } 26 | .#{$animation-prefix}modal-down-leave-active { 27 | animation: modal-down $animation-time reverse; 28 | .#{$prefixCls}-box-content-wrapper { 29 | animation: modal-scale $animation-time reverse; 30 | } 31 | } 32 | 33 | .#{$prefixCls}-box { 34 | position: fixed; 35 | top: 0; 36 | left: 0; 37 | right: 0; 38 | bottom: 0; 39 | z-index: 120; 40 | .msk { 41 | background-color: $background-color-dark; 42 | position: absolute; 43 | top: 0; 44 | bottom: 0; 45 | left: 0; 46 | right: 0; 47 | } 48 | .#{$prefixCls}-box-content-wrapper { 49 | position: absolute; 50 | left: 50%; 51 | top: 50%; 52 | transform: translate(-50%, -50%); 53 | box-shadow: $box-shadow-base; 54 | .#{$prefixCls}-box-close { 55 | position: absolute; 56 | right: 16px; 57 | top: 10px; 58 | color: $sub-text-color-light; 59 | cursor: pointer; 60 | &:hover { 61 | color: $primary-color; 62 | } 63 | .ans-icon-close { 64 | font-size: 12px; 65 | } 66 | } 67 | .#{$prefixCls}-box-content { 68 | background-color: $background-color-base; 69 | border: 0; 70 | border-radius: 4px; 71 | .#{$prefixCls}-content-header { 72 | .#{$prefixCls}-header-inner { 73 | height: 55px; 74 | padding: 0 25px; 75 | font-size: 16px; 76 | line-height: 55px; 77 | color: $title-color-light; 78 | font-weight: 500; 79 | overflow: hidden; 80 | text-overflow: ellipsis; 81 | white-space: nowrap; 82 | box-sizing: border-box; 83 | border-bottom: 1px solid $border-color-base; 84 | } 85 | } 86 | .#{$prefixCls}-content-body { 87 | padding: 25px; 88 | font-size: 14px; 89 | line-height: 1.5; 90 | color: $content-color-light; 91 | box-sizing: border-box; 92 | } 93 | .#{$prefixCls}-content-footer { 94 | border-top: 1px solid $border-color-base; 95 | padding: 10px 25px; 96 | text-align: right; 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/style/components/button/button.scss: -------------------------------------------------------------------------------- 1 | @import "./mixin.scss"; 2 | 3 | $btn-prefix-cls: #{$lib-name}-btn; 4 | $btn-padding-base: 8px 16px; 5 | $btn-padding-large: 11px 20px; 6 | $btn-padding-small: 6px 12px; 7 | $btn-padding-xsmall: 5px 10px; 8 | $btn-circle-size: 64px; 9 | $line-height-base: 1.5; 10 | 11 | .#{$btn-prefix-cls} { 12 | @include btn-common(); 13 | 14 | &-long { 15 | width: 100%; 16 | } 17 | 18 | & > .#{$lib-name}-icon + span, 19 | & > span + .#{$lib-name}-icon { 20 | margin-left: 10px; 21 | display: inline-block; 22 | } 23 | 24 | // type 25 | &-primary { 26 | @include dark-bg-btn(); 27 | } 28 | 29 | &-ghost { 30 | @include white-bg-btn($title-color-light); 31 | } 32 | 33 | &-dashed { 34 | @include white-bg-btn($title-color-light); 35 | border-style: dashed; 36 | } 37 | 38 | &-text { 39 | @include white-bg-btn($title-color-light); 40 | border: transparent; 41 | 42 | &:active, 43 | &.active { 44 | border: transparent; 45 | } 46 | } 47 | 48 | &-success { 49 | @include dark-bg-btn($success-color); 50 | } 51 | 52 | &-warning { 53 | @include dark-bg-btn($warning-color); 54 | } 55 | 56 | &-error { 57 | @include dark-bg-btn($error-color); 58 | } 59 | 60 | &-info { 61 | @include dark-bg-btn($info-color); 62 | } 63 | 64 | // shape 65 | &-circle { 66 | border-radius: $btn-circle-size; 67 | &.#{$btn-prefix-cls}-icon-only { 68 | @include square(32px); 69 | @include button-size(0, 14px); 70 | border-radius: 50%; 71 | 72 | &.#{$btn-prefix-cls}-large { 73 | @include square(40px); 74 | @include button-size(0, 16px); 75 | } 76 | 77 | &.#{$btn-prefix-cls}-small { 78 | @include square(28px); 79 | @include button-size(0, 12px); 80 | } 81 | 82 | &.#{$btn-prefix-cls}-xsmall { 83 | @include square(26px); 84 | @include button-size(0, 12px); 85 | } 86 | } 87 | } 88 | 89 | // loading mask 90 | &:before { 91 | position: absolute; 92 | top: -1px; 93 | left: -1px; 94 | bottom: -1px; 95 | right: -1px; 96 | background: $background-color-base; 97 | opacity: 0.35; 98 | content: ""; 99 | border-radius: inherit; 100 | z-index: 1; 101 | transition: opacity $transition-time; 102 | pointer-events: none; 103 | display: none; 104 | } 105 | 106 | &-loading { 107 | position: relative; 108 | pointer-events: none; 109 | &:before { 110 | display: block; 111 | } 112 | } 113 | 114 | // group 115 | &-group { 116 | @include btn-group($btn-prefix-cls); 117 | } 118 | 119 | &-group-vertical { 120 | @include btn-group-vertical($btn-prefix-cls); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/style/components/form/form.scss: -------------------------------------------------------------------------------- 1 | $form-name: $lib-name + "-form"; 2 | $form-item-name: $lib-name + "-form-item"; 3 | 4 | .#{$form-name} { 5 | .#{$form-item-name} { 6 | display: flex; 7 | align-items: flex-start; 8 | margin-bottom: 10px; 9 | &::after { 10 | display: block; 11 | clear: both; 12 | content: ""; 13 | } 14 | .#{$form-item-name}-label { 15 | text-align: right; 16 | vertical-align: middle; 17 | box-sizing: border-box; 18 | font-size: 14px; 19 | color: $sub-text-color-light; 20 | height: 32px; 21 | line-height: 32px; 22 | padding-right: 16px; 23 | } 24 | .#{$form-item-name}-content { 25 | .#{$lib-name}-radio-group, 26 | .#{$lib-name}-checkbox-group { 27 | line-height: 32px; 28 | } 29 | .#{$form-item-name}-error-tip { 30 | margin: 6px 0 0; 31 | font-size: 12px; 32 | color: $error-color; 33 | } 34 | &.form-item-error { 35 | .input-element.no-border { 36 | border-bottom-color: $error-color; 37 | } 38 | .input-element:not(.no-border) { 39 | border-color: $error-color; 40 | } 41 | } 42 | } 43 | } 44 | &.vertical-form-item { 45 | .#{$form-item-name} { 46 | flex-direction: column; 47 | .#{$form-item-name}-label { 48 | text-align: left; 49 | font-size: 12px; 50 | height: 20px; 51 | line-height: 20px; 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/style/components/index.scss: -------------------------------------------------------------------------------- 1 | @import "./switch/switch.scss"; 2 | @import "./pagination/pagination.scss"; 3 | @import "./tooltip/tooltip.scss"; 4 | @import "./spin/spin.scss"; 5 | @import "./radio/radio.scss"; 6 | @import "./checkbox/checkbox.scss"; 7 | @import "./button/button.scss"; 8 | @import "./poptip/poptip.scss"; 9 | @import "./progress/progress.scss"; 10 | @import "./select/select.scss"; 11 | @import "./box/box.scss"; 12 | @import "./datepicker/datepicker.scss"; 13 | @import "./input/input.scss"; 14 | @import "./cascader/cascader.scss"; 15 | @import "./drawer/drawer.scss"; 16 | @import "./table/table.scss"; 17 | @import "./scroller/scroller.scss"; 18 | @import "./form/form.scss"; -------------------------------------------------------------------------------- /src/style/components/poptip/poptip.scss: -------------------------------------------------------------------------------- 1 | .#{$lib-name}-poptip { 2 | position: absolute; 3 | background: $background-color-base; 4 | min-width: 150px; 5 | border-radius: $border-radius-base; 6 | border: 1px solid $border-color-base; 7 | padding: 12px; 8 | z-index: 500; 9 | color: $content-color-light; 10 | line-height: 1.5; 11 | text-align: justify; 12 | box-shadow: $box-shadow-base; 13 | 14 | &:focus:active, 15 | &:focus { 16 | outline-width: 0; 17 | } 18 | 19 | &--plain { 20 | padding: 12px 16px; 21 | } 22 | 23 | &__title { 24 | color: $title-color-light; 25 | font-size: 14px; 26 | line-height: 1; 27 | margin-bottom: 12px; 28 | } 29 | 30 | &__reference { 31 | &:focus:not(.focusing), 32 | &:focus:hover { 33 | outline-width: 0; 34 | } 35 | } 36 | 37 | &__content { 38 | font-size: 14px; 39 | color: $content-color-light; 40 | text-align: justify; 41 | } 42 | 43 | &__footer { 44 | text-align: right; 45 | margin-top: 10px; 46 | button { 47 | &:first-child { 48 | margin-right: 15px; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/style/components/progress/progress.scss: -------------------------------------------------------------------------------- 1 | .#{$lib-name}-progress { 2 | display: flex; 3 | align-items: center; 4 | .progress-bar { 5 | flex: 1; 6 | background: $background-color-disabled; 7 | .progress-percentage { 8 | position: relative; 9 | height: 100%; 10 | background: $primary-color; 11 | transition: width $transition-time, background $transition-time; 12 | &.success { 13 | background: $success-color; 14 | } 15 | &.exception { 16 | background: $error-color; 17 | } 18 | .progress-inner { 19 | position: absolute; 20 | z-index: 1; 21 | right: 10px; 22 | height: 100%; 23 | display: flex; 24 | align-items: center; 25 | .inner-text { 26 | font-size: 14px; 27 | color: $title-color-dark; 28 | } 29 | } 30 | } 31 | } 32 | .progress-right { 33 | padding-left: 8px; 34 | width: 50px; 35 | .right-text { 36 | font-size: 14px; 37 | color: $sub-text-color-light; 38 | } 39 | .success { 40 | font-size: 14px; 41 | color: $success-color; 42 | } 43 | .exception { 44 | font-size: 14px; 45 | color: $error-color; 46 | } 47 | } 48 | .progress-ring { 49 | position: relative; 50 | .progress-background { 51 | stroke: $background-color-disabled; 52 | fill: transparent; 53 | } 54 | .progress-percentage { 55 | stroke: $primary-color; 56 | fill: transparent; 57 | transition: stroke $transition-time, stroke-dashoffset $transition-time; 58 | &.success { 59 | stroke: $success-color; 60 | } 61 | &.exception { 62 | stroke: $error-color; 63 | } 64 | } 65 | .progress-center { 66 | position: absolute; 67 | z-index: 1; 68 | top: 0; 69 | left: 0; 70 | display: flex; 71 | justify-content: center; 72 | align-items: center; 73 | width: 100%; 74 | height: 100%; 75 | .progress-inner { 76 | font-size: 16px; 77 | color: $content-color-light; 78 | .success { 79 | font-size: 16px; 80 | color: $success-color; 81 | } 82 | .exception { 83 | font-size: 16px; 84 | color: $error-color; 85 | } 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/style/components/scroller/scroller.scss: -------------------------------------------------------------------------------- 1 | $scrollbar-width: 4px; 2 | $scrollbar-margin: 2px; 3 | 4 | .#{$lib-name}-scroller { 5 | position: relative; 6 | overflow: hidden; 7 | // fix inline-block gap 8 | line-height: 1px; 9 | .scroll-area-wrapper { 10 | position: relative; 11 | top: 0; 12 | left: 0; 13 | display: inline-block; 14 | &.scroll-transition { 15 | transition: transform $transition-time; 16 | } 17 | } 18 | .#{$lib-name}-v-scrollbar, 19 | .#{$lib-name}-h-scrollbar { 20 | position: absolute; 21 | z-index: 1; 22 | box-sizing: content-box; 23 | .scrollbar-thumb { 24 | position: relative; 25 | border-radius: $scrollbar-width; 26 | background: $border-color-base; 27 | transition: background-color $transition-time; 28 | &.scroll-transition { 29 | transition: transform $transition-time; 30 | } 31 | cursor: pointer; 32 | &:hover { 33 | background: darken($border-color-base, 10); 34 | } 35 | } 36 | } 37 | .#{$lib-name}-v-scrollbar { 38 | top: 0; 39 | right: 0; 40 | width: $scrollbar-width; 41 | height: 100%; 42 | padding: 0 $scrollbar-margin; 43 | .scrollbar-thumb { 44 | top: 0; 45 | width: 100%; 46 | } 47 | } 48 | .#{$lib-name}-h-scrollbar { 49 | left: 0; 50 | bottom: 0; 51 | width: 100%; 52 | height: $scrollbar-width; 53 | padding: $scrollbar-margin 0; 54 | .scrollbar-thumb { 55 | left: 0; 56 | height: 100%; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/style/components/spin/spin.scss: -------------------------------------------------------------------------------- 1 | .#{$lib-name}-spin { 2 | position: absolute; 3 | z-index: 999; 4 | margin: 0; 5 | top: 0; 6 | right: 0; 7 | bottom: 0; 8 | left: 0; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | background: rgba($background-color-base, 0.85); 13 | .spin-center-container { 14 | text-align: center; 15 | color: $primary-color; 16 | .loading-text { 17 | font-size: 16px; 18 | line-height: 30px; 19 | } 20 | } 21 | &.is-fullscreen { 22 | position: fixed; 23 | } 24 | } 25 | 26 | .spin-relative-parent { 27 | position: relative !important; 28 | } 29 | 30 | .spin-lock-overflow { 31 | overflow: hidden !important; 32 | } 33 | 34 | @keyframes rotating { 35 | 0% { 36 | transform: rotate(0deg); 37 | } 38 | 100% { 39 | transform: rotate(1turn); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/style/components/tooltip/tooltip.scss: -------------------------------------------------------------------------------- 1 | $tooltip-wrapper-name: $lib-name + "-tooltip"; 2 | 3 | $tooltip-dark-bg-color: rgba($title-color-light, 0.95); 4 | $tooltip-dark-text-color: $background-color-disabled; 5 | 6 | $tooltip-light-bg-color: $background-color-base; 7 | $tooltip-light-border-color: $border-color-base; 8 | $tooltip-light-text-color: $title-color-light; 9 | 10 | .#{$tooltip-wrapper-name} { 11 | padding: 8px; 12 | border-radius: 4px; 13 | &.dark { 14 | background: $tooltip-dark-bg-color; 15 | box-shadow: $box-shadow-base; 16 | .tooltip-content { 17 | color: $tooltip-dark-text-color; 18 | } 19 | } 20 | &.light { 21 | background: $tooltip-light-bg-color; 22 | border: 1px solid $tooltip-light-border-color; 23 | box-shadow: $box-shadow-base; 24 | .tooltip-content { 25 | color: $tooltip-light-text-color; 26 | } 27 | } 28 | .tooltip-content { 29 | font-size: 12px; 30 | line-height: 1; 31 | text-align: justify; 32 | } 33 | &.large { 34 | padding: 12px 16px; 35 | border-radius: 6px; 36 | .tooltip-content { 37 | font-size: 13px; 38 | line-height: 21px; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/style/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/src/style/font/iconfont.eot -------------------------------------------------------------------------------- /src/style/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/src/style/font/iconfont.ttf -------------------------------------------------------------------------------- /src/style/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analysys/ans-ui/a3845f638bd5497b06c9456cfee36ee2c5bea863/src/style/font/iconfont.woff -------------------------------------------------------------------------------- /src/style/index.scss: -------------------------------------------------------------------------------- 1 | @import "./vars.scss"; 2 | @import "./animation/index.scss"; 3 | @import "./font.scss"; 4 | @import "./common.scss"; 5 | @import "./components/index.scss"; -------------------------------------------------------------------------------- /src/style/vars.scss: -------------------------------------------------------------------------------- 1 | // 库名 2 | $lib-name: "ans"; 3 | 4 | // 字体路径 5 | $icon-path: "./font"; 6 | 7 | // 主要颜色 8 | $primary-color: #1489e2 !default; 9 | $primary-color-hover: #1799fc !default; 10 | $primary-color-active: #127ac9 !default; 11 | $sub-color: #ff8c00 !default; 12 | $sub-color-hover: #ff981a !default; 13 | $sub-color-active: #ef6c00 !default; 14 | $info-color: #1489e2 !default; 15 | $success-color: #4caf50 !default; 16 | $warning-color: #ffc107 !default; 17 | $error-color: #f14343 !default; 18 | 19 | // 浅色背景文本颜色 20 | $title-color-light: #252d39 !default; 21 | $content-color-light: #4c6072 !default; 22 | $sub-text-color-light: #6d859e !default; 23 | $disabled-text-color-light: #c5ced8 !default; 24 | 25 | // 深色背景文本颜色 26 | $title-color-dark: #fff !default; 27 | $content-color-dark: #eee !default; 28 | $sub-text-color-dark: #c5ced8 !default; 29 | $disabled-text-color-dark: #888 !default; 30 | $bg-color-in-dark: #4c6072; 31 | 32 | // radius 33 | $border-radius-base: 4px; 34 | 35 | // 边框颜色 36 | $border-color-base: #e4eaf1 !default; 37 | $box-shadow-base: 0 2px 8px 0 rgba(0,0,0,0.14) !default; 38 | 39 | // 背景色 40 | $background-color-base: #fff; 41 | $background-color-disabled: #ecf3f8; 42 | $background-color-dark: rgba(0, 0, 0, 0.6); 43 | 44 | // 动画 45 | $animation-prefix: "x-ani-" !default; 46 | $animation-time: .3s; 47 | $transition-time: .2s; 48 | $ease-in-out: ease-in-out; -------------------------------------------------------------------------------- /src/util/assist.js: -------------------------------------------------------------------------------- 1 | // base on iview assist.js 2 | 3 | // Find components upward 4 | export function findComponentUpward (context, componentName, componentNames) { 5 | if (typeof componentName === 'string') { 6 | componentNames = [componentName] 7 | } else { 8 | componentNames = componentName 9 | } 10 | 11 | let parent = context.$parent 12 | let name = parent.$options.name 13 | while (parent && (!name || componentNames.indexOf(name) < 0)) { 14 | parent = parent.$parent 15 | if (parent) name = parent.$options.name 16 | } 17 | return parent 18 | } 19 | 20 | // Find component downward 21 | export function findComponentDownward (context, componentName) { 22 | const childrens = context.$children 23 | let children = null 24 | 25 | if (childrens.length) { 26 | for (const child of childrens) { 27 | const name = child.$options.name 28 | if (name === componentName) { 29 | children = child 30 | break 31 | } else { 32 | children = findComponentDownward(child, componentName) 33 | if (children) break 34 | } 35 | } 36 | } 37 | return children 38 | } 39 | 40 | // Find components downward 41 | export function findComponentsDownward (context, componentName) { 42 | return context.$children.reduce((components, child) => { 43 | if (child.$options.name === componentName) components.push(child) 44 | const foundChilds = findComponentsDownward(child, componentName) 45 | return components.concat(foundChilds) 46 | }, []) 47 | } 48 | 49 | // Find components upward 50 | export function findComponentsUpward (context, componentName) { 51 | const parents = [] 52 | const parent = context.$parent 53 | if (parent) { 54 | if (parent.$options.name === componentName) parents.push(parent) 55 | return parents.concat(findComponentsUpward(parent, componentName)) 56 | } else { 57 | return [] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/util/constants.js: -------------------------------------------------------------------------------- 1 | export const LIB_NAME = 'ans' 2 | export const ANIMATION_PREFIX = 'x-ani-' 3 | -------------------------------------------------------------------------------- /src/util/customRenderer.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'CustomRenderer', 3 | functional: true, 4 | props: { 5 | render: Function, 6 | params: { 7 | default () { 8 | return {} 9 | } 10 | } 11 | }, 12 | render: (h, ctx) => { 13 | return ctx.props.render(h, ctx.params) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/util/directives/clickOutside.js: -------------------------------------------------------------------------------- 1 | import { on } from '../event' 2 | 3 | const nodeList = [] 4 | const ctx = '@@clickoutsideContext' 5 | 6 | let startClick 7 | let seed = 0 8 | 9 | on(document, 'mousedown', e => (startClick = e)) 10 | 11 | on(document, 'mouseup', e => { 12 | nodeList.forEach(node => node[ctx].documentHandler(e, startClick)) 13 | }) 14 | 15 | function createDocumentHandler (el, binding, vnode) { 16 | return function (mouseup = {}, mousedown = {}) { 17 | if (!vnode || 18 | !vnode.context || 19 | !mouseup.target || 20 | !mousedown.target || 21 | el.contains(mouseup.target) || 22 | el.contains(mousedown.target) || 23 | el === mouseup.target) return 24 | 25 | if (binding.expression && 26 | el[ctx].methodName && 27 | vnode.context[el[ctx].methodName]) { 28 | vnode.context[el[ctx].methodName]() 29 | } else { 30 | el[ctx].bindingFn && el[ctx].bindingFn() 31 | } 32 | } 33 | } 34 | 35 | export default { 36 | bind (el, binding, vnode) { 37 | nodeList.push(el) 38 | const id = seed++ 39 | el[ctx] = { 40 | id, 41 | documentHandler: createDocumentHandler(el, binding, vnode), 42 | methodName: binding.expression, 43 | bindingFn: binding.value 44 | } 45 | }, 46 | 47 | update (el, binding, vnode) { 48 | el[ctx].documentHandler = createDocumentHandler(el, binding, vnode) 49 | el[ctx].methodName = binding.expression 50 | el[ctx].bindingFn = binding.value 51 | }, 52 | 53 | unbind (el) { 54 | const len = nodeList.length 55 | for (let i = 0; i < len; i++) { 56 | if (nodeList[i][ctx].id === el[ctx].id) { 57 | nodeList.splice(i, 1) 58 | break 59 | } 60 | } 61 | delete el[ctx] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/util/directives/index.js: -------------------------------------------------------------------------------- 1 | import clickOutside from './clickOutside' 2 | import mousewheel from './mousewheel' 3 | 4 | export { 5 | clickOutside, 6 | mousewheel 7 | } 8 | -------------------------------------------------------------------------------- /src/util/directives/mousewheel.js: -------------------------------------------------------------------------------- 1 | import normalizeWheel from 'normalize-wheel' 2 | import { hasClass } from '../../util' 3 | 4 | const handler = function (event) { 5 | let scrollDom = null 6 | let parent = event.target.parentNode 7 | while (parent) { 8 | if (hasClass(parent, 'ans-scroller')) { 9 | scrollDom = parent 10 | break 11 | } else { 12 | parent = parent.parentNode 13 | } 14 | } 15 | if (scrollDom) { 16 | const callback = scrollDom.__wheel_callback 17 | const normalized = normalizeWheel(event) 18 | callback && callback.apply(this, [event, normalized]) 19 | } 20 | } 21 | 22 | const eventType = normalizeWheel.getEventType() 23 | 24 | const mousewheel = function (element, callback) { 25 | if (element && element.addEventListener) { 26 | element.__wheel_callback = callback 27 | element.addEventListener(eventType, handler) 28 | } 29 | } 30 | 31 | export default { 32 | bind (el, binding) { 33 | mousewheel(el, binding.value) 34 | }, 35 | unbind (el) { 36 | el.removeEventListener(eventType, el.__wheel_callback) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/util/dom/animatedScroll.js: -------------------------------------------------------------------------------- 1 | const requestAnimFrame = (function () { 2 | return window.requestAnimationFrame || 3 | window.webkitRequestAnimationFrame || 4 | window.mozRequestAnimationFrame || 5 | function (callback) { 6 | window.setTimeout(callback, 1000 / 60) 7 | } 8 | })() 9 | 10 | const linear = function (t, b, c, d) { 11 | return t / d * c + b 12 | } 13 | 14 | const scrollBy = function (element, change, vertical, duration, callback) { 15 | const start = vertical ? element.scrollTop : element.scrollLeft 16 | let to = start + change 17 | if (element.__scroll__controller && element.__scroll__controller.isAnimating()) { 18 | to = element.__scroll__controller.to + change 19 | element.__scroll__controller.stop() 20 | } 21 | 22 | const controller = _scrollTo(element, start, to, vertical, duration, callback) 23 | element.__scroll__controller = controller 24 | return controller 25 | } 26 | 27 | const scrollTo = function (element, to, vertical, duration, callback) { 28 | const start = vertical ? element.scrollTop : element.scrollLeft 29 | if (element.__scroll__controller && element.__scroll__controller.isAnimating()) { 30 | element.__scroll__controller.stop() 31 | } 32 | 33 | const controller = _scrollTo(element, start, to, vertical, duration, callback) 34 | element.__scroll__controller = controller 35 | return controller 36 | } 37 | 38 | function _scrollTo (element, start, to, vertical, duration = 200, callback) { 39 | const change = to - start 40 | const animationStart = +new Date() 41 | let animating = true 42 | let lastValue = null 43 | 44 | const animateScroll = function () { 45 | if (!animating) { 46 | return 47 | } 48 | requestAnimFrame(animateScroll) 49 | const now = +new Date() 50 | const val = Math.floor(linear(now - animationStart, start, change, duration)) 51 | if (lastValue) { 52 | const targetValue = vertical ? element.scrollTop : element.scrollLeft 53 | if (lastValue === targetValue) { 54 | lastValue = val 55 | vertical ? (element.scrollTop = val) : (element.scrollLeft = val) 56 | } else { 57 | animating = false 58 | } 59 | } else { 60 | lastValue = val 61 | vertical ? (element.scrollTop = val) : (element.scrollLeft = val) 62 | } 63 | if (now > animationStart + duration) { 64 | vertical ? (element.scrollTop = to) : (element.scrollLeft = to) 65 | animating = false 66 | if (callback) { callback() } 67 | } 68 | } 69 | requestAnimFrame(animateScroll) 70 | 71 | const maxScroll = vertical 72 | ? element.scrollHeight - element.offsetHeight 73 | : element.scrollWidth - element.offsetWidth 74 | const validTo = Math.min(Math.max(to, 0), maxScroll) 75 | 76 | return { 77 | to: validTo, 78 | isAnimating () { 79 | return animating 80 | }, 81 | stop () { 82 | animating = false 83 | } 84 | } 85 | } 86 | 87 | export default { 88 | scrollTo, 89 | scrollBy 90 | } 91 | -------------------------------------------------------------------------------- /src/util/dom/class.js: -------------------------------------------------------------------------------- 1 | /* istanbul ignore next */ 2 | export function hasClass (el, cls) { 3 | if (!el || !cls) return false 4 | if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.') 5 | if (el.classList) { 6 | return el.classList.contains(cls) 7 | } else { 8 | return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1 9 | } 10 | } 11 | 12 | /* istanbul ignore next */ 13 | export function addClass (el, cls) { 14 | if (!el) return 15 | let curClass = el.className 16 | const classes = (cls || '').split(' ') 17 | 18 | for (let i = 0, j = classes.length; i < j; i++) { 19 | const clsName = classes[i] 20 | if (!clsName) continue 21 | 22 | if (el.classList) { 23 | el.classList.add(clsName) 24 | } else { 25 | if (!hasClass(el, clsName)) { 26 | curClass += ' ' + clsName 27 | } 28 | } 29 | } 30 | if (!el.classList) { 31 | el.className = curClass 32 | } 33 | } 34 | 35 | /* istanbul ignore next */ 36 | export function removeClass (el, cls) { 37 | if (!el || !cls) return 38 | const classes = cls.split(' ') 39 | let curClass = ' ' + el.className + ' ' 40 | 41 | for (let i = 0, j = classes.length; i < j; i++) { 42 | const clsName = classes[i] 43 | if (!clsName) continue 44 | 45 | if (el.classList) { 46 | el.classList.remove(clsName) 47 | } else { 48 | if (hasClass(el, clsName)) { 49 | curClass = curClass.replace(' ' + clsName + ' ', ' ') 50 | } 51 | } 52 | } 53 | if (!el.classList) { 54 | el.className = curClass.trim() 55 | } 56 | } 57 | 58 | const SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g 59 | const MOZ_HACK_REGEXP = /^moz([A-Z])/ 60 | 61 | const camelCase = function (name) { 62 | return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) { 63 | return offset ? letter.toUpperCase() : letter 64 | }).replace(MOZ_HACK_REGEXP, 'Moz$1') 65 | } 66 | 67 | export function getStyle (element, styleName) { 68 | if (!element || !styleName) return null 69 | styleName = camelCase(styleName) 70 | if (styleName === 'float') { 71 | styleName = 'cssFloat' 72 | } 73 | try { 74 | var computed = document.defaultView.getComputedStyle(element, '') 75 | return element.style[styleName] || computed ? computed[styleName] : null 76 | } catch (e) { 77 | return element.style[styleName] 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/util/dom/index.js: -------------------------------------------------------------------------------- 1 | import scrollIntoView from './scrollIntoView' 2 | import scrollbarWidth from './scrollbarWidth' 3 | import animatedScroll from './animatedScroll' 4 | import limitedLoop from './limitedLoop' 5 | 6 | export * from './class' 7 | export * from './style' 8 | 9 | export { 10 | scrollIntoView, 11 | scrollbarWidth, 12 | animatedScroll, 13 | limitedLoop 14 | } 15 | -------------------------------------------------------------------------------- /src/util/dom/limitedLoop.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | const TIME_LIMIT = 500 4 | 5 | const _nextTick = function (func, thisArg, ...args) { 6 | if (!func || typeof func !== 'function') return 7 | if (!func.startTime) { 8 | func.startTime = new Date() 9 | } 10 | if (new Date() - func.startTime > TIME_LIMIT) { 11 | func.startTime = null 12 | } else { 13 | Vue.nextTick(() => { 14 | func.apply(thisArg, args) 15 | }) 16 | } 17 | } 18 | 19 | const _setTimeout = function (func, thisArg, timeout, ...args) { 20 | if (!func || typeof func !== 'function') return 21 | if (!func.startTime) { 22 | func.startTime = new Date() 23 | } 24 | if (new Date() - func.startTime > TIME_LIMIT) { 25 | func.startTime = null 26 | } else { 27 | setTimeout(() => { 28 | func.apply(thisArg, args) 29 | }, timeout) 30 | } 31 | } 32 | 33 | export default { 34 | nextTick: _nextTick, 35 | setTimeout: _setTimeout 36 | } 37 | -------------------------------------------------------------------------------- /src/util/dom/scrollIntoView.js: -------------------------------------------------------------------------------- 1 | export default function scrollIntoView (container, selected) { 2 | if (!selected) { 3 | container.scrollTop = 0 4 | return 5 | } 6 | 7 | const top = selected.offsetTop 8 | const bottom = selected.offsetTop + selected.offsetHeight 9 | const viewRectTop = container.scrollTop 10 | const viewRectBottom = viewRectTop + container.clientHeight 11 | 12 | if (top < viewRectTop) { 13 | container.scrollTop = top 14 | } else if (bottom > viewRectBottom) { 15 | container.scrollTop = bottom - container.clientHeight 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/util/dom/scrollbarWidth.js: -------------------------------------------------------------------------------- 1 | let scrollbarWidth 2 | 3 | export default function () { 4 | if (scrollbarWidth !== undefined) return scrollbarWidth 5 | 6 | const outer = document.createElement('div') 7 | outer.style.visibility = 'hidden' 8 | outer.style.width = '100px' 9 | outer.style.position = 'absolute' 10 | outer.style.top = '-9999px' 11 | document.body.appendChild(outer) 12 | 13 | const widthNoScroll = outer.offsetWidth 14 | outer.style.overflow = 'scroll' 15 | 16 | const inner = document.createElement('div') 17 | inner.style.width = '100%' 18 | outer.appendChild(inner) 19 | 20 | const widthWithScroll = inner.offsetWidth 21 | outer.parentNode.removeChild(outer) 22 | scrollbarWidth = widthNoScroll - widthWithScroll 23 | 24 | return scrollbarWidth 25 | } 26 | -------------------------------------------------------------------------------- /src/util/dom/style.js: -------------------------------------------------------------------------------- 1 | const formatSize = (prop) => { 2 | const propType = typeof prop 3 | if (propType === 'number') { 4 | return prop + 'px' 5 | } 6 | if (propType === 'string') { 7 | if (/^\d+$/.test(prop)) return parseInt(prop, 10) + 'px' 8 | return prop 9 | } 10 | return null 11 | } 12 | 13 | export { 14 | formatSize 15 | } 16 | -------------------------------------------------------------------------------- /src/util/event.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const on = (el, event, handler) => { 4 | if (el && event && handler) { 5 | el.addEventListener(event, handler, false) 6 | } 7 | } 8 | 9 | const off = (el, event, handler) => { 10 | if (el && event && handler) { 11 | el.removeEventListener(event, handler, false) 12 | } 13 | } 14 | 15 | export { 16 | on, 17 | off 18 | } 19 | -------------------------------------------------------------------------------- /src/util/index.js: -------------------------------------------------------------------------------- 1 | import xCuctomRender from './customRenderer.js' 2 | 3 | export { 4 | xCuctomRender 5 | } 6 | 7 | export * from './directives' 8 | export * from './dom' 9 | export * from './mixins' 10 | export * from './assist' 11 | export * from './constants' 12 | export * from './event' 13 | export * from './lang' 14 | -------------------------------------------------------------------------------- /src/util/lang.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * A simple uuid generator, support prefix and template pattern. 5 | * 6 | * @example 7 | * 8 | * uuid('v-') // -> v-xxx 9 | * uuid('v-ani-%{s}-translate') // -> v-ani-xxx 10 | */ 11 | function uuid (prefix) { 12 | var id = Math.floor(Math.random() * 10000).toString(36) 13 | return prefix ? ( 14 | ~prefix.indexOf('%{s}') ? ( 15 | prefix.replace(/%\{s\}/g, id) 16 | ) : (prefix + id) 17 | ) : id 18 | } 19 | 20 | const getValueByPath = (model, path) => { 21 | if (!path || !model) return '' 22 | if (path.indexOf('.') < 0) { 23 | return getArrayValue(model, path) 24 | } 25 | const key = path.split('.') 26 | let current = model 27 | for (let i = 0; i < key.length; i++) { 28 | const currentKey = key[i] 29 | current = getArrayValue(current, currentKey) 30 | } 31 | return current 32 | } 33 | 34 | function getArrayValue (model, key) { 35 | if (key.includes('[')) { 36 | const parts = key.split(/[[\]]/).filter(p => p !== '') 37 | let value = model[parts[0]] 38 | for (const index of parts.slice(1)) { 39 | value = value[index] 40 | } 41 | return value 42 | } else { 43 | return model[key] 44 | } 45 | } 46 | 47 | export { 48 | uuid, 49 | getValueByPath 50 | } 51 | -------------------------------------------------------------------------------- /src/util/mixins/emitter.js: -------------------------------------------------------------------------------- 1 | function broadcast (componentName, eventName, params) { 2 | this.$children.forEach(child => { 3 | var name = child.$options.name 4 | 5 | if (name === componentName) { 6 | child.$emit.apply(child, [eventName].concat(params)) 7 | } else { 8 | broadcast.apply(child, [componentName, eventName].concat(params)) 9 | } 10 | }) 11 | } 12 | 13 | export default { 14 | methods: { 15 | dispatch (componentName, eventName, params) { 16 | var parent = this.$parent 17 | var name = parent.$options.name 18 | 19 | while (parent && (!name || name !== componentName)) { 20 | parent = parent.$parent 21 | 22 | if (parent) { 23 | name = parent.$options.name 24 | } 25 | } 26 | if (parent) { 27 | parent.$emit.apply(parent, [eventName].concat(params)) 28 | } 29 | }, 30 | broadcast (componentName, eventName, params) { 31 | broadcast.call(this, componentName, eventName, params) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/util/mixins/index.js: -------------------------------------------------------------------------------- 1 | import emitter from './emitter' 2 | import Popper from './popper' 3 | import Locale from './locale' 4 | 5 | export { 6 | emitter, 7 | Popper, 8 | Locale 9 | } 10 | -------------------------------------------------------------------------------- /src/util/mixins/locale.js: -------------------------------------------------------------------------------- 1 | import { t } from '../../locale' 2 | 3 | export default { 4 | methods: { 5 | t (...args) { 6 | return t.apply(this, args) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | mocha: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | Vue.config.productionTip = false 3 | 4 | // require all test files (files that ends with .spec.js) 5 | const testsContext = require.context('./specs', true, /\.spec$/) 6 | testsContext.keys().forEach(testsContext) 7 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var webpackConfig = require('../../build/webpack.config.test') 7 | 8 | module.exports = function (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | browsers: ['ChromeHeadless'], 15 | frameworks: ['mocha', 'sinon-chai'], 16 | reporters: ['spec'], 17 | files: ['./index.js'], 18 | preprocessors: { 19 | './index.js': ['webpack', 'sourcemap'] 20 | }, 21 | webpack: webpackConfig, 22 | webpackMiddleware: { 23 | noInfo: true 24 | } 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /test/unit/specs/button.spec.js: -------------------------------------------------------------------------------- 1 | import { createVue, destroyVM } from '../util' 2 | import { expect } from 'chai' 3 | 4 | describe('Button', () => { 5 | let vm 6 | afterEach(() => { 7 | destroyVM(vm) 8 | }) 9 | 10 | it('should render as