新增通道列表查询页面

This commit is contained in:
2025-04-28 17:41:54 +08:00
parent b20ec85db9
commit b44888a6d7
16 changed files with 290 additions and 117 deletions

View File

@@ -1,5 +1,4 @@
'use client'
import * as LabelPrimitive from '@radix-ui/react-label'
import {Slot} from '@radix-ui/react-slot'
import {
@@ -8,13 +7,13 @@ import {
ControllerProps,
SubmitHandler,
FieldValues, useFormContext, FieldPath, UseFormReturn, ControllerRenderProps,
ControllerFieldState, UseFormStateReturn, FieldError, FieldErrors, SubmitErrorHandler,
ControllerFieldState, UseFormStateReturn, FieldError, SubmitErrorHandler,
} from 'react-hook-form'
import {merge} from '@/lib/utils'
import {Label} from '@/components/ui/label'
import React, {BaseSyntheticEvent, ComponentProps, createContext, ReactNode, useContext, useId} from 'react'
import React, {ComponentProps, createContext, ReactNode, useContext, useId} from 'react'
type FormProps<T extends FieldValues> = {
form: UseFormReturn<T>
@@ -60,13 +59,6 @@ type FormFieldProps<
}) => ReactNode
} & Omit<ControllerProps<V, N>, 'control' | 'render'>
type FormFieldContext = {
id: string
error?: FieldError
}
const FormFieldContext = createContext<FormFieldContext | null>(null)
function FormField<
V extends FieldValues = FieldValues,
N extends FieldPath<V> = FieldPath<V>,
@@ -76,68 +68,48 @@ function FormField<
return (
<Controller<V, N> name={props.name} control={form.control} render={({field, fieldState, formState}) => (
<div data-slot="form-field" className={merge('grid gap-2', props.className)}>
<FormFieldContext value={{id: id, error: fieldState.error}}>
{!!props.label &&
<Label
data-slot="form-label"
data-fail={!!fieldState.error}
className={merge('data-[error=true]:text-fail')}
htmlFor={id}>
{props.label}
</Label>
}
{!!props.label &&
<FormLabel error={fieldState.error}>
{props.label}
</FormLabel>
}
<Slot
data-slot="form-control"
aria-invalid={!!fieldState.error}
aria-describedby={
!!fieldState.error
? `${id}-description`
: `${id}-description ${id}-message`
}>
{props.children({id, field, fieldState, formState})}
</Slot>
<Slot
data-slot="form-control"
aria-invalid={!!fieldState.error}
aria-describedby={
!!fieldState.error
? `${id}-description`
: `${id}-description ${id}-message`
}>
{props.children({id, field, fieldState, formState})}
</Slot>
{!fieldState.error ? null : (
<p
data-slot="form-message"
className={merge('text-fail text-sm')}>
{fieldState.error?.message}
</p>
)}
</FormFieldContext>
{!fieldState.error ? null : (
<FormMessage error={fieldState.error}/>
)}
</div>
)}
/>
)}/>
)
}
const useFormField = () => {
const context = useContext(FormFieldContext)
if (!context) {
throw new Error('FormField components must be used within a FormField component')
}
return context
type FormState = {
error?: FieldError
}
function FormLabel({className, ...props}: ComponentProps<typeof LabelPrimitive.Root>) {
const {id, error} = useFormField()
function FormLabel({className, id, error, ...props}: ComponentProps<typeof LabelPrimitive.Root> & FormState) {
return (
<Label
data-slot="form-label"
data-fail={!!error}
className={merge('data-[error=true]:text-fail', className)}
className={merge('data-[fail=true]:text-fail', className)}
htmlFor={id}
{...props}
/>
)
}
function FormDescription({className, ...props}: ComponentProps<'p'>) {
const {id} = useFormField()
function FormDescription({className, id, error, ...props}: ComponentProps<'p'> & FormState) {
return (
<p
data-slot="form-description"
@@ -148,8 +120,7 @@ function FormDescription({className, ...props}: ComponentProps<'p'>) {
)
}
function FormMessage({className, ...props}: ComponentProps<'p'>) {
const {id, error} = useFormField()
function FormMessage({className, id, error, ...props}: ComponentProps<'p'> & FormState) {
const body = error ? String(error?.message ?? '') : props.children
if (!body) {