From bc22a2bfb97a0a28750328ba4e6e4f1940931be0 Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Fri, 17 Dec 2021 09:10:01 +0800 Subject: [PATCH 01/13] feat(colorPicker): 'new add colorPicker Component' --- .../__tests__/color-picker.spec.ts | 8 + .../devui-vue/devui/color-picker/index.ts | 17 + .../color-picker/src/color-picker-types.ts | 26 + .../devui/color-picker/src/color-picker.scss | 76 +++ .../devui/color-picker/src/color-picker.tsx | 193 +++++++ .../color-alpha-slider.scss | 42 ++ .../color-alpha-slider/color-alpha-slider.tsx | 98 ++++ .../color-picker-alpha-slider-types.ts | 25 + .../color-basic/color-basic-types.ts | 10 + .../components/color-basic/color-basic.scss | 14 + .../components/color-basic/color-basic.tsx | 31 ++ .../src/components/color-edit/color-edit.scss | 65 +++ .../src/components/color-edit/color-edit.tsx | 281 ++++++++++ .../color-edit/color-picker-edit-types.ts | 22 + .../color-history/color-history.scss | 22 + .../color-history/color-history.tsx | 100 ++++ .../color-picker-history-types.ts | 10 + .../color-hue-slider/color-hue-slider.scss | 71 +++ .../color-hue-slider/color-hue-slider.tsx | 100 ++++ .../color-picker-hue-slider-types.ts | 27 + .../color-palette/color-palette.scss | 32 ++ .../color-palette/color-palette.tsx | 128 +++++ .../color-picker-palette-types.ts | 20 + .../color-picker-panel-types.ts | 20 + .../color-picker-panel.scss | 7 + .../color-picker-panel/color-picker-panel.tsx | 86 ++++ .../src/utils/color-utils-types.ts | 36 ++ .../color-picker/src/utils/color-utils.ts | 481 ++++++++++++++++++ .../devui/color-picker/src/utils/color.ts | 47 ++ .../color-picker/src/utils/domDragger.ts | 363 +++++++++++++ .../devui/color-picker/src/utils/helpers.ts | 48 ++ .../docs/components/color-picker/index.md | 66 +++ 32 files changed, 2572 insertions(+) create mode 100644 packages/devui-vue/devui/color-picker/__tests__/color-picker.spec.ts create mode 100644 packages/devui-vue/devui/color-picker/index.ts create mode 100644 packages/devui-vue/devui/color-picker/src/color-picker-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/color-picker.scss create mode 100644 packages/devui-vue/devui/color-picker/src/color-picker.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.scss create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-picker-alpha-slider-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.scss create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.scss create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-edit/color-picker-edit-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-history/color-history.scss create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-history/color-picker-history-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.scss create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-picker-hue-slider-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.scss create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.scss create mode 100644 packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx create mode 100644 packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts create mode 100644 packages/devui-vue/devui/color-picker/src/utils/color-utils.ts create mode 100644 packages/devui-vue/devui/color-picker/src/utils/color.ts create mode 100644 packages/devui-vue/devui/color-picker/src/utils/domDragger.ts create mode 100644 packages/devui-vue/devui/color-picker/src/utils/helpers.ts create mode 100644 packages/devui-vue/docs/components/color-picker/index.md diff --git a/packages/devui-vue/devui/color-picker/__tests__/color-picker.spec.ts b/packages/devui-vue/devui/color-picker/__tests__/color-picker.spec.ts new file mode 100644 index 0000000000..a4cd0eb1f6 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/__tests__/color-picker.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { ColorPicker } from '../index'; + +describe('color-picker test', () => { + it('color-picker init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/color-picker/index.ts b/packages/devui-vue/devui/color-picker/index.ts new file mode 100644 index 0000000000..0b15cd3019 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import ColorPicker from './src/color-picker' + +ColorPicker.install = function (app: App): void { + app.component(ColorPicker.name, ColorPicker) +} + +export { ColorPicker } + +export default { + title: 'ColorPicker 颜色选择器', + category: '数据录入', + status: '80%', // TODO: 组件若开发完成则填入"100%",并删除该注释 + install(app: App): void { + app.use(ColorPicker as any) + } +} diff --git a/packages/devui-vue/devui/color-picker/src/color-picker-types.ts b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts new file mode 100644 index 0000000000..41b97a6166 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts @@ -0,0 +1,26 @@ +import type { PropType, ExtractPropTypes } from 'vue' +export const colorPickerProps = { + modelValue: { + type: [Object, String] as PropType + }, + mode: { + type: String + }, + showAlpha: { + type: Boolean, + default: true + }, + dotSize: { + type: Number, + default: 12 + }, + swatches: { + type: Array as PropType + }, + defaultTab: { + type: String, + default: 'palette' + } +} as const + +export type ColorPickerProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.scss b/packages/devui-vue/devui/color-picker/src/color-picker.scss new file mode 100644 index 0000000000..f00644c1fd --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/color-picker.scss @@ -0,0 +1,76 @@ +.devui-color-picker { + position: relative; + &-position { + position: absolute; + z-index: 9999; + background: #fff; + + top: 0; + } + + &-color-value { + display: flex; + position: absolute; + z-index: 4; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + font-weight: bold; + color: rgb(204, 15, 15); + } + + &-container { + padding: 3px; + border: 1px solid rgb(224, 224, 230); + border-radius: 3px; + &-wrap { + width: 100%; + height: 26px; + box-sizing: content-box; + box-shadow: 3px 0 5px #00000014; + position: relative; + cursor: pointer; + overflow: hidden; + display: inline-block; + vertical-align: middle; + + &-current-color { + top: 0; + right: 0; + left: 0; + position: absolute; + z-index: 3; + width: 100%; + height: 100%; + } + &-current-color-transparent { + top: 0; + right: 0; + left: 0; + overflow: hidden; + padding: 3px; + width: 100%; + height: 100%; + position: absolute; + z-index: 2; + } + &-transparent { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); + background-repeat: repeat; + } + } + } +} + +.color-picker-transition-enter-from, +.color-picker-transition-leave-to { + opacity: 0; +} +.color-picker-transition-enter-to, +.color-picker-transition-leave-from { + opacity: 1; +} +.color-picker-transition-enter-active, +.color-picker-transition-leave-active { + transition: opacity 0.2s ease-in-out; +} diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx new file mode 100644 index 0000000000..5a25d497bf --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -0,0 +1,193 @@ +import { + defineComponent, + ref, + computed, + onMounted, + watch, + nextTick, + provide, + Teleport, + unref, + reactive, + readonly, + Transition +} from 'vue' +import { colorPickerProps, ColorPickerProps } from './color-picker-types' +import colorPanel from './components/color-picker-panel/color-picker-panel' +import './color-picker.scss' +import { fromRGBA, parseColor, extractColor, RGBAtoCSS } from './utils/color-utils' +export default defineComponent({ + name: 'DColorPicker', + components: { + colorPanel + }, + props: colorPickerProps, + emits: ['update:modelValue'], + setup(props: ColorPickerProps, { emit }) { + const DEFAUTL_MODE = 'rgb' + const provideData = reactive({ + showAlpha: useReactive(() => props.showAlpha), + swatches: useReactive(() => props.swatches), + tab: useReactive(() => props.defaultTab) + }) + provide('provideData', readonly(provideData)) + const initialColor = ref(fromRGBA({ r: 255, g: 0, b: 0, a: 1 })) + const colorCubeRef = ref() + const pickerRef = ref() + const containerRef = ref() + const left = ref(0) + const top = ref(0) + const isChangeTextColor = ref(true) + const showColorPicker = ref(false) + const formItemText = ref(`${props.mode ?? DEFAUTL_MODE}`) + const mode = ref(unref(props.mode)) + onMounted(() => { + // resize 响应式 colorpicker + window.addEventListener('resize', colorPickerResize) + // 点击展示 colorpicker + window.addEventListener('click', isExhibitionColorPicker) + }) + // ** computeds + // colorpicker panel 组件位置 + const colorPickerPostion = computed(() => { + if (colorCubeRef.value) { + return { + transform: `translate(${left.value}px, ${top.value}px)` + } + } + return null + }) + // 交互触发item 颜色 面板 + const tiggerColor = computed(() => { + const trigger = initialColor.value.rgba + if (!props.showAlpha) { + trigger.a = 1 + } + return { + backgroundColor: `${RGBAtoCSS(trigger)}` + } + }) + // 交互面板 的value 值 动态展示 根据不同 type + const formItemValue = computed(() => { + return extractColor(initialColor.value, '', formItemText.value, props.showAlpha) + }) + // 动态 根据当前 透明度修改文本颜色 tips:根据不同 面板颜色 目前 不够优雅 + const textColor = computed(() => { + if (initialColor.value.alpha > 0.5) { + return isChangeTextColor.value ? { color: '#fff' } : { color: '#000' } + } else { + return { color: '#000' } + } + }) + // ** emits + // 动态 交互面板 文本展示颜色 tips:根据不同 面板颜色 目前 不够优雅 + function changeTextColor(value: boolean) { + isChangeTextColor.value = value + } + // 通过修改画板 颜色 修改 v-model 颜色 + function changePaletteColor(colorMap) { + updateUserColor(colorMap) + } + // 通过用户点击触发修改 交互面板 文本类型 + function changeTextModeType(type: string) { + mode.value = type + formItemText.value = type + } + function useReactive(source) { + const model = ref(source()) + watch(source, (newValue) => { + model.value = newValue + }) + return model + } + // 初始化的时候 确定 colopicker位置 + watch( + () => showColorPicker.value, + (newValue) => { + const textPalette = colorCubeRef.value?.getBoundingClientRect() + newValue && + nextTick(() => { + pickerRef.value.style.transform = `translate(${textPalette.left + 'px'}, ${ + textPalette.top + textPalette.height + 'px' + })` + }) + }, + { + deep: true, + immediate: true + } + ) + // 监听用户输入 2021.12.10 + watch( + () => props.modelValue, + (newValue) => { + // 全部转换成对象 + updateUserColor(parseColor(newValue, initialColor.value)) + }, + { immediate: true } + ) + // 更新用户输入颜色 2021.12.10 + function updateUserColor(color) { + initialColor.value = color + // 提取颜色 2021.12.10 + const value = extractColor(initialColor.value, props.modelValue, mode.value, props.showAlpha) + emit('update:modelValue', value) + } + function colorPickerResize() { + const rect = colorCubeRef.value?.getBoundingClientRect() + left.value = rect.left + top.value = rect.top + rect.height + } + function isExhibitionColorPicker(e) { + if (colorCubeRef.value?.contains(e.target)) { + showColorPicker.value = true + } + if (!!pickerRef.value && !pickerRef.value?.contains(e.target)) { + showColorPicker.value = !showColorPicker.value + } + } + return () => { + return ( +
+
+
+
+
+
+

{formItemValue.value}

+
+
+
+ + + {showColorPicker.value ? ( +
+ +
+ ) : null} +
+
+
+ ) + } + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.scss b/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.scss new file mode 100644 index 0000000000..b624a0ea53 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.scss @@ -0,0 +1,42 @@ +.devui-color-picker-alpha-slider { + position: relative; + margin-bottom: 15px; + width: 100%; + height: 14px; + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.08); + border-radius: 15px; + + &.transparent { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); + background-repeat: repeat; + } + + &__bar { + position: relative; + width: 100%; + height: 100%; + border-radius: 15px; + + &-pointer { + position: absolute; + width: 14px; + height: 14px; + } + + &-handle { + width: 14px; + height: 14px; + border-radius: 6px; + transform: translate(-7px, -2px); + background-color: #f8f8f8; + margin-top: 2px; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37); + cursor: pointer; + + &.vertical { + transform: translate(0, -7px); + margin-top: 0; + } + } + } +} diff --git a/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.tsx b/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.tsx new file mode 100644 index 0000000000..3df8c6c99e --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-alpha-slider.tsx @@ -0,0 +1,98 @@ +import { computed, defineComponent, ref, onMounted } from 'vue' +import { colorPickerAlphaSliderProps } from './color-picker-alpha-slider-types' +import { DOMUtils } from '../../utils/domDragger' +import { RGBtoCSS, fromHSVA } from '../../utils/color-utils' +import './color-alpha-slider.scss' +export default defineComponent({ + name: 'ColorAlphaSlider', + props: colorPickerAlphaSliderProps, + emits: ['update:modelValue'], + setup(props: colorPickerAlphaSliderProps, ctx) { + const DEFAULT_TRANSITION = { transition: 'all 0.3s ease' } + const clickTransfrom = ref(DEFAULT_TRANSITION) + const barElement = ref(null) + const cursorElement = ref(null) + const onClickSider = (event: Event) => { + const target = event.target + if (target !== barElement.value) { + onMoveBar(event as MouseEvent) + } + } + + const onMoveBar = (event: MouseEvent) => { + event.stopPropagation() + if (barElement.value && cursorElement.value) { + const rect = barElement.value.getBoundingClientRect() + const offsetWidth = cursorElement.value.offsetWidth + let left = event.clientX - rect.left + left = Math.max(offsetWidth / 2, left) + left = Math.min(left, rect.width - offsetWidth / 2) + const alpha = Math.round(((left - offsetWidth / 2) / (rect.width - offsetWidth)) * 100) + ctx.emit('update:modelValue', fromHSVA({ ...props.modelValue.hsva, a: alpha / 100 })) + } + } + + const getBackgroundStyle = computed(() => { + return { + background: `linear-gradient(to right, transparent , ${RGBtoCSS(props.modelValue.rgba)})` + } + }) + + const getCursorLeft = computed(() => { + if (barElement.value && cursorElement.value) { + const alpha = props.modelValue.rgba.a + const rect = barElement.value.getBoundingClientRect() + const offsetWidth = cursorElement.value.offsetWidth + return Math.round(alpha * (rect.width - offsetWidth) + offsetWidth / 2) + } + return 0 + }) + + const getCursorStyle = computed(() => { + const left = getCursorLeft.value + return { + left: left + 'px', + top: 0, + ...clickTransfrom.value + } + }) + onMounted(() => { + const dragConfig = { + drag: (event: Event) => { + clickTransfrom.value = null + onMoveBar(event as MouseEvent) + }, + end: (event: Event) => { + clickTransfrom.value = DEFAULT_TRANSITION + onMoveBar(event as MouseEvent) + } + } + if (barElement.value && cursorElement.value) { + DOMUtils.triggerDragEvent(barElement.value, dragConfig) + } + }) + const alphaClass = computed(() => { + return ['devui-color-picker-alpha-slider', 'transparent'] + }) + return () => { + return ( +
+
+
+
+
+
+
+ ) + } + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-picker-alpha-slider-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-picker-alpha-slider-types.ts new file mode 100644 index 0000000000..51f23d935d --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-alpha-slider/color-picker-alpha-slider-types.ts @@ -0,0 +1,25 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import type { ColorPickerColor } from '../../utils/color-utils-types' + +export const colorPickerAlphaSliderProps = { + color: { + type: Object + }, + modelValue: { + type: Object as PropType + }, + rgba: { + type: Object, + default: null + }, + height: { + type: Number, + default: 15 + }, + width: { + type: Number, + default: 300 + } +} as const + +export type colorPickerAlphaSliderProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic-types.ts new file mode 100644 index 0000000000..b719464714 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic-types.ts @@ -0,0 +1,10 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import type { ColorPickerColor } from '../../utils/color-utils-types' + +export const colorPickerBasicColorProps = { + color: { + type: Object as PropType + } +} as const + +export type colorPickerBasicColorProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.scss b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.scss new file mode 100644 index 0000000000..0380285bc8 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.scss @@ -0,0 +1,14 @@ +.devui-color-picker-basic { + flex-wrap: wrap; + // justify-content: space-between; + align-items: center; + &-div { + box-sizing: content-box; + margin: 4px; + width: 20px; + height: 20px; + border: solid 1px #e7e7e7; + cursor: pointer; + border-radius: 1px; + } +} diff --git a/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx new file mode 100644 index 0000000000..3023d3ab20 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx @@ -0,0 +1,31 @@ +import { defineComponent, ref, inject } from 'vue' +import { colorPickerBasicColorProps } from './color-basic-types' +import { fromHex } from '../../utils/color-utils' +import './color-basic.scss' +import { color } from '../../utils/color' +export default defineComponent({ + name: 'ColorBasic', + props: colorPickerBasicColorProps, + setup(props) { + const swatchesInject = inject('provideData') + + const currentColor = ref(props.color) + function changeBasicColor(hex: string) { + currentColor.value = fromHex(hex) + } + const swatches = ref(Object.values(swatchesInject.swatches ?? [])) + return () => { + return ( +
+ {(swatches.value.length !== 0 ? swatches.value : color).map((hex: string) => ( +
changeBasicColor(hex)} + class={['devui-color-picker-basic-div']} + style={{ backgroundColor: hex }} + >
+ ))} +
+ ) + } + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.scss b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.scss new file mode 100644 index 0000000000..5240bb27bb --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.scss @@ -0,0 +1,65 @@ +.devui-color-picker-edit { + justify-content: space-between; + align-items: center; + + &-text { + display: inline-block; + width: 50px; + padding: 0 10px; + user-select: none; + } + + &-name { + user-select: none; + cursor: pointer; + display: flex; + align-items: center; + justify-content: space-around; + width: 50px; + } + + &-flex { + display: flex; + align-items: center; + } + + &-input { + flex: 1; + padding: 0 5px; + + input { + border: none; + outline: none; + width: 100%; + text-align: center; + } + + &-wrapper { + width: 100%; + border: 1px solid rgba(0, 0, 0, 0.2); + padding: 2px; + + &:focus-within { + border: 1px solid var(--devui-primary); + } + } + + &.string-input &-wrapper { + border-radius: 5px; + } + + &.number-input &-wrapper { + border-radius: 0; + + &:first-child { + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + } + + &:last-child { + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + } + } + } +} diff --git a/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx new file mode 100644 index 0000000000..9ef92dd92c --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx @@ -0,0 +1,281 @@ +import { defineComponent, computed, ref, inject } from 'vue' +import { ColorPickerEditProps, colorPickerEditProps } from './color-picker-edit-types' +import { provideColor, ColorPickerColor } from '../../utils/color-utils-types' +import './color-edit.scss' +import { fromHex, fromHexa, fromHSLA, fromHSVA, fromRGBA } from '../../utils/color-utils' +import Schema, { Rules } from 'async-validator' + +// MODE支持模式 +const MODE_SUPPORT = ['rgb', 'hex', 'hsl', 'hsv'] as const + +// 色值校验规则 +const colorRules: Rules = { + alpha: [ + { + type: 'number', + required: true, + min: 0, + max: 1 + } + ], + hex: [{ type: 'string', pattern: /^#[0-9a-fA-F]{6}/ }], + hexa: [{ type: 'string', pattern: /^#[0-9a-fA-F]{6,8}/ }], + rgba: { + type: 'object', + required: true, + fields: { + r: { type: 'number', required: true, min: 0, max: 255 }, + g: { type: 'number', required: true, min: 0, max: 255 }, + b: { type: 'number', required: true, min: 0, max: 255 }, + a: { type: 'number', required: true, min: 0, max: 1 } + } + }, + hsla: { + type: 'object', + required: true, + fields: { + h: { type: 'number', required: true, min: 0, max: 360 }, + s: { type: 'number', required: true, min: 0, max: 1 }, + l: { type: 'number', required: true, min: 0, max: 1 }, + a: { type: 'number', required: true, min: 0, max: 1 } + } + }, + hsva: { + type: 'object', + required: true, + fields: { + h: { type: 'number', required: true, min: 0, max: 360 }, + s: { type: 'number', required: true, min: 0, max: 1 }, + v: { type: 'number', required: true, min: 0, max: 1 }, + a: { type: 'number', required: true, min: 0, max: 1 } + } + } +} + +export default defineComponent({ + name: 'ColorEdit', + props: colorPickerEditProps, + emits: ['changeTextModeColor', 'update:modelValue'], + setup(props: ColorPickerEditProps, { emit }) { + // 设置showalpha 为false 会报错 2021.12.14 + const isShowAlpha: provideColor = inject('provideData') + // 模式值 + const modelValue = computed(() => `${props.mode}${isShowAlpha.showAlpha ? 'a' : ''}`) + // 颜色值 + const colorValue = ref(props.color) + // 模式值类型 + const modelValueType = computed(() => (props.mode === 'hex' ? 'string' : 'number')) + + /** + * 获取有效颜色值 + * @param color + * @returns + */ + function getValidColor(color: ColorPickerColor) { + const validator = new Schema(colorRules) + + // 使用ColorRules验证有效性 + return new Promise((resolve, reject) => { + validator.validate(color, (errors) => { + errors && console.warn('色值校验异常:', errors) + errors ? reject() : resolve(color) + }) + }) + } + + /** + * 修改Mode值 + */ + function onChangeModel() { + // 安装MODE_SUPPORT列表进行更换 + const currentIndex = MODE_SUPPORT.findIndex((x) => x === props.mode) + const mode = MODE_SUPPORT[(currentIndex + 1) % MODE_SUPPORT.length] + emit('changeTextModeColor', mode) + } + + /** + * 渲染字符类型组件 + */ + function renderStringValue() { + // 绑定KEy + const key = modelValue.value + const value = colorValue.value[key] + + const getConvertColor = (v: string) => { + // 获取转换函数 + const from = isShowAlpha.showAlpha ? fromHexa : fromHex + + // 获取颜色值 + const color = from(v) + + // 获取色值有效性 + return getValidColor(color) + } + + /** + * 更新输入值 + */ + const updateValue = async (event: Event) => { + const target = event.target as HTMLInputElement + + getConvertColor(target.value) + // 如果Color为有效值则进行更新 + .then((color) => (colorValue.value = color)) + // 如果Color为无效值则还原数值 + .catch(() => (target.value = value)) + } + + return ( +
+
+ +
+
+ ) + } + + /** + * 渲染数值类型组件 + * TODO: alpha需要进行白分化显示处理 + * TODO: 监听键盘上下键进行值修改 + */ + function renderNumberValue() { + // 绑定缩放KEYS + const scaleKeys = ['s', 'v', 'l'] as const + const percentKeys = ['a'] as const + + const key = modelValue.value + // 对指定数值进行缩放处理 + const value = colorValue.value[key.replace(/a?$/, 'a')] + + const getConvertColor = (model) => { + // 获取转换函数 + const { from } = [ + { mode: ['rgb', 'rgba'], from: fromRGBA }, + { mode: ['hsv', 'hsva'], from: fromHSVA }, + { mode: ['hsl', 'hsla'], from: fromHSLA } + ].find((x) => x.mode.includes(key)) + // 获取颜色值 + const color = from(isShowAlpha.showAlpha ? model : { ...model, a: 1 }) + + // 通过RGBA进行验证有效性 + return getValidColor(color) + } + + /** + * 更新输入值 + */ + const updateValue = (k: string) => async (event: Event) => { + const target = event.target as HTMLInputElement + + // 获取有效颜色值 + // 无效则进行还原 + // 直接截位取整 + getConvertColor({ ...value, [k]: parseValue(k, target.value) }) + // 如果Color为有效值则进行更新 + .then((color) => (colorValue.value = color)) + // 如果Color为无效值则还原数值 + .catch(() => (target.value = formatValue(k, value[k]))) + } + + /** + * 将存储值转换为显示值 + * @param k + * @param v + * @returns + */ + function formatValue(k, v: number): string { + switch (true) { + case scaleKeys.includes(k): + return (v * 100).toFixed() + case percentKeys.includes(k): + return `${Math.round(v * 100)}%` + default: + return v.toString() + } + } + + /** + * 将显示值转换为存储值 + * @param k + * @param v + * @returns + */ + function parseValue(k, v: string): number { + switch (true) { + case scaleKeys.includes(k): + return parseFloat((parseInt(v) / 100).toFixed(2)) + case percentKeys.includes(k): + return parseFloat((parseInt(v.replace(/%$/, '')) / 100).toFixed(2)) + default: + return Number(v) + } + } + + /** + * 方向键修改值处理 + * @returns + */ + function onKeyChangeValue() { + return (e: KeyboardEvent) => { + const target = e.target as HTMLInputElement + + const changeValue = { + ArrowUp: 1, + ArrowDown: -1 + }[e.code] + + if (changeValue !== undefined) { + e.preventDefault() + const [v] = target.value.match(/\d+/g) + const newValue = (parseInt(v) + changeValue).toString() + target.value = target.value.replace(/\d+/g, newValue) + // 发送数值修改事件 + target.dispatchEvent(new CustomEvent('change')) + } + } + } + + return ( +
+ {key.split('').map((k: string) => ( +
+ +
+ ))} +
+ ) + } + + /** + * 渲染输入组件 + * @returns + */ + function renderValueInput() { + switch (modelValueType.value) { + case 'string': + return renderStringValue() + case 'number': + return renderNumberValue() + } + } + + return () => ( +
+
+ {modelValue.value.toUpperCase()} +
+ {renderValueInput()} +
+ ) + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-edit/color-picker-edit-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-picker-edit-types.ts new file mode 100644 index 0000000000..e7310ebe00 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-picker-edit-types.ts @@ -0,0 +1,22 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import { ColorPickerColor } from '../../utils/color-utils-types' +export const colorPickerEditProps = { + /* test: { + type: Object as PropType<{ xxx: xxx }> + } */ + /** + * 选择器圆点大小 + */ + showAlpha: { + type: Boolean, + default: false + }, + mode: { + type: String + }, + color: { + type: Object as PropType + } +} as const + +export type ColorPickerEditProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.scss b/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.scss new file mode 100644 index 0000000000..7a217b8877 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.scss @@ -0,0 +1,22 @@ +.devui-color-picker-history { + margin-top: 10px; + + &_color-box { + cursor: pointer; + margin: 5px; + height: 20px; + width: 20px; + border: solid 1px #e7e7e7; + + &.transparent { + background: linear-gradient( + to bottom right, + rgba(0, 0, 0, 0) 0%, + rgba(0, 0, 0, 0) calc(50% - 1.5px), + #f18887 50%, + rgba(0, 0, 0, 0) calc(50% + 1.5px), + rgba(0, 0, 0, 0) 100% + ); + } + } +} diff --git a/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx b/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx new file mode 100644 index 0000000000..7cbb4ed870 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx @@ -0,0 +1,100 @@ +import { defineComponent, Ref, ref, UnwrapRef, watch, inject } from 'vue' +import { ColorPickerHistoryProps, colorPickerHistoryProps } from './color-picker-history-types' +import { Icon } from '../../../../icon' +import './color-history.scss' +import { fromHexa } from '../../utils/color-utils' +import { provideColor, ColorPickerColor } from '../../utils/color-utils-types' +import { debounce } from 'lodash-es' + +const STORAGE_KEY = 'STORAGE_COLOR_PICKER_HISTORY_KEY' +const MAX_HISOTRY_COUNT = 8 + +/** + * 创建支持存储Store + * @param v + * @param params + * @returns + */ +function useStore(v: T, { storage }: { storage?: boolean } = {}): Ref> { + // 获取默认值 + const getDefaultValue = (): T => { + if (storage) { + return JSON.parse(localStorage.getItem(STORAGE_KEY)) || v + } else { + return v + } + } + + // 创建Store + const store = ref(getDefaultValue()) + + // 监听Store修改 + watch(store, (value) => { + if (storage) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(value)) + } + }) + + return store +} + +export default defineComponent({ + name: 'ColorEdit', + components: { + Icon + }, + props: colorPickerHistoryProps, + emits: ['update:color'], + setup(props: ColorPickerHistoryProps) { + // 获取 是否showalpha + const alphaInject: provideColor = inject('provideData') + + // 创建历史存储 + const history = useStore([], { storage: true }) + const color = ref(props.color) + + // 更新历史值函数 + // 进行缓冲处理 + const updateHistory = debounce((value: ColorPickerColor) => { + const index = history.value.findIndex( + (x) => x === value.hexa || (x.endsWith('00') && value.alpha === 0) + ) + if (index >= 0) { + history.value.splice(index, 1) + } + + history.value = [alphaInject.showAlpha ? value.hexa : value.hex, ...history.value].slice( + 0, + MAX_HISOTRY_COUNT + ) + }, 100) + + // 更新历史值 + watch(props.color, (value) => { + updateHistory(value) + }) + + /** + * 选择历史色 + * @param value + */ + function onChangeColor(value: string) { + color.value = fromHexa(value) + } + + return () => ( +
+ {history.value.map((hexa: string) => ( +
onChangeColor(hexa)} + class={[ + 'devui-color-picker-history_color-box', + hexa.endsWith('00') ? 'transparent' : '' + ]} + style={{ backgroundColor: hexa }} + >
+ ))} +
+ ) + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-history/color-picker-history-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-history/color-picker-history-types.ts new file mode 100644 index 0000000000..454b44d98d --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-history/color-picker-history-types.ts @@ -0,0 +1,10 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import type { ColorPickerColor } from '../../utils/color-utils-types' + +export const colorPickerHistoryProps = { + color: { + type: Object as PropType + } +} as const + +export type ColorPickerHistoryProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.scss b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.scss new file mode 100644 index 0000000000..3756a5e2ce --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.scss @@ -0,0 +1,71 @@ +.devui-color-picker-hue-slider { + position: relative; + margin: 13px 0; + width: 100%; + height: 14px; + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.08); + border-radius: 15px; + &.transparent { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); + background-repeat: repeat; + } + + &__bar { + position: relative; + width: 100%; + height: 100%; + border-radius: 15px; + background: -webkit-linear-gradient( + left, + rgb(255, 0, 0) 0%, + rgb(255, 255, 0) 16.66%, + rgb(0, 255, 0) 33.33%, + rgb(0, 255, 255) 50%, + rgb(0, 0, 255) 66.66%, + rgb(255, 0, 255) 83.33%, + rgb(255, 0, 0) 100% + ); + background: -moz-linear-gradient( + left, + rgb(255, 0, 0) 0%, + rgb(255, 255, 0) 16.66%, + rgb(0, 255, 0) 33.33%, + rgb(0, 255, 255) 50%, + rgb(0, 0, 255) 66.66%, + rgb(255, 0, 255) 83.33%, + rgb(255, 0, 0) 100% + ); + background: -ms-linear-gradient( + left, + rgb(255, 0, 0) 0%, + rgb(255, 255, 0) 16.66%, + rgb(0, 255, 0) 33.33%, + rgb(0, 255, 255) 50%, + rgb(0, 0, 255) 66.66%, + rgb(255, 0, 255) 83.33%, + rgb(255, 0, 0) 100% + ); + + &-pointer { + position: absolute; + width: 14px; + height: 14px; + } + + &-handle { + width: 14px; + height: 14px; + border-radius: 6px; + transform: translate(-7px, -2px); + background-color: #f8f8f8; + margin-top: 2px; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37); + cursor: pointer; + + &.vertical { + transform: translate(0, -7px); + margin-top: 0; + } + } + } +} diff --git a/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx new file mode 100644 index 0000000000..ae5b7ef0da --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx @@ -0,0 +1,100 @@ +import { computed, defineComponent, ref, onMounted, watch } from 'vue' +import { colorPickerHueSliderProps } from './color-picker-hue-slider-types' +import { DOMUtils } from '../../utils/domDragger' +import { fromHSVA } from '../../utils/color-utils' +import './color-hue-slider.scss' +export default defineComponent({ + name: 'ColorHueSlider', + props: colorPickerHueSliderProps, + emits: ['update:modelValue'], + setup(props, ctx) { + const DEFAULT_TRANSITION = { transition: 'all 0.3s ease' } + const barElement = ref(null) + const cursorElement = ref(null) + const clickTransfrom = ref(DEFAULT_TRANSITION) + const getCursorLeft = () => { + if (barElement.value && cursorElement.value) { + const rect = barElement.value.getBoundingClientRect() + const offsetWidth = cursorElement.value.offsetWidth + if (props.modelValue.hue === 360) { + return rect.width - offsetWidth / 2 + } + return ((props.modelValue.hue % 360) * (rect.width - offsetWidth)) / 360 + offsetWidth / 2 + } + + return 0 + } + + const getCursorStyle = computed(() => { + const left = getCursorLeft() + return { + left: left + 'px', + top: 0, + ...clickTransfrom.value + } + }) + const onClickSider = (event: Event) => { + const target = event.target + if (target !== barElement.value) { + onMoveBar(event as MouseEvent) + } + } + + const onMoveBar = (event: MouseEvent) => { + event.stopPropagation() + if (barElement.value && cursorElement.value) { + const rect = barElement.value.getBoundingClientRect() + + const offsetWidth = cursorElement.value.offsetWidth + + let left = event.clientX - rect.left + left = Math.min(left, rect.width - offsetWidth / 2) + left = Math.max(offsetWidth / 2, left) + + const hue = Math.round(((left - offsetWidth / 2) / (rect.width - offsetWidth)) * 360) + + ctx.emit( + 'update:modelValue', + fromHSVA({ + h: hue, + s: props.modelValue.hsva.s, + v: props.modelValue.hsva.v, + a: props.modelValue.hsva.a + }) + ) + } + } + + onMounted(() => { + const dragConfig = { + drag: (event: Event) => { + clickTransfrom.value = null + onMoveBar(event as MouseEvent) + }, + end: (event: Event) => { + clickTransfrom.value = DEFAULT_TRANSITION + onMoveBar(event as MouseEvent) + } + } + + if (barElement.value && cursorElement.value) { + DOMUtils.triggerDragEvent(barElement.value, dragConfig) + } + }) + return () => { + return ( +
+
+
+
+
+
+
+ ) + } + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-picker-hue-slider-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-picker-hue-slider-types.ts new file mode 100644 index 0000000000..c4bcd4314a --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-picker-hue-slider-types.ts @@ -0,0 +1,27 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import type { ColorPickerColor } from '../../utils/color-utils-types' + +export const colorPickerHueSliderProps = { + /* test: { + type: Object as PropType<{ xxx: xxx }> + } */ + /** + * 选择器圆点大小 + */ + color: { + type: Object + }, + modelValue: { + type: Object as PropType + }, + width: { + type: Number, + default: 300 + }, + height: { + type: Number, + default: 15 + } +} as const + +export type colorPickerHueSliderProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.scss b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.scss new file mode 100644 index 0000000000..86eb7471fc --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.scss @@ -0,0 +1,32 @@ +.devui-color-picker-palette { + position: relative; + width: 100%; + &__white, + &__black { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + &__black { + background: linear-gradient(0deg, #000, transparent); + } + + &__white { + background: linear-gradient(90deg, #fff, hsla(0, 0%, 100%, 0)); + } + + &-handler { + position: absolute; + // z-index: 999; + div { + width: 10px; + height: 10px; + border-radius: 50%; + border: 2px solid #ffffff; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37); + cursor: pointer; + } + } +} diff --git a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx new file mode 100644 index 0000000000..c6ff05a862 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx @@ -0,0 +1,128 @@ +import { defineComponent, ref, onMounted, computed, getCurrentInstance, watch } from 'vue' +import { DOMUtils } from '../../utils/domDragger' +import { fromHSVA } from '../../utils/color-utils' +import { clamp } from '../../utils/helpers' +import { colorPickerPaletteProps } from './color-picker-palette-types' +import './color-palette.scss' +export default defineComponent({ + name: 'ColorPallete', + props: colorPickerPaletteProps, + emits: ['update:modelValue', 'changeTextColor'], + setup(props: colorPickerPaletteProps, ctx) { + const DEFAULT_TRANSITION = { transition: 'all 0.3s ease' } + const clickTransfrom = ref(DEFAULT_TRANSITION) + const paletteElement = ref() + const canvasElement = ref() + const handlerElement = ref() + const paletteInstance = getCurrentInstance() + + const cursorTop = ref(0) + const cursorLeft = ref(0) + const getDotStyle = computed(() => { + return { + width: `${props.dotSize}px`, + height: `${props.dotSize}px`, + transform: `translate(-${props.dotSize / 2}px, -${props.dotSize / 2}px)` + } + }) + const getCursorStyle = computed(() => { + return { + top: cursorTop.value + 'px', + left: cursorLeft.value + 'px', + ...clickTransfrom.value + } + }) + function renderCanvas() { + const canvas = canvasElement.value.getContext('2d') + const parentWidth = paletteElement.value.offsetWidth + canvasElement.value.width = parentWidth + canvasElement.value.height = props.height + const saturationGradient = canvas.createLinearGradient(0, 0, parentWidth, 0) + saturationGradient.addColorStop(0, 'hsla(0, 0%, 100%, 1)') // white + saturationGradient.addColorStop(1, `hsla(${props.modelValue.hue}, 100%, 50%, 1)`) + canvas.fillStyle = saturationGradient + canvas.fillRect(0, 0, parentWidth, props.height) + const valueGradient = canvas.createLinearGradient(0, 0, 0, props.height) + valueGradient.addColorStop(0, 'hsla(0, 0%, 100%, 0)') // transparent + valueGradient.addColorStop(1, 'hsla(0, 0%, 0%, 1)') // black + canvas.fillStyle = valueGradient + canvas.fillRect(0, 0, parentWidth, props.height) + } + function clickPalette(event: Event) { + const target = event.target + if (target !== paletteElement.value) { + handleDrag(event as MouseEvent) + } + } + function updatePosition() { + if (paletteInstance) { + const parentWidth = paletteElement.value.offsetWidth + cursorLeft.value = Number(props.modelValue?.hsva.s) * parentWidth + cursorTop.value = (1 - Number(props.modelValue?.hsva.v)) * props.height + } + } + function handleDrag(event: any) { + const parentWidth = paletteElement.value.offsetWidth + if (paletteInstance) { + const el = canvasElement.value + const rect = el?.getBoundingClientRect() + let left = event.clientX - rect.left + let top = event.clientY - rect.top + left = clamp(left, 0, parentWidth) + top = clamp(top, 0, props.height) + cursorLeft.value = left + cursorTop.value = top + const isChangeTextColor = computed(() => { + if (left > rect.width / 2 || top > rect.height / 2) { + return true + } else { + return false + } + }) + ctx.emit( + 'update:modelValue', + fromHSVA({ + h: props.modelValue.hue, + s: clamp(event.clientX - rect.left, 0, rect.width) / rect.width, + v: 1 - clamp(event.clientY - rect.top, 0, rect.height) / rect.height, + a: props.modelValue.alpha + }) + ) + ctx.emit('changeTextColor', isChangeTextColor.value) + } + } + onMounted(() => { + renderCanvas() + if (paletteInstance && paletteInstance.vnode.el && handlerElement.value) { + DOMUtils.triggerDragEvent(handlerElement.value, { + drag: (event: Event) => { + clickTransfrom.value = null + handleDrag(event as MouseEvent) + }, + end: (event) => { + clickTransfrom.value = DEFAULT_TRANSITION + handleDrag(event as MouseEvent) + } + }) + updatePosition() + } + }) + watch( + () => props.modelValue, + () => { + updatePosition() + } + ) + ctx.expose({ renderCanvas }) + return () => { + return ( +
+ +
+
+
+
+ ) + } + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts new file mode 100644 index 0000000000..ef1cb2b2ac --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts @@ -0,0 +1,20 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import { fromRGBA } from '../../utils/color-utils' +import type { ColorPickerColor } from '../../utils/color-utils-types' + +export const colorPickerPaletteProps = { + modelValue: { + type: Object as PropType, + default: () => fromRGBA({ r: 255, g: 0, b: 0, a: 1 }) + }, + height: { + type: Number, + default: 200 + }, + dotSize: { + type: Number, + default: 15 + } +} as const + +export type colorPickerPaletteProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel-types.ts new file mode 100644 index 0000000000..f6194b8264 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel-types.ts @@ -0,0 +1,20 @@ +import type { PropType, ExtractPropTypes } from 'vue' +import { ColorPickerColor } from '../../utils/color-utils-types' + +export const colorPickerProps = { + colorMap: { + type: Object + }, + modelValue: { + type: Object as PropType + }, + showAlpha: { + type: Boolean, + default: true + }, + mode: { + type: String + } +} as const + +export type ColorPickerProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.scss b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.scss new file mode 100644 index 0000000000..93e7c06373 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.scss @@ -0,0 +1,7 @@ +.devui-color-picker-panel { + width: 270px; + padding: 12px; + border-radius: 4px; + box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.1), 0 5px 8px 0 rgba(0, 0, 0, 0.1), + 0 1px 14px 0 rgba(0, 0, 0, 0.1); +} diff --git a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx new file mode 100644 index 0000000000..15c9e2221b --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx @@ -0,0 +1,86 @@ +import { defineComponent, ref, watch, nextTick, inject } from 'vue' +import { colorPickerProps, ColorPickerProps } from './color-picker-panel-types' +import { provideColor } from '../../utils/color-utils-types' +import { Tabs } from '../../../../tabs' +import colorPalette from '../color-palette/color-palette' +import colorHueSlider from '../color-hue-slider/color-hue-slider' +import colorAlphaSlider from '../color-alpha-slider/color-alpha-slider' +import colorEdit from '../color-edit/color-edit' +import colorBasic from '../color-basic/color-basic' +import './color-picker-panel.scss' +import colorHistory from '../color-history/color-history' +export default defineComponent({ + name: 'ColorPanel', + components: { + colorPalette, + colorHueSlider, + colorAlphaSlider, + colorEdit, + colorBasic, + Tabs, + colorHistory + }, + props: colorPickerProps, + emits: [ + 'update:modelValue', + 'changeTextColor', + 'changeTiggerColor', + 'changePaletteColor', + 'changeTextModeType' + ], + setup(props: ColorPickerProps, { emit }) { + const injectData: provideColor = inject('provideData') + const paletteElement = ref(null) + const showAlpha = injectData.showAlpha + const tab = ref(injectData.tab) + function changeTextColor(isChange: boolean) { + emit('changeTextColor', isChange) + } + function changeTextModeColor(currentType: string) { + emit('changeTextModeType', currentType) + } + + // 画板值 + const paletteColorMap = ref(props.modelValue) + // hue slider 值 + watch( + () => paletteColorMap.value, + (newValue) => { + emit('update:modelValue', newValue) + emit('changePaletteColor', newValue) + nextTick(() => { + paletteElement.value && paletteElement.value.renderCanvas() + }) + } + ) + return () => { + return ( +
+ + + + + + + + + + {showAlpha ? ( + + ) : null} + + +
+ ) + } + } +}) diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts new file mode 100644 index 0000000000..168eb2ce29 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts @@ -0,0 +1,36 @@ +import { Ref } from 'vue' + +export type ColorModeType = 'hsl' | 'rgb' | 'hsv' | 'hsv' | 'hex' +export interface provideColor { + mode?: ColorModeType | boolean + showAlpha?: boolean + tab?: string +} +export interface ColorPickerColor { + alpha: number + hex: Hex + hexa: Hexa + hsla: HSLA + hsva: HSVA + hue: number + rgba: RGBA + hsv?: any + hsl?: any +} +export interface position { + left?: Ref + top?: Ref + right?: Ref + bottom?: Ref +} +// Types +export type ColorInt = number +export type HSV = { h: number; s: number; v: number } +export type HSVA = HSV & { a: number } +export type RGB = { r: number; g: number; b: number } +export type RGBA = RGB & { a: number } +export type HSL = { h: number; s: number; l: number } +export type HSLA = HSL & { a: number } +export type Hex = string +export type Hexa = string +export type Color = string | number | {} diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts new file mode 100644 index 0000000000..1cf5fbd494 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts @@ -0,0 +1,481 @@ +// Utilities +import { ref } from 'vue' +import { chunk, padEnd, has, keepDecimal } from './helpers' +import { + ColorPickerColor, + position, + ColorInt, + HSV, + HSVA, + RGB, + RGBA, + HSL, + HSLA, + Hex, + Hexa, + Color +} from './color-utils-types' +export function isCssColor(color?: string | false): boolean { + return !!color && !!color.match(/^(#|var\(--|(rgb|hsl)a?\()/) +} + +export function colorToInt(color: Color): ColorInt { + let rgb + + if (typeof color === 'number') { + rgb = color + } else if (typeof color === 'string') { + let c = color[0] === '#' ? color.substring(1) : color + if (c.length === 3) { + c = c + .split('') + .map((char) => char + char) + .join('') + } + if (c.length !== 6) { + // consoleWarn(`'${color}' is not a valid rgb color`) + } + rgb = parseInt(c, 16) + } else { + throw new TypeError( + `Colors can only be numbers or strings, recieved ${ + color == null ? color : color.constructor.name + } instead` + ) + } + + if (rgb < 0) { + // consoleWarn(`Colors cannot be negative: '${color}'`) + rgb = 0 + } else if (rgb > 0xffffff || isNaN(rgb)) { + // consoleWarn(`'${color}' is not a valid rgb color`) + rgb = 0xffffff + } + + return rgb +} +export function intToHex(color: ColorInt): string { + let hexColor: string = color.toString(16) + + if (hexColor.length < 6) hexColor = '0'.repeat(6 - hexColor.length) + hexColor + + return '#' + hexColor +} + +export function colorToHex(color: Color): string { + return intToHex(colorToInt(color)) +} + +/** + * Converts HSVA to RGBA. Based on formula from https://en.wikipedia.org/wiki/HSL_and_HSV + * + * @param color HSVA color as an array [0-360, 0-1, 0-1, 0-1] + */ +export function HSVAtoRGBA(hsva: HSVA): RGBA { + const { h, s, v, a } = hsva + const f = (n: number) => { + const k = (n + h / 60) % 6 + return v - v * s * Math.max(Math.min(k, 4 - k, 1), 0) + } + + const rgb = [f(5), f(3), f(1)].map((v) => Math.round(v * 255)) + + return { r: rgb[0], g: rgb[1], b: rgb[2], a } +} + +/** + * Converts RGBA to HSVA. Based on formula from https://en.wikipedia.org/wiki/HSL_and_HSV + * + * @param color RGBA color as an array [0-255, 0-255, 0-255, 0-1] + */ +export function RGBAtoHSVA(rgba: RGBA): HSVA { + if (!rgba) return { h: 0, s: 1, v: 1, a: 1 } + + const r = rgba.r / 255 + const g = rgba.g / 255 + const b = rgba.b / 255 + const max = Math.max(r, g, b) + const min = Math.min(r, g, b) + + let h = 0 + + if (max !== min) { + if (max === r) { + h = 60 * (0 + (g - b) / (max - min)) + } else if (max === g) { + h = 60 * (2 + (b - r) / (max - min)) + } else if (max === b) { + h = 60 * (4 + (r - g) / (max - min)) + } + } + + if (h < 0) h = h + 360 + + const s = max === 0 ? 0 : (max - min) / max + const hsv = [h, s, max] + + return { h: Math.round(hsv[0]), s: hsv[1], v: hsv[2], a: rgba.a } +} + +export function HSVAtoHSLA(hsva: HSVA): HSLA { + const { h, s, v, a } = hsva + + const l = v - (v * s) / 2 + + const sprime = l === 1 || l === 0 ? 0 : (v - l) / Math.min(l, 1 - l) + + return { h: Math.round(h), s: sprime, l, a } +} + +export function HSLAtoHSVA(hsl: HSLA): HSVA { + const { h, s, l, a } = hsl + + const v = l + s * Math.min(l, 1 - l) + + const sprime = v === 0 ? 0 : 2 - (2 * l) / v + + return { h: Math.round(h), s: sprime, v, a } +} + +export function RGBAtoCSS(rgba: RGBA): string { + return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})` +} + +export function RGBtoCSS(rgba: RGBA): string { + return RGBAtoCSS({ ...rgba, a: 1 }) +} + +export function RGBAtoHex(rgba: RGBA): Hex { + const toHex = (v: number) => { + const h = Math.round(v).toString(16) + return ('00'.substr(0, 2 - h.length) + h).toUpperCase() + } + + return `#${[toHex(rgba.r), toHex(rgba.g), toHex(rgba.b), toHex(Math.round(rgba.a * 255))].join( + '' + )}` +} + +export function HexToRGBA(hex: Hex): RGBA { + const rgba = chunk(hex.slice(1), 2).map((c: string) => parseInt(c, 16)) + + return { + r: rgba[0], + g: rgba[1], + b: rgba[2], + a: Math.round((rgba[3] / 255) * 100) / 100 + } +} + +export function HexToHSVA(hex: Hex): HSVA { + const rgb = HexToRGBA(hex) + return RGBAtoHSVA(rgb) +} + +export function HSVAtoHex(hsva: HSVA): Hex { + return RGBAtoHex(HSVAtoRGBA(hsva)) +} + +export function parseHex(hex: string): Hex { + if (hex.startsWith('#')) { + hex = hex.slice(1) + } + + hex = hex.replace(/([^0-9a-f])/gi, 'F') + + if (hex.length === 3 || hex.length === 4) { + hex = hex + .split('') + .map((x) => x + x) + .join('') + } + + if (hex.length === 6) { + hex = padEnd(hex, 8, 'F') + } else { + hex = padEnd(padEnd(hex, 6), 8, 'F') + } + + return `#${hex}`.toUpperCase().substr(0, 9) +} + +export function RGBtoInt(rgba: RGBA): ColorInt { + return (rgba.r << 16) + (rgba.g << 8) + rgba.b +} + +export function fromHSVA(hsva: HSVA): ColorPickerColor { + hsva = { ...hsva } + const hexa = HSVAtoHex(hsva) + const hsla = HSVAtoHSLA(hsva) + const rgba = HSVAtoRGBA(hsva) + return { + alpha: hsva.a, + hex: hexa.substr(0, 7), + hexa, + hsla, + hsva, + hue: hsva.h, + rgba + } +} +export function fromRGBA(rgba: RGBA): ColorPickerColor { + const hsva = RGBAtoHSVA(rgba) + const hexa = RGBAtoHex(rgba) + const hsla = HSVAtoHSLA(hsva) + const hsv = { h: hsva.h, s: hsva.s, v: hsva.v } + const hsl = { h: hsla.h, s: hsla.s, l: hsla.l } + return { + alpha: hsva.a, + hex: hexa.substr(0, 7), + hexa, + hsla, + hsva, + hsv, + hsl, + hue: hsva.h, + rgba + } +} +export function fromHexa(hexa: Hexa): ColorPickerColor { + const hsva = HexToHSVA(hexa) + const hsla = HSVAtoHSLA(hsva) + const rgba = HSVAtoRGBA(hsva) + return { + alpha: hsva.a, + hex: hexa.substr(0, 7), + hexa, + hsla, + hsva, + hue: hsva.h, + rgba + } +} +export function fromHSLA(hsla: HSLA): ColorPickerColor { + const hsva = HSLAtoHSVA(hsla) + const hexa = HSVAtoHex(hsva) + const rgba = HSVAtoRGBA(hsva) + return { + alpha: hsva.a, + hex: hexa.substr(0, 7), + hexa, + hsla, + hsva, + hue: hsva.h, + rgba + } +} +export function fromHex(hex: Hex): ColorPickerColor { + return fromHexa(parseHex(hex)) +} + +export function parseColor(color: Color, oldColor?: ColorPickerColor | null): ColorPickerColor { + if (!color) return fromRGBA({ r: 255, g: 0, b: 0, a: 1 }) + + if (typeof color === 'string') { + if (color.indexOf('#') !== -1) { + // const hex = color.replace('#', '').trim() + // return fromHexa(hex) + } else if (color.indexOf('hsl') !== -1) { + let alpha = null + const parts = color + .replace(/hsla|hsl|\(|\)/gm, '') + .split(/\s|,/g) + .filter((val) => val !== '') + .map((val) => parseFloat(val)) + if (parts.length === 4) { + alpha = parts[3] + } else if (parts.length === 3) { + alpha = 1 + } + return fromHSLA({ h: parts[0], s: parts[1], l: parts[2], a: alpha }) + } else if (color.indexOf('rgb') !== -1) { + let alpha = null + const parts = color + .replace(/rgba|rgb|\(|\)/gm, '') + .split(/\s|,/g) + .filter((val) => val !== '') + .map((val) => parseFloat(val)) + + if (parts.length === 4) { + alpha = parts[3] + } else if (parts.length === 3) { + alpha = 1 + } + return fromRGBA({ r: parts[0], g: parts[1], b: parts[2], a: alpha }) + } else if (color.indexOf('hsv') !== -1) { + let alpha = null + const parts = color + .replace(/hsva|hsv|\(|\)/gm, '') + .split(/\s|,/g) + .filter((val) => val !== '') + .map((val) => parseFloat(val)) + + if (parts.length === 4) { + alpha = parts[3] + } else if (parts.length === 3) { + alpha = 1 + } + return fromHSVA({ h: parts[0], s: parts[1], v: parts[2], a: alpha }) + } + if (color === 'transparent') return fromHexa('#00000000') + const hex = parseHex(color) + if (oldColor && hex === oldColor.hexa) { + return oldColor + } else { + return fromHexa(hex) + } + } + + if (typeof color === 'object') { + if (color.hasOwnProperty('alpha')) return color + + const a = color.hasOwnProperty('a') ? parseFloat(color.a) : 1 + + if (has(color, ['r', 'g', 'b'])) { + if (oldColor && color === oldColor.rgba) return oldColor + else return fromRGBA({ ...color, a }) + } else if (has(color, ['h', 's', 'l'])) { + if (oldColor && color === oldColor.hsla) return oldColor + else return fromHSLA({ ...color, a }) + } else if (has(color, ['h', 's', 'v'])) { + if (oldColor && color === oldColor.hsva) return oldColor + else return fromHSVA({ ...color, a }) + } + } + + return fromRGBA({ r: 255, g: 0, b: 0, a: 1 }) +} + +function stripAlpha(color: Color, stripAlpha: boolean) { + if (stripAlpha) { + const { a, ...rest } = color + + return rest + } + + return color +} + +export function extractColor(color: ColorPickerColor, input: Color, mode, showAlpha: boolean): any { + // 色相 + const hue = keepDecimal(color.hsla.h, 2) + // 饱和度 + const hslSaturation = keepDecimal(color.hsla.s, 2) + // 亮度 + const lightness = keepDecimal(color.hsla.l, 2) + // red + const red = keepDecimal(color.rgba.r) + // green + const green = keepDecimal(color.rgba.g) + // blue + const blue = keepDecimal(color.rgba.b) + // HSV饱和度 + const hsvSaturation = keepDecimal(color.hsva.s, 2) + // value + const value = keepDecimal(color.hsva.v, 2) + if (input == null) return color + function isShowAlpha(mode) { + return showAlpha ? mode + 'a' : mode + } + if (typeof input === 'string') { + if (mode === 'hex') { + return showAlpha ? color.hexa : color.hex + } else if (mode === 'hsl') { + return `${isShowAlpha(mode)}(${hue}, ${hslSaturation}, ${lightness}${ + showAlpha ? ', ' + color.alpha : '' + })` + } else if (mode === 'rgb') { + return `${isShowAlpha(mode)}(${red}, ${green}, ${blue}${showAlpha ? ', ' + color.alpha : ''})` + } else if (mode === 'hsv') { + return `${isShowAlpha(mode)}(${hue}, ${hsvSaturation}, ${value}${ + showAlpha ? ', ' + color.alpha : '' + })` + } + return input.length === 7 ? color.hex : color.hexa + } + + if (typeof input === 'object') { + const shouldStrip = typeof input.a === 'number' && input.a === 0 ? !!input.a : !input.a + if (has(input, ['r', 'g', 'b'])) return stripAlpha(color.rgba, shouldStrip) + else if (has(input, ['h', 's', 'l'])) return stripAlpha(color.hsla, shouldStrip) + else if (has(input, ['h', 's', 'v'])) return stripAlpha(color.hsva, shouldStrip) + } +} + +export function hasAlpha(color: Color): boolean { + if (!color) return false + + if (typeof color === 'string') { + return color.length > 7 + } + + if (typeof color === 'object') { + return has(color, ['a']) || has(color, ['alpha']) + } + + return false +} +export const elementResize = (parentElement: HTMLElement): position => { + const left = ref(0) + const top = ref(0) + window.addEventListener('resize', () => { + left.value = parentElement?.getBoundingClientRect().left + top.value = + parentElement?.getBoundingClientRect().top + parentElement?.getBoundingClientRect().height + }) + return { + left, + top + } +} + +export function RGBtoRGBA(rgba: RGBA): RGBA { + if (typeof rgba === 'string') { + rgba = (/rgba?\((.*?)\)/.exec(rgba) || ['', '0,0,0,1'])[1].split(',') + return { + r: Number(rgba[0]) || 0, + g: Number(rgba[1]) || 0, + b: Number(rgba[2]) || 0, + a: Number(rgba[3] ? rgba[3] : 1) // Avoid the case of 0 + } + } else { + return rgba + } +} +export function RGBtoHSV(rgb: RGB): HSV { + if (!rgb) return { h: 0, s: 1, v: 1 } + + const r = rgb.r / 255 + const g = rgb.g / 255 + const b = rgb.b / 255 + const max = Math.max(r, g, b) + const min = Math.min(r, g, b) + + let h = 0 + + if (max !== min) { + if (max === r) { + h = 60 * (0 + (g - b) / (max - min)) + } else if (max === g) { + h = 60 * (2 + (b - r) / (max - min)) + } else if (max === b) { + h = 60 * (4 + (r - g) / (max - min)) + } + } + + if (h < 0) h = h + 360 + + const s = max === 0 ? 0 : (max - min) / max + const hsv = [h, s, max] + + return { h: hsv[0], s: hsv[1].toFixed(2), v: hsv[2].toFixed(2) } +} +export function HSVtoHSL(hsv: HSV): HSL { + const { h, s, v } = hsv + + const l = Number((v - (v * s) / 2).toFixed(2)) + + const sprime = l === 1 || l === 0 ? 0 : (v - l) / Math.min(l, 1 - l) + + return { h, s: Number(sprime.toFixed(2)), l } +} diff --git a/packages/devui-vue/devui/color-picker/src/utils/color.ts b/packages/devui-vue/devui/color-picker/src/utils/color.ts new file mode 100644 index 0000000000..435f0913c4 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/utils/color.ts @@ -0,0 +1,47 @@ +export const color: string[] = [ + '#ffffff', + '#ffd7d5', + '#ffdaa9', + '#fffed5', + '#d4fa00', + '#73fcd6', + '#a5c8ff', + '#ffacd5', + '#ff7faa', + '#d6d6d6', + '#ffacaa', + '#ffb995', + '#fffb00', + '#73fa79', + '#00fcff', + '#78acfe', + '#d84fa9', + '#ff4f79', + '#b2b2b2', + '#d7aba9', + '#ff6827', + '#ffda51', + '#00d100', + '#00d5ff', + '#0080ff', + '#ac39ff', + '#ff2941', + '#888888', + '#7a4442', + '#ff4c00', + '#ffa900', + '#3da742', + '#3daad6', + '#0052ff', + '#7a4fd6', + '#d92142', + '#000000', + '#7b0c00', + '#ff4c41', + '#d6a841', + '#407600', + '#007aaa', + '#021eaa', + '#797baa', + '#ab1942' +] diff --git a/packages/devui-vue/devui/color-picker/src/utils/domDragger.ts b/packages/devui-vue/devui/color-picker/src/utils/domDragger.ts new file mode 100644 index 0000000000..f42aa3ba22 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/utils/domDragger.ts @@ -0,0 +1,363 @@ +export const isObject = (val: unknown): val is Record => + val !== null && typeof val === 'object' + +export const isString = (val: unknown): val is string => typeof val === 'string' + +export const enum NodeType { + ELEMENT_NODE = 1, + ATTRIBUTE_NODE = 2, + TEXT_NODE = 3, + CDATA_SECTION_NODE = 4, + ENTITY_REFERENCE_NODE = 5, + COMMENT_NODE = 6, + PROCESSING_INSTRUCTION_NODE = 7, + DOCUMENT_NODE = 9 +} + +export interface DragEventOptions { + drag?: (event: Event) => void + start?: (event: Event) => void + end?: (event: Event) => void +} + +export type ScrollElement = Element | Window + +export class DOMUtils { + static isWindow(val: unknown): val is Window { + return val === window + } + + /** + * 添加事件 + * + * + * @param element 如果为null将不会添加事件 + * @param event + * @param handler + * @param options + */ + static addEventListener( + element: HTMLElement | Document | Window | null, + event: string, + handler: EventListenerOrEventListenerObject, + options: boolean | AddEventListenerOptions = false + ): void { + if (element && event && handler) { + element.addEventListener(event, handler, options) + } + } + + /** + * 移除事件 + * + * @param element 如果为null将不会移除事件 + * @param event + * @param handler + * @param options + */ + static removeEventListener( + element: HTMLElement | Document | Window | null, + event: string, + handler: EventListenerOrEventListenerObject, + options: boolean | EventListenerOptions = false + ): void { + if (element && event && handler) { + element.removeEventListener(event, handler, options) + } + } + + /** + * 触发拖拽事件 + * + * @param element + * @param options + */ + static triggerDragEvent(element: HTMLElement, options: DragEventOptions): void { + let isDragging = false + + const moveFn = function (event: Event) { + options.drag?.(event) + } + + const upFn = (event: Event) => { + DOMUtils.removeEventListener(document, 'mousemove', moveFn) + DOMUtils.removeEventListener(document, 'mouseup', upFn) + document.onselectstart = null + document.ondragstart = null + + isDragging = false + + options.end?.(event) + } + + DOMUtils.addEventListener(element, 'mousedown', (event) => { + if (isDragging) return + document.onselectstart = () => false + document.ondragstart = () => false + DOMUtils.addEventListener(document, 'mousemove', moveFn) + DOMUtils.addEventListener(document, 'mouseup', upFn) + + isDragging = true + + options.start?.(event) + }) + + return + } + + static getBoundingClientRect(element: HTMLElement): DOMRect | null { + if (element && isObject(element) && element.nodeType === NodeType.ELEMENT_NODE) { + return element.getBoundingClientRect() + } + + return null + } + + /** + * 判断是否存在className样式 + * + * @param element + * @param className + */ + public static hasClass(element: HTMLElement, className: string): boolean { + if ( + element && + isObject(element) && + isString(className) && + element.nodeType === NodeType.ELEMENT_NODE + ) { + return element.classList.contains(className.trim()) + } + return false + } + + /** + * 添加样式 + * + * @param element + * @param className + */ + public static addClass(element: HTMLElement, className: string): void { + if ( + element && + isObject(element) && + isString(className) && + element.nodeType === NodeType.ELEMENT_NODE + ) { + className = className.trim() + if (!DOMUtils.hasClass(element, className)) { + const cl = element.className + element.className = cl ? cl + ' ' + className : className + } + } + } + + /** + * 移除样式 + * + * @param element + * @param className + */ + public static removeClass(element: HTMLElement, className: string): void { + if ( + element && + isObject(element) && + isString(className) && + element.nodeType === NodeType.ELEMENT_NODE && + typeof element.className === 'string' + ) { + className = className.trim() + const classes = element.className.trim().split(' ') + for (let i = classes.length - 1; i >= 0; i--) { + classes[i] = classes[i].trim() + if (!classes[i] || classes[i] === className) { + classes.splice(i, 1) + } + } + element.className = classes.join(' ') + } + } + + /** + * 切换样式 + * + * @param element + * @param className + * @param force + */ + public static toggleClass(element: HTMLElement, className: string, force?: boolean): void { + if ( + element && + isObject(element) && + isString(className) && + element.nodeType === NodeType.ELEMENT_NODE + ) { + element.classList.toggle(className, force) + } + } + + /** + * 替换样式 + * + * @param element + * @param oldClassName + * @param newClassName + */ + public static replaceClass( + element: HTMLElement, + oldClassName: string, + newClassName: string + ): void { + if ( + element && + isObject(element) && + isString(oldClassName) && + isString(newClassName) && + element.nodeType === NodeType.ELEMENT_NODE + ) { + oldClassName = oldClassName.trim() + newClassName = newClassName.trim() + DOMUtils.removeClass(element, oldClassName) + DOMUtils.addClass(element, newClassName) + } + } + + static getScrollTop(el: ScrollElement): number { + const top = 'scrollTop' in el ? el.scrollTop : el.pageYOffset + + // iOS scroll bounce cause minus scrollTop + return Math.max(top, 0) + } + + static setScrollTop(el: ScrollElement, value: number): void { + if ('scrollTop' in el) { + el.scrollTop = value + } else { + el.scrollTo(el.scrollX, value) + } + } + + static getRootScrollTop(): number { + return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0 + } + + static setRootScrollTop(value: number): void { + DOMUtils.setScrollTop(window, value) + DOMUtils.setScrollTop(document.body, value) + } + + static getElementTop(el: ScrollElement, scroller?: HTMLElement): number { + if (DOMUtils.isWindow(el)) { + return 0 + } + + const scrollTop = scroller ? DOMUtils.getScrollTop(scroller) : DOMUtils.getRootScrollTop() + return el.getBoundingClientRect().top + scrollTop + } + + static getVisibleHeight(el: ScrollElement): number { + if (DOMUtils.isWindow(el)) { + return el.innerHeight + } + return el.getBoundingClientRect().height + } + + static isHidden(el: HTMLElement) { + if (!el) { + return false + } + + const style = window.getComputedStyle(el) + const hidden = style.display === 'none' + + // 在以下情况下,offsetParent返回null: + // 1. 元素或其父元素的display属性设置为none. + // 2. 元素的position属性设置为fixed + const parentHidden = el.offsetParent === null && style.position !== 'fixed' + + return hidden || parentHidden + } + + /** + * 触发事件 + * + * @param el + * @param type + */ + static triggerEvent(el: Element, type: string) { + if ('createEvent' in document) { + // modern browsers, IE9+ + const e = document.createEvent('HTMLEvents') + e.initEvent(type, false, true) + el.dispatchEvent(e) + } + } + + /** + * 计算相对于中心点的旋转角度 + * @param element + * @param event + */ + static calcAngle(element: HTMLElement, event: MouseEvent) { + const rect = element.getBoundingClientRect() + + const originX = rect.left + rect.width / 2 + const originY = rect.top + rect.height / 2 + + //获得中心点和鼠标坐标连线,与y轴正半轴之间的夹角 + const x = Math.abs(originX - event.clientX) + const y = Math.abs(originY - event.clientY) + const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) + const cos = y / z + const rad = Math.acos(cos) //用反三角函数求弧度 + let angle = Math.floor(180 / (Math.PI / rad)) //将弧度转换成角度 + + if (event.clientX > originX && event.clientY > originY) { + //鼠标在第四象限 + angle = 180 - angle + } + + if (event.clientX == originX && event.clientY > originY) { + //鼠标在y轴负方向上 + angle = 180 + } + + if (event.clientX > originX && event.clientY == originY) { + //鼠标在x轴正方向上 + angle = 90 + } + + if (event.clientX < originX && event.clientY > originY) { + //鼠标在第三象限 + angle = 180 + angle + } + + if (event.clientX < originX && event.clientY == originY) { + //鼠标在x轴负方向 + angle = 270 + } + + if (event.clientX < originX && event.clientY < originY) { + //鼠标在第二象限 + angle = 360 - angle + } + + return angle + } + + /** + * querySelector + * + * @param selectors + * @param parentElement + */ + static querySelector( + selectors: string, + parentElement?: HTMLElement + ): E | null { + if (parentElement) { + return parentElement.querySelector(selectors) + } + return document.querySelector(selectors) + } +} diff --git a/packages/devui-vue/devui/color-picker/src/utils/helpers.ts b/packages/devui-vue/devui/color-picker/src/utils/helpers.ts new file mode 100644 index 0000000000..9052074fb2 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/utils/helpers.ts @@ -0,0 +1,48 @@ +export function padEnd(str: string, length: number, char = '0'): string { + return str + char.repeat(Math.max(0, length - str.length)) +} +export function chunk(str: string, size = 1): string[] { + const chunked: string[] = [] + let index = 0 + while (index < str.length) { + chunked.push(str.substr(index, size)) + index += size + } + return chunked +} +export function mergeObjects(source, target): any { + return Object.assign(source, target) +} +export function parseHex(value: string): number { + return parseInt(value, 16) +} +export const clamp = (value: number, min: number, max: number): number => { + return min < max + ? value < min + ? min + : value > max + ? max + : value + : value < max + ? max + : value > min + ? min + : value +} +export const upperCase = (word: string): string => { + return word.toLocaleUpperCase() +} +export const lowerCase = (word: string): string => { + return word.toLocaleLowerCase() +} +export function splitStr(str: string, chars: string): string { + return str.split(chars)[0] +} +// 保留小数工具 +export function keepDecimal(value: number, digits = 0): number { + const COUNT_VALUE = 10 ** digits + return Math.round(value * COUNT_VALUE) / COUNT_VALUE +} +export function has(obj: any, key: string[]): boolean { + return key.every((k) => obj.hasOwnProperty(k)) +} diff --git a/packages/devui-vue/docs/components/color-picker/index.md b/packages/devui-vue/docs/components/color-picker/index.md new file mode 100644 index 0000000000..2ab41d6ca5 --- /dev/null +++ b/packages/devui-vue/docs/components/color-picker/index.md @@ -0,0 +1,66 @@ +# ColorPicker 颜色选择器 + +### 何时使用 + + +### 基本用法 +:::demo + +```vue + + + + + +``` + +::: + +### d-color-picker + +d-color-picker 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ---- | ---- | ---- | ---- | --------- | ---------- | +| | | | | | | +| | | | | | | +| | | | | | | + +d-color-picker 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| ---- | ---- | ---- | --------- | +| | | | | +| | | | | +| | | | | + From 75ab168ac4cde6ab781ea7d40dc50959a22a0cee Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Fri, 17 Dec 2021 18:20:20 +0800 Subject: [PATCH 02/13] =?UTF-8?q?feat(color-picker):=20'compose=E5=8F=AF?= =?UTF-8?q?=E6=8B=86=E5=88=86=E5=87=BD=E6=95=B0'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/color-picker/src/color-picker.tsx | 28 +++++------------ .../color-hue-slider/color-hue-slider.tsx | 5 --- .../color-picker/src/utils/composeable.ts | 31 +++++++++++++++++++ 3 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 packages/devui-vue/devui/color-picker/src/utils/composeable.ts diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx index 5a25d497bf..9ea18245cf 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker.tsx +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -12,6 +12,7 @@ import { readonly, Transition } from 'vue' +import { useReactive, colorPickerResize, isExhibitionColorPicker } from './utils/composeable' import { colorPickerProps, ColorPickerProps } from './color-picker-types' import colorPanel from './components/color-picker-panel/color-picker-panel' import './color-picker.scss' @@ -43,9 +44,9 @@ export default defineComponent({ const mode = ref(unref(props.mode)) onMounted(() => { // resize 响应式 colorpicker - window.addEventListener('resize', colorPickerResize) + window.addEventListener('resize', resize) // 点击展示 colorpicker - window.addEventListener('click', isExhibitionColorPicker) + window.addEventListener('click', isExhibition) }) // ** computeds // colorpicker panel 组件位置 @@ -93,13 +94,7 @@ export default defineComponent({ mode.value = type formItemText.value = type } - function useReactive(source) { - const model = ref(source()) - watch(source, (newValue) => { - model.value = newValue - }) - return model - } + // 初始化的时候 确定 colopicker位置 watch( () => showColorPicker.value, @@ -133,18 +128,11 @@ export default defineComponent({ const value = extractColor(initialColor.value, props.modelValue, mode.value, props.showAlpha) emit('update:modelValue', value) } - function colorPickerResize() { - const rect = colorCubeRef.value?.getBoundingClientRect() - left.value = rect.left - top.value = rect.top + rect.height + function resize() { + return colorPickerResize(colorCubeRef, top, left) } - function isExhibitionColorPicker(e) { - if (colorCubeRef.value?.contains(e.target)) { - showColorPicker.value = true - } - if (!!pickerRef.value && !pickerRef.value?.contains(e.target)) { - showColorPicker.value = !showColorPicker.value - } + function isExhibition(event: Event) { + return isExhibitionColorPicker(event, colorCubeRef, pickerRef, showColorPicker) } return () => { return ( diff --git a/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx index ae5b7ef0da..7f1e5dcd3b 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-hue-slider/color-hue-slider.tsx @@ -21,7 +21,6 @@ export default defineComponent({ } return ((props.modelValue.hue % 360) * (rect.width - offsetWidth)) / 360 + offsetWidth / 2 } - return 0 } @@ -44,15 +43,11 @@ export default defineComponent({ event.stopPropagation() if (barElement.value && cursorElement.value) { const rect = barElement.value.getBoundingClientRect() - const offsetWidth = cursorElement.value.offsetWidth - let left = event.clientX - rect.left left = Math.min(left, rect.width - offsetWidth / 2) left = Math.max(offsetWidth / 2, left) - const hue = Math.round(((left - offsetWidth / 2) / (rect.width - offsetWidth)) * 360) - ctx.emit( 'update:modelValue', fromHSVA({ diff --git a/packages/devui-vue/devui/color-picker/src/utils/composeable.ts b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts new file mode 100644 index 0000000000..f8379d5ae3 --- /dev/null +++ b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts @@ -0,0 +1,31 @@ +import { Ref, ref, watch } from 'vue' +import { provideColor } from './color-utils-types' +export function colorPickerResize( + colorCubeRef: Ref, + top: Ref, + left: Ref +): void { + const rect = colorCubeRef.value?.getBoundingClientRect() + left.value = rect.left + top.value = rect.top + rect.height +} +export function isExhibitionColorPicker( + event: PointerEvent, + colorCubeRef: Ref, + pickerRef: Ref, + showColorPicker: Ref +): void { + if (colorCubeRef.value?.contains(event.target)) { + showColorPicker.value = true + } + if (!!pickerRef.value && !pickerRef.value?.contains(event.target)) { + showColorPicker.value = !showColorPicker.value + } +} +export function useReactive(source): Ref { + const model = ref(source()) + watch(source, (newValue) => { + model.value = newValue + }) + return model +} From b0bc07ccb048070353cd9da0b8ad75fd6b15f787 Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Fri, 17 Dec 2021 19:25:42 +0800 Subject: [PATCH 03/13] =?UTF-8?q?Bug(color-picker):=20'=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E8=89=B2=E5=9D=97=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E9=A2=9C=E8=89=B2=E5=A4=B1=E6=95=88'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/color-picker/src/color-picker.tsx | 14 ++++++++------ .../color-picker/src/utils/color-utils-types.ts | 3 +++ .../devui/color-picker/src/utils/composeable.ts | 11 ++++++++++- .../docs/components/color-picker/index.md | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx index 9ea18245cf..a46b981b67 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker.tsx +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -12,7 +12,12 @@ import { readonly, Transition } from 'vue' -import { useReactive, colorPickerResize, isExhibitionColorPicker } from './utils/composeable' +import { + useReactive, + colorPickerResize, + isExhibitionColorPicker, + changeColorValue +} from './utils/composeable' import { colorPickerProps, ColorPickerProps } from './color-picker-types' import colorPanel from './components/color-picker-panel/color-picker-panel' import './color-picker.scss' @@ -74,11 +79,8 @@ export default defineComponent({ }) // 动态 根据当前 透明度修改文本颜色 tips:根据不同 面板颜色 目前 不够优雅 const textColor = computed(() => { - if (initialColor.value.alpha > 0.5) { - return isChangeTextColor.value ? { color: '#fff' } : { color: '#000' } - } else { - return { color: '#000' } - } + // 数字代表 hsv 中的value 值 纵轴 动态切换 文本颜色 + return changeColorValue(initialColor.value, 0.5) }) // ** emits // 动态 交互面板 文本展示颜色 tips:根据不同 面板颜色 目前 不够优雅 diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts index 168eb2ce29..905e36a528 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts @@ -6,6 +6,9 @@ export interface provideColor { showAlpha?: boolean tab?: string } +export interface CssColorObject { + color?: Hex +} export interface ColorPickerColor { alpha: number hex: Hex diff --git a/packages/devui-vue/devui/color-picker/src/utils/composeable.ts b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts index f8379d5ae3..d80f112c9f 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/composeable.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts @@ -1,5 +1,5 @@ import { Ref, ref, watch } from 'vue' -import { provideColor } from './color-utils-types' +import { ColorPickerColor, CssColorObject, provideColor } from './color-utils-types' export function colorPickerResize( colorCubeRef: Ref, top: Ref, @@ -29,3 +29,12 @@ export function useReactive(source): Ref { }) return model } + +// 根据 value 饱和度 判断文本颜色 +export function changeColorValue(value: ColorPickerColor, maxValue: number): CssColorObject { + if (value.alpha > maxValue) { + return value.hsva.v < maxValue ? { color: '#fff' } : { color: '#000' } + } else { + return { color: '#000' } + } +} diff --git a/packages/devui-vue/docs/components/color-picker/index.md b/packages/devui-vue/docs/components/color-picker/index.md index 2ab41d6ca5..4376a6ba1a 100644 --- a/packages/devui-vue/docs/components/color-picker/index.md +++ b/packages/devui-vue/docs/components/color-picker/index.md @@ -19,7 +19,7 @@ import { defineComponent, watch, ref } from 'vue' export default defineComponent({ setup() { - const msg = ref('#935DB280') + const msg = ref('') const show = ref(true) const isShowAlpha = () => { show.value = !show.value From ea7c70e6733a39827b54da6bc01245c5df502885 Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Fri, 17 Dec 2021 19:40:35 +0800 Subject: [PATCH 04/13] =?UTF-8?q?fix(color-picker):=20'=E7=A7=BB=E9=99=A4d?= =?UTF-8?q?efaultTab=E4=BF=AE=E6=94=B9tab=E5=B1=9E=E6=80=A7'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/color-picker/src/color-picker-types.ts | 4 ---- .../devui-vue/devui/color-picker/src/color-picker.tsx | 3 +-- .../components/color-picker-panel/color-picker-panel.tsx | 8 ++++---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/devui-vue/devui/color-picker/src/color-picker-types.ts b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts index 41b97a6166..8161dfec0f 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker-types.ts +++ b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts @@ -16,10 +16,6 @@ export const colorPickerProps = { }, swatches: { type: Array as PropType - }, - defaultTab: { - type: String, - default: 'palette' } } as const diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx index a46b981b67..37e4cfba70 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker.tsx +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -33,8 +33,7 @@ export default defineComponent({ const DEFAUTL_MODE = 'rgb' const provideData = reactive({ showAlpha: useReactive(() => props.showAlpha), - swatches: useReactive(() => props.swatches), - tab: useReactive(() => props.defaultTab) + swatches: useReactive(() => props.swatches) }) provide('provideData', readonly(provideData)) const initialColor = ref(fromRGBA({ r: 255, g: 0, b: 0, a: 1 })) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx index 15c9e2221b..a28583d777 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx @@ -32,7 +32,7 @@ export default defineComponent({ const injectData: provideColor = inject('provideData') const paletteElement = ref(null) const showAlpha = injectData.showAlpha - const tab = ref(injectData.tab) + const tab = ref('basic') function changeTextColor(isChange: boolean) { emit('changeTextColor', isChange) } @@ -57,6 +57,9 @@ export default defineComponent({ return (
+ + + - - - {showAlpha ? ( From 197d4328e17eb8eacb3064c9029ee7cade454be6 Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Fri, 17 Dec 2021 19:47:00 +0800 Subject: [PATCH 05/13] =?UTF-8?q?fix(color-picker):=20'dotsize=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=A4=B1=E6=95=88=E9=97=AE=E9=A2=98'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/color-picker/src/color-picker-types.ts | 2 +- .../devui-vue/devui/color-picker/src/color-picker.tsx | 3 ++- .../src/components/color-palette/color-palette.tsx | 10 ++++++---- .../color-palette/color-picker-palette-types.ts | 4 ---- .../devui/color-picker/src/utils/color-utils-types.ts | 1 + 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/devui-vue/devui/color-picker/src/color-picker-types.ts b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts index 8161dfec0f..42982276b5 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker-types.ts +++ b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts @@ -12,7 +12,7 @@ export const colorPickerProps = { }, dotSize: { type: Number, - default: 12 + default: 15 }, swatches: { type: Array as PropType diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx index 37e4cfba70..82d3bdb78e 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker.tsx +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -33,7 +33,8 @@ export default defineComponent({ const DEFAUTL_MODE = 'rgb' const provideData = reactive({ showAlpha: useReactive(() => props.showAlpha), - swatches: useReactive(() => props.swatches) + swatches: useReactive(() => props.swatches), + dotSize: useReactive(() => props.dotSize) }) provide('provideData', readonly(provideData)) const initialColor = ref(fromRGBA({ r: 255, g: 0, b: 0, a: 1 })) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx index c6ff05a862..5335a09ad6 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx @@ -1,8 +1,9 @@ -import { defineComponent, ref, onMounted, computed, getCurrentInstance, watch } from 'vue' +import { defineComponent, ref, onMounted, computed, getCurrentInstance, watch, inject } from 'vue' import { DOMUtils } from '../../utils/domDragger' import { fromHSVA } from '../../utils/color-utils' import { clamp } from '../../utils/helpers' import { colorPickerPaletteProps } from './color-picker-palette-types' +import { provideColor } from '../../utils/color-utils-types' import './color-palette.scss' export default defineComponent({ name: 'ColorPallete', @@ -10,6 +11,7 @@ export default defineComponent({ emits: ['update:modelValue', 'changeTextColor'], setup(props: colorPickerPaletteProps, ctx) { const DEFAULT_TRANSITION = { transition: 'all 0.3s ease' } + const dotSizeInject: provideColor = inject('provideData') const clickTransfrom = ref(DEFAULT_TRANSITION) const paletteElement = ref() const canvasElement = ref() @@ -20,9 +22,9 @@ export default defineComponent({ const cursorLeft = ref(0) const getDotStyle = computed(() => { return { - width: `${props.dotSize}px`, - height: `${props.dotSize}px`, - transform: `translate(-${props.dotSize / 2}px, -${props.dotSize / 2}px)` + width: `${dotSizeInject.dotSize}px`, + height: `${dotSizeInject.dotSize}px`, + transform: `translate(-${dotSizeInject.dotSize / 2}px, -${dotSizeInject.dotSize / 2}px)` } }) const getCursorStyle = computed(() => { diff --git a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts index ef1cb2b2ac..577f8a4328 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts +++ b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-picker-palette-types.ts @@ -10,10 +10,6 @@ export const colorPickerPaletteProps = { height: { type: Number, default: 200 - }, - dotSize: { - type: Number, - default: 15 } } as const diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts index 905e36a528..8f12a71ef8 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts @@ -5,6 +5,7 @@ export interface provideColor { mode?: ColorModeType | boolean showAlpha?: boolean tab?: string + dotSize?: number } export interface CssColorObject { color?: Hex From 4711e79800da8e18233853b826c436d08744bfc9 Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Fri, 17 Dec 2021 20:58:26 +0800 Subject: [PATCH 06/13] =?UTF-8?q?fix(color-picker):=20'=E4=BF=AE=E6=94=B9t?= =?UTF-8?q?s=E7=B1=BB=E5=9E=8B=20=E4=BF=AE=E6=94=B9=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=A2=9C=E8=89=B2'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui-vue/devui/color-picker/src/color-picker.tsx | 8 +++++--- .../src/components/color-basic/color-basic.tsx | 3 ++- .../color-picker/src/components/color-edit/color-edit.tsx | 4 ++-- .../src/components/color-history/color-history.tsx | 4 ++-- .../src/components/color-palette/color-palette.tsx | 5 +++-- .../components/color-picker-panel/color-picker-panel.tsx | 4 ++-- .../devui/color-picker/src/utils/color-utils-types.ts | 3 ++- .../devui-vue/devui/color-picker/src/utils/color-utils.ts | 2 +- .../devui-vue/devui/color-picker/src/utils/composeable.ts | 4 ++-- 9 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx index 82d3bdb78e..89276265ce 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker.tsx +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -31,13 +31,13 @@ export default defineComponent({ emits: ['update:modelValue'], setup(props: ColorPickerProps, { emit }) { const DEFAUTL_MODE = 'rgb' - const provideData = reactive({ + const provideData = { showAlpha: useReactive(() => props.showAlpha), swatches: useReactive(() => props.swatches), dotSize: useReactive(() => props.dotSize) - }) + } provide('provideData', readonly(provideData)) - const initialColor = ref(fromRGBA({ r: 255, g: 0, b: 0, a: 1 })) + const initialColor = ref(null) const colorCubeRef = ref() const pickerRef = ref() const containerRef = ref() @@ -66,6 +66,8 @@ export default defineComponent({ // 交互触发item 颜色 面板 const tiggerColor = computed(() => { const trigger = initialColor.value.rgba + console.log(trigger) + if (!props.showAlpha) { trigger.a = 1 } diff --git a/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx index 3023d3ab20..3117b00cb1 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-basic/color-basic.tsx @@ -1,5 +1,6 @@ import { defineComponent, ref, inject } from 'vue' import { colorPickerBasicColorProps } from './color-basic-types' +import { provideColorOptions } from '../../utils/color-utils-types' import { fromHex } from '../../utils/color-utils' import './color-basic.scss' import { color } from '../../utils/color' @@ -7,7 +8,7 @@ export default defineComponent({ name: 'ColorBasic', props: colorPickerBasicColorProps, setup(props) { - const swatchesInject = inject('provideData') + const swatchesInject: provideColorOptions = inject('provideData') const currentColor = ref(props.color) function changeBasicColor(hex: string) { diff --git a/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx index 9ef92dd92c..5ac815a9e3 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx @@ -1,6 +1,6 @@ import { defineComponent, computed, ref, inject } from 'vue' import { ColorPickerEditProps, colorPickerEditProps } from './color-picker-edit-types' -import { provideColor, ColorPickerColor } from '../../utils/color-utils-types' +import { provideColorOptions, ColorPickerColor } from '../../utils/color-utils-types' import './color-edit.scss' import { fromHex, fromHexa, fromHSLA, fromHSVA, fromRGBA } from '../../utils/color-utils' import Schema, { Rules } from 'async-validator' @@ -58,7 +58,7 @@ export default defineComponent({ emits: ['changeTextModeColor', 'update:modelValue'], setup(props: ColorPickerEditProps, { emit }) { // 设置showalpha 为false 会报错 2021.12.14 - const isShowAlpha: provideColor = inject('provideData') + const isShowAlpha: provideColorOptions = inject('provideData') // 模式值 const modelValue = computed(() => `${props.mode}${isShowAlpha.showAlpha ? 'a' : ''}`) // 颜色值 diff --git a/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx b/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx index 7cbb4ed870..2ce842c1a2 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-history/color-history.tsx @@ -3,7 +3,7 @@ import { ColorPickerHistoryProps, colorPickerHistoryProps } from './color-picker import { Icon } from '../../../../icon' import './color-history.scss' import { fromHexa } from '../../utils/color-utils' -import { provideColor, ColorPickerColor } from '../../utils/color-utils-types' +import { provideColorOptions, ColorPickerColor } from '../../utils/color-utils-types' import { debounce } from 'lodash-es' const STORAGE_KEY = 'STORAGE_COLOR_PICKER_HISTORY_KEY' @@ -47,7 +47,7 @@ export default defineComponent({ emits: ['update:color'], setup(props: ColorPickerHistoryProps) { // 获取 是否showalpha - const alphaInject: provideColor = inject('provideData') + const alphaInject: provideColorOptions = inject('provideData') // 创建历史存储 const history = useStore([], { storage: true }) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx index 5335a09ad6..1bd6e577eb 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-palette/color-palette.tsx @@ -3,7 +3,7 @@ import { DOMUtils } from '../../utils/domDragger' import { fromHSVA } from '../../utils/color-utils' import { clamp } from '../../utils/helpers' import { colorPickerPaletteProps } from './color-picker-palette-types' -import { provideColor } from '../../utils/color-utils-types' +import { provideColorOptions } from '../../utils/color-utils-types' import './color-palette.scss' export default defineComponent({ name: 'ColorPallete', @@ -11,7 +11,8 @@ export default defineComponent({ emits: ['update:modelValue', 'changeTextColor'], setup(props: colorPickerPaletteProps, ctx) { const DEFAULT_TRANSITION = { transition: 'all 0.3s ease' } - const dotSizeInject: provideColor = inject('provideData') + const dotSizeInject: provideColorOptions = inject('provideData') + const clickTransfrom = ref(DEFAULT_TRANSITION) const paletteElement = ref() const canvasElement = ref() diff --git a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx index a28583d777..2b204a862b 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx @@ -1,6 +1,6 @@ import { defineComponent, ref, watch, nextTick, inject } from 'vue' import { colorPickerProps, ColorPickerProps } from './color-picker-panel-types' -import { provideColor } from '../../utils/color-utils-types' +import { provideColorOptions } from '../../utils/color-utils-types' import { Tabs } from '../../../../tabs' import colorPalette from '../color-palette/color-palette' import colorHueSlider from '../color-hue-slider/color-hue-slider' @@ -29,7 +29,7 @@ export default defineComponent({ 'changeTextModeType' ], setup(props: ColorPickerProps, { emit }) { - const injectData: provideColor = inject('provideData') + const injectData: provideColorOptions = inject('provideData') const paletteElement = ref(null) const showAlpha = injectData.showAlpha const tab = ref('basic') diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts index 8f12a71ef8..82089fa702 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts @@ -1,11 +1,12 @@ import { Ref } from 'vue' export type ColorModeType = 'hsl' | 'rgb' | 'hsv' | 'hsv' | 'hex' -export interface provideColor { +export interface provideColorOptions { mode?: ColorModeType | boolean showAlpha?: boolean tab?: string dotSize?: number + swatches?: string[] } export interface CssColorObject { color?: Hex diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts index 1cf5fbd494..662d1f88c2 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts @@ -269,7 +269,7 @@ export function fromHex(hex: Hex): ColorPickerColor { } export function parseColor(color: Color, oldColor?: ColorPickerColor | null): ColorPickerColor { - if (!color) return fromRGBA({ r: 255, g: 0, b: 0, a: 1 }) + if (!color) return fromRGBA({ r: 0, g: 0, b: 0, a: 1 }) if (typeof color === 'string') { if (color.indexOf('#') !== -1) { diff --git a/packages/devui-vue/devui/color-picker/src/utils/composeable.ts b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts index d80f112c9f..9f270016c0 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/composeable.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts @@ -1,5 +1,5 @@ import { Ref, ref, watch } from 'vue' -import { ColorPickerColor, CssColorObject, provideColor } from './color-utils-types' +import { ColorPickerColor, CssColorObject, provideColorOptions } from './color-utils-types' export function colorPickerResize( colorCubeRef: Ref, top: Ref, @@ -22,7 +22,7 @@ export function isExhibitionColorPicker( showColorPicker.value = !showColorPicker.value } } -export function useReactive(source): Ref { +export function useReactive(source): Ref { const model = ref(source()) watch(source, (newValue) => { model.value = newValue From 673ceb23c6f034db237300ff86ef8b6548370d3c Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Sat, 18 Dec 2021 09:23:53 +0800 Subject: [PATCH 07/13] =?UTF-8?q?feat(color-picker):=20'=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E9=A2=9C=E8=89=B2=E5=B1=95=E7=A4=BA=E8=A7=84?= =?UTF-8?q?=E5=88=99=20=E4=BC=98=E5=8C=96ts'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/color-picker/src/color-picker.tsx | 14 +-- .../src/components/color-edit/color-edit.tsx | 12 ++- .../src/utils/color-utils-types.ts | 2 +- .../color-picker/src/utils/composeable.ts | 11 ++- .../docs/components/color-picker/index.md | 86 +++++++++++++++---- 5 files changed, 95 insertions(+), 30 deletions(-) diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx index 89276265ce..01695c399d 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker.tsx +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -8,7 +8,6 @@ import { provide, Teleport, unref, - reactive, readonly, Transition } from 'vue' @@ -21,7 +20,8 @@ import { import { colorPickerProps, ColorPickerProps } from './color-picker-types' import colorPanel from './components/color-picker-panel/color-picker-panel' import './color-picker.scss' -import { fromRGBA, parseColor, extractColor, RGBAtoCSS } from './utils/color-utils' +import { parseColor, extractColor, RGBAtoCSS } from './utils/color-utils' +import { ColorPickerColor } from './utils/color-utils-types' export default defineComponent({ name: 'DColorPicker', components: { @@ -31,6 +31,8 @@ export default defineComponent({ emits: ['update:modelValue'], setup(props: ColorPickerProps, { emit }) { const DEFAUTL_MODE = 'rgb' + console.log(props.mode) + const provideData = { showAlpha: useReactive(() => props.showAlpha), swatches: useReactive(() => props.swatches), @@ -66,8 +68,6 @@ export default defineComponent({ // 交互触发item 颜色 面板 const tiggerColor = computed(() => { const trigger = initialColor.value.rgba - console.log(trigger) - if (!props.showAlpha) { trigger.a = 1 } @@ -86,15 +86,15 @@ export default defineComponent({ }) // ** emits // 动态 交互面板 文本展示颜色 tips:根据不同 面板颜色 目前 不够优雅 - function changeTextColor(value: boolean) { + function changeTextColor(value: boolean): void { isChangeTextColor.value = value } // 通过修改画板 颜色 修改 v-model 颜色 - function changePaletteColor(colorMap) { + function changePaletteColor(colorMap: ColorPickerColor): void { updateUserColor(colorMap) } // 通过用户点击触发修改 交互面板 文本类型 - function changeTextModeType(type: string) { + function changeTextModeType(type: string): void { mode.value = type formItemText.value = type } diff --git a/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx index 5ac815a9e3..baa4b92bc5 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-edit/color-edit.tsx @@ -4,6 +4,8 @@ import { provideColorOptions, ColorPickerColor } from '../../utils/color-utils-t import './color-edit.scss' import { fromHex, fromHexa, fromHSLA, fromHSVA, fromRGBA } from '../../utils/color-utils' import Schema, { Rules } from 'async-validator' +// 默认 mode +const DEFAUTL_MODE = 'rgb' // MODE支持模式 const MODE_SUPPORT = ['rgb', 'hex', 'hsl', 'hsv'] as const @@ -60,11 +62,15 @@ export default defineComponent({ // 设置showalpha 为false 会报错 2021.12.14 const isShowAlpha: provideColorOptions = inject('provideData') // 模式值 - const modelValue = computed(() => `${props.mode}${isShowAlpha.showAlpha ? 'a' : ''}`) + const modelValue = computed( + () => `${props.mode ?? DEFAUTL_MODE}${isShowAlpha.showAlpha ? 'a' : ''}` + ) // 颜色值 const colorValue = ref(props.color) // 模式值类型 - const modelValueType = computed(() => (props.mode === 'hex' ? 'string' : 'number')) + const modelValueType = computed(() => + (props.mode ?? DEFAUTL_MODE) === 'hex' ? 'string' : 'number' + ) /** * 获取有效颜色值 @@ -88,7 +94,7 @@ export default defineComponent({ */ function onChangeModel() { // 安装MODE_SUPPORT列表进行更换 - const currentIndex = MODE_SUPPORT.findIndex((x) => x === props.mode) + const currentIndex = MODE_SUPPORT.findIndex((x) => x === props.mode ?? DEFAUTL_MODE) const mode = MODE_SUPPORT[(currentIndex + 1) % MODE_SUPPORT.length] emit('changeTextModeColor', mode) } diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts index 82089fa702..5c4c3e79d7 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts @@ -2,7 +2,7 @@ import { Ref } from 'vue' export type ColorModeType = 'hsl' | 'rgb' | 'hsv' | 'hsv' | 'hex' export interface provideColorOptions { - mode?: ColorModeType | boolean + mode?: ColorModeType showAlpha?: boolean tab?: string dotSize?: number diff --git a/packages/devui-vue/devui/color-picker/src/utils/composeable.ts b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts index 9f270016c0..d599cd0669 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/composeable.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/composeable.ts @@ -1,5 +1,5 @@ import { Ref, ref, watch } from 'vue' -import { ColorPickerColor, CssColorObject, provideColorOptions } from './color-utils-types' +import { ColorPickerColor, CssColorObject } from './color-utils-types' export function colorPickerResize( colorCubeRef: Ref, top: Ref, @@ -22,8 +22,9 @@ export function isExhibitionColorPicker( showColorPicker.value = !showColorPicker.value } } -export function useReactive(source): Ref { - const model = ref(source()) +export function useReactive(source: () => T): Ref { + const model = ref() + model.value = source() watch(source, (newValue) => { model.value = newValue }) @@ -33,7 +34,9 @@ export function useReactive(source): Ref { // 根据 value 饱和度 判断文本颜色 export function changeColorValue(value: ColorPickerColor, maxValue: number): CssColorObject { if (value.alpha > maxValue) { - return value.hsva.v < maxValue ? { color: '#fff' } : { color: '#000' } + return value.hsva.v > maxValue && value.hsva.s < maxValue + ? { color: '#000' } + : { color: '#fff' } } else { return { color: '#000' } } diff --git a/packages/devui-vue/docs/components/color-picker/index.md b/packages/devui-vue/docs/components/color-picker/index.md index 4376a6ba1a..4c0cf5586e 100644 --- a/packages/devui-vue/docs/components/color-picker/index.md +++ b/packages/devui-vue/docs/components/color-picker/index.md @@ -1,17 +1,27 @@ # ColorPicker 颜色选择器 ### 何时使用 - +允许用户使用各种交互方法来选择颜色 ### 基本用法 :::demo ```vue +``` + +::: + +### 颜色透明度 +允许用户动态调节展示alpha模式 +:::demo + +```vue + +``` - +::: + +### 颜色模式 +设置mode展示响应颜色模式 +:::demo + +```vue + + + +``` + +::: + +### 历史颜色 +自定义是否展示历史颜色 +:::demo + +```vue + + + ``` ::: + + ### d-color-picker d-color-picker 参数 From cbeeab31660cdcdfc560145df411b55fb0f22016 Mon Sep 17 00:00:00 2001 From: erkelost <1256029807@qq.com> Date: Sat, 18 Dec 2021 11:38:56 +0800 Subject: [PATCH 08/13] =?UTF-8?q?fix(color-picker):=20'=E7=A7=BB=E9=99=A4s?= =?UTF-8?q?ubstr=20API=20=E6=96=B0=E5=A2=9E=E5=B1=95=E7=A4=BA=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E9=A2=9C=E8=89=B2api'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../color-picker/src/color-picker-types.ts | 4 ++ .../devui/color-picker/src/color-picker.tsx | 3 +- .../color-picker-panel/color-picker-panel.tsx | 2 +- .../src/utils/color-utils-types.ts | 1 + .../color-picker/src/utils/color-utils.ts | 12 ++-- .../docs/components/color-picker/index.md | 66 ++++++++++++++----- 6 files changed, 65 insertions(+), 23 deletions(-) diff --git a/packages/devui-vue/devui/color-picker/src/color-picker-types.ts b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts index 42982276b5..7d6c4164bf 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker-types.ts +++ b/packages/devui-vue/devui/color-picker/src/color-picker-types.ts @@ -16,6 +16,10 @@ export const colorPickerProps = { }, swatches: { type: Array as PropType + }, + showHistory: { + type: Boolean, + default: true } } as const diff --git a/packages/devui-vue/devui/color-picker/src/color-picker.tsx b/packages/devui-vue/devui/color-picker/src/color-picker.tsx index 01695c399d..1f5b6ad86c 100644 --- a/packages/devui-vue/devui/color-picker/src/color-picker.tsx +++ b/packages/devui-vue/devui/color-picker/src/color-picker.tsx @@ -36,7 +36,8 @@ export default defineComponent({ const provideData = { showAlpha: useReactive(() => props.showAlpha), swatches: useReactive(() => props.swatches), - dotSize: useReactive(() => props.dotSize) + dotSize: useReactive(() => props.dotSize), + showHistory: useReactive(() => props.showHistory) } provide('provideData', readonly(provideData)) const initialColor = ref(null) diff --git a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx index 2b204a862b..a47afcc54e 100644 --- a/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx +++ b/packages/devui-vue/devui/color-picker/src/components/color-picker-panel/color-picker-panel.tsx @@ -78,7 +78,7 @@ export default defineComponent({ color={paletteColorMap} onChangeTextModeColor={changeTextModeColor} > - + {injectData.showHistory ? : null}
) } diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts index 5c4c3e79d7..229faa0eec 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils-types.ts @@ -7,6 +7,7 @@ export interface provideColorOptions { tab?: string dotSize?: number swatches?: string[] + showHistory?: boolean } export interface CssColorObject { color?: Hex diff --git a/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts b/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts index 662d1f88c2..eec542f0e1 100644 --- a/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts +++ b/packages/devui-vue/devui/color-picker/src/utils/color-utils.ts @@ -148,7 +148,7 @@ export function RGBtoCSS(rgba: RGBA): string { export function RGBAtoHex(rgba: RGBA): Hex { const toHex = (v: number) => { const h = Math.round(v).toString(16) - return ('00'.substr(0, 2 - h.length) + h).toUpperCase() + return ('00'.substring(0, 2 - h.length) + h).toUpperCase() } return `#${[toHex(rgba.r), toHex(rgba.g), toHex(rgba.b), toHex(Math.round(rgba.a * 255))].join( @@ -196,7 +196,7 @@ export function parseHex(hex: string): Hex { hex = padEnd(padEnd(hex, 6), 8, 'F') } - return `#${hex}`.toUpperCase().substr(0, 9) + return `#${hex}`.toUpperCase().substring(0, 9) } export function RGBtoInt(rgba: RGBA): ColorInt { @@ -210,7 +210,7 @@ export function fromHSVA(hsva: HSVA): ColorPickerColor { const rgba = HSVAtoRGBA(hsva) return { alpha: hsva.a, - hex: hexa.substr(0, 7), + hex: hexa.substring(0, 7), hexa, hsla, hsva, @@ -226,7 +226,7 @@ export function fromRGBA(rgba: RGBA): ColorPickerColor { const hsl = { h: hsla.h, s: hsla.s, l: hsla.l } return { alpha: hsva.a, - hex: hexa.substr(0, 7), + hex: hexa.substring(0, 7), hexa, hsla, hsva, @@ -242,7 +242,7 @@ export function fromHexa(hexa: Hexa): ColorPickerColor { const rgba = HSVAtoRGBA(hsva) return { alpha: hsva.a, - hex: hexa.substr(0, 7), + hex: hexa.substring(0, 7), hexa, hsla, hsva, @@ -256,7 +256,7 @@ export function fromHSLA(hsla: HSLA): ColorPickerColor { const rgba = HSVAtoRGBA(hsva) return { alpha: hsva.a, - hex: hexa.substr(0, 7), + hex: hexa.substring(0, 7), hexa, hsla, hsva, diff --git a/packages/devui-vue/docs/components/color-picker/index.md b/packages/devui-vue/docs/components/color-picker/index.md index 4c0cf5586e..8379cd804d 100644 --- a/packages/devui-vue/docs/components/color-picker/index.md +++ b/packages/devui-vue/docs/components/color-picker/index.md @@ -1,10 +1,12 @@ # ColorPicker 颜色选择器 ### 何时使用 + 允许用户使用各种交互方法来选择颜色 ### 基本用法 -:::demo + +:::demo ```vue