Color keyboard control

This commit is contained in:
Graham Fairweather 2018-05-15 14:26:58 +02:00
parent b924d14da3
commit f2bcd4adaf
13 changed files with 1314 additions and 653 deletions

View file

@ -1,46 +1,157 @@
<template> <template>
<div style="margin: 100px;"> <div style="margin: 100px;">
{{ color }} {{color}}
<!--<Input placeholder="请输入..." size="large" style="width: 50px;"></Input>--> <!--<Input placeholder="请输入..." size="large" style="width: 50px;"></Input>-->
<color-picker @on-change="c1" @on-active-change="c2" v-model="color" placement="bottom-start" size="large"></color-picker> <color-picker
<Date-picker transfer type="date" placeholder="选择日期" style="width: 200px"></Date-picker> v-model="color"
<color-picker :transfer="true" ref="xxx" v-model="color" format="rgb" alpha :recommend="true"></color-picker> placement="bottom-start"
<color-picker v-model="color2" format="hsv" :alpha="true" :recommend="false"></color-picker> size="large"
@on-change="c1"
@on-active-change="c2"></color-picker>
<Date-picker
transfer
type="date"
placeholder="选择日期"
style="width: 200px"></Date-picker>
<color-picker
ref="xxx"
:transfer="true"
v-model="color"
:recommend="true"
format="rgb"
alpha
@on-change="onChange"
@on-active-change="onActiveChange"></color-picker>
<color-picker
v-model="color2"
:alpha="true"
:recommend="false"
format="hsv"></color-picker>
<!--<Date-picker type="date" placeholder="选择日期" style="width: 200px"></Date-picker>--> <!--<Date-picker type="date" placeholder="选择日期" style="width: 200px"></Date-picker>-->
<color-picker v-model="color" placement="bottom-start" size="small"></color-picker> <color-picker
<Date-picker type="date" placeholder="选择日期" size="small" style="width: 200px"></Date-picker> v-model="color"
placement="bottom-start"
size="small"></color-picker>
<Date-picker
type="date"
placeholder="选择日期"
size="small"
style="width: 200px"></Date-picker>
<color-picker
ref="yyy"
:colors="colors"
v-model="color"
transfer
format="rgb"
alpha></color-picker>
<Button @click="setColor">set color</Button> <Button @click="setColor">set color</Button>
<br><br><br><br> <br><br><br><br>
{{openState}} {{openState}}
<ColorPicker v-model="color7" :hue="false" @on-open-change="onOpenChange"></ColorPicker> <ColorPicker
v-model="color7"
:hue="false"
@on-open-change="onOpenChange"></ColorPicker>
<ColorPicker
v-model="color7"
:hue="false"
:hide-drop-down="hideDropDown"
transfer
@on-open-change="onOpenChange"></ColorPicker>
<br><br><br><br>
<ColorPicker
v-model="color7"
disabled></ColorPicker>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: {}, props: {},
data () {
return { data() {
color: 'rgba(12,34,255,.85)', return {
color2: '', color: 'rgba(12,34,255,.85)',
color7: '#19be6b', color2: '',
openState: false, color7: '#19be6b',
}; openState: false,
colors: [
'#2d8cf0',
'#19be6b',
'#ff9900',
'#ed3f14',
'#00b5ff',
'#19c919',
'#f9e31c',
'#ea1a1a',
'#9b1dea',
'#00c2b1',
'#ac7a33',
'#1d35ea',
'#8bc34a',
'#f16b62',
'#ea4ca3',
'#0d94aa',
'#febd79',
'#5d4037',
'#00bcd4',
'#f06292',
'#cddc39',
'#607d8b',
'#000000',
'#ffffff',
'#2d8cf0',
'#19be6b',
'#ff9900',
'#ed3f14',
'#00b5ff',
'#19c919',
'#f9e31c',
'#ea1a1a',
'#9b1dea',
'#00c2b1',
'#ac7a33',
'#1d35ea',
'#8bc34a',
'#f16b62',
'#ea4ca3',
'#0d94aa',
'#febd79',
'#5d4037',
],
hideDropDown: false,
};
},
computed: {},
mounted() {
setInterval(this.toggleShowHide, 2000);
},
methods: {
setColor() {
this.color = '#26bc77';
}, },
computed: {}, c1(d) {
methods: { console.log(d);
setColor () { },
this.color = '#26bc77'; c2(d) {
}, console.log(d);
c1 (d) { },
console.log(d); onOpenChange(state) {
}, this.openState = state;
c2 (d) { },
console.log(d); onChange(d) {
}, console.log(d);
onOpenChange(state){ },
this.openState = state; onActiveChange(d) {
} console.log(d);
} },
}; toggleShowHide() {
this.hideDropDown = !this.hideDropDown;
},
},
};
</script> </script>

View file

@ -1,77 +1,103 @@
<template> <template>
<div class="ivu-color-picker-alpha"> <div
<div class="ivu-color-picker-alpha-checkboard-wrap"> :class="[prefixCls + '-alpha']"
<div class="ivu-color-picker-alpha-checkerboard"></div> tabindex="0"
@click="$el.focus()"
@keydown.esc="handleEscape"
@keydown.left="handleLeft"
@keydown.right="handleRight"
@keydown.up="handleUp"
@keydown.down="handleDown"
>
<div :class="[prefixCls + '-alpha-checkboard-wrap']">
<div :class="[prefixCls + '-alpha-checkerboard']"></div>
</div> </div>
<div class="ivu-color-picker-alpha-gradient" :style="{background: gradientColor}"></div> <div
<div class="ivu-color-picker-alpha-container" ref="container" :style="gradientStyle"
@mousedown="handleMouseDown" :class="[prefixCls + '-alpha-gradient']"></div>
@touchmove="handleChange" <div
@touchstart="handleChange"> ref="container"
<div class="ivu-color-picker-alpha-pointer" :style="{left: colors.a * 100 + '%'}"> :class="[prefixCls + '-alpha-container']"
<div class="ivu-color-picker-alpha-picker"></div> @mousedown="handleMouseDown"
@touchmove="handleChange"
@touchstart="handleChange">
<div
:style="{top: 0, left: `${value.a * 100}%`}"
:class="[prefixCls + '-alpha-pointer']">
<div :class="[prefixCls + '-alpha-picker']"></div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { import HSAMixin from './hsaMixin';
name: 'Alpha', import Prefixes from './prefixMixin';
props: { import {clamp, toRGBAString} from './utils';
value: Object,
onChange: Function export default {
name: 'Alpha',
mixins: [HSAMixin, Prefixes],
data() {
const normalStep = 1;
const jumpStep = 10;
return {
left: -normalStep,
right: normalStep,
up: jumpStep,
down: -jumpStep,
powerKey: 'shiftKey',
};
},
computed: {
gradientStyle() {
const {r, g, b} = this.value.rgba;
const start = toRGBAString({r, g, b, a: 0});
const finish = toRGBAString({r, g, b, a: 1});
return {background: `linear-gradient(to right, ${start} 0%, ${finish} 100%)`};
}, },
computed: { },
colors () {
return this.value; methods: {
}, change(newAlpha) {
gradientColor () { const {h, s, l} = this.value.hsl;
const rgba = this.colors.rgba; const {a} = this.value;
const rgbStr = [rgba.r, rgba.g, rgba.b].join(',');
return 'linear-gradient(to right, rgba(' + rgbStr + ', 0) 0%, rgba(' + rgbStr + ', 1) 100%)'; if (a !== newAlpha) {
this.$emit('change', {h, s, l, a: newAlpha, source: 'rgba'});
} }
}, },
methods: { handleSlide(e, direction) {
handleChange (e, skip) { e.preventDefault();
!skip && e.preventDefault(); e.stopPropagation();
const container = this.$refs.container;
const containerWidth = container.clientWidth;
const xOffset = container.getBoundingClientRect().left + window.pageXOffset; this.change(clamp(e[this.powerKey] ? direction : Math.round(this.value.hsl.a * 100 + direction) / 100, 0, 1));
const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0); },
const left = pageX - xOffset; handleChange(e) {
e.preventDefault();
e.stopPropagation();
let a; const left = this.getLeft(e);
if (left < 0) {
a = 0;
} else if (left > containerWidth) {
a = 1;
} else {
a = Math.round(left * 100 / containerWidth) / 100;
}
if (this.colors.a !== a) { if (left < 0) {
this.$emit('change', { this.change(0);
h: this.colors.hsl.h, return;
s: this.colors.hsl.s,
l: this.colors.hsl.l,
a: a,
source: 'rgba'
});
}
},
handleMouseDown (e) {
this.handleChange(e, true);
window.addEventListener('mousemove', this.handleChange);
window.addEventListener('mouseup', this.handleMouseUp);
},
handleMouseUp () {
this.unbindEventListeners();
},
unbindEventListeners () {
window.removeEventListener('mousemove', this.handleChange);
window.removeEventListener('mouseup', this.handleMouseUp);
} }
}
}; const {clientWidth} = this.$refs.container;
</script>
if (left > clientWidth) {
this.change(1);
return;
}
this.change(Math.round(left * 100 / clientWidth) / 100);
},
},
};
</script>

