refactor: drop primevue/colorpicker from FormColorPicker and ColorCustomizationSelector (FE-804)

This commit is contained in:
Glary-Bot
2026-05-20 22:54:23 +00:00
parent 2717d59451
commit 6d66cdacd8
4 changed files with 45 additions and 45 deletions

View File

@@ -1,10 +1,10 @@
import { render } from '@testing-library/vue'
import userEvent from '@testing-library/user-event'
import ColorPicker from 'primevue/colorpicker'
import PrimeVue from 'primevue/config'
import SelectButton from 'primevue/selectbutton'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createApp, nextTick } from 'vue'
import { createI18n } from 'vue-i18n'
import ColorCustomizationSelector from './ColorCustomizationSelector.vue'
@@ -14,6 +14,12 @@ describe('ColorCustomizationSelector', () => {
{ name: 'Green', value: '#28a745' }
]
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: { en: { color: { hex: 'Hex', rgba: 'RGBA' } } }
})
beforeEach(() => {
const app = createApp({})
app.use(PrimeVue)
@@ -27,8 +33,8 @@ describe('ColorCustomizationSelector', () => {
const result = render(ColorCustomizationSelector, {
global: {
plugins: [PrimeVue],
components: { SelectButton, ColorPicker }
plugins: [PrimeVue, i18n],
components: { SelectButton }
},
props: {
modelValue: null,
@@ -68,24 +74,21 @@ describe('ColorCustomizationSelector', () => {
const buttons = getToggleButtons(container)
const customButton = buttons[buttons.length - 1]
expect(customButton).toHaveAttribute('aria-pressed', 'true')
// eslint-disable-next-line testing-library/no-container, testing-library/no-node-access -- PrimeVue ColorPicker uses readonly input preview with no ARIA role
const colorPreview = container.querySelector(
'.p-colorpicker-preview'
) as HTMLInputElement | null
expect(colorPreview).not.toBeNull()
})
it('shows color picker when custom option is selected', async () => {
const { container, user } = renderComponent()
const { container, user } = renderComponent({ modelValue: '#0d6efd' })
await nextTick()
const buttons = getToggleButtons(container)
await user.click(buttons[buttons.length - 1])
// eslint-disable-next-line testing-library/no-node-access, testing-library/no-container -- count buttons to detect the ColorPicker popover trigger appearing
const initialButtonCount = container.querySelectorAll('button').length
const toggleButtons = getToggleButtons(container)
await user.click(toggleButtons[toggleButtons.length - 1])
await nextTick()
expect(
// eslint-disable-next-line testing-library/no-container, testing-library/no-node-access -- PrimeVue ColorPicker internal DOM
container.querySelector('[data-pc-name="colorpicker"]')
).not.toBeNull()
// eslint-disable-next-line testing-library/no-node-access, testing-library/no-container -- count buttons to detect the ColorPicker popover trigger appearing
const afterButtonCount = container.querySelectorAll('button').length
expect(afterButtonCount).toBe(initialButtonCount + 1)
})
it('emits update when predefined color is selected', async () => {
@@ -117,7 +120,7 @@ describe('ColorCustomizationSelector', () => {
onUpdate.mockClear()
await user.click(buttons[buttons.length - 1]) // Switch to custom
// When switching to custom, the custom color value inherits from Blue ('0d6efd')
// When switching to custom, the custom color value inherits from Blue
// and the watcher on customColorValue emits the update
expect(onUpdate).toHaveBeenCalledWith('#0d6efd')
})

View File

@@ -25,15 +25,17 @@
<ColorPicker
v-if="selectedColorOption.name === '_custom'"
v-model="customColorValue"
class="w-28"
/>
</div>
</template>
<script setup lang="ts">
import ColorPicker from 'primevue/colorpicker'
import SelectButton from 'primevue/selectbutton'
import { computed, onMounted, ref, watch } from 'vue'
import ColorPicker from '@/components/ui/color-picker/ColorPicker.vue'
const {
modelValue,
colorOptions,
@@ -65,7 +67,7 @@ onMounted(() => {
selectedColorOption.value = predefinedColor
} else {
selectedColorOption.value = customColorOption
customColorValue.value = modelValue.replace('#', '')
customColorValue.value = modelValue
}
}
})
@@ -74,7 +76,7 @@ onMounted(() => {
watch(selectedColorOption, (newOption, oldOption) => {
if (newOption.name === '_custom') {
// Inherit the color from previous selection
customColorValue.value = oldOption.value.replace('#', '')
customColorValue.value = oldOption.value
} else {
emit('update:modelValue', newOption.value)
}
@@ -82,7 +84,7 @@ watch(selectedColorOption, (newOption, oldOption) => {
watch(customColorValue, (newValue) => {
if (selectedColorOption.value.name === '_custom') {
emit('update:modelValue', newValue ? `#${newValue}` : null)
emit('update:modelValue', newValue || null)
}
})
</script>

View File

@@ -2,11 +2,7 @@
<Dialog v-model:open="visible" :modal="false">
<DialogPortal>
<DialogOverlay />
<DialogContent
size="md"
:aria-labelledby="titleId"
@pointer-down-outside="onPointerDownOutside"
>
<DialogContent size="md" :aria-labelledby="titleId">
<DialogHeader>
<DialogTitle :id="titleId">
{{ $t('g.customizeFolder') }}
@@ -92,21 +88,6 @@ const emit = defineEmits<{
const titleId = useId()
// PrimeVue ColorPicker overlay teleports to body. Reka treats clicks on it as
// outside and would dismiss the dialog mid-color-pick. Treat any PrimeVue
// overlay click as inside.
const PRIMEVUE_OVERLAY_SELECTORS =
'.p-colorpicker-panel, .p-overlay, .p-overlay-mask'
function onPointerDownOutside(
event: CustomEvent<{ originalEvent: PointerEvent }>
) {
const target = event.detail.originalEvent.target
if (target instanceof Element && target.closest(PRIMEVUE_OVERLAY_SELECTORS)) {
event.preventDefault()
}
}
const nodeBookmarkStore = useNodeBookmarkStore()
const iconOptions = [

View File

@@ -1,13 +1,15 @@
<template>
<div class="color-picker-wrapper flex items-center gap-2">
<ColorPicker v-model="modelValue" v-bind="$attrs" />
<InputText v-model="modelValue" class="w-28" :placeholder="label" />
<ColorPicker v-model="hexValue" class="w-28" v-bind="$attrs" />
<Input v-model="hexValue" class="w-28" :placeholder="label" />
</div>
</template>
<script setup lang="ts">
import ColorPicker from 'primevue/colorpicker'
import InputText from 'primevue/inputtext'
import { computed } from 'vue'
import ColorPicker from '@/components/ui/color-picker/ColorPicker.vue'
import Input from '@/components/ui/input/Input.vue'
const modelValue = defineModel<string>('modelValue')
defineProps<{
@@ -17,4 +19,16 @@ defineProps<{
defineOptions({
inheritAttrs: false
})
// Preserve the PrimeVue ColorPicker storage contract (hex without `#`);
// the underlying picker uses `#`-prefixed hex, so normalize on read.
const hexValue = computed<string>({
get: () =>
modelValue.value?.startsWith('#')
? modelValue.value
: `#${modelValue.value ?? '000000'}`,
set: (next) => {
modelValue.value = next.replace(/^#/, '')
}
})
</script>