diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..962a1c63f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "eslintIntegration": true, + "singleQuote": true, + "semi": false +} diff --git a/packages/veui-loader/src/index.js b/packages/veui-loader/src/index.js index 105a120fc..7b159408b 100644 --- a/packages/veui-loader/src/index.js +++ b/packages/veui-loader/src/index.js @@ -5,6 +5,13 @@ import slash from 'slash' import loaderUtils from 'loader-utils' import { kebabCase, camelCase, pascalCase, getJSON, normalize } from './utils' import COMPONENTS from 'veui/components.json' +import getDebug from "debug" + +const debug = getDebug('veui-loader:') +const debugFilterKeyword = (process.env.DEBUG_FILTER_KEYWORD || '').toLowerCase() +const debugFilter = function (modulePath) { + return debugFilterKeyword ? modulePath.toLowerCase().indexOf(debugFilterKeyword) >= 0 : true +} const COMPONENTS_DIRNAME = 'components' const EXT_TYPES = { @@ -179,6 +186,7 @@ function getParts (component, options) { template: fileName }) let peerPath = slash(path.join(pack, packPath, peerComponent)) + if (debugFilter(peerPath)) debug(`Peer path: ${peerPath}`) pushPart(acc, { path: peerPath }) return acc }, @@ -278,7 +286,11 @@ async function assurePath (modulePath, resolve) { if (typeof resolve === 'function') { try { resolveCache[modulePath] = !!(await resolve(modulePath)) + if (!resolveCache[modulePath]) { + if (debugFilter(modulePath)) debug(`Not found: ${modulePath}`) + } } catch (e) { + if (debugFilter(modulePath)) debug(`Can not resolve module: ${modulePath}`) resolveCache[modulePath] = false } } diff --git a/packages/veui-theme-one/components/ColorPalette.js b/packages/veui-theme-one/components/ColorPalette.js new file mode 100644 index 000000000..af35d02ee --- /dev/null +++ b/packages/veui-theme-one/components/ColorPalette.js @@ -0,0 +1,10 @@ + +import config from 'veui/managers/config' + +config.defaults({ + ui: { + size: { + values: ['small'] + } + } +}, 'colorpalette') diff --git a/packages/veui-theme-one/components/ColorPicker.js b/packages/veui-theme-one/components/ColorPicker.js new file mode 100644 index 000000000..b20bd7727 --- /dev/null +++ b/packages/veui-theme-one/components/ColorPicker.js @@ -0,0 +1,26 @@ + +import config from 'veui/managers/config' + +config.defaults({ + ui: { + size: { + values: ['small'], + data: { + default: { + shadeFieldSize: [294, 294] + }, + small: { + shadeFieldSize: [248, 180] + } + } + }, + swatch: { + boolean: true, + default: false + }, + tip: { + boolean: true, + default: false + } + } +}, 'colorpicker') diff --git a/packages/veui-theme-one/components/ColorSwatch.js b/packages/veui-theme-one/components/ColorSwatch.js new file mode 100644 index 000000000..3778e4f7d --- /dev/null +++ b/packages/veui-theme-one/components/ColorSwatch.js @@ -0,0 +1,14 @@ + +import config from 'veui/managers/config' + +config.defaults({ + ui: { + size: { + values: ['small'] + }, + tip: { + boolean: true, + default: false + } + } +}, 'colorswatch') diff --git a/packages/veui-theme-one/components/color-palette.less b/packages/veui-theme-one/components/color-palette.less new file mode 100644 index 000000000..dae81fe60 --- /dev/null +++ b/packages/veui-theme-one/components/color-palette.less @@ -0,0 +1,68 @@ +@import "../lib.less"; + +.veui-color-palette { + padding: 10px 15px; + border-top: 1px solid @veui-gray-color-8; + + &-colors { + .clearfix(); + } + + &-color { + float: left; + margin: 5px; + width: @veui-height-tiny; + height: @veui-height-tiny; + border: 1px solid fade(@veui-gray-color-3, 20%); + border-radius: 4px; + + div { + width: 100%; + height: 100%; + } + + & > div { + .veui-transparency-grid-background(); + } + + // add button + line-height: @veui-height-tiny; + text-align: center; + background: @veui-gray-color-6; + + path { + fill: @veui-gray-color-5; + } + + &-outside { + opacity: .7; + position: relative; + z-index: 1; + + &::before { + content: "移除"; + position: absolute; + font-size: 12px; + width: 40px; + top: -20px; + left: -10px; + } + } + + &-putback { + transition: transform 300ms; + } + } + + &[ui~="small"] { + padding: 6px; + + .veui-color-palette-color { + margin: 4px; + width: 17px; + height: 17px; + line-height: 17px; + border-radius: 2px; + } + } +} diff --git a/packages/veui-theme-one/components/color-picker.less b/packages/veui-theme-one/components/color-picker.less new file mode 100644 index 000000000..df8c86ee2 --- /dev/null +++ b/packages/veui-theme-one/components/color-picker.less @@ -0,0 +1,101 @@ +@import "../lib.less"; + +.veui-color-shade-field { + position: relative; + + &-shade { + width: 100%; + height: 100%; + } + + &-aperture { + position: absolute; + top: 0; + left: 0; + width: 12px; + height: 12px; + border: 2px solid @veui-gray-color-5; + border-radius: 100%; + box-shadow: 0 2px 4px 0 fade(#000, 50%); + } +} + +.veui-color-slider { + margin: 5px 0; + padding: 3px 0; + + .veui-slider { + height: 18px; + + .veui-slider-thumb { + top: -2px; + } + + .veui-slider-custom-thumb { + width: 8px; + height: 22px; + border: 1px solid rgba(51, 51, 51, .8); + background: rgba(255, 255, 255, .9); + box-shadow: 1px 1px 4px rgba(0, 0, 0, .8); + border-radius: 2px; + } + + .veui-slider-custom-track { + width: 100%; + height: 18px; + } + } +} + +.veui-color-hue-slider { + .veui-slider-custom-track { + background: url("data:image/svg+xml;utf8;"); + background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00); + } +} + +.veui-color-alpha-slider { + .veui-slider-track { + .veui-transparency-grid-background(); + } +} + +.veui-color-picker { + width: 336px; + color: #333; + border: 1px solid @veui-gray-color-3; + box-shadow: 0 1px 5px 0 fade(#000, 20%); + border-radius: 2px; + + &-main { + padding: 20px; + + &-panel { + &-sliders { + margin-top: 15px; + } + } + + .veui-color-swatch { + margin-top: 15px; + } + } + + &[ui~="small"] { + width: 250px + 20px; + + .veui-color-picker-main { + padding: 10px; + + &-panel { + &-sliders { + margin-top: 10px; + } + } + + .veui-color-swatch { + margin-top: 10px; + } + } + } +} diff --git a/packages/veui-theme-one/components/color-swatch.less b/packages/veui-theme-one/components/color-swatch.less new file mode 100644 index 000000000..a28c74fcb --- /dev/null +++ b/packages/veui-theme-one/components/color-swatch.less @@ -0,0 +1,273 @@ +@import "../lib.less"; + +.veui-color-swatch { + @height: 40px; + + .clearfix(); + + &-box, + .veui-color-value-alpha-group { + float: left; + height: @height; + line-height: @height; + } + + &-box { + width: @height; + border: 1px solid fade(@veui-gray-color-3, 20%); + border-radius: 2px; + + div { + height: 100%; + } + + &-bg { + .veui-transparency-grid-background(); + } + } + + &[ui~="small"] { + @height: 30px; + @space-width: 10px; + @input-width: 45px; + + .veui-color-swatch-box, + .veui-color-value-alpha-group { + height: @height; + line-height: @height; + } + + .veui-color-swatch-box { + width: @height; + } + + .veui-color-value-hex { + .veui-color-value { + width: @input-width * 3 + 5 * 2; + } + } + + .veui-color-value-hsl, + .veui-color-value-rgb, + .veui-color-value-alpha { + .veui-color-value { + width: @input-width; + } + } + + .veui-color-value-alpha-group { + &-color, + &-alpha { + margin-left: @space-width; + } + + &-alpha { + margin-left: @space-width + 8px; + } + + &-separator { + &-wrap { + width: @space-width + 8px; + } + + &-dots { + div { + margin: 4px; + width: 4px; + height: 4px; + } + } + } + + &-tip { + &-hsl, + &-rgb, + &-hex { + float: left; + margin-left: @space-width; + } + + &-hsl, + &-rgb { + div { + width: @input-width; + } + } + + &-hex { + width: @input-width * 3 + 5 * 2; + } + + &-alpha { + float: right; + width: @input-width; + } + } + } + } +} + +.veui-color-value { + .veui-input { + width: 100%; + } +} + +.veui-color-value-hex { + .veui-input-input { + text-transform: uppercase; + letter-spacing: 1px; + } + + .veui-color-value { + width: 160px; + } +} + +.veui-color-value-hsl, +.veui-color-value-rgb, +.veui-color-value-alpha { + .clearfix(); + + .veui-input-input { + padding: 0; + text-align: center; + } + + .veui-color-value { + float: left; + width: 50px; + margin-left: 5px; + + &:first-child { + margin-left: 0; + } + } +} + +.veui-color-value-alpha-group { + @space-width: 18px; + + &-values { + .clearfix(); + + &, + div { + height: 100%; + } + } + + &-color, + &-alpha { + margin-left: @space-width; + float: left; + } + + &-alpha { + margin-left: @space-width + 8px; + } + + &-separator { + float: left; + height: 100%; + position: relative; + + &-wrap { + position: absolute; + top: 0; + left: 0; + width: @space-width + 8px; + + div { + height: auto; + } + } + + &-dots { + top: 50%; + left: 50%; + position: absolute; + transform: translate(-50%, -50%); + + div { + margin: 4px; + width: 4px; + height: 4px; + border-radius: 100%; + background-color: @veui-gray-color-3; + } + } + } + + &-format-hex { + .veui-color-value-alpha-group-separator-dot { + &:nth-child(1) { + background-color: @veui-gray-color-2; + } + } + } + + &-format-rgb { + .veui-color-value-alpha-group-separator-dot { + &:nth-child(2) { + background-color: @veui-gray-color-2; + } + } + } + + &-format-hsl { + .veui-color-value-alpha-group-separator-dot { + &:nth-child(3) { + background-color: @veui-gray-color-2; + } + } + } + + &-show-tip { + position: relative; + padding-bottom: 16px; + box-sizing: content-box; + } + + &-tip { + .clearfix(); + color: @veui-gray-color-2; + font-size: @veui-font-size-small; + text-align: center; + line-height: 1; + + position: absolute; + bottom: 0; + left: 0; + right: 0; + + &-hsl, + &-rgb, + &-hex { + float: left; + margin-left: 15px; + } + + &-hsl, + &-rgb { + div { + float: left; + width: 50px; + margin-left: 5px; + + &:first-child { + margin-left: 0; + } + } + } + + &-hex { + width: 160px; + } + + &-alpha { + float: right; + width: 50px; + } + } +} diff --git a/packages/veui-theme-one/mixins.less b/packages/veui-theme-one/mixins.less index 2d46f06cb..004a9ffb3 100644 --- a/packages/veui-theme-one/mixins.less +++ b/packages/veui-theme-one/mixins.less @@ -67,3 +67,7 @@ outline-offset: @offset; box-shadow: none; } + +.veui-transparency-grid-background() { + background: #fff url("data:image/svg+xml;utf8,"); +} diff --git a/packages/veui-theme-one/package-lock.json b/packages/veui-theme-one/package-lock.json index ae357e14c..a9e75fadf 100644 --- a/packages/veui-theme-one/package-lock.json +++ b/packages/veui-theme-one/package-lock.json @@ -733,6 +733,21 @@ "globals": "^9.18.0", "invariant": "^2.2.2", "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "http://registry.npm.baidu-int.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "http://registry.npm.baidu-int.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } } }, "babel-types": { @@ -1039,11 +1054,11 @@ } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.1.1", + "resolved": "http://registry.npm.baidu-int.com/debug/-/debug-4.1.1.tgz", + "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "decamelize": { @@ -1966,9 +1981,9 @@ } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.1", + "resolved": "http://registry.npm.baidu-int.com/ms/-/ms-2.1.1.tgz", + "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" }, "normalize-package-data": { "version": "2.5.0", diff --git a/packages/veui-theme-one/package.json b/packages/veui-theme-one/package.json index 50a1549bc..3ce37191b 100644 --- a/packages/veui-theme-one/package.json +++ b/packages/veui-theme-one/package.json @@ -28,6 +28,7 @@ "babel-plugin-transform-runtime": "^6.22.0", "babel-preset-env": "^1.2.1", "babel-preset-stage-2": "^6.22.0", + "debug": "^4.1.1", "esm": "^3.0.84", "mkdirp": "^0.5.1", "rimraf": "^2.6.2", diff --git a/packages/veui/components.json b/packages/veui/components.json index bd5f055d0..430084bd0 100644 --- a/packages/veui/components.json +++ b/packages/veui/components.json @@ -43,6 +43,22 @@ "name": "CheckboxGroup", "path": "CheckboxGroup.vue" }, + { + "name": "ColorPalette", + "path": "ColorPicker/ColorPalette.vue" + }, + { + "name": "ColorPicker", + "path": "ColorPicker/ColorPicker.vue" + }, + { + "name": "ColorSwatch", + "path": "ColorPicker/ColorSwatch.vue" + }, + { + "name": "ColorPicker", + "path": "ColorPicker.js" + }, { "name": "Column", "path": "Column.js" diff --git a/packages/veui/config/index.js b/packages/veui/config/index.js index eabd3910f..1ca9a0cd5 100644 --- a/packages/veui/config/index.js +++ b/packages/veui/config/index.js @@ -24,7 +24,7 @@ module.exports = { dev: { env: require('./dev.env'), port: 8080, - autoOpenBrowser: true, + autoOpenBrowser: false, assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: {}, diff --git a/packages/veui/demo/cases/ColorPicker.vue b/packages/veui/demo/cases/ColorPicker.vue new file mode 100644 index 000000000..38837a23c --- /dev/null +++ b/packages/veui/demo/cases/ColorPicker.vue @@ -0,0 +1,260 @@ + + + + + diff --git a/packages/veui/demo/cases/index.js b/packages/veui/demo/cases/index.js index 7b3a2e881..9c7c1da4b 100644 --- a/packages/veui/demo/cases/index.js +++ b/packages/veui/demo/cases/index.js @@ -8,6 +8,7 @@ import Breadcrumb from './Breadcrumb' import Input from './Input' import Form from './Form' import Calendar from './Calendar' +import ColorPicker from './ColorPicker' import DatePicker from './DatePicker' import Select from './Select' import Dropdown from './Dropdown' @@ -83,6 +84,11 @@ export default [ name: 'CheckboxGroup', component: CheckboxGroup }, + { + path: '/color-picker', + name: 'ColorPicker', + component: ColorPicker + }, { path: '/date-picker', name: 'DatePicker', @@ -247,4 +253,6 @@ export default [ name: 'Uploader', component: Uploader } -] +].sort(function (a, b) { + return a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1 +}) diff --git a/packages/veui/package-lock.json b/packages/veui/package-lock.json index de42a431a..30765432b 100644 --- a/packages/veui/package-lock.json +++ b/packages/veui/package-lock.json @@ -9735,6 +9735,11 @@ "setimmediate": "^1.0.4" } }, + "tinycolor2": { + "version": "1.4.1", + "resolved": "http://registry.npm.baidu-int.com/tinycolor2/-/tinycolor2-1.4.1.tgz", + "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", diff --git a/packages/veui/package.json b/packages/veui/package.json index 9616d4b04..dbd955094 100644 --- a/packages/veui/package.json +++ b/packages/veui/package.json @@ -22,6 +22,7 @@ "lodash": "^4.17.4", "resize-detector": "^0.1.6", "tether": "^1.4.5", + "tinycolor2": "^1.4.1", "vue-awesome": "^3.3.1" }, "peerDependencies": { diff --git a/packages/veui/src/components/ColorPicker.js b/packages/veui/src/components/ColorPicker.js new file mode 100755 index 000000000..75c55f62e --- /dev/null +++ b/packages/veui/src/components/ColorPicker.js @@ -0,0 +1,3 @@ +import ColorPicker from './ColorPicker/ColorPicker' +export default ColorPicker + diff --git a/packages/veui/src/components/ColorPicker/ColorPalette.vue b/packages/veui/src/components/ColorPicker/ColorPalette.vue new file mode 100755 index 000000000..914116cd8 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/ColorPalette.vue @@ -0,0 +1,166 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/ColorPicker.vue b/packages/veui/src/components/ColorPicker/ColorPicker.vue new file mode 100755 index 000000000..164f283fe --- /dev/null +++ b/packages/veui/src/components/ColorPicker/ColorPicker.vue @@ -0,0 +1,57 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/ColorSwatch.vue b/packages/veui/src/components/ColorPicker/ColorSwatch.vue new file mode 100755 index 000000000..7184726f5 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/ColorSwatch.vue @@ -0,0 +1,44 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorAlphaSlider.vue b/packages/veui/src/components/ColorPicker/_ColorAlphaSlider.vue new file mode 100755 index 000000000..f148ecbdb --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorAlphaSlider.vue @@ -0,0 +1,53 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorHueSlider.vue b/packages/veui/src/components/ColorPicker/_ColorHueSlider.vue new file mode 100755 index 000000000..584e91a2e --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorHueSlider.vue @@ -0,0 +1,59 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorShadeField.vue b/packages/veui/src/components/ColorPicker/_ColorShadeField.vue new file mode 100755 index 000000000..3a05e9c98 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorShadeField.vue @@ -0,0 +1,179 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorValueAlpha.vue b/packages/veui/src/components/ColorPicker/_ColorValueAlpha.vue new file mode 100755 index 000000000..57a984ce9 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorValueAlpha.vue @@ -0,0 +1,33 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorValueAlphaGroup.vue b/packages/veui/src/components/ColorPicker/_ColorValueAlphaGroup.vue new file mode 100755 index 000000000..9d60411c0 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorValueAlphaGroup.vue @@ -0,0 +1,125 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorValueHex.vue b/packages/veui/src/components/ColorPicker/_ColorValueHex.vue new file mode 100755 index 000000000..d9ccae10b --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorValueHex.vue @@ -0,0 +1,32 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorValueHsl.vue b/packages/veui/src/components/ColorPicker/_ColorValueHsl.vue new file mode 100755 index 000000000..4ce0d4b97 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorValueHsl.vue @@ -0,0 +1,54 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/_ColorValueInput.vue b/packages/veui/src/components/ColorPicker/_ColorValueInput.vue new file mode 100644 index 000000000..262eb3fd1 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorValueInput.vue @@ -0,0 +1,117 @@ + + diff --git a/packages/veui/src/components/ColorPicker/_ColorValueRgb.vue b/packages/veui/src/components/ColorPicker/_ColorValueRgb.vue new file mode 100755 index 000000000..73dbbd333 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/_ColorValueRgb.vue @@ -0,0 +1,53 @@ + + + diff --git a/packages/veui/src/components/ColorPicker/mixins/_ColorHomer.js b/packages/veui/src/components/ColorPicker/mixins/_ColorHomer.js new file mode 100755 index 000000000..a2f8854c1 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/mixins/_ColorHomer.js @@ -0,0 +1,55 @@ +import {formatColor} from '../../../utils/color' +import tinycolor from 'tinycolor2' +import {merge} from 'lodash' + +export default { + uiTypes: ['color-homer'], + props: { + color: String, + ui: String, + variant: String, + alpha: Boolean, + switchable: Boolean + }, + model: { + prop: 'color', + event: 'update:color' + }, + data () { + return { + lockedHue: null + } + }, + computed: { + hsl () { + let hsl = tinycolor(this.color).toHsl() + return this.lockedHue ? {...hsl, h: this.lockedHue} : hsl + }, + hsv () { + let hsv = tinycolor(this.color).toHsv() + return this.lockedHue ? {...hsv, h: this.lockedHue} : hsv + }, + rgb () { + return tinycolor(this.color).toRgb() + } + }, + methods: { + updateColor (color) { + this.$emit('update:color', formatColor(color, { + format: this.variant + })) + }, + updateHsvValue (hsv) { + this.updateColor(merge(this.hsv, hsv)) + }, + updateHslValue (hsl) { + this.updateColor(merge(this.hsl, hsl)) + }, + updateRgbValue (rgb) { + this.updateColor(merge(this.rgb, rgb)) + }, + lockHue (hue) { + this.lockedHue = hue + } + } +} diff --git a/packages/veui/src/components/ColorPicker/mixins/_ColorSlider.js b/packages/veui/src/components/ColorPicker/mixins/_ColorSlider.js new file mode 100755 index 000000000..95fdf36f7 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/mixins/_ColorSlider.js @@ -0,0 +1,14 @@ +import ColorUpdater from './_ColorUpdater' +import Slider from '../../Slider' + +export default { + components: { + 'veui-slider': Slider + }, + mixins: [ + ColorUpdater + ], + props: { + hsl: Object + } +} diff --git a/packages/veui/src/components/ColorPicker/mixins/_ColorUpdater.js b/packages/veui/src/components/ColorPicker/mixins/_ColorUpdater.js new file mode 100755 index 000000000..01346e446 --- /dev/null +++ b/packages/veui/src/components/ColorPicker/mixins/_ColorUpdater.js @@ -0,0 +1,26 @@ +import {getTypedAncestorTracker} from '../../../utils/helper' + +export default { + mixins: [ + getTypedAncestorTracker('color-homer') + ], + methods: { + updateColor ({h, s, v, l, a, r, g, b}) { + switch (true) { + case v !== undefined: + this.colorHomer.updateHsvValue({h, s, v, a}) + break + + case r !== undefined: + case g !== undefined: + case b !== undefined: + this.colorHomer.updateRgbValue({r, g, b, a}) + break + + default: + this.colorHomer.updateHslValue({h, s, l, a}) + break + } + } + } +} diff --git a/packages/veui/src/components/ColorPicker/mixins/_ColorValueInput.js b/packages/veui/src/components/ColorPicker/mixins/_ColorValueInput.js new file mode 100644 index 000000000..a37d216ed --- /dev/null +++ b/packages/veui/src/components/ColorPicker/mixins/_ColorValueInput.js @@ -0,0 +1,52 @@ +import ColorUpdater from './_ColorUpdater' +import ColorValueInput from '../_ColorValueInput' +import {clamp} from 'lodash' + +export default { + components: { + 'veui-color-value-input': ColorValueInput + }, + mixins: [ColorUpdater], + props: { + hsl: Object, + rgb: Object, + readonly: Boolean + }, + methods: { + parseHexValue (val) { + if (!/^#[0-9A-F]{6}$/i.test(val)) { + throw new Error('Illegal hex color value') + } + return val + }, + + formatHue (val) { + return Math.round(val) + }, + parseHue (val) { + let realValue = parseFloat(val) + if (isNaN(realValue)) { + throw new Error('Illegal hue value') + } + return realValue % 360 + }, + + formatPercentage (val) { + return Math.round(val * 100) + '%' + }, + parsePercentage (val) { + if (!/^\d+(\.\d+)?%$/.test(val)) { + throw new Error('Illegal percentage value') + } + return clamp(parseFloat(val) / 100, 0, 1) + }, + + parseFFValue (val) { + let realValue = parseInt(val, 10) + if (isNaN(realValue) || realValue < 0 || realValue > 255) { + throw new Error('Illegal value') + } + return realValue + } + } +} diff --git a/packages/veui/src/index.js b/packages/veui/src/index.js index 4c56afd69..0943220df 100644 --- a/packages/veui/src/index.js +++ b/packages/veui/src/index.js @@ -53,3 +53,6 @@ export { default as Tooltip } from './components/Tooltip' export { default as Transfer } from './components/Transfer' export { default as Tree } from './components/Tree' export { default as Uploader } from './components/Uploader' +export { default as ColorPicker } from './components/ColorPicker' +export { default as ColorSwatch } from './components/ColorPicker/ColorSwatch' +export { default as ColorPalette } from './components/ColorPicker/ColorPalette' diff --git a/packages/veui/src/utils/color.js b/packages/veui/src/utils/color.js new file mode 100644 index 000000000..c17f19b8d --- /dev/null +++ b/packages/veui/src/utils/color.js @@ -0,0 +1,40 @@ +import tinycolor from 'tinycolor2' + +export function formatColor (color, { + precision = 4, + format = 'hsl' +} = {}) { + let tcolor = tinycolor(color) + switch (format) { + case 'rgb': + return tcolor.toRgbString() + + case 'hex': + return color.a !== 1 ? tcolor.toHex8String() : tcolor.toHexString() + + case 'hsl': + default: + // 因为 tinycolor 的 toHslString() 得到的颜色没有小数 + // 精度丢失会导致数字修改时突变,所以自己实现一个format保留4位小数 + return formatHsla(tcolor.toHsl(), {precision}) + } +} + +/** + * 格式化 hsla + * + * @param {Number} color.h Hue + * @param {Number} color.s Saturation + * @param {Number} color.l Lightness + * @param {Number} color.a Alpha + * @param {Number} options.precision precision + * @return {String} + */ +export function formatHsla ({h, s, l, a}, {precision = 4} = {}) { + precision = Math.pow(10, precision) + h = Math.round(h % 360 * precision) / precision + s = Math.round(s * 100 * precision) / precision + l = Math.round(l * 100 * precision) / precision + a = Math.round(a * precision) / precision + return a === 1 ? `hsl(${h}, ${s}%, ${l}%)` : `hsla(${h}, ${s}%, ${l}%, ${a})` +}