<template>
  <a-dropdown
    :trigger="['click']"
    :disabled="disabled"
    v-model:visible="showPicker"
    @visibleChange="handleVisibleChange">
    <div :class="triggerClass">
      <div :class="['ele-border-split ele-color-picker-trigger-inner', {'is-empty': !displayValue}]">
        <div :style="{'background-color': displayValue}"></div>
      </div>
      <div class="ele-text-secondary ele-color-picker-trigger-arrow">
        <down-outlined v-if="displayValue"/>
        <close-outlined v-else/>
      </div>
    </div>
    <template #overlay>
      <div :class="['ant-dropdown-menu ele-color-picker', popperClass]">
        <div @click.stop="">
          <ele-sv-panel
            :hue="colorHue"
            :saturation="colorSaturation"
            :value="colorValue"
            @change="handleSVChange"/>
          <ele-hue-slider
            :hue="colorHue"
            @update:hue="handleHChange"/>
          <ele-alpha-slider
            v-if="showAlpha"
            :rgb="colorRgb"
            :alpha="colorAlpha"
            @update:alpha="handleAChange"/>
          <ele-predefine
            v-if="predefine"
            :color="displayValue"
            :colors="predefineColors"
            @update:color="handleColorChange"/>
          <div class="ele-color-picker-footer">
            <div class="ele-color-picker-value">
              <a-input
                size="small"
                v-model:value="inputValue"
                @pressEnter="handleInput"
                @blur="handleInput"/>
            </div>
            <div class="ele-color-picker-button-group">
              <locale-receiver component-name="ColorPicker">
                <template #default="locale">
                  <a-button
                    size="small"
                    @click="clearValue">
                    {{ locale['btn:clear'] }}
                  </a-button>
                </template>
              </locale-receiver>
              <locale-receiver component-name="Popconfirm">
                <template #default="locale">
                  <a-button
                    size="small"
                    type="primary"
                    @click="confirmValue">
                    {{ locale['okText'] }}
                  </a-button>
                </template>
              </locale-receiver>
            </div>
          </div>
        </div>
      </div>
    </template>
  </a-dropdown>
</template>

<script>
import Color from './color';
import EleSvPanel from './components/ele-sv-panel';
import EleHueSlider from './components/ele-hue-slider';
import EleAlphaSlider from './components/ele-alpha-slider';
import ElePredefine from './components/ele-predefine';
import {DownOutlined, CloseOutlined} from '@ant-design/icons-vue';
import LocaleReceiver from 'ant-design-vue/es/locale-provider/LocaleReceiver';

