Browse Source

feat: 主分支代码

master
shizhanyi 4 years ago
parent
commit
824c48e2cd
  1. BIN
      .DS_Store
  2. 14
      .editorconfig
  3. 6
      .env.development
  4. 5
      .env.production
  5. 7
      .env.staging
  6. 4
      .eslintignore
  7. 197
      .eslintrc.js
  8. 23
      .gitignore
  9. 2
      README.md
  10. 23
      babel.config.js
  11. 1
      index.html
  12. 24
      jest.config.js
  13. 9
      jsconfig.json
  14. 71
      package.json
  15. 8
      postcss.config.js
  16. 0
      public/favicon.ico
  17. 17
      public/index.html
  18. 11
      src/App.vue
  19. 0
      src/api/index.js
  20. BIN
      src/assets/datapage_images/No1.png
  21. BIN
      src/assets/datapage_images/No1@2x.png
  22. BIN
      src/assets/datapage_images/No2.png
  23. BIN
      src/assets/datapage_images/No2@2x.png
  24. BIN
      src/assets/datapage_images/No3.png
  25. BIN
      src/assets/datapage_images/No3@2x.png
  26. BIN
      src/assets/layout_images/LOGO.png
  27. BIN
      src/assets/layout_images/LOGO@2x.png
  28. BIN
      src/assets/layout_images/LOGO@3x.png
  29. BIN
      src/assets/layout_images/MATRIX@2x.png
  30. BIN
      src/assets/layout_images/MATRIX备份.png
  31. BIN
      src/assets/layout_images/MATRIX备份@3x.png
  32. 0
      src/assets/login_img/login_bg.png
  33. 0
      src/assets/login_img/logo.png
  34. 0
      src/assets/registration_img/code.png
  35. BIN
      src/assets/registration_img/mail.png
  36. 0
      src/assets/workAvatar.png
  37. 0
      src/assets/workImg.png
  38. BIN
      src/assets/上传之后的图片备份.png
  39. BIN
      src/assets/上传之后的图片备份@2x.png
  40. 39
      src/components/Breadcrumb/index.vue
  41. 118
      src/components/ContainerBox/index.vue
  42. 128
      src/components/baseDetail/CompactDetailCard.vue
  43. 110
      src/components/baseDetail/TwoRowDetail.vue
  44. 0
      src/components/index.js
  45. 76
      src/components/menu/_util/clickoutside.js
  46. 368
      src/components/menu/_util/date.js
  47. 291
      src/components/menu/_util/dateUtil.js
  48. 229
      src/components/menu/_util/dom.js
  49. 43
      src/components/menu/_util/getRequestAnimationFrame.js
  50. 17
      src/components/menu/_util/getScroll.js
  51. 1
      src/components/menu/_util/icon.json
  52. 14
      src/components/menu/_util/merge.js
  53. 1257
      src/components/menu/_util/popper.js
  54. 218
      src/components/menu/_util/popup/index.js
  55. 194
      src/components/menu/_util/popup/popup-manager.js
  56. 7
      src/components/menu/_util/proptype.js
  57. 24
      src/components/menu/_util/repeatClick.js
  58. 33
      src/components/menu/_util/resizeEvent.js
  59. 27
      src/components/menu/_util/scrollIntoView.js
  60. 29
      src/components/menu/_util/scrollbar-width.js
  61. 35
      src/components/menu/_util/soda.js
  62. 8
      src/components/menu/_util/switchcase.js
  63. 47
      src/components/menu/_util/throttleByAnimationFrame.js
  64. 237
      src/components/menu/_util/tree/node.js
  65. 120
      src/components/menu/_util/tree/tree.js
  66. 141
      src/components/menu/_util/util.js
  67. 205
      src/components/menu/_util/vue-popper.js
  68. 13
      src/components/menu/index.js
  69. 95
      src/components/menu/menu-item.vue
  70. 79
      src/components/menu/menu-itemgroup.vue
  71. 158
      src/components/menu/menu-submenu.vue
  72. 165
      src/components/menu/menu.vue
  73. 2
      src/components/menu/style/index.js
  74. 717
      src/components/menu/style/index.less
  75. 108
      src/components/menu/style/style/color/bezierEasing.less
  76. 46
      src/components/menu/style/style/color/colorPalette.less
  77. 92
      src/components/menu/style/style/color/colors.less
  78. 1184
      src/components/menu/style/style/color/tinyColor.less
  79. 126
      src/components/menu/style/style/core/base.less
  80. 1181
      src/components/menu/style/style/core/icon/iconfont.css
  81. 0
      src/components/menu/style/style/core/icon/iconfont.eot
  82. 1
      src/components/menu/style/style/core/icon/iconfont.js
  83. 0
      src/components/menu/style/style/core/icon/iconfont.svg
  84. 0
      src/components/menu/style/style/core/icon/iconfont.ttf
  85. 0
      src/components/menu/style/style/core/icon/iconfont.woff
  86. BIN
      src/components/menu/style/style/core/icon/iconfont.woff2
  87. 2214
      src/components/menu/style/style/core/iconfont.less
  88. 4
      src/components/menu/style/style/core/index.less
  89. 15
      src/components/menu/style/style/core/motion.less
  90. 31
      src/components/menu/style/style/core/motion/fade.less
  91. 120
      src/components/menu/style/style/core/motion/move.less
  92. 10
      src/components/menu/style/style/core/motion/other.less
  93. 120
      src/components/menu/style/style/core/motion/slide.less
  94. 33
      src/components/menu/style/style/core/motion/swing.less
  95. 160
      src/components/menu/style/style/core/motion/zoom.less
  96. 447
      src/components/menu/style/style/core/normalize.less
  97. 1
      src/components/menu/style/style/index.js
  98. 2
      src/components/menu/style/style/index.less
  99. 16
      src/components/menu/style/style/mixins/clearfix.less
  100. 45
      src/components/menu/style/style/mixins/compatibility.less

BIN
.DS_Store

14
.editorconfig

@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

6
.env.development

@ -0,0 +1,6 @@
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'
VUE_CLI_BABEL_TRANSPILE_MODULES = true

5
.env.production

@ -0,0 +1,5 @@
ENV = 'production'
# base api
VUE_APP_BASE_API = '/prod-api'

7
.env.staging

@ -0,0 +1,7 @@
NODE_ENV = production
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'

4
.eslintignore

@ -0,0 +1,4 @@
build/*.js
src/assets
public
dist

197
.eslintrc.js

@ -0,0 +1,197 @@
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/essential', 'eslint:recommended'],
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/singleline-html-element-content-newline": "off",
"vue/multiline-html-element-content-newline": "off",
"vue/name-property-casing": ["error", "PascalCase"],
"vue/no-v-html": "off",
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", {
"null": "ignore"
}],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

23
.gitignore

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
tree.txt
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

2
README.md

@ -79,6 +79,4 @@ revert commit 回退
#### 帮助
- [x] [Matrix](https://matrix.58.com/)
- [x] [Arthur](http://arthurci.58corp.com/my-project)
- [x] [常见命名参考](http://igit.58corp.com/bic-fe-common/bic-guide/blob/master/%E5%B8%B8%E8%A7%81%E5%91%BD%E5%90%8D%E5%8F%82%E8%80%83%E8%A7%84%E8%8C%83.md)

23
babel.config.js

@ -0,0 +1,23 @@
const plugins = []
if (process.env.NODE_ENV === 'production') {
// 如果是生产环境,则自动清理掉打印的日志,但保留error 与 warn
plugins.push([
'transform-remove-console',
{
// 保留 console.error 与 console.warn
exclude: ['error']
}
])
}
plugins.push(['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant'])
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins
}

1
index.html

@ -1 +0,0 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=https://ape_card.gitee.io/matrix-template-vertical/favicon.ico><title>MATRIX MAGIC</title><link href=https://ape_card.gitee.io/matrix-template-vertical/static/css/chunk-mdsUI.css rel=stylesheet><link href=https://ape_card.gitee.io/matrix-template-vertical/static/css/chunk-libs.css rel=stylesheet><link href=https://ape_card.gitee.io/matrix-template-vertical/static/css/app.css rel=stylesheet></head><body><noscript><strong>We're sorry but MATRIX MAGIC doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=https://ape_card.gitee.io/matrix-template-vertical/static/js/runtime.js></script><script src=https://ape_card.gitee.io/matrix-template-vertical/static/js/chunk-mdsUI.js></script><script src=https://ape_card.gitee.io/matrix-template-vertical/static/js/chunk-libs.js></script><script src=https://ape_card.gitee.io/matrix-template-vertical/static/js/app.js></script></body></html>

24
jest.config.js

@ -0,0 +1,24 @@
module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
// 'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/'
}

9
jsconfig.json

@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

71
package.json

@ -0,0 +1,71 @@
{
"name": "matrix-magic",
"version": "1.0.0",
"scripts": {
"start": "npm run dev",
"dev": "npm run serve",
"serve": "vue-cli-service serve",
"build": "npm run build:prod",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"lint": "eslint --fix --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit"
},
"dependencies": {
"@babel/core": "^7.11.4",
"@bic-fe/mds-ui": "0.0.10",
"babel-loader": "^7.1.5",
"babel-register": "^6.26.0",
"echarts": "^4.8.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"vue": "2.6.10",
"vue-router": "3.0.6",
"vuex": "3.1.0"
},
"devDependencies": {
"@babel/core": "^7.11.4",
"@vue/cli-plugin-babel": "~4.4.0",
"@vue/cli-plugin-eslint": "~4.4.0",
"@vue/cli-plugin-unit-jest": "3.6.3",
"@vue/cli-service": "3.6.0",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1",
"babel-eslint": "10.1.0",
"babel-jest": "23.6.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"chalk": "2.4.2",
"connect": "3.6.6",
"core-js": "3.6.4",
"eslint": "5.15.3",
"eslint-plugin-vue": "5.2.2",
"html-webpack-plugin": "3.2.0",
"less": "2.7.2",
"less-loader": "^6.2.0",
"lint-staged": "^9.5.0",
"runjs": "^4.3.2",
"sass": "^1.26.8",
"sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3",
"serve-static": "^1.13.2",
"vue-template-compiler": "2.6.10"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"gitHooks": {},
"lint-staged": {
"*.{js,jsx,vue}": [
"vue-cli-service lint",
"git add"
]
}
}

8
postcss.config.js

@ -0,0 +1,8 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
'plugins': {
// to edit target browsers: use "browserslist" field in package.json
'autoprefixer': {}
}
}

0
favicon.ico → public/favicon.ico

17
public/index.html

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

11
src/App.vue

@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>

0
src/api/index.js

BIN
src/assets/datapage_images/No1.png

After

Width: 24  |  Height: 19  |  Size: 928 B

BIN
src/assets/datapage_images/No1@2x.png

After

Width: 48  |  Height: 38  |  Size: 2.2 KiB

BIN
src/assets/datapage_images/No2.png

After

Width: 24  |  Height: 20  |  Size: 915 B

BIN
src/assets/datapage_images/No2@2x.png

After

Width: 48  |  Height: 40  |  Size: 2.0 KiB

BIN
src/assets/datapage_images/No3.png

After

Width: 24  |  Height: 20  |  Size: 1.1 KiB

BIN
src/assets/datapage_images/No3@2x.png

After

Width: 48  |  Height: 40  |  Size: 2.6 KiB

BIN
src/assets/layout_images/LOGO.png

After

Width: 31  |  Height: 32  |  Size: 1.6 KiB

BIN
src/assets/layout_images/LOGO@2x.png

After

Width: 62  |  Height: 64  |  Size: 3.6 KiB

BIN
src/assets/layout_images/LOGO@3x.png

After

Width: 93  |  Height: 96  |  Size: 6.4 KiB

BIN
src/assets/layout_images/MATRIX@2x.png

After

Width: 218  |  Height: 28  |  Size: 2.9 KiB

BIN
src/assets/layout_images/MATRIX备份.png

After

Width: 109  |  Height: 14  |  Size: 1.6 KiB

BIN
src/assets/layout_images/MATRIX备份@3x.png

After

Width: 327  |  Height: 42  |  Size: 6.4 KiB

0
static/img/login_bg.7f96e603.png → src/assets/login_img/login_bg.png

Before

Width: 2880  |  Height: 1800  |  Size: 4.8 MiB

After

Width: 2880  |  Height: 1800  |  Size: 4.8 MiB

0
static/img/logo.ad726749.png → src/assets/login_img/logo.png

Before

Width: 96  |  Height: 96  |  Size: 8.5 KiB

After

Width: 96  |  Height: 96  |  Size: 8.5 KiB

0
static/img/code.dde97681.png → src/assets/registration_img/code.png

Before

Width: 154  |  Height: 56  |  Size: 21 KiB

After

Width: 154  |  Height: 56  |  Size: 21 KiB

BIN
src/assets/registration_img/mail.png

After

Width: 96  |  Height: 96  |  Size: 2.9 KiB

0
static/img/workAvatar.d2fb89be.png → src/assets/workAvatar.png

Before

Width: 176  |  Height: 176  |  Size: 11 KiB

After

Width: 176  |  Height: 176  |  Size: 11 KiB

0
static/img/workImg.9bba60ab.png → src/assets/workImg.png

Before

Width: 218  |  Height: 62  |  Size: 11 KiB

After

Width: 218  |  Height: 62  |  Size: 11 KiB

BIN
src/assets/上传之后的图片备份.png

After

Width: 267  |  Height: 170  |  Size: 2.4 KiB

BIN
src/assets/上传之后的图片备份@2x.png

After

Width: 534  |  Height: 340  |  Size: 6.4 KiB

39
src/components/Breadcrumb/index.vue

@ -0,0 +1,39 @@
<template>
<div>
<mds-breadcrumb separator="/">
<template v-for="(item, index) in levelList">
<mds-breadcrumb-item
v-if="index !== (levelList.length - 1)"
:key="item.path"
:to="item.path"
>{{ item.meta.title }}</mds-breadcrumb-item>
<mds-breadcrumb-item :key="item.path" v-else>{{ item.meta.title }}</mds-breadcrumb-item>
</template>
</mds-breadcrumb>
</div>
</template>
<script>
export default {
data() {
return {
levelList: null
}
},
watch: {
$route(route) {
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
const matched = this.$route.matched.filter(item => item.meta && item.meta.title)
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}
}
}
</script>

118
src/components/ContainerBox/index.vue

@ -0,0 +1,118 @@
<template>
<div class="containerbox-wrapper">
<mds-tabs v-model="active" ref="containerboxMdsTabs" :class="{'not-show': !showTabTitle}">
<mds-tabs-pane tab="模版页" :index="1">
<div class="containerbox-tab_item">
<slot name="container" />
</div>
</mds-tabs-pane>
<!-- <mds-tabs-pane tab="设计说明" :index="2">
<div class="containerbox-tab_item">
<slot name="info" />
</div>
</mds-tabs-pane> -->
</mds-tabs>
</div>
</template>
<script>
export default {
name: 'ContainerBox',
props: {
metaTitle: {
type: String,
required: true,
default: ''
}
},
data() {
return {
active: 1,
showTabTitle: false
}
},
mounted() {
this.changeTabTitle()
setTimeout(() => {
this.showTabTitle = true
}, 300)
},
methods: {
changeTabTitle() {
try {
this.$refs['containerboxMdsTabs'].$children[0].$el.setAttribute('data-star', this.metaTitle)
// eslint-disable-next-line no-empty
} catch {}
}
}
}
</script>
<style lang="scss">
.containerbox-wrapper {
.not-show .mds-tabs-nav-container {
opacity: 0 !important;
}
.mds-tabs {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
.mds-tabs-bar {
position: relative;
width: 100%;
flex-shrink: 0;
background-color: #fff;
padding: 0 26px 8px 24px;
margin: 0;
display: flex;
justify-content: flex-end;
border: none;
&::after {
content: attr(data-star);
position: absolute;
top: 40%;
left: 24px;
transform: translateY(-50%);
font-size: 20px;
font-weight: bold;
font-family:PingFangSC-Medium,PingFang SC;
color: #354052;
line-height: 28px;
}
}
.mds-tabs-content {
width: 100%;
// flex: 1;
// overflow: hidden;
height: calc(100% - 43px);
background-color: #F0F2F5;
.mds-tabs-tabpane {
box-sizing: border-box;
padding: 21px 24px;
}
}
}
}
</style>
<style lang="scss" scoped>
.containerbox-wrapper {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
.containerbox-tab_item {
width: 100%;
height: 100%;
min-height: 100%;
background-color: #fff;
border-radius: 4px;
overflow: auto;
}
}
</style>

128
src/components/baseDetail/CompactDetailCard.vue

@ -0,0 +1,128 @@
<template>
<div class="ComDetailCard">
<div class="cardBox" v-for="(item,index) in formData" :key="index" :style="'width:'+item.pop">
<div class="cardRow" v-if="!item.flag">
<span class="labelBox">
<span class="labelText">{{item.label}} </span>
</span>
<span class="valueBox">{{item.value}}</span>
</div>
<div class="imgRowBox" v-if="item.flag">
<span class="imglabelBox">{{item.label}}</span>
<span class="imgvalueBox">
<img v-for="(i,index) in item.img_list" :style="'height:'+item.height+';width:'+item.width+';'" :key=index src="../../assets/上传之后的图片备份.png" alt="">
</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
formData: {
type: Array,
default: () =>
[{
label: '姓 名:',
value: '经纬(jingwei01)',
color: '',
flag: false
}]
}
},
data() {
return {
}
}
}
</script>
<style lang="scss" scoped>
.ComDetailCard{
background:rgba(255,255,255,1);
height: 100%;
display: flex;
justify-content: flex-start;
flex-direction: row;
flex-wrap: wrap;
background:rgba(255,255,255,1);
.cardBox{
display: flex;
justify-content: flex-start;
align-items: center;
padding: 16px 0 16px 0;
flex-direction: row;
flex-wrap: nowrap;
.cardRow{
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
.labelBox{
display: flex;
justify-content: flex-end;
width: 50%;
.labelText{
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(127,143,164,1);
line-height:22px;
// width: 458px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
}
.valueBox{
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(53,64,82,1);
line-height:22px;
text-align: start;
width: 50%;
}
}
.imgRowBox{
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
.imglabelBox{
display: flex;
justify-content: flex-end;
align-items: flex-start;
padding-left: 24px;
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(127,143,164,1);
line-height:22px;
width: 50%;
}
.imgvalueBox{
width: 50%;
display: flex;
justify-content:flex-start;
flex-wrap: wrap;
img{
// background: burlywood;
margin:20px 16px 0px 16px;
}
}
}
}
}
</style>

110
src/components/baseDetail/TwoRowDetail.vue

@ -0,0 +1,110 @@
<template>
<div class="trDetail">
<div class="rowBox" v-for="(item,index) in formData" :key="index" :style="'width:'+item.pop">
<div v-if="!item.flag">
<span class="labelBox">{{item.label}}</span>
<span class="valueBox">{{item.value}}</span>
</div>
<div class="imgRowBox" v-if="item.flag">
<span class="imglabelBox">{{item.label}}</span>
<span class="imgvalueBox">
<img v-for="(i,index) in item.img_list" :style="'height:'+item.height+';width:'+item.width+';'" :key=index src="../../assets/上传之后的图片备份.png" alt="">
</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
formData: {
type: Array,
default: () =>
[{
label: '姓 名:',
value: '经纬(jingwei01)',
color: '',
flag: false
}]
}
}
}
</script>
<style lang="scss" scoped>
.trDetail{
height: 100%;
display: flex;
justify-content: flex-start;
flex-direction: row;
flex-wrap: wrap;
background:rgba(255,255,255,1);
div:nth-child(even)
{
border-left: 1px solid rgba(240,242,245,1);
}
.rowBox{
width: 50%;
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid rgba(240,242,245,1);
padding: 17px 0 17px 0;
flex-direction: row;
.labelBox{
padding-left: 24px;
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(127,143,164,1);
line-height:22px;
width: 76px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.valueBox{
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(53,64,82,1);
line-height:22px;
text-align: start;
}
.imgRowBox{
display: flex;
flex-direction: row;
.imglabelBox{
display: flex;
justify-content: flex-start;
align-items: flex-start;
padding-left: 24px;
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(127,143,164,1);
line-height:22px;
width: 102px;
}
.imgvalueBox{
display: flex;
justify-content:flex-start;
flex-wrap: wrap;
img{
// background: burlywood;
margin:20px 16px 0px 16px;
}
}
}
}
}
</style>

0
src/components/index.js

76
src/components/menu/_util/clickoutside.js

@ -0,0 +1,76 @@
import Vue from 'vue'
import { on } from './dom.js'
const nodeList = []
const ctx = '@@clickoutsideContext'
let startClick
let seed = 0
!Vue.prototype.$isServer && on(document, 'mousedown', e => (startClick = e))
!Vue.prototype.$isServer && on(document, 'mouseup', e => {
nodeList.forEach(node => node[ctx].documentHandler(e, startClick))
})
function createDocumentHandler(el, binding, vnode) {
return function(mouseup = {}, mousedown = {}) {
if (!vnode ||
!vnode.context ||
!mouseup.target ||
!mousedown.target ||
el.contains(mouseup.target) ||
el.contains(mousedown.target) ||
el === mouseup.target ||
(vnode.context.popperElm &&
(vnode.context.popperElm.contains(mouseup.target) ||
vnode.context.popperElm.contains(mousedown.target)))) return
if (binding.expression &&
el[ctx].methodName &&
vnode.context[el[ctx].methodName]) {
vnode.context[el[ctx].methodName]()
} else {
el[ctx].bindingFn && el[ctx].bindingFn()
}
}
}
/**
* v-clickoutside
* @desc 点击元素外面才会触发的事件
* @example
* ```vue
* <div v-element-clickoutside="handleClose">
* ```
*/
export default {
bind(el, binding, vnode) {
nodeList.push(el)
const id = seed++
el[ctx] = {
id,
documentHandler: createDocumentHandler(el, binding, vnode),
methodName: binding.expression,
bindingFn: binding.value
}
},
update(el, binding, vnode) {
el[ctx].documentHandler = createDocumentHandler(el, binding, vnode)
el[ctx].methodName = binding.expression
el[ctx].bindingFn = binding.value
},
unbind(el) {
const len = nodeList.length
for (let i = 0; i < len; i++) {
if (nodeList[i][ctx].id === el[ctx].id) {
nodeList.splice(i, 1)
break
}
}
delete el[ctx]
}
}

