mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +00:00
feat: widget styles for V3 UI (#5320)
* feat: widget input text style * feat: widget select button style * feat: the selection style of LGraphNode * feat(V3 UI style): color picker + file upload + input text + multi select + select + select button + slider + textarea + tree select * feat: placeholder * fix: filter multi select options * fix: direct binding, no transform for select button widget
This commit is contained in:
@@ -10,7 +10,8 @@
|
|||||||
cn(
|
cn(
|
||||||
'bg-white dark-theme:bg-[#15161A]',
|
'bg-white dark-theme:bg-[#15161A]',
|
||||||
'min-w-[445px]',
|
'min-w-[445px]',
|
||||||
'lg-node absolute border-2 border-solid rounded-2xl',
|
'lg-node absolute border border-solid rounded-2xl',
|
||||||
|
'outline outline-transparent outline-2 hover:outline-black dark-theme:hover:outline-white',
|
||||||
{
|
{
|
||||||
'border-blue-500 ring-2 ring-blue-300': selected,
|
'border-blue-500 ring-2 ring-blue-300': selected,
|
||||||
'border-[#e1ded5] dark-theme:border-[#292A30]': !selected,
|
'border-[#e1ded5] dark-theme:border-[#292A30]': !selected,
|
||||||
@@ -19,8 +20,7 @@
|
|||||||
'border-red-500 bg-red-50': error,
|
'border-red-500 bg-red-50': error,
|
||||||
'will-change-transform': isDragging
|
'will-change-transform': isDragging
|
||||||
},
|
},
|
||||||
lodCssClass,
|
lodCssClass
|
||||||
'hover:border-green-500'
|
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
:style="[
|
:style="[
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
<!-- Needs custom color picker for alpha support -->
|
<!-- Needs custom color picker for alpha support -->
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-1">
|
<WidgetLayoutField :widget="widget">
|
||||||
<label v-if="widget.name" class="text-sm opacity-80">{{
|
<label
|
||||||
widget.name
|
:class="
|
||||||
}}</label>
|
cn(WidgetInputBaseClass, 'flex items-center gap-2 w-full px-4 py-2')
|
||||||
<ColorPicker
|
"
|
||||||
v-model="localValue"
|
>
|
||||||
v-bind="filteredProps"
|
<ColorPicker
|
||||||
:disabled="readonly"
|
v-model="localValue"
|
||||||
inline
|
v-bind="filteredProps"
|
||||||
@update:model-value="onChange"
|
:disabled="readonly"
|
||||||
/>
|
class="w-8 h-4 !rounded-full overflow-hidden border-none"
|
||||||
</div>
|
:pt="{
|
||||||
|
preview: '!w-full !h-full !border-none'
|
||||||
|
}"
|
||||||
|
@update:model-value="onChange"
|
||||||
|
/>
|
||||||
|
<span class="text-xs">#{{ localValue }}</span>
|
||||||
|
</label>
|
||||||
|
</WidgetLayoutField>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -20,11 +27,15 @@ import { computed } from 'vue'
|
|||||||
|
|
||||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
import {
|
import {
|
||||||
PANEL_EXCLUDED_PROPS,
|
PANEL_EXCLUDED_PROPS,
|
||||||
filterWidgetProps
|
filterWidgetProps
|
||||||
} from '@/utils/widgetPropFilter'
|
} from '@/utils/widgetPropFilter'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from './layout'
|
||||||
|
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
widget: SimplifiedWidget<string>
|
widget: SimplifiedWidget<string>
|
||||||
modelValue: string
|
modelValue: string
|
||||||
|
|||||||
@@ -157,6 +157,7 @@
|
|||||||
<Button
|
<Button
|
||||||
label="Browse Files"
|
label="Browse Files"
|
||||||
size="small"
|
size="small"
|
||||||
|
severity="secondary"
|
||||||
class="text-xs"
|
class="text-xs"
|
||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
@click="triggerFileInput"
|
@click="triggerFileInput"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
v-bind="filteredProps"
|
v-bind="filteredProps"
|
||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="w-full text-xs"
|
:class="cn(WidgetInputBaseClass, 'w-full text-xs py-2 px-4')"
|
||||||
size="small"
|
size="small"
|
||||||
@update:model-value="onChange"
|
@update:model-value="onChange"
|
||||||
/>
|
/>
|
||||||
@@ -17,11 +17,13 @@ import { computed } from 'vue'
|
|||||||
|
|
||||||
import { useStringWidgetValue } from '@/composables/graph/useWidgetValue'
|
import { useStringWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
import {
|
import {
|
||||||
INPUT_EXCLUDED_PROPS,
|
INPUT_EXCLUDED_PROPS,
|
||||||
filterWidgetProps
|
filterWidgetProps
|
||||||
} from '@/utils/widgetPropFilter'
|
} from '@/utils/widgetPropFilter'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from './layout'
|
||||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
v-bind="filteredProps"
|
v-bind="filteredProps"
|
||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="w-full text-xs"
|
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||||
size="small"
|
size="small"
|
||||||
|
display="chip"
|
||||||
:pt="{
|
:pt="{
|
||||||
option: 'text-xs'
|
option: 'text-xs'
|
||||||
}"
|
}"
|
||||||
@@ -20,11 +21,13 @@ import { computed } from 'vue'
|
|||||||
|
|
||||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
import {
|
import {
|
||||||
PANEL_EXCLUDED_PROPS,
|
PANEL_EXCLUDED_PROPS,
|
||||||
filterWidgetProps
|
filterWidgetProps
|
||||||
} from '@/utils/widgetPropFilter'
|
} from '@/utils/widgetPropFilter'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from './layout'
|
||||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -51,7 +54,18 @@ const MULTISELECT_EXCLUDED_PROPS = [
|
|||||||
'overlayStyle'
|
'overlayStyle'
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
const filteredProps = computed(() =>
|
const filteredProps = computed(() => {
|
||||||
filterWidgetProps(props.widget.options, MULTISELECT_EXCLUDED_PROPS)
|
const filtered = filterWidgetProps(
|
||||||
)
|
props.widget.options,
|
||||||
|
MULTISELECT_EXCLUDED_PROPS
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensure options array is available for MultiSelect
|
||||||
|
const values = props.widget.options?.values
|
||||||
|
if (values && Array.isArray(values)) {
|
||||||
|
filtered.options = values
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
:options="selectOptions"
|
:options="selectOptions"
|
||||||
v-bind="filteredProps"
|
v-bind="filteredProps"
|
||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="w-full text-xs bg-[#F9F8F4] dark-theme:bg-[#0E0E12] border-[#E1DED5] dark-theme:border-[#15161C] !rounded-lg"
|
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||||
size="small"
|
size="small"
|
||||||
:pt="{
|
:pt="{
|
||||||
option: 'text-xs'
|
option: 'text-xs'
|
||||||
@@ -21,11 +21,13 @@ import { computed } from 'vue'
|
|||||||
|
|
||||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
import {
|
import {
|
||||||
PANEL_EXCLUDED_PROPS,
|
PANEL_EXCLUDED_PROPS,
|
||||||
filterWidgetProps
|
filterWidgetProps
|
||||||
} from '@/utils/widgetPropFilter'
|
} from '@/utils/widgetPropFilter'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from './layout'
|
||||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|||||||
@@ -1,62 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<WidgetLayoutField :widget="widget">
|
<WidgetLayoutField :widget="widget">
|
||||||
<SelectButton
|
<FormSelectButton
|
||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
v-bind="filteredProps"
|
:options="widget.options?.values || []"
|
||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="w-full text-xs"
|
class="w-full"
|
||||||
:pt="{
|
|
||||||
pcToggleButton: {
|
|
||||||
label: 'text-xs'
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
@update:model-value="onChange"
|
@update:model-value="onChange"
|
||||||
/>
|
/>
|
||||||
</WidgetLayoutField>
|
</WidgetLayoutField>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import SelectButton from 'primevue/selectbutton'
|
import { useStringWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import { computed } from 'vue'
|
|
||||||
|
|
||||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
import {
|
|
||||||
STANDARD_EXCLUDED_PROPS,
|
|
||||||
filterWidgetProps
|
|
||||||
} from '@/utils/widgetPropFilter'
|
|
||||||
|
|
||||||
|
import FormSelectButton from './form/FormSelectButton.vue'
|
||||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
widget: SimplifiedWidget<any>
|
widget: SimplifiedWidget<string>
|
||||||
modelValue: any
|
modelValue: string
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
'update:modelValue': [value: any]
|
'update:modelValue': [value: string]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// Use the composable for consistent widget value handling
|
// Use the composable for consistent widget value handling
|
||||||
const { localValue, onChange } = useWidgetValue({
|
const { localValue, onChange } = useStringWidgetValue(
|
||||||
widget: props.widget,
|
props.widget,
|
||||||
modelValue: props.modelValue,
|
props.modelValue,
|
||||||
defaultValue: null,
|
|
||||||
emit
|
emit
|
||||||
})
|
|
||||||
|
|
||||||
const filteredProps = computed(() =>
|
|
||||||
filterWidgetProps(props.widget.options, STANDARD_EXCLUDED_PROPS)
|
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.p-selectbutton) {
|
|
||||||
border: 1px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.p-selectbutton:hover) {
|
|
||||||
border-color: currentColor;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<WidgetLayoutField :widget="widget">
|
<WidgetLayoutField :widget="widget">
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-2 w-full rounded-lg pl-4 pr-2 bg-[#F9F8F4] dark-theme:bg-[#0E0E12] border-[#E1DED5] dark-theme:border-[#15161C] border-solid border"
|
:class="
|
||||||
|
cn(WidgetInputBaseClass, 'flex items-center gap-2 w-full pl-4 pr-2')
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<Slider
|
<Slider
|
||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
@@ -33,11 +35,13 @@ import { computed, ref, watch } from 'vue'
|
|||||||
|
|
||||||
import { useNumberWidgetValue } from '@/composables/graph/useWidgetValue'
|
import { useNumberWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
import {
|
import {
|
||||||
STANDARD_EXCLUDED_PROPS,
|
STANDARD_EXCLUDED_PROPS,
|
||||||
filterWidgetProps
|
filterWidgetProps
|
||||||
} from '@/utils/widgetPropFilter'
|
} from '@/utils/widgetPropFilter'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from './layout'
|
||||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
v-bind="filteredProps"
|
v-bind="filteredProps"
|
||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="w-full text-xs"
|
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||||
|
:placeholder="placeholder || widget.name || ''"
|
||||||
size="small"
|
size="small"
|
||||||
rows="3"
|
rows="3"
|
||||||
@update:model-value="onChange"
|
@update:model-value="onChange"
|
||||||
@@ -16,15 +17,19 @@ import { computed } from 'vue'
|
|||||||
|
|
||||||
import { useStringWidgetValue } from '@/composables/graph/useWidgetValue'
|
import { useStringWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
import {
|
import {
|
||||||
INPUT_EXCLUDED_PROPS,
|
INPUT_EXCLUDED_PROPS,
|
||||||
filterWidgetProps
|
filterWidgetProps
|
||||||
} from '@/utils/widgetPropFilter'
|
} from '@/utils/widgetPropFilter'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from './layout'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
widget: SimplifiedWidget<string>
|
widget: SimplifiedWidget<string>
|
||||||
modelValue: string
|
modelValue: string
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
|
placeholder?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
v-bind="filteredProps"
|
v-bind="filteredProps"
|
||||||
:disabled="readonly"
|
:disabled="readonly"
|
||||||
class="w-full text-xs"
|
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||||
size="small"
|
size="small"
|
||||||
@update:model-value="onChange"
|
@update:model-value="onChange"
|
||||||
/>
|
/>
|
||||||
@@ -17,11 +17,13 @@ import { computed } from 'vue'
|
|||||||
|
|
||||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
import {
|
import {
|
||||||
PANEL_EXCLUDED_PROPS,
|
PANEL_EXCLUDED_PROPS,
|
||||||
filterWidgetProps
|
filterWidgetProps
|
||||||
} from '@/utils/widgetPropFilter'
|
} from '@/utils/widgetPropFilter'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from './layout'
|
||||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
WidgetInputBaseClass,
|
||||||
|
'p-1 inline-flex justify-center items-center gap-1'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-for="(option, index) in options"
|
||||||
|
:key="getOptionValue(option, index)"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'flex-1 h-6 px-5 py-[5px] rounded flex justify-center items-center gap-1 transition-all duration-150 ease-in-out',
|
||||||
|
'bg-transparent border-none',
|
||||||
|
'text-center text-xs font-normal',
|
||||||
|
{
|
||||||
|
'bg-white': isSelected(option) && !disabled,
|
||||||
|
'hover:bg-zinc-200/50': !isSelected(option) && !disabled,
|
||||||
|
'opacity-50 cursor-not-allowed': disabled,
|
||||||
|
'cursor-pointer': !disabled
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'text-neutral-900': isSelected(option) && !disabled,
|
||||||
|
'text-zinc-500': !isSelected(option) || disabled
|
||||||
|
}
|
||||||
|
)
|
||||||
|
"
|
||||||
|
:disabled="disabled"
|
||||||
|
@click="handleSelect(option)"
|
||||||
|
>
|
||||||
|
{{ getOptionLabel(option) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script
|
||||||
|
setup
|
||||||
|
lang="ts"
|
||||||
|
generic="T extends string | number | { label: string; value: any }"
|
||||||
|
>
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
|
|
||||||
|
import { WidgetInputBaseClass } from '../layout'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
modelValue: string | null | undefined
|
||||||
|
options: T[] // Now using generic type instead of any[]
|
||||||
|
optionLabel?: string // PrimeVue compatible prop
|
||||||
|
optionValue?: string // PrimeVue compatible prop
|
||||||
|
disabled?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
'update:modelValue': [value: string]
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
disabled: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
|
// handle both string/number arrays and object arrays with PrimeVue compatibility
|
||||||
|
const getOptionValue = (option: T, index: number): string => {
|
||||||
|
if (typeof option === 'object' && option !== null) {
|
||||||
|
// Use PrimeVue optionValue prop if provided, otherwise fallback to common fields
|
||||||
|
const valueField = props.optionValue ?? 'value'
|
||||||
|
const value =
|
||||||
|
(option as any)[valueField] ??
|
||||||
|
(option as any).value ??
|
||||||
|
(option as any).name ??
|
||||||
|
(option as any).label ??
|
||||||
|
index
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
|
return String(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for display with PrimeVue compatibility
|
||||||
|
const getOptionLabel = (option: T): string => {
|
||||||
|
if (typeof option === 'object' && option !== null) {
|
||||||
|
// Use PrimeVue optionLabel prop if provided, otherwise fallback to common fields
|
||||||
|
const labelField = props.optionLabel ?? 'label'
|
||||||
|
return (
|
||||||
|
(option as any)[labelField] ??
|
||||||
|
(option as any).label ??
|
||||||
|
(option as any).name ??
|
||||||
|
(option as any).value ??
|
||||||
|
String(option)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return String(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSelected = (option: T): boolean => {
|
||||||
|
const optionValue = getOptionValue(option, props.options.indexOf(option))
|
||||||
|
return optionValue === String(props.modelValue ?? '')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = (option: T) => {
|
||||||
|
if (props.disabled) return
|
||||||
|
|
||||||
|
const optionValue = getOptionValue(option, props.options.indexOf(option))
|
||||||
|
emit('update:modelValue', optionValue)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
export const WidgetInputBaseClass = [
|
||||||
|
// Background
|
||||||
|
'bg-zinc-500/10',
|
||||||
|
// Outline
|
||||||
|
'border-none',
|
||||||
|
'outline',
|
||||||
|
'outline-1',
|
||||||
|
'outline-offset-[-1px]',
|
||||||
|
'outline-zinc-300/10',
|
||||||
|
// Rounded
|
||||||
|
'!rounded-lg',
|
||||||
|
// Hover
|
||||||
|
'hover:outline-blue-500/80'
|
||||||
|
].join(' ')
|
||||||
@@ -23,6 +23,12 @@ const TYPE_TO_ENUM_MAP: Record<string, string> = {
|
|||||||
// Selection
|
// Selection
|
||||||
combo: WidgetType.COMBO,
|
combo: WidgetType.COMBO,
|
||||||
COMBO: WidgetType.COMBO,
|
COMBO: WidgetType.COMBO,
|
||||||
|
selectbutton: WidgetType.SELECTBUTTON,
|
||||||
|
SELECTBUTTON: WidgetType.SELECTBUTTON,
|
||||||
|
multiselect: WidgetType.MULTISELECT,
|
||||||
|
MULTISELECT: WidgetType.MULTISELECT,
|
||||||
|
treeselect: WidgetType.TREESELECT,
|
||||||
|
TREESELECT: WidgetType.TREESELECT,
|
||||||
|
|
||||||
// Boolean
|
// Boolean
|
||||||
toggle: WidgetType.TOGGLESWITCH,
|
toggle: WidgetType.TOGGLESWITCH,
|
||||||
@@ -32,6 +38,7 @@ const TYPE_TO_ENUM_MAP: Record<string, string> = {
|
|||||||
// Multiline text
|
// Multiline text
|
||||||
multiline: WidgetType.TEXTAREA,
|
multiline: WidgetType.TEXTAREA,
|
||||||
textarea: WidgetType.TEXTAREA,
|
textarea: WidgetType.TEXTAREA,
|
||||||
|
TEXTAREA: WidgetType.TEXTAREA,
|
||||||
customtext: WidgetType.TEXTAREA,
|
customtext: WidgetType.TEXTAREA,
|
||||||
MARKDOWN: WidgetType.MARKDOWN,
|
MARKDOWN: WidgetType.MARKDOWN,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user