├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── README-zh_CN.md
├── README.md
├── build
├── build.js
├── check-versions.js
├── dev-client.js
├── dev-server.js
├── git-release.sh
├── utils.js
├── webpack.base.conf.js
├── webpack.dev.conf.js
├── webpack.prod.conf.js
└── webpack.prod.min.conf.js
├── components
├── alert
│ ├── alert.vue
│ ├── index.js
│ └── style
│ │ └── index.less
├── badge
│ ├── badge.vue
│ ├── index.js
│ └── style
│ │ └── index.less
├── breadcrumb
│ ├── breadcrumb-item.vue
│ ├── breadcrumb.vue
│ ├── index.js
│ └── style
│ │ └── index.less
├── button
│ ├── button-group.vue
│ ├── button.vue
│ ├── index.js
│ └── style
│ │ ├── index.less
│ │ └── mixin.less
├── card
│ ├── card.js
│ ├── index.js
│ └── style
│ │ └── index.less
├── checkbox
│ ├── checkbox-group.vue
│ ├── checkbox.vue
│ ├── index.js
│ ├── store.js
│ └── style
│ │ ├── index.less
│ │ └── mixin.less
├── collapse
│ ├── collapse.vue
│ ├── index.js
│ ├── panel.vue
│ ├── store.js
│ └── style
│ │ └── index.less
├── dropdown
│ ├── dropdown-item.vue
│ ├── dropdown-menu.vue
│ ├── dropdown.vue
│ ├── index.js
│ └── style
│ │ └── index.less
├── grid
│ ├── col.vue
│ ├── index.js
│ ├── row.vue
│ └── style
│ │ ├── index.less
│ │ └── mixin.less
├── icon
│ ├── icon.vue
│ └── index.js
├── index.js
├── input-number
│ ├── index.js
│ ├── input-number.vue
│ └── style
│ │ └── index.less
├── input
│ ├── index.js
│ ├── input.vue
│ └── style
│ │ ├── index.less
│ │ ├── mixin.less
│ │ └── search-input.less
├── menu
│ ├── enum.js
│ ├── index.js
│ ├── menu-item-group.vue
│ ├── menu-item.vue
│ ├── menu.vue
│ ├── mixins.js
│ ├── store.js
│ ├── style
│ │ └── index.less
│ └── sub-menu.vue
├── message
│ ├── index.js
│ ├── message.js
│ ├── node.js
│ ├── nodes.js
│ └── style
│ │ └── index.less
├── mixins
│ ├── popper.js
│ └── tooltip.js
├── modal
│ ├── confirm.js
│ ├── index.js
│ ├── modal.js
│ └── style
│ │ ├── confirm.less
│ │ ├── index.less
│ │ └── modal.less
├── notification
│ ├── index.js
│ ├── node.js
│ ├── nodes.js
│ ├── notification.js
│ └── style
│ │ └── index.less
├── pagination
│ ├── index.js
│ ├── mixins.js
│ ├── options.js
│ ├── pager.js
│ ├── pagination.js
│ ├── simple-pager.js
│ └── style
│ │ └── index.less
├── popconfirm
│ ├── index.js
│ └── popconfirm.js
├── popover
│ ├── index.js
│ ├── popover.js
│ └── style
│ │ └── index.less
├── radio
│ ├── index.js
│ ├── radio-button.vue
│ ├── radio-group.vue
│ ├── radio-mixin.js
│ ├── radio.vue
│ ├── store.js
│ └── style
│ │ └── index.less
├── rate
│ ├── index.js
│ ├── rate.js
│ └── style
│ │ └── index.less
├── select
│ ├── index.js
│ ├── option-group.vue
│ ├── option.vue
│ ├── select.vue
│ └── style
│ │ └── index.less
├── style
│ ├── color
│ │ ├── bezierEasing.less
│ │ ├── colorPalette.less
│ │ ├── colors.less
│ │ └── tinyColor.less
│ ├── core
│ │ ├── base.less
│ │ ├── iconfont.less
│ │ ├── index.less
│ │ ├── motion.less
│ │ ├── motion
│ │ │ ├── fade.less
│ │ │ ├── move.less
│ │ │ ├── other.less
│ │ │ ├── slide.less
│ │ │ ├── swing.less
│ │ │ └── zoom.less
│ │ └── normalize.less
│ ├── index.less
│ ├── mixins
│ │ ├── clearfix.less
│ │ ├── compatibility.less
│ │ ├── iconfont.less
│ │ ├── index.less
│ │ ├── motion.less
│ │ ├── opacity.less
│ │ └── size.less
│ └── themes
│ │ └── default.less
├── switch
│ ├── index.js
│ ├── style
│ │ └── index.less
│ └── switch.vue
├── tabs
│ ├── index.js
│ ├── store.js
│ ├── style
│ │ ├── card-style.less
│ │ └── index.less
│ ├── tab-nav.js
│ ├── tab-pane.js
│ └── tabs.js
├── tag
│ ├── index.js
│ ├── style
│ │ └── index.less
│ └── tag.vue
├── tooltip
│ ├── index.js
│ ├── style
│ │ └── index.less
│ └── tooltip.js
├── transition
│ ├── collapse.js
│ ├── fade.js
│ ├── index.js
│ ├── move-up.js
│ ├── slide-up.js
│ ├── zoom-big-fast.js
│ └── zoom.js
└── utils
│ ├── base-store.js
│ ├── calcTextareaHeight.js
│ ├── clickoutside.js
│ ├── dom.js
│ └── keycode.js
├── config
├── dev.env.js
├── index.js
└── prod.env.js
└── package.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2"],
3 | "plugins": ["transform-vue-jsx"],
4 | "comments": false
5 | }
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | config/*.js
3 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | mocha: true,
7 | es6: true,
8 | },
9 | parser: 'babel-eslint',
10 | parserOptions: {
11 | sourceType: 'module'
12 | },
13 | extends: 'airbnb-base',
14 | // required to lint *.vue files
15 | plugins: [
16 | 'html'
17 | ],
18 | // check if imports actually resolve
19 | 'settings': {
20 | 'import/resolver': {
21 | 'webpack': {
22 | 'config': 'build/webpack.base.conf.js'
23 | }
24 | }
25 | },
26 | // add your custom rules here
27 | 'rules': {
28 | // don't require .vue extension when importing
29 | 'import/extensions': ['error', 'always', {
30 | 'js': 'never',
31 | 'vue': 'never'
32 | }],
33 | // 结尾禁用逗号
34 | 'comma-dangle': ['error', 'never'],
35 | // 结尾禁用分号
36 | 'semi': ['error', 'never'],
37 | // 允许使用一元操作符 ++ 和 --
38 | 'no-plusplus': 'off',
39 | // 可以对函数参数再赋值
40 | 'no-param-reassign': 0,
41 | // allow debugger during development
42 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
43 | // 禁止未使用过的变量,但函数中的参数不检查
44 | 'no-unused-vars': ["error", { "vars": "all", "args": "none" }],
45 | // 允许优先级相同的使用不同的操作符
46 | 'no-mixed-operators': ["error", {"allowSamePrecedence": true}],
47 | // 允许标识符中有悬空下划线
48 | 'no-underscore-dangle': 0
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log
5 | /.idea
6 | /node_modules.zip
7 | build/release.sh
8 |
--------------------------------------------------------------------------------
/README-zh_CN.md:
--------------------------------------------------------------------------------
1 | # Ant Design of Vue
2 |
3 | [](https://www.npmjs.org/package/antv)
4 |
5 | 一套企业级的 UI 设计语言和 Vue 实现。
6 |
7 | [README in English](README.md)
8 |
9 | ## 特性
10 |
11 | - 提炼自企业级中后台产品的交互语言和视觉风格。
12 | - 基于卓越的 [Ant Design](https://ant.design) 实现的高质量 Vue 组件。
13 | - 基于 npm + webpack + babel + [Vue2.0](https://vuejs.org) 的工作流。
14 |
15 | ## 支持环境
16 |
17 | * 现代浏览器和 IE9 及以上。
18 |
19 | ## 安装
20 |
21 | ### 使用 npm 安装
22 |
23 | **我们推荐使用 npm 的方式进行开发**,不仅可在开发环境轻松调试,也可放心地在生产环境打包部署使用,享受整个生态圈和工具链带来的诸多好处。
24 |
25 | ```bash
26 | $ npm install antv --save
27 | ```
28 |
29 | 如果你的网络环境不佳,推荐使用 [cnpm](https://github.com/cnpm/cnpm)。
30 |
31 | ### 浏览器引入
32 |
33 | 在浏览器中使用 `script` 和 `link` 标签直接引入文件,并使用全局变量 `antv`。
34 |
35 | 我们在 npm 发布包内的 `antv/dist` 目录下提供了 `antv.js` `antv.css` 以及 `antv.min.js` `antv.min.css`。
36 |
37 | ## 示例
38 |
39 | ```jsx
40 | import Vue from 'vue'
41 | import Antv from 'antv'
42 | import 'antv/dist/antv.css'
43 |
44 | Vue.use(Antv)
45 |
46 | new Vue({
47 | el: '#app',
48 | render() {
49 | return (Primary)
50 | }
51 | })
52 | ```
53 |
54 | ## 链接
55 |
56 | - [Antd](http://ant.design/)
57 | - [Element UI](http://element.eleme.io)
58 | - [UI 组件库](/docs/vue/introduce)
59 | - [设计规范速查手册](https://github.com/ant-design/ant-design/wiki/Ant-Design-%E8%AE%BE%E8%AE%A1%E5%9F%BA%E7%A1%80%E7%AE%80%E7%89%88)
60 | - [Awesome Ant Design](https://github.com/websemantics/awesome-ant-design)
61 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ant Design of Vue
2 |
3 | [](https://www.npmjs.org/package/antv)
4 |
5 | An enterprise-class UI design language and Vue-based implementation.
6 |
7 | [中文 README](README-zh_CN.md)
8 |
9 | ## Features
10 |
11 | - An enterprise-class UI design language for web applications.
12 | - A high-quality Vue components based on superior [Ant Design](https://ant.design).
13 | - A npm + webpack + babel + [Vue2.0](https://vuejs.org) front-end development workflow.
14 |
15 | ## Environment Support
16 |
17 | * Browser: Modern browsers and Internet Explorer 9+
18 |
19 | ## Installation
20 |
21 | ### Using npm
22 |
23 | **We recommend using npm or yarn to install**,it not only makes development easier,but also allow you to take advantage of the rich ecosystem of javascript packages and tooling.
24 |
25 | ```bash
26 | $ npm install antv --save
27 | ```
28 |
29 | If you are in a bad network enviornment,you can try other registers and tools like [cnpm](https://github.com/cnpm/cnpm).
30 |
31 | ### Import in Browser
32 |
33 | Add `script` and `link` tags in your browser and use the global variable `antv`.
34 |
35 | We provide `antv.js` `antv.css` and `antv.min.js` `antv.min.css` under `antv/dist` in antv's npm package.
36 |
37 | ## Usage
38 |
39 | ```jsx
40 | import Vue from 'vue'
41 | import Antv from 'antv'
42 | import 'antv/dist/antv.css'
43 |
44 | Vue.use(Antv)
45 |
46 | new Vue({
47 | el: '#app',
48 | render() {
49 | return (Primary)
50 | }
51 | })
52 | ```
53 |
54 | ## Links
55 |
56 | - [Antd](http://ant.design/)
57 | - [Element UI](http://element.eleme.io)
58 | - [UI library](/docs/Vue/introduce)
59 | - [Design Code Quick Guide](https://github.com/ant-design/ant-design/wiki/Ant-Design-%E8%AE%BE%E8%AE%A1%E5%9F%BA%E7%A1%80%E7%AE%80%E7%89%88)
60 | - [Awesome Ant Design](https://github.com/websemantics/awesome-ant-design)
61 |
--------------------------------------------------------------------------------
/build/build.js:
--------------------------------------------------------------------------------
1 | // https://github.com/shelljs/shelljs
2 | require('./check-versions')()
3 | require('shelljs/global')
4 | env.NODE_ENV = 'production'
5 |
6 | var path = require('path')
7 | var config = require('../config')
8 | var ora = require('ora')
9 | var webpack = require('webpack')
10 | var webpackConfig = require('./webpack.prod.conf')
11 | var prodWebpackConfig = require('./webpack.prod.min.conf')
12 |
13 | console.log(
14 | ' Tip:\n' +
15 | ' Built files are meant to be served over an HTTP server.\n' +
16 | ' Opening index.html over file:// won\'t work.\n'
17 | )
18 |
19 | var spinner = ora('building for production...')
20 | spinner.start()
21 |
22 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
23 | rm('-rf', assetsPath)
24 | mkdir('-p', assetsPath)
25 | cp('-R', 'static/*', assetsPath)
26 |
27 | webpack([webpackConfig, prodWebpackConfig], function (err, stats) {
28 | spinner.stop()
29 | if (err) throw err
30 | process.stdout.write(stats.toString({
31 | colors: true,
32 | modules: false,
33 | children: false,
34 | chunks: false,
35 | chunkModules: false
36 | }) + '\n')
37 | })
38 |
--------------------------------------------------------------------------------
/build/check-versions.js:
--------------------------------------------------------------------------------
1 | var semver = require('semver')
2 | var chalk = require('chalk')
3 | var packageConfig = require('../package.json')
4 | var exec = function (cmd) {
5 | return require('child_process')
6 | .execSync(cmd).toString().trim()
7 | }
8 |
9 | var versionRequirements = [
10 | {
11 | name: 'node',
12 | currentVersion: semver.clean(process.version),
13 | versionRequirement: packageConfig.engines.node
14 | },
15 | {
16 | name: 'npm',
17 | currentVersion: exec('npm --version'),
18 | versionRequirement: packageConfig.engines.npm
19 | }
20 | ]
21 |
22 | module.exports = function () {
23 | var warnings = []
24 | for (var i = 0; i < versionRequirements.length; i++) {
25 | var mod = versionRequirements[i]
26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
27 | warnings.push(mod.name + ': ' +
28 | chalk.red(mod.currentVersion) + ' should be ' +
29 | chalk.green(mod.versionRequirement)
30 | )
31 | }
32 | }
33 |
34 | if (warnings.length) {
35 | console.log('')
36 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
37 | console.log()
38 | for (var i = 0; i < warnings.length; i++) {
39 | var warning = warnings[i]
40 | console.log(' ' + warning)
41 | }
42 | console.log()
43 | process.exit(1)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/build/dev-client.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | require('eventsource-polyfill')
3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
4 |
5 | hotClient.subscribe(function (event) {
6 | if (event.action === 'reload') {
7 | window.location.reload()
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/build/dev-server.js:
--------------------------------------------------------------------------------
1 | require('./check-versions')()
2 | var config = require('../config')
3 | if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
4 | var path = require('path')
5 | var express = require('express')
6 | var webpack = require('webpack')
7 | var opn = require('opn')
8 | var proxyMiddleware = require('http-proxy-middleware')
9 | var webpackConfig = require('./webpack.dev.conf')
10 |
11 | // default port where dev server listens for incoming traffic
12 | var port = process.env.PORT || config.dev.port
13 | // Define HTTP proxies to your custom API backend
14 | // https://github.com/chimurai/http-proxy-middleware
15 | var proxyTable = config.dev.proxyTable
16 |
17 | var app = express()
18 | var compiler = webpack(webpackConfig)
19 |
20 | var devMiddleware = require('webpack-dev-middleware')(compiler, {
21 | publicPath: webpackConfig.output.publicPath,
22 | stats: {
23 | colors: true,
24 | chunks: false
25 | }
26 | })
27 |
28 | var hotMiddleware = require('webpack-hot-middleware')(compiler)
29 | // force page reload when html-webpack-plugin template changes
30 | compiler.plugin('compilation', function (compilation) {
31 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
32 | hotMiddleware.publish({ action: 'reload' })
33 | cb()
34 | })
35 | })
36 |
37 | // proxy api requests
38 | Object.keys(proxyTable).forEach(function (context) {
39 | var options = proxyTable[context]
40 | if (typeof options === 'string') {
41 | options = { target: options }
42 | }
43 | app.use(proxyMiddleware(context, options))
44 | })
45 |
46 | // handle fallback for HTML5 history API
47 | app.use(require('connect-history-api-fallback')())
48 |
49 | // serve webpack bundle output
50 | app.use(devMiddleware)
51 |
52 | // enable hot-reload and state-preserving
53 | // compilation error display
54 | app.use(hotMiddleware)
55 |
56 | // serve pure static assets
57 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
58 | app.use(staticPath, express.static('./static'))
59 |
60 | module.exports = app.listen(port, function (err) {
61 | if (err) {
62 | console.log(err)
63 | return
64 | }
65 | var uri = 'http://localhost:' + port
66 | console.log('Listening at ' + uri + '\n')
67 |
68 | // when env is testing, don't need open it
69 | if (process.env.NODE_ENV !== 'testing') {
70 | opn(uri)
71 | }
72 | })
73 |
--------------------------------------------------------------------------------
/build/git-release.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | git checkout dev
3 |
4 | if test -n "$(git status --porcelain)"; then
5 | echo 'Unclean working tree. Commit or stash changes first.' >&2;
6 | exit 128;
7 | fi
8 |
9 | if ! git fetch --quiet 2>/dev/null; then
10 | echo 'There was a problem fetching your branch. Run `git fetch` to see more...' >&2;
11 | exit 128;
12 | fi
13 |
14 | if test "0" != "$(git rev-list --count --left-only @'{u}'...HEAD)"; then
15 | echo 'Remote history differ. Please pull changes.' >&2;
16 | exit 128;
17 | fi
18 |
19 | echo 'No conflicts.' >&2;
20 |
--------------------------------------------------------------------------------
/build/utils.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
4 |
5 | exports.assetsPath = function (_path) {
6 | var assetsSubDirectory = process.env.NODE_ENV === 'production'
7 | ? config.build.assetsSubDirectory
8 | : config.dev.assetsSubDirectory
9 | return path.posix.join(assetsSubDirectory, _path)
10 | }
11 |
12 | exports.cssLoaders = function (options) {
13 | options = options || {}
14 | // generate loader string to be used with extract text plugin
15 | function generateLoaders (loaders) {
16 | var sourceLoader = loaders.map(function (loader) {
17 | var extraParamChar
18 | if (/\?/.test(loader)) {
19 | loader = loader.replace(/\?/, '-loader?')
20 | extraParamChar = '&'
21 | } else {
22 | loader = loader + '-loader'
23 | extraParamChar = '?'
24 | }
25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
26 | }).join('!')
27 |
28 | // Extract CSS when that option is specified
29 | // (which is the case during production build)
30 | if (options.extract) {
31 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader)
32 | } else {
33 | return ['vue-style-loader', sourceLoader].join('!')
34 | }
35 | }
36 |
37 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
38 | return {
39 | css: generateLoaders(['css']),
40 | postcss: generateLoaders(['css']),
41 | less: generateLoaders(['css', 'less']),
42 | sass: generateLoaders(['css', 'sass?indentedSyntax']),
43 | scss: generateLoaders(['css', 'sass']),
44 | stylus: generateLoaders(['css', 'stylus']),
45 | styl: generateLoaders(['css', 'stylus'])
46 | }
47 | }
48 |
49 | // Generate loaders for standalone style files (outside of .vue)
50 | exports.styleLoaders = function (options) {
51 | var output = []
52 | var loaders = exports.cssLoaders(options)
53 | for (var extension in loaders) {
54 | var loader = loaders[extension]
55 | output.push({
56 | test: new RegExp('\\.' + extension + '$'),
57 | loader: loader
58 | })
59 | }
60 | return output
61 | }
62 |
--------------------------------------------------------------------------------
/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var utils = require('./utils')
4 | var projectRoot = path.resolve(__dirname, '../')
5 |
6 | var env = process.env.NODE_ENV
7 | // check env & config/index.js to decide weither to enable CSS Sourcemaps for the
8 | // various preprocessor loaders added to vue-loader at the end of this file
9 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
10 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
11 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd
12 |
13 | module.exports = {
14 | entry: {
15 | antv: './components'
16 | },
17 | output: {
18 | path: config.build.assetsRoot,
19 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
20 | filename: '[name].js'
21 | },
22 | resolve: {
23 | extensions: ['', '.js', '.vue'],
24 | fallback: [path.join(__dirname, '../node_modules')],
25 | alias: {
26 | 'vue$': 'vue/dist/vue',
27 | 'src': path.resolve(__dirname, '../src'),
28 | 'assets': path.resolve(__dirname, '../src/assets'),
29 | 'components': path.resolve(__dirname, '../src/components')
30 | }
31 | },
32 | resolveLoader: {
33 | fallback: [path.join(__dirname, '../node_modules')]
34 | },
35 | module: {
36 | preLoaders: [
37 | {
38 | test: /\.vue$/,
39 | loader: 'eslint',
40 | include: projectRoot,
41 | exclude: /node_modules/
42 | },
43 | {
44 | test: /\.js$/,
45 | loader: 'eslint',
46 | include: projectRoot,
47 | exclude: /node_modules/
48 | }
49 | ],
50 | loaders: [
51 | {
52 | test: /\.vue$/,
53 | loader: 'vue'
54 | },
55 | {
56 | test: /\.js$/,
57 | loader: 'babel',
58 | include: projectRoot,
59 | exclude: /node_modules/
60 | },
61 | {
62 | test: /\.json$/,
63 | loader: 'json'
64 | },
65 | {
66 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
67 | loader: 'url',
68 | query: {
69 | limit: 10000,
70 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
71 | }
72 | },
73 | {
74 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
75 | loader: 'url',
76 | query: {
77 | limit: 10000,
78 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
79 | }
80 | }
81 | ]
82 | },
83 | eslint: {
84 | formatter: require('eslint-friendly-formatter')
85 | },
86 | vue: {
87 | preserveWhitespace: false,
88 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }),
89 | postcss: [
90 | require('autoprefixer')({
91 | browsers: ['last 2 versions']
92 | })
93 | ]
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | var config = require('../config')
2 | var webpack = require('webpack')
3 | var merge = require('webpack-merge')
4 | var utils = require('./utils')
5 | var baseWebpackConfig = require('./webpack.base.conf')
6 | var HtmlWebpackPlugin = require('html-webpack-plugin')
7 |
8 | // add hot-reload related code to entry chunks
9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) {
10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
11 | })
12 |
13 | module.exports = merge(baseWebpackConfig, {
14 | entry: {
15 | antv: './test/main.js'
16 | },
17 | module: {
18 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
19 | },
20 | // eval-source-map is faster for development
21 | devtool: '#inline-source-map',
22 | plugins: [
23 | new webpack.DefinePlugin({
24 | 'process.env': config.dev.env
25 | }),
26 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
27 | new webpack.optimize.OccurenceOrderPlugin(),
28 | new webpack.OldWatchingPlugin(),
29 | new webpack.HotModuleReplacementPlugin(),
30 | new webpack.NoErrorsPlugin(),
31 | // https://github.com/ampedandwired/html-webpack-plugin
32 | new HtmlWebpackPlugin({
33 | filename: './test/index.html',
34 | template: './test/index.html',
35 | inject: true
36 | })
37 | ]
38 | })
39 |
--------------------------------------------------------------------------------
/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var utils = require('./utils')
4 | var webpack = require('webpack')
5 | var merge = require('webpack-merge')
6 | var baseWebpackConfig = require('./webpack.base.conf')
7 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
8 | var env = config.build.env
9 |
10 | var webpackConfig = merge(baseWebpackConfig, {
11 | module: {
12 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true })
13 | },
14 | devtool: config.build.productionSourceMap ? '#source-map' : false,
15 | output: {
16 | path: config.build.assetsRoot,
17 | filename: utils.assetsPath('[name].js'),
18 | library: 'antv',
19 | libraryTarget: 'umd',
20 | umdNamedDefine: true
21 | },
22 | externals: {
23 | vue: {
24 | root: 'Vue',
25 | commonjs: 'vue',
26 | commonjs2: 'vue',
27 | amd: 'vue'
28 | }
29 | },
30 | vue: {
31 | loaders: utils.cssLoaders({
32 | sourceMap: false,
33 | extract: true
34 | })
35 | },
36 | plugins: [
37 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
38 | new webpack.DefinePlugin({
39 | 'process.env': env
40 | }),
41 | new webpack.optimize.OccurrenceOrderPlugin(),
42 | // extract css into its own file
43 | new ExtractTextPlugin(utils.assetsPath('[name].css')),
44 | ]
45 | })
46 |
47 | module.exports = webpackConfig
48 |
--------------------------------------------------------------------------------
/build/webpack.prod.min.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var utils = require('./utils')
3 | var config = require('../config')
4 | var webpack = require('webpack')
5 | var merge = require('webpack-merge')
6 | var prodWebpackConfig = require('./webpack.prod.conf')
7 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
8 |
9 | var webpackConfig = merge(prodWebpackConfig, {
10 | output: {
11 | path: config.build.assetsRoot,
12 | filename: utils.assetsPath('[name].min.js'),
13 | library: 'antv',
14 | libraryTarget: 'umd',
15 | umdNamedDefine: true
16 | },
17 | plugins: [
18 | new webpack.optimize.UglifyJsPlugin({
19 | compress: {
20 | warnings: false
21 | }
22 | }),
23 | new ExtractTextPlugin(utils.assetsPath('[name].min.css'))
24 | ]
25 | })
26 |
27 | if (config.build.productionGzip) {
28 | var CompressionWebpackPlugin = require('compression-webpack-plugin')
29 |
30 | webpackConfig.plugins.push(
31 | new CompressionWebpackPlugin({
32 | asset: '[path].gz[query]',
33 | algorithm: 'gzip',
34 | test: new RegExp(
35 | '\\.(' +
36 | config.build.productionGzipExtensions.join('|') +
37 | ')$'
38 | ),
39 | threshold: 10240,
40 | minRatio: 0.8
41 | })
42 | )
43 | }
44 |
45 | module.exports = webpackConfig
46 |
--------------------------------------------------------------------------------
/components/alert/alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 |
84 |
--------------------------------------------------------------------------------
/components/alert/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Alert from './alert'
4 |
5 | export default Alert
6 |
--------------------------------------------------------------------------------
/components/alert/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 |
3 | @alert-prefix-cls: ~"@{ant-prefix}-alert";
4 |
5 | .@{alert-prefix-cls} {
6 | position: relative;
7 | padding: 8px 48px 8px 38px;
8 | border-radius: @border-radius-base;
9 | color: @text-color;
10 | font-size: @font-size-base;
11 | line-height: 16px;
12 | margin-bottom: 10px;
13 |
14 | &&-no-icon {
15 | padding: 8px 48px 8px 16px;
16 | }
17 |
18 | &-icon {
19 | font-size: @font-size-lg;
20 | top: 9.5px;
21 | left: 16px;
22 | position: absolute;
23 | }
24 |
25 | &-description {
26 | font-size: @font-size-base;
27 | line-height: 21px;
28 | display: none;
29 | }
30 |
31 | &-success {
32 | border: @border-width-base @border-style-base @green-2;
33 | background-color: @green-1;
34 | .@{alert-prefix-cls}-icon {
35 | color: @success-color;
36 | }
37 | }
38 |
39 | &-info {
40 | border: @border-width-base @border-style-base @primary-2;
41 | background-color: @primary-1;
42 | .@{alert-prefix-cls}-icon {
43 | color: @primary-color;
44 | }
45 | }
46 |
47 | &-warning {
48 | border: @border-width-base @border-style-base @yellow-2;
49 | background-color: @yellow-1;
50 | .@{alert-prefix-cls}-icon {
51 | color: @warning-color;
52 | }
53 | }
54 |
55 | &-error {
56 | border: @border-width-base @border-style-base @red-2;
57 | background-color: @red-1;
58 | .@{alert-prefix-cls}-icon {
59 | color: @error-color;
60 | }
61 | }
62 |
63 | &-close-icon {
64 | font-size: @font-size-base;
65 | position: absolute;
66 | right: 16px;
67 | top: 10px;
68 | height: 12px;
69 | line-height: 12px;
70 | overflow: hidden;
71 | cursor: pointer;
72 |
73 | .@{iconfont-css-prefix}-cross {
74 | color: @text-color-secondary;
75 | transition: color .3s ease;
76 | &:hover {
77 | color: #404040;
78 | }
79 | }
80 | }
81 |
82 | &-close-text {
83 | position: absolute;
84 | right: 16px;
85 | }
86 |
87 | &-with-description {
88 | padding: 16px 16px 16px 60px;
89 | position: relative;
90 | border-radius: @border-radius-base;
91 | margin-bottom: 10px;
92 | color: @text-color;
93 | line-height: 1.5;
94 | }
95 |
96 | &-with-description&-no-icon {
97 | padding: 16px;
98 | }
99 |
100 | &-with-description &-icon {
101 | position: absolute;
102 | top: 16px;
103 | left: 20px;
104 | font-size: 24px;
105 | }
106 |
107 | &-with-description &-close-icon {
108 | position: absolute;
109 | top: 16px;
110 | right: 16px;
111 | cursor: pointer;
112 | font-size: @font-size-base;
113 | }
114 |
115 | &-with-description &-message {
116 | font-size: @font-size-lg;
117 | color: @heading-color;
118 | display: block;
119 | margin-bottom: 4px;
120 | }
121 |
122 | &-with-description &-description {
123 | display: block;
124 | }
125 |
126 | &&-close {
127 | height: 0 !important;
128 | margin: 0;
129 | padding-top: 0;
130 | padding-bottom: 0;
131 | transition: all .3s @ease-in-out-circ;
132 | transform-origin: 50% 0;
133 | }
134 |
135 | &-slide-up-leave {
136 | animation: antAlertSlideUpOut .3s @ease-in-out-circ;
137 | animation-fill-mode: both;
138 | }
139 |
140 | &-banner {
141 | border-radius: 0;
142 | border: 0;
143 | margin-bottom: 0;
144 | }
145 | }
146 |
147 | @keyframes antAlertSlideUpIn {
148 | 0% {
149 | opacity: 0;
150 | transform-origin: 0% 0%;
151 | transform: scaleY(0);
152 | }
153 | 100% {
154 | opacity: 1;
155 | transform-origin: 0% 0%;
156 | transform: scaleY(1);
157 | }
158 | }
159 |
160 | @keyframes antAlertSlideUpOut {
161 | 0% {
162 | opacity: 1;
163 | transform-origin: 0% 0%;
164 | transform: scaleY(1);
165 | }
166 | 100% {
167 | opacity: 0;
168 | transform-origin: 0% 0%;
169 | transform: scaleY(0);
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/components/badge/badge.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
11 | {{displayCount}}
12 |
13 |
14 |
15 |
16 | {{text}}
17 |
18 |
19 |
20 |
87 |
--------------------------------------------------------------------------------
/components/badge/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Badge from './badge'
4 |
5 | export default Badge
6 |
--------------------------------------------------------------------------------
/components/badge/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 |
3 | @badge-prefix-cls: ~"@{ant-prefix}-badge";
4 | @number-prefix-cls: ~"@{ant-prefix}-scroll-number";
5 |
6 | .@{badge-prefix-cls} {
7 | position: relative;
8 | display: inline-block;
9 | line-height: 1;
10 | vertical-align: middle;
11 |
12 | &-count {
13 | position: absolute;
14 | transform: translateX(-50%);
15 | top: -@badge-height / 2;
16 | height: @badge-height;
17 | border-radius: @badge-height / 2;
18 | min-width: @badge-height;
19 | background: @highlight-color;
20 | color: #fff;
21 | line-height: @badge-height;
22 | text-align: center;
23 | padding: 0 6px;
24 | font-size: @font-size-base;
25 | white-space: nowrap;
26 | transform-origin: -10% center;
27 | font-family: tahoma;
28 | box-shadow: 0 0 0 1px #fff;
29 | a,
30 | a:hover {
31 | color: #fff;
32 | }
33 | }
34 |
35 | &-dot {
36 | position: absolute;
37 | transform: translateX(-50%);
38 | transform-origin: 0 center;
39 | top: -@badge-dot-size / 2;
40 | height: @badge-dot-size;
41 | width: @badge-dot-size;
42 | border-radius: 100%;
43 | background: @highlight-color;
44 | z-index: 10;
45 | box-shadow: 0 0 0 1px #fff;
46 | }
47 |
48 | &-status {
49 | line-height: inherit;
50 | vertical-align: baseline;
51 |
52 | &-dot {
53 | width: 8px;
54 | height: 8px;
55 | display: inline-block;
56 | border-radius: 50%;
57 | }
58 | &-success {
59 | background-color: @success-color;
60 | }
61 | &-processing {
62 | background-color: @primary-color;
63 | position: relative;
64 | &:after {
65 | position: absolute;
66 | top: 0;
67 | left: 0;
68 | width: 100%;
69 | height: 100%;
70 | border-radius: 50%;
71 | border: 1px solid @primary-color;
72 | content: '';
73 | animation: antStatusProcessing 1.2s infinite ease-in-out;
74 | }
75 | }
76 | &-default {
77 | background-color: @normal-color;
78 | }
79 | &-error {
80 | background-color: @error-color;
81 | }
82 | &-warning {
83 | background-color: @warning-color;
84 | }
85 | &-text {
86 | color: @text-color;
87 | font-size: @font-size-base;
88 | margin-left: 8px;
89 | }
90 | }
91 |
92 | &-zoom-appear,
93 | &-zoom-enter {
94 | animation: antZoomBadgeIn .3s @ease-out-back;
95 | animation-fill-mode: both;
96 | }
97 |
98 | &-zoom-leave {
99 | animation: antZoomBadgeOut .3s @ease-in-back;
100 | animation-fill-mode: both;
101 | }
102 |
103 | &-not-a-wrapper &-count {
104 | top: auto;
105 | display: block;
106 | position: relative;
107 | transform: none!important;
108 | }
109 | }
110 |
111 | @keyframes antStatusProcessing {
112 | 0% {
113 | transform: scale(0.8);
114 | opacity: 0.5;
115 | }
116 | 100% {
117 | transform: scale(2.4);
118 | opacity: 0;
119 | }
120 | }
121 |
122 | .@{number-prefix-cls} {
123 | overflow: hidden;
124 | &-only {
125 | display: inline-block;
126 | transition: transform .3s @ease-in-out;
127 | height: @badge-height;
128 | > p {
129 | height: @badge-height;
130 | }
131 | }
132 | // for IE8/9 display
133 | &.not-support-css-animation &-only {
134 | > p {
135 | display: none;
136 | &.current {
137 | display: block;
138 | }
139 | }
140 | }
141 | }
142 |
143 | @keyframes antZoomBadgeIn {
144 | 0% {
145 | opacity: 0;
146 | transform: scale(0) translateX(-50%);
147 | }
148 | 100% {
149 | transform: scale(1) translateX(-50%);
150 | }
151 | }
152 |
153 | @keyframes antZoomBadgeOut {
154 | 0% {
155 | transform: scale(1) translateX(-50%);
156 | }
157 | 100% {
158 | opacity: 0;
159 | transform: scale(0) translateX(-50%);
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/components/breadcrumb/breadcrumb-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{separator}}
10 |
11 |
12 |
27 |
--------------------------------------------------------------------------------
/components/breadcrumb/breadcrumb.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{route.name}}
7 |
8 |
9 |
10 |
11 |
30 |
--------------------------------------------------------------------------------
/components/breadcrumb/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Breadcrumb from './breadcrumb'
4 | import BreadcrumbItem from './breadcrumb-item'
5 |
6 | Breadcrumb.Item = BreadcrumbItem
7 |
8 | export default Breadcrumb
9 |
--------------------------------------------------------------------------------
/components/breadcrumb/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 |
3 | @breadcrumb-prefix-cls: ~"@{ant-prefix}-breadcrumb";
4 |
5 | .@{breadcrumb-prefix-cls} {
6 | color: @text-color;
7 | font-size: @font-size-base;
8 |
9 | a {
10 | color: @text-color;
11 | transition: color .3s;
12 | &:hover {
13 | color: @primary-5;
14 | }
15 | }
16 |
17 | & > span:last-child {
18 | font-weight: bold;
19 | color: @text-color;
20 | }
21 |
22 | & > span:last-child &-separator {
23 | display: none;
24 | }
25 |
26 | &-separator {
27 | margin: 0 8px;
28 | color: rgba(0, 0, 0, 0.3);
29 | }
30 |
31 | &-link {
32 | > .@{iconfont-css-prefix} + span {
33 | margin-left: 4px;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/components/button/button-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
33 |
--------------------------------------------------------------------------------
/components/button/button.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
58 |
--------------------------------------------------------------------------------
/components/button/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Button from './button'
4 | import ButtonGroup from './button-group'
5 |
6 | Button.Group = ButtonGroup
7 | export default Button
8 |
--------------------------------------------------------------------------------
/components/button/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 | @import "./mixin";
4 |
5 | @btn-prefix-cls: ~"@{ant-prefix}-btn";
6 |
7 | // for compatibile
8 | @btn-ghost-color : @text-color;
9 | @btn-ghost-bg : transparent;
10 | @btn-ghost-border : @border-color-base;
11 |
12 | // Button styles
13 | // -----------------------------
14 | .@{btn-prefix-cls} {
15 | .btn;
16 | .btn-default;
17 |
18 | &-primary {
19 | .btn-primary;
20 |
21 | .@{btn-prefix-cls}-group &:not(:first-child):not(:last-child) {
22 | border-right-color: @btn-group-border;
23 | border-left-color: @btn-group-border;
24 |
25 | &:disabled {
26 | border-color: @btn-default-border;
27 | }
28 | }
29 |
30 | .@{btn-prefix-cls}-group &:first-child {
31 | &:not(:last-child) {
32 | border-right-color: @btn-group-border;
33 | &[disabled] {
34 | border-right-color: @btn-default-border;
35 | }
36 | }
37 | }
38 |
39 | .@{btn-prefix-cls}-group &:last-child:not(:first-child),
40 | .@{btn-prefix-cls}-group & + & {
41 | border-left-color: @btn-group-border;
42 | &[disabled] {
43 | border-left-color: @btn-default-border;
44 | }
45 | }
46 | }
47 |
48 | &-ghost {
49 | .btn-ghost;
50 | }
51 |
52 | &-dashed {
53 | .btn-dashed;
54 | }
55 |
56 | &-danger {
57 | .btn-danger;
58 | }
59 |
60 | &-circle,
61 | &-circle-outline {
62 | .btn-circle(@btn-prefix-cls);
63 | }
64 |
65 | &:before {
66 | position: absolute;
67 | top: -1px;
68 | left: -1px;
69 | bottom: -1px;
70 | right: -1px;
71 | background: #fff;
72 | opacity: 0.35;
73 | content: '';
74 | border-radius: inherit;
75 | z-index: 1;
76 | transition: opacity .2s;
77 | pointer-events: none;
78 | display: none;
79 | }
80 |
81 | &&-loading:before {
82 | display: block;
83 | }
84 |
85 | .@{iconfont-css-prefix} {
86 | transition: all .3s @ease-in-out;
87 | }
88 |
89 | &&-loading:not(&-circle):not(&-circle-outline) {
90 | padding-left: 29px;
91 | pointer-events: none;
92 | position: relative;
93 | .@{iconfont-css-prefix} {
94 | margin-left: -14px;
95 | }
96 | }
97 |
98 | &-sm&-loading:not(&-circle):not(&-circle-outline) {
99 | padding-left: 24px;
100 | .@{iconfont-css-prefix} {
101 | margin-left: -17px;
102 | }
103 | }
104 |
105 | &-group {
106 | .btn-group(@btn-prefix-cls);
107 | }
108 |
109 | &:not(&-circle):not(&-circle-outline)&-icon-only {
110 | padding-left: 8px;
111 | padding-right: 8px;
112 | }
113 |
114 | // http://stackoverflow.com/a/21281554/3040605
115 | &:focus > span,
116 | &:active > span {
117 | position: relative;
118 | }
119 |
120 | // To ensure that a space will be placed between character and `Icon`.
121 | > .@{iconfont-css-prefix} + span,
122 | > span + .@{iconfont-css-prefix} {
123 | margin-left: 0.5em;
124 | }
125 |
126 | &-clicked:after {
127 | content: '';
128 | position: absolute;
129 | top: -1px;
130 | left: -1px;
131 | bottom: -1px;
132 | right: -1px;
133 | border-radius: inherit;
134 | border: 0 solid @primary-color;
135 | opacity: 0.4;
136 | animation: buttonEffect .4s;
137 | display: block;
138 | }
139 |
140 | &-danger&-clicked:after {
141 | border-color: @btn-danger-bg;
142 | }
143 |
144 | &-background-ghost {
145 | background: transparent!important;
146 | border-color: #fff;
147 | color: #fff;
148 | }
149 |
150 | &-background-ghost&-primary {
151 | .button-variant-other(@primary-color; transparent; @primary-color);
152 | }
153 | }
154 |
155 | @keyframes buttonEffect {
156 | to {
157 | opacity: 0;
158 | top: -6px;
159 | left: -6px;
160 | bottom: -6px;
161 | right: -6px;
162 | border-width: 6px;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/components/card/card.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'VCard',
3 |
4 | props: {
5 | title: null,
6 | extra: null,
7 | bordered: {
8 | type: Boolean,
9 | default: true
10 | },
11 | bodyStyle: Object,
12 | loading: {
13 | type: Boolean,
14 | default: false
15 | }
16 | },
17 |
18 | render() {
19 | const vLoading = (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
)
29 | return (
30 |
31 | { this.title ?
{this.title}
: null}
32 |
33 |
{ this.loading ? vLoading : this.$slots.default}
35 |
)
36 | },
37 |
38 | computed: {
39 | classes() {
40 | return {
41 | 'ant-card-bordered': this.bordered
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/components/card/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Card from './card'
4 |
5 | export default Card
6 |
--------------------------------------------------------------------------------
/components/card/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 |
3 | @card-prefix-cls: ~"@{ant-prefix}-card";
4 |
5 | .@{card-prefix-cls} {
6 | background: @component-background;
7 | border-radius: @border-radius-base;
8 | font-size: @font-size-base;
9 | position: relative;
10 | overflow: hidden;
11 | transition: all .3s;
12 |
13 | &:hover {
14 | box-shadow: @box-shadow-base;
15 | border-color: transparent;
16 | }
17 |
18 | &-bordered {
19 | border: @border-width-base @border-style-base @border-color-split;
20 | }
21 |
22 | &-head {
23 | height: 48px;
24 | line-height: 48px;
25 | border-bottom: @border-width-base @border-style-base @border-color-split;
26 | padding: 0 24px;
27 |
28 | &-title {
29 | font-size: @font-size-lg;
30 | display: inline-block;
31 | text-overflow: ellipsis;
32 | width: 100%;
33 | overflow: hidden;
34 | white-space: nowrap;
35 | }
36 | }
37 |
38 | &-extra {
39 | position: absolute;
40 | right: 24px;
41 | top: 14px;
42 | }
43 |
44 | &-body {
45 | padding: 24px;
46 | }
47 |
48 | &-loading &-body {
49 | user-select: none;
50 | }
51 |
52 | &-loading-block {
53 | display: inline-block;
54 | margin: 5px 1% 0;
55 | height: 14px;
56 | border-radius: @border-radius-sm;
57 | background: linear-gradient(90deg, rgba(207, 216, 220, .2), rgba(207, 216, 220, .4), rgba(207, 216, 220, .2));
58 | animation: card-loading 1.4s ease infinite;
59 | background-size: 600% 600%;
60 | }
61 | }
62 |
63 | @keyframes card-loading {
64 | 0%,
65 | 100% {
66 | background-position: 0 50%;
67 | }
68 | 50% {
69 | background-position: 100% 50%;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/components/checkbox/checkbox-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
36 |
37 |
--------------------------------------------------------------------------------
/components/checkbox/checkbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
76 |
--------------------------------------------------------------------------------
/components/checkbox/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Checkbox from './checkbox'
4 | import CheckboxGroup from './checkbox-group'
5 |
6 | Checkbox.Group = CheckboxGroup
7 | export default Checkbox
8 |
--------------------------------------------------------------------------------
/components/checkbox/store.js:
--------------------------------------------------------------------------------
1 | import BaseStore from '../utils/base-store'
2 |
3 | class Store extends BaseStore {
4 | constructor(component, initialState = {}) {
5 | super(component, initialState)
6 |
7 | this.state = {
8 | value: [],
9 | disabled: false
10 | }
11 |
12 | this.setState(initialState)
13 | }
14 | }
15 |
16 | export default Store
17 |
--------------------------------------------------------------------------------
/components/checkbox/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "./mixin";
3 |
4 | .antCheckboxFn();
5 |
--------------------------------------------------------------------------------
/components/checkbox/style/mixin.less:
--------------------------------------------------------------------------------
1 | @import "../../style/mixins/index";
2 |
3 | .antCheckboxFn(@checkbox-prefix-cls: ~"@{ant-prefix}-checkbox") {
4 | @checkbox-inner-prefix-cls: ~"@{checkbox-prefix-cls}-inner";
5 | // 一般状态
6 | .@{checkbox-prefix-cls} {
7 | white-space: nowrap;
8 | cursor: pointer;
9 | outline: none;
10 | display: inline-block;
11 | line-height: 1;
12 | position: relative;
13 | vertical-align: middle;
14 |
15 | .@{checkbox-prefix-cls}-wrapper:hover &,
16 | &:hover &-inner,
17 | &-input:focus + &-inner {
18 | border-color: @primary-color;
19 | }
20 |
21 | &-inner {
22 | position: relative;
23 | top: 0;
24 | left: 0;
25 | display: block;
26 | width: 14px;
27 | height: 14px;
28 | border: @border-width-base @border-style-base @border-color-base;
29 | border-radius: @border-radius-sm;
30 | background-color: #fff;
31 | transition: all .3s;
32 |
33 | &:after {
34 | transform: rotate(45deg) scale(0);
35 | position: absolute;
36 | left: 4px;
37 | top: 1px;
38 | display: table;
39 | width: 5px;
40 | height: 8px;
41 | border: 2px solid #fff;
42 | border-top: 0;
43 | border-left: 0;
44 | content: ' ';
45 | transition: all .1s @ease-in-back;
46 | }
47 | }
48 |
49 | &-input {
50 | position: absolute;
51 | left: 0;
52 | z-index: 1;
53 | cursor: pointer;
54 | .opacity(0);
55 | top: 0;
56 | bottom: 0;
57 | right: 0;
58 | width: 100%;
59 | height: 100%;
60 | }
61 | }
62 |
63 | // 半选状态
64 | .@{checkbox-prefix-cls}-indeterminate .@{checkbox-inner-prefix-cls}:after {
65 | content: ' ';
66 | transform: scale(1);
67 | position: absolute;
68 | left: 2px;
69 | top: 5px;
70 | width: 8px;
71 | height: 1px;
72 | }
73 |
74 | // 选中状态
75 | .@{checkbox-prefix-cls}-checked .@{checkbox-inner-prefix-cls}:after {
76 | transform: rotate(45deg) scale(1);
77 | position: absolute;
78 | left: 4px;
79 | top: 1px;
80 | display: table;
81 | width: 5px;
82 | height: 8px;
83 | border: 2px solid #fff;
84 | border-top: 0;
85 | border-left: 0;
86 | content: ' ';
87 | transition: all .2s @ease-out-back .1s;
88 | }
89 |
90 | .@{checkbox-prefix-cls}-checked,
91 | .@{checkbox-prefix-cls}-indeterminate {
92 | .@{checkbox-inner-prefix-cls} {
93 | background-color: @primary-color;
94 | border-color: @primary-color;
95 | }
96 | }
97 |
98 | .@{checkbox-prefix-cls}-disabled {
99 | &.@{checkbox-prefix-cls}-checked {
100 | .@{checkbox-inner-prefix-cls}:after {
101 | animation-name: none;
102 | border-color: @disabled-color;
103 | }
104 | }
105 |
106 | .@{checkbox-inner-prefix-cls} {
107 | border-color: @border-color-base!important;
108 | background-color: #f3f3f3;
109 | &:after {
110 | animation-name: none;
111 | border-color: #f3f3f3;
112 | }
113 | }
114 |
115 | & + span {
116 | color: @disabled-color;
117 | cursor: not-allowed;
118 | }
119 | }
120 |
121 | .@{checkbox-prefix-cls}-wrapper {
122 | cursor: pointer;
123 | font-size: @font-size-base;
124 | display: inline-block;
125 | &:not(:last-child) {
126 | margin-right: 8px;
127 | }
128 | }
129 |
130 | .@{checkbox-prefix-cls}-wrapper + span,
131 | .@{checkbox-prefix-cls} + span {
132 | padding-left: 8px;
133 | padding-right: 8px;
134 | vertical-align: middle;
135 | }
136 |
137 | .@{checkbox-prefix-cls}-group {
138 | font-size: @font-size-base;
139 | &-item {
140 | display: inline-block;
141 | }
142 | }
143 |
144 | @ie8: \0screen;
145 |
146 | // IE8 hack for https://github.com/ant-design/ant-design/issues/2148
147 | @media @ie8 {
148 | .@{checkbox-prefix-cls}-checked .@{checkbox-prefix-cls}-inner:before,
149 | .@{checkbox-prefix-cls}-checked .@{checkbox-prefix-cls}-inner:after {
150 | .iconfont-font("\e632");
151 | font-weight: bold;
152 | font-size: 8px;
153 | border: 0;
154 | color: #fff;
155 | left: 2px;
156 | top: 3px;
157 | position: absolute;
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/components/collapse/collapse.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
45 |
--------------------------------------------------------------------------------
/components/collapse/index.js:
--------------------------------------------------------------------------------
1 | import Collapse from './collapse'
2 | import Panel from './panel'
3 |
4 | Collapse.Panel = Panel
5 |
6 | export default Collapse
7 |
--------------------------------------------------------------------------------
/components/collapse/panel.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
46 |
--------------------------------------------------------------------------------
/components/collapse/store.js:
--------------------------------------------------------------------------------
1 | import BaseStore from '../utils/base-store'
2 |
3 | class Mutations {
4 | openPanel({ indexs }) {
5 | indexs.forEach((index) => {
6 | if (this.state.activeIndexs.indexOf(index) > -1) return
7 | if (this.state.accordion) {
8 | this.state.activeIndexs = [index]
9 | } else {
10 | this.state.activeIndexs.push(index)
11 | }
12 | })
13 | this.mutations.activeChange.call(this)
14 | }
15 |
16 | closePanel({ indexs }) {
17 | indexs.forEach((index) => {
18 | const i = this.state.activeIndexs.indexOf(index)
19 | if (i > -1) {
20 | this.state.activeIndexs.splice(i, 1)
21 | }
22 | })
23 | this.mutations.activeChange.call(this)
24 | }
25 |
26 | activeChange() {
27 | this.component.$children.forEach((node) => {
28 | node.active = this.state.activeIndexs.indexOf(node.index) > -1
29 | })
30 | this.component.$emit('input', this.state.activeIndexs)
31 | this.component.$emit('onChange', this.state.activeIndexs)
32 | }
33 | }
34 |
35 | class Store extends BaseStore {
36 | constructor(component, initialState = {}) {
37 | super(component, initialState)
38 |
39 | this.state = {
40 | activeIndexs: [],
41 | accordion: false
42 | }
43 | this.setState(initialState)
44 |
45 | this.mutations = new Mutations()
46 | }
47 | }
48 |
49 | export default Store
50 |
--------------------------------------------------------------------------------
/components/collapse/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 |
4 | @collapse-prefix-cls: ~"@{ant-prefix}-collapse";
5 |
6 | .collapse-close() {
7 | .iconfont-size-under-12px(9px, 0);
8 | }
9 | .collapse-open() {
10 | .iconfont-size-under-12px(9px, 90deg);
11 | }
12 |
13 | .@{collapse-prefix-cls} {
14 | background-color: @background-color-base;
15 | border-radius: @border-radius-base;
16 | border: @border-width-base @border-style-base @border-color-base;
17 | border-bottom: 0;
18 |
19 | & > &-item {
20 | border-bottom: @border-width-base @border-style-base @border-color-base;
21 | > .@{collapse-prefix-cls}-header {
22 | height: 38px;
23 | line-height: 38px;
24 | padding-left: 32px;
25 | color: @text-color;
26 | cursor: pointer;
27 | position: relative;
28 | transition: all .3s;
29 |
30 | &:active {
31 | background-color: #eee!important;
32 | }
33 |
34 | .arrow {
35 | .collapse-close();
36 | .iconfont-mixin();
37 | position: absolute;
38 | color: @text-color-secondary;
39 | display: inline-block;
40 | font-weight: bold;
41 | line-height: 40px;
42 | vertical-align: middle;
43 | transition: transform 0.24s;
44 | top: 0;
45 | left: 16px;
46 | /* stylelint-disable declaration-block-no-duplicate-properties */
47 | top: ~"16px \9";
48 | left: ~"0 \9";
49 | /* stylelint-enable declaration-block-no-duplicate-properties */
50 | &:before {
51 | content: "\E61F";
52 | }
53 | }
54 | }
55 | }
56 |
57 | &-anim-active {
58 | transition: height .2s @ease-out;
59 | }
60 |
61 | &-content {
62 | overflow: hidden;
63 | color: @text-color;
64 | padding: 0 16px;
65 | background-color: @component-background;
66 |
67 | & > &-box {
68 | padding-top: 16px;
69 | padding-bottom: 16px;
70 | }
71 |
72 | &-inactive {
73 | display: none;
74 | }
75 | }
76 |
77 | &-item:last-child {
78 | > .@{collapse-prefix-cls}-content {
79 | border-radius: 0 0 @border-radius-base @border-radius-base;
80 | }
81 | }
82 |
83 | & > &-item > &-header[aria-expanded="true"] {
84 | .arrow {
85 | .collapse-open();
86 | }
87 | }
88 |
89 | &-borderless {
90 | background-color: @component-background;
91 | border: 0;
92 | }
93 |
94 | &-borderless > &-item-active {
95 | border: 0;
96 | }
97 |
98 | &-borderless > &-item > &-content {
99 | background-color: transparent;
100 | border-top: @border-width-base @border-style-base @border-color-base;
101 | }
102 |
103 | &-borderless > &-item > &-header {
104 | transition: all .3s;
105 | &:hover {
106 | background-color: @background-color-base;
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/components/dropdown/dropdown-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
25 |
--------------------------------------------------------------------------------
/components/dropdown/dropdown-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
22 |
23 |
28 |
--------------------------------------------------------------------------------
/components/dropdown/dropdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/components/dropdown/index.js:
--------------------------------------------------------------------------------
1 | import Dropdown from './dropdown'
2 | import DropdownItem from './dropdown-item'
3 | import DropdownMenu from './dropdown-menu'
4 |
5 | Dropdown.DropdownItem = DropdownItem
6 | Dropdown.DropdownMenu = DropdownMenu
7 |
8 | export default Dropdown
9 |
--------------------------------------------------------------------------------
/components/grid/col.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
37 |
--------------------------------------------------------------------------------
/components/grid/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Row from './row'
4 | import Col from './col'
5 |
6 | export { Row, Col }
7 |
--------------------------------------------------------------------------------
/components/grid/row.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
47 |
--------------------------------------------------------------------------------
/components/grid/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 | @import "./mixin";
4 |
5 | // Grid system
6 | .@{ant-prefix}-row {
7 | .make-row();
8 | display: block;
9 | }
10 |
11 | .@{ant-prefix}-row-flex {
12 | display: flex;
13 | flex-direction: row;
14 | flex-wrap: wrap;
15 |
16 | &:before,
17 | &:after {
18 | display: flex;
19 | }
20 | }
21 |
22 | // x轴原点
23 | .@{ant-prefix}-row-flex-start {
24 | justify-content: flex-start;
25 | }
26 |
27 | // x轴居中
28 | .@{ant-prefix}-row-flex-center {
29 | justify-content: center;
30 | }
31 |
32 | // x轴反方向
33 | .@{ant-prefix}-row-flex-end {
34 | justify-content: flex-end;
35 | }
36 |
37 | // x轴平分
38 | .@{ant-prefix}-row-flex-space-between {
39 | justify-content: space-between;
40 | }
41 |
42 | // x轴有间隔地平分
43 | .@{ant-prefix}-row-flex-space-around {
44 | justify-content: space-around;
45 | }
46 |
47 | // 顶部对齐
48 | .@{ant-prefix}-row-flex-top {
49 | align-items: flex-start;
50 | }
51 |
52 | // 居中对齐
53 | .@{ant-prefix}-row-flex-middle {
54 | align-items: center;
55 | }
56 |
57 | // 底部对齐
58 | .@{ant-prefix}-row-flex-bottom {
59 | align-items: flex-end;
60 | }
61 |
62 | .@{ant-prefix}-col {
63 | position: relative;
64 | display: block;
65 | }
66 |
67 | .make-grid-columns();
68 | .make-grid();
69 |
70 | // Extra small grid
71 | //
72 | // Columns, offsets, pushes, and pulls for extra small devices like
73 | // smartphones.
74 |
75 | .make-grid(-xs);
76 |
77 | // Small grid
78 | //
79 | // Columns, offsets, pushes, and pulls for the small device range, from phones
80 | // to tablets.
81 |
82 | @media (min-width: @screen-sm-min) {
83 | .make-grid(-sm);
84 | }
85 |
86 | // Medium grid
87 | //
88 | // Columns, offsets, pushes, and pulls for the desktop device range.
89 |
90 | @media (min-width: @screen-md-min) {
91 | .make-grid(-md);
92 | }
93 |
94 | // Large grid
95 | //
96 | // Columns, offsets, pushes, and pulls for the large desktop device range.
97 |
98 | @media (min-width: @screen-lg-min) {
99 | .make-grid(-lg);
100 | }
101 |
102 | // Extra Large grid
103 | //
104 | // Columns, offsets, pushes, and pulls for the full hd device range.
105 |
106 | @media (min-width: @screen-xl-min) {
107 | .make-grid(-xl);
108 | }
109 |
--------------------------------------------------------------------------------
/components/grid/style/mixin.less:
--------------------------------------------------------------------------------
1 | @import "../../style/mixins/index";
2 |
3 | // mixins for grid system
4 | // ------------------------
5 | .make-row(@gutter: @grid-gutter-width) {
6 | position: relative;
7 | margin-left: (@gutter / -2);
8 | margin-right: (@gutter / -2);
9 | height: auto;
10 | .clearfix;
11 | }
12 |
13 | .make-grid-columns() {
14 | .col(@index) {
15 | @item: ~".@{ant-prefix}-col-@{index}, .@{ant-prefix}-col-xs-@{index}, .@{ant-prefix}-col-sm-@{index}, .@{ant-prefix}-col-md-@{index}, .@{ant-prefix}-col-lg-@{index}";
16 | .col((@index + 1), @item);
17 | }
18 | .col(@index, @list) when (@index =< @grid-columns) {
19 | @item: ~".@{ant-prefix}-col-@{index}, .@{ant-prefix}-col-xs-@{index}, .@{ant-prefix}-col-sm-@{index}, .@{ant-prefix}-col-md-@{index}, .@{ant-prefix}-col-lg-@{index}";
20 | .col((@index + 1), ~"@{list}, @{item}");
21 | }
22 | .col(@index, @list) when (@index > @grid-columns) {
23 | @{list} {
24 | position: relative;
25 | // Prevent columns from collapsing when empty
26 | min-height: 1px;
27 | padding-left: (@grid-gutter-width / 2);
28 | padding-right: (@grid-gutter-width / 2);
29 | }
30 | }
31 | .col(1);
32 | }
33 |
34 | .float-grid-columns(@class) {
35 | .col(@index) { // initial
36 | @item: ~".@{ant-prefix}-col@{class}-@{index}";
37 | .col((@index + 1), @item);
38 | }
39 | .col(@index, @list) when (@index =< @grid-columns) { // general
40 | @item: ~".@{ant-prefix}-col@{class}-@{index}";
41 | .col((@index + 1), ~"@{list}, @{item}");
42 | }
43 | .col(@index, @list) when (@index > @grid-columns) { // terminal
44 | @{list} {
45 | float: left;
46 | flex: 0 0 auto;
47 | }
48 | }
49 | .col(1); // kickstart it
50 | }
51 |
52 | // lesshint false
53 | .loop-grid-columns(@index, @class) when (@index > 0) {
54 | .@{ant-prefix}-col@{class}-@{index} {
55 | display: block;
56 | width: percentage((@index / @grid-columns));
57 | }
58 | .@{ant-prefix}-col@{class}-push-@{index} {
59 | left: percentage((@index / @grid-columns));
60 | }
61 | .@{ant-prefix}-col@{class}-pull-@{index} {
62 | right: percentage((@index / @grid-columns));
63 | }
64 | .@{ant-prefix}-col@{class}-offset-@{index} {
65 | margin-left: percentage((@index / @grid-columns));
66 | }
67 | .@{ant-prefix}-col@{class}-order-@{index} {
68 | order: @index;
69 | }
70 | .loop-grid-columns((@index - 1), @class);
71 | }
72 |
73 | .loop-grid-columns(@index, @class) when (@index = 0) {
74 | .@{ant-prefix}-col@{class}-@{index} {
75 | display: none;
76 | }
77 | .@{ant-prefix}-col-push-@{index} {
78 | left: auto;
79 | }
80 | .@{ant-prefix}-col-pull-@{index} {
81 | right: auto;
82 | }
83 | .@{ant-prefix}-col@{class}-push-@{index} {
84 | left: auto;
85 | }
86 | .@{ant-prefix}-col@{class}-pull-@{index} {
87 | right: auto;
88 | }
89 | .@{ant-prefix}-col@{class}-offset-@{index} {
90 | margin-left: 0;
91 | }
92 | .@{ant-prefix}-col@{class}-order-@{index} {
93 | order: 0;
94 | }
95 | }
96 |
97 | .make-grid(@class: ~'') {
98 | .float-grid-columns(@class);
99 | .loop-grid-columns(@grid-columns, @class);
100 | }
101 |
--------------------------------------------------------------------------------
/components/icon/icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/components/icon/index.js:
--------------------------------------------------------------------------------
1 | import Icon from './icon'
2 |
3 | export default Icon
4 |
--------------------------------------------------------------------------------
/components/index.js:
--------------------------------------------------------------------------------
1 | import { Col, Row } from './grid'
2 | import Button from './button'
3 | import Icon from './icon'
4 | import Menu from './menu'
5 | import Pagination from './pagination'
6 | import Tabs from './tabs'
7 | import Breadcrumb from './breadcrumb'
8 | import Dropdown from './dropdown'
9 | import Input from './input'
10 | import InputNumber from './input-number'
11 | import Rate from './rate'
12 | import Radio from './radio'
13 | import Checkbox from './checkbox'
14 | import Switch from './switch'
15 | import Select from './select'
16 | import Badge from './badge'
17 | import Card from './card'
18 | import Collapse from './collapse'
19 | import Tooltip from './tooltip'
20 | import Popover from './popover'
21 | import Tag from './tag'
22 | import Alert from './alert'
23 | import Modal from './modal'
24 | import Message from './message'
25 | import Notification from './notification'
26 | import Popconfirm from './popconfirm'
27 |
28 | import VTransition from './transition'
29 |
30 | const components = {
31 | Menu,
32 | SubMenu: Menu.SubMenu,
33 | MenuItemGroup: Menu.ItemGroup,
34 | MenuItem: Menu.Item,
35 | Pagination,
36 | Tabs,
37 | TabPane: Tabs.Pane,
38 | Breadcrumb,
39 | BreadcrumbItem: Breadcrumb.Item,
40 | Dropdown,
41 | DropdownItem: Dropdown.DropdownItem,
42 | DropdownMenu: Dropdown.DropdownMenu,
43 | Col,
44 | Row,
45 | Button,
46 | ButtonGroup: Button.Group,
47 | Icon,
48 | Input,
49 | InputNumber,
50 | Rate,
51 | Radio,
52 | RadioButton: Radio.RadioButton,
53 | RadioGroup: Radio.Group,
54 | Checkbox,
55 | CheckboxGroup: Checkbox.Group,
56 | Switch,
57 | Select,
58 | Option: Select.Option,
59 | OptionGroup: Select.OptionGroup,
60 | Badge,
61 | Card,
62 | Collapse,
63 | Panel: Collapse.Panel,
64 | Tooltip,
65 | Popover,
66 | Tag,
67 | Alert,
68 | Modal,
69 | Popconfirm,
70 | VTransition
71 | }
72 |
73 | Object.keys(components).forEach((key) => {
74 | if (!components[key].install && components[key].name) {
75 | components[key].install = (Vue) => {
76 | Vue.component(components[key].name, components[key])
77 | }
78 | }
79 | })
80 |
81 | const install = (Vue) => {
82 | if (install.installed) return
83 |
84 | Object.keys(components).forEach((key) => {
85 | if (components[key].install) {
86 | Vue.use(components[key])
87 | }
88 | })
89 |
90 | Vue.prototype.$message = Message
91 | Vue.prototype.$modal = Modal
92 | Vue.prototype.$notification = Notification
93 | }
94 |
95 | export default {
96 | install,
97 | ...components
98 | }
99 |
--------------------------------------------------------------------------------
/components/input-number/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import InputNumber from './input-number'
4 |
5 | export default InputNumber
6 |
--------------------------------------------------------------------------------
/components/input-number/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 | @import "../../input/style/mixin";
4 |
5 | @input-number-prefix-cls: ~"@{ant-prefix}-input-number";
6 |
7 | .handler-disabled() {
8 | opacity: 0.72;
9 | color: #ccc !important;
10 | cursor: not-allowed;
11 | }
12 |
13 | .@{input-number-prefix-cls} {
14 | .input();
15 | margin: 0;
16 | padding: 0;
17 | font-size: @font-size-base;
18 | height: @input-height-base;
19 | display: inline-block;
20 | border: @border-width-base @border-style-base @border-color-base;
21 | border-radius: @border-radius-base;
22 | width: 80px;
23 |
24 | &-handler {
25 | text-align: center;
26 | line-height: 0;
27 | height: 50%;
28 | overflow: hidden;
29 | color: @text-color-secondary;
30 | position: relative;
31 | transition: all 0.1s linear;
32 | display: block;
33 | width: 100%;
34 | font-weight: bold;
35 | &:active {
36 | background: #f4f4f4;
37 | }
38 | &:hover &-up-inner,
39 | &:hover &-down-inner {
40 | color: @primary-5;
41 | }
42 | }
43 |
44 | &-handler-up-inner,
45 | &-handler-down-inner {
46 | .iconfont-mixin();
47 | line-height: 12px;
48 | user-select: none;
49 | position: absolute;
50 | width: 12px;
51 | height: 12px;
52 | transition: all 0.1s linear;
53 | .iconfont-size-under-12px(7px);
54 | right: 4px;
55 | color: @text-color-secondary;
56 | }
57 |
58 | &:hover {
59 | .hover();
60 | }
61 |
62 | &-focused {
63 | .active();
64 | }
65 |
66 | &-disabled {
67 | .disabled();
68 | }
69 |
70 | &-input {
71 | width: 100%;
72 | text-align: left;
73 | outline: 0;
74 | -moz-appearance: textfield;
75 | line-height: @input-height-base - 2px;
76 | height: @input-height-base - 2px;
77 | transition: all 0.3s linear;
78 | color: @input-color;
79 | border: 0;
80 | border-radius: @border-radius-base;
81 | padding: 0 7px;
82 |
83 | &[disabled] {
84 | .disabled();
85 | }
86 | }
87 |
88 | &-lg {
89 | padding: 0;
90 |
91 | input {
92 | height: @input-height-lg - 2px;
93 | line-height: @input-height-lg - 2px;
94 | }
95 | }
96 |
97 | &-sm {
98 | padding: 0;
99 |
100 | input {
101 | height: @input-height-sm - 2px;
102 | line-height: @input-height-sm - 2px;
103 | }
104 | }
105 |
106 | &-handler-wrap {
107 | border-left: @border-width-base @border-style-base @border-color-base;
108 | width: 22px;
109 | height: 100%;
110 | background: @component-background;
111 | position: absolute;
112 | top: 0;
113 | right: 0;
114 | opacity: 0;
115 | border-radius: 0 @border-radius-base @border-radius-base 0;
116 | transition: opacity 0.24s linear 0.1s;
117 | }
118 |
119 | &-handler-wrap:hover &-handler {
120 | height: 40%;
121 | }
122 |
123 | &:hover &-handler-wrap {
124 | opacity: 1;
125 | }
126 |
127 | &-handler-up {
128 | cursor: pointer;
129 | &-inner {
130 | top: 50%;
131 | margin-top: -6px;
132 | &:before {
133 | text-align: center;
134 | content: "\e61e";
135 | }
136 | }
137 | &:hover {
138 | height: 60%!important;
139 | }
140 | }
141 |
142 | &-handler-down {
143 | border-top: @border-width-base @border-style-base @border-color-base;
144 | top: -1px;
145 | cursor: pointer;
146 | &-inner {
147 | top: 50%;
148 | margin-top: -6px;
149 | &:before {
150 | text-align: center;
151 | content: "\e61d";
152 | }
153 | }
154 | &:hover {
155 | height: 60%!important;
156 | }
157 | }
158 |
159 | &-handler-down-disabled,
160 | &-handler-up-disabled,
161 | &-disabled {
162 | .@{input-number-prefix-cls}-handler-down-inner,
163 | .@{input-number-prefix-cls}-handler-up-inner {
164 | .handler-disabled();
165 | }
166 | }
167 |
168 | &-disabled {
169 | .@{input-number-prefix-cls}-input {
170 | opacity: 0.72;
171 | cursor: not-allowed;
172 | background-color: #f3f3f3;
173 | }
174 | .@{input-number-prefix-cls}-handler-wrap {
175 | display: none;
176 | }
177 | .@{input-number-prefix-cls}-handler {
178 | .handler-disabled();
179 | }
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/components/input/index.js:
--------------------------------------------------------------------------------
1 | import Input from './input'
2 |
3 | export default Input
4 |
--------------------------------------------------------------------------------
/components/input/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 | @import "./mixin";
4 | @import "./search-input";
5 |
6 | // Input styles
7 | .@{ant-prefix}-input {
8 | .input;
9 | }
10 |
11 | //== Style for input-group: input with label, with button or dropdown...
12 | .@{ant-prefix}-input-group {
13 | .input-group(~"@{ant-prefix}-input");
14 | }
15 |
16 | // Input with suffix
17 | .@{ant-prefix}-input-preSuffix-wrapper {
18 | .input-preSuffix-wrapper(~"@{ant-prefix}-input");
19 | }
20 |
--------------------------------------------------------------------------------
/components/input/style/search-input.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 | @import "../../button/style/mixin";
4 | @import "./mixin";
5 |
6 | .@{ant-prefix}-input-search-icon {
7 | cursor: pointer;
8 | transition: all .3s;
9 | font-size: 14px;
10 | &:hover {
11 | color: @input-hover-border-color;
12 | }
13 | }
14 |
15 | // code blow is keeped for compatibility
16 | // for this demo: http://1x.ant.design/components/select/#components-select-demo-search-box
17 | // do not delete until 3.x
18 | .@{ant-prefix}-search-input-wrapper {
19 | display: inline-block;
20 | vertical-align: middle;
21 | }
22 |
23 | .@{ant-prefix}-search-input {
24 | &.@{ant-prefix}-input-group .@{ant-prefix}-input:first-child,
25 | &.@{ant-prefix}-input-group .@{ant-prefix}-select:first-child {
26 | border-radius: @border-radius-base;
27 | position: absolute;
28 | top: -1px;
29 | width: 100%;
30 | }
31 |
32 | &.@{ant-prefix}-input-group .@{ant-prefix}-input:first-child {
33 | padding-right: 36px;
34 | }
35 |
36 | .@{ant-prefix}-search-btn {
37 | .btn-default;
38 | border-radius: 0 @border-radius-base - 1 @border-radius-base - 1 0;
39 | left: -1px;
40 | position: relative;
41 | border-width: 0 0 0 1px;
42 | z-index: 2;
43 | padding-left: 8px;
44 | padding-right: 8px;
45 | &:hover {
46 | border-color: @border-color-base;
47 | }
48 | }
49 | &&-focus .@{ant-prefix}-search-btn-noempty,
50 | &:hover .@{ant-prefix}-search-btn-noempty {
51 | .btn-primary;
52 | }
53 | .@{ant-prefix}-select-combobox {
54 | .@{ant-prefix}-select-selection__rendered {
55 | margin-right: 29px;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/components/menu/enum.js:
--------------------------------------------------------------------------------
1 | export default {
2 | MODE: {
3 | VERTICAL: 'vertical',
4 | HORIZONTAL: 'horizontal',
5 | INLINE: 'inline'
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/components/menu/index.js:
--------------------------------------------------------------------------------
1 | import Menu from './menu'
2 | import SubMenu from './sub-menu'
3 | import MenuItemGroup from './menu-item-group'
4 | import MenuItem from './menu-item'
5 |
6 | Menu.SubMenu = SubMenu
7 | Menu.ItemGroup = MenuItemGroup
8 | Menu.Item = MenuItem
9 |
10 | export default Menu
11 |
--------------------------------------------------------------------------------
/components/menu/menu-item-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 | {{title}}
8 |
9 |
10 |
13 |
14 |
15 |
16 |
41 |
--------------------------------------------------------------------------------
/components/menu/menu-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
60 |
--------------------------------------------------------------------------------
/components/menu/menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
11 |
109 |
--------------------------------------------------------------------------------
/components/menu/mixins.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | computed: {
3 | indexPath() {
4 | let parent = this.$parent
5 | const path = [this.index]
6 | while (parent.$options.name !== 'VMenu') {
7 | if (parent.index) {
8 | path.unshift(parent.index)
9 | }
10 | parent = parent.$parent
11 | }
12 | return path
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/components/menu/store.js:
--------------------------------------------------------------------------------
1 | import BaseStore from '../utils/base-store'
2 |
3 | class Mutations {
4 | openMenu({ index, indexPath = [] }) {
5 | if (this.state.openIndexs.indexOf(index) > -1) return
6 | if (this.state.uniqueOpened) {
7 | this.state.openIndexs = [].concat(indexPath)
8 | } else {
9 | this.state.openIndexs.push(index)
10 | }
11 | this.mutations.openChange.call(this)
12 | }
13 |
14 | closeMenu({ index }) {
15 | const i = this.state.openIndexs.indexOf(index)
16 | if (i > -1) {
17 | this.state.openIndexs.splice(i, 1)
18 | this.mutations.openChange.call(this)
19 | }
20 | }
21 |
22 | selectMenu({ index }) {
23 | this.state.selectedIndex = index
24 |
25 | let item
26 | const deepNodes = (nodes) => {
27 | nodes.forEach((node) => {
28 | if (node.$options.name === 'VMenuItem') {
29 | node.selected = node.index === this.state.selectedIndex
30 | if (node.selected) item = node
31 | } else if (node.$options.name === 'VSubMenu') {
32 | let selected = false
33 | const deepNode = (childNodes) => {
34 | childNodes.forEach((childNode) => {
35 | if (childNode.$options.name === 'VMenuItem') {
36 | childNode.selected = childNode.index === this.state.selectedIndex
37 | if (childNode.selected) selected = true
38 | } else {
39 | deepNode(childNode.$children)
40 | }
41 | })
42 | }
43 | deepNode(node.$children)
44 | node.selected = selected
45 | deepNodes(node.$children)
46 | } else {
47 | deepNodes(node.$children)
48 | }
49 | })
50 | }
51 |
52 | deepNodes(this.component.$children)
53 | if (item) {
54 | if (this.state.router) this.component.$router.push({ name: this.state.selectedIndex })
55 | this.component.$emit('onSelect', this.state.selectedIndex, item)
56 | }
57 | }
58 |
59 | openChange() {
60 | const deepNodes = (nodes) => {
61 | nodes.forEach((node) => {
62 | if (node.$options.name === 'VSubMenu') {
63 | node.opened = this.state.openIndexs.indexOf(node.index) > -1
64 | }
65 | deepNodes(node.$children)
66 | })
67 | }
68 | deepNodes(this.component.$children)
69 | this.component.$emit('onOpenChange', this.state.openIndexs)
70 | }
71 | }
72 |
73 | class Store extends BaseStore {
74 | constructor(component, initialState = {}) {
75 | super(component, initialState)
76 |
77 | this.state = {
78 | ENUM_MODE: {
79 | VERTICAL: 'vertical',
80 | HORIZONTAL: 'horizontal',
81 | INLINE: 'inline'
82 | },
83 | uniqueOpened: false,
84 | openIndexs: [],
85 | selectedIndex: '',
86 | router: false
87 | }
88 | this.setState(initialState)
89 |
90 | this.mutations = new Mutations()
91 | }
92 | }
93 |
94 | export default Store
95 |
--------------------------------------------------------------------------------
/components/menu/sub-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
119 |
--------------------------------------------------------------------------------
/components/message/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Message from './message'
4 |
5 | export default Message
6 |
--------------------------------------------------------------------------------
/components/message/message.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | import VNodes from './nodes'
4 |
5 | const VMessage = Vue.extend(VNodes)
6 |
7 | let instance
8 | let instancePool = [] // 保持生成的实例用于destroy
9 | let defaultDuration = 1.5 // 自动关闭延时
10 | let defaultTop = 16 // 消息距离顶部的位置
11 | const noop = () => {
12 | }
13 |
14 | function getInstance() {
15 | if (instance) return instance
16 | const message = new VMessage()
17 | message.top = defaultTop
18 | instance = message.$mount()
19 | instancePool.push(instance)
20 | document.body.appendChild(instance.$el)
21 | return instance
22 | }
23 |
24 | class Message {
25 | static config({ top = defaultTop, duration = defaultDuration }) {
26 | // 对比新旧实例的配置,配置改变了需删除旧的
27 | if (instance && instance.top !== top) {
28 | instance = null
29 | }
30 | defaultTop = top
31 | defaultDuration = duration
32 | }
33 |
34 | static destroy() {
35 | if (instancePool.length) {
36 | instancePool.forEach((_instance) => {
37 | _instance.visible = false
38 | _instance.$nextTick(() => {
39 | _instance.$destroy()
40 | _instance = null
41 | })
42 | })
43 | instance = null
44 | instancePool = []
45 | }
46 | }
47 | }
48 |
49 | ['info', 'success', 'error', 'warning', 'loading'].forEach((type) => {
50 | Message[type] = (content, duration = defaultDuration, onClose = noop) => {
51 | getInstance().add({ type, content, duration, onClose })
52 | }
53 | })
54 |
55 |
56 | export default Message
57 |
--------------------------------------------------------------------------------
/components/message/node.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'VNode',
3 |
4 | props: {
5 | index: String,
6 | content: String,
7 | duration: Number,
8 | type: {
9 | type: String,
10 | default: 'info'
11 | },
12 | onClose: Function
13 | },
14 |
15 | render() {
16 | return (
17 |
18 |
19 |
20 |
21 | { this.content }
22 |
23 |
24 |
25 | )
26 | },
27 |
28 | mounted() {
29 | if (this.duration) {
30 | setTimeout(() => {
31 | this.$parent.remove(this.index)
32 | if (this.onClose) {
33 | this.$nextTick(() => {
34 | this.onClose.call(this, this.index)
35 | })
36 | }
37 | }, this.duration * 1000)
38 | }
39 | },
40 |
41 | computed: {
42 | iconCls() {
43 | const icon = {
44 | info: 'info',
45 | success: 'check',
46 | warning: 'exclamation',
47 | error: 'cross'
48 | }[this.type]
49 | return {
50 | [`anticon-${icon}-circle`]: !!icon,
51 | 'anticon-spin anticon-loading': this.type === 'loading'
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/components/message/nodes.js:
--------------------------------------------------------------------------------
1 | import VNode from './node'
2 |
3 | let seed = 0
4 | const now = Date.now()
5 |
6 | function getUuid() {
7 | return `message_${now}_${seed++}`
8 | }
9 |
10 | export default {
11 | name: 'VNodes',
12 |
13 | data() {
14 | return {
15 | top: 24,
16 | nodes: [],
17 | visible: true
18 | }
19 | },
20 |
21 | methods: {
22 | add(node) {
23 | node.index = getUuid()
24 | if (this.nodes.some(n => n.index === node.index)) return
25 | this.nodes.push(node)
26 | },
27 |
28 | remove(index) {
29 | this.nodes = this.nodes.filter(node => node.index !== index)
30 | }
31 | },
32 |
33 | render() {
34 | const vnodes = this.nodes.map(node =>
35 | (()))
36 | const vm = (
37 | {vnodes}
38 |
)
39 | return (this.visible ? vm : null)
40 | },
41 |
42 | components: {
43 | VNode
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/components/message/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 |
3 | @message-prefix-cls: ~"@{ant-prefix}-message";
4 |
5 | .@{message-prefix-cls} {
6 | font-size: @font-size-base;
7 | position: fixed;
8 | z-index: @zindex-message;
9 | width: 100%;
10 | top: 16px;
11 | left: 0;
12 | pointer-events: none;
13 |
14 | &-notice {
15 | padding: 8px;
16 | text-align: center;
17 | &:first-child {
18 | margin-top: -8px;
19 | }
20 | }
21 |
22 | &-notice-content {
23 | padding: 8px 16px;
24 | border-radius: @border-radius-base;
25 | box-shadow: @shadow-2;
26 | background: @component-background;
27 | display: inline-block;
28 | pointer-events: all;
29 | }
30 |
31 | &-success .@{iconfont-css-prefix} {
32 | color: @success-color;
33 | }
34 |
35 | &-error .@{iconfont-css-prefix} {
36 | color: @error-color;
37 | }
38 |
39 | &-warning .@{iconfont-css-prefix} {
40 | color: @warning-color;
41 | }
42 |
43 | &-info .@{iconfont-css-prefix},
44 | &-loading .@{iconfont-css-prefix} {
45 | color: @primary-color;
46 | }
47 |
48 | .@{iconfont-css-prefix} {
49 | margin-right: 8px;
50 | font-size: @font-size-lg;
51 | top: 1px;
52 | position: relative;
53 | }
54 |
55 | &-notice.move-up-leave.move-up-leave-active {
56 | animation-name: MessageMoveOut;
57 | overflow: hidden;
58 | animation-duration: .3s;
59 | }
60 | }
61 |
62 | @keyframes MessageMoveOut {
63 | 0% {
64 | opacity: 1;
65 | max-height: 150px;
66 | padding: 8px;
67 | }
68 | 100% {
69 | opacity: 0;
70 | max-height: 0;
71 | padding: 0;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/components/modal/confirm.js:
--------------------------------------------------------------------------------
1 | import Modal from './modal'
2 |
3 | export default {
4 | props: {
5 | title: [String, Object],
6 | content: [String, Object],
7 | okText: {
8 | type: String,
9 | default: '确定'
10 | },
11 | cancelText: {
12 | type: String,
13 | default: '取消'
14 | },
15 | maskClosable: {
16 | type: Boolean,
17 | default: false
18 | },
19 | width: {
20 | type: Number,
21 | default: 416
22 | },
23 | type: {
24 | type: String,
25 | default: 'confirm'
26 | },
27 | iconType: {
28 | type: String,
29 | default: 'question-circle'
30 | },
31 | okCancel: {
32 | type: Boolean,
33 | default: false
34 | },
35 | onOk: Function,
36 | onCancel: Function
37 | },
38 |
39 | data() {
40 | return {
41 | visible: false
42 | }
43 | },
44 |
45 | render() {
46 | const modalData = {
47 | ref: 'modal',
48 | props: {
49 | value: this.visible,
50 | title: null,
51 | closable: false,
52 | footer: null,
53 | wrapClassName: `ant-confirm ant-confirm-${this.type}`,
54 | ...this.$props
55 | },
56 | on: {
57 | onCancel: this.close.bind(this, 'cancel'),
58 | afterClose: this.afterClose
59 | }
60 | }
61 |
62 | return (
63 |
64 |
65 |
66 | {this.title}
67 | {this.content}
68 |
69 |
70 | {this.okCancel ?
71 | Cancel : null}
72 | Ok
73 |
74 |
75 | )
76 | },
77 |
78 | mounted() {
79 | document.body.appendChild(this.$el)
80 | this.visible = true
81 | },
82 |
83 | methods: {
84 | close(type) {
85 | this.visible = false
86 | if (type === 'cancel' && this.onCancel) {
87 | this.onCancel()
88 | } else if (type === 'ok' && this.onOk) {
89 | this.onOk()
90 | }
91 | },
92 |
93 | afterClose() {
94 | document.body.removeChild(this.$el)
95 | this.$destroy()
96 | }
97 | },
98 |
99 | components: {
100 | Modal
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/components/modal/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | import '../style/index.less'
4 | import './style/index.less'
5 |
6 | // style dependencies
7 | import '../button/style/index.less'
8 |
9 |
10 | import Modal from './modal'
11 | import Confirm from './confirm'
12 |
13 | const VConfirm = Vue.extend(Confirm)
14 |
15 | function getInstance(props) {
16 | const confirm = new VConfirm()
17 | Object.assign(confirm, props)
18 | return confirm.$mount()
19 | }
20 |
21 | Modal.confirm = function (props = {}) {
22 | props.okCancel = true
23 | return getInstance(props)
24 | }
25 |
26 | Modal.info = function (props = {}) {
27 | props.type = 'info'
28 | props.iconType = 'info-circle'
29 | return getInstance(props)
30 | }
31 |
32 | Modal.success = function (props = {}) {
33 | props.type = 'success'
34 | props.iconType = 'check-circle'
35 | return getInstance(props)
36 | }
37 |
38 | Modal.error = function (props = {}) {
39 | props.type = 'error'
40 | props.iconType = 'cross-circle'
41 | return getInstance(props)
42 | }
43 |
44 | Modal.warning = function (props = {}) {
45 | props.type = 'warning'
46 | props.iconType = 'exclamation-circle'
47 | return getInstance(props)
48 | }
49 |
50 | export default Modal
51 |
--------------------------------------------------------------------------------
/components/modal/style/confirm.less:
--------------------------------------------------------------------------------
1 | @import "../../style/mixins/index";
2 |
3 | @confirm-prefix-cls: ~"@{ant-prefix}-confirm";
4 |
5 | .@{confirm-prefix-cls} {
6 | .@{ant-prefix}-modal-header {
7 | display: none;
8 | }
9 |
10 | .@{ant-prefix}-modal-close {
11 | display: none;
12 | }
13 |
14 | .@{ant-prefix}-modal-body {
15 | padding: 30px 40px;
16 | }
17 |
18 | &-body-wrapper {
19 | .clearfix();
20 | }
21 |
22 | &-body {
23 | .@{confirm-prefix-cls}-title {
24 | color: @text-color;
25 | font-weight: bold;
26 | font-size: @font-size-lg;
27 | }
28 |
29 | .@{confirm-prefix-cls}-content {
30 | margin-left: 42px;
31 | font-size: @font-size-base;
32 | color: @text-color;
33 | margin-top: 8px;
34 | }
35 |
36 | > .@{iconfont-css-prefix} {
37 | font-size: 24px;
38 | margin-right: 16px;
39 | padding: 0 1px;
40 | float: left;
41 | }
42 | }
43 |
44 | .@{confirm-prefix-cls}-btns {
45 | margin-top: 30px;
46 | float: right;
47 |
48 | button + button {
49 | margin-left: 10px;
50 | margin-bottom: 0;
51 | }
52 | }
53 |
54 | &-error &-body > .@{iconfont-css-prefix} {
55 | color: @error-color;
56 | }
57 |
58 | &-warning &-body > .@{iconfont-css-prefix},
59 | &-confirm &-body > .@{iconfont-css-prefix} {
60 | color: @warning-color;
61 | }
62 |
63 | &-info &-body > .@{iconfont-css-prefix} {
64 | color: @primary-color;
65 | }
66 |
67 | &-success &-body > .@{iconfont-css-prefix} {
68 | color: @success-color;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/components/modal/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "./modal";
3 | @import "./confirm";
4 |
--------------------------------------------------------------------------------
/components/modal/style/modal.less:
--------------------------------------------------------------------------------
1 | @dialog-prefix-cls: ~"@{ant-prefix}-modal";
2 |
3 | .@{dialog-prefix-cls} {
4 | position: relative;
5 | width: auto;
6 | margin: 0 auto;
7 | top: 100px;
8 | padding-bottom: 24px;
9 |
10 | &-wrap {
11 | position: fixed;
12 | overflow: auto;
13 | top: 0;
14 | right: 0;
15 | bottom: 0;
16 | left: 0;
17 | z-index: @zindex-modal;
18 | -webkit-overflow-scrolling: touch;
19 | outline: 0;
20 | }
21 |
22 | &-title {
23 | margin: 0;
24 | font-size: @font-size-lg;
25 | line-height: 21px;
26 | font-weight: bold;
27 | }
28 |
29 | &-content {
30 | position: relative;
31 | background-color: @component-background;
32 | border: 0;
33 | border-radius: @border-radius-base;
34 | background-clip: padding-box;
35 | box-shadow: @shadow-2;
36 | }
37 |
38 | &-close {
39 | cursor: pointer;
40 | border: 0;
41 | background: transparent;
42 | position: absolute;
43 | right: 16px;
44 | top: 16px;
45 | z-index: 10;
46 | font-weight: 700;
47 | line-height: 1;
48 | text-decoration: none;
49 | transition: color .3s ease;
50 | color: @text-color-secondary;
51 | outline: 0;
52 |
53 | &-x {
54 | display: block;
55 | font-style: normal;
56 | vertical-align: baseline;
57 | text-align: center;
58 | text-transform: none;
59 | text-rendering: auto;
60 | width: 14px;
61 | height: 14px;
62 | font-size: @font-size-lg;
63 | line-height: 1;
64 |
65 | &:before {
66 | content: "\e633";
67 | display: block;
68 | font-family: "anticon" !important;
69 | }
70 | }
71 |
72 | &:focus,
73 | &:hover {
74 | color: #444;
75 | text-decoration: none;
76 | }
77 | }
78 |
79 | &-header {
80 | padding: 14px 16px;
81 | border-radius: @border-radius-base @border-radius-base 0 0;
82 | background: @component-background;
83 | color: @text-color;
84 | border-bottom: @border-width-base @border-style-base @border-color-split;
85 | }
86 |
87 | &-body {
88 | padding: 16px;
89 | font-size: @font-size-base;
90 | line-height: 1.5;
91 | }
92 |
93 | &-footer {
94 | border-top: @border-width-base @border-style-base @border-color-split;
95 | padding: 10px 16px 10px 10px;
96 | text-align: right;
97 | border-radius: 0 0 @border-radius-base @border-radius-base;
98 | button + button {
99 | margin-left: 8px;
100 | margin-bottom: 0;
101 | }
102 | }
103 |
104 | &.zoom-enter,
105 | &.zoom-appear {
106 | animation-duration: @animation-duration-slow;
107 | transform: none; // reset scale avoid mousePosition bug
108 | opacity: 0;
109 | }
110 |
111 | &-mask {
112 | position: fixed;
113 | top: 0;
114 | right: 0;
115 | left: 0;
116 | bottom: 0;
117 | background-color: #373737;
118 | background-color: rgba(55, 55, 55, 0.6); // lesshint duplicateProperty: false
119 | height: 100%;
120 | z-index: @zindex-modal-mask;
121 | filter: ~"alpha(opacity=50)";
122 |
123 | &-hidden {
124 | display: none;
125 | }
126 | }
127 |
128 | &-open {
129 | overflow: hidden;
130 | }
131 | }
132 |
133 | @media (max-width: 768px) {
134 | .@{dialog-prefix-cls} {
135 | width: auto !important;
136 | margin: 10px;
137 | }
138 | .vertical-center-modal {
139 | .@{dialog-prefix-cls} {
140 | flex: 1;
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/components/notification/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Message from './notification'
4 |
5 | export default Message
6 |
--------------------------------------------------------------------------------
/components/notification/node.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'VNode',
3 |
4 | props: {
5 | index: String,
6 | icon: [String, Object],
7 | message: [String, Object],
8 | description: String,
9 | duration: Number,
10 | type: {
11 | type: String,
12 | default: 'open'
13 | },
14 | onClose: Function
15 | },
16 |
17 | render() {
18 | return (
19 |
20 |
21 |
22 | {this.vicon ?
{this.vicon} : null}
23 |
{ this.message }
24 |
{ this.description }
25 |
26 |
27 |
29 |
30 | )
31 | },
32 |
33 | mounted() {
34 | if (this.duration) {
35 | this.closeTimer = setTimeout(this.close, this.duration * 1000)
36 | }
37 | },
38 |
39 | computed: {
40 | vicon() {
41 | if (this.icon) return this.icon
42 | return this.type !== 'open' ? () : ''
43 | },
44 |
45 | iconCls() {
46 | const icon = {
47 | info: 'info',
48 | success: 'check',
49 | warning: 'exclamation',
50 | error: 'cross'
51 | }[this.type]
52 | return {
53 | [`anticon-${icon}-circle-o ant-notification-notice-icon ant-notification-notice-icon-${this.type}`]: !!icon,
54 | 'anticon-spin anticon-loading': this.type === 'loading'
55 | }
56 | }
57 | },
58 |
59 | methods: {
60 | clearCloseTimer() {
61 | if (this.closeTimer) {
62 | clearTimeout(this.closeTimer)
63 | this.closeTimer = null
64 | }
65 | },
66 |
67 | close() {
68 | this.clearCloseTimer()
69 | this.$parent.remove(this.index)
70 | if (this.onClose) {
71 | this.$nextTick(() => {
72 | this.onClose.call(this, this.index)
73 | })
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/components/notification/nodes.js:
--------------------------------------------------------------------------------
1 | import VNode from './node'
2 |
3 | let seed = 0
4 | const now = Date.now()
5 |
6 | function getUuid() {
7 | return `notification_${now}_${seed++}`
8 | }
9 |
10 | export default {
11 | name: 'VNodes',
12 |
13 | data() {
14 | return {
15 | top: 24,
16 | bottom: 24,
17 | placement: 'topRight',
18 | nodes: [],
19 | visible: true
20 | }
21 | },
22 |
23 | methods: {
24 | add(node) {
25 | this.placement = node.placement
26 | node.index = getUuid()
27 | if (this.nodes.some(n => n.index === node.index)) return
28 | this.nodes.push(node)
29 | },
30 |
31 | remove(index) {
32 | this.nodes = this.nodes.filter(node => node.index !== index)
33 | }
34 | },
35 |
36 | computed: {
37 | /**
38 | * 将placement转换为页面上四个角的位置
39 | * @returns {*}
40 | */
41 | getPlacementStyle() {
42 | let style
43 | switch (this.placement) {
44 | case 'topLeft':
45 | style = {
46 | left: 0,
47 | top: `${this.top}px`,
48 | bottom: 'auto'
49 | }
50 | break
51 | case 'bottomLeft':
52 | style = {
53 | left: 0,
54 | top: 'auto',
55 | bottom: `${this.bottom}px`
56 | }
57 | break
58 | case 'bottomRight':
59 | style = {
60 | right: 0,
61 | top: 'auto',
62 | bottom: `${this.bottom}px`
63 | }
64 | break
65 | default:
66 | style = {
67 | right: 0,
68 | top: `${this.top}px`,
69 | bottom: 'auto'
70 | }
71 | }
72 | return style
73 | },
74 |
75 | vdata() {
76 | return {
77 | class: [`ant-notification-${this.placement}`],
78 | style: this.getPlacementStyle
79 | }
80 | }
81 | },
82 |
83 | render() {
84 | // 每个node增加key属性,每次nodes数据变化时强制替换组件,避免vue重复使用组件导致组件内使用setTimeout时引用错误
85 | const vnodes = this.nodes.map(node =>
86 | (()))
87 | const vm = (
88 |
89 | {vnodes}
90 |
)
91 | return (this.visible ? vm : null)
92 | },
93 |
94 | components: {
95 | VNode
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/components/notification/notification.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | import VNodes from './nodes'
4 |
5 | const VNotification = Vue.extend(VNodes)
6 |
7 | let instance
8 | let instancePool = [] // 保持生成的实例用于destroy
9 | let defaultDuration = 4.5 // 自动关闭延时
10 | let defaultTop = 24 // 消息距离顶部的位置
11 | let defaultBottom = 24 // 消息距离底部的位置
12 | let defaultPlacement = 'topRight' // 弹出位置,可选 topLeft topRight bottomLeft bottomRight
13 | const noop = () => {
14 | }
15 |
16 | function getInstance() {
17 | if (instance) return instance
18 | const notification = new VNotification()
19 | notification.top = defaultTop
20 | notification.bottom = defaultBottom
21 | notification.placement = defaultPlacement
22 | instance = notification.$mount()
23 | instancePool.push(instance)
24 | document.body.appendChild(instance.$el)
25 | return instance
26 | }
27 |
28 | class Notification {
29 | static config({
30 | top = defaultTop,
31 | bottom = defaultBottom,
32 | placement = defaultPlacement,
33 | duration = defaultDuration
34 | }) {
35 | // 对比新旧实例的配置,配置改变了需删除旧的
36 | if (instance &&
37 | (instance.top !== top || instance.bottom !== bottom || instance.placement !== placement)) {
38 | instance = null
39 | }
40 | defaultTop = top
41 | defaultBottom = bottom
42 | defaultPlacement = placement
43 | defaultDuration = duration
44 | }
45 |
46 | static destroy() {
47 | if (instancePool.length) {
48 | instancePool.forEach((_instance) => {
49 | _instance.visible = false
50 | _instance.$nextTick(() => {
51 | _instance.$destroy()
52 | _instance = null
53 | })
54 | })
55 | instance = null
56 | instancePool = []
57 | }
58 | }
59 | }
60 |
61 | ['open', 'info', 'success', 'error', 'warning'].forEach((type) => {
62 | Notification[type] = ({
63 | icon,
64 | message,
65 | description,
66 | duration = defaultDuration,
67 | placement = defaultPlacement,
68 | onClose = noop
69 | }) => {
70 | // 若旧实例的位置和新实例的位置不同,需删除旧的
71 | if (instance && instance.placement !== placement) {
72 | instance = null
73 | }
74 | getInstance().add({ type, icon, message, description, duration, placement, onClose })
75 | }
76 | })
77 |
78 | export default Notification
79 |
--------------------------------------------------------------------------------
/components/notification/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 |
4 | @notification-prefix-cls: ~"@{ant-prefix}-notification";
5 | @notification-width: 335px;
6 | @notification-padding: 16px;
7 | @notification-margin-bottom: 10px;
8 |
9 | .@{notification-prefix-cls} {
10 | position: fixed;
11 | z-index: @zindex-notification;
12 | width: @notification-width;
13 | margin-right: 24px;
14 |
15 | &-topLeft,
16 | &-bottomLeft {
17 | margin-left: 24px;
18 | margin-right: 0;
19 |
20 | .@{notification-prefix-cls}-fade-enter.@{notification-prefix-cls}-fade-enter-active,
21 | .@{notification-prefix-cls}-fade-appear.@{notification-prefix-cls}-fade-appear-active {
22 | animation-name: NotificationLeftFadeIn;
23 | }
24 | }
25 |
26 | &-notice {
27 | padding: @notification-padding;
28 | border-radius: @border-radius-base;
29 | box-shadow: @shadow-2;
30 | background: @component-background;
31 | line-height: 1.5;
32 | position: relative;
33 | margin-bottom: @notification-margin-bottom;
34 | overflow: hidden;
35 |
36 | &-message {
37 | font-size: @font-size-lg;
38 | color: @heading-color;
39 | margin-bottom: 4px;
40 | line-height: 20px;
41 | }
42 |
43 | &-description {
44 | font-size: @font-size-base;
45 | }
46 |
47 | &-closable &-message {
48 | padding-right: 24px;
49 | }
50 |
51 | &-with-icon &-message {
52 | font-size: @font-size-lg;
53 | margin-left: 48px;
54 | margin-bottom: 4px;
55 | }
56 |
57 | &-with-icon &-description {
58 | margin-left: 48px;
59 | font-size: @font-size-base;
60 | }
61 |
62 | &-icon {
63 | float: left;
64 | font-size: 32px;
65 | line-height: 32px;
66 |
67 | &-success {
68 | color: @success-color;
69 | }
70 | &-info {
71 | color: @primary-color;
72 | }
73 | &-warning {
74 | color: @warning-color;
75 | }
76 | &-error {
77 | color: @error-color;
78 | }
79 | }
80 |
81 | &-close-x:after {
82 | font-size: @font-size-base;
83 | content: "\e633";
84 | font-family: "anticon";
85 | cursor: pointer;
86 | }
87 |
88 | &-close {
89 | position: absolute;
90 | right: 16px;
91 | top: 10px;
92 | color: @text-color-secondary;
93 | outline: none;
94 | &:hover {
95 | color: #404040;
96 | }
97 | }
98 |
99 | &-btn {
100 | float: right;
101 | margin-top: 16px;
102 | }
103 | }
104 |
105 | .notification-fade-effect {
106 | animation-duration: 0.24s;
107 | animation-fill-mode: both;
108 | animation-timing-function: @ease-in-out;
109 | }
110 |
111 | &-fade-enter,
112 | &-fade-appear {
113 | opacity: 0;
114 | .notification-fade-effect();
115 | animation-play-state: paused;
116 | }
117 |
118 | &-fade-leave {
119 | .notification-fade-effect();
120 | animation-duration: 0.2s;
121 | animation-play-state: paused;
122 | }
123 |
124 | &-fade-enter&-fade-enter-active,
125 | &-fade-appear&-fade-appear-active {
126 | animation-name: NotificationFadeIn;
127 | animation-play-state: running;
128 | }
129 |
130 | &-fade-leave&-fade-leave-active {
131 | animation-name: NotificationFadeOut;
132 | animation-play-state: running;
133 | }
134 | }
135 |
136 | @keyframes NotificationFadeIn {
137 | 0% {
138 | opacity: 0;
139 | left: @notification-width;
140 | }
141 | 100% {
142 | left: 0;
143 | opacity: 1;
144 | }
145 | }
146 |
147 | @keyframes NotificationLeftFadeIn {
148 | 0% {
149 | opacity: 0;
150 | right: @notification-width;
151 | }
152 | 100% {
153 | right: 0;
154 | opacity: 1;
155 | }
156 | }
157 |
158 | @keyframes NotificationFadeOut {
159 | 0% {
160 | opacity: 1;
161 | margin-bottom: @notification-margin-bottom;
162 | padding-top: @notification-padding;
163 | padding-bottom: @notification-padding;
164 | max-height: 150px;
165 | }
166 | 100% {
167 | opacity: 0;
168 | margin-bottom: 0;
169 | padding-top: 0;
170 | padding-bottom: 0;
171 | max-height: 0;
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/components/pagination/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Pagination from './pagination'
4 |
5 | export default Pagination
6 |
--------------------------------------------------------------------------------
/components/pagination/mixins.js:
--------------------------------------------------------------------------------
1 | import KEYCODE from '../utils/keycode'
2 |
3 | export default {
4 | props: {
5 | page: Number,
6 | allPages: Number
7 | },
8 |
9 | methods: {
10 | onKeyDown(e) {
11 | const key = e.keyCode
12 | if (!((!e.shiftKey && (key >= KEYCODE.ZERO &&
13 | key <= KEYCODE.NINE)) ||
14 | key === KEYCODE.LEFT ||
15 | key === KEYCODE.RIGHT ||
16 | key === KEYCODE.DELETE ||
17 | key === KEYCODE.BACKSPACE)) {
18 | e.preventDefault()
19 | }
20 | },
21 |
22 | onKeyUp(e) {
23 | const _val = e.target.value
24 | let val
25 |
26 | if (_val === '') {
27 | val = _val
28 | } else if (isNaN(Number(_val))) {
29 | val = this.page
30 | } else {
31 | val = Number(_val)
32 | }
33 |
34 | if (e.keyCode === KEYCODE.ENTER) {
35 | this.handleChange(val)
36 | } else if (e.keyCode === KEYCODE.UP) {
37 | this.handleChange(val - 1)
38 | } else if (e.keyCode === KEYCODE.DOWN) {
39 | this.handleChange(val + 1)
40 | }
41 | },
42 |
43 | handleChange(page) {
44 | this.$emit('onChange', page)
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/components/pagination/options.js:
--------------------------------------------------------------------------------
1 | import Mixins from './mixins'
2 |
3 | export default {
4 | name: 'VOptions',
5 |
6 | mixins: [Mixins],
7 |
8 | props: {
9 | showQuickJumper: Boolean,
10 | showSizeChanger: Boolean,
11 | pageSizeOptions: Array,
12 | pageSize: Number,
13 | size: String
14 | },
15 |
16 | data() {
17 | return {
18 | currentPageSize: this.pageSize
19 | }
20 | },
21 |
22 | render() {
23 | const options = this.pageSizeOptions.map(size =>
24 | ({size} / page))
25 | return ()
48 | },
49 |
50 | methods: {
51 | onSelect(option) {
52 | this.$emit('onSizeChange', option)
53 | console.log(option)
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/components/pagination/pager.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'VPager',
3 |
4 | props: {
5 | page: {
6 | type: Number,
7 | default: 1
8 | },
9 | allPages: Number
10 | },
11 |
12 | render() {
13 | const { page, allPages } = this
14 | const pagers = []
15 | const pageBufferSize = 2
16 |
17 | if (allPages < 5 + (pageBufferSize * 2)) {
18 | for (let i = 1; i <= allPages; i++) {
19 | pagers.push(i)
20 | }
21 | } else {
22 | let left = Math.max(2, page - pageBufferSize)
23 | let right = Math.min(page + pageBufferSize, allPages - 1)
24 |
25 | if (page + pageBufferSize > allPages) {
26 | left = allPages - (pageBufferSize * 2)
27 | }
28 |
29 | if (page - pageBufferSize <= 0) {
30 | right = 1 + (pageBufferSize * 2)
31 | }
32 | pagers.push(1)
33 | if (left - pageBufferSize >= 1 && left !== 2) {
34 | pagers.push('prev')
35 | }
36 |
37 | for (let i = left; i <= right; i++) {
38 | pagers.push(i)
39 | }
40 |
41 | if (right + pageBufferSize <= allPages && right !== allPages - 1) {
42 | pagers.push('next')
43 | }
44 | pagers.push(allPages)
45 | }
46 |
47 | const pagerVM = pagers.map((pager) => {
48 | if (pager === 'prev' || pager === 'next') {
49 | const nextPrevData = {
50 | class: `ant-pagination-jump-${pager}`,
51 | on: {
52 | click: this.jumpNextPrev.bind(this, pager)
53 | }
54 | }
55 | return ()
56 | }
57 | const pagerData = {
58 | class: [
59 | [`ant-pagination-item-${pager}`],
60 | {
61 | 'ant-pagination-item-active': page === pager
62 | }
63 | ],
64 | on: {
65 | click: this.onChange.bind(this, pager)
66 | }
67 | }
68 | return ()
69 | })
70 | return ()
71 | },
72 |
73 | methods: {
74 | onChange(page) {
75 | this.$emit('onChange', page)
76 | },
77 |
78 | jumpNextPrev(page) {
79 | let jumpPage = page
80 | if (page === 'prev') {
81 | jumpPage = Math.max(1, this.page - 5)
82 | } else {
83 | jumpPage = Math.min(this.allPages, this.page + 5)
84 | }
85 | this.onChange(jumpPage)
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/components/pagination/pagination.js:
--------------------------------------------------------------------------------
1 | import VPager from './pager'
2 | import VOptions from './options'
3 | import VSimplePager from './simple-pager'
4 |
5 | export default {
6 | name: 'VPagination',
7 |
8 | props: {
9 | value: {
10 | type: Number,
11 | default: 1
12 | },
13 | total: Number,
14 | size: {
15 | type: String,
16 | default: ''
17 | },
18 | pageSize: {
19 | type: Number,
20 | default: 10
21 | },
22 | simple: {
23 | type: Boolean,
24 | default: false
25 | },
26 | showSizeChanger: {
27 | type: Boolean,
28 | default: false
29 | },
30 | showQuickJumper: {
31 | type: Boolean,
32 | default: false
33 | },
34 | showTotal: Function,
35 | pageSizeOptions: {
36 | type: Array,
37 | default() {
38 | return ['10', '20', '30', '40']
39 | }
40 | }
41 | },
42 |
43 | data() {
44 | return {
45 | currentPage: this.value,
46 | currentPageSize: this.pageSize,
47 | inputValue: this.value
48 | }
49 | },
50 |
51 | render() {
52 | const { simple, currentPage, pageSize, total, allPages, showTotal } = this
53 | const pagerData = {
54 | props: {
55 | allPages,
56 | page: currentPage
57 | },
58 | on: {
59 | onChange: this.handleChange
60 | }
61 | }
62 |
63 | let pager = null
64 |
65 | if (simple) {
66 | pager = ()
67 | } else {
68 | pager = ()
69 | }
70 |
71 | const optionsData = {
72 | props: {
73 | page: currentPage,
74 | ...this.$props
75 | },
76 | on: {
77 | onChange: this.handleChange,
78 | onSizeChange: this.onSizeChange
79 | }
80 | }
81 |
82 | const paginationData = {
83 | class: {
84 | mini: this.size === 'small',
85 | 'ant-pagination-simple': this.simple
86 | }
87 | }
88 |
89 | let totalText
90 | if (showTotal) {
91 | totalText = (
92 | )
99 | }
100 |
101 | return ()
116 | },
117 |
118 | computed: {
119 | allPages() {
120 | return Math.ceil(this.total / this.currentPageSize)
121 | }
122 | },
123 |
124 | methods: {
125 | onSizeChange(pageSize) {
126 | this.currentPageSize = pageSize
127 | this.currentPage = this.currentPage > this.allPages ? this.allPages : this.currentPage
128 | this.$emit('onShowSizeChange', this.currentPage, pageSize)
129 | },
130 |
131 | prev() {
132 | if (!this.hasPrev()) return
133 | this.handleChange(this.currentPage - 1)
134 | },
135 | next() {
136 | if (!this.hasNext()) return
137 | this.handleChange(this.currentPage + 1)
138 | },
139 | hasPrev() {
140 | return this.currentPage > 1
141 | },
142 | hasNext() {
143 | return this.currentPage < this.allPages
144 | },
145 | handleChange(page) {
146 | if (this.isValid(page)) {
147 | if (page > this.allPages) {
148 | page = this.allPages
149 | }
150 |
151 | this.currentPage = page
152 | this.inputValue = page
153 | this.$emit('input', page)
154 | this.$emit('onChange', page, this.pageSize)
155 |
156 | return page
157 | }
158 |
159 | return this.currentPage
160 | },
161 |
162 | isValid(page) {
163 | return typeof page === 'number' && page >= 1 && page !== this.currentPage
164 | }
165 | },
166 |
167 | components: {
168 | VPager,
169 | VOptions,
170 | VSimplePager
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/components/pagination/simple-pager.js:
--------------------------------------------------------------------------------
1 | import Mixins from './mixins'
2 |
3 | export default {
4 | name: 'VSimplePager',
5 |
6 | mixins: [Mixins],
7 |
8 | render() {
9 | return (
10 | )
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/components/popconfirm/index.js:
--------------------------------------------------------------------------------
1 | import Popconfirm from './popconfirm'
2 |
3 | export default Popconfirm
4 |
--------------------------------------------------------------------------------
/components/popconfirm/popconfirm.js:
--------------------------------------------------------------------------------
1 | import '../popover/style/index.less'
2 | import '../button/style/index.less'
3 |
4 | import TooltipMixin from '../mixins/tooltip'
5 |
6 | export default {
7 | name: 'VPopconfirm',
8 |
9 | mixins: [TooltipMixin],
10 |
11 | props: {
12 | okText: {
13 | type: String,
14 | default: 'Yes'
15 | },
16 | cancelText: {
17 | type: String,
18 | default: 'No'
19 | },
20 | trigger: {
21 | type: String,
22 | default: 'click'
23 | }
24 | },
25 |
26 | data() {
27 | return {
28 | prefixCls: 'ant-popover'
29 | }
30 | },
31 |
32 | methods: {
33 | onConfirm(e) {
34 | this.closePopper()
35 | this.$emit('onConfirm', e)
36 | },
37 |
38 | onCancel(e) {
39 | this.closePopper()
40 | this.$emit('onCancel', e)
41 | }
42 | },
43 |
44 | components: {
45 | /**
46 | * 定义函数化组件用于插入到popperVM
47 | * 实际浮层显示的内容
48 | */
49 | VTooltipContent: {
50 | functional: true,
51 |
52 | render(h, context) {
53 | const data = context.data
54 | return (
55 |
56 |
57 |
58 |
59 |
60 |
{ data.title || data.$slots.title}
61 |
62 |
63 |
65 | { data.cancelText }
66 |
67 |
69 | { data.okText }
70 |
71 |
72 |
73 |
74 |
)
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/components/popover/index.js:
--------------------------------------------------------------------------------
1 | import Popover from './popover'
2 |
3 | export default Popover
4 |
--------------------------------------------------------------------------------
/components/popover/popover.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 | import TooltipMixin from '../mixins/tooltip'
3 |
4 | export default {
5 | name: 'VPopover',
6 |
7 | mixins: [TooltipMixin],
8 |
9 | props: {
10 | content: [String, Object]
11 | },
12 |
13 | data() {
14 | return {
15 | prefixCls: 'ant-popover'
16 | }
17 | },
18 |
19 | components: {
20 | /**
21 | * 定义函数化组件用于插入到popperVM
22 | * 实际浮层显示的内容
23 | */
24 | VTooltipContent: {
25 | functional: true,
26 |
27 | render(h, context) {
28 | const data = context.data
29 | return (
30 |
31 |
32 |
{ data.title || data.$slots.title}
33 |
{ data.content || data.$slots.content}
34 |
35 |
)
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/components/radio/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Radio from './radio'
4 | import RadioButton from './radio-button'
5 | import RadioGroup from './radio-group'
6 |
7 | Radio.RadioButton = RadioButton
8 | Radio.Group = RadioGroup
9 | export default Radio
10 |
--------------------------------------------------------------------------------
/components/radio/radio-button.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
43 |
44 |
--------------------------------------------------------------------------------
/components/radio/radio-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
42 |
--------------------------------------------------------------------------------
/components/radio/radio-mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | value: [String, Number, Boolean],
4 | label: [String, Number, Boolean],
5 | disabled: Boolean
6 | },
7 |
8 | data() {
9 | return {
10 | store: {}
11 | }
12 | },
13 |
14 | computed: {
15 | model: {
16 | get() {
17 | return this.store.state ? this.store.state.value : this.value
18 | },
19 |
20 | set(val) {
21 | if (this.store.state) {
22 | this.store.state.value = val
23 | } else {
24 | this.$emit('input', val)
25 | }
26 | }
27 | },
28 |
29 | isDisabled() {
30 | return this.store.state ? this.store.state.disabled || this.disabled : this.disabled
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/components/radio/radio.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
42 |
--------------------------------------------------------------------------------
/components/radio/store.js:
--------------------------------------------------------------------------------
1 | import BaseStore from '../utils/base-store'
2 |
3 | class Store extends BaseStore {
4 | constructor(component, initialState = {}) {
5 | super(component, initialState)
6 |
7 | this.state = {
8 | value: null,
9 | disabled: false
10 | }
11 |
12 | this.setState(initialState)
13 | }
14 | }
15 |
16 | export default Store
17 |
--------------------------------------------------------------------------------
/components/rate/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Rate from './rate'
4 |
5 | export default Rate
6 |
--------------------------------------------------------------------------------
/components/rate/rate.js:
--------------------------------------------------------------------------------
1 | import Dom from '../utils/dom'
2 |
3 | export default {
4 | name: 'VRate',
5 |
6 | props: {
7 | count: {
8 | type: Number,
9 | default: 5
10 | },
11 | value: Number,
12 | disabled: {
13 | type: Boolean,
14 | default: false
15 | },
16 | allowHalf: {
17 | type: Boolean,
18 | default: false
19 | },
20 | character: [String, Object]
21 | },
22 |
23 | data() {
24 | return {
25 | hoverValue: undefined
26 | }
27 | },
28 |
29 | render() {
30 | const stars = []
31 | for (let i = 0; i < this.count; i++) {
32 | const starData = {
33 | ref: `star_${i}`,
34 | on: {
35 | click: this.onClick.bind(this, i),
36 | mousemove: this.onHover.bind(this, i)
37 | },
38 | class: this.getClass(i)
39 | }
40 |
41 | stars.push((
42 | {this.getCharacterVM()}
43 | {this.getCharacterVM()}
44 | ))
45 | }
46 |
47 | const rateData = {
48 | on: {
49 | mouseleave: this.onMouseLeave
50 | },
51 | class: {
52 | 'ant-rate-disabled': this.disabled
53 | }
54 | }
55 | return (
56 |
57 | {this.$slots.default}
58 | )
59 | },
60 |
61 | methods: {
62 | getCharacterVM() {
63 | return !this.character ? () : this.character
64 | },
65 |
66 | getClass(index) {
67 | const { value, hoverValue, allowHalf } = this
68 | const starValue = index + 1
69 | const currentValue = hoverValue === undefined ? value : hoverValue
70 | if (allowHalf && currentValue + 0.5 === starValue) {
71 | return 'ant-rate-star ant-rate-star-half ant-rate-star-active'
72 | }
73 | return starValue <= currentValue ? 'ant-rate-star ant-rate-star-full' : 'ant-rate-star ant-rate-star-zero'
74 | },
75 |
76 | onClick(index, e) {
77 | if (this.disabled) return
78 | const value = this.getStarValue(index, e.pageX)
79 | this.onMouseLeave()
80 | this.$emit('input', value)
81 | this.$emit('onChange', value)
82 | },
83 |
84 | onHover(index, e) {
85 | if (this.disabled) return
86 | this.hoverValue = this.getStarValue(index, e.pageX)
87 | this.$emit('onHoverChange', this.hoverValue)
88 | },
89 |
90 | onMouseLeave() {
91 | if (this.disabled) return
92 | this.hoverValue = undefined
93 | this.$emit('onHoverChange', this.hoverValue)
94 | },
95 |
96 | getStarValue(index, x) {
97 | let value = index + 1
98 | if (this.allowHalf) {
99 | const leftEdge = Dom.getOffset(this.$refs.star_0).left
100 | const width = Dom.getOffset(this.$refs.star_1).left - leftEdge
101 | if ((x - leftEdge - (width * index)) < width / 2) {
102 | value -= 0.5
103 | }
104 | }
105 | return value
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/components/rate/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 |
4 | @rate-prefix-cls: ~"@{ant-prefix}-rate";
5 |
6 | .@{rate-prefix-cls} {
7 | margin: 0;
8 | padding: 0;
9 | list-style: none;
10 | font-size: 20px;
11 | display: inline-block;
12 | vertical-align: middle;
13 |
14 | &-disabled &-star {
15 | cursor: not-allowed;
16 | &:hover {
17 | transform: scale(1);
18 | }
19 | }
20 |
21 | &-star {
22 | margin: 0;
23 | padding: 0;
24 | display: inline-block;
25 | margin-right: 8px;
26 | position: relative;
27 | transition: all .3s;
28 | color: @rate-star-bg;
29 | cursor: pointer;
30 |
31 | &-first,
32 | &-second {
33 | user-select: none;
34 | transition: all .3s;
35 | }
36 |
37 | &:hover {
38 | transform: scale(1.1);
39 | }
40 |
41 | &-first {
42 | position: absolute;
43 | left: 0;
44 | top: 0;
45 | width: 50%;
46 | height: 100%;
47 | overflow: hidden;
48 | opacity: 0;
49 | }
50 |
51 | &-half &-first,
52 | &-half &-second {
53 | opacity: 1;
54 | }
55 |
56 | &-half &-first,
57 | &-full &-second {
58 | color: @rate-star-color;
59 | }
60 |
61 | &-half:hover &-first,
62 | &-full:hover &-second {
63 | color: tint(@rate-star-color, 20%);
64 | }
65 | }
66 |
67 | &-text {
68 | margin-left: 8px;
69 | vertical-align: middle;
70 | display: inline-block;
71 | font-size: @font-size-base;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/components/select/index.js:
--------------------------------------------------------------------------------
1 | import Select from './select'
2 | import Option from './option'
3 | import OptionGroup from './option-group'
4 |
5 | Select.Option = Option
6 | Select.OptionGroup = OptionGroup
7 |
8 | export default Select
9 |
--------------------------------------------------------------------------------
/components/select/option-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
22 |
--------------------------------------------------------------------------------
/components/select/option.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
25 |
--------------------------------------------------------------------------------
/components/style/color/bezierEasing.less:
--------------------------------------------------------------------------------
1 | .bezierEasingMixin() {
2 | @functions: ~`(function() {
3 | var NEWTON_ITERATIONS = 4;
4 | var NEWTON_MIN_SLOPE = 0.001;
5 | var SUBDIVISION_PRECISION = 0.0000001;
6 | var SUBDIVISION_MAX_ITERATIONS = 10;
7 |
8 | var kSplineTableSize = 11;
9 | var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
10 |
11 | var float32ArraySupported = typeof Float32Array === 'function';
12 |
13 | function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
14 | function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
15 | function C (aA1) { return 3.0 * aA1; }
16 |
17 | // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
18 | function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
19 |
20 | // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
21 | function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
22 |
23 | function binarySubdivide (aX, aA, aB, mX1, mX2) {
24 | var currentX, currentT, i = 0;
25 | do {
26 | currentT = aA + (aB - aA) / 2.0;
27 | currentX = calcBezier(currentT, mX1, mX2) - aX;
28 | if (currentX > 0.0) {
29 | aB = currentT;
30 | } else {
31 | aA = currentT;
32 | }
33 | } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
34 | return currentT;
35 | }
36 |
37 | function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
38 | for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
39 | var currentSlope = getSlope(aGuessT, mX1, mX2);
40 | if (currentSlope === 0.0) {
41 | return aGuessT;
42 | }
43 | var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
44 | aGuessT -= currentX / currentSlope;
45 | }
46 | return aGuessT;
47 | }
48 |
49 | var BezierEasing = function (mX1, mY1, mX2, mY2) {
50 | if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
51 | throw new Error('bezier x values must be in [0, 1] range');
52 | }
53 |
54 | // Precompute samples table
55 | var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
56 | if (mX1 !== mY1 || mX2 !== mY2) {
57 | for (var i = 0; i < kSplineTableSize; ++i) {
58 | sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
59 | }
60 | }
61 |
62 | function getTForX (aX) {
63 | var intervalStart = 0.0;
64 | var currentSample = 1;
65 | var lastSample = kSplineTableSize - 1;
66 |
67 | for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
68 | intervalStart += kSampleStepSize;
69 | }
70 | --currentSample;
71 |
72 | // Interpolate to provide an initial guess for t
73 | var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
74 | var guessForT = intervalStart + dist * kSampleStepSize;
75 |
76 | var initialSlope = getSlope(guessForT, mX1, mX2);
77 | if (initialSlope >= NEWTON_MIN_SLOPE) {
78 | return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
79 | } else if (initialSlope === 0.0) {
80 | return guessForT;
81 | } else {
82 | return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
83 | }
84 | }
85 |
86 | return function BezierEasing (x) {
87 | if (mX1 === mY1 && mX2 === mY2) {
88 | return x; // linear
89 | }
90 | // Because JavaScript number are imprecise, we should guarantee the extremes are right.
91 | if (x === 0) {
92 | return 0;
93 | }
94 | if (x === 1) {
95 | return 1;
96 | }
97 | return calcBezier(getTForX(x), mY1, mY2);
98 | };
99 | };
100 |
101 | this.colorEasing = BezierEasing(0.26, 0.09, 0.37, 0.18);
102 | })()`;
103 | }
104 | // It is hacky way to make this function will be compiled preferentially by less
105 | // resolve error: `ReferenceError: colorPalette is not defined`
106 | // https://github.com/ant-design/ant-motion/issues/44
107 | .bezierEasingMixin();
108 |
--------------------------------------------------------------------------------
/components/style/color/colorPalette.less:
--------------------------------------------------------------------------------
1 | @import "bezierEasing";
2 | @import "tinyColor";
3 |
4 | // We create a very complex algorithm which take the place of original tint/shade color system
5 | // to make sure no one can understand it 👻
6 | // and create an entire color palette magicly by inputing just a single primary color.
7 | // We are using bezier-curve easing function and some color manipulations like tint/shade/darken/spin
8 | .colorPaletteMixin() {
9 | @functions: ~`(function() {
10 | var warmDark = 0.5; // warm color darken radio
11 | var warmRotate = -26; // warm color rotate degree
12 | var coldDark = 0.55; // cold color darken radio
13 | var coldRotate = 10; // cold color rotate degree
14 | var getShadeColor = function(c) {
15 | var shadeColor = tinycolor(c);
16 | // warm and cold color will darken in different radio, and rotate in different degree
17 | // warmer color
18 | if (shadeColor.toRgb().r > shadeColor.toRgb().b) {
19 | return shadeColor.darken(shadeColor.toHsl().l * warmDark * 100).spin(warmRotate).toHexString();
20 | }
21 | // colder color
22 | return shadeColor.darken(shadeColor.toHsl().l * coldDark * 100).spin(coldRotate).toHexString();
23 | }
24 | var primaryEasing = colorEasing(0.6);
25 | this.colorPalette = function(color, index) {
26 | var currentEasing = colorEasing(index * 0.1);
27 | // return light colors after tint
28 | if (index <= 6) {
29 | return tinycolor.mix(
30 | '#ffffff',
31 | color,
32 | currentEasing * 100 / primaryEasing
33 | ).toHexString();
34 | }
35 | return tinycolor.mix(
36 | getShadeColor(color),
37 | color,
38 | (1 - (currentEasing - primaryEasing) / (1 - primaryEasing)) * 100
39 | ).toHexString();
40 | };
41 | })()`;
42 | }
43 | // It is hacky way to make this function will be compiled preferentially by less
44 | // resolve error: `ReferenceError: colorPalette is not defined`
45 | // https://github.com/ant-design/ant-motion/issues/44
46 | .colorPaletteMixin();
47 |
--------------------------------------------------------------------------------
/components/style/color/colors.less:
--------------------------------------------------------------------------------
1 | @import 'colorPalette';
2 |
3 | // color palettes
4 | @blue-1: color(~`colorPalette("@{blue-6}", 1)`);
5 | @blue-2: color(~`colorPalette("@{blue-6}", 2)`);
6 | @blue-3: color(~`colorPalette("@{blue-6}", 3)`);
7 | @blue-4: color(~`colorPalette("@{blue-6}", 4)`);
8 | @blue-5: color(~`colorPalette("@{blue-6}", 5)`);
9 | @blue-6: #108ee9;
10 | @blue-7: color(~`colorPalette("@{blue-6}", 7)`);
11 | @blue-8: color(~`colorPalette("@{blue-6}", 8)`);
12 | @blue-9: color(~`colorPalette("@{blue-6}", 9)`);
13 | @blue-10: color(~`colorPalette("@{blue-6}", 10)`);
14 |
15 | @purple-1: color(~`colorPalette("@{purple-6}", 1)`);
16 | @purple-2: color(~`colorPalette("@{purple-6}", 2)`);
17 | @purple-3: color(~`colorPalette("@{purple-6}", 3)`);
18 | @purple-4: color(~`colorPalette("@{purple-6}", 4)`);
19 | @purple-5: color(~`colorPalette("@{purple-6}", 5)`);
20 | @purple-6: #7265e6;
21 | @purple-7: color(~`colorPalette("@{purple-6}", 7)`);
22 | @purple-8: color(~`colorPalette("@{purple-6}", 8)`);
23 | @purple-9: color(~`colorPalette("@{purple-6}", 9)`);
24 | @purple-10: color(~`colorPalette("@{purple-6}", 10)`);
25 |
26 | @cyan-1: color(~`colorPalette("@{cyan-6}", 1)`);
27 | @cyan-2: color(~`colorPalette("@{cyan-6}", 2)`);
28 | @cyan-3: color(~`colorPalette("@{cyan-6}", 3)`);
29 | @cyan-4: color(~`colorPalette("@{cyan-6}", 4)`);
30 | @cyan-5: color(~`colorPalette("@{cyan-6}", 5)`);
31 | @cyan-6: #00a2ae;
32 | @cyan-7: color(~`colorPalette("@{cyan-6}", 7)`);
33 | @cyan-8: color(~`colorPalette("@{cyan-6}", 8)`);
34 | @cyan-9: color(~`colorPalette("@{cyan-6}", 9)`);
35 | @cyan-10: color(~`colorPalette("@{cyan-6}", 10)`);
36 |
37 | @green-1: color(~`colorPalette("@{green-6}", 1)`);
38 | @green-2: color(~`colorPalette("@{green-6}", 2)`);
39 | @green-3: color(~`colorPalette("@{green-6}", 3)`);
40 | @green-4: color(~`colorPalette("@{green-6}", 4)`);
41 | @green-5: color(~`colorPalette("@{green-6}", 5)`);
42 | @green-6: #00a854;
43 | @green-7: color(~`colorPalette("@{green-6}", 7)`);
44 | @green-8: color(~`colorPalette("@{green-6}", 8)`);
45 | @green-9: color(~`colorPalette("@{green-6}", 9)`);
46 | @green-10: color(~`colorPalette("@{green-6}", 10)`);
47 |
48 | @pink-1: color(~`colorPalette("@{pink-6}", 1)`);
49 | @pink-2: color(~`colorPalette("@{pink-6}", 2)`);
50 | @pink-3: color(~`colorPalette("@{pink-6}", 3)`);
51 | @pink-4: color(~`colorPalette("@{pink-6}", 4)`);
52 | @pink-5: color(~`colorPalette("@{pink-6}", 5)`);
53 | @pink-6: #f5317f;
54 | @pink-7: color(~`colorPalette("@{pink-6}", 7)`);
55 | @pink-8: color(~`colorPalette("@{pink-6}", 8)`);
56 | @pink-9: color(~`colorPalette("@{pink-6}", 9)`);
57 | @pink-10: color(~`colorPalette("@{pink-6}", 10)`);
58 |
59 | @red-1: color(~`colorPalette("@{red-6}", 1)`);
60 | @red-2: color(~`colorPalette("@{red-6}", 2)`);
61 | @red-3: color(~`colorPalette("@{red-6}", 3)`);
62 | @red-4: color(~`colorPalette("@{red-6}", 4)`);
63 | @red-5: color(~`colorPalette("@{red-6}", 5)`);
64 | @red-6: #f04134;
65 | @red-7: color(~`colorPalette("@{red-6}", 7)`);
66 | @red-8: color(~`colorPalette("@{red-6}", 8)`);
67 | @red-9: color(~`colorPalette("@{red-6}", 9)`);
68 | @red-10: color(~`colorPalette("@{red-6}", 10)`);
69 |
70 | @orange-1: color(~`colorPalette("@{orange-6}", 1)`);
71 | @orange-2: color(~`colorPalette("@{orange-6}", 2)`);
72 | @orange-3: color(~`colorPalette("@{orange-6}", 3)`);
73 | @orange-4: color(~`colorPalette("@{orange-6}", 4)`);
74 | @orange-5: color(~`colorPalette("@{orange-6}", 5)`);
75 | @orange-6: #f56a00;
76 | @orange-7: color(~`colorPalette("@{orange-6}", 7)`);
77 | @orange-8: color(~`colorPalette("@{orange-6}", 8)`);
78 | @orange-9: color(~`colorPalette("@{orange-6}", 9)`);
79 | @orange-10: color(~`colorPalette("@{orange-6}", 10)`);
80 |
81 | @yellow-1: color(~`colorPalette("@{yellow-6}", 1)`);
82 | @yellow-2: color(~`colorPalette("@{yellow-6}", 2)`);
83 | @yellow-3: color(~`colorPalette("@{yellow-6}", 3)`);
84 | @yellow-4: color(~`colorPalette("@{yellow-6}", 4)`);
85 | @yellow-5: color(~`colorPalette("@{yellow-6}", 5)`);
86 | @yellow-6: #ffbf00;
87 | @yellow-7: color(~`colorPalette("@{yellow-6}", 7)`);
88 | @yellow-8: color(~`colorPalette("@{yellow-6}", 8)`);
89 | @yellow-9: color(~`colorPalette("@{yellow-6}", 9)`);
90 | @yellow-10: color(~`colorPalette("@{yellow-6}", 10)`);
91 |
--------------------------------------------------------------------------------
/components/style/core/base.less:
--------------------------------------------------------------------------------
1 | @import "./normalize.less";
2 |
3 | * {
4 | box-sizing: border-box;
5 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); // remove tap highlight color for mobile safari
6 | }
7 |
8 | *:before,
9 | *:after {
10 | box-sizing: border-box;
11 | }
12 |
13 | // HTML & Body reset
14 | html, body {
15 | .square(100%);
16 | }
17 |
18 | body {
19 | font-family: @font-family;
20 | font-size: @font-size-base;
21 | line-height: @line-height-base;
22 | color: @text-color;
23 | background-color: @body-background;
24 | }
25 |
26 | // unify the setting of elements's margin and padding for browsers
27 | body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section {
28 | margin: 0;
29 | padding: 0;
30 | }
31 |
32 | // Reset fonts for relevant elements
33 | button,input,select,textarea {
34 | font-family: inherit;
35 | font-size: inherit;
36 | line-height: inherit;
37 | color: inherit;
38 | }
39 |
40 | ul,
41 | ol {
42 | list-style: none;
43 | }
44 |
45 | // Remove the clear button of a text input control in IE10+
46 | input::-ms-clear, input::-ms-reveal {
47 | display: none;
48 | }
49 |
50 | ::selection {
51 | background: @primary-color;
52 | color: #fff;
53 | }
54 |
55 | // Links
56 | a {
57 | color: @link-color;
58 | background: transparent;
59 | text-decoration: none;
60 | outline: none;
61 | cursor: pointer;
62 | transition: color .3s ease;
63 |
64 | &:hover {
65 | color: @link-hover-color;
66 | }
67 |
68 | &:active {
69 | color: @link-active-color;
70 | }
71 |
72 | &:active,
73 | &:hover {
74 | outline: 0;
75 | text-decoration: none;
76 | }
77 |
78 | &[disabled] {
79 | color: @disabled-color;
80 | cursor: not-allowed;
81 | pointer-events: none;
82 | }
83 | }
84 |
85 | .@{ant-prefix}-divider {
86 | margin: 0 6px;
87 | display: inline-block;
88 | height: 8px;
89 | width: 1px;
90 | background: #ccc;
91 | }
92 |
93 | code,
94 | kbd,
95 | pre,
96 | samp {
97 | font-family: @code-family;
98 | }
99 |
100 | // Utility classes
101 | .clearfix {
102 | .clearfix();
103 | }
104 |
--------------------------------------------------------------------------------
/components/style/core/index.less:
--------------------------------------------------------------------------------
1 | @import "../mixins/index";
2 | @import "base";
3 | @import "iconfont";
4 | @import "motion";
5 |
--------------------------------------------------------------------------------
/components/style/core/motion.less:
--------------------------------------------------------------------------------
1 | @import "../mixins/motion";
2 | @import "motion/fade";
3 | @import "motion/move";
4 | @import "motion/other";
5 | @import "motion/slide";
6 | @import "motion/swing";
7 | @import "motion/zoom";
8 |
9 | // For common/openAnimation
10 | .ant-motion-collapse {
11 | overflow: hidden;
12 | &-active {
13 | transition: height .12s, opacity .12s;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/components/style/core/motion/fade.less:
--------------------------------------------------------------------------------
1 | .fade-motion(@className, @keyframeName) {
2 | .make-motion(@className, @keyframeName);
3 | .@{className}-enter,
4 | .@{className}-appear {
5 | opacity: 0;
6 | animation-timing-function: linear;
7 | }
8 | .@{className}-leave {
9 | animation-timing-function: linear;
10 | }
11 | }
12 |
13 | .fade-motion(fade, antFade);
14 |
15 | @keyframes antFadeIn {
16 | 0% {
17 | opacity: 0;
18 | }
19 | 100% {
20 | opacity: 1;
21 | }
22 | }
23 |
24 | @keyframes antFadeOut {
25 | 0% {
26 | opacity: 1;
27 | }
28 | 100% {
29 | opacity: 0;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/components/style/core/motion/move.less:
--------------------------------------------------------------------------------
1 | .move-motion(@className, @keyframeName) {
2 | .make-motion(@className, @keyframeName);
3 | .@{className}-enter,
4 | .@{className}-appear {
5 | opacity: 0;
6 | animation-timing-function: @ease-out-circ;
7 | }
8 | .@{className}-leave {
9 | animation-timing-function: @ease-in-circ;
10 | }
11 | }
12 |
13 | .move-motion(move-up, antMoveUp);
14 | .move-motion(move-down, antMoveDown);
15 | .move-motion(move-left, antMoveLeft);
16 | .move-motion(move-right, antMoveRight);
17 |
18 | @keyframes antMoveDownIn {
19 | 0% {
20 | transform-origin: 0 0;
21 | transform: translateY(100%);
22 | opacity: 0;
23 | }
24 | 100% {
25 | transform-origin: 0 0;
26 | transform: translateY(0%);
27 | opacity: 1;
28 | }
29 | }
30 |
31 | @keyframes antMoveDownOut {
32 | 0% {
33 | transform-origin: 0 0;
34 | transform: translateY(0%);
35 | opacity: 1;
36 | }
37 | 100% {
38 | transform-origin: 0 0;
39 | transform: translateY(100%);
40 | opacity: 0;
41 | }
42 | }
43 |
44 | @keyframes antMoveLeftIn {
45 | 0% {
46 | transform-origin: 0 0;
47 | transform: translateX(-100%);
48 | opacity: 0;
49 | }
50 | 100% {
51 | transform-origin: 0 0;
52 | transform: translateX(0%);
53 | opacity: 1;
54 | }
55 | }
56 |
57 | @keyframes antMoveLeftOut {
58 | 0% {
59 | transform-origin: 0 0;
60 | transform: translateX(0%);
61 | opacity: 1;
62 | }
63 | 100% {
64 | transform-origin: 0 0;
65 | transform: translateX(-100%);
66 | opacity: 0;
67 | }
68 | }
69 |
70 | @keyframes antMoveRightIn {
71 | 0% {
72 | opacity: 0;
73 | transform-origin: 0 0;
74 | transform: translateX(100%);
75 | }
76 | 100% {
77 | opacity: 1;
78 | transform-origin: 0 0;
79 | transform: translateX(0%);
80 | }
81 | }
82 |
83 | @keyframes antMoveRightOut {
84 | 0% {
85 | transform-origin: 0 0;
86 | transform: translateX(0%);
87 | opacity: 1;
88 | }
89 | 100% {
90 | transform-origin: 0 0;
91 | transform: translateX(100%);
92 | opacity: 0;
93 | }
94 | }
95 |
96 | @keyframes antMoveUpIn {
97 | 0% {
98 | transform-origin: 0 0;
99 | transform: translateY(-100%);
100 | opacity: 0;
101 | }
102 | 100% {
103 | transform-origin: 0 0;
104 | transform: translateY(0%);
105 | opacity: 1;
106 | }
107 | }
108 |
109 | @keyframes antMoveUpOut {
110 | 0% {
111 | transform-origin: 0 0;
112 | transform: translateY(0%);
113 | opacity: 1;
114 | }
115 | 100% {
116 | transform-origin: 0 0;
117 | transform: translateY(-100%);
118 | opacity: 0;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/components/style/core/motion/other.less:
--------------------------------------------------------------------------------
1 | @keyframes loadingCircle {
2 | 0% {
3 | transform-origin: 50% 50%;
4 | transform: rotate(0deg);
5 | }
6 | 100% {
7 | transform-origin: 50% 50%;
8 | transform: rotate(360deg);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/components/style/core/motion/slide.less:
--------------------------------------------------------------------------------
1 | .slide-motion(@className, @keyframeName) {
2 | .make-motion(@className, @keyframeName);
3 | .@{className}-enter,
4 | .@{className}-appear {
5 | opacity: 0;
6 | animation-timing-function: @ease-out-quint;
7 | }
8 | .@{className}-leave {
9 | animation-timing-function: @ease-in-quint;
10 | }
11 | }
12 |
13 | .slide-motion(slide-up, antSlideUp);
14 | .slide-motion(slide-down, antSlideDown);
15 | .slide-motion(slide-left, antSlideLeft);
16 | .slide-motion(slide-right, antSlideRight);
17 |
18 | @keyframes antSlideUpIn {
19 | 0% {
20 | opacity: 0;
21 | transform-origin: 0% 0%;
22 | transform: scaleY(.8);
23 | }
24 | 100% {
25 | opacity: 1;
26 | transform-origin: 0% 0%;
27 | transform: scaleY(1);
28 | }
29 | }
30 |
31 | @keyframes antSlideUpOut {
32 | 0% {
33 | opacity: 1;
34 | transform-origin: 0% 0%;
35 | transform: scaleY(1);
36 | }
37 | 100% {
38 | opacity: 0;
39 | transform-origin: 0% 0%;
40 | transform: scaleY(.8);
41 | }
42 | }
43 |
44 | @keyframes antSlideDownIn {
45 | 0% {
46 | opacity: 0;
47 | transform-origin: 100% 100%;
48 | transform: scaleY(.8);
49 | }
50 | 100% {
51 | opacity: 1;
52 | transform-origin: 100% 100%;
53 | transform: scaleY(1);
54 | }
55 | }
56 |
57 | @keyframes antSlideDownOut {
58 | 0% {
59 | opacity: 1;
60 | transform-origin: 100% 100%;
61 | transform: scaleY(1);
62 | }
63 | 100% {
64 | opacity: 0;
65 | transform-origin: 100% 100%;
66 | transform: scaleY(.8);
67 | }
68 | }
69 |
70 | @keyframes antSlideLeftIn {
71 | 0% {
72 | opacity: 0;
73 | transform-origin: 0% 0%;
74 | transform: scaleX(.8);
75 | }
76 | 100% {
77 | opacity: 1;
78 | transform-origin: 0% 0%;
79 | transform: scaleX(1);
80 | }
81 | }
82 |
83 | @keyframes antSlideLeftOut {
84 | 0% {
85 | opacity: 1;
86 | transform-origin: 0% 0%;
87 | transform: scaleX(1);
88 | }
89 | 100% {
90 | opacity: 0;
91 | transform-origin: 0% 0%;
92 | transform: scaleX(.8);
93 | }
94 | }
95 |
96 | @keyframes antSlideRightIn {
97 | 0% {
98 | opacity: 0;
99 | transform-origin: 100% 0%;
100 | transform: scaleX(.8);
101 | }
102 | 100% {
103 | opacity: 1;
104 | transform-origin: 100% 0%;
105 | transform: scaleX(1);
106 | }
107 | }
108 |
109 | @keyframes antSlideRightOut {
110 | 0% {
111 | opacity: 1;
112 | transform-origin: 100% 0%;
113 | transform: scaleX(1);
114 | }
115 | 100% {
116 | opacity: 0;
117 | transform-origin: 100% 0%;
118 | transform: scaleX(.8);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/components/style/core/motion/swing.less:
--------------------------------------------------------------------------------
1 | .swing-motion(@className, @keyframeName) {
2 | .@{className}-enter,
3 | .@{className}-appear {
4 | .motion-common();
5 | animation-play-state: paused;
6 | }
7 | .@{className}-enter.@{className}-enter-active,
8 | .@{className}-appear.@{className}-appear-active {
9 | animation-name: ~"@{keyframeName}In";
10 | animation-play-state: running;
11 | }
12 | }
13 |
14 | .swing-motion(swing, antSwing);
15 |
16 | @keyframes antSwingIn {
17 | 0%,
18 | 100% {
19 | transform: translateX(0);
20 | }
21 | 20% {
22 | transform: translateX(-10px);
23 | }
24 | 40% {
25 | transform: translateX(10px);
26 | }
27 | 60% {
28 | transform: translateX(-5px);
29 | }
30 | 80% {
31 | transform: translateX(5px);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/components/style/core/motion/zoom.less:
--------------------------------------------------------------------------------
1 | .zoom-motion(@className, @keyframeName, @duration: @animation-duration-base) {
2 | .make-motion(@className, @keyframeName, @duration);
3 | .@{className}-enter,
4 | .@{className}-appear {
5 | transform: scale(0); // need this by yiminghe
6 | animation-timing-function: @ease-out-circ;
7 | }
8 | .@{className}-leave {
9 | animation-timing-function: @ease-in-out-circ;
10 | }
11 | }
12 |
13 | // For Modal, Select choosen item
14 | .zoom-motion(zoom, antZoom);
15 | // For Popover, Popconfirm, Dropdown
16 | .zoom-motion(zoom-big, antZoomBig);
17 | // For Tooltip
18 | .zoom-motion(zoom-big-fast, antZoomBig, @animation-duration-fast);
19 |
20 | .zoom-motion(zoom-up, antZoomUp);
21 | .zoom-motion(zoom-down, antZoomDown);
22 | .zoom-motion(zoom-left, antZoomLeft);
23 | .zoom-motion(zoom-right, antZoomRight);
24 |
25 | @keyframes antZoomIn {
26 | 0% {
27 | opacity: 0;
28 | transform: scale(0.2);
29 | }
30 | 100% {
31 | opacity: 1;
32 | transform: scale(1);
33 | }
34 | }
35 |
36 | @keyframes antZoomOut {
37 | 0% {
38 | transform: scale(1);
39 | }
40 | 100% {
41 | opacity: 0;
42 | transform: scale(0.2);
43 | }
44 | }
45 |
46 | @keyframes antZoomBigIn {
47 | 0% {
48 | opacity: 0;
49 | transform: scale(.8);
50 | }
51 | 100% {
52 | transform: scale(1);
53 | }
54 | }
55 |
56 | @keyframes antZoomBigOut {
57 | 0% {
58 | transform: scale(1);
59 | }
60 | 100% {
61 | opacity: 0;
62 | transform: scale(.8);
63 | }
64 | }
65 |
66 | @keyframes antZoomUpIn {
67 | 0% {
68 | opacity: 0;
69 | transform-origin: 50% 0%;
70 | transform: scale(.8);
71 | }
72 | 100% {
73 | transform-origin: 50% 0%;
74 | transform: scale(1);
75 | }
76 | }
77 |
78 | @keyframes antZoomUpOut {
79 | 0% {
80 | transform-origin: 50% 0%;
81 | transform: scale(1);
82 | }
83 | 100% {
84 | opacity: 0;
85 | transform-origin: 50% 0%;
86 | transform: scale(.8);
87 | }
88 | }
89 |
90 | @keyframes antZoomLeftIn {
91 | 0% {
92 | opacity: 0;
93 | transform-origin: 0% 50%;
94 | transform: scale(.8);
95 | }
96 | 100% {
97 | transform-origin: 0% 50%;
98 | transform: scale(1);
99 | }
100 | }
101 |
102 | @keyframes antZoomLeftOut {
103 | 0% {
104 | transform-origin: 0% 50%;
105 | transform: scale(1);
106 | }
107 | 100% {
108 | opacity: 0;
109 | transform-origin: 0% 50%;
110 | transform: scale(.8);
111 | }
112 | }
113 |
114 | @keyframes antZoomRightIn {
115 | 0% {
116 | opacity: 0;
117 | transform-origin: 100% 50%;
118 | transform: scale(.8);
119 | }
120 | 100% {
121 | transform-origin: 100% 50%;
122 | transform: scale(1);
123 | }
124 | }
125 |
126 | @keyframes antZoomRightOut {
127 | 0% {
128 | transform-origin: 100% 50%;
129 | transform: scale(1);
130 | }
131 | 100% {
132 | opacity: 0;
133 | transform-origin: 100% 50%;
134 | transform: scale(.8);
135 | }
136 | }
137 |
138 | @keyframes antZoomDownIn {
139 | 0% {
140 | opacity: 0;
141 | transform-origin: 50% 100%;
142 | transform: scale(.8);
143 | }
144 | 100% {
145 | transform-origin: 50% 100%;
146 | transform: scale(1);
147 | }
148 | }
149 |
150 | @keyframes antZoomDownOut {
151 | 0% {
152 | transform-origin: 50% 100%;
153 | transform: scale(1);
154 | }
155 | 100% {
156 | opacity: 0;
157 | transform-origin: 50% 100%;
158 | transform: scale(.8);
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/components/style/index.less:
--------------------------------------------------------------------------------
1 | @import "./themes/default";
2 | @import "./core/index";
3 |
--------------------------------------------------------------------------------
/components/style/mixins/clearfix.less:
--------------------------------------------------------------------------------
1 | // mixins for clearfix
2 | // ------------------------
3 | .clearfix() {
4 | zoom: 1;
5 | &:before,
6 | &:after {
7 | content: " ";
8 | display: table;
9 | }
10 | &:after {
11 | clear: both;
12 | visibility: hidden;
13 | font-size: 0;
14 | height: 0;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/components/style/mixins/compatibility.less:
--------------------------------------------------------------------------------
1 | // Compatibility for browsers.
2 |
3 | // rotate for ie8 and blow
4 | .ie-rotate(@rotation) {
5 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
6 | }
7 |
8 | // rotate for ie8 and blow
9 | // degrees unit
10 | .ie-rotate-via-degrees(@degrees) {
11 | /* IE6-IE8 */
12 | @radians: ~`parseInt("@{degrees}") * Math.PI * 2 / 360`;
13 | @costheta: ~`Math.cos("@{radians}")`;
14 | @sintheta: ~`Math.sin("@{radians}")`;
15 | @negsintheta: ~`"@{sintheta}" * -1`;
16 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=@{costheta}, M12=@{negsintheta}, M21=@{sintheta}, M22=@{costheta})";
17 | zoom: 1;
18 |
19 | :root & {
20 | filter: none;
21 | }
22 | }
23 |
24 | // support rotate for all browsers
25 | .cross-rotate(@degrees) {
26 | .rotate(@degrees);
27 | .ie-rotate-via-degrees(@degrees);
28 | }
29 |
30 | // Placeholder text
31 | .placeholder(@color: @input-placeholder-color) {
32 | // Firefox
33 | &::-moz-placeholder {
34 | color: @color;
35 | opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526
36 | }
37 | // Internet Explorer 10+
38 | &:-ms-input-placeholder {
39 | color: @color;
40 | }
41 | // Safari and Chrome
42 | &::-webkit-input-placeholder {
43 | color: @color;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/components/style/mixins/iconfont.less:
--------------------------------------------------------------------------------
1 | .iconfont-mixin() {
2 | display: inline-block;
3 | font-style: normal;
4 | vertical-align: baseline;
5 | text-align: center;
6 | text-transform: none;
7 | line-height: 1;
8 | text-rendering: optimizeLegibility;
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | &:before {
12 | display: block;
13 | font-family: "anticon" !important;
14 | }
15 | }
16 |
17 | .iconfont-font(@content) {
18 | font-family: 'anticon';
19 | text-rendering: optimizeLegibility;
20 | -webkit-font-smoothing: antialiased;
21 | -moz-osx-font-smoothing: grayscale;
22 | content: @content;
23 | }
24 |
25 | // for iconfont font size
26 | // fix chrome 12px bug, support ie
27 | .iconfont-size-under-12px(@size, @rotate: 0deg) {
28 | display: inline-block;
29 | @font-scale: unit(@size / 12px);
30 | font-size: @font-size-base;
31 | // ie8-9
32 | font-size: ~"@{size} \9"; // lesshint duplicateProperty: false
33 | transform: scale(@font-scale) rotate(@rotate);
34 | .ie-rotate-via-degrees(@rotate);
35 | :root & {
36 | font-size: @font-size-base; // reset ie9 and above
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/components/style/mixins/index.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------------------------------
3 | @import "opacity";
4 | @import "size";
5 | @import "compatibility";
6 | @import "clearfix";
7 | @import "iconfont";
8 | @import "motion";
9 |
--------------------------------------------------------------------------------
/components/style/mixins/motion.less:
--------------------------------------------------------------------------------
1 | @import '../themes/default';
2 |
3 | .motion-common(@duration: @animation-duration-base) {
4 | animation-duration: @duration;
5 | animation-fill-mode: both;
6 | }
7 |
8 | .motion-common-leave(@duration: @animation-duration-base) {
9 | animation-duration: @duration;
10 | animation-fill-mode: both;
11 | }
12 |
13 | .make-motion(@className, @keyframeName, @duration: @animation-duration-base) {
14 | .@{className}-enter,
15 | .@{className}-appear {
16 | .motion-common(@duration);
17 | animation-play-state: paused;
18 | }
19 | .@{className}-leave {
20 | .motion-common-leave(@duration);
21 | animation-play-state: paused;
22 | }
23 | .@{className}-enter.@{className}-enter-active,
24 | .@{className}-appear.@{className}-appear-active {
25 | animation-name: ~"@{keyframeName}In";
26 | animation-play-state: running;
27 | }
28 | .@{className}-leave.@{className}-leave-active {
29 | animation-name: ~"@{keyframeName}Out";
30 | animation-play-state: running;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/components/style/mixins/opacity.less:
--------------------------------------------------------------------------------
1 | // Opacity
2 |
3 | .opacity(@opacity) {
4 | opacity: @opacity;
5 | // IE8 filter
6 | @opacity-ie: (@opacity * 100);
7 | filter: ~"alpha(opacity=@{opacity-ie})";
8 | }
9 |
--------------------------------------------------------------------------------
/components/style/mixins/size.less:
--------------------------------------------------------------------------------
1 | // Sizing shortcuts
2 |
3 | .size(@width; @height) {
4 | width: @width;
5 | height: @height;
6 | }
7 |
8 | .square(@size) {
9 | .size(@size; @size);
10 | }
11 |
--------------------------------------------------------------------------------
/components/switch/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Switch from './switch'
4 |
5 | export default Switch
6 |
--------------------------------------------------------------------------------
/components/switch/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 |
4 | @switch-prefix-cls: ~"@{ant-prefix}-switch";
5 | @switch-duration: .3s;
6 |
7 | .@{switch-prefix-cls} {
8 | position: relative;
9 | display: inline-block;
10 | box-sizing: border-box;
11 | height: 22px;
12 | min-width: 44px;
13 | line-height: 20px;
14 | vertical-align: middle;
15 | border-radius: 20px;
16 | border: 1px solid #ccc;
17 | background-color: @disabled-color;
18 | cursor: pointer;
19 | transition: all @switch-duration;
20 | user-select: none;
21 |
22 | &-inner {
23 | color: #fff;
24 | font-size: @font-size-base;
25 | margin-left: 24px;
26 | margin-right: 6px;
27 | display: block;
28 | }
29 |
30 | &:after {
31 | position: absolute;
32 | width: 18px;
33 | height: 18px;
34 | left: 1px;
35 | top: 1px;
36 |
37 | border-radius: 18px;
38 | background-color: @component-background;
39 | content: " ";
40 | cursor: pointer;
41 | transition: all @switch-duration, width @switch-duration;
42 | }
43 |
44 | &:active:after {
45 | width: 24px;
46 | }
47 |
48 | &:focus {
49 | box-shadow: 0 0 0 2px fade(@primary-color, 20%);
50 | outline: 0;
51 | }
52 |
53 | &:focus:hover {
54 | box-shadow: none;
55 | }
56 |
57 | &-small {
58 | height: 14px;
59 | min-width: 28px;
60 | line-height: 12px;
61 |
62 | .@{switch-prefix-cls}-inner {
63 | margin-left: 18px;
64 | margin-right: 3px;
65 | }
66 |
67 | &:after {
68 | width: 12px;
69 | height: 12px;
70 | top: 0;
71 | left: 0.5px;
72 | }
73 |
74 | &:active:after {
75 | width: 16px;
76 | }
77 | }
78 |
79 | &-small&-checked {
80 | &:after {
81 | left: 100%;
82 | margin-left: -12.5px;
83 | }
84 |
85 | .@{switch-prefix-cls}-inner {
86 | margin-left: 3px;
87 | margin-right: 18px;
88 | }
89 | }
90 |
91 | &-small:active&-checked:after {
92 | margin-left: -16.5px;
93 | }
94 |
95 | &-checked {
96 | border-color: @primary-color;
97 | background-color: @primary-color;
98 |
99 | .@{switch-prefix-cls}-inner {
100 | margin-left: 6px;
101 | margin-right: 24px;
102 | }
103 |
104 | &:after {
105 | left: 100%;
106 | margin-left: -19px;
107 | }
108 |
109 | &:active:after {
110 | margin-left: -25px;
111 | }
112 | }
113 |
114 | &-disabled {
115 | cursor: not-allowed;
116 | background: #f4f4f4;
117 | border-color: #f4f4f4;
118 |
119 | &:after {
120 | background: #ccc;
121 | cursor: not-allowed;
122 | }
123 |
124 | .@{switch-prefix-cls}-inner {
125 | color: @disabled-color;
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/components/switch/switch.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | {{checkedChildren}}
9 | {{unCheckedChildren}}
10 |
11 |
12 |
13 |
49 |
--------------------------------------------------------------------------------
/components/tabs/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Tabs from './tabs'
4 | import TabPane from './tab-pane'
5 |
6 | Tabs.Pane = TabPane
7 |
8 | export default Tabs
9 |
--------------------------------------------------------------------------------
/components/tabs/store.js:
--------------------------------------------------------------------------------
1 | import BaseStore from '../utils/base-store'
2 |
3 | class Mutations {
4 | onTabClick(index) {
5 | this.state.activeIndex = index
6 |
7 | this.component.$emit('onTabClick', index)
8 | this.component.$emit('input', index)
9 | }
10 | }
11 |
12 | class Store extends BaseStore {
13 | constructor(component, initialState = {}) {
14 | super(component, initialState)
15 |
16 | this.state = { ...initialState }
17 |
18 | this.setState(initialState)
19 |
20 | this.mutations = new Mutations()
21 | }
22 | }
23 |
24 | export default Store
25 |
--------------------------------------------------------------------------------
/components/tabs/style/card-style.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 | @tab-prefix-cls: ~"@{ant-prefix}-tabs";
4 |
5 | // card style
6 | .@{tab-prefix-cls} {
7 | &&-card > &-bar &-nav-container {
8 | height: 32px;
9 | }
10 | &&-card > &-bar &-ink-bar {
11 | visibility: hidden;
12 | }
13 | &&-card > &-bar &-tab {
14 | margin: 0;
15 | border: @border-width-base @border-style-base @border-color-base;
16 | border-bottom: 0;
17 | border-radius: @border-radius-base @border-radius-base 0 0;
18 | transition: all 0.3s @ease-in-out;
19 | background: #f9f9f9;
20 | margin-right: 2px;
21 | }
22 | &&-card > &-bar &-tab {
23 | padding: 5px 16px 4px;
24 | transition: all 0.3s @ease-in-out;
25 | }
26 | &&-card > &-bar &-tab-active {
27 | background: @component-background;
28 | transform: translateZ(0);
29 | border-color: @border-color-base;
30 | color: @primary-color;
31 | }
32 | &&-card > &-bar &-tab-active {
33 | padding-bottom: 5px;
34 | transform: translateZ(0);
35 | }
36 | &&-card > &-bar &-nav-wrap {
37 | margin-bottom: 0;
38 | }
39 | &&-card > &-bar &-tab .@{iconfont-css-prefix}-close {
40 | margin-right: 0;
41 | color: @text-color-secondary;
42 | transition: all 0.3s @ease-in-out;
43 | .iconfont-size-under-12px(9px);
44 | transform-origin: 100% 50%;
45 | width: 0;
46 | text-align: right;
47 | vertical-align: middle;
48 | overflow: hidden;
49 | &:hover {
50 | color: #404040;
51 | font-weight: bold;
52 | }
53 | }
54 |
55 | &&-editable-card > &-bar &-tab > div {
56 | transition: all 0.3s @ease-in-out;
57 | }
58 | &&-editable-card > &-bar &-tab:not(&-tab-active):hover > div:not(&-tab-unclosable) {
59 | margin-left: -8px;
60 | margin-right: -8px;
61 | }
62 |
63 | &&-card > &-bar &-tab-active .@{iconfont-css-prefix}-close,
64 | &&-card > &-bar &-tab:hover .@{iconfont-css-prefix}-close {
65 | width: 16px;
66 | transform: translateZ(0);
67 | }
68 |
69 | &-extra-content {
70 | float: right;
71 | line-height: 32px;
72 |
73 | .@{tab-prefix-cls}-new-tab {
74 | width: 20px;
75 | height: 20px;
76 | line-height: 20px;
77 | text-align: center;
78 | cursor: pointer;
79 | border-radius: @border-radius-base;
80 | border: @border-width-base @border-style-base @border-color-base;
81 | font-size: @font-size-base;
82 | .iconfont-size-under-12px(10px);
83 | color: @text-color-secondary;
84 | transition: color 0.3s ease;
85 | &:hover {
86 | color: #404040;
87 | }
88 | }
89 | }
90 |
91 | // https://github.com/ant-design/ant-design/issues/4669
92 | &-vertical&-card > .@{tab-prefix-cls}-bar {
93 | .@{tab-prefix-cls}-nav-container {
94 | height: auto;
95 | }
96 | .@{tab-prefix-cls}-tab {
97 | border-bottom: @border-width-base @border-style-base @border-color-base;
98 | margin-bottom: 8px;
99 | &-active {
100 | padding-bottom: 4px;
101 | }
102 | &:last-child {
103 | margin-bottom: 8px;
104 | }
105 | }
106 | }
107 |
108 | &-vertical&-card&-left > .@{tab-prefix-cls}-bar {
109 | .@{tab-prefix-cls}-nav-wrap {
110 | margin-right: 0;
111 | }
112 | .@{tab-prefix-cls}-tab {
113 | border-right: 0;
114 | border-radius: @border-radius-base 0 0 @border-radius-base;
115 | margin-right: 1px;
116 | &-active {
117 | margin-right: -1px;
118 | padding-right: 18px;
119 | }
120 | }
121 | }
122 |
123 | &-vertical&-card&-right > .@{tab-prefix-cls}-bar {
124 | .@{tab-prefix-cls}-nav-wrap {
125 | margin-left: 0;
126 | }
127 | .@{tab-prefix-cls}-tab {
128 | border-left: 0;
129 | border-radius: 0 @border-radius-base @border-radius-base 0;
130 | margin-left: 1px;
131 | &-active {
132 | margin-left: -1px;
133 | padding-left: 18px;
134 | }
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/components/tabs/tab-pane.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'VTabPane',
3 |
4 | props: {
5 | index: String,
6 | disabled: {
7 | type: Boolean,
8 | default: false
9 | },
10 | closable: {
11 | type: Boolean,
12 | default: true
13 | },
14 | tab: [String, Object]
15 | },
16 | data() {
17 | return {
18 | store: this.$parent.store
19 | }
20 | },
21 | render() {
22 | const activeIndex = this.store.state.activeIndex
23 | const data = {
24 | class: {
25 | 'ant-tabs-tabpane-active': activeIndex === this.index,
26 | 'ant-tabs-tabpane-inactive': activeIndex !== this.index
27 | }
28 | }
29 | return ({this.$slots.default}
)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/components/tabs/tabs.js:
--------------------------------------------------------------------------------
1 | import VTabNav from './tab-nav'
2 | import Store from './store'
3 |
4 | export default {
5 | name: 'VTabs',
6 |
7 | props: {
8 | value: String,
9 | type: {
10 | type: String,
11 | default: 'line'
12 | },
13 | size: String,
14 | hideAdd: Boolean,
15 | tabBarExtraContent: null
16 | },
17 |
18 | data() {
19 | const store = new Store(this, { activeIndex: this.value, injected: true, ...this.$props })
20 | return {
21 | store
22 | }
23 | },
24 |
25 | watch: {
26 | value() {
27 | this.store.state.activeIndex = this.value
28 | }
29 | },
30 |
31 | render() {
32 | const panes = this.$slots.default || []
33 | const tabsData = {
34 | class: {
35 | 'ant-tabs-mini': this.size === 'small',
36 | 'ant-tabs-card': this.type === 'editable-card',
37 | [`ant-tabs-${this.type}`]: !!this.type
38 | }
39 | }
40 | const tabNavData = {
41 | props: {
42 | panes
43 | }
44 | }
45 | const panesIndex = panes.findIndex(pane =>
46 | (pane.componentOptions.propsData.index === this.store.state.activeIndex))
47 |
48 | const style = {
49 | 'margin-left': `${-panesIndex * 100}%`
50 | }
51 | return (
52 |
53 |
54 | {panes}
55 |
56 |
)
57 | },
58 |
59 | components: {
60 | VTabNav
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/components/tag/index.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 |
3 | import Tag from './tag'
4 |
5 | export default Tag
6 |
--------------------------------------------------------------------------------
/components/tag/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 |
4 | @tag-prefix-cls: ~"@{ant-prefix}-tag";
5 |
6 | .@{tag-prefix-cls} {
7 | display: inline-block;
8 | line-height: 20px;
9 | height: 22px;
10 | padding: 0 8px;
11 | border-radius: @border-radius-base;
12 | border: @border-width-base @border-style-base @border-color-split;
13 | background: @background-color-base;
14 | font-size: @font-size-base;
15 | transition: all 0.3s @ease-in-out-circ;
16 | opacity: 1;
17 | margin-right: 8px;
18 | cursor: pointer;
19 | white-space: nowrap;
20 |
21 | &:hover {
22 | opacity: 0.85;
23 | }
24 |
25 | &,
26 | a,
27 | a:hover {
28 | color: @text-color;
29 | }
30 |
31 | &-text {
32 | a:first-child:last-child {
33 | display: inline-block;
34 | margin: 0 -8px;
35 | padding: 0 8px;
36 | }
37 | }
38 |
39 | .@{iconfont-css-prefix}-cross {
40 | .iconfont-size-under-12px(10px);
41 | cursor: pointer;
42 | font-weight: bold;
43 | margin-left: 3px;
44 | transition: all 0.3s ease;
45 | opacity: 0.66;
46 |
47 | &:hover {
48 | opacity: 1;
49 | }
50 | }
51 |
52 | &-has-color {
53 | border-color: transparent;
54 | &,
55 | a,
56 | a:hover,
57 | .@{iconfont-css-prefix}-cross,
58 | .@{iconfont-css-prefix}-cross:hover {
59 | color: #fff;
60 | }
61 | }
62 |
63 | &-checkable {
64 | background-color: transparent;
65 | border-color: transparent;
66 | &:hover,
67 | &:active,
68 | &-checked {
69 | color: #fff;
70 | }
71 | &:hover {
72 | background-color: @primary-5;
73 | }
74 | &-checked {
75 | background-color: @primary-6;
76 | }
77 | &:active {
78 | background-color: @primary-7;
79 | }
80 | }
81 |
82 | &-close {
83 | width: 0 !important;
84 | padding: 0;
85 | margin: 0;
86 | }
87 |
88 | &-zoom-enter,
89 | &-zoom-appear {
90 | animation: antFadeIn .2s @ease-in-out-circ;
91 | animation-fill-mode: both;
92 | }
93 |
94 | &-zoom-leave {
95 | animation: antZoomOut .3s @ease-in-out-circ;
96 | animation-fill-mode: both;
97 | }
98 |
99 | @colors: pink, red, orange, yellow, cyan, green, blue, purple;
100 |
101 | // mixin to iterate over colors and create CSS class for each one
102 | .make-color-classes(@i: length(@colors)) when (@i > 0) {
103 | .make-color-classes(@i - 1);
104 | @color: extract(@colors, @i);
105 | @lightColor: "@{color}-2";
106 | @darkColor: "@{color}-6";
107 | &-@{color} {
108 | color: @@darkColor;
109 | background: @@lightColor;
110 | border-color: @@lightColor;
111 | }
112 | &-@{color}-inverse {
113 | background: @@darkColor;
114 | border-color: @@darkColor;
115 | color: #fff;
116 | }
117 | }
118 |
119 | .make-color-classes();
120 | }
121 |
--------------------------------------------------------------------------------
/components/tag/tag.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
72 |
--------------------------------------------------------------------------------
/components/tooltip/index.js:
--------------------------------------------------------------------------------
1 | import Tooltip from './tooltip'
2 |
3 | export default Tooltip
4 |
--------------------------------------------------------------------------------
/components/tooltip/style/index.less:
--------------------------------------------------------------------------------
1 | @import "../../style/themes/default";
2 | @import "../../style/mixins/index";
3 |
4 | @tooltip-prefix-cls: ~"@{ant-prefix}-tooltip";
5 |
6 | // Base class
7 | .@{tooltip-prefix-cls} {
8 | position: absolute;
9 | z-index: @zindex-tooltip;
10 | display: block;
11 | visibility: visible;
12 | font-size: @font-size-base;
13 | line-height: @line-height-base;
14 |
15 | &-hidden {
16 | display: none;
17 | }
18 |
19 | &-placement-top,
20 | &-placement-topLeft,
21 | &-placement-topRight {
22 | padding: @tooltip-arrow-width 0 @tooltip-distance 0;
23 | }
24 | &-placement-right,
25 | &-placement-rightTop,
26 | &-placement-rightBottom {
27 | padding: 0 @tooltip-arrow-width 0 @tooltip-distance;
28 | }
29 | &-placement-bottom,
30 | &-placement-bottomLeft,
31 | &-placement-bottomRight {
32 | padding: @tooltip-distance 0 @tooltip-arrow-width 0;
33 | }
34 | &-placement-left,
35 | &-placement-leftTop,
36 | &-placement-leftBottom {
37 | padding: 0 @tooltip-distance 0 @tooltip-arrow-width;
38 | }
39 | }
40 |
41 | // Wrapper for the tooltip content
42 | .@{tooltip-prefix-cls}-inner {
43 | max-width: @tooltip-max-width;
44 | padding: 8px 10px;
45 | color: @tooltip-color;
46 | text-align: left;
47 | text-decoration: none;
48 | background-color: @tooltip-bg;
49 | border-radius: @border-radius-base;
50 | box-shadow: @box-shadow-base;
51 | min-height: 34px;
52 | }
53 |
54 | // Arrows
55 | .@{tooltip-prefix-cls}-arrow {
56 | position: absolute;
57 | width: 0;
58 | height: 0;
59 | border-color: transparent;
60 | border-style: solid;
61 | }
62 |
63 | .@{tooltip-prefix-cls} {
64 | &-placement-top &-arrow,
65 | &-placement-topLeft &-arrow,
66 | &-placement-topRight &-arrow {
67 | bottom: @tooltip-distance - @tooltip-arrow-width;
68 | border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
69 | border-top-color: @tooltip-arrow-color;
70 | }
71 |
72 | &-placement-top &-arrow {
73 | left: 50%;
74 | margin-left: -@tooltip-arrow-width;
75 | }
76 |
77 | &-placement-topLeft &-arrow {
78 | left: 16px;
79 | }
80 |
81 | &-placement-topRight &-arrow {
82 | right: 16px;
83 | }
84 |
85 | &-placement-right &-arrow,
86 | &-placement-rightTop &-arrow,
87 | &-placement-rightBottom &-arrow {
88 | left: @tooltip-distance - @tooltip-arrow-width;
89 | border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;
90 | border-right-color: @tooltip-arrow-color;
91 | }
92 |
93 | &-placement-right &-arrow {
94 | top: 50%;
95 | margin-top: -@tooltip-arrow-width;
96 | }
97 |
98 | &-placement-rightTop &-arrow {
99 | top: 8px;
100 | }
101 |
102 | &-placement-rightBottom &-arrow {
103 | bottom: 8px;
104 | }
105 |
106 | &-placement-left &-arrow,
107 | &-placement-leftTop &-arrow,
108 | &-placement-leftBottom &-arrow {
109 | right: @tooltip-distance - @tooltip-arrow-width;
110 | border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;
111 | border-left-color: @tooltip-arrow-color;
112 | }
113 |
114 | &-placement-left &-arrow {
115 | top: 50%;
116 | margin-top: -@tooltip-arrow-width;
117 | }
118 |
119 | &-placement-leftTop &-arrow {
120 | top: 8px;
121 | }
122 |
123 | &-placement-leftBottom &-arrow {
124 | bottom: 8px;
125 | }
126 |
127 | &-placement-bottom &-arrow,
128 | &-placement-bottomLeft &-arrow,
129 | &-placement-bottomRight &-arrow {
130 | top: @tooltip-distance - @tooltip-arrow-width;
131 | border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
132 | border-bottom-color: @tooltip-arrow-color;
133 | }
134 |
135 | &-placement-bottom &-arrow {
136 | left: 50%;
137 | margin-left: -@tooltip-arrow-width;
138 | }
139 |
140 | &-placement-bottomLeft &-arrow {
141 | left: 16px;
142 | }
143 |
144 | &-placement-bottomRight &-arrow {
145 | right: 16px;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/components/tooltip/tooltip.js:
--------------------------------------------------------------------------------
1 | import './style/index.less'
2 | import TooltipMixin from '../mixins/tooltip'
3 |
4 | export default {
5 | name: 'VTooltip',
6 |
7 | mixins: [TooltipMixin],
8 |
9 | data() {
10 | return {
11 | prefixCls: 'ant-tooltip'
12 | }
13 | },
14 |
15 | components: {
16 | /**
17 | * 定义函数化组件用于插入到popperVM
18 | * 实际浮层显示的内容
19 | */
20 | VTooltipContent: {
21 | functional: true,
22 |
23 | render(h, context) {
24 | return ({ context.data.title }
)
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/components/transition/collapse.js:
--------------------------------------------------------------------------------
1 | class Transition {
2 | constructor() {
3 | this.props = {
4 | 'enter-active-class': 'ant-motion-collapse ant-motion-collapse-active',
5 | 'leave-active-class': 'ant-motion-collapse ant-motion-collapse-active'
6 | }
7 | this.on = {
8 | beforeEnter(el) {
9 | // 获取隐藏的元素的高度
10 | // const oldStyle = {
11 | // visibility: el.style.visibility,
12 | // position: el.style.position,
13 | // display: el.style.display
14 | // }
15 | // el.style.visibility = 'hidden'
16 | // el.style.position = 'absolute'
17 | // el.style.display = ''
18 | // el.dataset.offsetHeight = el.offsetHeight
19 | // Object.keys(oldStyle).forEach((key) => {
20 | // el.style[key] = oldStyle[key]
21 | // })
22 | el.style.height = '0px'
23 | },
24 | enter(el) {
25 | el.style.display = ''
26 | el.style.height = `${el.scrollHeight}px`
27 | },
28 | afterEnter(el) {
29 | el.style.display = ''
30 | el.style.height = ''
31 | },
32 | beforeLeave(el) {
33 | el.style.height = `${el.offsetHeight}px`
34 | },
35 | leave(el) {
36 | // todo: 为什么一定要setTimeout呢···
37 | // setTimeout(() => {
38 | // el.style.height = '0px'
39 | // }, 0)
40 | // todo: 一个奇怪的现象,必须要调用一次el的属性,否则没有过渡效果,不知道是否有兼容问题
41 | let h = el.scrollHeight
42 | h = '0px'
43 | el.style.height = h
44 | },
45 | afterLeave(el) {
46 | el.style.height = ''
47 | }
48 | }
49 | }
50 | }
51 |
52 | export default Transition
53 |
--------------------------------------------------------------------------------
/components/transition/fade.js:
--------------------------------------------------------------------------------
1 | class Transition {
2 | constructor({ prefixCls }) {
3 | const cls = prefixCls ? `${prefixCls}-` : ''
4 | this.props = {
5 | 'enter-active-class': `${cls}fade-enter ${cls}fade-enter-active`,
6 | 'leave-active-class': `${cls}fade-leave ${cls}fade-leave-active`
7 | }
8 | }
9 | }
10 |
11 | export default Transition
12 |
--------------------------------------------------------------------------------
/components/transition/index.js:
--------------------------------------------------------------------------------
1 | import Collapse from './collapse'
2 | import SideUp from './slide-up'
3 | import ZoomBigFast from './zoom-big-fast'
4 | import MoveUp from './move-up'
5 | import Fade from './fade'
6 | import Zoom from './zoom'
7 |
8 | export default {
9 | name: 'VTransition',
10 | functional: true,
11 | render(createElement, context) {
12 | const attrs = context.data.attrs
13 | const type = attrs.type
14 | let data = {}
15 | switch (type) {
16 | case 'collapse':
17 | data = new Collapse(attrs)
18 | break
19 | case 'slide-up':
20 | data = new SideUp(attrs)
21 | break
22 | case 'zoom-big-fast':
23 | data = new ZoomBigFast(attrs)
24 | break
25 | case 'move-up':
26 | data = new MoveUp(attrs)
27 | break
28 | case 'fade':
29 | data = new Fade(attrs)
30 | break
31 | case 'zoom':
32 | data = new Zoom(attrs)
33 | break
34 | default:
35 | }
36 | data = Object.assign({}, context.data, data)
37 | return createElement('transition', data, context.children)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/components/transition/move-up.js:
--------------------------------------------------------------------------------
1 | class Transition {
2 | constructor() {
3 | this.props = {
4 | 'enter-active-class': 'move-up-enter move-up-enter-active',
5 | 'leave-active-class': 'move-up-leave move-up-leave-active'
6 | }
7 | }
8 | }
9 |
10 | export default Transition
11 |
--------------------------------------------------------------------------------
/components/transition/slide-up.js:
--------------------------------------------------------------------------------
1 | class Transition {
2 | constructor({ prefixCls }) {
3 | const cls = prefixCls ? `${prefixCls}-` : ''
4 | this.props = {
5 | 'enter-active-class': `${cls}slide-up-enter ${cls}slide-up-enter-active`,
6 | 'leave-active-class': `${cls}slide-up-leave ${cls}slide-up-leave-active`
7 | }
8 | }
9 | }
10 |
11 | export default Transition
12 |
--------------------------------------------------------------------------------
/components/transition/zoom-big-fast.js:
--------------------------------------------------------------------------------
1 | class Transition {
2 | constructor() {
3 | this.props = {
4 | 'enter-active-class': 'zoom-big-fast-enter zoom-big-fast-enter-active',
5 | 'leave-active-class': 'zoom-big-fast-leave zoom-big-fast-leave-active'
6 | }
7 | }
8 | }
9 |
10 | export default Transition
11 |
--------------------------------------------------------------------------------
/components/transition/zoom.js:
--------------------------------------------------------------------------------
1 | class Transition {
2 | constructor({ prefixCls }) {
3 | const cls = prefixCls ? `${prefixCls}-` : ''
4 | this.props = {
5 | 'enter-active-class': `${cls}zoom-enter ${cls}zoom-enter-active`,
6 | 'leave-active-class': `${cls}zoom-leave ${cls}zoom-leave-active`
7 | }
8 | }
9 | }
10 |
11 | export default Transition
12 |
--------------------------------------------------------------------------------
/components/utils/base-store.js:
--------------------------------------------------------------------------------
1 | class BaseStore {
2 | constructor(component) {
3 | if (!component) {
4 | throw new Error('component is required.')
5 | }
6 | this.component = component
7 |
8 | this.state = {}
9 | }
10 |
11 | setState(state) {
12 | this.state.injected = false // 标记store是否注入,为false时自动将store注入到所有子组件中
13 |
14 | Object.keys(state).forEach((prop) => {
15 | if ({}.hasOwnProperty.call(this.state, prop)) {
16 | this.state[prop] = state[prop]
17 | }
18 | })
19 |
20 | this.component.$nextTick(() => {
21 | if (!this.state.injected) this.reject()
22 | })
23 | }
24 |
25 | reject() {
26 | const deepNodes = (nodes) => {
27 | nodes.forEach((node) => {
28 | node.store = this
29 | deepNodes(node.$children)
30 | })
31 | }
32 |
33 | deepNodes(this.component.$children)
34 | this.state.injected = true
35 | }
36 |
37 | commit(name, ...args) {
38 | if (!this.state.injected) this.reject()
39 | const mutations = this.mutations
40 | if (mutations[name]) {
41 | mutations[name].apply(this, args)
42 | }
43 | }
44 | }
45 |
46 | export default BaseStore
47 |
--------------------------------------------------------------------------------
/components/utils/calcTextareaHeight.js:
--------------------------------------------------------------------------------
1 | // Thanks to
2 | // https://github.com/andreypopp/react-textarea-autosize/
3 | // https://github.com/ElemeFE/element/blob/master/packages/input/src/calcTextareaHeight.js
4 |
5 | let hiddenTextarea
6 |
7 | const HIDDEN_STYLE = `
8 | height:0 !important;
9 | visibility:hidden !important;
10 | overflow:hidden !important;
11 | position:absolute !important;
12 | z-index:-1000 !important;
13 | top:0 !important;
14 | right:0 !important;
15 | `
16 |
17 | const CONTEXT_STYLE = [
18 | 'letter-spacing',
19 | 'line-height',
20 | 'padding-top',
21 | 'padding-bottom',
22 | 'font-family',
23 | 'font-weight',
24 | 'font-size',
25 | 'text-rendering',
26 | 'text-transform',
27 | 'width',
28 | 'text-indent',
29 | 'padding-left',
30 | 'padding-right',
31 | 'border-width',
32 | 'box-sizing'
33 | ]
34 |
35 | function calculateNodeStyling(node) {
36 | const style = window.getComputedStyle(node)
37 |
38 | const boxSizing = style.getPropertyValue('box-sizing')
39 |
40 | const paddingSize = (
41 | parseFloat(style.getPropertyValue('padding-bottom')) +
42 | parseFloat(style.getPropertyValue('padding-top'))
43 | )
44 |
45 | const borderSize = (
46 | parseFloat(style.getPropertyValue('border-bottom-width')) +
47 | parseFloat(style.getPropertyValue('border-top-width'))
48 | )
49 |
50 | const contextStyle = CONTEXT_STYLE
51 | .map(name => `${name}:${style.getPropertyValue(name)}`)
52 | .join(';')
53 |
54 | return { contextStyle, paddingSize, borderSize, boxSizing }
55 | }
56 |
57 | export default function calcTextareaHeight(targetNode, minRows = null, maxRows = null) {
58 | if (!hiddenTextarea) {
59 | hiddenTextarea = document.createElement('textarea')
60 | document.body.appendChild(hiddenTextarea)
61 | }
62 |
63 | const {
64 | paddingSize,
65 | borderSize,
66 | boxSizing,
67 | contextStyle
68 | } = calculateNodeStyling(targetNode)
69 |
70 | hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`)
71 | hiddenTextarea.value = targetNode.value || targetNode.placeholder || ''
72 |
73 | let height = hiddenTextarea.scrollHeight
74 | let minHeight = -Infinity
75 | let maxHeight = Infinity
76 |
77 | if (boxSizing === 'border-box') {
78 | height += borderSize
79 | } else if (boxSizing === 'content-box') {
80 | height -= paddingSize
81 | }
82 |
83 | hiddenTextarea.value = ''
84 | const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize
85 |
86 | if (minRows !== null) {
87 | minHeight = singleRowHeight * minRows
88 | if (boxSizing === 'border-box') {
89 | minHeight = minHeight + paddingSize + borderSize
90 | }
91 | height = Math.max(minHeight, height)
92 | }
93 | if (maxRows !== null) {
94 | maxHeight = singleRowHeight * maxRows
95 | if (boxSizing === 'border-box') {
96 | maxHeight = maxHeight + paddingSize + borderSize
97 | }
98 | height = Math.min(maxHeight, height)
99 | }
100 |
101 | return {
102 | height: `${height}px`,
103 | minHeight: `${minHeight}px`,
104 | maxHeight: `${maxHeight}px`
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/components/utils/clickoutside.js:
--------------------------------------------------------------------------------
1 | // https://github.com/ElemeFE/element/blob/dev/src/utils/clickoutside.js
2 |
3 | const nodeList = []
4 | const ctx = '@@clickoutsideContext'
5 |
6 | window.document.addEventListener('mousedown', (e) => {
7 | nodeList.forEach(node => node[ctx].documentHandler(e))
8 | })
9 |
10 | /**
11 | * v-clickoutside
12 | * @desc 点击元素外面才会触发的事件
13 | * @example
14 | * ```vue
15 | *
16 | * ```
17 | */
18 | export default {
19 | bind(el, binding, vnode) {
20 | const id = nodeList.push(el) - 1
21 | const documentHandler = (e) => {
22 | if (!vnode.context ||
23 | el.contains(e.target) ||
24 | (vnode.context.popper &&
25 | vnode.context.popper.contains(e.target))) return
26 |
27 | if (binding.expression && el[ctx].methodName && vnode.context[el[ctx].methodName]) {
28 | vnode.context[el[ctx].methodName]()
29 | } else if (el[ctx].bindingFn) {
30 | el[ctx].bindingFn()
31 | }
32 | }
33 | el[ctx] = {
34 | id,
35 | documentHandler,
36 | methodName: binding.expression,
37 | bindingFn: binding.value
38 | }
39 | },
40 |
41 | update(el, binding) {
42 | el[ctx].methodName = binding.expression
43 | el[ctx].bindingFn = binding.value
44 | },
45 |
46 | unbind(el) {
47 | nodeList.some((node, index) => {
48 | if (node[ctx].id === el[ctx].id) {
49 | nodeList.splice(index, 1)
50 | return true
51 | }
52 | return false
53 | })
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/components/utils/dom.js:
--------------------------------------------------------------------------------
1 | let cached
2 |
3 | class Dom {
4 | /**
5 | * 获取元素的offset:{top, left}
6 | * @param elem
7 | * @returns {{top: number, left: number}}
8 | */
9 | static getOffset(elem) {
10 | if (!elem.getClientRects().length) return { top: 0, left: 0 }
11 |
12 | const rect = elem.getBoundingClientRect()
13 | const doc = elem.ownerDocument
14 | const docElem = doc.documentElement
15 | const win = doc.defaultView
16 |
17 | return {
18 | top: rect.top + win.pageYOffset - docElem.clientTop,
19 | left: rect.left + win.pageXOffset - docElem.clientLeft
20 | }
21 | }
22 |
23 | /**
24 | * 设置transform,浏览器兼容处理
25 | * @param style
26 | * @param v
27 | */
28 | static setTransform(style, v) {
29 | style.transform = v
30 | style.webkitTransform = v
31 | style.mozTransform = v
32 | }
33 |
34 | static setTransformOrigin(node, value) {
35 | const style = node.style
36 | const list = ['Webkit', 'Moz', 'Ms', 'ms']
37 | list.forEach((prefix) => {
38 | style[`${prefix}TransformOrigin`] = value
39 | })
40 | style.transformOrigin = value
41 | }
42 |
43 | static getScrollBarSize(fresh) {
44 | if (fresh || cached === undefined) {
45 | const inner = document.createElement('div')
46 | inner.style.width = '100%'
47 | inner.style.height = '200px'
48 |
49 | const outer = document.createElement('div')
50 | const outerStyle = outer.style
51 |
52 | outerStyle.position = 'absolute'
53 | outerStyle.top = 0
54 | outerStyle.left = 0
55 | outerStyle.pointerEvents = 'none'
56 | outerStyle.visibility = 'hidden'
57 | outerStyle.width = '200px'
58 | outerStyle.height = '150px'
59 | outerStyle.overflow = 'hidden'
60 |
61 | outer.appendChild(inner)
62 |
63 | document.body.appendChild(outer)
64 |
65 | const widthContained = inner.offsetWidth
66 | outer.style.overflow = 'scroll'
67 | let widthScroll = inner.offsetWidth
68 |
69 | if (widthContained === widthScroll) {
70 | widthScroll = outer.clientWidth
71 | }
72 |
73 | document.body.removeChild(outer)
74 |
75 | cached = widthContained - widthScroll
76 | }
77 | return cached
78 | }
79 | }
80 |
81 | export default Dom
82 |
--------------------------------------------------------------------------------
/components/utils/keycode.js:
--------------------------------------------------------------------------------
1 | export default {
2 | ZERO: 48,
3 | NINE: 57,
4 |
5 | NUMPAD_ZERO: 96,
6 | NUMPAD_NINE: 105,
7 |
8 | ESC: 27,
9 | TAB: 9,
10 | BACKSPACE: 8,
11 | DELETE: 46,
12 | ENTER: 13,
13 |
14 | LEFT: 37,
15 | UP: 38,
16 | RIGHT: 39,
17 | DOWN: 40
18 | }
19 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | // index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: '',
10 | assetsPublicPath: '/',
11 | productionSourceMap: false,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css']
18 | },
19 | dev: {
20 | env: require('./dev.env'),
21 | port: 8080,
22 | assetsRoot: path.resolve(__dirname, '../dist'),
23 | assetsSubDirectory: '',
24 | assetsPublicPath: '/',
25 | proxyTable: {},
26 | // CSS Sourcemaps off by default because relative paths are "buggy"
27 | // with this option, according to the CSS-Loader README
28 | // (https://github.com/webpack/css-loader#sourcemaps)
29 | // In our experience, they generally work as expected,
30 | // just be aware of this issue when enabling this option.
31 | cssSourceMap: false
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "antv",
3 | "version": "0.2.2",
4 | "description": "Ant Design of Vue",
5 | "author": "FlashHK ",
6 | "main": "dist/antv",
7 | "files": [
8 | "dist"
9 | ],
10 | "directories": {
11 | "test": "test"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/ant-design-vue/antv.git"
16 | },
17 | "keywords": [
18 | "antd",
19 | "ant-design",
20 | "vue",
21 | "vue-component",
22 | "ui",
23 | "component",
24 | "components",
25 | "framework",
26 | "frontend"
27 | ],
28 | "license": "ISC",
29 | "bugs": {
30 | "url": "https://github.com/ant-design-vue/antv/issues"
31 | },
32 | "homepage": "https://github.com/ant-design-vue/antv#readme",
33 | "scripts": {
34 | "bootstrap": "npm i",
35 | "dev": "node build/dev-server.js",
36 | "build": "node build/build.js",
37 | "lint": "eslint components --ext .js,.vue src",
38 | "pub": "sh build/git-release.sh && sh build/release.sh"
39 | },
40 | "dependencies": {
41 | "popper.js": "^0.6.4",
42 | "vue": "^2.2.0",
43 | "vue-router": "^2.0.0-rc.7"
44 | },
45 | "devDependencies": {
46 | "autoprefixer": "^6.4.0",
47 | "babel-core": "^6.0.0",
48 | "babel-eslint": "^7.0.0",
49 | "babel-loader": "^6.0.0",
50 | "babel-plugin-transform-runtime": "^6.0.0",
51 | "babel-helper-vue-jsx-merge-props": "^2.0.2",
52 | "babel-plugin-syntax-jsx": "^6.8.0",
53 | "babel-plugin-transform-vue-jsx": "^3.4.2",
54 | "babel-preset-es2015": "^6.0.0",
55 | "babel-preset-stage-2": "^6.0.0",
56 | "babel-register": "^6.0.0",
57 | "chalk": "^1.1.3",
58 | "connect-history-api-fallback": "^1.1.0",
59 | "css-loader": "^0.25.0",
60 | "eslint": "^3.7.1",
61 | "eslint-friendly-formatter": "^2.0.5",
62 | "eslint-loader": "^1.5.0",
63 | "eslint-plugin-html": "^1.3.0",
64 | "eslint-config-airbnb-base": "^8.0.0",
65 | "eslint-import-resolver-webpack": "^0.6.0",
66 | "eslint-plugin-import": "^1.16.0",
67 | "eventsource-polyfill": "^0.9.6",
68 | "express": "^4.13.3",
69 | "extract-text-webpack-plugin": "^1.0.1",
70 | "file-loader": "^0.9.0",
71 | "function-bind": "^1.0.2",
72 | "html-webpack-plugin": "^2.8.1",
73 | "http-proxy-middleware": "^0.17.2",
74 | "json-loader": "^0.5.4",
75 | "semver": "^5.3.0",
76 | "opn": "^4.0.2",
77 | "ora": "^0.3.0",
78 | "shelljs": "^0.7.4",
79 | "url-loader": "^0.5.7",
80 | "vue-loader": "^11.1.4",
81 | "vue-template-compiler": "^2.1.0",
82 | "vue-style-loader": "^1.0.0",
83 | "webpack": "^1.13.2",
84 | "webpack-dev-middleware": "^1.8.3",
85 | "webpack-hot-middleware": "^2.12.2",
86 | "webpack-merge": "^0.14.1",
87 | "less": "^2.7.1",
88 | "less-loader": "^2.2.3"
89 | },
90 | "engines": {
91 | "node": ">= 4.0.0",
92 | "npm": ">= 3.0.0"
93 | }
94 | }
95 |
--------------------------------------------------------------------------------