View file

@ -1,375 +1,453 @@
<template> <template>
<div :class="classes" v-clickoutside="handleClose"> <div
<div ref="reference" @click="toggleVisible" :class="wrapClasses"> v-click-outside.capture="handleClose"
<input type="hidden" :name="name" :value="currentValue"> v-click-outside:mousedown.capture="handleClose"
<i class="ivu-icon ivu-icon-arrow-down-b ivu-input-icon ivu-input-icon-normal"></i> :class="classes">
<div :class="inputClasses"> <div
ref="reference"
:class="wrapClasses"
@click="toggleVisible">
<input
:name="name"
:value="currentValue"
type="hidden">
<i :class="arrowClasses"></i>
<div
ref="input"
:tabindex="disabled ? undefined : 0"
:class="inputClasses"
@keydown.tab="onTab"
@keydown.esc="onEscape"
@keydown.up="onArrow"
@keydown.down="onArrow"
>
<div :class="[prefixCls + '-color']"> <div :class="[prefixCls + '-color']">
<div :class="[prefixCls + '-color-empty']" v-show="value === '' && !visible"> <div
<i class="ivu-icon ivu-icon-ios-close-empty"></i> v-show="value === '' && !visible"
:class="[prefixCls + '-color-empty']">
<i :class="[iconPrefixCls, iconPrefixCls + '-ios-close-empty']"></i>
</div> </div>
<div v-show="value || visible" :style="{backgroundColor: displayedColor}"></div> <div
v-show="value || visible"
:style="displayedColorStyle"></div>
</div> </div>
</div> </div>
</div> </div>
<transition name="transition-drop"> <transition name="transition-drop">
<Drop <Drop
v-transfer-dom
v-show="visible" v-show="visible"
@click.native="handleTransferClick"
:class="{ [prefixCls + '-transfer']: transfer }"
class-name="ivu-transfer-no-max-height"
:placement="placement"
ref="drop" ref="drop"
:placement="placement"
:data-transfer="transfer" :data-transfer="transfer"
v-transfer-dom> :class="dropClasses"
<div :class="[prefixCls + '-picker']"> >
<div :class="[prefixCls + '-picker-wrapper']"> <transition name="fade">
<div :class="[prefixCls + '-picker-panel']"> <div
<Saturation v-model="saturationColors" @change="childChange"></Saturation> v-if="visible"
:class="[prefixCls + '-picker']">
<div :class="[prefixCls + '-picker-wrapper']">
<div :class="[prefixCls + '-picker-panel']">
<Saturation
ref="saturation"
v-model="saturationColors"
:focused="visible"
@change="childChange"
@keydown.native.tab="handleFirstTab"
></Saturation>
</div>
<div
v-if="hue"
:class="[prefixCls + '-picker-hue-slider']">
<Hue
v-model="saturationColors"
@change="childChange"></Hue>
</div>
<div
v-if="alpha"
:class="[prefixCls + '-picker-alpha-slider']">
<Alpha
v-model="saturationColors"
@change="childChange"></Alpha>
</div>
<recommend-colors
v-if="colors.length"
:list="colors"
:class="[prefixCls + '-picker-colors']"
@picker-color="handleSelectColor"></recommend-colors>
<recommend-colors
v-if="!colors.length && recommend"
:list="recommendedColor"
:class="[prefixCls + '-picker-colors']"
@picker-color="handleSelectColor"></recommend-colors>
</div> </div>
<div v-if="hue" :class="[prefixCls + '-picker-hue-slider']"> <div :class="[prefixCls + '-confirm']">
<Hue v-model="saturationColors" @change="childChange"></Hue> <span :class="[prefixCls + '-confirm-color']">{{formatColor}}</span>
<i-button
ref="clear"
:tabindex="0"
size="small"
type="ghost"
@click.native="handleClear"
@keydown.enter="handleClear"
@keydown.native.esc="closer"
>{{t('i.datepicker.clear')}}</i-button>
<i-button
ref="ok"
:tabindex="0"
size="small"
type="primary"
@click.native="handleSuccess"
@keydown.native.tab="handleLastTab"
@keydown.enter="handleSuccess"
@keydown.native.esc="closer"
>{{t('i.datepicker.ok')}}</i-button>
</div> </div>
<div v-if="alpha" :class="[prefixCls + '-picker-alpha-slider']">
<Alpha v-model="saturationColors" @change="childChange"></Alpha>
</div>
<recommend-colors
v-if="colors.length"
:list="colors"
:class="[prefixCls + '-picker-colors']"
@picker-color="handleSelectColor"></recommend-colors>
<recommend-colors
v-if="!colors.length && recommend"
:list="recommendedColor"
:class="[prefixCls + '-picker-colors']"
@picker-color="handleSelectColor"></recommend-colors>
</div> </div>
<div :class="[prefixCls + '-confirm']"> </transition>
<span :class="[prefixCls + '-confirm-color']">{{ formatColor }}</span>
<Confirm @on-pick-success="handleSuccess" @on-pick-clear="handleClear"></Confirm>
</div>
</div>
</Drop> </Drop>
</transition> </transition>
</div> </div>
</template> </template>
<script> <script>
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import vClickOutside from 'v-click-outside-x/index';
import TransferDom from '../../directives/transfer-dom';
import Drop from '../../components/select/dropdown.vue';
import RecommendColors from './recommend-colors.vue';
import Saturation from './saturation.vue';
import Hue from './hue.vue';
import Alpha from './alpha.vue';
import Locale from '../../mixins/locale';
import {oneOf} from '../../utils/assist';
import Emitter from '../../mixins/emitter';
import Prefixes from './prefixMixin';
import {changeColor, toRGBAString} from './utils';
import clickoutside from '../../directives/clickoutside'; export default {
import TransferDom from '../../directives/transfer-dom'; name: 'ColorPicker',
import Drop from '../../components/select/dropdown.vue'; components: {Drop, RecommendColors, Saturation, Hue, Alpha},
import RecommendColors from './recommend-colors.vue';
import Confirm from '../date-picker/base/confirm.vue';
import Saturation from './saturation.vue';
import Hue from './hue.vue';
import Alpha from './alpha.vue';
import { oneOf } from '../../utils/assist'; directives: {clickOutside: vClickOutside.directive, TransferDom},
import Emitter from '../../mixins/emitter';
const prefixCls = 'ivu-color-picker'; mixins: [Emitter, Locale, Prefixes],
const inputPrefixCls = 'ivu-input';
function _colorChange (data, oldHue) { props: {
data = data === '' ? '#2d8cf0' : data; value: {
const alpha = data && data.a; type: String,
let color; default: undefined,
},
// hsl is better than hex between conversions hue: {
if (data && data.hsl) { type: Boolean,
color = tinycolor(data.hsl); default: true,
} else if (data && data.hex && data.hex.length > 0) { },
color = tinycolor(data.hex); alpha: {
} else { type: Boolean,
color = tinycolor(data); default: false,
} },
recommend: {
if (color && (color._a === undefined || color._a === null)) { type: Boolean,
color.setAlpha(alpha || 1); default: false,
} },
format: {
const hsl = color.toHsl(); type: String,
const hsv = color.toHsv(); validator(value) {
return oneOf(value, ['hsl', 'hsv', 'hex', 'rgb']);
if (hsl.s === 0) { },
hsv.h = hsl.h = data.h || (data.hsl && data.hsl.h) || oldHue || 0; default: undefined,
} },
colors: {
// when the hsv.v is less than 0.0164 (base on test) type: Array,
// because of possible loss of precision default() {
// the result of hue and saturation would be miscalculated return [];
if (hsv.v < 0.0164) { },
hsv.h = data.h || (data.hsv && data.hsv.h) || 0; },
hsv.s = data.s || (data.hsv && data.hsv.s) || 0; disabled: {
} type: Boolean,
default: false,
if (hsl.l < 0.01) { },
hsl.h = data.h || (data.hsl && data.hsl.h) || 0; size: {
hsl.s = data.s || (data.hsl && data.hsl.s) || 0; type: String,
} validator(value) {
return oneOf(value, ['small', 'large', 'default']);
},
default: 'default',
},
hideDropDown: {
type: Boolean,
default: false,
},
placement: {
type: String,
validator(value) {
return oneOf(value, [
'top',
'top-start',
'top-end',
'bottom',
'bottom-start',
'bottom-end',
'left',
'left-start',
'left-end',
'right',
'right-start',
'right-end',
]);
},
default: 'bottom',
},
transfer: {
type: Boolean,
default: false,
},
name: {
type: String,
default: undefined,
},
},
data() {
return { return {
hsl: hsl, val: changeColor(this.value),
hex: color.toHexString().toUpperCase(), currentValue: this.value,
rgba: color.toRgb(), dragging: false,
hsv: hsv, visible: false,
oldHue: data.h || oldHue || hsl.h, recommendedColor: [
source: data.source, '#2d8cf0',
a: data.a || color.getAlpha() '#19be6b',
'#ff9900',
'#ed3f14',
'#00b5ff',
'#19c919',
'#f9e31c',
'#ea1a1a',
'#9b1dea',
'#00c2b1',
'#ac7a33',
'#1d35ea',
'#8bc34a',
'#f16b62',
'#ea4ca3',
'#0d94aa',
'#febd79',
'#5d4037',
'#00bcd4',
'#f06292',
'#cddc39',
'#607d8b',
'#000000',
'#ffffff',
],
}; };
} },
export default { computed: {
name: 'ColorPicker', arrowClasses() {
mixins: [ Emitter ], return [
components: { Drop, Confirm, RecommendColors, Saturation, Hue, Alpha }, this.iconPrefixCls,
directives: { clickoutside, TransferDom }, `${this.iconPrefixCls}-arrow-down-b`,
props: { `${this.inputPrefixCls}-icon`,
value: { `${this.inputPrefixCls}-icon-normal`,
type: String ];
},
transition() {
return oneOf(this.placement, ['bottom-start', 'bottom', 'bottom-end']) ? 'slide-up' : 'fade';
},
saturationColors: {
get() {
return this.val;
}, },
hue: { set(newVal) {
type: Boolean, this.val = newVal;
default: true this.$emit('on-active-change', this.formatColor);
}, },
alpha: { },
type: Boolean, classes() {
default: false return [
}, `${this.prefixCls}`,
recommend: { {
type: Boolean, [`${this.prefixCls}-transfer`]: this.transfer,
default: false
},
format: {
validator (value) {
return oneOf(value, ['hsl', 'hsv', 'hex', 'rgb']);
}
},
colors: {
type: Array,
default () {
return [];
}
},
disabled: {
type: Boolean,
default: false
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
}, },
default: 'default' ];
}, },
placement: { wrapClasses() {
validator (value) { return [
return oneOf(value, ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end']); `${this.prefixCls}-rel`,
`${this.prefixCls}-${this.size}`,
`${this.inputPrefixCls}-wrapper`,
`${this.inputPrefixCls}-wrapper-${this.size}`,
{
[`${this.prefixCls}-disabled`]: this.disabled,
}, },
default: 'bottom' ];
},
transfer: {
type: Boolean,
default: false
},
name: {
type: String
}
}, },
data () { inputClasses() {
return { return [
val: _colorChange(this.value), `${this.prefixCls}-input`,
currentValue: this.value, `${this.inputPrefixCls}`,
prefixCls: prefixCls, `${this.inputPrefixCls}-${this.size}`,
visible: false, {
disableCloseUnderTransfer: false, // transfer Drop [`${this.prefixCls}-focused`]: this.visible,
recommendedColor: [ [`${this.prefixCls}-disabled`]: this.disabled,
'#2d8cf0',
'#19be6b',
'#ff9900',
'#ed3f14',
'#00b5ff',
'#19c919',
'#f9e31c',
'#ea1a1a',
'#9b1dea',
'#00c2b1',
'#ac7a33',
'#1d35ea',
'#8bc34a',
'#f16b62',
'#ea4ca3',
'#0d94aa',
'#febd79',
'#5d4037',
'#00bcd4',
'#f06292',
'#cddc39',
'#607d8b',
'#000000',
'#ffffff'
]
};
},
computed: {
transition () {
if (this.placement === 'bottom-start' || this.placement === 'bottom' || this.placement === 'bottom-end') {
return 'slide-up';
} else {
return 'fade';
}
},
saturationColors: {
get () {
return this.val;
}, },
set (newVal) { ];
this.val = newVal; },
this.$emit('on-active-change', this.formatColor); dropClasses() {
} return [
}, `${this.transferPrefixCls}-no-max-height`,
classes () { {
return [ [`${this.prefixCls}-transfer`]: this.transfer,
`${prefixCls}`, [`${this.prefixCls}-hide-drop`]: this.hideDropDown,
{ },
[`${prefixCls}-transfer`]: this.transfer ];
} },
]; displayedColorStyle() {
}, return {backgroundColor: toRGBAString(this.visible ? this.saturationColors.rgba : tinycolor(this.value).toRgb())};
wrapClasses () { },
return [ formatColor() {
`${prefixCls}-rel`, const {format, saturationColors} = this;
`${prefixCls}-${this.size}`,
`${inputPrefixCls}-wrapper`,
`${inputPrefixCls}-wrapper-${this.size}`
];
},
inputClasses () {
return [
`${prefixCls}-input`,
`${inputPrefixCls}`,
`${inputPrefixCls}-${this.size}`,
{
[`${inputPrefixCls}-disabled`]: this.disabled
}
];
},
displayedColor () {
let color;
if (this.visible) {
const rgba = this.saturationColors.rgba;
color = {
r: rgba.r,
g: rgba.g,
b: rgba.b,
a: rgba.a
};
} else {
color = tinycolor(this.value).toRgb();
}
return `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`;
},
formatColor () {
const value = this.saturationColors;
const format = this.format;
let color;
const rgba = `rgba(${value.rgba.r}, ${value.rgba.g}, ${value.rgba.b}, ${value.rgba.a})`; if (format) {
if (format) { if (format === 'hsl') {
if (format === 'hsl') { return tinycolor(saturationColors.hsl).toHslString();
color = tinycolor(value.hsl).toHslString();
} else if (format === 'hsv') {
color = tinycolor(value.hsv).toHsvString();
} else if (format === 'hex') {
color = value.hex;
} else if (format === 'rgb') {
color = rgba;
}
} else if (this.alpha) {
color = rgba;
} else {
color = value.hex;
} }
return color;
if (format === 'hsv') {
return tinycolor(saturationColors.hsv).toHsvString();
}
if (format === 'hex') {
return saturationColors.hex;
}
if (format === 'rgb') {
return toRGBAString(saturationColors.rgba);
}
} else if (this.alpha) {
return toRGBAString(saturationColors.rgba);
}
return saturationColors.hex;
},
},
watch: {
value(newVal) {
this.val = changeColor(newVal);
},
visible(val) {
this.val = changeColor(this.value);
this.$refs.drop[val ? 'update' : 'destroy']();
this.$emit('on-open-change', Boolean(val));
},
},
mounted() {
this.$on('on-escape-keydown', this.closer);
this.$on('on-dragging', this.setDragging);
},
methods: {
setDragging(value) {
this.dragging = value;
},
handleClose(event) {
if (this.visible) {
if (this.dragging || event.type === 'mousedown') {
event.preventDefault();
return;
}
if (this.transfer) {
const {$el} = this.$refs.drop;
if ($el === event.target || $el.contains(event.target)) {
return;
}
}
this.closer(event);
return;
}
this.visible = false;
},
toggleVisible() {
if (this.disabled) {
return;
}
this.visible = !this.visible;
this.$refs.input.focus();
},
childChange(data) {
this.colorChange(data);
},
colorChange(data, oldHue) {
this.oldHue = this.saturationColors.hsl.h;
this.saturationColors = changeColor(data, oldHue || this.oldHue);
},
closer(event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
this.visible = false;
this.$refs.input.focus();
},
handleButtons(event, value) {
this.currentValue = value;
this.$emit('input', value);
this.$emit('on-change', value);
this.dispatch('FormItem', 'on-form-change', value);
this.closer(event);
},
handleSuccess(event) {
this.handleButtons(event, this.formatColor);
this.$emit('on-pick-success');
},
handleClear(event) {
this.handleButtons(event, '');
this.$emit('on-pick-clear');
},
handleSelectColor(color) {
this.val = changeColor(color);
this.$emit('on-active-change', this.formatColor);
},
handleFirstTab(event) {
if (event.shiftKey) {
event.preventDefault();
event.stopPropagation();
this.$refs.ok.$el.focus();
} }
}, },
watch: { handleLastTab(event) {
value (newVal) { if (!event.shiftKey) {
this.val = _colorChange(newVal); event.preventDefault();
}, event.stopPropagation();
visible (val) { this.$refs.saturation.$el.focus();
this.val = _colorChange(this.value);
if (val) {
this.$refs.drop.update();
} else {
this.$refs.drop.destroy();
}
this.$emit('on-open-change', Boolean(val));
} }
}, },
methods: { onTab(event) {
// transfer Drop if (this.visible) {
handleTransferClick () { event.preventDefault();
if (this.transfer) this.disableCloseUnderTransfer = true;
},
handleClose () {
if (this.disableCloseUnderTransfer) {
this.disableCloseUnderTransfer = false;
return false;
}
this.visible = false;
},
toggleVisible () {
this.visible = !this.visible;
},
childChange (data) {
this.colorChange(data);
},
colorChange (data, oldHue) {
this.oldHue = this.saturationColors.hsl.h;
this.saturationColors = _colorChange(data, oldHue || this.oldHue);
},
isValidHex (hex) {
return tinycolor(hex).isValid();
},
simpleCheckForValidColor (data) {
const keysToCheck = ['r', 'g', 'b', 'a', 'h', 's', 'l', 'v'];
let checked = 0;
let passed = 0;
for (let i = 0; i < keysToCheck.length; i++) {
const letter = keysToCheck[i];
if (data[letter]) {
checked++;
if (!isNaN(data[letter])) {
passed++;
}
}
}
if (checked === passed) {
return data;
}
},
handleSuccess () {
const color = this.formatColor;
this.currentValue = color;
this.$emit('input', color);
this.$emit('on-change', color);
this.dispatch('FormItem', 'on-form-change', color);
this.handleClose();
},
handleClear () {
this.currentValue = '';
this.$emit('input', '');
this.$emit('on-change', '');
this.dispatch('FormItem', 'on-form-change', '');
this.handleClose();
},
handleSelectColor (color) {
this.val = _colorChange(color);
} }
} },
}; onEscape(event) {
if (this.visible) {
this.closer(event);
}
},
onArrow(event) {
if (!this.visible) {
event.preventDefault();
event.stopPropagation();
this.visible = true;
}
},
},
};
</script> </script>