368
src/components/menu/_util/date.js

@ -0,0 +1,368 @@
/* Modified from https://github.com/taylorhakes/fecha
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Taylor Hakes
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*eslint-disable*/
// 把 YYYY-MM-DD 改成了 yyyy-MM-dd
(function (main) {
'use strict'
/**
* Parse or format dates
* @class fecha
*/
var fecha = {}
var token = /d{1,4}|M{1,4}|yy(?:yy)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g
var twoDigits = '\\d\\d?'
var threeDigits = '\\d{3}'
var fourDigits = '\\d{4}'
var word = '[^\\s]+'
var literal = /\[([^]*?)\]/gm
var noop = function () {
}
function regexEscape(str) {
return str.replace( /[|\\{()[^$+*?.-]/g, '\\$&')
}
function shorten(arr, sLen) {
var newArr = []
for (var i = 0, len = arr.length; i < len; i++) {
newArr.push(arr[i].substr(0, sLen))
}
return newArr
}
function monthUpdate(arrName) {
return function (d, v, i18n) {
var index = i18n[arrName].indexOf(v.charAt(0).toUpperCase() + v.substr(1).toLowerCase())
if (~index) {
d.month = index
}
}
}
function pad(val, len) {
val = String(val)
len = len || 2
while (val.length < len) {
val = '0' + val
}
return val
}
var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
var monthNamesShort = shorten(monthNames, 3)
var dayNamesShort = shorten(dayNames, 3)
fecha.i18n = {
dayNamesShort: dayNamesShort,
dayNames: dayNames,
monthNamesShort: monthNamesShort,
monthNames: monthNames,
amPm: ['am', 'pm'],
DoFn: function DoFn(D) {
return D + ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D - D % 10 !== 10) * D % 10]
}
}
var formatFlags = {
D: function(dateObj) {
return dateObj.getDay()
},
DD: function(dateObj) {
return pad(dateObj.getDay())
},
Do: function(dateObj, i18n) {
return i18n.DoFn(dateObj.getDate())
},
d: function(dateObj) {
return dateObj.getDate()
},
dd: function(dateObj) {
return pad(dateObj.getDate())
},
ddd: function(dateObj, i18n) {
return i18n.dayNamesShort[dateObj.getDay()]
},
dddd: function(dateObj, i18n) {
return i18n.dayNames[dateObj.getDay()]
},
M: function(dateObj) {
return dateObj.getMonth() + 1
},
MM: function(dateObj) {
return pad(dateObj.getMonth() + 1)
},
MMM: function(dateObj, i18n) {
return i18n.monthNamesShort[dateObj.getMonth()]
},
MMMM: function(dateObj, i18n) {
return i18n.monthNames[dateObj.getMonth()]
},
yy: function(dateObj) {
return pad(String(dateObj.getFullYear()), 4).substr(2)
},
yyyy: function(dateObj) {
return pad(dateObj.getFullYear(), 4)
},
h: function(dateObj) {
return dateObj.getHours() % 12 || 12
},
hh: function(dateObj) {
return pad(dateObj.getHours() % 12 || 12)
},
H: function(dateObj) {
return dateObj.getHours()
},
HH: function(dateObj) {
return pad(dateObj.getHours())
},
m: function(dateObj) {
return dateObj.getMinutes()
},
mm: function(dateObj) {
return pad(dateObj.getMinutes())
},
s: function(dateObj) {
return dateObj.getSeconds()
},
ss: function(dateObj) {
return pad(dateObj.getSeconds())
},
S: function(dateObj) {
return Math.round(dateObj.getMilliseconds() / 100)
},
SS: function(dateObj) {
return pad(Math.round(dateObj.getMilliseconds() / 10), 2)
},
SSS: function(dateObj) {
return pad(dateObj.getMilliseconds(), 3)
},
a: function(dateObj, i18n) {
return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]
},
A: function(dateObj, i18n) {
return dateObj.getHours() < 12 ? i18n.amPm[0].toUpperCase() : i18n.amPm[1].toUpperCase()
},
ZZ: function(dateObj) {
var o = dateObj.getTimezoneOffset()
return (o > 0 ? '-' : '+') + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
}
}
var parseFlags = {
d: [twoDigits, function (d, v) {
d.day = v
}],
Do: [twoDigits + word, function (d, v) {
d.day = parseInt(v, 10)
}],
M: [twoDigits, function (d, v) {
d.month = v - 1
}],
yy: [twoDigits, function (d, v) {
var da = new Date(), cent = +('' + da.getFullYear()).substr(0, 2)
d.year = '' + (v > 68 ? cent - 1 : cent) + v
}],
h: [twoDigits, function (d, v) {
d.hour = v
}],
m: [twoDigits, function (d, v) {
d.minute = v
}],
s: [twoDigits, function (d, v) {
d.second = v
}],
yyyy: [fourDigits, function (d, v) {
d.year = v
}],
S: ['\\d', function (d, v) {
d.millisecond = v * 100
}],
SS: ['\\d{2}', function (d, v) {
d.millisecond = v * 10
}],
SSS: [threeDigits, function (d, v) {
d.millisecond = v
}],
D: [twoDigits, noop],
ddd: [word, noop],
MMM: [word, monthUpdate('monthNamesShort')],
MMMM: [word, monthUpdate('monthNames')],
a: [word, function (d, v, i18n) {
var val = v.toLowerCase()
if (val === i18n.amPm[0]) {
d.isPm = false
} else if (val === i18n.amPm[1]) {
d.isPm = true
}
}],
ZZ: ['[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z', function (d, v) {
var parts = (v + '').match(/([+-]|\d\d)/gi), minutes
if (parts) {
minutes = +(parts[1] * 60) + parseInt(parts[2], 10)
d.timezoneOffset = parts[0] === '+' ? minutes : -minutes
}
}]
}
parseFlags.dd = parseFlags.d
parseFlags.dddd = parseFlags.ddd
parseFlags.DD = parseFlags.D
parseFlags.mm = parseFlags.m
parseFlags.hh = parseFlags.H = parseFlags.HH = parseFlags.h
parseFlags.MM = parseFlags.M
parseFlags.ss = parseFlags.s
parseFlags.A = parseFlags.a
// Some common format strings
fecha.masks = {
default: 'ddd MMM dd yyyy HH:mm:ss',
shortDate: 'M/D/yy',
mediumDate: 'MMM d, yyyy',
longDate: 'MMMM d, yyyy',
fullDate: 'dddd, MMMM d, yyyy',
shortTime: 'HH:mm',
mediumTime: 'HH:mm:ss',
longTime: 'HH:mm:ss.SSS'
}
/***
* Format a date
* @method format
* @param {Date|number} dateObj
* @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'
*/
fecha.format = function (dateObj, mask, i18nSettings) {
var i18n = i18nSettings || fecha.i18n
if (typeof dateObj === 'number') {
dateObj = new Date(dateObj)
}
if (Object.prototype.toString.call(dateObj) !== '[object Date]' || isNaN(dateObj.getTime())) {
throw new Error('Invalid Date in fecha.format')
}
mask = fecha.masks[mask] || mask || fecha.masks['default']
var literals = []
// Make literals inactive by replacing them with ??
mask = mask.replace(literal, function($0, $1) {
literals.push($1)
return '@@@'
})
// Apply formatting rules
mask = mask.replace(token, function ($0) {
return $0 in formatFlags ? formatFlags[$0](dateObj, i18n) : $0.slice(1, $0.length - 1)
})
// Inline literal values back into the formatted value
return mask.replace(/@@@/g, function() {
return literals.shift()
})
}
/**
* Parse a date string into an object, changes - into /
* @method parse
* @param {string} dateStr Date string
* @param {string} format Date parse format
* @returns {Date|boolean}
*/
fecha.parse = function (dateStr, format, i18nSettings) {
var i18n = i18nSettings || fecha.i18n
if (typeof format !== 'string') {
throw new Error('Invalid format in fecha.parse')
}
format = fecha.masks[format] || format
// Avoid regular expression denial of service, fail early for really long strings
// https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
if (dateStr.length > 1000) {
return null
}
var dateInfo = {}
var parseInfo = []
var literals = []
format = format.replace(literal, function($0, $1) {
literals.push($1)
return '@@@'
})
var newFormat = regexEscape(format).replace(token, function ($0) {
if (parseFlags[$0]) {
var info = parseFlags[$0]
parseInfo.push(info[1])
return '(' + info[0] + ')'
}
return $0
})
newFormat = newFormat.replace(/@@@/g, function() {
return literals.shift()
})
var matches = dateStr.match(new RegExp(newFormat, 'i'))
if (!matches) {
return null
}
for (var i = 1; i < matches.length; i++) {
parseInfo[i - 1](dateInfo, matches[i], i18n)
}
var today = new Date()
if (dateInfo.isPm === true && dateInfo.hour != null && +dateInfo.hour !== 12) {
dateInfo.hour = +dateInfo.hour + 12
} else if (dateInfo.isPm === false && +dateInfo.hour === 12) {
dateInfo.hour = 0
}
var date
if (dateInfo.timezoneOffset != null) {
dateInfo.minute = +(dateInfo.minute || 0) - +dateInfo.timezoneOffset
date = new Date(Date.UTC(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0))
} else {
date = new Date(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0)
}
return date
}
/* istanbul ignore next */
if (typeof module !== 'undefined' && module.exports) {
module.exports = fecha
} else if (typeof define === 'function' && define.amd) {
define(function () {
return fecha
})
} else {
main.fecha = fecha
}
})(this)

291
src/components/menu/_util/dateUtil.js

