@fe6/water-pro
Version:
An enterprise-class UI design language and Vue-based implementation
247 lines (243 loc) • 7.67 kB
JSX
import { ref } from 'vue';
import debounce from 'lodash-es/debounce';
import { isUndefined } from '@fe6/shared';
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
// TODO [fix][vite2] The requested module '/shop/node_modules/@simonwep/pickr/dist/pickr.es5.min.js?v=037821b3' does not provide an export named 'default'
// import Pickr from '@simonwep/pickr/dist/pickr.es5.min';
import Pickr from './colors/pickr';
import { getOptionProps, findDOMNode, getListeners } from '../_util/props-util';
import PropTypes from '../_util/vue-types';
import useConfigInject from '../_util/hooks/useConfigInject';
import BaseMixin from '../_util/BaseMixin';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import zhCn from './locale/zh_CN';
import { generateAriaId } from './utils';
export default {
name: 'AColorPicker',
mixins: [BaseMixin],
props: {
prefixCls: PropTypes.string,
defaultValue: PropTypes.string, // 默认值
config: PropTypes.object, // pickr配置
value: PropTypes.string, // 颜色值
locale: PropTypes.object.def(zhCn),
colorRounded: PropTypes.number, // 颜色数值保留几位小数
size: PropTypes.oneOf(['default', 'small', 'large']).def('default'), // 尺寸
getPopupContainer: PropTypes.func, // 指定渲染容器
disabled: PropTypes.looseBool.def(false), // 是否禁用
format: PropTypes.string, // 颜色格式设置
alpha: PropTypes.looseBool.def(false), // 是否开启透明通道
hue: PropTypes.looseBool.def(true), // 是否开启色彩预选
padding: PropTypes.number.def(16), // 弹框间距
predefine: {
type: Array,
default: () => [
'rgba(244, 67, 54, 1)',
'rgba(233, 30, 99, 1)',
'rgba(156, 39, 176, 1)',
'rgba(103, 58, 183, 1)',
'rgba(63, 81, 181, 1)',
'rgb(255, 120, 0)',
'#c71585',
'rgba(0, 188, 212, 1)',
'rgba(0, 150, 136, 1)',
'rgba(76, 175, 80, 1)',
'rgba(139, 195, 74, 1)',
'rgba(205, 220, 57, 1)',
'rgba(255, 235, 59, 1)',
'rgba(255, 193, 7, 1)',
],
},
},
emits: ['update:value', 'change', 'openChange'],
setup(props) {
const { prefixCls: prefixClsNew, configProvider } = useConfigInject('color-picker', props);
const i18n = ref(configProvider.locale?.ColorPicker || zhCn);
return {
uid: generateAriaId(prefixClsNew.value),
i18n,
configProvider,
};
},
data() {
return {
myOpen: false,
pickr: null,
};
},
watch: {
'configProvider.locale': {
handler(val) {
this.i18n = val?.ColorPicker;
this.reInitialize();
},
},
value(val) {
if (!val) {
this.reInitialize();
} else {
this.pickr.setColor(val);
}
},
disabled(val) {
this.pickr[val ? 'disable' : 'enable']();
},
config: {
handler() {
this.reInitialize();
},
deep: true,
},
format(val) {
const type = val.toLocaleUpperCase();
const res = this.pickr.setColorRepresentation(type);
if (res) {
this.pickr.applyColor();
} else {
throw new TypeError('format was invalid');
}
},
},
mounted() {
this.createPickr();
this.eventsBinding();
},
unmounted() {
this.pickr.destroyAndRemove();
},
methods: {
reInitialize() {
this.pickr.destroyAndRemove();
const dom = document.createElement('div');
dom.id = `color-picker${this.uid}`;
const box = findDOMNode(this).querySelector(`#color-picker-box${this.uid}`);
box.appendChild(dom);
this.createPickr();
this.eventsBinding();
},
setColor: debounce(function (val) {
this.pickr.setColor(val);
}, 1000),
eventsBinding() {
const pickrEvents = [
'init',
'hide',
'show',
'save',
'clear',
'change',
'changestop',
'cancel',
'swatchselect',
];
const listeners = getListeners(this);
Object.keys(listeners).forEach((event) => {
pickrEvents.includes(event) && this.pickr.on(event, listeners[event]);
});
},
createPickr() {
const { getPopupContainer } = getOptionProps(this);
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
const container = getPopupContainer || getContextPopupContainer;
this.pickr = Pickr.create(
Object.assign(
{
el: `#color-picker${this.uid}`,
container: (container && container(findDOMNode(this))) || document.body,
theme: 'monolith', // or 'monolith', or 'nano'
default: this.value || this.defaultValue || null, // 有默认颜色pickr才可以获取到_representation
swatches: this.predefine,
padding: this.padding,
closeOnScroll: true,
components: {
preview: true,
opacity: this.alpha,
hue: this.hue,
interaction: {
input: true,
clear: true,
save: true,
},
},
},
this.config,
{ i18n: this.i18n },
),
)
.on('save', (color, instance) => {
if (color) {
const _representation = instance._representation || 'HEXA';
color = color[`to${_representation}`]().toString(this.colorRounded || 0);
}
this.$emit('update:value', color || '');
this.$emit('change', color || '');
this.handleOpenChange(false);
})
.on('clear', () => {
this.$emit('update:value', null);
this.$emit('change', null);
})
.on('hide', () => {
this.setState({ myOpen: false });
this.$emit('openChange', false);
});
this.pickr[this.disabled ? 'disable' : 'enable']();
},
handleOpenChange(status) {
const open = isUndefined(status) ? !this.myOpen : status;
this.setState({ myOpen: open });
this.pickr[open ? 'show' : 'hide']();
this.$emit('openChange', open);
},
getDefaultLocale() {
const result = {
...zhCn,
...this.$props.locale,
};
result.lang = {
...zhCn,
...(this.$props.locale || {}).lang,
};
return this.locale;
},
openColorPicker() {
if (!this.disabled) {
setTimeout(() => {
this.handleOpenChange();
}, 0);
}
},
renderColorPicker() {
const { prefixCls: customizePrefixCls } = this.$props;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('color-picker', customizePrefixCls);
const { disabled } = getOptionProps(this);
const classString = {
[prefixCls]: true,
[`${prefixCls}-open`]: this.myOpen,
[`${prefixCls}-lg`]: this.size === 'large',
[`${prefixCls}-sm`]: this.size === 'small',
[`${prefixCls}-disabled`]: this.disabled,
};
return (
<div class={classString} tabindex={disabled ? -1 : 0} onClick={this.openColorPicker}>
<div class={`${prefixCls}-selection`}>
<div id={`color-picker-box${this.uid}`}>
<div id={`color-picker${this.uid}`}></div>
</div>
<DownOutlined class={`${prefixCls}-icon`} />
</div>
</div>
);
},
},
render() {
return (
<LocaleReceiver
componentName="ColorPicker"
defaultLocale={this.getDefaultLocale}
children={this.renderColorPicker}
/>
);
},
};