View file

@ -0,0 +1,7 @@
export default {
methods: {
handleEscape(e) {
this.dispatch('ColorPicker', 'on-escape-keydown', e);
},
},
};

View file

@ -0,0 +1,73 @@
import Emitter from '../../mixins/emitter';
import handleEscapeMixin from './handleEscapeMixin';
import {getTouches} from './utils';
export default {
mixins: [Emitter, handleEscapeMixin],
props: {
focused: {
type: Boolean,
default: false,
},
value: {
type: Object,
default: undefined,
},
},
beforeDestroy() {
this.unbindEventListeners();
},
created() {
if (this.focused) {
setTimeout(() => this.$el.focus(), 1);
}
},
methods: {
handleLeft(e) {
this.handleSlide(e, this.left, 'left');
},
handleRight(e) {
this.handleSlide(e, this.right, 'right');
},
handleUp(e) {
this.handleSlide(e, this.up, 'up');
},
handleDown(e) {
this.handleSlide(e, this.down, 'down');
},
handleMouseDown(e) {
this.dispatch('ColorPicker', 'on-dragging', true);
this.handleChange(e, true);
window.addEventListener('mousemove', this.handleChange, false);
window.addEventListener('mouseup', this.handleMouseUp, false);
},
handleMouseUp() {
this.unbindEventListeners();
},
unbindEventListeners() {
window.removeEventListener('mousemove', this.handleChange);
window.removeEventListener('mouseup', this.handleMouseUp);
// This timeout is required so that the click handler for click-outside
// has the chance to run before the mouseup removes the dragging flag.
setTimeout(() => this.dispatch('ColorPicker', 'on-dragging', false), 1);
},
getLeft(e) {
const {container} = this.$refs;
const xOffset = container.getBoundingClientRect().left + window.pageXOffset;
const pageX = e.pageX || getTouches(e, 'PageX');
return pageX - xOffset;
},
getTop(e) {
const {container} = this.$refs;
const yOffset = container.getBoundingClientRect().top + window.pageYOffset;
const pageY = e.pageY || getTouches(e, 'PageY');
return pageY - yOffset;
},
},
};

