[Feature] Add InputKnob component and integrate with FormItem (#2821)

This commit is contained in:
Miguel C
2025-03-03 09:54:16 -06:00
committed by GitHub
parent a38a11f397
commit 82a8aba704
3 changed files with 98 additions and 0 deletions

View File

@@ -39,6 +39,7 @@ import { type Component, markRaw } from 'vue'
import CustomFormValue from '@/components/common/CustomFormValue.vue'
import FormColorPicker from '@/components/common/FormColorPicker.vue'
import FormImageUpload from '@/components/common/FormImageUpload.vue'
import InputKnob from '@/components/common/InputKnob.vue'
import InputSlider from '@/components/common/InputSlider.vue'
import UrlInput from '@/components/common/UrlInput.vue'
import { FormItem } from '@/types/settingTypes'
@@ -91,6 +92,8 @@ function getFormComponent(item: FormItem): Component {
return InputNumber
case 'slider':
return InputSlider
case 'knob':
return InputKnob
case 'combo':
return Select
case 'image':
@@ -111,6 +114,11 @@ function getFormComponent(item: FormItem): Component {
@apply w-20;
}
.form-input :deep(.input-knob) .p-inputnumber input,
.form-input :deep(.input-knob) .knob-part {
@apply w-32;
}
.form-input :deep(.p-inputtext),
.form-input :deep(.p-select) {
@apply w-44;

View File

@@ -0,0 +1,89 @@
<template>
<div class="input-knob flex flex-row items-center gap-2">
<Knob
:modelValue="modelValue"
@update:modelValue="updateValue"
:valueTemplate="displayValue"
class="knob-part"
:class="knobClass"
:min="min"
:max="max"
:step="step"
v-bind="$attrs"
/>
<InputNumber
:modelValue="modelValue"
@update:modelValue="updateValue"
class="input-part"
:max-fraction-digits="3"
:class="inputClass"
:min="min"
:max="max"
:step="step"
:allowEmpty="false"
/>
</div>
</template>
<script setup lang="ts">
import InputNumber from 'primevue/inputnumber'
import Knob from 'primevue/knob'
import { ref, watch } from 'vue'
const props = defineProps<{
modelValue: number
inputClass?: string
knobClass?: string
min?: number
max?: number
step?: number
resolution?: number
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: number): void
}>()
const localValue = ref(props.modelValue)
watch(
() => props.modelValue,
(newValue) => {
localValue.value = newValue
}
)
const updateValue = (newValue: number | null) => {
if (newValue === null) {
// If the input is cleared, reset to the minimum value or 0
newValue = Number(props.min) || 0
}
const min = Number(props.min ?? Number.NEGATIVE_INFINITY)
const max = Number(props.max ?? Number.POSITIVE_INFINITY)
const step = Number(props.step) || 1
// Ensure the value is within the allowed range
newValue = Math.max(min, Math.min(max, newValue))
// Round to the nearest step
newValue = Math.round(newValue / step) * step
// Update local value and emit change
localValue.value = newValue
emit('update:modelValue', newValue)
}
const displayValue = (value: number): string => {
updateValue(value)
const stepString = props.step.toString()
const resolution = stepString.includes('.')
? stepString.split('.')[1].length
: 0
return value.toFixed(props.resolution ?? resolution)
}
defineOptions({
inheritAttrs: false
})
</script>

View File

@@ -4,6 +4,7 @@ export type SettingInputType =
| 'boolean'
| 'number'
| 'slider'
| 'knob'
| 'combo'
| 'text'
| 'image'