@ -0,0 +1,291 @@
import fecha from './date.js'
const weeks = ['日', '一', '二', '三', '四', '五', '六']
const months = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
const newArray = function(start, end) {
const result = []
for (let i = start; i <= end; i++) {
result.push(i)
}
return result
}
export const getI18nSettings = () => {
return {
dayNamesShort: weeks,
dayNames: weeks,
monthNamesShort: months,
monthNames: months,
amPm: ['am', 'pm']
}
}
export const toDate = function(date) {
return isDate(date) ? new Date(date) : null
}
export const isDate = function(date) {
if (date === null || date === undefined) return false
if (isNaN(new Date(date).getTime())) return false
if (Array.isArray(date)) return false // deal with `new Date([ new Date() ]) -> new Date()`
return true
}
export const isDateObject = function(val) {
return val instanceof Date
}
export const formatDate = function(date, format) {
date = toDate(date)
if (!date) return ''
return fecha.format(date, format || 'yyyy-MM-dd', getI18nSettings())
}
export const parseDate = function(string, format) {
return fecha.parse(string, format || 'yyyy-MM-dd', getI18nSettings())
}
export const getDayCountOfMonth = function(year, month) {
if (month === 3 || month === 5 || month === 8 || month === 10) {
return 30
}
if (month === 1) {
if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) {
return 29
} else {
return 28
}
}
return 31
}
export const getDayCountOfYear = function(year) {
const isLeapYear = year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)
return isLeapYear ? 366 : 365
}
export const getFirstDayOfMonth = function(date) {
const temp = new Date(date.getTime())
temp.setDate(1)
return temp.getDay()
}
// see: https://stackoverflow.com/questions/3674539/incrementing-a-date-in-javascript
// {prev, next} Date should work for Daylight Saving Time
// Adding 24 * 60 * 60 * 1000 does not work in the above scenario
export const prevDate = function(date, amount = 1) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate() - amount)
}
export const nextDate = function(date, amount = 1) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount)
}
export const getStartDateOfMonth = function(year, month) {
const result = new Date(year, month, 1)
const day = result.getDay()
if (day === 0) {
return prevDate(result, 7)
} else {
return prevDate(result, day)
}
}
export const getWeekNumber = function(src) {
if (!isDate(src)) return null
const date = new Date(src.getTime())
date.setHours(0, 0, 0, 0)
// Thursday in current week decides the year.
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7)
// January 4 is always in week 1.
const week1 = new Date(date.getFullYear(), 0, 4)
// Adjust to Thursday in week 1 and count number of weeks from date to week 1.
// Rounding should be fine for Daylight Saving Time. Its shift should never be more than 12 hours.
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7)
}
export const getRangeHours = function(ranges = []) {
const hours = []
let disabledHours = []
ranges.forEach(range => {
const value = range.map(date => date.getHours())
disabledHours = disabledHours.concat(newArray(value[0], value[1]))
})
if (disabledHours.length) {
for (let i = 0; i < 24; i++) {
hours[i] = disabledHours.indexOf(i) === -1
}
} else {
for (let i = 0; i < 24; i++) {
hours[i] = false
}
}
return hours
}
export const getPrevMonthLastDays = (date, amount) => {
if (amount <= 0) return []
const temp = new Date(date.getTime())
temp.setDate(0)
const lastDay = temp.getDate()
return range(amount).map((_, index) => lastDay - (amount - index - 1))
}
export const getMonthDays = (date) => {
const temp = new Date(date.getFullYear(), date.getMonth() + 1, 0)
const days = temp.getDate()
return range(days).map((_, index) => index + 1)
}
function setRangeData(arr, start, end, value) {
for (let i = start; i < end; i++) {
arr[i] = value
}
}
export const getRangeMinutes = function(ranges, hour) {
const minutes = new Array(60)
if (ranges.length > 0) {
ranges.forEach(range => {
const start = range[0]
const end = range[1]
const startHour = start.getHours()
const startMinute = start.getMinutes()
const endHour = end.getHours()
const endMinute = end.getMinutes()
if (startHour === hour && endHour !== hour) {
setRangeData(minutes, startMinute, 60, true)
} else if (startHour === hour && endHour === hour) {
setRangeData(minutes, startMinute, endMinute + 1, true)
} else if (startHour !== hour && endHour === hour) {
setRangeData(minutes, 0, endMinute + 1, true)
} else if (startHour < hour && endHour > hour) {
setRangeData(minutes, 0, 60, true)
}
})
} else {
setRangeData(minutes, 0, 60, true)
}
return minutes
}
export const range = function(n) {
// see https://stackoverflow.com/questions/3746725/create-a-javascript-array-containing-1-n
return Array.apply(null, { length: n }).map((_, n) => n)
}
export const modifyDate = function(date, y, m, d) {
return new Date(y, m, d, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds())
}
export const modifyTime = function(date, h, m, s) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), h, m, s, date.getMilliseconds())
}
export const modifyWithTimeString = (date, time) => {
if (date == null || !time) {
return date
}
time = parseDate(time, 'HH:mm:ss')
return modifyTime(date, time.getHours(), time.getMinutes(), time.getSeconds())
}
export const clearTime = function(date) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate())
}
export const clearMilliseconds = function(date) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), 0)
}
export const limitTimeRange = function(date, ranges, format = 'HH:mm:ss') {
// TODO: refactory a more elegant solution
if (ranges.length === 0) return date
const normalizeDate = date => fecha.parse(fecha.format(date, format), format)
const ndate = normalizeDate(date)
const nranges = ranges.map(range => range.map(normalizeDate))
if (nranges.some(nrange => ndate >= nrange[0] && ndate <= nrange[1])) return date
let minDate = nranges[0][0]
let maxDate = nranges[0][0]
nranges.forEach(nrange => {
minDate = new Date(Math.min(nrange[0], minDate))
maxDate = new Date(Math.max(nrange[1], minDate))
})
const ret = ndate < minDate ? minDate : maxDate
// preserve Year/Month/Date
return modifyDate(
ret,
date.getFullYear(),
date.getMonth(),
date.getDate()
)
}
export const timeWithinRange = function(date, selectableRange, format) {
const limitedDate = limitTimeRange(date, selectableRange, format)
return limitedDate.getTime() === date.getTime()
}
export const changeYearMonthAndClampDate = function(date, year, month) {
// clamp date to the number of days in `year`, `month`
// eg: (2010-1-31, 2010, 2) => 2010-2-28
const monthDate = Math.min(date.getDate(), getDayCountOfMonth(year, month))
return modifyDate(date, year, month, monthDate)
}
export const prevMonth = function(date) {
const year = date.getFullYear()
const month = date.getMonth()
return month === 0
? changeYearMonthAndClampDate(date, year - 1, 11)
: changeYearMonthAndClampDate(date, year, month - 1)
}
export const nextMonth = function(date) {
const year = date.getFullYear()
const month = date.getMonth()
return month === 11
? changeYearMonthAndClampDate(date, year + 1, 0)
: changeYearMonthAndClampDate(date, year, month + 1)
}
export const prevYear = function(date, amount = 1) {
const year = date.getFullYear()
const month = date.getMonth()
return changeYearMonthAndClampDate(date, year - amount, month)
}
export const nextYear = function(date, amount = 1) {
const year = date.getFullYear()
const month = date.getMonth()
return changeYearMonthAndClampDate(date, year + amount, month)
}
export const extractDateFormat = function(format) {
return format
.replace(/\W?m{1,2}|\W?ZZ/g, '')
.replace(/\W?h{1,2}|\W?s{1,3}|\W?a/gi, '')
.trim()
}
export const extractTimeFormat = function(format) {
return format
.replace(/\W?D{1,2}|\W?Do|\W?d{1,4}|\W?M{1,4}|\W?y{2,4}/g, '')
.trim()
}
export const validateRangeInOneMonth = function(start, end) {
return (start.getMonth() === end.getMonth()) && (start.getFullYear() === end.getFullYear())
}

229
src/components/menu/_util/dom.js

@ -0,0 +1,229 @@
/* istanbul ignore next */
import Vue from 'vue'
const isServer = Vue.prototype.$isServer
/* eslint no-useless-escape: 0 */
const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g
const MOZ_HACK_REGEXP = /^moz([A-Z])/
const ieVersion = isServer ? 0 : Number(document.documentMode)
/* istanbul ignore next */
const trim = function(string) {
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '')
}
/* istanbul ignore next */
const camelCase = function(name) {
return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
return offset ? letter.toUpperCase() : letter
}).replace(MOZ_HACK_REGEXP, 'Moz$1')
}
/* istanbul ignore next */
export const on = (function() {
if (!isServer && document.addEventListener) {
return function(element, event, handler) {
if (element && event && handler) {
element.addEventListener(event, handler, false)
}
}
} else {
return function(element, event, handler) {
if (element && event && handler) {
element.attachEvent('on' + event, handler)
}
}
}
})()
/* istanbul ignore next */
export const off = (function() {
if (!isServer && document.removeEventListener) {
return function(element, event, handler) {
if (element && event) {
element.removeEventListener(event, handler, false)
}
}
} else {
return function(element, event, handler) {
if (element && event) {
element.detachEvent('on' + event, handler)
}
}
}
})()
/* istanbul ignore next */
export const once = function(el, event, fn) {
var listener = function() {
if (fn) {
fn.apply(this, arguments)
}
off(el, event, listener)
}
on(el, event, listener)
}
/* istanbul ignore next */
export function hasClass(el, cls) {
if (!el || !cls) return false
if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.')
if (el.classList) {
return el.classList.contains(cls)
} else {
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1
}
}
/* istanbul ignore next */
export function addClass(el, cls) {
if (!el) return
var curClass = el.className
var classes = (cls || '').split(' ')
for (var i = 0, j = classes.length; i < j; i++) {
var clsName = classes[i]
if (!clsName) continue
if (el.classList) {
el.classList.add(clsName)
} else if (!hasClass(el, clsName)) {
curClass += ' ' + clsName
}
}
if (!el.classList) {
el.className = curClass
}
}
/* istanbul ignore next */
export function removeClass(el, cls) {
if (!el || !cls) return
var classes = cls.split(' ')
var curClass = ' ' + el.className + ' '
for (var i = 0, j = classes.length; i < j; i++) {
var clsName = classes[i]
if (!clsName) continue
if (el.classList) {
el.classList.remove(clsName)
} else if (hasClass(el, clsName)) {
curClass = curClass.replace(' ' + clsName + ' ', ' ')
}
}
if (!el.classList) {
el.className = trim(curClass)
}
}
/* istanbul ignore next */
export const getStyle = ieVersion < 9 ? function(element, styleName) {
if (isServer) return
if (!element || !styleName) return null
styleName = camelCase(styleName)
if (styleName === 'float') {
styleName = 'styleFloat'
}
try {
switch (styleName) {
case 'opacity':
try {
return element.filters.item('alpha').opacity / 100
} catch (e) {
return 1.0
}
default:
return (element.style[styleName] || element.currentStyle ? element.currentStyle[styleName] : null)
}
} catch (e) {
return element.style[styleName]
}
} : function(element, styleName) {
if (isServer) return
if (!element || !styleName) return null
styleName = camelCase(styleName)
if (styleName === 'float') {
styleName = 'cssFloat'
}
try {
var computed = document.defaultView.getComputedStyle(element, '')
return element.style[styleName] || computed ? computed[styleName] : null
} catch (e) {
return element.style[styleName]
}
}
/* istanbul ignore next */
export function setStyle(element, styleName, value) {
if (!element || !styleName) return
if (typeof styleName === 'object') {
for (var prop in styleName) {
if (styleName.hasOwnProperty(prop)) {
setStyle(element, prop, styleName[prop])
}
}
} else {
styleName = camelCase(styleName)
if (styleName === 'opacity' && ieVersion < 9) {
element.style.filter = isNaN(value) ? '' : 'alpha(opacity=' + value * 100 + ')'
} else {
element.style[styleName] = value
}
}
}
export const isScroll = (el, vertical) => {
if (isServer) return
const determinedDirection = vertical !== null || vertical !== undefined
const overflow = determinedDirection
? vertical
? getStyle(el, 'overflow-y')
: getStyle(el, 'overflow-x')
: getStyle(el, 'overflow')
return overflow.match(/(scroll|auto)/)
}
export const getScrollContainer = (el, vertical) => {
if (isServer) return
let parent = el
while (parent) {
if ([window, document, document.documentElement].includes(parent)) {
return window
}
if (isScroll(parent, vertical)) {
return parent
}
parent = parent.parentNode
}
return parent
}
export const isInContainer = (el, container) => {
if (isServer || !el || !container) return false
const elRect = el.getBoundingClientRect()
let containerRect
if ([window, document, document.documentElement, null, undefined].includes(container)) {
containerRect = {
top: 0,
right: window.innerWidth,
bottom: window.innerHeight,
left: 0
}
} else {
containerRect = container.getBoundingClientRect()
}
return elRect.top < containerRect.bottom &&
elRect.bottom > containerRect.top &&
elRect.right > containerRect.left &&
elRect.left < containerRect.right
}

43
src/components/menu/_util/getRequestAnimationFrame.js

@ -0,0 +1,43 @@
const availablePrefixs = ['moz', 'ms', 'webkit']
function requestAnimationFramePolyfill() {
let lastTime = 0
return function(callback) {
const currTime = new Date().getTime()
const timeToCall = Math.max(0, 16 - (currTime - lastTime))
const id = window.setTimeout(function() {
const rs = currTime + timeToCall
callback(rs)
}, timeToCall)
lastTime = currTime + timeToCall
return id
}
}
export default function getRequestAnimationFrame() {
if (typeof window === 'undefined') {
return () => {}
}
if (window.requestAnimationFrame) {
// https://github.com/vuejs/vue/issues/4465
return window.requestAnimationFrame.bind(window)
}
const prefix = availablePrefixs.filter(key => `${key}RequestAnimationFrame` in window)[0]
return prefix
? window[`${prefix}RequestAnimationFrame`]
: requestAnimationFramePolyfill()
}
export function cancelRequestAnimationFrame(id) {
if (typeof window === 'undefined') {
return null
}
if (window.cancelAnimationFrame) {
return window.cancelAnimationFrame(id)
}
const prefix = availablePrefixs.filter(key => `${key}CancelAnimationFrame` in window || `${key}CancelRequestAnimationFrame` in window)[0]
return prefix ? (window[`${prefix}CancelAnimationFrame`] || window[`${prefix}CancelRequestAnimationFrame`]).call(this, id) : clearTimeout(id)
}

17
src/components/menu/_util/getScroll.js

@ -0,0 +1,17 @@
export default function getScroll(target, top) {
if (typeof window === 'undefined') {
return 0
}
const prop = top ? 'pageYOffset' : 'pageXOffset'
const method = top ? 'scrollTop' : 'scrollLeft'
const isWindow = target === window
let ret = isWindow ? target[prop] : target[method]
// ie6,7,8 standard mode
if (isWindow && typeof ret !== 'number') {
ret = window.document.documentElement[method]
}
return ret
}

1
src/components/menu/_util/icon.json

@ -0,0 +1 @@
["info","error","success","warning","question","back","arrow-left","arrow-down","arrow-right","arrow-up","caret-left","caret-bottom","caret-top","caret-right","d-arrow-left","d-arrow-right","minus","plus","remove","circle-plus","remove-outline","circle-plus-outline","close","check","circle-close","circle-check","circle-close-outline","circle-check-outline","zoom-out","zoom-in","d-caret","sort","sort-down","sort-up","tickets","document","goods","sold-out","news","message","date","printer","time","bell","mobile-phone","service","view","menu","more","more-outline","star-on","star-off","location","location-outline","phone","phone-outline","picture","picture-outline","delete","search","edit","edit-outline","rank","refresh","share","setting","upload","upload2","download","loading"]

14
src/components/menu/_util/merge.js

@ -0,0 +1,14 @@
export default function(target) {
for (let i = 1, j = arguments.length; i < j; i++) {
const source = arguments[i] || {}
for (const prop in source) {
if (source.hasOwnProperty(prop)) {
const value = source[prop]
if (value !== undefined) {
target[prop] = value
}
}
}
}
return target
}

1257
src/components/menu/_util/popper.js
File diff suppressed because it is too large
View File

218
src/components/menu/_util/popup/index.js