View file

@ -1,86 +1,95 @@
<template> <template>
<div class="ivu-color-picker-hue"> <div
<div class="ivu-color-picker-hue-container" ref="container" :class="[prefixCls + '-hue']"
@mousedown="handleMouseDown" tabindex="0"
@touchmove="handleChange" @click="$el.focus()"
@touchstart="handleChange"> @keydown.esc="handleEscape"
<div class="ivu-color-picker-hue-pointer" :style="{top: 0, left: pointerLeft}"> @keydown.left="handleLeft"
<div class="ivu-color-picker-hue-picker"></div> @keydown.right="handleRight"
@keydown.up="handleUp"
@keydown.down="handleDown"
>
<div
ref="container"
:class="[prefixCls + '-hue-container']"
@mousedown="handleMouseDown"
@touchmove="handleChange"
@touchstart="handleChange">
<div
:style="{top: 0, left: `${percent}%`}"
:class="[prefixCls + '-hue-pointer']">
<div :class="[prefixCls + '-hue-picker']"></div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { import HASMixin from './hsaMixin';
name: 'Hue', import Prefixes from './prefixMixin';
props: { import {clamp} from './utils';
value: Object
},
data () {
return {
oldHue: 0,
pullDirection: ''
};
},
computed: {
colors () {
const h = this.value.hsl.h;
if (h !== 0 && h - this.oldHue > 0) this.pullDirection = 'right';
if (h !== 0 && h - this.oldHue < 0) this.pullDirection = 'left';
this.oldHue = h;
return this.value; export default {
}, name: 'Hue',
pointerLeft () {
if (this.colors.hsl.h === 0 && this.pullDirection === 'right') return '100%'; mixins: [HASMixin, Prefixes],
return (this.colors.hsl.h * 100) / 360 + '%';
data() {
const normalStep = 1 / 360 * 25;
const jumpStep = 20 * normalStep;
return {
left: -normalStep,
right: normalStep,
up: jumpStep,
down: -jumpStep,
powerKey: 'shiftKey',
percent: clamp(this.value.hsl.h * 100 / 360, 0, 100),
};
},
methods: {
change(percent) {
this.percent = clamp(percent, 0, 100);
const {h, s, l, a} = this.value.hsl;
const newHue = clamp(percent / 100 * 360, 0, 360);
if (h !== newHue) {
this.$emit('change', {h: newHue, s, l, a, source: 'hsl'});
} }
}, },
methods: { handleSlide(e, direction) {
handleChange (e, skip) { e.preventDefault();
!skip && e.preventDefault(); e.stopPropagation();
const container = this.$refs.container; if (e[this.powerKey]) {
const containerWidth = container.clientWidth; this.change(direction < 0 ? 0 : 100);
return;
const xOffset = container.getBoundingClientRect().left + window.pageXOffset;
const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0);
const left = pageX - xOffset;
let h;
let percent;
if (left < 0) {
h = 0;
} else if (left > containerWidth) {
h = 360;
} else {
percent = left * 100 / containerWidth;
h = (360 * percent / 100);
}
if (this.colors.hsl.h !== h) {
this.$emit('change', {
h: h,
s: this.colors.hsl.s,
l: this.colors.hsl.l,
a: this.colors.hsl.a,
source: 'hsl'
});
}
},
handleMouseDown (e) {
this.handleChange(e, true);
window.addEventListener('mousemove', this.handleChange);
window.addEventListener('mouseup', this.handleMouseUp);
},
handleMouseUp () {
this.unbindEventListeners();
},
unbindEventListeners () {
window.removeEventListener('mousemove', this.handleChange);
window.removeEventListener('mouseup', this.handleMouseUp);
} }
}
}; this.change(this.percent + direction);
</script> },
handleChange(e) {
e.preventDefault();
e.stopPropagation();
const left = this.getLeft(e);
if (left < 0) {
this.change(0);
return;
}
const {clientWidth} = this.$refs.container;
if (left > clientWidth) {
this.change(100);
return;
}
this.change(left * 100 / clientWidth);
},
},
};
</script>

