Vue component multi-select widget (#2987)

This commit is contained in:
Chenlei Hu
2025-03-12 12:03:21 -04:00
committed by GitHub
parent aad7ded636
commit bcd76ba49b
8 changed files with 299 additions and 133 deletions

View File

@@ -6,6 +6,7 @@
:key="widget.id"
:widget="widget"
:widget-state="domWidgetStore.widgetStates.get(widget.id)"
@update:widget-value="widget.value = $event"
/>
</div>
</template>
@@ -16,7 +17,7 @@ import { computed, watch } from 'vue'
import DomWidget from '@/components/graph/widgets/DomWidget.vue'
import { useChainCallback } from '@/composables/functional/useChainCallback'
import { DOMWidget } from '@/scripts/domWidget'
import { BaseDOMWidget } from '@/scripts/domWidget'
import { useDomWidgetStore } from '@/stores/domWidgetStore'
import { useCanvasStore } from '@/stores/graphStore'
@@ -24,7 +25,7 @@ const domWidgetStore = useDomWidgetStore()
const widgets = computed(() =>
Array.from(
domWidgetStore.widgetInstances.values() as Iterable<
DOMWidget<HTMLElement, object | string>
BaseDOMWidget<string | object>
>
)
)

View File

@@ -5,7 +5,15 @@
ref="widgetElement"
:style="style"
v-show="widgetState.visible"
/>
>
<component
v-if="isComponentWidget(widget)"
:is="widget.component"
:modelValue="widget.value"
@update:modelValue="emit('update:widgetValue', $event)"
:widget="widget"
/>
</div>
</template>
<script setup lang="ts">
@@ -15,16 +23,24 @@ import { CSSProperties, computed, onMounted, ref, watch } from 'vue'
import { useAbsolutePosition } from '@/composables/element/useAbsolutePosition'
import { useDomClipping } from '@/composables/element/useDomClipping'
import type { DOMWidget } from '@/scripts/domWidget'
import {
type BaseDOMWidget,
isComponentWidget,
isDOMWidget
} from '@/scripts/domWidget'
import { DomWidgetState } from '@/stores/domWidgetStore'
import { useCanvasStore } from '@/stores/graphStore'
import { useSettingStore } from '@/stores/settingStore'
const { widget, widgetState } = defineProps<{
widget: DOMWidget<HTMLElement, any>
widget: BaseDOMWidget<string | object>
widgetState: DomWidgetState
}>()
const emit = defineEmits<{
(e: 'update:widgetValue', value: string | object): void
}>()
const widgetElement = ref<HTMLElement>()
const { style: positionStyle, updatePositionWithTransform } =
@@ -92,27 +108,31 @@ watch(
}
)
if (widget.element.blur) {
useEventListener(document, 'mousedown', (event) => {
if (!widget.element.contains(event.target as HTMLElement)) {
widget.element.blur()
}
})
}
if (isDOMWidget(widget)) {
if (widget.element.blur) {
useEventListener(document, 'mousedown', (event) => {
if (!widget.element.contains(event.target as HTMLElement)) {
widget.element.blur()
}
})
}
for (const evt of widget.options.selectOn ?? ['focus', 'click']) {
useEventListener(widget.element, evt, () => {
const lgCanvas = canvasStore.canvas
lgCanvas?.selectNode(widget.node)
lgCanvas?.bringToFront(widget.node)
})
for (const evt of widget.options.selectOn ?? ['focus', 'click']) {
useEventListener(widget.element, evt, () => {
const lgCanvas = canvasStore.canvas
lgCanvas?.selectNode(widget.node)
lgCanvas?.bringToFront(widget.node)
})
}
}
const inputSpec = widget.node.constructor.nodeData
const tooltip = inputSpec?.inputs?.[widget.name]?.tooltip
onMounted(() => {
widgetElement.value.appendChild(widget.element)
if (isDOMWidget(widget)) {
widgetElement.value.appendChild(widget.element)
}
})
</script>

View File

@@ -0,0 +1,30 @@
<template>
<div>
<MultiSelect
v-model="selectedItems"
:options="options"
filter
:placeholder="placeholder"
:maxSelectedLabels="3"
:display="display"
class="w-full"
/>
</div>
</template>
<script setup lang="ts">
import MultiSelect from 'primevue/multiselect'
import type { ComboInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import type { ComponentWidget } from '@/scripts/domWidget'
const selectedItems = defineModel<string[]>({ required: true })
const { widget } = defineProps<{
widget: ComponentWidget<string[]>
}>()
const inputSpec = widget.inputSpec as ComboInputSpec
const options = inputSpec.options ?? []
const placeholder = inputSpec.multi_select?.placeholder ?? 'Select items'
const display = inputSpec.multi_select?.chip ? 'chip' : 'comma'
</script>