@ -0,0 +1,218 @@
import Vue from 'vue'
import merge from './../merge'
import PopupManager from './popup-manager'
import getScrollBarWidth from '../scrollbar-width'
import { getStyle, addClass, removeClass, hasClass } from '../dom'
let idSeed = 1
let scrollBarWidth
export default {
props: {
visible: {
type: Boolean,
default: false
},
openDelay: {},
closeDelay: {},
zIndex: {},
modal: {
type: Boolean,
default: false
},
modalFade: {
type: Boolean,
default: true
},
modalClass: {},
modalAppendToBody: {
type: Boolean,
default: false
},
lockScroll: {
type: Boolean,
default: true
},
closeOnPressEscape: {
type: Boolean,
default: false
},
closeOnClickModal: {
type: Boolean,
default: false
}
},
beforeMount() {
this._popupId = 'popup-' + idSeed++
PopupManager.register(this._popupId, this)
},
beforeDestroy() {
PopupManager.deregister(this._popupId)
PopupManager.closeModal(this._popupId)
this.restoreBodyStyle()
},
data() {
return {
opened: false,
bodyPaddingRight: null,
computedBodyPaddingRight: 0,
withoutHiddenClass: true,
rendered: false
}
},
watch: {
visible(val) {
if (val) {
if (this._opening) return
if (!this.rendered) {
this.rendered = true
Vue.nextTick(() => {
this.open()
})
} else {
this.open()
}
} else {
this.close()
}
}
},
methods: {
open(options) {
if (!this.rendered) {
this.rendered = true
}
const props = merge({}, this.$props || this, options)
if (this._closeTimer) {
clearTimeout(this._closeTimer)
this._closeTimer = null
}
clearTimeout(this._openTimer)
const openDelay = Number(props.openDelay)
if (openDelay > 0) {
this._openTimer = setTimeout(() => {
this._openTimer = null
this.doOpen(props)
}, openDelay)
} else {
this.doOpen(props)
}
},
doOpen(props) {
if (this.$isServer) return
if (this.willOpen && !this.willOpen()) return
if (this.opened) return
this._opening = true
const dom = this.$el
const modal = props.modal
const zIndex = props.zIndex
if (zIndex) {
PopupManager.zIndex = zIndex
}
if (modal) {
if (this._closing) {
PopupManager.closeModal(this._popupId)
this._closing = false
}
PopupManager.openModal(this._popupId, PopupManager.nextZIndex(), this.modalAppendToBody ? undefined : dom, props.modalClass, props.modalFade)
if (props.lockScroll) {
this.withoutHiddenClass = !hasClass(document.body, 'mds-popup-parent--hidden')
if (this.withoutHiddenClass) {
this.bodyPaddingRight = document.body.style.paddingRight
this.computedBodyPaddingRight = parseInt(getStyle(document.body, 'paddingRight'), 10)
}
scrollBarWidth = getScrollBarWidth()
const bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight
const bodyOverflowY = getStyle(document.body, 'overflowY')
if (scrollBarWidth > 0 && (bodyHasOverflow || bodyOverflowY === 'scroll') && this.withoutHiddenClass) {
document.body.style.paddingRight = this.computedBodyPaddingRight + scrollBarWidth + 'px'
}
addClass(document.body, 'mds-popup-parent--hidden')
}
}
if (getComputedStyle(dom).position === 'static') {
dom.style.position = 'absolute'
}
dom.style.zIndex = PopupManager.nextZIndex()
this.opened = true
this.onOpen && this.onOpen()
this.doAfterOpen()
},
doAfterOpen() {
this._opening = false
},
close() {
if (this.willClose && !this.willClose()) return
if (this._openTimer !== null) {
clearTimeout(this._openTimer)
this._openTimer = null
}
clearTimeout(this._closeTimer)
const closeDelay = Number(this.closeDelay)
if (closeDelay > 0) {
this._closeTimer = setTimeout(() => {
this._closeTimer = null
this.doClose()
}, closeDelay)
} else {
this.doClose()
}
},
doClose() {
this._closing = true
this.onClose && this.onClose()
if (this.lockScroll) {
setTimeout(this.restoreBodyStyle, 200)
}
this.opened = false
this.doAfterClose()
},
doAfterClose() {
PopupManager.closeModal(this._popupId)
this._closing = false
},
restoreBodyStyle() {
if (this.modal && this.withoutHiddenClass) {
document.body.style.paddingRight = this.bodyPaddingRight
removeClass(document.body, 'mds-popup-parent--hidden')
}
this.withoutHiddenClass = true
}
}
}
export {
PopupManager
}

194
src/components/menu/_util/popup/popup-manager.js

@ -0,0 +1,194 @@
import Vue from 'vue'
import { addClass, removeClass } from '../dom'
let hasModal = false
let hasInitZIndex = false
let zIndex
const getModal = function() {
if (Vue.prototype.$isServer) return
let modalDom = PopupManager.modalDom
if (modalDom) {
hasModal = true
} else {
hasModal = false
modalDom = document.createElement('div')
PopupManager.modalDom = modalDom
modalDom.addEventListener('touchmove', function(event) {
event.preventDefault()
event.stopPropagation()
})
modalDom.addEventListener('click', function() {
PopupManager.doOnModalClick && PopupManager.doOnModalClick()
})
}
return modalDom
}
const instances = {}
const PopupManager = {
modalFade: true,
getInstance: function(id) {
return instances[id]
},
register: function(id, instance) {
if (id && instance) {
instances[id] = instance
}
},
deregister: function(id) {
if (id) {
instances[id] = null
delete instances[id]
}
},
nextZIndex: function() {
return PopupManager.zIndex++
},
modalStack: [],
doOnModalClick: function() {
const topItem = PopupManager.modalStack[PopupManager.modalStack.length - 1]
if (!topItem) return
const instance = PopupManager.getInstance(topItem.id)
if (instance && instance.closeOnClickModal) {
instance.close()
}
},
openModal: function(id, zIndex, dom, modalClass, modalFade) {
if (Vue.prototype.$isServer) return
if (!id || zIndex === undefined) return
this.modalFade = modalFade
const modalStack = this.modalStack
for (let i = 0, j = modalStack.length; i < j; i++) {
const item = modalStack[i]
if (item.id === id) {
return
}
}
const modalDom = getModal()
addClass(modalDom, 'v-modal')
if (this.modalFade && !hasModal) {
addClass(modalDom, 'v-modal-enter')
}
if (modalClass) {
const classArr = modalClass.trim().split(/\s+/)
classArr.forEach(item => addClass(modalDom, item))
}
setTimeout(() => {
removeClass(modalDom, 'v-modal-enter')
}, 200)
if (dom && dom.parentNode && dom.parentNode.nodeType !== 11) {
dom.parentNode.appendChild(modalDom)
} else {
document.body.appendChild(modalDom)
}
if (zIndex) {
modalDom.style.zIndex = zIndex
}
modalDom.tabIndex = 0
modalDom.style.display = ''
this.modalStack.push({ id: id, zIndex: zIndex, modalClass: modalClass })
},
closeModal: function(id) {
const modalStack = this.modalStack
const modalDom = getModal()
if (modalStack.length > 0) {
const topItem = modalStack[modalStack.length - 1]
if (topItem.id === id) {
if (topItem.modalClass) {
const classArr = topItem.modalClass.trim().split(/\s+/)
classArr.forEach(item => removeClass(modalDom, item))
}
modalStack.pop()
if (modalStack.length > 0) {
modalDom.style.zIndex = modalStack[modalStack.length - 1].zIndex
}
} else {
for (let i = modalStack.length - 1; i >= 0; i--) {
if (modalStack[i].id === id) {
modalStack.splice(i, 1)
break
}
}
}
}
if (modalStack.length === 0) {
if (this.modalFade) {
addClass(modalDom, 'v-modal-leave')
}
setTimeout(() => {
if (modalStack.length === 0) {
if (modalDom.parentNode) modalDom.parentNode.removeChild(modalDom)
modalDom.style.display = 'none'
PopupManager.modalDom = undefined
}
removeClass(modalDom, 'v-modal-leave')
}, 200)
}
}
}
Object.defineProperty(PopupManager, 'zIndex', {
configurable: true,
get() {
if (!hasInitZIndex) {
zIndex = zIndex || (Vue.prototype.$ELEMENT || {}).zIndex || 2000
hasInitZIndex = true
}
return zIndex
},
set(value) {
zIndex = value
}
})
const getTopPopup = function() {
if (Vue.prototype.$isServer) return
if (PopupManager.modalStack.length > 0) {
const topPopup = PopupManager.modalStack[PopupManager.modalStack.length - 1]
if (!topPopup) return
const instance = PopupManager.getInstance(topPopup.id)
return instance
}
}
if (!Vue.prototype.$isServer) {
// handle `esc` key when the popup is shown
window.addEventListener('keydown', function(event) {
if (event.keyCode === 27) {
const topPopup = getTopPopup()
if (topPopup && topPopup.closeOnPressEscape) {
topPopup.handleClose
? topPopup.handleClose()
: (topPopup.handleAction ? topPopup.handleAction('cancel') : topPopup.close())
}
}
})
}
export default PopupManager

7
src/components/menu/_util/proptype.js

@ -0,0 +1,7 @@
/**
* Check if a value in validList
* @param {String} value
* @param {Array} validList
* @return {Boolean}
*/
export const oneOf = (value, validList) => validList.indexOf(value) > -1

24
src/components/menu/_util/repeatClick.js

@ -0,0 +1,24 @@
import { once, on } from './dom.js'
export default {
bind(el, binding, vnode) {
let interval = null
let startTime
const handler = () => vnode.context[binding.expression].apply()
const clear = () => {
if (Date.now() - startTime < 100) {
handler()
}
clearInterval(interval)
interval = null
}
on(el, 'mousedown', (e) => {
if (e.button !== 0) return
startTime = Date.now()
once(document, 'mouseup', clear)
clearInterval(interval)
interval = setInterval(handler, 100)
})
}
}

33
src/components/menu/_util/resizeEvent.js

@ -0,0 +1,33 @@
import ResizeObserver from 'resize-observer-polyfill'
const isServer = typeof window === 'undefined'
const resizeHandler = function(entries) {
for (const entry of entries) {
const listeners = entry.target.__resizeListeners__ || []
if (listeners.length) {
listeners.forEach(fn => {
fn()
})
}
}
}
export const addResizeListener = function(element, fn) {
if (isServer) return
if (!element.__resizeListeners__) {
element.__resizeListeners__ = []
element.__ro__ = new ResizeObserver(resizeHandler)
element.__ro__.observe(element)
}
element.__resizeListeners__.push(fn)
}
/* istanbul ignore next */
export const removeResizeListener = function(element, fn) {
if (!element || !element.__resizeListeners__) return
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1)
if (!element.__resizeListeners__.length) {
element.__ro__.disconnect()
}
}

27
src/components/menu/_util/scrollIntoView.js

@ -0,0 +1,27 @@
import Vue from 'vue'
export default function scrollIntoView(container, selected) {
if (Vue.prototype.$isServer) return
if (!selected) {
container.scrollTop = 0
return
}
const offsetParents = []
let pointer = selected.offsetParent
while (pointer && container !== pointer && container.contains(pointer)) {
offsetParents.push(pointer)
pointer = pointer.offsetParent
}
const top = selected.offsetTop + offsetParents.reduce((prev, curr) => (prev + curr.offsetTop), 0)
const bottom = top + selected.offsetHeight
const viewRectTop = container.scrollTop
const viewRectBottom = viewRectTop + container.clientHeight
if (top < viewRectTop) {
container.scrollTop = top
} else if (bottom > viewRectBottom) {
container.scrollTop = bottom - container.clientHeight
}
}

29
src/components/menu/_util/scrollbar-width.js

@ -0,0 +1,29 @@
import Vue from 'vue'
let scrollBarWidth
export default function() {
if (Vue.prototype.$isServer) return 0
if (scrollBarWidth !== undefined) return scrollBarWidth
const outer = document.createElement('div')
outer.className = 'mds-scrollbar__wrap'
outer.style.visibility = 'hidden'
outer.style.width = '100px'
outer.style.position = 'absolute'
outer.style.top = '-9999px'
document.body.appendChild(outer)
const widthNoScroll = outer.offsetWidth
outer.style.overflow = 'scroll'
const inner = document.createElement('div')
inner.style.width = '100%'
outer.appendChild(inner)
const widthWithScroll = inner.offsetWidth
outer.parentNode.removeChild(outer)
scrollBarWidth = widthNoScroll - widthWithScroll
return scrollBarWidth
}

35
src/components/menu/_util/soda.js

@ -0,0 +1,35 @@
import { assert } from './util'
class Soda {
constructor(vm, options = {}) {
this.mutations = options.mutations
assert(typeof options.state === 'function', 'Soda state must be a function.')
this.state = options.state()
this.root = vm
this.init(vm)
return this
}
commit(type, payload) {
this.mutations[type].call(this, this.state, payload)
}
init(root = this.root) {
const map = (_vm) => {
if (!_vm.$children.length) return
_vm.$children.forEach(child => {
inject(child)
map(child)
})
}
const inject = (_vm) => {
if (typeof _vm.soda === 'undefined' || typeof this.$soda !== 'undefined') return
_vm.$soda = this
_vm.soda = this.state
}
root.soda = this.state
map(root)
}
}
export default Soda

8
src/components/menu/_util/switchcase.js

@ -0,0 +1,8 @@
const executeIfFunction = f =>
typeof f === 'function' ? f() : f
export const switchcase = cases => defaultCase => key =>
key in cases ? cases[key] : defaultCase
export const switchcaseF = cases => defaultCase => key =>
executeIfFunction(switchcase(cases)(defaultCase)(key))

47
src/components/menu/_util/throttleByAnimationFrame.js

@ -0,0 +1,47 @@
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from './getRequestAnimationFrame'
const reqAnimFrame = getRequestAnimationFrame()
export default function throttleByAnimationFrame(fn) {
let requestId
const later = args => () => {
requestId = null
fn(...args)
}
const throttled = (...args) => {
if (requestId == null) {
requestId = reqAnimFrame(later(args))
}
}
throttled.cancel = () => cancelRequestAnimationFrame(requestId)
return throttled
}
export function throttleByAnimationFrameDecorator() {
return function(target, key, descriptor) {
const fn = descriptor.value
let definingProperty = false
return {
configurable: true,
get() {
if (definingProperty || this === target.prototype || this.hasOwnProperty(key)) {
return fn
}
const boundFn = throttleByAnimationFrame(fn.bind(this))
definingProperty = true
Object.defineProperty(this, key, {
value: boundFn,
configurable: true,
writable: true
})
definingProperty = false
return boundFn
}
}
}
}

237
src/components/menu/_util/tree/node.js

