Skip to content

Commit 9d7db7a

Browse files
authored
feat(colorPicker): new add colorPicker Component Full version available (#26)
* feat(colorPicker): 'new add colorPicker Component' * feat(color-picker): 'compose可拆分函数' * Bug(color-picker): '修复基础色块导致的文本颜色失效' * fix(color-picker): '移除defaultTab修改tab属性' * fix(color-picker): 'dotsize属性失效问题' * fix(color-picker): '修改ts类型 修改用户默认颜色' * feat(color-picker): '修改文本颜色展示规则 优化ts' * fix(color-picker): '移除substr API 新增展示历史颜色api' * feat(color-picker): '新增color-picker文档' * bug(color-picker): '修复scroll滚动导致colorpicker位置错误问题' * fix(color-picker): '优化动态修改alpha代码 优化ts 文档' * fix(color-picker): '修复暗黑模式下teleport 背景颜色' * bug(color-picker): '修复resize时picker位置错误问题'
1 parent d577ce4 commit 9d7db7a

33 files changed

+2712
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { mount } from '@vue/test-utils';
2+
import { ColorPicker } from '../index';
3+
4+
describe('color-picker test', () => {
5+
it('color-picker init render', async () => {
6+
// todo
7+
})
8+
})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { App } from 'vue'
2+
import ColorPicker from './src/color-picker'
3+
4+
ColorPicker.install = function (app: App): void {
5+
app.component(ColorPicker.name, ColorPicker)
6+
}
7+
8+
export { ColorPicker }
9+
10+
export default {
11+
title: 'ColorPicker 颜色选择器',
12+
category: '数据录入',
13+
status: '80%', // TODO: 组件若开发完成则填入"100%",并删除该注释
14+
install(app: App): void {
15+
app.use(ColorPicker as any)
16+
}
17+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { PropType, ExtractPropTypes } from 'vue'
2+
export const colorPickerProps = {
3+
modelValue: {
4+
type: [Object, String] as PropType<string | number>
5+
},
6+
mode: {
7+
type: String
8+
},
9+
showAlpha: {
10+
type: Boolean,
11+
default: true
12+
},
13+
dotSize: {
14+
type: Number,
15+
default: 15
16+
},
17+
swatches: {
18+
type: Array as PropType<string[]>
19+
},
20+
showHistory: {
21+
type: Boolean,
22+
default: true
23+
}
24+
} as const
25+
26+
export type ColorPickerProps = ExtractPropTypes<typeof colorPickerProps>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
@import '../../style/theme/color';
2+
3+
.devui-color-picker {
4+
position: relative;
5+
&-position {
6+
position: absolute;
7+
z-index: 9999;
8+
background-color: $devui-connected-overlay-bg;
9+
top: 0;
10+
}
11+
12+
&-color-value {
13+
display: flex;
14+
position: absolute;
15+
z-index: 4;
16+
left: 50%;
17+
top: 50%;
18+
transform: translate(-50%, -50%);
19+
font-weight: bold;
20+
color: rgb(204, 15, 15);
21+
}
22+
23+
&-container {
24+
padding: 3px;
25+
border: 1px solid rgb(224, 224, 230);
26+
border-radius: 3px;
27+
&-wrap {
28+
width: 100%;
29+
height: 26px;
30+
box-sizing: content-box;
31+
box-shadow: 3px 0 5px #00000014;
32+
position: relative;
33+
cursor: pointer;
34+
overflow: hidden;
35+
display: inline-block;
36+
vertical-align: middle;
37+
38+
&-current-color {
39+
top: 0;
40+
right: 0;
41+
left: 0;
42+
position: absolute;
43+
z-index: 3;
44+
width: 100%;
45+
height: 100%;
46+
}
47+
&-current-color-transparent {
48+
top: 0;
49+
right: 0;
50+
left: 0;
51+
overflow: hidden;
52+
padding: 3px;
53+
width: 100%;
54+
height: 100%;
55+
position: absolute;
56+
z-index: 2;
57+
}
58+
&-transparent {
59+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
60+
background-repeat: repeat;
61+
}
62+
}
63+
}
64+
}
65+
66+
.color-picker-transition-enter-from,
67+
.color-picker-transition-leave-to {
68+
opacity: 0;
69+
}
70+
.color-picker-transition-enter-to,
71+
.color-picker-transition-leave-from {
72+
opacity: 1;
73+
}
74+
.color-picker-transition-enter-active,
75+
.color-picker-transition-leave-active {
76+
transition: opacity 0.2s ease-in-out;
77+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import {
2+
defineComponent,
3+
ref,
4+
computed,
5+
onMounted,
6+
watch,
7+
nextTick,
8+
provide,
9+
Teleport,
10+
unref,
11+
readonly,
12+
Transition
13+
} from 'vue'
14+
import {
15+
useReactive,
16+
colorPickerResize,
17+
isExhibitionColorPicker,
18+
changeColorValue
19+
} from './utils/composeable'
20+
import { colorPickerProps, ColorPickerProps } from './color-picker-types'
21+
import colorPanel from './components/color-picker-panel/color-picker-panel'
22+
import './color-picker.scss'
23+
import { parseColor, extractColor, RGBAtoCSS } from './utils/color-utils'
24+
import { ColorPickerColor } from './utils/color-utils-types'
25+
export default defineComponent({
26+
name: 'DColorPicker',
27+
components: {
28+
colorPanel
29+
},
30+
props: colorPickerProps,
31+
emits: ['update:modelValue'],
32+
setup(props: ColorPickerProps, { emit }) {
33+
const DEFAUTL_MODE = 'rgb'
34+
const provideData = {
35+
showAlpha: useReactive(() => props.showAlpha),
36+
swatches: useReactive(() => props.swatches),
37+
dotSize: useReactive(() => props.dotSize),
38+
showHistory: useReactive(() => props.showHistory)
39+
}
40+
provide('provideData', readonly(provideData))
41+
const initialColor = ref(null)
42+
const colorCubeRef = ref<HTMLElement | null>()
43+
const pickerRef = ref<HTMLElement | null>()
44+
const containerRef = ref<HTMLElement | null>()
45+
const left = ref(0)
46+
const top = ref(0)
47+
const isChangeTextColor = ref(true)
48+
const showColorPicker = ref(false)
49+
const formItemText = ref(`${props.mode ?? DEFAUTL_MODE}`)
50+
const mode = ref(unref(props.mode))
51+
onMounted(() => {
52+
// resize 响应式 colorpicker
53+
window.addEventListener('resize', resize)
54+
// 点击展示 colorpicker
55+
window.addEventListener('click', isExhibition)
56+
})
57+
// ** computeds
58+
// colorpicker panel 组件位置
59+
const colorPickerPostion = computed(() => {
60+
if (colorCubeRef.value) {
61+
return {
62+
transform: `translate(${left.value}px, ${top.value}px)`
63+
}
64+
}
65+
return null
66+
})
67+
// 交互触发item 颜色 面板 动态修改alpha后要还原 alpha 2021.12.18
68+
const tiggerColor = computed(() => {
69+
const currentColor = initialColor.value.rgba
70+
const trigger = { ...currentColor, a: props.showAlpha ? currentColor.a : 1 }
71+
return {
72+
backgroundColor: `${RGBAtoCSS(trigger)}`
73+
}
74+
})
75+
// 交互面板 的value 值 动态展示 根据不同 type
76+
const formItemValue = computed(() => {
77+
return extractColor(initialColor.value, '', formItemText.value, props.showAlpha)
78+
})
79+
// 动态 根据当前 透明度修改文本颜色 tips:根据不同 面板颜色 目前 不够优雅
80+
const textColor = computed(() => {
81+
// 数字代表 hsv 中的value 值 纵轴 动态切换 文本颜色
82+
return changeColorValue(initialColor.value, 0.5)
83+
})
84+
// ** emits
85+
// 动态 交互面板 文本展示颜色 tips:根据不同 面板颜色 目前 不够优雅
86+
function changeTextColor(value: boolean): void {
87+
isChangeTextColor.value = value
88+
}
89+
// 通过修改画板 颜色 修改 v-model 颜色
90+
function changePaletteColor(colorMap: ColorPickerColor): void {
91+
updateUserColor(colorMap)
92+
}
93+
// 通过用户点击触发修改 交互面板 文本类型
94+
function changeTextModeType(type: string): void {
95+
mode.value = type
96+
formItemText.value = type
97+
}
98+
99+
// 初始化的时候 确定 colopicker位置 由于 pickerref 默认 为 undefined 所以监听 showcolorpicker
100+
watch(
101+
() => showColorPicker.value,
102+
(newValue) => {
103+
const textPalette = colorCubeRef.value?.getBoundingClientRect()
104+
newValue &&
105+
nextTick(() => {
106+
pickerRef.value.style.transform = `translate(${textPalette.left + 'px'}, ${
107+
textPalette.top + window.scrollY + textPalette.height + 'px'
108+
})`
109+
})
110+
}
111+
)
112+
// 监听用户输入 2021.12.10
113+
watch(
114+
() => props.modelValue,
115+
(newValue) => {
116+
// 全部转换成对象
117+
updateUserColor(parseColor(newValue, initialColor.value))
118+
},
119+
{ immediate: true }
120+
)
121+
// 更新用户输入颜色 2021.12.10
122+
function updateUserColor(color) {
123+
initialColor.value = color
124+
// 提取颜色 2021.12.10
125+
const value = extractColor(initialColor.value, props.modelValue, mode.value, props.showAlpha)
126+
emit('update:modelValue', value)
127+
}
128+
function resize() {
129+
return colorPickerResize(colorCubeRef, top, left)
130+
}
131+
function isExhibition(event: Event) {
132+
return isExhibitionColorPicker(event, colorCubeRef, pickerRef, showColorPicker)
133+
}
134+
return () => {
135+
return (
136+
<div class='devui-color-picker' ref={colorCubeRef}>
137+
<div class='devui-color-picker-container'>
138+
<div class='devui-color-picker-container-wrap'>
139+
<div
140+
class='devui-color-picker-container-wrap-current-color'
141+
style={tiggerColor.value}
142+
></div>
143+
<div
144+
class={[
145+
'devui-color-picker-container-wrap-transparent',
146+
'devui-color-picker-container-wrap-current-color-transparent'
147+
]}
148+
></div>
149+
<div class='devui-color-picker-color-value'>
150+
<p style={textColor.value}>{formItemValue.value}</p>
151+
</div>
152+
</div>
153+
</div>
154+
<Teleport to='body'>
155+
<Transition name='color-picker-transition'>
156+
{showColorPicker.value ? (
157+
<div
158+
ref={pickerRef}
159+
style={colorPickerPostion.value}
160+
class={['devui-color-picker-position']}
161+
>
162+
<color-panel
163+
v-model={initialColor.value}
164+
ref={containerRef}
165+
mode={mode.value}
166+
onChangeTextColor={changeTextColor}
167+
onChangePaletteColor={changePaletteColor}
168+
onChangeTextModeType={changeTextModeType}
169+
></color-panel>
170+
</div>
171+
) : null}
172+
</Transition>
173+
</Teleport>
174+
</div>
175+
)
176+
}
177+
}
178+
})
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.devui-color-picker-alpha-slider {
2+
position: relative;
3+
margin-bottom: 15px;
4+
width: 100%;
5+
height: 14px;
6+
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.08);
7+
border-radius: 15px;
8+
9+
&.transparent {
10+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
11+
background-repeat: repeat;
12+
}
13+
14+
&__bar {
15+
position: relative;
16+
width: 100%;
17+
height: 100%;
18+
border-radius: 15px;
19+
20+
&-pointer {
21+
position: absolute;
22+
width: 14px;
23+
height: 14px;
24+
}
25+
26+
&-handle {
27+
width: 14px;
28+
height: 14px;
29+
border-radius: 6px;
30+
transform: translate(-7px, -2px);
31+
background-color: #f8f8f8;
32+
margin-top: 2px;
33+
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37);
34+
cursor: pointer;
35+
36+
&.vertical {
37+
transform: translate(0, -7px);
38+
margin-top: 0;
39+
}
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)