chore: ⬆️ Upgrade to Nuxt 4
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 1s
Deploy to GitHub Pages / build (push) Failing after 1s
Deploy to GitHub Pages / deploy (push) Has been skipped
Docker / build (push) Failing after 1s
Mirror to Codeberg / Mirror (push) Failing after 1s

This commit is contained in:
Jesse Wierzbinski 2025-07-16 07:48:39 +02:00
parent 8debe97f63
commit 7f7cf20311
386 changed files with 2376 additions and 2332 deletions

View file

@ -0,0 +1,17 @@
<script lang="ts" setup>
import { Slot } from "reka-ui";
import { useFormField } from "./useFormField";
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
</script>
<template>
<Slot
:id="formItemId"
data-slot="form-control"
:aria-describedby="!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`"
:aria-invalid="!!error"
>
<slot />
</Slot>
</template>

View file

@ -0,0 +1,21 @@
<script lang="ts" setup>
import type { HTMLAttributes } from "vue";
import { cn } from "@/lib/utils";
import { useFormField } from "./useFormField";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
const { formDescriptionId } = useFormField();
</script>
<template>
<p
:id="formDescriptionId"
data-slot="form-description"
:class="cn('text-muted-foreground text-sm', props.class)"
>
<slot />
</p>
</template>

View file

@ -0,0 +1,22 @@
<script lang="ts" setup>
import { useId } from "reka-ui";
import { type HTMLAttributes, provide } from "vue";
import { cn } from "@/lib/utils";
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
const id = useId();
provide(FORM_ITEM_INJECTION_KEY, id);
</script>
<template>
<div
data-slot="form-item"
:class="cn('grid gap-2', props.class)"
>
<slot />
</div>
</template>

View file

@ -0,0 +1,25 @@
<script lang="ts" setup>
import type { LabelProps } from "reka-ui";
import type { HTMLAttributes } from "vue";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
import { useFormField } from "./useFormField";
const props = defineProps<LabelProps & { class?: HTMLAttributes["class"] }>();
const { error, formItemId } = useFormField();
</script>
<template>
<Label
data-slot="form-label"
:data-error="!!error"
:class="cn(
'data-[error=true]:text-destructive-foreground',
props.class,
)"
:for="formItemId"
>
<slot />
</Label>
</template>

View file

@ -0,0 +1,22 @@
<script lang="ts" setup>
import { ErrorMessage } from "vee-validate";
import { type HTMLAttributes, toValue } from "vue";
import { cn } from "@/lib/utils";
import { useFormField } from "./useFormField";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
const { name, formMessageId } = useFormField();
</script>
<template>
<ErrorMessage
:id="formMessageId"
data-slot="form-message"
as="p"
:name="toValue(name)"
:class="cn('text-destructive-foreground text-sm', props.class)"
/>
</template>

View file

@ -0,0 +1,11 @@
export {
Field as FormField,
FieldArray as FormFieldArray,
Form,
} from "vee-validate";
export { default as FormControl } from "./FormControl.vue";
export { default as FormDescription } from "./FormDescription.vue";
export { default as FormItem } from "./FormItem.vue";
export { default as FormLabel } from "./FormLabel.vue";
export { default as FormMessage } from "./FormMessage.vue";
export { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";

View file

@ -0,0 +1,3 @@
import type { InjectionKey } from "vue";
export const FORM_ITEM_INJECTION_KEY = Symbol() as InjectionKey<string>;

View file

@ -0,0 +1,37 @@
import {
FieldContextKey,
useFieldError,
useIsFieldDirty,
useIsFieldTouched,
useIsFieldValid,
} from "vee-validate";
import { inject } from "vue";
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";
export function useFormField() {
const fieldContext = inject(FieldContextKey);
const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY);
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>");
}
const { name } = fieldContext;
const id = fieldItemContext;
const fieldState = {
valid: useIsFieldValid(name),
isDirty: useIsFieldDirty(name),
isTouched: useIsFieldTouched(name),
error: useFieldError(name),
};
return {
id,
name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
};
}