@ -0,0 +1,237 @@
let defaultId = new Date().getTime()
export default class Node {
constructor(options) {
this.id = defaultId++
this.checked = false
this.indeterminate = false
this.data = null
this.expanded = false
this.parent = null
this.isLeaf = false
for (const name in options) {
if (options.hasOwnProperty(name)) {
this[name] = options[name]
}
}
this.select = false
this.loaded = false
this.childNodes = []
this.loading = false
this.parent ? this.level = this.parent.level + 1 : this.level = 0
this.update(this.data)
}
update(data) {
const { prop } = this.tree
let children
this.markData(data)
if (this.key !== null) {
this.id = this.key
}
if (Array.isArray(data) && this.level === 0) {
children = data
this.id = 'root'
} else if (data.hasOwnProperty(prop.children)) {
children = data[prop.children]
} else {
if (!this.tree.lazy) this.isLeaf = true
}
if (Array.isArray(children) && children.length > 0) {
children.forEach(data => {
this.appendChild(data)
})
} else {
if (!this.tree.lazy) this.isLeaf = true
}
this.tree.nodesMap.set(this.id, this)
}
getTrueData(prop) {
const props = this.tree.prop[prop]
const data = this.data
if (data.hasOwnProperty(props)) {
return data[props]
} else if (data.hasOwnProperty(prop)) {
return data[prop]
} else {
return null
}
}
get label() {
return this.getTrueData('label')
}
get key() {
return this.getTrueData('key')
}
get disabled() {
return this.getTrueData('disabled')
}
get check() {
return this.checked
}
set check(val) {
if (val !== this.checked) {
this.checked = val
this.handleCheckChange()
}
}
get siblingsNodes() {
const arr = []
const currentNode = this
this.parent.childNodes.forEach(node => {
if (node.id !== currentNode.id) {
arr.push(node)
}
})
return arr
}
get checkedChildNodes() {
const arr = []
this.childNodes.forEach(node => {
if (node.checked) arr.push(node)
})
return arr
}
get indeterminateChildNodes() {
const arr = []
this.childNodes.forEach(node => {
if (node.checked || node.indeterminate) arr.push(node)
})
return arr
}
markData(data) {
Object.defineProperty(data, '_node', {
value: this,
enumerable: false,
configurable: false,
writable: false
})
if (!Array.isArray(data)) {
Object.defineProperty(data, '_nodeId', {
value: this.id,
enumerable: false,
configurable: false,
writable: false
})
} else if (this.level === 0) {
Object.defineProperty(data, '_nodeId', {
value: 'root',
enumerable: false,
configurable: false,
writable: false
})
}
}
get isExpanded() {
return this.expanded
}
set isExpanded(value) {
this.changeExpanded(value)
}
changeExpanded(value) {
if (this.tree.lazy && !this.loaded) {
this.loadNode()
} else {
this.expanded = value
}
if (this.tree.accordion && value) {
this.siblingsNodes.forEach(node => {
node.expanded = false
})
}
}
loadNode() {
const node = this
if (node.loaded || node.loading || !node.tree.lazy || node.childNodes.length > 0) {
return
}
node.loading = true
node.tree.load(node.data, (data) => {
if (!Array.isArray(data)) throw new Error('传入子元素必须是数组')
data.forEach(data => {
node.appendChild(data)
})
node.loading = false
node.loaded = true
node.check = false
node.expanded = true
})
}
getPath() {
const arr = []
let n = 0
let node = this
if (Array.isArray(this.tree.root)) {
n = 1
}
while (node.level > n) {
arr.push(node.data)
node = node.parent
}
return arr
}
handleCheckChange() {
const checked = this.checked
this.childNodes.forEach(node => {
node.check = checked
})
if (this.parent) {
this.parent.handleChildCheckChange()
}
}
handleChildCheckChange() {
if (Array.isArray(this.data) || this.level === 0) {
return
}
if (this.childNodes.length === this.checkedChildNodes.length && this.childNodes.length !== 0) {
this.checked = true
this.indeterminate = false
} else if (this.checkedChildNodes.length > 0) {
this.checked = false
this.indeterminate = true
} else {
this.checked = false
this.indeterminate = false
for (let i = 0; i < this.childNodes.length; i++) {
if (this.childNodes[i].indeterminate) {
this.indeterminate = true
break
}
}
}
this.parent.handleChildCheckChange()
}
appendChild(data, index) {
let isLeaf = false
this.isLeaf = false
if (data.hasOwnProperty(this.tree.prop.leaf)) isLeaf = data[this.tree.prop.leaf]
if (data.hasOwnProperty(this.tree.prop.key)) {
if (this.tree.nodesMap.get(data[this.tree.prop.key])) {
throw new Error('节点的key不能重复')
}
}
const child = new Node({
parent: this,
data: data,
index: this.childNodes.length,
tree: this.tree,
isLeaf
})
if (index) {
this.childNodes.splice(index, 0, child)
} else {
this.childNodes.push(child)
}
if (this.parent) this.parent.handleChildCheckChange()
}
remove() {
let node = this
const index = node.parent.childNodes.indexOf(node)
node.parent.childNodes.splice(index, 1)
node.parent.handleChildCheckChange()
node.tree.nodesMap.delete(node.id)
node = null
}
}

120
src/components/menu/_util/tree/tree.js

@ -0,0 +1,120 @@
import Node from './node'
const copyData = (data, tree) => {
const newData = {}
for (const key in data) {
if (data.hasOwnProperty(key) && key !== tree.prop.children) {
newData[key] = data[key]
}
}
return newData
}
const copyNode = (node, tree) => {
const newData = copyData(node.data, tree)
if (node.isLeaf) {
return newData
}
newData[tree.prop.children] = []
node.indeterminateChildNodes.forEach(item => {
newData[tree.prop.children].push(copyNode(item, tree))
})
return newData
}
export default class Tree {
constructor(options) {
this.accordion = true
for (const name in options) {
if (options.hasOwnProperty(name)) {
this[name] = options[name]
}
}
if (typeof this.prop !== 'object') {
this.prop = {
label: 'label',
key: 'key',
leaf: 'leaf',
disabled: 'disabled',
children: 'children'
}
}
if (this.lazy && !this.load) {
throw new Error('loadNodeFunction is required!')
}
this.nodesMap = new Map()
this.root = new Node({
data: this.data,
tree: this
})
}
getCheckNode() {
const arr = []
this.nodesMap.forEach(item => {
if (item.checked) {
arr.push(item.data)
}
})
return arr
}
setCheckNode(keys, bor = true) {
const nodesMap = this.nodesMap
if (Array.isArray(keys)) {
keys.forEach(item => {
const node = nodesMap.get(item)
if (node) node.check = bor
})
} else {
const node = nodesMap.get(keys)
if (node) nodesMap.get(keys).check = bor
}
}
getCheckNodeTree() {
const root = this.root
if (Array.isArray(root.data)) {
const newTree = []
root.indeterminateChildNodes.forEach(item => {
newTree.push(copyNode(item, this))
})
return newTree
} else {
return copyNode(root, this)
}
}
clearCheckNode() {
this.nodesMap.forEach(item => {
item.check = false
})
}
clearExpandNode() {
this.nodesMap.forEach(item => {
item.isExpanded = false
})
}
appendNodes(key, nodes) {
const parent = this.nodesMap.get(key)
if (!parent) {
return
}
if (Array.isArray(nodes)) {
if (typeof nodes === 'object') {
nodes.forEach(item => {
parent.appendChild(item)
})
}
} else if (typeof nodes === 'object') {
parent.appendChild(nodes)
}
}
delectNodeByKey(keys) {
if (Array.isArray(keys)) {
keys.forEach(item => {
const node = this.nodesMap.get(item)
if (node) node.remove()
})
} else {
const node = this.nodesMap.get(keys)
node.remove()
}
}
}

141
src/components/menu/_util/util.js

@ -0,0 +1,141 @@
import Vue from 'vue'
export const noop = () => {}
const getScroll = (w, top) => {
let ret = top ? w.pageYOffset : w.pageXOffset
const method = top ? 'scrollTop' : 'scrollLeft'
if (typeof ret !== 'number') {
const d = w.document
// ie6,7,8 standard mode
ret = d.documentElement[method]
if (typeof ret !== 'number') {
// quirks mode
ret = d.body[method]
}
}
return ret
}
const getClientPosition = elem => {
let box = null
let x
let y
const doc = elem.ownerDocument
const body = doc.body
const docElem = doc && doc.documentElement
box = elem.getBoundingClientRect()
x = box.left
y = box.top
x -= docElem.clientLeft || body.clientLeft || 0
y -= docElem.clientTop || body.clientTop || 0
return {
left: x,
top: y
}
}
export const getOffsetLeft = el => {
const pos = getClientPosition(el)
const doc = el.ownerDocument
const w = doc.defaultView || doc.parentWindow
pos.left += getScroll(w)
return pos.left
}
/**
* 获取对象深层级的对象避免循环
* @export
* @param {*} sourceObj 源对象 {a:{b:{d:1}}}
* @param {*} pathName path组成的数组 例如'a.b.c'
* @param {*} defaultValue 如果没有值默认的值 []
*/
export function getValueByPath(sourceObj, pathName, defaultValue) {
const getValue = function(sourceObj, pathNameArray) {
const key = pathNameArray.shift()
const value = sourceObj[key]
if (value === undefined || value === null) {
return defaultValue
} else if (pathNameArray.length === 0) {
return value
} else if (pathNameArray.length > 0) {
return getValue(value, pathNameArray)
}
}
const pathNameArray = pathName.split('.')
return getValue(sourceObj, pathNameArray)
}
/**
*
* 判断两个数是否相等
* @param {*} a
* @param {*} b
* @returns
*/
export const valueEquals = (a, b) => {
// see: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
if (a === b) return true
if (!(a instanceof Array)) return false
if (!(b instanceof Array)) return false
if (a.length !== b.length) return false
for (let i = 0; i !== a.length; ++i) {
if (a[i] !== b[i]) return false
}
return true
}
// TODO: use native Array.find, Array.findIndex when IE support is dropped
export const arrayFindIndex = function(arr, pred) {
for (let i = 0; i !== arr.length; ++i) {
if (pred(arr[i])) {
return i
}
}
return -1
}
export const arrayFind = function(arr, pred) {
const idx = arrayFindIndex(arr, pred)
return idx !== -1 ? arr[idx] : undefined
}
// coerce truthy value to array
export const coerceTruthyValueToArray = function(val) {
if (Array.isArray(val)) {
return val
} else if (val) {
return [val]
} else {
return []
}
}
export const isIE = function() {
return !Vue.prototype.$isServer && !isNaN(Number(document.documentMode))
}
export const isEdge = function() {
return !Vue.prototype.$isServer && navigator.userAgent.indexOf('Edge') > -1
}
export const isFirefox = function() {
return !Vue.prototype.$isServer && !!window.navigator.userAgent.match(/firefox/i)
}
export const assert = (condition, msg) => {
if (!condition) throw new Error(`[mds-ui] ${msg}`)
}
/**
*
* 特殊字符转译
* @param {string} [value='']
*/
export const escapeRegexpString = (value = '') => String(value).replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
/**
* Get element offset width
* @param {*} node HTMLDOMElemment
* @return {Number} width
*/
/**
* Get element offset width
* @param {*} node HTMLDOMElemment
* @return {Number} width
*/
export const getOffsetWidth = (node) => node ? node.offsetWidth : 0

205
src/components/menu/_util/vue-popper.js

@ -0,0 +1,205 @@
import Vue from 'vue'
import {
PopupManager
} from './popup'
import PopperJS2 from './popper.js'
// todo 可以替换但是 替换后功能有差异 待定
// import PopperJS2 from 'popper.js'
const PopperJS = Vue.prototype.$isServer ? function() {} : PopperJS2
const stop = e => e.stopPropagation()
/**
* @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper.
* @param {HTMLElement} [popper=$refs.popper] - The HTML element used as popper, or a configuration used to generate the popper.
* @param {String} [placement=button] - Placement of the popper accepted values: top(-start, -end), right(-start, -end), bottom(-start, -end), left(-start, -end)
* @param {Number} [offset=0] - Amount of pixels the popper will be shifted (can be negative).
* @param {Boolean} [visible=false] Visibility of the popup element.
* @param {Boolean} [visible-arrow=false] Visibility of the arrow, no style.
*/
export default {
props: {
transformOrigin: {
type: [Boolean, String],
default: true
},
placement: {
type: String,
default: 'bottom'
},
boundariesPadding: {
type: Number,
default: 5
},
reference: {},
popper: {},
offset: {
default: 0
},
value: Boolean,
visibleArrow: Boolean,
arrowOffset: {
type: Number,
default: 35
},
appendToBody: {
type: Boolean,
default: true
},
popperOptions: {
type: Object,
default() {
return {
gpuAcceleration: false
}
}
}
},
data() {
return {
showPopper: false,
currentPlacement: ''
}
},
watch: {
value: {
immediate: true,
handler(val) {
this.showPopper = val
this.$emit('input', val)
}
},
showPopper(val) {
if (this.disabled) return
val ? this.updatePopper() : this.destroyPopper()
this.$emit('input', val)
}
},
methods: {
createPopper() {
if (this.$isServer) return
this.currentPlacement = this.currentPlacement || this.placement
if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.currentPlacement)) {
return
}
const options = this.popperOptions
const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper
let reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference
if (!reference &&
this.$slots.reference &&
this.$slots.reference[0]) {
reference = this.referenceElm = this.$slots.reference[0].elm
}
if (!popper || !reference) return
if (this.visibleArrow) this.appendArrow(popper)
if (this.appendToBody) document.body.appendChild(this.popperElm)
if (this.popperJS && this.popperJS.destroy) {
this.popperJS.destroy()
}
options.placement = this.currentPlacement
options.offset = this.offset
options.arrowOffset = this.arrowOffset
this.popperJS = new PopperJS(reference, popper, options)
this.popperJS.onCreate(_ => {
this.$emit('created', this)
this.resetTransformOrigin()
this.$nextTick(this.updatePopper)
})
if (typeof options.onUpdate === 'function') {
this.popperJS.onUpdate(options.onUpdate)
}
this.popperJS._popper.style.zIndex = PopupManager.nextZIndex()
this.popperElm.addEventListener('click', stop)
},
updatePopper() {
const popperJS = this.popperJS
if (popperJS) {
popperJS.update()
if (popperJS._popper) {
popperJS._popper.style.zIndex = PopupManager.nextZIndex()
}
} else {
this.createPopper()
}
},
doDestroy(forceDestroy) {
/* istanbul ignore if */
if (!this.popperJS || (this.showPopper && !forceDestroy)) return
if (!forceDestroy) {
if (this.popperElm && this.popperElm.parentNode === document.body) {
this.popperElm.removeEventListener('click', stop)
document.body.removeChild(this.popperElm)
}
}
this.popperJS.destroy()
this.popperJS = null
},
destroyPopper() {
if (this.popperJS) {
this.resetTransformOrigin()
}
},
resetTransformOrigin() {
if (!this.transformOrigin) return
const placementMap = {
top: 'bottom',
bottom: 'top',
left: 'right',
right: 'left'
}
const placement = this.popperJS._popper.getAttribute('x-placement').split('-')[0]
const origin = placementMap[placement]
this.popperJS._popper.style.transformOrigin = typeof this.transformOrigin === 'string'
? this.transformOrigin
: ['top', 'bottom'].indexOf(placement) > -1 ? `center ${origin}` : `${origin} center`
},
appendArrow(element) {
let hash
if (this.appended) {
return
}
this.appended = true
for (const item in element.attributes) {
if (/^_v-/.test(element.attributes[item].name)) {
hash = element.attributes[item].name
break
}
}
const arrow = document.createElement('div')
if (hash) {
arrow.setAttribute(hash, '')
}
arrow.setAttribute('x-arrow', '')
arrow.className = 'popper__arrow'
element.appendChild(arrow)
}
},
beforeDestroy() {
this.doDestroy(true)
if (this.popperElm && this.popperElm.parentNode === document.body) {
this.popperElm.removeEventListener('click', stop)
document.body.removeChild(this.popperElm)
}
},
// call destroy in keep-alive mode
deactivated() {
this.$options.beforeDestroy[0].call(this)
}
}

13
src/components/menu/index.js

@ -0,0 +1,13 @@
import './style/index.js'
import MdsMenuLocal from './menu'
import MdsItemLocal from './menu-item'
import MdsSubMenuLocal from './menu-submenu'
import MdsItemGroupLocal from './menu-itemgroup'
export default {
MdsMenuLocal,
MdsItemLocal,
MdsSubMenuLocal,
MdsItemGroupLocal
}

95
src/components/menu/menu-item.vue

@ -0,0 +1,95 @@
<template>
<li
role="menuitem"
:aria-selected="selected"
:aria-disabled="disabled"
:class="classes"
:style="style"
@click="handleClick"
@keydown.enter="handleKeyDown"
>
<slot />
</li>
</template>
<script>
export default {
name: 'MdsMenuItemLocal',
inject: ['menuRoot'],
props: {
disabled: {
type: Boolean,
default: false
},
index: [String, Number]
},
_parent: null,
computed: {
classes() {
const prefixCls = this.menuRoot.prefixCls
return [
`${prefixCls}-item`,
{
[`${prefixCls}-item-disabled`]: this.disabled,
[`${prefixCls}-item-selected`]: this.selected
}
]
},
style() {
const res = {}
if (this.mode === 'inline' && this.level > 0) {
res['padding-left'] = this.level * this.inlineIndent + 'px'
}
return res
},
// From parent
multiple() {
return this.$options._parent.multiple
},
mode() {
if (this.inlineCollapsed) {
return 'vertical'
} else {
return this.$options._parent.mode
}
},
inlineCollapsed() {
return this.$options._parent.inlineCollapsed
},
selected() {
return this.$options._parent.selected.indexOf(this.index) > -1
},
level() {
return this.$options._parent.level + 1
},
path() {
return this.$options._parent.path.slice().concat(this.index)
},
inlineIndent() {
return this.$options._parent.inlineIndent
}
},
created() {
this.$options._parent = this.$parent
while (!this.$options._parent.mode) {
this.$options._parent = this.$options._parent.$parent
}
},
methods: {
handleClick(e) {
const info = {
e,
vm: this,
path: this.path,
index: this.index
}
this.$options._parent.handleClickItem(info)
this.multiple ? this.selected ? this.$options._parent.handleDeSelect(info) : this.$options._parent.handleSelect(info)
: !this.selected && this.$options._parent.handleSelect(info)
},
handleKeyDown(e) {
this.handleClick(e)
}
}
}
</script>

