mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-07 16:40:05 +00:00
feat(EditableText): add doubleClickToEdit prop for inline editing trigger
Amp-Thread-ID: https://ampcode.com/threads/T-019bc4be-bbb6-7290-98f0-4cc630ec28bb Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -65,8 +65,10 @@ describe('EditableText', () => {
|
||||
})
|
||||
await wrapper.findComponent(InputText).trigger('blur')
|
||||
expect(wrapper.emitted('edit')).toBeTruthy()
|
||||
// @ts-expect-error fixme ts strict error
|
||||
expect(wrapper.emitted('edit')[0]).toEqual(['Test Text'])
|
||||
expect(wrapper.emitted('edit')?.[0]).toEqual(['Test Text'])
|
||||
|
||||
// Should exit edit mode via v-model
|
||||
expect(wrapper.emitted('update:isEditing')?.at(-1)).toEqual([false])
|
||||
})
|
||||
|
||||
it('cancels editing on escape key', async () => {
|
||||
@@ -87,10 +89,12 @@ describe('EditableText', () => {
|
||||
// Should NOT emit edit event
|
||||
expect(wrapper.emitted('edit')).toBeFalsy()
|
||||
|
||||
// Input value should be reset to original
|
||||
expect(wrapper.findComponent(InputText).props()['modelValue']).toBe(
|
||||
'Original Text'
|
||||
)
|
||||
// Should exit edit mode (isEditing set to false via v-model)
|
||||
expect(wrapper.emitted('update:isEditing')).toBeTruthy()
|
||||
expect(wrapper.emitted('update:isEditing')?.at(-1)).toEqual([false])
|
||||
|
||||
// Text should be reset to original value (now displayed in span)
|
||||
expect(wrapper.find('span').text()).toBe('Original Text')
|
||||
})
|
||||
|
||||
it('does not save changes when escape is pressed and blur occurs', async () => {
|
||||
@@ -102,15 +106,15 @@ describe('EditableText', () => {
|
||||
// Change the input value
|
||||
await wrapper.findComponent(InputText).setValue('Modified Text')
|
||||
|
||||
// Press escape (which triggers blur internally)
|
||||
// Press escape (which triggers blur internally and sets isEditing to false)
|
||||
await wrapper.findComponent(InputText).trigger('keyup.escape')
|
||||
|
||||
// Manually trigger blur to simulate the blur that happens after escape
|
||||
await wrapper.findComponent(InputText).trigger('blur')
|
||||
|
||||
// Should emit cancel but not edit
|
||||
expect(wrapper.emitted('cancel')).toBeTruthy()
|
||||
expect(wrapper.emitted('edit')).toBeFalsy()
|
||||
|
||||
// Should exit edit mode
|
||||
expect(wrapper.emitted('update:isEditing')?.at(-1)).toEqual([false])
|
||||
})
|
||||
|
||||
it('saves changes on enter but not on escape', async () => {
|
||||
@@ -124,8 +128,7 @@ describe('EditableText', () => {
|
||||
// Trigger blur that happens after enter
|
||||
await enterWrapper.findComponent(InputText).trigger('blur')
|
||||
expect(enterWrapper.emitted('edit')).toBeTruthy()
|
||||
// @ts-expect-error fixme ts strict error
|
||||
expect(enterWrapper.emitted('edit')[0]).toEqual(['Saved Text'])
|
||||
expect(enterWrapper.emitted('edit')?.[0]).toEqual(['Saved Text'])
|
||||
|
||||
// Test Escape key cancels changes with a fresh wrapper
|
||||
const escapeWrapper = mountComponent({
|
||||
@@ -137,4 +140,42 @@ describe('EditableText', () => {
|
||||
expect(escapeWrapper.emitted('cancel')).toBeTruthy()
|
||||
expect(escapeWrapper.emitted('edit')).toBeFalsy()
|
||||
})
|
||||
|
||||
describe('doubleClickToEdit', () => {
|
||||
it('enters edit mode on double-click when doubleClickToEdit is true', async () => {
|
||||
const wrapper = mountComponent({
|
||||
modelValue: 'Test Text',
|
||||
isEditing: false,
|
||||
doubleClickToEdit: true
|
||||
})
|
||||
|
||||
expect(wrapper.find('span').exists()).toBe(true)
|
||||
await wrapper.find('span').trigger('dblclick')
|
||||
|
||||
expect(wrapper.emitted('update:isEditing')?.[0]).toEqual([true])
|
||||
})
|
||||
|
||||
it('does not enter edit mode on double-click when doubleClickToEdit is false', async () => {
|
||||
const wrapper = mountComponent({
|
||||
modelValue: 'Test Text',
|
||||
isEditing: false,
|
||||
doubleClickToEdit: false
|
||||
})
|
||||
|
||||
await wrapper.find('span').trigger('dblclick')
|
||||
|
||||
expect(wrapper.emitted('update:isEditing')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('does not enter edit mode on double-click by default', async () => {
|
||||
const wrapper = mountComponent({
|
||||
modelValue: 'Test Text',
|
||||
isEditing: false
|
||||
})
|
||||
|
||||
await wrapper.find('span').trigger('dblclick')
|
||||
|
||||
expect(wrapper.emitted('update:isEditing')).toBeFalsy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="editable-text">
|
||||
<span v-if="!isEditing">
|
||||
<span v-if="!isEditing" @dblclick="handleDoubleClick">
|
||||
{{ modelValue }}
|
||||
</span>
|
||||
<!-- Avoid double triggering finishEditing event when keyup.enter is triggered -->
|
||||
@@ -34,19 +34,26 @@ import { nextTick, ref, watch } from 'vue'
|
||||
|
||||
const {
|
||||
modelValue,
|
||||
isEditing = false,
|
||||
inputAttrs = {}
|
||||
inputAttrs = {},
|
||||
doubleClickToEdit = false
|
||||
} = defineProps<{
|
||||
modelValue: string
|
||||
isEditing?: boolean
|
||||
inputAttrs?: Record<string, string>
|
||||
doubleClickToEdit?: boolean
|
||||
}>()
|
||||
|
||||
const isEditing = defineModel<boolean>('isEditing', { default: false })
|
||||
|
||||
const emit = defineEmits(['edit', 'cancel'])
|
||||
const inputValue = ref<string>(modelValue)
|
||||
const inputRef = ref<InstanceType<typeof InputText> | undefined>()
|
||||
const isCanceling = ref(false)
|
||||
|
||||
const handleDoubleClick = () => {
|
||||
if (doubleClickToEdit) {
|
||||
isEditing.value = true
|
||||
}
|
||||
}
|
||||
const blurInputElement = () => {
|
||||
// @ts-expect-error - $el is an internal property of the InputText component
|
||||
inputRef.value?.$el.blur()
|
||||
@@ -57,6 +64,7 @@ const finishEditing = () => {
|
||||
emit('edit', inputValue.value)
|
||||
}
|
||||
isCanceling.value = false
|
||||
isEditing.value = false
|
||||
}
|
||||
const cancelEditing = () => {
|
||||
// Set canceling flag to prevent blur from saving
|
||||
@@ -65,11 +73,12 @@ const cancelEditing = () => {
|
||||
inputValue.value = modelValue
|
||||
// Emit cancel event
|
||||
emit('cancel')
|
||||
isEditing.value = false
|
||||
// Blur the input to exit edit mode
|
||||
blurInputElement()
|
||||
}
|
||||
watch(
|
||||
() => isEditing,
|
||||
isEditing,
|
||||
async (newVal) => {
|
||||
if (newVal) {
|
||||
inputValue.value = modelValue
|
||||
|
||||
Reference in New Issue
Block a user