export default {
  name: 'EleColorPicker',
  components: {
    EleSvPanel,
    EleHueSlider,
    EleAlphaSlider,
    ElePredefine,
    DownOutlined,
    CloseOutlined,
    LocaleReceiver
  },
  emits: [
    'change',
    'active-change',
    'update:value'
  ],
  props: {
    // 绑定的颜色, v-model
    value: String,
    // 绑定的颜色格式, hsl / hsv / hex / rgb
    colorFormat: String,
    // 是否支持透明度选择
    showAlpha: Boolean,
    // 预定义颜色
    predefine: Array,
    // 尺寸
    size: String,
    // 是否禁用
    disabled: Boolean,
    // 自定义下拉框类名
    popperClass: String,
    // 自定义类名
    customClass: String
  },
  data() {
    const color = new Color({
      enableAlpha: this.showAlpha,
      format: this.colorFormat
    });
    let displayValue = null;
    if (this.value) {
      color.fromString(this.value);
      displayValue = color.value;
    }
    return {
      // 颜色封装
      color: color,
      // 色相
      colorHue: color._hue,
      // 饱和度
      colorSaturation: color._saturation,
      // 明度
      colorValue: color._value,
      // 透明度
      colorAlpha: color._alpha,
      // rgb
      colorRgb: color.toRgb(),
      // 输入的颜色值
      inputValue: displayValue,
      // 当前显示的颜色值
      displayValue: displayValue,
      // 是否显示popper
      showPicker: false
    };
  },
  computed: {
    triggerClass() {
      return [
        'ele-bg-white ele-border-split ele-color-picker-trigger',
        {'ele-color-picker-large': this.size === 'large'},
        {'ele-color-picker-small': this.size === 'small'},
        {'is-disabled': this.disabled},
        this.customClass
      ];
    },
    predefineColors() {
      return this.predefine && this.predefine.map((value) => {
        const c = new Color({
          enableAlpha: this.showAlpha,
          format: this.colorFormat
        });
        c.fromString(value);
        return c.value;
      });
    }
  },
  methods: {
    /* 确定 */
    confirmValue() {
      this.$emit('update:value', this.color.value);
      this.$emit('change', this.color.value);
      this.$emit('active-change', this.color.value);
      this.showPicker = false;
    },
    /* 清空 */
    clearValue() {
      this.$emit('update:value', null);
      this.$emit('change', null);
      this.$emit('active-change', null);
      this.inputValue = null;
      this.displayValue = null;
      this.showPicker = false;
    },
    /* 色相改变处理 */
    handleHChange(value) {
      this.color.set('_hue', value);
      this.colorHue = this.color._hue;
      this.colorRgb = this.color.toRgb();
      this.inputValue = this.color.value;
      this.displayValue = this.color.value;
      this.$emit('active-change', this.color.value);
    },
    /* 饱和度和明度改变处理 */
    handleSVChange(obj) {
      this.color.set({
        _saturation: obj.saturation,
        _value: obj.value
      });
      this.colorSaturation = this.color._saturation;
      this.colorValue = this.color._value;
      this.colorRgb = this.color.toRgb();
      this.inputValue = this.color.value;
      this.displayValue = this.color.value;
      this.$emit('active-change', this.color.value);
    },
    /* 透明度改变处理 */
    handleAChange(value) {
      this.color.set('_alpha', value);
      this.colorAlpha = this.color._alpha;
      this.inputValue = this.color.value;
      this.displayValue = this.color.value;
      this.$emit('active-change', this.color.value);
    },
    /* 颜色改变处理 */
    handleColorChange(value) {
      if (value) {
        if (value !== this.color.value) {
          this.color.fromString(value);
          this.colorHue = this.color._hue;
          this.colorSaturation = this.color._saturation;
          this.colorValue = this.color._value;
          this.colorAlpha = this.color._alpha;
          this.colorRgb = this.color.toRgb();
        }
        this.inputValue = this.color.value;
        this.displayValue = this.color.value;
        this.$emit('active-change', this.color.value);
      }
    },
    /* 颜色输入改变处理 */
    handleInput() {
      if (this.inputValue) {
        this.handleColorChange(this.inputValue);
      } else {
        this.inputValue = this.color.value;
        this.displayValue = this.color.value;
        this.$emit('active-change', this.color.value);
      }
    },
    /* picker展开/关闭处理 */
    handleVisibleChange(visible) {
      if (!visible) {
        if (this.value) {
          this.handleColorChange(this.value);
        } else {
          this.inputValue = null;
          this.displayValue = null;
          this.$emit('active-change', null);
        }
      }
    }
  },
  watch: {
    value(value) {
      if (value) {
        this.handleColorChange(value);
      } else {
        this.inputValue = null;
        this.displayValue = null;
        this.$emit('active-change', null);
      }
    },
    colorFormat(value) {
      this.color.set('format', value);
      this.inputValue = this.color.value;
      this.displayValue = this.color.value;
      this.$emit('active-change', this.color.value);
    },
    showAlpha(value) {
      this.color.set('enableAlpha', value);
      this.inputValue = this.color.value;
      this.displayValue = this.color.value;
      this.$emit('active-change', this.color.value);
    }
  }
};
</script>

<style>
/* trigger */
.ele-color-picker-trigger {
  width: 32px;
  height: 32px;
  position: relative;
  display: inline-block;
  padding: 4px;
  border-radius: 2px;
  border: 1px solid hsla(0, 0%, 60%, .15);
  box-sizing: border-box;
  text-align: center;
  cursor: pointer;
}

.ele-color-picker-trigger .ele-color-picker-trigger-inner {
  height: 100%;
  border-radius: 2px;
  box-shadow: 0 0 0 1px hsla(0, 0%, 60%, .15);
  overflow: hidden;
}

.ele-color-picker-trigger .ele-color-picker-trigger-inner:not(.is-empty) {
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
}

.ele-color-picker-trigger .ele-color-picker-trigger-inner > div {
  height: 100%;
}

.ele-color-picker-trigger .ele-color-picker-trigger-arrow {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -6px auto auto -6px;
  font-size: 12px;
  line-height: 0;
}

.ele-color-picker-trigger .ele-color-picker-trigger-arrow > .anticon:not(.anticon-close) {
  color: #fff;
}

/* 禁用状态 */
.ele-color-picker-trigger.is-disabled {
  cursor: not-allowed;
}

.ele-color-picker-trigger.is-disabled .ele-color-picker-trigger-inner {
  opacity: .6;
}

/* 尺寸控制 */
.ele-color-picker-trigger.ele-color-picker-large {
  width: 40px;
  height: 40px;
}

.ele-color-picker-trigger.ele-color-picker-small {
  width: 24px;
  height: 24px;
  padding: 3px;
}

/* picker */
.ele-color-picker.ant-dropdown-menu {
  width: 280px;
  padding: 12px;
  box-sizing: content-box;
}

/* footer */
.ele-color-picker .ele-color-picker-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 12px;
}

.ele-color-picker .ele-color-picker-footer .ele-color-picker-value {
  width: 140px;
}

.ele-color-picker .ele-color-picker-footer .ele-color-picker-value > .ant-input {
  height: 24px;
  line-height: 1;
  padding: 0 4px;
  font-size: 12px;
  display: block;
}

.ele-color-picker .ele-color-picker-footer .ant-btn + .ant-btn {
  margin-left: 8px;
}
</style>
