feat: dropdown widgets vue node ui (#5624)

- Load media dropdown widgets
- Load models dropdown widgets

I added a lot of feedback effects during interactions.
I tried my best to break the Dropdown into small components.
To make it more flexible, I provided many configurable props and
v-model.

<img width="1000" alt="CleanShot 2025-09-18 at 01 54 38"
src="https://github.com/user-attachments/assets/1a413078-1547-44b8-8b48-1ce8f8e764b5"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5624-feat-dropdown-widgets-vue-node-ui-2716d73d36508115a52bc1fb6d6376d0)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
This commit is contained in:
Rizumu Ayaka
2025-09-27 03:04:39 +08:00
committed by GitHub
parent 9f19d8fb4b
commit c96f719f91
19 changed files with 1270 additions and 51 deletions

View File

@@ -0,0 +1,68 @@
<template>
<WidgetLayoutField :widget>
<Select
v-model="localValue"
:options="selectOptions"
v-bind="combinedProps"
:disabled="readonly"
class="w-full text-xs bg-[#F9F8F4] dark-theme:bg-[#0E0E12] border-[#E1DED5] dark-theme:border-[#15161C] !rounded-lg"
size="small"
:pt="{
option: 'text-xs'
}"
@update:model-value="onChange"
/>
</WidgetLayoutField>
</template>
<script setup lang="ts">
import Select from 'primevue/select'
import { computed } from 'vue'
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
import { useTransformCompatOverlayProps } from '@/composables/useTransformCompatOverlayProps'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import {
PANEL_EXCLUDED_PROPS,
filterWidgetProps
} from '@/utils/widgetPropFilter'
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
const props = defineProps<{
widget: SimplifiedWidget<string | number | undefined>
modelValue: string | number | undefined
readonly?: boolean
}>()
const emit = defineEmits<{
'update:modelValue': [value: string | number | undefined]
}>()
// Use the composable for consistent widget value handling
const { localValue, onChange } = useWidgetValue({
widget: props.widget,
modelValue: props.modelValue,
defaultValue: props.widget.options?.values?.[0] || '',
emit
})
// Transform compatibility props for overlay positioning
const transformCompatProps = useTransformCompatOverlayProps()
const combinedProps = computed(() => ({
...filterWidgetProps(props.widget.options, PANEL_EXCLUDED_PROPS),
...transformCompatProps.value
}))
// Extract select options from widget options
const selectOptions = computed(() => {
const options = props.widget.options
if (options?.values && Array.isArray(options.values)) {
return options.values
}
return []
})
</script>