View file

@ -1,2 +1,3 @@
import ColorPicker from './color-picker.vue'; import ColorPicker from './color-picker.vue';
export default ColorPicker;
export default ColorPicker;

View file

@ -0,0 +1,10 @@
export default {
data() {
return {
prefixCls: 'ivu-color-picker',
inputPrefixCls: 'ivu-input',
iconPrefixCls: 'ivu-icon',
transferPrefixCls: 'ivu-transfer',
};
},
};

View file

@ -1,20 +1,153 @@
<template> <template>
<div> <div
ref="reference"
tabindex="0"
@click="handleClick"
@keydown.esc="handleEscape"
@keydown.enter="handleEnter"
@keydown.left="handleArrow($event, 'x', left)"
@keydown.right="handleArrow($event, 'x', right)"
@keydown.up="handleArrow($event, 'y', up)"
@keydown.down="handleArrow($event, 'y', down)"
@blur="blurColor"
@focus="focusColor"
>
<template v-for="(item, index) in list"> <template v-for="(item, index) in list">
<span @click="handleClick(index)"><em :style="{'background': item}"></em></span> <div
<br v-if="(index + 1) % 12 === 0 && index !== 0 && (index + 1) !== list.length"> :key="item + ':' + index"
:class="[prefixCls + '-picker-colors-wrapper']">
<div :data-color-id="index">
<div
:style="{background: item}"
:class="[prefixCls + '-picker-colors-wrapper-color']"
></div>
<div
:ref="'color-circle-' + index"
:class="[prefixCls + '-picker-colors-wrapper-circle', hideClass]"></div>
</div>
</div>
<br v-if="lineBreak(list, index)">
</template> </template>
</div> </div>
</template> </template>
<script> <script>
export default { import Emitter from '../../mixins/emitter';
props: { import HandleEscapeMixin from './handleEscapeMixin';
list: Array import Prefixes from './prefixMixin';
import {clamp} from './utils';
export default {
name: 'RecommendedColors',
mixins: [Emitter, HandleEscapeMixin, Prefixes],
props: {
list: {
type: Array,
default: undefined,
}, },
methods: { },
handleClick (index) {
this.$emit('picker-color', this.list[index]); data() {
const columns = 12;
const rows = Math.ceil(this.list.length / columns);
const normalStep = 1;
return {
left: -normalStep,
right: normalStep,
up: -normalStep,
down: normalStep,
powerKey: 'shiftKey',
grid: {x: 1, y: 1},
rows,
columns,
};
},
computed: {
hideClass() {
return `${this.prefixCls}-hide`;
},
linearIndex() {
return this.getLinearIndex(this.grid);
},
currentCircle() {
return this.$refs[`color-circle-${this.linearIndex}`][0];
},
},
methods: {
getLinearIndex(grid) {
return this.columns * (grid.y - 1) + grid.x - 1;
},
getMaxLimit(axis) {
return axis === 'x' ? this.columns : this.rows;
},
handleArrow(e, axis, direction) {
e.preventDefault();
e.stopPropagation();
this.blurColor();
const grid = {...this.grid};
if (e[this.powerKey]) {
if (direction < 0) {
grid[axis] = 1;
} else {
grid[axis] = this.getMaxLimit(axis);
}
} else {
grid[axis] += direction;
} }
}
}; const index = this.getLinearIndex(grid);
</script>
if (index >= 0 && index < this.list.length) {
this.grid[axis] = clamp(grid[axis], 1, this.getMaxLimit(axis));
}
this.focusColor();
},
blurColor() {
this.currentCircle.classList.add(this.hideClass);
},
focusColor() {
this.currentCircle.classList.remove(this.hideClass);
},
handleEnter(e) {
this.handleClick(e, this.currentCircle);
},
handleClick(e, circle) {
e.preventDefault();
e.stopPropagation();
this.$refs.reference.focus();
const target = circle || e.target;
const colorId = target.dataset.colorId || target.parentElement.dataset.colorId;
if (colorId) {
this.blurColor();
const id = Number(colorId) + 1;
this.grid.x = id % this.columns || this.columns;
this.grid.y = Math.ceil(id / this.columns);
this.focusColor();
this.$emit('picker-color', this.list[colorId]);
this.$emit('change', {hex: this.list[colorId], source: 'hex'});
}
},
lineBreak(list, index) {
if (!index) {
return false;
}
const nextIndex = index + 1;
return nextIndex < list.length && nextIndex % this.columns === 0;
},
},
};
</script>

