chore(module): lint

This commit is contained in:
Benjamin Canac
2024-04-12 14:02:23 +02:00
parent 74a640ceca
commit abb7580f71
22 changed files with 112 additions and 116 deletions

View File

@@ -21,7 +21,7 @@ export default defineNuxtModule<ModuleOptions>({
prefix: 'U', prefix: 'U',
colors: undefined colors: undefined
}, },
async setup (options, nuxt) { async setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url) const { resolve } = createResolver(import.meta.url)
options.colors = options.colors || ['primary', 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchia', 'pink', 'rose'] options.colors = options.colors || ['primary', 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchia', 'pink', 'rose']

View File

@@ -52,7 +52,7 @@ const inputId = _inputId.value ?? useId()
const modelValue = defineModel<boolean | undefined>({ const modelValue = defineModel<boolean | undefined>({
default: undefined, default: undefined,
set (value) { set(value) {
return value return value
} }
}) })
@@ -60,10 +60,10 @@ const modelValue = defineModel<boolean | undefined>({
const indeterminate = computed(() => (modelValue.value === undefined && props.indeterminate)) const indeterminate = computed(() => (modelValue.value === undefined && props.indeterminate))
const checked = computed({ const checked = computed({
get () { get() {
return indeterminate.value ? 'indeterminate' : modelValue.value return indeterminate.value ? 'indeterminate' : modelValue.value
}, },
set (value) { set(value) {
modelValue.value = value === 'indeterminate' ? undefined : value modelValue.value = value === 'indeterminate' ? undefined : value
} }
}) })
@@ -71,7 +71,7 @@ const checked = computed({
// FIXME: I think there's a race condition between this and the v-model event. // FIXME: I think there's a race condition between this and the v-model event.
// This must be triggered after the value updates, otherwise the form validates // This must be triggered after the value updates, otherwise the form validates
// the previous value. // the previous value.
function onChecked () { function onChecked() {
emitFormChange() emitFormChange()
} }

View File

@@ -14,7 +14,7 @@ export interface FormProps<T extends object> {
id?: string | number id?: string | number
schema?: FormSchema<T> schema?: FormSchema<T>
state: Partial<T> state: Partial<T>
validate?: (state: Partial<T>) => Promise<FormError[] | void> validate?: (state: Partial<T>) => Promise<FormError[]>
validateOn?: FormInputEvents[] validateOn?: FormInputEvents[]
disabled?: boolean disabled?: boolean
validateOnInputDelay?: number validateOnInputDelay?: number
@@ -38,7 +38,7 @@ import { useId } from '#imports'
import { getYupErrors, isYupSchema, getValibotError, isValibotSchema, getZodErrors, isZodSchema, getJoiErrors, isJoiSchema } from '#ui/utils/form' import { getYupErrors, isYupSchema, getValibotError, isValibotSchema, getZodErrors, isZodSchema, getJoiErrors, isJoiSchema } from '#ui/utils/form'
const props = withDefaults(defineProps<FormProps<T>>(), { const props = withDefaults(defineProps<FormProps<T>>(), {
validateOn () { validateOn() {
return ['input', 'blur', 'change'] as FormInputEvents[] return ['input', 'blur', 'change'] as FormInputEvents[]
}, },
validateOnInputDelay: 300 validateOnInputDelay: 300
@@ -55,7 +55,6 @@ const parentBus = inject<UseEventBusReturn<FormEvent, string> | undefined>(
) )
provide('form-events', bus) provide('form-events', bus)
const nestedForms = ref<Map<string | number, { validate: () => any }>>(new Map()) const nestedForms = ref<Map<string | number, { validate: () => any }>>(new Map())
onMounted(async () => { onMounted(async () => {
@@ -98,14 +97,14 @@ provide('form-errors', errors)
const inputs = ref<Record<string, string>>({}) const inputs = ref<Record<string, string>>({})
provide('form-inputs', inputs) provide('form-inputs', inputs)
function resolveErrorIds (errs: FormError[]): FormErrorWithId[] { function resolveErrorIds(errs: FormError[]): FormErrorWithId[] {
return errs.map((err) => ({ return errs.map(err => ({
...err, ...err,
id: inputs.value[err.name] id: inputs.value[err.name]
})) }))
} }
async function getErrors (): Promise<FormErrorWithId[]> { async function getErrors(): Promise<FormErrorWithId[]> {
let errs = props.validate ? (await props.validate(props.state)) ?? [] : [] let errs = props.validate ? (await props.validate(props.state)) ?? [] : []
if (props.schema) { if (props.schema) {
@@ -125,26 +124,23 @@ async function getErrors (): Promise<FormErrorWithId[]> {
return resolveErrorIds(errs) return resolveErrorIds(errs)
} }
async function _validate ( async function _validate(opts: { name?: string | string[], silent?: boolean, nested?: boolean } = { silent: false, nested: true }): Promise<T | false> {
opts: { name?: string | string[], silent?: boolean, nested?: boolean } = { silent: false, nested: true }
): Promise<T | false> {
const names = opts.name && !Array.isArray(opts.name) ? [opts.name] : opts.name const names = opts.name && !Array.isArray(opts.name) ? [opts.name] : opts.name
const nestedValidatePromises = !names && opts.nested ? Array.from(nestedForms.value.values()).map( const nestedValidatePromises = !names && opts.nested
({ validate }) => validate().then(() => undefined).catch((error: Error) => { ? Array.from(nestedForms.value.values()).map(
if (!(error instanceof FormValidationException)) { ({ validate }) => validate().then(() => undefined).catch((error: Error) => {
throw error if (!(error instanceof FormValidationException)) {
} throw error
return error }
}) return error
) : [] })
)
: []
if (names) { if (names) {
const otherErrors = errors.value.filter( const otherErrors = errors.value.filter(error => !names!.includes(error.name))
(error) => !names!.includes(error.name) const pathErrors = (await getErrors()).filter(error => names!.includes(error.name)
)
const pathErrors = (await getErrors()).filter((error) =>
names!.includes(error.name)
) )
errors.value = otherErrors.concat(pathErrors) errors.value = otherErrors.concat(pathErrors)
} else { } else {
@@ -160,7 +156,7 @@ async function _validate (
return props.state as T return props.state as T
} }
async function onSubmit (payload: Event) { async function onSubmit(payload: Event) {
const event = payload as SubmitEvent const event = payload as SubmitEvent
try { try {
@@ -170,7 +166,6 @@ async function onSubmit (payload: Event) {
data: props.state data: props.state
} }
emit('submit', submitEvent) emit('submit', submitEvent)
} catch (error) { } catch (error) {
if (!(error instanceof FormValidationException)) { if (!(error instanceof FormValidationException)) {
throw error throw error
@@ -190,30 +185,30 @@ defineExpose<Form<T>>({
validate: _validate, validate: _validate,
errors, errors,
setErrors (errs: FormError[], name?: string) { setErrors(errs: FormError[], name?: string) {
if (name) { if (name) {
errors.value = errors.value errors.value = errors.value
.filter((error) => error.name !== name) .filter(error => error.name !== name)
.concat(resolveErrorIds(errs)) .concat(resolveErrorIds(errs))
} else { } else {
errors.value = resolveErrorIds(errs) errors.value = resolveErrorIds(errs)
} }
}, },
async submit () { async submit() {
await onSubmit(new Event('submit')) await onSubmit(new Event('submit'))
}, },
getErrors (name?: string) { getErrors(name?: string) {
if (name) { if (name) {
return errors.value.filter((err) => err.name === name) return errors.value.filter(err => err.name === name)
} }
return errors.value return errors.value
}, },
clear (name?: string) { clear(name?: string) {
if (name) { if (name) {
errors.value = errors.value.filter((err) => err.name !== name) errors.value = errors.value.filter(err => err.name !== name)
} else { } else {
errors.value = [] errors.value = []
} }

View File

@@ -52,10 +52,10 @@ const ui = computed(() => tv({ extend: formField, slots: props.ui })({
const formErrors = inject<Ref<FormError[]> | null>('form-errors', null) const formErrors = inject<Ref<FormError[]> | null>('form-errors', null)
const error = computed(() => { const error = computed(() => {
return (props.error && typeof props.error === 'string') || return (props.error && typeof props.error === 'string')
typeof props.error === 'boolean' || typeof props.error === 'boolean'
? props.error ? props.error
: formErrors?.value?.find((error) => error.name === props.name)?.message : formErrors?.value?.find(error => error.name === props.name)?.message
}) })
const inputId = ref(useId()) const inputId = ref(useId())

View File

@@ -73,14 +73,14 @@ const ui = computed(() => tv({ extend: input, slots: props.ui })({
const inputRef = ref<HTMLInputElement | null>(null) const inputRef = ref<HTMLInputElement | null>(null)
function autoFocus () { function autoFocus() {
if (props.autofocus) { if (props.autofocus) {
inputRef.value?.focus() inputRef.value?.focus()
} }
} }
// Custom function to handle the v-model properties // Custom function to handle the v-model properties
function updateInput (value: string) { function updateInput(value: string) {
if (modelModifiers.trim) { if (modelModifiers.trim) {
value = value.trim() value = value.trim()
} }
@@ -93,13 +93,13 @@ function updateInput (value: string) {
emitFormInput() emitFormInput()
} }
function onInput (event: Event) { function onInput(event: Event) {
if (!modelModifiers.lazy) { if (!modelModifiers.lazy) {
updateInput((event.target as HTMLInputElement).value) updateInput((event.target as HTMLInputElement).value)
} }
} }
function onChange (event: Event) { function onChange(event: Event) {
const value = (event.target as HTMLInputElement).value const value = (event.target as HTMLInputElement).value
if (modelModifiers.lazy) { if (modelModifiers.lazy) {
@@ -112,7 +112,7 @@ function onChange (event: Event) {
} }
} }
function onBlur (event: FocusEvent) { function onBlur(event: FocusEvent) {
emitFormBlur() emitFormBlur()
emit('blur', event) emit('blur', event)
} }

View File

@@ -55,7 +55,7 @@ const ui = computed(() => tv({
} }
})) }))
function isLinkActive (slotProps: any) { function isLinkActive(slotProps: any) {
if (props.active !== undefined) { if (props.active !== undefined) {
return props.active return props.active
} }
@@ -78,7 +78,7 @@ function isLinkActive (slotProps: any) {
return false return false
} }
function resolveLinkClass (slotProps: any) { function resolveLinkClass(slotProps: any) {
const active = isLinkActive(slotProps) const active = isLinkActive(slotProps)
if (props.raw) { if (props.raw) {

View File

@@ -23,7 +23,7 @@ const props = withDefaults(defineProps<LinkBaseProps>(), {
type: 'button' type: 'button'
}) })
function onClick (e: MouseEvent) { function onClick(e: MouseEvent) {
if (props.disabled) { if (props.disabled) {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
@@ -43,10 +43,10 @@ function onClick (e: MouseEvent) {
<template> <template>
<Primitive <Primitive
v-bind="href ? { v-bind="href ? {
as: 'a', 'as': 'a',
href: disabled ? undefined : href, 'href': disabled ? undefined : href,
'aria-disabled': disabled ? 'true' : undefined, 'aria-disabled': disabled ? 'true' : undefined,
role: disabled ? 'link' : undefined 'role': disabled ? 'link' : undefined
} : as === 'button' ? { } : as === 'button' ? {
as, as,
type, type,

View File

@@ -58,8 +58,8 @@ const contentProps = toRef(() => props.content)
const contentEvents = computed(() => { const contentEvents = computed(() => {
if (props.preventClose) { if (props.preventClose) {
return { return {
'pointerDownOutside': (e: Event) => e.preventDefault(), pointerDownOutside: (e: Event) => e.preventDefault(),
'interactOutside': (e: Event) => e.preventDefault() interactOutside: (e: Event) => e.preventDefault()
} }
} }

View File

@@ -9,7 +9,7 @@ const appConfig = _appConfig as AppConfig & { ui: { popover: Partial<typeof them
const popover = tv({ extend: tv(theme), ...(appConfig.ui?.popover || {}) }) const popover = tv({ extend: tv(theme), ...(appConfig.ui?.popover || {}) })
export interface PopoverProps extends PopoverRootProps, Pick<HoverCardRootProps, 'openDelay' | 'closeDelay'>{ export interface PopoverProps extends PopoverRootProps, Pick<HoverCardRootProps, 'openDelay' | 'closeDelay'> {
/** /**
* The mode of the popover. * The mode of the popover.
* @defaultValue "click" * @defaultValue "click"

View File

@@ -35,7 +35,7 @@ export type RadioGroupEmits = {
export interface RadioGroupSlots<T> { export interface RadioGroupSlots<T> {
legend(): any legend(): any
label(props: { option: RadioGroupOption<T> }): any label(props: { option: RadioGroupOption<T> }): any
description(props: { option: RadioGroupOption<T>}): any description(props: { option: RadioGroupOption<T> }): any
} }
</script> </script>
@@ -61,7 +61,7 @@ const ui = computed(() => tv({ extend: radioGroup, slots: props.ui })({
required: props.required required: props.required
})) }))
function normalizeOption (option: any) { function normalizeOption(option: any) {
if (['string', 'number', 'boolean'].includes(typeof option)) { if (['string', 'number', 'boolean'].includes(typeof option)) {
return { return {
id: `${inputId}:${option}`, id: `${inputId}:${option}`,
@@ -82,7 +82,7 @@ const normalizedOptions = computed(() => {
}) })
const modelValue = defineModel<T>({ const modelValue = defineModel<T>({
set (value) { set(value) {
emits('change', value) emits('change', value)
return value return value
} }
@@ -91,7 +91,7 @@ const modelValue = defineModel<T>({
// FIXME: I think there's a race condition between this and the v-model event. // FIXME: I think there's a race condition between this and the v-model event.
// This must be triggered after the value updates, otherwise the form validates // This must be triggered after the value updates, otherwise the form validates
// the previous value. // the previous value.
function onUpdate () { function onUpdate() {
emitFormChange() emitFormChange()
} }
</script> </script>

View File

@@ -61,8 +61,8 @@ const contentProps = toRef(() => props.content)
const contentEvents = computed(() => { const contentEvents = computed(() => {
if (props.preventClose) { if (props.preventClose) {
return { return {
'pointerDownOutside': (e: Event) => e.preventDefault(), pointerDownOutside: (e: Event) => e.preventDefault(),
'interactOutside': (e: Event) => e.preventDefault() interactOutside: (e: Event) => e.preventDefault()
} }
} }

View File

@@ -51,7 +51,7 @@ const ui = computed(() => tv({ extend: switchTv, slots: props.ui })({
// FIXME: I think there's a race condition between this and the v-model event. // FIXME: I think there's a race condition between this and the v-model event.
// This must be triggered after the value updates, otherwise the form validates // This must be triggered after the value updates, otherwise the form validates
// the previous value. // the previous value.
async function onChecked () { async function onChecked() {
emitFormChange() emitFormChange()
} }
</script> </script>

View File

@@ -65,14 +65,14 @@ const ui = computed(() => tv({ extend: textarea, slots: props.ui })({
const textareaRef = ref<HTMLTextAreaElement | null>(null) const textareaRef = ref<HTMLTextAreaElement | null>(null)
function autoFocus () { function autoFocus() {
if (props.autofocus) { if (props.autofocus) {
textareaRef.value?.focus() textareaRef.value?.focus()
} }
} }
// Custom function to handle the v-model properties // Custom function to handle the v-model properties
function updateInput (value: string) { function updateInput(value: string) {
if (modelModifiers.trim) { if (modelModifiers.trim) {
value = value.trim() value = value.trim()
} }
@@ -85,7 +85,7 @@ function updateInput (value: string) {
emitFormInput() emitFormInput()
} }
function onInput (event: Event) { function onInput(event: Event) {
autoResize() autoResize()
if (!modelModifiers.lazy) { if (!modelModifiers.lazy) {
@@ -93,7 +93,7 @@ function onInput (event: Event) {
} }
} }
function onChange (event: Event) { function onChange(event: Event) {
const value = (event.target as HTMLInputElement).value const value = (event.target as HTMLInputElement).value
if (modelModifiers.lazy) { if (modelModifiers.lazy) {
@@ -106,7 +106,7 @@ function onChange (event: Event) {
} }
} }
function onBlur (event: FocusEvent) { function onBlur(event: FocusEvent) {
emitFormBlur() emitFormBlur()
emit('blur', event) emit('blur', event)
} }
@@ -117,9 +117,8 @@ onMounted(() => {
}, props.autofocusDelay) }, props.autofocusDelay)
}) })
function autoResize () { function autoResize() {
if (props.autoresize) { if (props.autoresize) {
if (!textareaRef.value) { if (!textareaRef.value) {
return return
} }
@@ -127,10 +126,10 @@ function autoResize () {
textareaRef.value.rows = props.rows textareaRef.value.rows = props.rows
const styles = window.getComputedStyle(textareaRef.value) const styles = window.getComputedStyle(textareaRef.value)
const paddingTop = parseInt(styles.paddingTop) const paddingTop = Number.parseInt(styles.paddingTop)
const paddingBottom = parseInt(styles.paddingBottom) const paddingBottom = Number.parseInt(styles.paddingBottom)
const padding = paddingTop + paddingBottom const padding = paddingTop + paddingBottom
const lineHeight = parseInt(styles.lineHeight) const lineHeight = Number.parseInt(styles.lineHeight)
const { scrollHeight } = textareaRef.value const { scrollHeight } = textareaRef.value
const newRows = (scrollHeight - padding) / lineHeight const newRows = (scrollHeight - padding) / lineHeight

View File

@@ -40,16 +40,16 @@ const { toasts, remove } = useToast()
const swipeDirection = computed(() => { const swipeDirection = computed(() => {
switch (props.position) { switch (props.position) {
case 'top-center': case 'top-center':
return 'up' return 'up'
case 'top-right': case 'top-right':
case 'bottom-right': case 'bottom-right':
return 'right' return 'right'
case 'bottom-center': case 'bottom-center':
return 'down' return 'down'
case 'top-left': case 'top-left':
case 'bottom-left': case 'bottom-left':
return 'left' return 'left'
} }
return 'right' return 'right'
}) })
@@ -59,7 +59,7 @@ const ui = computed(() => tv({ extend: toaster, slots: props.ui })({
swipeDirection: swipeDirection.value swipeDirection: swipeDirection.value
})) }))
function onUpdateOpen (value: boolean, id: string | number) { function onUpdateOpen(value: boolean, id: string | number) {
if (value) { if (value) {
return return
} }
@@ -75,7 +75,7 @@ const refs = ref<{ height: number }[]>([])
const height = computed(() => refs.value.reduce((acc, { height }) => acc + height + 16, 0)) const height = computed(() => refs.value.reduce((acc, { height }) => acc + height + 16, 0))
const frontHeight = computed(() => refs.value[refs.value.length - 1]?.height || 0) const frontHeight = computed(() => refs.value[refs.value.length - 1]?.height || 0)
function getOffset (index: number) { function getOffset(index: number) {
return refs.value.slice(index + 1).reduce((acc, { height }) => acc + height + 16, 0) return refs.value.slice(index + 1).reduce((acc, { height }) => acc + height + 16, 0)
} }

View File

@@ -12,7 +12,7 @@ export interface UseComponentIconsProps {
loadingIcon?: IconProps['name'] loadingIcon?: IconProps['name']
} }
export function useComponentIcons (props: UseComponentIconsProps) { export function useComponentIcons(props: UseComponentIconsProps) {
const appConfig = useAppConfig() const appConfig = useAppConfig()
const isLeading = computed(() => (props.icon && props.leading) || (props.icon && !props.trailing) || (props.loading && !props.trailing && !props.trailingIcon) || !!props.leadingIcon) const isLeading = computed(() => (props.icon && props.leading) || (props.icon && !props.trailing) || (props.loading && !props.trailing && !props.trailingIcon) || !!props.leadingIcon)

View File

@@ -5,16 +5,16 @@ import type { FormEvent, FormInputEvents, FormFieldInjectedOptions, FormInjected
type Props<T> = { type Props<T> = {
id?: string id?: string
name?: string name?: string
// @ts-ignore FIXME: TS doesn't like this // @ts-expect-error FIXME: TS doesn't like this
size?: T['size'] size?: T['size']
// @ts-ignore FIXME: TS doesn't like this // @ts-expect-error FIXME: TS doesn't like this
color?: T['color'] color?: T['color']
eagerValidation?: boolean eagerValidation?: boolean
legend?: string legend?: string
disabled?: boolean disabled?: boolean
} }
export function useFormField <T> (inputProps?: Props<T>) { export function useFormField<T>(inputProps?: Props<T>) {
const formOptions = inject<FormInjectedOptions | undefined>('form-options', undefined) const formOptions = inject<FormInjectedOptions | undefined>('form-options', undefined)
const formBus = inject<UseEventBusReturn<FormEvent, string> | undefined>('form-events', undefined) const formBus = inject<UseEventBusReturn<FormEvent, string> | undefined>('form-events', undefined)
const formField = inject<FormFieldInjectedOptions<T> | undefined>('form-field', undefined) const formField = inject<FormFieldInjectedOptions<T> | undefined>('form-field', undefined)
@@ -33,18 +33,18 @@ export function useFormField <T> (inputProps?: Props<T>) {
const blurred = ref(false) const blurred = ref(false)
function emitFormEvent (type: FormInputEvents, name: string) { function emitFormEvent(type: FormInputEvents, name: string) {
if (formBus && formField) { if (formBus && formField) {
formBus.emit({ type, name }) formBus.emit({ type, name })
} }
} }
function emitFormBlur () { function emitFormBlur() {
emitFormEvent('blur', formField?.name.value as string) emitFormEvent('blur', formField?.name.value as string)
blurred.value = true blurred.value = true
} }
function emitFormChange () { function emitFormChange() {
emitFormEvent('change', formField?.name.value as string) emitFormEvent('change', formField?.name.value as string)
} }

View File

@@ -6,10 +6,10 @@ export interface Toast extends Omit<ToastProps, 'defaultOpen'> {
click?: (toast: Toast) => void click?: (toast: Toast) => void
} }
export function useToast () { export function useToast() {
const toasts = useState<Toast[]>('toasts', () => []) const toasts = useState<Toast[]>('toasts', () => [])
function add (toast: Partial<Toast>): Toast { function add(toast: Partial<Toast>): Toast {
const body = { const body = {
id: new Date().getTime().toString(), id: new Date().getTime().toString(),
open: true, open: true,
@@ -26,7 +26,7 @@ export function useToast () {
return body return body
} }
function update (id: string | number, toast: Partial<Toast>) { function update(id: string | number, toast: Partial<Toast>) {
const index = toasts.value.findIndex((t: Toast) => t.id === id) const index = toasts.value.findIndex((t: Toast) => t.id === id)
if (index !== -1) { if (index !== -1) {
toasts.value[index] = { toasts.value[index] = {
@@ -36,7 +36,7 @@ export function useToast () {
} }
} }
function remove (id: string | number) { function remove(id: string | number) {
const index = toasts.value.findIndex((t: Toast) => t.id === id) const index = toasts.value.findIndex((t: Toast) => t.id === id)
if (index !== -1) { if (index !== -1) {
toasts.value[index] = { toasts.value[index] = {

View File

@@ -1,5 +1,6 @@
declare module '#build/app.config' { declare module '#build/app.config' {
import type { AppConfig } from '@nuxt/schema' import type { AppConfig } from '@nuxt/schema'
const _default: AppConfig const _default: AppConfig
export default _default export default _default
} }

View File

@@ -71,7 +71,7 @@ export interface FormInjectedOptions {
export interface FormFieldInjectedOptions<T> { export interface FormFieldInjectedOptions<T> {
inputId: Ref<string | undefined> inputId: Ref<string | undefined>
name: ComputedRef<string | undefined> name: ComputedRef<string | undefined>
// @ts-ignore FIXME: TS doesn't like this // @ts-expect-error FIXME: TS doesn't like this
size: ComputedRef<T['size']> size: ComputedRef<T['size']>
error: ComputedRef<string | boolean | undefined> error: ComputedRef<string | boolean | undefined>
eagerValidation: ComputedRef<boolean | undefined> eagerValidation: ComputedRef<boolean | undefined>
@@ -83,7 +83,7 @@ export class FormValidationException extends Error {
errors: FormErrorWithId[] errors: FormErrorWithId[]
childrens: FormValidationException[] childrens: FormValidationException[]
constructor (formId: string | number, errors: FormErrorWithId[], childErrors: FormValidationException[]) { constructor(formId: string | number, errors: FormErrorWithId[], childErrors: FormValidationException[]) {
super('Form validation exception') super('Form validation exception')
this.formId = formId this.formId = formId
this.errors = errors this.errors = errors

View File

@@ -4,21 +4,21 @@ import type { ObjectSchema as YupObjectSchema, ValidationError as YupError } fro
import type { ObjectSchemaAsync as ValibotObjectSchema } from 'valibot' import type { ObjectSchemaAsync as ValibotObjectSchema } from 'valibot'
import type { FormError } from '#ui/types/form' import type { FormError } from '#ui/types/form'
export function isYupSchema (schema: any): schema is YupObjectSchema<any> { export function isYupSchema(schema: any): schema is YupObjectSchema<any> {
return schema.validate && schema.__isYupSchema__ return schema.validate && schema.__isYupSchema__
} }
export function isYupError (error: any): error is YupError { export function isYupError(error: any): error is YupError {
return error.inner !== undefined return error.inner !== undefined
} }
export async function getYupErrors (state: any, schema: YupObjectSchema<any>): Promise<FormError[]> { export async function getYupErrors(state: any, schema: YupObjectSchema<any>): Promise<FormError[]> {
try { try {
await schema.validate(state, { abortEarly: false }) await schema.validate(state, { abortEarly: false })
return [] return []
} catch (error) { } catch (error) {
if (isYupError(error)) { if (isYupError(error)) {
return error.inner.map((issue) => ({ return error.inner.map(issue => ({
name: issue.path ?? '', name: issue.path ?? '',
message: issue.message message: issue.message
})) }))
@@ -28,14 +28,14 @@ export async function getYupErrors (state: any, schema: YupObjectSchema<any>): P
} }
} }
export function isZodSchema (schema: any): schema is ZodSchema { export function isZodSchema(schema: any): schema is ZodSchema {
return schema.parse !== undefined return schema.parse !== undefined
} }
export async function getZodErrors (state: any, schema: ZodSchema): Promise<FormError[]> { export async function getZodErrors(state: any, schema: ZodSchema): Promise<FormError[]> {
const result = await schema.safeParseAsync(state) const result = await schema.safeParseAsync(state)
if (result.success === false) { if (result.success === false) {
return result.error.issues.map((issue) => ({ return result.error.issues.map(issue => ({
name: issue.path.join('.'), name: issue.path.join('.'),
message: issue.message message: issue.message
})) }))
@@ -43,21 +43,21 @@ export async function getZodErrors (state: any, schema: ZodSchema): Promise<Form
return [] return []
} }
export function isJoiSchema (schema: any): schema is JoiSchema { export function isJoiSchema(schema: any): schema is JoiSchema {
return schema.validateAsync !== undefined && schema.id !== undefined return schema.validateAsync !== undefined && schema.id !== undefined
} }
export function isJoiError (error: any): error is JoiError { export function isJoiError(error: any): error is JoiError {
return error.isJoi === true return error.isJoi === true
} }
export async function getJoiErrors (state: any, schema: JoiSchema): Promise<FormError[]> { export async function getJoiErrors(state: any, schema: JoiSchema): Promise<FormError[]> {
try { try {
await schema.validateAsync(state, { abortEarly: false }) await schema.validateAsync(state, { abortEarly: false })
return [] return []
} catch (error) { } catch (error) {
if (isJoiError(error)) { if (isJoiError(error)) {
return error.details.map((detail) => ({ return error.details.map(detail => ({
name: detail.path.join('.'), name: detail.path.join('.'),
message: detail.message message: detail.message
})) }))
@@ -67,15 +67,15 @@ export async function getJoiErrors (state: any, schema: JoiSchema): Promise<Form
} }
} }
export function isValibotSchema (schema: any): schema is ValibotObjectSchema<any> { export function isValibotSchema(schema: any): schema is ValibotObjectSchema<any> {
return schema._parse !== undefined return schema._parse !== undefined
} }
export async function getValibotError (state: any, schema: ValibotObjectSchema<any>): Promise<FormError[]> { export async function getValibotError(state: any, schema: ValibotObjectSchema<any>): Promise<FormError[]> {
const result = await schema._parse(state) const result = await schema._parse(state)
if (result.issues) { if (result.issues) {
return result.issues.map((issue) => ({ return result.issues.map(issue => ({
name: issue.path?.map((p) => p.key).join('.') || '', name: issue.path?.map(p => p.key).join('.') || '',
message: issue.message message: issue.message
})) }))
} }

View File

@@ -1,4 +1,4 @@
export function pick<Data extends object, Keys extends keyof Data> (data: Data, keys: Keys[]): Pick<Data, Keys> { export function pick<Data extends object, Keys extends keyof Data>(data: Data, keys: Keys[]): Pick<Data, Keys> {
const result = {} as Pick<Data, Keys> const result = {} as Pick<Data, Keys>
for (const key of keys) { for (const key of keys) {
@@ -8,17 +8,18 @@ export function pick<Data extends object, Keys extends keyof Data> (data: Data,
return result return result
} }
export function omit<Data extends object, Keys extends keyof Data> (data: Data, keys: Keys[]): Omit<Data, Keys> { export function omit<Data extends object, Keys extends keyof Data>(data: Data, keys: Keys[]): Omit<Data, Keys> {
const result = { ...data } const result = { ...data }
for (const key of keys) { for (const key of keys) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete result[key] delete result[key]
} }
return result as Omit<Data, Keys> return result as Omit<Data, Keys>
} }
export function looseToNumber (val: any): any { export function looseToNumber(val: any): any {
const n = parseFloat(val) const n = Number.parseFloat(val)
return isNaN(n) ? val : n return Number.isNaN(n) ? val : n
} }

View File

@@ -4,7 +4,7 @@ import type { Nuxt } from '@nuxt/schema'
import type { ModuleOptions } from './module' import type { ModuleOptions } from './module'
import * as theme from './theme' import * as theme from './theme'
export function addTemplates (options: ModuleOptions, nuxt: Nuxt) { export function addTemplates(options: ModuleOptions, nuxt: Nuxt) {
const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]
const template = addTemplate({ const template = addTemplate({