79
src/components/menu/menu-itemgroup.vue

@ -0,0 +1,79 @@
<template>
<li
:class="`${prefixCls}-item-group`"
>
<div
v-if="title"
:class="`${prefixCls}-item-group-title`"
:style="style"
v-text="title"
/>
<ul
v-if="$slots.default"
:class="`${prefixCls}-item-group-list`"
>
<slot />
</ul>
</li>
</template>
<script>
export default {
name: 'MdsMenuItemGroupLocal',
inject: ['menuRoot'],
props: {
title: String
},
_parent: null,
data() {
return {
prefixCls: this.menuRoot.prefixCls
}
},
computed: {
style() {
const res = {}
if (this.mode === 'inline' && this.level > 0) {
res['padding-left'] = (this.level + 1) * this.inlineIndent + 'px'
}
return res
},
mode() {
return this.$options._parent.mode
},
multiple() {
return this.$options._parent.multiple
},
level() {
return this.$options._parent.level
},
inlineIndent() {
return this.$options._parent.inlineIndent
},
path() {
return this.$options._parent.path.slice()
},
selected() {
return this.$options._parent.selected
},
handleClickItem() {
return this.$options._parent.handleClickItem
},
handleSelect() {
return this.$options._parent.handleSelect
},
handleDeSelect() {
return this.$options._parent.handleDeSelect
},
handleOpenChange() {
return this.$options._parent.handleOpenChange
}
},
created() {
this.$options._parent = this.$parent
while (!this.$options._parent.mode) {
this.$options._parent = this.$options._parent.$parent
}
}
}
</script>

158
src/components/menu/menu-submenu.vue

@ -0,0 +1,158 @@
<template>
<li
:aria-expanded="isOpen"
aria-haspopup="true"
:class="[
`${prefixCls}-submenu`,
`${prefixCls}-submenu-${mode}`,
disabled ? `${prefixCls}-submenu-disabled` : ``,
isOpen ? `${prefixCls}-submenu-open` : ``
]"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<div
v-if="$slots.title || title"
:class="`${prefixCls}-submenu-title`"
:style="style"
@click="handleClick"
>
<slot name="title">{{ title }}</slot>
<mds-icon type="down" :class="`${prefixCls}-submenu-title-after`" />
</div>
<mds-transition v-if="$slots.default" :type="animition.type" :motion="animition.motion">
<ul
v-show="isOpen"
:class="[
prefixCls,
`${prefixCls}-sub`,
`${prefixCls}-${subMode}`
]"
>
<slot />
</ul>
</mds-transition>
</li>
</template>
<script>
import { switchcase } from './_util/switchcase'
export default {
name: 'MdsMenuSubmenuLocal',
inject: ['menuRoot'],
props: {
disabled: {
type: Boolean,
default: false
},
index: [String, Number],
title: String
},
_parent: null,
data() {
return {
timer: null,
prefixCls: this.menuRoot.prefixCls
}
},
computed: {
animition() {
return switchcase({
'horizontal': {
type: 'slide',
motion: 'up'
},
'vertical': {
type: 'zoom',
motion: 'big'
},
'inline': {
type: 'collapse'
}
})('')(this.mode)
},
path() {
return this.$options._parent.path.slice().concat(this.index)
},
style() {
const res = {}
if (this.mode === 'inline' && this.level > 0) {
res['padding-left'] = this.level * this.inlineIndent + 'px'
}
return res
},
// From parent
mode() {
if (this.inlineCollapsed) {
return 'vertical'
} else {
return this.$options._parent.mode
}
},
inlineCollapsed() {
return this.$options._parent.inlineCollapsed
},
multiple() {
return this.$options._parent.multiple
},
subMode() {
if (this.inlineCollapsed) {
return 'vertical'
} else {
return this.$options._parent.mode === 'horizontal' ? 'vertical' : this.$options._parent.mode
}
},
level() {
return this.$options._parent.level + 1
},
inlineIndent() {
return this.$options._parent.inlineIndent
},
isOpen() {
return this.$options._parent.open.indexOf(this.index) > -1
},
open() {
return this.$options._parent.open
},
selected() {
return this.$options._parent.selected
},
handleClickItem() {
return this.$options._parent.handleClickItem
},
handleSelect() {
return this.$options._parent.handleSelect
},
handleDeSelect() {
return this.$options._parent.handleDeSelect
},
handleOpenChange() {
return this.$options._parent.handleOpenChange
}
},
created() {
this.$options._parent = this.$parent
while (!this.$options._parent.mode) {
this.$options._parent = this.$options._parent.$parent
}
},
methods: {
handleClick() {
if (this.mode !== 'inline') return
this.$options._parent.handleOpenChange(this.index, !this.isOpen)
},
handleMouseEnter(e) {
if (this.mode === 'inline') return
this.timer && clearTimeout(this.timer)
this.$options._parent.handleOpenChange(this.index, true)
},
handleMouseLeave(e) {
if (this.mode === 'inline') return
this.timer = setTimeout(() => {
this.$options._parent.handleOpenChange(this.index, false)
}, 100)
}
}
}
</script>

165
src/components/menu/menu.vue

@ -0,0 +1,165 @@
<template>
<ul
aria-activedescendant
role="menu"
:class="classes"
>
<slot />
</ul>
</template>
<script>
import { oneOf } from './_util/proptype'
export default {
name: 'MdsMenuLocal',
provide() {
return {
menuRoot: this
}
},
props: {
prefixCls: {
type: String,
default: 'mds-menu'
},
defaultSelectedKeys: {
type: Array,
default() {
return []
}
},
defaultOpenKeys: {
type: Array,
default() {
return []
}
},
inlineCollapsed: {
type: Boolean,
default: false
},
inlineIndent: {
type: Number,
default: 24
},
mode: {
type: String,
default: 'vertical',
validator(value) {
return oneOf(value, ['vertical', 'horizontal', 'inline'])
}
},
multiple: {
type: Boolean,
default: false
},
openKeys: {
type: Array,
default() {
return []
}
},
selectable: {
type: Boolean,
default: true
},
selectedKeys: {
type: Array,
default() {
return []
}
},
theme: {
type: String,
default: 'light',
validator(value) {
return oneOf(value, ['dark', 'light'])
}
}
},
data() {
return {
level: 0,
path: [],
selected: [],
open: []
}
},
computed: {
classes() {
const prefixCls = this.prefixCls
return [
`${prefixCls}`,
`${prefixCls}-root`,
`${prefixCls}-${this.theme}`,
`${prefixCls}-${this.mode}`,
{
[`${prefixCls}-inline-collapsed`]: this.inlineCollapsed
}
]
}
},
watch: {
openKeys(value) {
this.open = value.slice()
},
selectedKeys(value) {
this.selected = value.slice()
},
inlineCollapsed(value) {
if (value) {
this.mode = 'vertical'
}
}
},
created() {
function mergeDefaultAndSetting(def, setting) {
const arr = setting.length ? setting.slice()
: def.length ? def.slice() : []
return arr
}
this.selected = mergeDefaultAndSetting(this.defaultSelectedKeys, this.selectedKeys)
this.open = mergeDefaultAndSetting(this.defaultOpenKeys, this.openKeys)
},
methods: {
handleClickItem(info) {
this.mode !== 'inline' && (this.open = [])
this.$emit('click', info)
},
handleDeSelect(info) {
const { index } = info
if (!this.selectable) return
this.removeArrayEle(this.selected, index)
this.$emit('de-select', info)
},
removeArrayEle(arr, val) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === val) {
arr.splice(i, 1)
break
}
}
},
handleOpenChange(index, isIncrease) {
let changed = false
const increaseOpen = () => {
const pos = this.open.indexOf(index)
pos < 0 && this.open.push(index) && (changed = true)
}
const deleteOpen = () => {
const pos = this.open.indexOf(index)
pos > -1 && this.open.splice(pos, 1) && (changed = true)
}
isIncrease ? increaseOpen() : deleteOpen()
changed && this.$emit('open-change', this.open)
},
handleSelect(info) {
const { index } = info
if (!this.selectable) return
this.selected = this.multiple ? this.selected.concat([index]) : [index]
info.selected = this.selected
this.$emit('select', info)
}
}
}
</script>

2
src/components/menu/style/index.js

@ -0,0 +1,2 @@
import './style/index.less'
import './index.less'

717
src/components/menu/style/index.less

@ -0,0 +1,717 @@
@import "./style/themes/default";
@import "./style/mixins/index";
@menu-prefix-cls: ~"@{mds-prefix}-menu";
@menu-default-inline-submie-color: #CCD2DB;
@tooltip-prefix-cls: ~"@{mds-prefix}-tooltip";
// Base class
.@{tooltip-prefix-cls} {
position: absolute;
z-index: @zindex-tooltip;
display: block;
visibility: visible;
font-size: @font-size-base;
line-height: @line-height-base;
&-hidden {
display: none;
}
&-placement-top,
&-placement-topLeft,
&-placement-topRight {
padding-bottom: @tooltip-distance;
}
&-placement-right,
&-placement-rightTop,
&-placement-rightBottom {
padding-left: @tooltip-distance;
}
&-placement-bottom,
&-placement-bottomLeft,
&-placement-bottomRight {
padding-top: @tooltip-distance;
}
&-placement-left,
&-placement-leftTop,
&-placement-leftBottom {
padding-right: @tooltip-distance;
}
}
// Wrapper for the tooltip content
.@{tooltip-prefix-cls}-inner {
max-width: @tooltip-max-width;
padding: 8px 16px;
color: @tooltip-color;
text-align: center;
text-decoration: none;
background-color: @tooltip-bg;
border-radius: @border-radius-base;
box-shadow: @box-shadow-base;
min-height: 34px;
font-size:@f14;
font-family:PingFangSC-Regular;
font-weight:@w400;
line-height:22px;
}
// Arrows
.@{tooltip-prefix-cls}-arrow {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.@{tooltip-prefix-cls} {
&-placement-top &-arrow,
&-placement-topLeft &-arrow,
&-placement-topRight &-arrow {
bottom: @tooltip-distance - @tooltip-arrow-width;
border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
border-top-color: @tooltip-arrow-color;
}
&-placement-top &-arrow {
left: 50%;
margin-left: -@tooltip-arrow-width;
}
&-placement-topLeft &-arrow {
left: 16px;
}
&-placement-topRight &-arrow {
right: 16px;
}
&-placement-right &-arrow,
&-placement-rightTop &-arrow,
&-placement-rightBottom &-arrow {
left: @tooltip-distance - @tooltip-arrow-width;
border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;
border-right-color: @tooltip-arrow-color;
}
&-placement-right &-arrow {
top: 50%;
margin-top: -@tooltip-arrow-width;
}
&-placement-rightTop &-arrow {
top: 8px;
}
&-placement-rightBottom &-arrow {
bottom: 8px;
}
&-placement-left &-arrow,
&-placement-leftTop &-arrow,
&-placement-leftBottom &-arrow {
right: @tooltip-distance - @tooltip-arrow-width;
border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;
border-left-color: @tooltip-arrow-color;
}
&-placement-left &-arrow {
top: 50%;
margin-top: -@tooltip-arrow-width;
}
&-placement-leftTop &-arrow {
top: 8px;
}
&-placement-leftBottom &-arrow {
bottom: 8px;
}
&-placement-bottom &-arrow,
&-placement-bottomLeft &-arrow,
&-placement-bottomRight &-arrow {
top: @tooltip-distance - @tooltip-arrow-width;
border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
border-bottom-color: @tooltip-arrow-color;
}
&-placement-bottom &-arrow {
left: 50%;
margin-left: -@tooltip-arrow-width;
}
&-placement-bottomLeft &-arrow {
left: 16px;
}
&-placement-bottomRight &-arrow {
right: 16px;
}
}
// default theme
.@{menu-prefix-cls} {
outline: none;
margin-bottom: 0;
padding-left: 0; // Override default ul/ol
list-style: none;
z-index: @zindex-dropdown;
box-shadow: @box-shadow-base;
color: @text-color-base ;
background: @component-background;
line-height: 46px;
transition: background .3s, width .2s;
&-hidden {
display: none;
}
&-item-group-list {
margin: 0;
padding: 0;
}
&-item-group-title {
color: @text-color-secondary;
font-size:@menu-font-size;
line-height: @line-height-base;
padding: 8px 16px;
transition: all .3s;
}
&-item .point{
position: relative;
top :-2px;
display: inline-block;
width: 3px;
height: 3px;
margin-right: 10px;
border-radius: 50%;
background:rgba(200,208,221,1);
vertical-align: middle;
}
&-item,
&-submenu,
&-submenu-title {
vertical-align: middle;
cursor: pointer;
}
&-submenu, &-submenu-inline {
transition: border-color .3s @ease-in-out, background .3s @ease-in-out, padding .15s @ease-in-out;
}
&-item, &-submenu-title {
transition: color .3s @ease-in-out, border-color .3s @ease-in-out, background .3s @ease-in-out, padding .15s @ease-in-out;
}
&-item:active,
&-submenu-title:active {
background: @item-active-bg;
}
&-submenu &-sub {
cursor: initial;
transition: background .3s @ease-in-out, padding .3s @ease-in-out;
}
&-item > a {
display: block;
color: @text-color;
&:hover {
color: @primary-color;
}
&:focus {
text-decoration: none;
}
&:before {
position: absolute;
background-color: transparent;
width: 100%;
height: 100%;
top: 0;
left: 0;
bottom: 0;
right: 0;
content: '';
}
}
&-item-divider {
height: 1px;
overflow: hidden;
background-color: @border-color-split;
line-height: 0;
}
&-item:hover,
&-item-active,
&:not(&-inline) &-submenu-open,
&-submenu-active,
&-submenu-title:hover {
color: @primary-color;
}
&:not(&-inline) &-submenu-open {
z-index: @zindex-dropdown;
}
&-horizontal &-item,
&-horizontal &-submenu {
margin-top: -1px;
}
&-horizontal > &-item:hover,
&-horizontal > &-item-active,
&-horizontal > &-submenu &-submenu-title:hover {
background-color: transparent;
}
&-item-selected {
color: #0366FF;
> a,
> a:hover {
color: #0366FF;
}
.point{
background-color: #0366FF;
}
}
&:not(&-horizontal) &-item-selected {
background:rgba(237,243,254,1)
}
&-horizontal,
&-inline,
&-vertical {
z-index: auto;
}
&-inline,
&-vertical {
// border-right: @border-width-base @border-style-base @border-color-split;
.@{menu-prefix-cls}-item {
margin-left: -1px;
left: 1px;
position: relative;
z-index: 1;
&:after {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
border-left: 3px solid #0366ff;
transform: scaleY(.0001);
opacity: 0;
transition: transform .15s @ease-out, opacity .15s @ease-out;
}
}
}
&-vertical&-sub {
border-right: 0;
.@{menu-prefix-cls}-item {
border-right: 0;
margin-left: 0;
left: 0;
&:after {
border-right: 0;
}
}
> .@{menu-prefix-cls}-item:first-child {
border-radius: @border-radius-base @border-radius-base 0 0;
}
> .@{menu-prefix-cls}-item:last-child,
> .@{menu-prefix-cls}-item-group:last-child > .@{menu-prefix-cls}-item-group-list:last-child > .@{menu-prefix-cls}-item:last-child {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
> .@{menu-prefix-cls}-item:only-child {
border-radius: @border-radius-base;
}
}
&-inline {
width: 100%;
.@{menu-prefix-cls}-selected,
.@{menu-prefix-cls}-item-selected {
&:after {
transition: transform .15s @ease-in-out, opacity .15s @ease-in-out;
opacity: 1;
transform: scaleY(1);
}
}
}
&-submenu-horizontal > & {
top: 100%;
left: 0;
position: absolute;
min-width: 100%;
margin-top: 7px;
z-index: @zindex-dropdown;
}
&-submenu-vertical {
z-index: 1;
}
&-submenu-vertical > & {
top: 0;
left: 100%;
position: absolute;
min-width: 160px;
margin-left: 4px;
z-index: @zindex-dropdown;
}
&-item,
&-submenu-title {
margin: 0;
padding: 0 20px;
position: relative;
display: block;
white-space: nowrap;
.@{iconfont-css-prefix} {
width:16px;
margin-right: 8px;
transition: font-size .15s @ease-out, margin .3s @ease-in-out;
+ span {
transition: opacity .3s @ease-in-out, width .3s @ease-in-out;
opacity: 1;
}
}
}
& > &-item-divider {
height: 1px;
margin: 1px 0;
overflow: hidden;
padding: 0;
line-height: 0;
background-color: @border-color-split;
}
&-submenu {
position: relative;
> .@{menu-prefix-cls} {
background-color: @component-background;
border-radius: @border-radius-base;
&-submenu-title:after {
transition: transform .3s @ease-in-out;
}
}
&-vertical > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-title-after {
// font-family: "mdsicon" !important;
font-style: normal;
vertical-align: baseline;
text-align: center;
text-transform: none;
text-rendering: auto;
position: absolute;
// content: "\e62a";
color: @menu-default-inline-submie-color;
font-size: 12px;
right: 16px;
top: 50%;
margin-top: -6px;
.ie-rotate(3);
transform: rotate(270deg);
}
&-inline > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-title-after {
// font-family: "mdsicon" !important;
font-style: normal;
vertical-align: baseline;
text-align: center;
text-transform: none;
text-rendering: auto;
position: absolute;
color: @menu-default-inline-submie-color;
// content: "\e62a";
right: 16px;
top: 50%;
margin-top: -6px;
font-size: 12px;
}
&-open {
&.@{menu-prefix-cls}-submenu-inline > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-title-after {
.ie-rotate(1);
transform: rotate(180deg);
}
}
}
&-vertical &-submenu-selected {
color: @primary-color;
> a {
color: @primary-color;
}
}
&-horizontal {
border: 0;
border-bottom: @border-width-base @border-style-base @border-color-split;
box-shadow: none;
z-index: 0;
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu {
position: relative;
top: 1px;
float: left;
border-bottom: 2px solid transparent;
&:hover,
&-active,
&-open,
&-selected {
border-bottom: 2px solid @primary-color;
color: @primary-color;
}
> a {
display: block;
color: @text-color;
&:hover {
color: @primary-color;
}
}
}
&:after {
content: "\20";
display: block;
height: 0;
clear: both;
}
}
&-vertical,
&-inline {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
padding: 0 16px;
font-size: @menu-font-size;
line-height: 44px;
height: 44px;
overflow: hidden;
text-overflow: ellipsis;
}
}
&-inline-collapsed {
width: @menu-collapsed-width;
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-item-group > .@{menu-prefix-cls}-item-group-list > .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
left: 0;
text-overflow: ellipsis;
padding: 0 (@menu-collapsed-width - 16px) / 2 !important;
.@{menu-prefix-cls}-submenu-title-after {
display: none;
}
.@{iconfont-css-prefix} {
font-size: 16px;
line-height: 42px;
margin: 0;
+ span {
max-width: 0;
display: inline-block !important;
opacity: 0;
}
}
}
&-tooltip {
pointer-events: none;
.@{iconfont-css-prefix} {
display: none;
}
a {
color: @text-color-dark;
}
}
.@{menu-prefix-cls}-item-group-title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding-left: 4px;
padding-right: 4px;
}
.@{menu-prefix-cls}-item-group-list {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
padding: 0 16px 0 28px;
}
}
}
&-item-group-list {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
padding: 0 16px 0 28px;
}
}
&-vertical&-sub {
padding: 0;
transform-origin: 0 0;
& > .@{menu-prefix-cls}-item,
& > .@{menu-prefix-cls}-submenu {
transform-origin: 0 0;
}
}
&-root&-vertical,
&-root&-inline {
box-shadow: none;
}
&-sub&-inline {
padding: 0;
border: 0;
box-shadow: none;
border-radius: 0;
& > .@{menu-prefix-cls}-item,
& > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
line-height: 44px;
height: 44px;
list-style-type: disc;
list-style-position: inside;
}
// & > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-sub .mds-menu-item-group {
// line-height: 44px;
// height: 44px;
// list-style-type: disc;
// list-style-position: inside;
// }
& .@{menu-prefix-cls}-item-group-title {
padding-left: 48px;
}
}
// Disabled state sets text to gray and nukes hover/tab effects
&-item-disabled,
&-submenu-disabled {
color: @disabled-color !important;
cursor: not-allowed;
background: none;
border-color: transparent !important;
> a {
color: @disabled-color !important;
pointer-events: none;
}
> .@{menu-prefix-cls}-submenu-title {
color: @disabled-color !important;
cursor: not-allowed;
}
}
}
// dark theme
.@{menu-prefix-cls} {
&-dark,
&-dark &-sub {
color: @menu-text-color-secondary-dark;
background: #2C405A;
}
&-dark &-inline&-sub {
background: #24364D;
}
&-dark&-horizontal {
border-bottom-color: @menu-dark-bg;
}
&-dark&-horizontal > &-item,
&-dark&-horizontal > &-submenu {
border-color: @menu-dark-bg;
border-bottom: 0;
}
&-dark &-item,
&-dark &-item-group-title,
&-dark &-item > a {
color:@menu-text-color-secondary-dark;
}
&-dark&-inline,
&-dark&-vertical {
border-right: 0;
}
&-dark&-inline &-item,
&-dark&-vertical &-item {
border-right: 0;
margin-left: 0;
left: 0;
&:after {
border-right: 0;
}
}
&-dark &-item:hover,
&-dark &-item-active,
&-dark &-submenu-active,
&-dark:not(&-inline) &-submenu-open,
&-dark &-submenu-selected,
&-dark &-submenu-title:hover {
background-color: transparent;
color: #fff;
> a {
color: #fff;
}
}
&-dark &-item-selected {
border-right: 0;
color: #fff;
&:after {
border-right: 0;
}
> a,
> a:hover {
color: #fff;
}
.point{
background-color: #fff;
}
}
&&-dark &-item-selected {
background-color: #0366ff;
}
// Disabled state sets text to dark gray and nukes hover/tab effects
&-dark &-item-disabled,
&-dark &-submenu-disabled {
&,
> a {
opacity: 0.8;
color: @disabled-color-dark !important;
}
> .@{menu-prefix-cls}-submenu-title {
color: @disabled-color-dark !important;
}
}
}