View file

@ -1,98 +1,98 @@
<template> <template>
<div class="ivu-color-picker-saturation-wrapper"> <div
:class="[prefixCls + '-saturation-wrapper']"
tabindex="0"
@keydown.esc="handleEscape"
@click="$el.focus()"
@keydown.left="handleLeft"
@keydown.right="handleRight"
@keydown.up="handleUp"
@keydown.down="handleDown"
>
<div <div
class="ivu-color-picker-saturation"
:style="{background: bgColor}"
ref="container" ref="container"
:style="bgColorStyle"
:class="[prefixCls + '-saturation']"
@mousedown="handleMouseDown"> @mousedown="handleMouseDown">
<div class="ivu-color-picker-saturation--white"></div> <div :class="[prefixCls + '-saturation--white']"></div>
<div class="ivu-color-picker-saturation--black"></div> <div :class="[prefixCls + '-saturation--black']"></div>
<div class="ivu-color-picker-saturation-pointer" :style="{top: pointerTop, left: pointerLeft}"> <div
<div class="ivu-color-picker-saturation-circle"></div> :style="pointerStyle"
:class="[prefixCls + '-saturation-pointer']">
<div :class="[prefixCls + '-saturation-circle']"></div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script>
import throttle from 'lodash.throttle';
export default { <script>
name: 'Saturation', import HSAMixin from './hsaMixin';
props: { import Prefixes from './prefixMixin';
value: Object import {clamp, getIncrement} from './utils';
export default {
name: 'Saturation',
mixins: [HSAMixin, Prefixes],
data() {
const normalStep = 0.01;
return {
left: -normalStep,
right: normalStep,
up: normalStep,
down: -normalStep,
multiplier: 10,
powerKey: 'shiftKey',
};
},
computed: {
bgColorStyle() {
return {background: `hsl(${this.value.hsv.h}, 100%, 50%)`};
}, },
data () { pointerStyle() {
return {}; return {top: `${-(this.value.hsv.v * 100) + 1 + 100}%`, left: `${this.value.hsv.s * 100}%`};
}, },
computed: { },
colors () {
return this.value; methods: {
}, change(h, s, v, a) {
bgColor () { this.$emit('change', {h, s, v, a, source: 'hsva'});
return `hsl(${this.colors.hsv.h}, 100%, 50%)`;
},
pointerTop () {
return (-(this.colors.hsv.v * 100) + 1) + 100 + '%';
},
pointerLeft () {
return this.colors.hsv.s * 100 + '%';
}
}, },
methods: { handleSlide(e, direction, key) {
throttle: throttle((fn, data) => {fn(data);}, 20, e.preventDefault();
{ e.stopPropagation();
'leading': true,
'trailing': false const isPowerKey = e[this.powerKey];
}), const increment = isPowerKey ? direction * this.multiplier : direction;
handleChange (e, skip) { const {h, s, v, a} = this.value.hsv;
!skip && e.preventDefault(); const saturation = clamp(s + getIncrement(key, ['left', 'right'], increment), 0, 1);
const container = this.$refs.container; const bright = clamp(v + getIncrement(key, ['up', 'down'], increment), 0, 1);
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight; this.change(h, saturation, bright, a);
const xOffset = container.getBoundingClientRect().left + window.pageXOffset; },
const yOffset = container.getBoundingClientRect().top + window.pageYOffset; handleChange(e) {
const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0); e.preventDefault();
const pageY = e.pageY || (e.touches ? e.touches[0].pageY : 0); e.stopPropagation();
let left = pageX - xOffset;
let top = pageY - yOffset; const {clientWidth, clientHeight} = this.$refs.container;
if (left < 0) { const left = clamp(this.getLeft(e), 0, clientWidth);
left = 0; const top = clamp(this.getTop(e), 0, clientHeight);
} else if (left > containerWidth) { const saturation = left / clientWidth;
left = containerWidth; const bright = clamp(1 - top / clientHeight, 0, 1);
} else if (top < 0) {
top = 0; this.change(this.value.hsv.h, saturation, bright, this.value.hsv.a);
} else if (top > containerHeight) { },
top = containerHeight; handleMouseDown(e) {
} HSAMixin.methods.handleMouseDown.call(this, e);
const saturation = left / containerWidth; window.addEventListener('mouseup', this.handleChange, false);
let bright = -(top / containerHeight) + 1; },
bright = bright > 0 ? bright : 0; unbindEventListeners(e) {
bright = bright > 1 ? 1 : bright; HSAMixin.methods.unbindEventListeners.call(this, e);
this.throttle(this.onChange, { window.removeEventListener('mouseup', this.handleChange);
h: this.colors.hsv.h, },
s: saturation, },
v: bright, };
a: this.colors.hsv.a, </script>
source: 'hsva'
});
},
onChange (param) {
this.$emit('change', param);
},
handleMouseDown () {
// this.handleChange(e, true)
window.addEventListener('mousemove', this.handleChange);
window.addEventListener('mouseup', this.handleChange);
window.addEventListener('mouseup', this.handleMouseUp);
},
handleMouseUp () {
this.unbindEventListeners();
},
unbindEventListeners () {
window.removeEventListener('mousemove', this.handleChange);
window.removeEventListener('mouseup', this.handleChange);
window.removeEventListener('mouseup', this.handleMouseUp);
}
}
};
</script>

