mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-24 22:58:08 +00:00
refactor: drop primevue/colorpicker from FormColorPicker and ColorCustomizationSelector (FE-804)
This commit is contained in:
@@ -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')
|
||||
})
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user