diff --git a/.changeset/curvy-parts-invite.md b/.changeset/curvy-parts-invite.md new file mode 100644 index 0000000000..f5ff7a26cc --- /dev/null +++ b/.changeset/curvy-parts-invite.md @@ -0,0 +1,5 @@ +--- +"@effect-app/vue-components": minor +--- + +Adds custom class names to inputs diff --git a/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts b/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts index 2700a8be77..d2afbd7282 100644 --- a/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts +++ b/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts @@ -25,6 +25,13 @@ export type BaseProps = DeepKeys> = { validators?: FieldValidators // Use FlexibleArrayPath: if name contains [], just use TName; otherwise intersect with Leaves name: FlexibleArrayPath extends never ? Leaves : TName + /** + * Optional class to apply to the input element. + * - If a string is provided, it will be used instead of the general class + * - If null is provided, no class will be applied (neither inputClass nor general class) + * - If undefined (not provided), the general class will be used + */ + inputClass?: string | null } export type TypesWithOptions = "radio" | "select" | "multiple" | "autocomplete" | "autocompletemultiple" diff --git a/packages/vue-components/src/components/OmegaForm/OmegaInternalInput.vue b/packages/vue-components/src/components/OmegaForm/OmegaInternalInput.vue index 82ab17a9e8..db008d1ae5 100644 --- a/packages/vue-components/src/components/OmegaForm/OmegaInternalInput.vue +++ b/packages/vue-components/src/components/OmegaForm/OmegaInternalInput.vue @@ -3,7 +3,7 @@
@@ -15,7 +15,7 @@ generic="From extends Record, Name extends DeepKeys" > import { type DeepKeys, useStore } from "@tanstack/vue-form" -import { computed, type ComputedRef, getCurrentInstance, useId } from "vue" +import { computed, type ComputedRef, getCurrentInstance, useAttrs, useId } from "vue" import type { InputProps, OmegaFieldInternalApi } from "./InputProps" import type { FieldValidators, MetaRecord, NestedKeyOf, TypeOverride } from "./OmegaFormStuff" import OmegaInputVuetify from "./OmegaInputVuetify.vue" @@ -33,6 +33,7 @@ const props = withDefaults( type?: TypeOverride validators?: FieldValidators required?: boolean + inputClass?: string | null register: ( field: ComputedRef<{ @@ -49,7 +50,8 @@ const props = withDefaults( required: undefined, type: undefined, options: undefined, - validators: undefined + validators: undefined, + inputClass: undefined } ) @@ -57,6 +59,20 @@ const isRequired = computed(() => props.required ?? props?.meta?.required) const instance = getCurrentInstance() const vuetified = instance?.appContext.components["VTextField"] +const attrs = useAttrs() + +// Compute the class to use based on inputClass prop +const computedClass = computed(() => { + if (props.inputClass === null) return undefined + if (props.inputClass !== undefined) return props.inputClass + return attrs.class +}) + +// Create attrs without the class property to avoid duplication +const attrsWithoutClass = computed(() => { + const { class: _, ...rest } = attrs + return rest +}) const id = useId() @@ -75,7 +91,6 @@ const fieldType = computed(() => { props.register(computed(() => ({ name: props.field.name, label: props.label, id }))) -const fieldValue = computed(() => fieldState.value.value) // workaround strange tanstack form issue where the errors key becomes undefined ??? const _errors = computed(() => fieldState.value.meta.errors ?? []) const errors = computed(() => diff --git a/packages/vue-components/stories/OmegaForm.stories.ts b/packages/vue-components/stories/OmegaForm.stories.ts index 7642e7e172..5d8a259b39 100644 --- a/packages/vue-components/stories/OmegaForm.stories.ts +++ b/packages/vue-components/stories/OmegaForm.stories.ts @@ -9,6 +9,7 @@ import BooleansComponent from "./OmegaForm/Booleans.vue" import ClearableComponent from "./OmegaForm/Clearable.vue" import ComplexFormComponent from "./OmegaForm/ComplexForm.vue" import CreateUseFormWithCustomInputComponent from "./OmegaForm/CreateUseFormWithCustomInput.vue" +import CustomInputClassNameComponent from "./OmegaForm/CustomInputClassName.vue" import DateComponent from "./OmegaForm/Date.vue" import DialogBlockingExamplesComponent from "./OmegaForm/DialogBlockingExamples.vue" import EmailFormComponent from "./OmegaForm/EmailForm.vue" @@ -222,3 +223,10 @@ export const WindowExitPrevention: Story = { template: "" }) } + +export const CustomInputClassName: Story = { + render: () => ({ + components: { CustomInputClassNameComponent }, + template: "" + }) +} diff --git a/packages/vue-components/stories/OmegaForm/CustomInput.vue b/packages/vue-components/stories/OmegaForm/CustomInput.vue index 5439022487..e8ca2be886 100644 --- a/packages/vue-components/stories/OmegaForm/CustomInput.vue +++ b/packages/vue-components/stories/OmegaForm/CustomInput.vue @@ -1,9 +1,11 @@