108
src/components/menu/style/style/color/bezierEasing.less

@ -0,0 +1,108 @@
/* stylelint-disable declaration-bang-space-before */
.bezierEasingMixin() {
@functions: ~`(function() {
var NEWTON_ITERATIONS = 4;
var NEWTON_MIN_SLOPE = 0.001;
var SUBDIVISION_PRECISION = 0.0000001;
var SUBDIVISION_MAX_ITERATIONS = 10;
var kSplineTableSize = 11;
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
var float32ArraySupported = typeof Float32Array === 'function';
function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
function C (aA1) { return 3.0 * aA1; }
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
function binarySubdivide (aX, aA, aB, mX1, mX2) {
var currentX, currentT, i = 0;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
if (currentX > 0.0) {
aB = currentT;
} else {
aA = currentT;
}
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
return currentT;
}
function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
var currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) {
return aGuessT;
}
var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
var BezierEasing = function (mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
throw new Error('bezier x values must be in [0, 1] range');
}
// Precompute samples table
var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
if (mX1 !== mY1 || mX2 !== mY2) {
for (var i = 0; i < kSplineTableSize; ++i) {
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
}
function getTForX (aX) {
var intervalStart = 0.0;
var currentSample = 1;
var lastSample = kSplineTableSize - 1;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
intervalStart += kSampleStepSize;
}
--currentSample;
// Interpolate to provide an initial guess for t
var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
var guessForT = intervalStart + dist * kSampleStepSize;
var initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= NEWTON_MIN_SLOPE) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
} else if (initialSlope === 0.0) {
return guessForT;
} else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
}
}
return function BezierEasing (x) {
if (mX1 === mY1 && mX2 === mY2) {
return x; // linear
}
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
if (x === 0) {
return 0;
}
if (x === 1) {
return 1;
}
return calcBezier(getTForX(x), mY1, mY2);
};
};
this.colorEasing = BezierEasing(0.26, 0.09, 0.37, 0.18);
})()`;
}
// It is hacky way to make this function will be compiled preferentially by less
// resolve error: `ReferenceError: colorPalette is not defined`
// https://github.com/mds-design/mds-motion/issues/44
.bezierEasingMixin();

46
src/components/menu/style/style/color/colorPalette.less

@ -0,0 +1,46 @@
@import "bezierEasing";
@import "tinyColor";
// We create a very complex algorithm which take the place of original tint/shade color system
// to make sure no one can understand it 👻
// and create an entire color palette magicly by inputing just a single primary color.
// We are using bezier-curve easing function and some color manipulations like tint/shade/darken/spin
.colorPaletteMixin() {
@functions: ~`(function() {
var warmDark = 0.5; // warm color darken radio
var warmRotate = -26; // warm color rotate degree
var coldDark = 0.55; // cold color darken radio
var coldRotate = 10; // cold color rotate degree
var getShadeColor = function(c) {
var shadeColor = tinycolor(c);
// warm and cold color will darken in different radio, and rotate in different degree
// warmer color
if (shadeColor.toRgb().r > shadeColor.toRgb().b) {
return shadeColor.darken(shadeColor.toHsl().l * warmDark * 100).spin(warmRotate).toHexString();
}
// colder color
return shadeColor.darken(shadeColor.toHsl().l * coldDark * 100).spin(coldRotate).toHexString();
}
var primaryEasing = colorEasing(0.6);
this.colorPalette = function(color, index) {
var currentEasing = colorEasing(index * 0.1);
// return light colors after tint
if (index <= 6) {
return tinycolor.mix(
'#ffffff',
color,
currentEasing * 100 / primaryEasing
).toHexString();
}
return tinycolor.mix(
getShadeColor(color),
color,
(1 - (currentEasing - primaryEasing) / (1 - primaryEasing)) * 100
).toHexString();
};
})()`;
}
// It is hacky way to make this function will be compiled preferentially by less
// resolve error: `ReferenceError: colorPalette is not defined`
// https://github.com/mds-design/mds-motion/issues/44
.colorPaletteMixin();

92
src/components/menu/style/style/color/colors.less

@ -0,0 +1,92 @@
@import 'colorPalette';
// color palettes
@blue-1: color(~`colorPalette("@{blue-6}", 1)`);
@blue-2: color(~`colorPalette("@{blue-6}", 2)`);
@blue-3: color(~`colorPalette("@{blue-6}", 3)`);
@blue-4: color(~`colorPalette("@{blue-6}", 4)`);
@blue-5: color(~`colorPalette("@{blue-6}", 5)`);
// @blue-6: #108ee9;
@blue-6: rgba(3,100,255,1);
@blue-7: color(~`colorPalette("@{blue-6}", 7)`);
@blue-8: color(~`colorPalette("@{blue-6}", 8)`);
@blue-9: color(~`colorPalette("@{blue-6}", 9)`);
@blue-10: color(~`colorPalette("@{blue-6}", 10)`);
@purple-1: color(~`colorPalette("@{purple-6}", 1)`);
@purple-2: color(~`colorPalette("@{purple-6}", 2)`);
@purple-3: color(~`colorPalette("@{purple-6}", 3)`);
@purple-4: color(~`colorPalette("@{purple-6}", 4)`);
@purple-5: color(~`colorPalette("@{purple-6}", 5)`);
@purple-6: #7265e6;
@purple-7: color(~`colorPalette("@{purple-6}", 7)`);
@purple-8: color(~`colorPalette("@{purple-6}", 8)`);
@purple-9: color(~`colorPalette("@{purple-6}", 9)`);
@purple-10: color(~`colorPalette("@{purple-6}", 10)`);
@cyan-1: color(~`colorPalette("@{cyan-6}", 1)`);
@cyan-2: color(~`colorPalette("@{cyan-6}", 2)`);
@cyan-3: color(~`colorPalette("@{cyan-6}", 3)`);
@cyan-4: color(~`colorPalette("@{cyan-6}", 4)`);
@cyan-5: color(~`colorPalette("@{cyan-6}", 5)`);
@cyan-6: #00a2ae;
@cyan-7: color(~`colorPalette("@{cyan-6}", 7)`);
@cyan-8: color(~`colorPalette("@{cyan-6}", 8)`);
@cyan-9: color(~`colorPalette("@{cyan-6}", 9)`);
@cyan-10: color(~`colorPalette("@{cyan-6}", 10)`);
@green-1: color(~`colorPalette("@{green-6}", 1)`);
@green-2: color(~`colorPalette("@{green-6}", 2)`);
@green-3: color(~`colorPalette("@{green-6}", 3)`);
@green-4: color(~`colorPalette("@{green-6}", 4)`);
@green-5: color(~`colorPalette("@{green-6}", 5)`);
@green-6: #00a854;
@green-7: color(~`colorPalette("@{green-6}", 7)`);
@green-8: color(~`colorPalette("@{green-6}", 8)`);
@green-9: color(~`colorPalette("@{green-6}", 9)`);
@green-10: color(~`colorPalette("@{green-6}", 10)`);
@pink-1: color(~`colorPalette("@{pink-6}", 1)`);
@pink-2: color(~`colorPalette("@{pink-6}", 2)`);
@pink-3: color(~`colorPalette("@{pink-6}", 3)`);
@pink-4: color(~`colorPalette("@{pink-6}", 4)`);
@pink-5: color(~`colorPalette("@{pink-6}", 5)`);
@pink-6: #f5317f;
@pink-7: color(~`colorPalette("@{pink-6}", 7)`);
@pink-8: color(~`colorPalette("@{pink-6}", 8)`);
@pink-9: color(~`colorPalette("@{pink-6}", 9)`);
@pink-10: color(~`colorPalette("@{pink-6}", 10)`);
@red-1: color(~`colorPalette("@{red-6}", 1)`);
@red-2: color(~`colorPalette("@{red-6}", 2)`);
@red-3: color(~`colorPalette("@{red-6}", 3)`);
@red-4: color(~`colorPalette("@{red-6}", 4)`);
@red-5: color(~`colorPalette("@{red-6}", 5)`);
// @red-6: #f04134;
@red-6: #EE3333;
@red-7: color(~`colorPalette("@{red-6}", 7)`);
@red-8: color(~`colorPalette("@{red-6}", 8)`);
@red-9: color(~`colorPalette("@{red-6}", 9)`);
@red-10: color(~`colorPalette("@{red-6}", 10)`);
@orange-1: color(~`colorPalette("@{orange-6}", 1)`);
@orange-2: color(~`colorPalette("@{orange-6}", 2)`);
@orange-3: color(~`colorPalette("@{orange-6}", 3)`);
@orange-4: color(~`colorPalette("@{orange-6}", 4)`);
@orange-5: color(~`colorPalette("@{orange-6}", 5)`);
@orange-6: #f56a00;
@orange-7: color(~`colorPalette("@{orange-6}", 7)`);
@orange-8: color(~`colorPalette("@{orange-6}", 8)`);
@orange-9: color(~`colorPalette("@{orange-6}", 9)`);
@orange-10: color(~`colorPalette("@{orange-6}", 10)`);
@yellow-1: color(~`colorPalette("@{yellow-6}", 1)`);
@yellow-2: color(~`colorPalette("@{yellow-6}", 2)`);
@yellow-3: color(~`colorPalette("@{yellow-6}", 3)`);
@yellow-4: color(~`colorPalette("@{yellow-6}", 4)`);
@yellow-5: color(~`colorPalette("@{yellow-6}", 5)`);
@yellow-6: #ffbf00;
@yellow-7: color(~`colorPalette("@{yellow-6}", 7)`);
@yellow-8: color(~`colorPalette("@{yellow-6}", 8)`);
@yellow-9: color(~`colorPalette("@{yellow-6}", 9)`);
@yellow-10: color(~`colorPalette("@{yellow-6}", 10)`);

