mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-11 00:10:40 +00:00
refactor: rebuild SingleSelect and MultiSelect with Reka UI (#9742)
## Summary - Rebuild `SingleSelect` with Reka UI Select primitives (SelectRoot, SelectTrigger, SelectContent, SelectItem) - Rebuild `MultiSelect` with Reka UI Popover + Listbox (PopoverRoot, ListboxRoot with `multiple`) - Remove PrimeVue dependency from both components - Preserve existing API contract for all consumers ## TODO - [x] Re-evaluate MultiSelect implementation (ComboboxRoot with `multiple` may be cleaner than Popover+Listbox) - [x] E2E verification in actual app (AssetFilterBar, WorkflowTemplateSelectorDialog, etc.) ## Test plan - [x] Storybook visual verification for all SingleSelect/MultiSelect stories - [x] Keyboard navigation (arrow keys, Enter, Escape, typeahead) - [x] Multi-selection with badge count - [x] Search filtering in MultiSelect - [x] Clear all functionality - [x] Disabled state - [x] Invalid state (SingleSelect) - [x] Loading state (SingleSelect) ## screenshot <img width="519" height="475" alt="스크린샷 2026-03-20 오전 12 12 37" src="https://github.com/user-attachments/assets/ffc7f0b0-c88c-486b-a253-73a4da73c1de" /> <img width="842" height="554" alt="스크린샷 2026-03-20 오전 12 23 51" src="https://github.com/user-attachments/assets/410551d4-c843-4898-b305-13a6ad6978ca" /> ## video https://github.com/user-attachments/assets/2fc3a9b9-2671-4c2c-9f54-4f83598afb53 Fixes #9700 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9742-refactor-rebuild-SingleSelect-and-MultiSelect-with-Reka-UI-3206d73d36508113bee2cf160c8f2d50) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Alexander Brown <drjkl@comfy.org>
This commit is contained in:
60
src/components/input/MultiSelect.test.ts
Normal file
60
src/components/input/MultiSelect.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
import MultiSelect from './MultiSelect.vue'
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
messages: {
|
||||
en: {
|
||||
g: {
|
||||
multiSelectDropdown: 'Multi-select dropdown',
|
||||
noResultsFound: 'No results found',
|
||||
search: 'Search',
|
||||
clearAll: 'Clear all',
|
||||
itemsSelected: 'Items selected'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
describe('MultiSelect', () => {
|
||||
function createWrapper() {
|
||||
return mount(MultiSelect, {
|
||||
attachTo: document.body,
|
||||
global: {
|
||||
plugins: [i18n]
|
||||
},
|
||||
props: {
|
||||
modelValue: [],
|
||||
label: 'Category',
|
||||
options: [
|
||||
{ name: 'One', value: 'one' },
|
||||
{ name: 'Two', value: 'two' }
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
it('keeps open-state border styling available while the dropdown is open', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
const trigger = wrapper.get('button[aria-haspopup="listbox"]')
|
||||
|
||||
expect(trigger.classes()).toContain(
|
||||
'data-[state=open]:border-node-component-border'
|
||||
)
|
||||
expect(trigger.attributes('aria-expanded')).toBe('false')
|
||||
|
||||
await trigger.trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(trigger.attributes('aria-expanded')).toBe('true')
|
||||
expect(trigger.attributes('data-state')).toBe('open')
|
||||
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user