| 175 | } |
| 176 | |
| 177 | function FieldError({ |
| 178 | className, |
| 179 | children, |
| 180 | errors, |
| 181 | ...props |
| 182 | }: React.ComponentProps<"div"> & { |
| 183 | errors?: Array<{ message?: string } | undefined>; |
| 184 | }) { |
| 185 | const content = useMemo(() => { |
| 186 | if (children) { |
| 187 | return children; |
| 188 | } |
| 189 | |
| 190 | if (!errors?.length) { |
| 191 | return null; |
| 192 | } |
| 193 | |
| 194 | // oxlint-disable-next-line executor/no-unknown-error-message -- boundary: FieldError receives typed UI validation messages, not thrown errors |
| 195 | const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()]; |
| 196 | |
| 197 | if (uniqueErrors?.length == 1) { |
| 198 | // oxlint-disable-next-line executor/no-unknown-error-message -- boundary: FieldError receives typed UI validation messages, not thrown errors |
| 199 | return uniqueErrors[0]?.message; |
| 200 | } |
| 201 | |
| 202 | return ( |
| 203 | <ul className="ml-4 flex list-disc flex-col gap-1"> |
| 204 | {/* oxlint-disable-next-line executor/no-unknown-error-message -- boundary: FieldError receives typed UI validation messages, not thrown errors */} |
| 205 | {uniqueErrors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)} |
| 206 | </ul> |
| 207 | ); |
| 208 | }, [children, errors]); |
| 209 | |
| 210 | if (!content) { |
| 211 | return null; |
| 212 | } |
| 213 | |
| 214 | return ( |
| 215 | <div |
| 216 | role="alert" |
| 217 | data-slot="field-error" |
| 218 | className={cn("text-sm font-normal text-destructive", className)} |
| 219 | {...props} |
| 220 | > |
| 221 | {content} |
| 222 | </div> |
| 223 | ); |
| 224 | } |
| 225 | |
| 226 | export { |
| 227 | Field, |