View file

@ -0,0 +1,118 @@
import tinycolor from 'tinycolor2';
import {oneOf} from '../../utils/assist';
function setAlpha(data, alpha) {
const color = tinycolor(data);
const {_a} = color;
if (_a === undefined || _a === null) {
color.setAlpha(alpha || 1);
}
return color;
}
function getColor(data, colorData) {
const alpha = colorData && colorData.a;
if (colorData) {
// hsl is better than hex between conversions
if (colorData.hsl) {
return setAlpha(colorData.hsl, alpha);
}
if (colorData.hex && colorData.hex.length > 0) {
return setAlpha(colorData.hex, alpha);
}
}
return setAlpha(colorData, alpha);
}
export function changeColor(data, oldHue) {
const colorData = data === '' ? '#2d8cf0' : data;
const color = getColor(data, colorData);
const hsl = color.toHsl();
const hsv = color.toHsv();
if (hsl.s === 0) {
hsl.h = colorData.h || (colorData.hsl && colorData.hsl.h) || oldHue || 0;
hsv.h = hsl.h;
}
// when the hsv.v is less than 0.0164 (base on test)
// because of possible loss of precision
// the result of hue and saturation would be miscalculated
if (hsv.v < 0.0164) {
hsv.h = colorData.h || (colorData.hsv && colorData.hsv.h) || 0;
hsv.s = colorData.s || (colorData.hsv && colorData.hsv.s) || 0;
}
if (hsl.l < 0.01) {
hsl.h = colorData.h || (colorData.hsl && colorData.hsl.h) || 0;
hsl.s = colorData.s || (colorData.hsl && colorData.hsl.s) || 0;
}
return {
hsl,
hex: color.toHexString().toUpperCase(),
rgba: color.toRgb(),
hsv,
oldHue: colorData.h || oldHue || hsl.h,
source: colorData.source,
a: colorData.a || color.getAlpha(),
};
}
export function clamp(value, min, max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
export function getIncrement(key, keys, increment) {
return oneOf(key, keys) ? increment : 0;
}
export function getTouches(e, prop) {
return e.touches ? e.touches[0][prop] : 0;
}
export function toRGBAString(rgba) {
const {r, g, b, a} = rgba;
return `rgba(${[r, g, b, a].join(',')})`;
}
export function isValidHex(hex) {
return tinycolor(hex).isValid();
}
function checkIteratee(data, counts, letter) {
let {checked, passed} = counts;
const value = data[letter];
if (value) {
checked += 1;
if (Number.isFinite(value)) {
passed += 1;
}
}
return {checked, passed};
}
const keysToCheck = ['r', 'g', 'b', 'a', 'h', 's', 'l', 'v'];
export function simpleCheckForValidColor(data) {
const results = keysToCheck.reduce(checkIteratee.bind(null, data), {checked: 0, passed: 0});
return results.checked === results.passed ? data : undefined;
}

View file

@ -1,103 +1,174 @@
@color-picker-prefix-cls: ~"@{css-prefix}color-picker"; @color-picker-prefix-cls: ~'@{css-prefix}color-picker';
.@{color-picker-prefix-cls} { .@{color-picker-prefix-cls} {
display: inline-block; display: inline-block;
&-hide {
display: none;
&-drop {
visibility: hidden;
}
}
&-disabled {
background-color: @input-disabled-bg;
opacity: 1;
cursor: @cursor-disabled;
color: #ccc;
}
& > div:first-child:hover {
.ivu-input {
border-color: @input-hover-border-color;
}
}
& > div:first-child.@{color-picker-prefix-cls}-disabled:hover {
.ivu-input {
border-color: tint(@input-border-color, 20%);
}
}
& .@{select-dropdown-prefix-cls} { & .@{select-dropdown-prefix-cls} {
padding: 0; padding: 0;
} }
&-rel{ &-focused {
box-shadow: 0 0 0 2px fade(@input-hover-border-color, 20%);
}
&-rel {
line-height: 0; line-height: 0;
} }
&-color{ &-color {
width: 18px; width: 18px;
height: 18px; height: 18px;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
border-radius: 2px; border-radius: 2px;
position: relative; position: relative;
top: 2px; top: 2px;
div{ div {
width: 100%; width: 100%;
height: 100%; height: 100%;
box-shadow: inset 0 0 0 1px rgba(0,0,0,.15); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
border-radius: 2px; border-radius: 2px;
} }
&-empty{ &-empty {
background: #fff; background: #fff;
overflow: hidden; overflow: hidden;
text-align: center; text-align: center;
i{ i {
font-size: 18px; font-size: 18px;
} }
} }
&-focused {
box-shadow: 0 0 0 2px fade(@input-hover-border-color, 20%);
}
} }
&-large &-color{ &-large &-color {
width: 20px; width: 20px;
height: 20px; height: 20px;
top: 1px; top: 1px;
&-empty{ &-empty {
i{ i {
font-size: 20px; font-size: 20px;
} }
} }
} }
&-small &-color{ &-small &-color {
width: 14px; width: 14px;
height: 14px; height: 14px;
top: 3px; top: 3px;
&-empty{ &-empty {
i{ i {
font-size: 14px; font-size: 14px;
} }
} }
} }
&-picker{ &-picker {
&-wrapper{ &-wrapper {
padding: 8px 8px 0; padding: 8px 8px 0;
} }
&-panel{ &-panel {
width: 240px; width: 240px;
margin: 0 auto; margin: 0 auto;
box-sizing: initial; box-sizing: initial;
position: relative; position: relative;
} }
&-hue-slider, &-alpha-slider{ &-hue-slider,
&-alpha-slider {
height: 10px; height: 10px;
margin-top: 8px; margin-top: 8px;
position: relative; position: relative;
} }
&-colors{ &-colors {
margin-top: 8px; margin-top: 8px;
overflow: hidden; overflow: hidden;
span{ outline: 0;
display: inline-block; border: 1px solid @input-border-color;
transition: border @transition-time @ease-in-out, box-shadow @transition-time @ease-in-out;
&:hover {
border: 1px solid @input-hover-border-color;
}
&:focus {
box-shadow: 0 0 0 2px fade(@input-hover-border-color, 20%);
}
&-wrapper {
display: inline;
width: 20px; width: 20px;
height: 20px; height: 20px;
float: left; float: left;
em{ position: relative;
&-color {
outline: 0;
display: block; display: block;
position: absolute;
width: 16px; width: 16px;
height: 16px; height: 16px;
margin: 2px; margin: 2px;
cursor: pointer; cursor: pointer;
border-radius: 2px; border-radius: 2px;
box-shadow: inset 0 0 0 1px rgba(0,0,0,.15); border: 1px solid @input-border-color;
transition: border @transition-time @ease-in-out, box-shadow @transition-time @ease-in-out;
&:hover {
border: 1px solid @input-hover-border-color;
}
&:focus {
box-shadow: 0 0 0 2px fade(@input-hover-border-color, 20%);
}
}
&-circle {
cursor: pointer;
top: 10px;
left: 10px;
position: absolute;
width: 4px;
height: 4px;
box-shadow: 0 0 0 1.5px #fff, inset 0 0 1px 1px rgba(0, 0, 0, 0.3), 0 0 1px 2px rgba(0, 0, 0, 0.4);
border-radius: 50%;
transform: translate(-2px, -2px);
} }
} }
} }
.@{picker-prefix-cls}-confirm{ .@{picker-prefix-cls}-confirm {
margin-top: 8px; margin-top: 8px;
} }
} }
&-saturation{ &-saturation {
&-wrapper{ &-wrapper {
width: 100%; width: 100%;
padding-bottom: 75%; padding-bottom: 75%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
outline: 0;
border: 1px solid @input-border-color;
box-shadow: @shadow-base;
transition: border @transition-time @ease-in-out, box-shadow @transition-time @ease-in-out;
&:hover {
border: 1px solid @input-hover-border-color;
}
&:focus {
box-shadow: 0 0 0 2px fade(@input-hover-border-color, 20%);
}
} }
&, &--white, &--black{ &,
&--white,
&--black {
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
top: 0; top: 0;
@ -105,26 +176,26 @@
right: 0; right: 0;
bottom: 0; bottom: 0;
} }
&--white{ &--white {
background: linear-gradient(to right, #fff, rgba(255,255,255,0)); background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
} }
&--black{ &--black {
background: linear-gradient(to top, #000, rgba(0,0,0,0)); background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
} }
&-pointer{ &-pointer {
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
} }
&-circle{ &-circle {
width: 4px; width: 4px;
height: 4px; height: 4px;
box-shadow: 0 0 0 1.5px #fff, inset 0 0 1px 1px rgba(0,0,0,.3), 0 0 1px 2px rgba(0,0,0,.4); box-shadow: 0 0 0 1.5px #fff, inset 0 0 1px 1px rgba(0, 0, 0, 0.3), 0 0 1px 2px rgba(0, 0, 0, 0.4);
border-radius: 50%; border-radius: 50%;
transform: translate(-2px, -2px); transform: translate(-2px, -2px);
} }
} }
&-hue{ &-hue {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
@ -132,35 +203,55 @@
left: 0; left: 0;
border-radius: 2px; border-radius: 2px;
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
&-container{ outline: 0;
border: 1px solid @input-border-color;
box-shadow: @shadow-base;
transition: border @transition-time @ease-in-out, box-shadow @transition-time @ease-in-out;
&:hover {
border: 1px solid @input-hover-border-color;
}
&:focus {
box-shadow: 0 0 0 2px fade(@input-hover-border-color, 20%);
}
&-container {
cursor: pointer; cursor: pointer;
margin: 0 2px; margin: 0 2px;
position: relative; position: relative;
height: 100%; height: 100%;
} }
&-pointer{ &-pointer {
z-index: 2; z-index: 2;
position: absolute; position: absolute;
} }
&-picker{ &-picker {
cursor: pointer; cursor: pointer;
margin-top: 1px; margin-top: 1px;
width: 4px; width: 4px;
border-radius: 1px; border-radius: 1px;
height: 8px; height: 8px;
box-shadow: 0 0 2px rgba(0, 0, 0, .6); box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
background: #fff; background: #fff;
transform: translateX(-2px); transform: translateX(-2px);
} }
} }
&-alpha{ &-alpha {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
&-checkboard-wrap{ outline: 0;
border: 1px solid @input-border-color;
box-shadow: @shadow-base;
transition: border @transition-time @ease-in-out, box-shadow @transition-time @ease-in-out;
&:hover {
border: 1px solid @input-hover-border-color;
}
&:focus {
box-shadow: 0 0 0 2px fade(@input-hover-border-color, 20%);
}
&-checkboard-wrap {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
@ -169,7 +260,7 @@
overflow: hidden; overflow: hidden;
border-radius: 2px; border-radius: 2px;
} }
&-checkerboard{ &-checkerboard {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
@ -177,7 +268,7 @@
left: 0; left: 0;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
} }
&-gradient{ &-gradient {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
@ -185,32 +276,37 @@
left: 0; left: 0;
border-radius: 2px; border-radius: 2px;
} }
&-container{ &-container {
cursor: pointer; cursor: pointer;
position: relative; position: relative;
z-index: 2; z-index: 2;
height: 100%; height: 100%;
margin: 0 3px; margin: 0 3px;
} }
&-pointer{ &-pointer {
z-index: 2; z-index: 2;
position: absolute; position: absolute;
} }
&-picker{ &-picker {
cursor: pointer; cursor: pointer;
width: 4px; width: 4px;
border-radius: 1px; border-radius: 1px;
height: 8px; height: 8px;
box-shadow: 0 0 2px rgba(0, 0, 0, .6); box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
background: #fff; background: #fff;
margin-top: 1px; margin-top: 1px;
transform: translateX(-2px); transform: translateX(-2px);
} }
} }
&-confirm{ &-confirm {
margin-top: 8px;
position: relative; position: relative;
&-color{ border-top: 1px solid @border-color-split;
text-align: right;
padding: 8px;
clear: both;
&-color {
position: absolute; position: absolute;
top: 11px; top: 11px;
left: 8px; left: 8px;

View file

@ -6,7 +6,6 @@
} }
.active(@color: @input-hover-border-color) { .active(@color: @input-hover-border-color) {
border-color: tint(@color, 20%);
outline: 0; outline: 0;
box-shadow: 0 0 0 2px fade(@color, 20%); box-shadow: 0 0 0 2px fade(@color, 20%);
} }
@ -266,4 +265,4 @@
&-append { &-append {
border-left: 0; border-left: 0;
} }
} }