1184
src/components/menu/style/style/color/tinyColor.less
File diff suppressed because it is too large
View File

126
src/components/menu/style/style/core/base.less

@ -0,0 +1,126 @@
@import "./normalize.less";
// http://stackoverflow.com/a/13611748/3040605
@font-face {
font-family: "Helvetica Neue For Number";
src: local("Helvetica Neue");
unicode-range: U+30-39;
}
* {
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); // remove tap highlight color for mobile safari
}
*:before,
*:after {
box-sizing: border-box;
}
// HTML & Body reset
html, body {
.square(100%);
}
body {
font-family: @font-family;
font-size: @font-size-base;
line-height: @line-height-base;
color: @text-color;
background-color: @body-background;
}
// unify the setting of elements's margin and padding for browsers
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 {
margin: 0;
padding: 0;
}
// Reset fonts for relevant elements
button,input,select,textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: inherit;
}
input[type="text"],
textarea {
-webkit-appearance: none;
}
ul,
ol {
list-style: none;
}
// Remove the clear button of a text input control in IE10+
input::-ms-clear, input::-ms-reveal {
display: none;
}
::selection {
background: @primary-color;
color: #fff;
}
// Headers
h1, h2, h3, h4, h5, h6 {
color: @heading-color;
font-weight: 500;
}
// Links
a {
color: @link-color;
background: transparent;
text-decoration: @link-decoration;
outline: none;
cursor: pointer;
transition: color .3s ease;
&:focus {
text-decoration: underline;
text-decoration-skip: ink;
}
&:hover {
color: @link-hover-color;
}
&:active {
color: @link-active-color;
}
&:active,
&:hover {
outline: 0;
text-decoration: @link-hover-decoration;
}
&[disabled] {
color: @disabled-color;
cursor: not-allowed;
pointer-events: none;
}
}
.@{mds-prefix}-divider {
margin: 0 6px;
display: inline-block;
height: 8px;
width: 1px;
background: #ccc;
}
code,
kbd,
pre,
samp {
font-family: @code-family;
}
// Utility classes
.clearfix {
.clearfix();
}

1181
src/components/menu/style/style/core/icon/iconfont.css
File diff suppressed because it is too large
View File

0
static/fonts/iconfont.0ce52ab.0ce52abc.eot → src/components/menu/style/style/core/icon/iconfont.eot

1
src/components/menu/style/style/core/icon/iconfont.js
File diff suppressed because it is too large
View File

0
static/img/iconfont.8d23e4e.8d23e4e4.svg → src/components/menu/style/style/core/icon/iconfont.svg

0
static/fonts/iconfont.13066b9.13066b99.ttf → src/components/menu/style/style/core/icon/iconfont.ttf

0
static/fonts/iconfont.5f85653.5f856534.woff → src/components/menu/style/style/core/icon/iconfont.woff

BIN
src/components/menu/style/style/core/icon/iconfont.woff2

2214
src/components/menu/style/style/core/iconfont.less
File diff suppressed because it is too large
View File

4
src/components/menu/style/style/core/index.less

@ -0,0 +1,4 @@
@import "../mixins/index";
@import "base";
@import "iconfont";
@import "motion";

15
src/components/menu/style/style/core/motion.less

@ -0,0 +1,15 @@
@import "../mixins/motion";
@import "motion/fade";
@import "motion/move";
@import "motion/other";
@import "motion/slide";
@import "motion/swing";
@import "motion/zoom";
// For common/openAnimation
.mds-motion-collapse {
overflow: hidden;
&-active {
transition: height .15s @ease-in-out, opacity .15s @ease-in-out !important;
}
}

31
src/components/menu/style/style/core/motion/fade.less

@ -0,0 +1,31 @@
.fade-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName);
.@{className}-enter,
.@{className}-appear {
opacity: 0;
animation-timing-function: linear;
}
.@{className}-leave {
animation-timing-function: linear;
}
}
.fade-motion(fade, antFade);
@keyframes antFadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes antFadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}

120
src/components/menu/style/style/core/motion/move.less

@ -0,0 +1,120 @@
.move-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName);
.@{className}-enter,
.@{className}-appear {
opacity: 0;
animation-timing-function: @ease-out-circ;
}
.@{className}-leave {
animation-timing-function: @ease-in-circ;
}
}
.move-motion(move-up, antMoveUp);
.move-motion(move-down, antMoveDown);
.move-motion(move-left, antMoveLeft);
.move-motion(move-right, antMoveRight);
@keyframes antMoveDownIn {
0% {
transform-origin: 0 0;
transform: translateY(100%);
opacity: 0;
}
100% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
}
@keyframes antMoveDownOut {
0% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateY(100%);
opacity: 0;
}
}
@keyframes antMoveLeftIn {
0% {
transform-origin: 0 0;
transform: translateX(-100%);
opacity: 0;
}
100% {
transform-origin: 0 0;
transform: translateX(0%);
opacity: 1;
}
}
@keyframes antMoveLeftOut {
0% {
transform-origin: 0 0;
transform: translateX(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes antMoveRightIn {
0% {
opacity: 0;
transform-origin: 0 0;
transform: translateX(100%);
}
100% {
opacity: 1;
transform-origin: 0 0;
transform: translateX(0%);
}
}
@keyframes antMoveRightOut {
0% {
transform-origin: 0 0;
transform: translateX(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateX(100%);
opacity: 0;
}
}
@keyframes antMoveUpIn {
0% {
transform-origin: 0 0;
transform: translateY(-100%);
opacity: 0;
}
100% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
}
@keyframes antMoveUpOut {
0% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateY(-100%);
opacity: 0;
}
}

10
src/components/menu/style/style/core/motion/other.less

@ -0,0 +1,10 @@
@keyframes loadingCircle {
0% {
transform-origin: 50% 50%;
transform: rotate(0deg);
}
100% {
transform-origin: 50% 50%;
transform: rotate(360deg);
}
}

120
src/components/menu/style/style/core/motion/slide.less

@ -0,0 +1,120 @@
.slide-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName);
.@{className}-enter,
.@{className}-appear {
opacity: 0;
animation-timing-function: @ease-out-quint;
}
.@{className}-leave {
animation-timing-function: @ease-in-quint;
}
}
.slide-motion(slide-up, antSlideUp);
.slide-motion(slide-down, antSlideDown);
.slide-motion(slide-left, antSlideLeft);
.slide-motion(slide-right, antSlideRight);
@keyframes antSlideUpIn {
0% {
opacity: 0;
transform-origin: 0% 0%;
transform: scaleY(.8);
}
100% {
opacity: 1;
transform-origin: 0% 0%;
transform: scaleY(1);
}
}
@keyframes antSlideUpOut {
0% {
opacity: 1;
transform-origin: 0% 0%;
transform: scaleY(1);
}
100% {
opacity: 0;
transform-origin: 0% 0%;
transform: scaleY(.8);
}
}
@keyframes antSlideDownIn {
0% {
opacity: 0;
transform-origin: 100% 100%;
transform: scaleY(.8);
}
100% {
opacity: 1;
transform-origin: 100% 100%;
transform: scaleY(1);
}
}
@keyframes antSlideDownOut {
0% {
opacity: 1;
transform-origin: 100% 100%;
transform: scaleY(1);
}
100% {
opacity: 0;
transform-origin: 100% 100%;
transform: scaleY(.8);
}
}
@keyframes antSlideLeftIn {
0% {
opacity: 0;
transform-origin: 0% 0%;
transform: scaleX(.8);
}
100% {
opacity: 1;
transform-origin: 0% 0%;
transform: scaleX(1);
}
}
@keyframes antSlideLeftOut {
0% {
opacity: 1;
transform-origin: 0% 0%;
transform: scaleX(1);
}
100% {
opacity: 0;
transform-origin: 0% 0%;
transform: scaleX(.8);
}
}
@keyframes antSlideRightIn {
0% {
opacity: 0;
transform-origin: 100% 0%;
transform: scaleX(.8);
}
100% {
opacity: 1;
transform-origin: 100% 0%;
transform: scaleX(1);
}
}
@keyframes antSlideRightOut {
0% {
opacity: 1;
transform-origin: 100% 0%;
transform: scaleX(1);
}
100% {
opacity: 0;
transform-origin: 100% 0%;
transform: scaleX(.8);
}
}

33
src/components/menu/style/style/core/motion/swing.less

@ -0,0 +1,33 @@
.swing-motion(@className, @keyframeName) {
.@{className}-enter,
.@{className}-appear {
.motion-common();
animation-play-state: paused;
}
.@{className}-enter.@{className}-enter-active,
.@{className}-appear.@{className}-appear-active {
animation-name: ~"@{keyframeName}In";
animation-play-state: running;
}
}
.swing-motion(swing, antSwing);
@keyframes antSwingIn {
0%,
100% {
transform: translateX(0);
}
20% {
transform: translateX(-10px);
}
40% {
transform: translateX(10px);
}
60% {
transform: translateX(-5px);
}
80% {
transform: translateX(5px);
}
}

160
src/components/menu/style/style/core/motion/zoom.less

@ -0,0 +1,160 @@
.zoom-motion(@className, @keyframeName, @duration: @animation-duration-base) {
.make-motion(@className, @keyframeName, @duration);
.@{className}-enter,
.@{className}-appear {
transform: scale(0); // need this by yiminghe
animation-timing-function: @ease-out-circ;
}
.@{className}-leave {
animation-timing-function: @ease-in-out-circ;
}
}
// For Modal, Select choosen item
.zoom-motion(zoom, antZoom);
// For Popover, Popconfirm, Dropdown
.zoom-motion(zoom-big, antZoomBig);
// For Tooltip
.zoom-motion(zoom-big-fast, antZoomBig, @animation-duration-fast);
.zoom-motion(zoom-up, antZoomUp);
.zoom-motion(zoom-down, antZoomDown);
.zoom-motion(zoom-left, antZoomLeft);
.zoom-motion(zoom-right, antZoomRight);
@keyframes antZoomIn {
0% {
opacity: 0;
transform: scale(0.2);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@keyframes antZoomOut {
0% {
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(0.2);
}
}
@keyframes antZoomBigIn {
0% {
opacity: 0;
transform: scale(.8);
}
100% {
transform: scale(1);
}
}
@keyframes antZoomBigOut {
0% {
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(.8);
}
}
@keyframes antZoomUpIn {
0% {
opacity: 0;
transform-origin: 50% 0%;
transform: scale(.8);
}
100% {
transform-origin: 50% 0%;
transform: scale(1);
}
}
@keyframes antZoomUpOut {
0% {
transform-origin: 50% 0%;
transform: scale(1);
}
100% {
opacity: 0;
transform-origin: 50% 0%;
transform: scale(.8);
}
}
@keyframes antZoomLeftIn {
0% {
opacity: 0;
transform-origin: 0% 50%;
transform: scale(.8);
}
100% {
transform-origin: 0% 50%;
transform: scale(1);
}
}
@keyframes antZoomLeftOut {
0% {
transform-origin: 0% 50%;
transform: scale(1);
}
100% {
opacity: 0;
transform-origin: 0% 50%;
transform: scale(.8);
}
}
@keyframes antZoomRightIn {
0% {
opacity: 0;
transform-origin: 100% 50%;
transform: scale(.8);
}
100% {
transform-origin: 100% 50%;
transform: scale(1);
}
}
@keyframes antZoomRightOut {
0% {
transform-origin: 100% 50%;
transform: scale(1);
}
100% {
opacity: 0;
transform-origin: 100% 50%;
transform: scale(.8);
}
}
@keyframes antZoomDownIn {
0% {
opacity: 0;
transform-origin: 50% 100%;
transform: scale(.8);
}
100% {
transform-origin: 50% 100%;
transform: scale(1);
}
}
@keyframes antZoomDownOut {
0% {
transform-origin: 50% 100%;
transform: scale(1);
}
100% {
opacity: 0;
transform-origin: 50% 100%;
transform: scale(.8);
}
}

447
src/components/menu/style/style/core/normalize.less

@ -0,0 +1,447 @@
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in
* IE on Windows Phone and in iOS.
*/
html {
line-height: 1.15; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers (opinionated).
*/
body {
margin: 0;
}
/**
* Add the correct display in IE 9-.
*/
article,
aside,
footer,
header,
nav,
section {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* Add the correct display in IE 9-.
* 1. Add the correct display in IE.
*/
figcaption,
figure,
main { /* 1 */
display: block;
}
/**
* Add the correct margin in IE 8.
*/
figure {
margin: 1em 40px;
}
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */ /* stylelint-disable-line */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* 1. Remove the gray background on active links in IE 10.
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
*/
a {
background-color: transparent; /* 1 */
-webkit-text-decoration-skip: objects; /* 2 */
}
/**
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
*/
b,
strong {
font-weight: inherit;
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */ /* stylelint-disable-line */
font-size: 1em; /* 2 */
}
/**
* Add the correct font style in Android 4.3-.
*/
dfn {
font-style: italic;
}
/**
* Add the correct background and color in IE 9-.
*/
mark {
background-color: #ff0;
color: #000;
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
audio,
video {
display: inline-block;
}
/**
* Add the correct display in iOS 4-7.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Remove the border on images inside links in IE 10-.
*/
img {
border-style: none;
}
/**
* Hide the overflow in IE.
*/
svg:not(:root) {
overflow: hidden;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers (opinionated).
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: sans-serif; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
* controls in Android 4.
* 2. Correct the inability to style clickable types in iOS and Safari.
*/
button,
html [type="button"], /* 1 */
[type="reset"],
[type="submit"] {
-webkit-appearance: button; /* 2 */
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* 1. Add the correct display in IE 9-.
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Remove the default vertical scrollbar in IE.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10-.
* 2. Remove the padding in IE 10-.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in IE 9-.
* 1. Add the correct display in Edge, IE, and Firefox.
*/
details, /* 1 */
menu {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Scripting
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
canvas {
display: inline-block;
}
/**
* Add the correct display in IE.
*/
template {
display: none;
}
/* Hidden
========================================================================== */
/**
* Add the correct display in IE 10-.
*/
[hidden] {
display: none;
}

1
src/components/menu/style/style/index.js

@ -0,0 +1 @@
import './index.less'

2
src/components/menu/style/style/index.less

@ -0,0 +1,2 @@
@import "./themes/default";
@import "./core/index";

16
src/components/menu/style/style/mixins/clearfix.less

@ -0,0 +1,16 @@
// mixins for clearfix
// ------------------------
.clearfix() {
zoom: 1;
&:before,
&:after {
content: " ";
display: table;
}
&:after {
clear: both;
visibility: hidden;
font-size: 0;
height: 0;
}
}

45
src/components/menu/style/style/mixins/compatibility.less

@ -0,0 +1,45 @@
// Compatibility for browsers.
// rotate for ie8 and blow
.ie-rotate(@rotation) {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
}
// rotate for ie8 and blow
// degrees unit
.ie-rotate-via-degrees(@degrees) {
/* IE6-IE8 */
@radians: ~`parseInt("@{degrees}") * Math.PI * 2 / 360`;
@costheta: ~`Math.cos("@{radians}")`;
@sintheta: ~`Math.sin("@{radians}")`;
@negsintheta: ~`"@{sintheta}" * -1`;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=@{costheta}, M12=@{negsintheta}, M21=@{sintheta}, M22=@{costheta})";
zoom: 1;
:root & {
filter: none;
}
}
// support rotate for all browsers
.cross-rotate(@degrees) {
.rotate(@degrees);
.ie-rotate-via-degrees(@degrees);
}
// Placeholder text
.placeholder(@color: @input-placeholder-color) {
// Firefox
&::-moz-placeholder {
color: @color;
opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526
}
// Internet Explorer 10+
&:-ms-input-placeholder {
color: @color;
}
// Safari and Chrome
&::-webkit-input-placeholder {
color: @color;
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save