fix: Field components should now infer state.value properly

* chore: refactor TS typings for React

* fix: field should now infer state.value properly in React adapter

* chore: fix Vue package typings

* chore: fix linting

* chore: fix React adapter

* chore: improve performance of TData type in FieldApi

* chore: add back index and parent type

* chore: add Vue TSC dep on Vue example

* chore: fix lint and type test

* chore: update Vite stuff

* chore: add implicit dep for Vue and React examples

* chore: add type test pre-req

* chore: install deps from examples in PR CI

* chore: remove filter from more installation
This commit is contained in:
Corbin Crutchley
2023-09-09 03:40:29 -07:00
committed by GitHub
parent b5a768f182
commit 160f71275f
14 changed files with 421 additions and 512 deletions

View File

@@ -22,7 +22,7 @@ jobs:
node-version: 18.15.0 node-version: 18.15.0
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm --filter "./packages/**" --filter form --prefer-offline install --no-frozen-lockfile run: pnpm --prefer-offline install --no-frozen-lockfile
- name: Run Tests - name: Run Tests
uses: nick-fields/retry@v2.8.3 uses: nick-fields/retry@v2.8.3
with: with:
@@ -48,7 +48,7 @@ jobs:
node-version: 16.14.2 node-version: 16.14.2
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm --filter "./packages/**" --filter form --prefer-offline install --no-frozen-lockfile run: pnpm --prefer-offline install --no-frozen-lockfile
- run: pnpm run test:eslint --base=${{ github.event.pull_request.base.sha }} - run: pnpm run test:eslint --base=${{ github.event.pull_request.base.sha }}
typecheck: typecheck:
name: 'Typecheck' name: 'Typecheck'
@@ -67,7 +67,7 @@ jobs:
node-version: 16.14.2 node-version: 16.14.2
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm --filter "./packages/**" --filter form --prefer-offline install --no-frozen-lockfile run: pnpm --prefer-offline install --no-frozen-lockfile
- run: pnpm run test:types --base=${{ github.event.pull_request.base.sha }} - run: pnpm run test:types --base=${{ github.event.pull_request.base.sha }}
format: format:
name: 'Format' name: 'Format'
@@ -86,7 +86,7 @@ jobs:
node-version: 16.14.2 node-version: 16.14.2
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm --filter "./packages/**" --filter form --prefer-offline install --no-frozen-lockfile run: pnpm --prefer-offline install --no-frozen-lockfile
- run: pnpm run test:format --base=${{ github.event.pull_request.base.sha }} - run: pnpm run test:format --base=${{ github.event.pull_request.base.sha }}
test-build: test-build:
name: 'Test Build' name: 'Test Build'
@@ -105,7 +105,7 @@ jobs:
node-version: 16.14.2 node-version: 16.14.2
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm --filter "./packages/**" --filter form --prefer-offline install --no-frozen-lockfile run: pnpm --prefer-offline install --no-frozen-lockfile
- name: Get appropriate base and head commits for `nx affected` commands - name: Get appropriate base and head commits for `nx affected` commands
uses: nrwl/nx-set-shas@v3 uses: nrwl/nx-set-shas@v3
with: with:

View File

@@ -13,12 +13,11 @@
"react": "^18.0.0", "react": "^18.0.0",
"react-dom": "^18.0.0", "react-dom": "^18.0.0",
"zod": "^3.21.4", "zod": "^3.21.4",
"@tanstack/form-core": "0.3.2", "@tanstack/form-core": "0.3.2"
"@tanstack/vue-form": "0.3.2"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-react": "^2.0.0", "@vitejs/plugin-react": "^4.0.4",
"vite": "^3.0.0" "vite": "^4.4.9"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [
@@ -31,5 +30,18 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"nx": {
"implicitDependencies": [
"@tanstack/form-core",
"@tanstack/react-form"
],
"targets": {
"test:types": {
"dependsOn": [
"build"
]
}
}
} }
} }

View File

@@ -5,17 +5,31 @@
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"build:dev": "vite build -m development", "build:dev": "vite build -m development",
"test:types": "vue-tsc --noEmit",
"serve": "vite preview" "serve": "vite preview"
}, },
"dependencies": { "dependencies": {
"@tanstack/vue-form": "0.3.2",
"vue": "^3.3.4",
"@tanstack/form-core": "0.3.2", "@tanstack/form-core": "0.3.2",
"@tanstack/react-form": "0.3.2" "@tanstack/vue-form": "0.3.2",
"vue": "^3.3.4"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.2.3", "@vitejs/plugin-vue": "^4.3.4",
"typescript": "^5.0.4", "typescript": "^5.0.4",
"vite": "^4.4.4" "vite": "^4.4.9",
"vue-tsc": "^1.8.10"
},
"nx": {
"implicitDependencies": [
"@tanstack/form-core",
"@tanstack/vue-form"
],
"targets": {
"test:types": {
"dependsOn": [
"build"
]
}
}
} }
} }

View File

@@ -15,7 +15,7 @@ const form = useForm({
form.provideFormContext() form.provideFormContext()
async function onChangeFirstName(value) { async function onChangeFirstName(value: string) {
await new Promise((resolve) => setTimeout(resolve, 1000)) await new Promise((resolve) => setTimeout(resolve, 1000))
return value.includes(`error`) && `No 'error' allowed in first name` return value.includes(`error`) && `No 'error' allowed in first name`
} }

View File

@@ -56,8 +56,6 @@
"@types/testing-library__jest-dom": "^5.14.5", "@types/testing-library__jest-dom": "^5.14.5",
"@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1", "@typescript-eslint/parser": "^6.4.1",
"@vitejs/plugin-vue": "^4.3.4",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"@vitest/coverage-istanbul": "^0.34.3", "@vitest/coverage-istanbul": "^0.34.3",
"axios": "^0.26.1", "axios": "^0.26.1",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",

View File

@@ -43,10 +43,19 @@ export interface FieldOptions<
defaultMeta?: Partial<FieldMeta> defaultMeta?: Partial<FieldMeta>
} }
export type FieldApiOptions<TData, TFormData> = FieldOptions< export interface FieldApiOptions<
TData, _TData,
TFormData TFormData,
> & { /**
* This allows us to restrict the name to only be a valid field name while
* also assigning it to a generic
*/
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
/**
* If TData is unknown, we can use the TName generic to determine the type
*/
TData = unknown extends _TData ? DeepValue<TFormData, TName> : _TData,
> extends FieldOptions<_TData, TFormData, TName, TData> {
form: FormApi<TFormData> form: FormApi<TFormData>
} }
@@ -65,35 +74,45 @@ export type FieldState<TData> = {
meta: FieldMeta meta: FieldMeta
} }
/** type GetTData<
* TData may not be known at the time of FieldApi construction, so we need to TData,
* use a conditional type to determine if TData is known or not. TFormData,
* Opts extends FieldApiOptions<TData, TFormData>,
* If TData is not known, we use the TFormData type to determine the type of > = Opts extends FieldApiOptions<
* the field value based on the field name. infer _TData,
*/ infer _TFormData,
type GetTData<Name, TData, TFormData> = unknown extends TData infer _TName,
? DeepValue<TFormData, Name> infer RealTData
: TData >
? RealTData
: never
export class FieldApi<TData, TFormData> { export class FieldApi<
_TData,
TFormData,
Opts extends FieldApiOptions<_TData, TFormData> = FieldApiOptions<
_TData,
TFormData
>,
TData extends GetTData<_TData, TFormData, Opts> = GetTData<
_TData,
TFormData,
Opts
>,
> {
uid: number uid: number
form: FormApi<TFormData> form: Opts['form']
name!: DeepKeys<TFormData> name!: DeepKeys<TFormData>
/** options: Opts = {} as any
* This is a hack that allows us to use `GetTData` without calling it everywhere store!: Store<FieldState<TData>>
* state!: FieldState<TData>
* Unfortunately this hack appears to be needed alongside the `TName` hack prevState!: FieldState<TData>
* further up in this file. This properly types all of the internal methods,
* while the `TName` hack types the options properly
*/
_tdata!: GetTData<typeof this.name, TData, TFormData>
store!: Store<FieldState<typeof this._tdata>>
state!: FieldState<typeof this._tdata>
prevState!: FieldState<typeof this._tdata>
options: FieldOptions<typeof this._tdata, TFormData> = {} as any
constructor(opts: FieldApiOptions<TData, TFormData>) { constructor(
opts: Opts & {
form: FormApi<TFormData>
},
) {
this.form = opts.form this.form = opts.form
this.uid = uid++ this.uid = uid++
// Support field prefixing from FieldScope // Support field prefixing from FieldScope
@@ -104,7 +123,7 @@ export class FieldApi<TData, TFormData> {
this.name = opts.name as any this.name = opts.name as any
this.store = new Store<FieldState<typeof this._tdata>>( this.store = new Store<FieldState<TData>>(
{ {
value: this.getValue(), value: this.getValue(),
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -138,7 +157,7 @@ export class FieldApi<TData, TFormData> {
mount = () => { mount = () => {
const info = this.getInfo() const info = this.getInfo()
info.instances[this.uid] = this info.instances[this.uid] = this as never
const unsubscribe = this.form.store.subscribe(() => { const unsubscribe = this.form.store.subscribe(() => {
this.store.batch(() => { this.store.batch(() => {
@@ -167,7 +186,7 @@ export class FieldApi<TData, TFormData> {
} }
} }
update = (opts: FieldApiOptions<typeof this._tdata, TFormData>) => { update = (opts: FieldApiOptions<TData, TFormData>) => {
// Default Value // Default Value
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (this.state.value === undefined) { if (this.state.value === undefined) {
@@ -189,12 +208,12 @@ export class FieldApi<TData, TFormData> {
this.options = opts as never this.options = opts as never
} }
getValue = (): typeof this._tdata => { getValue = (): TData => {
return this.form.getFieldValue(this.name) return this.form.getFieldValue(this.name)
} }
setValue = ( setValue = (
updater: Updater<typeof this._tdata>, updater: Updater<TData>,
options?: { touch?: boolean; notify?: boolean }, options?: { touch?: boolean; notify?: boolean },
) => { ) => {
this.form.setFieldValue(this.name, updater as never, options) this.form.setFieldValue(this.name, updater as never, options)
@@ -218,17 +237,12 @@ export class FieldApi<TData, TFormData> {
getInfo = () => this.form.getFieldInfo(this.name) getInfo = () => this.form.getFieldInfo(this.name)
pushValue = ( pushValue = (value: TData extends any[] ? TData[number] : never) =>
value: typeof this._tdata extends any[] this.form.pushFieldValue(this.name, value as any)
? (typeof this._tdata)[number]
: never,
) => this.form.pushFieldValue(this.name, value as any)
insertValue = ( insertValue = (
index: number, index: number,
value: typeof this._tdata extends any[] value: TData extends any[] ? TData[number] : never,
? (typeof this._tdata)[number]
: never,
) => this.form.insertFieldValue(this.name, index, value as any) ) => this.form.insertFieldValue(this.name, index, value as any)
removeValue = (index: number) => this.form.removeFieldValue(this.name, index) removeValue = (index: number) => this.form.removeFieldValue(this.name, index)
@@ -236,8 +250,8 @@ export class FieldApi<TData, TFormData> {
swapValues = (aIndex: number, bIndex: number) => swapValues = (aIndex: number, bIndex: number) =>
this.form.swapFieldValues(this.name, aIndex, bIndex) this.form.swapFieldValues(this.name, aIndex, bIndex)
getSubField = <TName extends DeepKeys<typeof this._tdata>>(name: TName) => getSubField = <TName extends DeepKeys<TData>>(name: TName) =>
new FieldApi<DeepValue<typeof this._tdata, TName>, TFormData>({ new FieldApi<DeepValue<TData, TName>, TFormData>({
name: `${this.name}.${name}` as never, name: `${this.name}.${name}` as never,
form: this.form, form: this.form,
}) })
@@ -371,7 +385,7 @@ export class FieldApi<TData, TFormData> {
validate = ( validate = (
cause: ValidationCause, cause: ValidationCause,
value?: typeof this._tdata, value?: TData,
): ValidationError[] | Promise<ValidationError[]> => { ): ValidationError[] | Promise<ValidationError[]> => {
// If the field is pristine and validatePristine is false, do not validate // If the field is pristine and validatePristine is false, do not validate
if (!this.state.meta.isTouched) return [] if (!this.state.meta.isTouched) return []
@@ -389,7 +403,7 @@ export class FieldApi<TData, TFormData> {
return this.validateAsync(value, cause) return this.validateAsync(value, cause)
} }
handleChange = (updater: Updater<typeof this._tdata>) => { handleChange = (updater: Updater<TData>) => {
this.setValue(updater, { touch: true }) this.setValue(updater, { touch: true })
} }

View File

@@ -0,0 +1,63 @@
import { assertType } from 'vitest'
import * as React from 'react'
import { useForm } from '../useForm'
it('should type state.value properly', () => {
function Comp() {
const form = useForm({
defaultValues: {
firstName: 'test',
age: 84,
},
} as const)
return (
<form.Provider>
<form.Field
name="firstName"
children={(field) => {
assertType<'test'>(field.state.value)
}}
/>
<form.Field
name="age"
children={(field) => {
assertType<84>(field.state.value)
}}
/>
</form.Provider>
)
}
})
it('should type onChange properly', () => {
function Comp() {
const form = useForm({
defaultValues: {
firstName: 'test',
age: 84,
},
} as const)
return (
<form.Provider>
<form.Field
name="firstName"
onChange={(val) => {
assertType<'test'>(val)
return null
}}
children={(field) => null}
/>
<form.Field
name="age"
onChange={(val) => {
assertType<84>(val)
return null
}}
children={(field) => null}
/>
</form.Provider>
)
}
})

View File

@@ -1,8 +1,9 @@
import type { FieldOptions } from '@tanstack/form-core' import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
export type UseFieldOptions<TData, TFormData> = FieldOptions< export type UseFieldOptions<
TData, TData,
TFormData TFormData,
> & { TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
> = FieldOptions<TData, TFormData, TName> & {
mode?: 'value' | 'array' mode?: 'value' | 'array'
} }

View File

@@ -3,17 +3,17 @@ import { useStore } from '@tanstack/react-store'
import type { import type {
DeepKeys, DeepKeys,
DeepValue, DeepValue,
FieldOptions, FieldApiOptions,
Narrow, Narrow,
} from '@tanstack/form-core' } from '@tanstack/form-core'
import { FieldApi, functionalUpdate } from '@tanstack/form-core' import { FieldApi, type FormApi, functionalUpdate } from '@tanstack/form-core'
import { useFormContext, formContext } from './formContext' import { useFormContext, formContext } from './formContext'
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect' import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'
import type { UseFieldOptions } from './types' import type { UseFieldOptions } from './types'
declare module '@tanstack/form-core' { declare module '@tanstack/form-core' {
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
interface FieldApi<TData, TFormData> { interface FieldApi<_TData, TFormData, Opts, TData> {
Field: FieldComponent<TData, TFormData> Field: FieldComponent<TData, TFormData>
} }
} }
@@ -25,13 +25,27 @@ export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(
>, >,
) => FieldApi<DeepValue<TFormData, TField>, TFormData> ) => FieldApi<DeepValue<TFormData, TField>, TFormData>
export function useField<TData, TFormData>( export function useField<
opts: UseFieldOptions<TData, TFormData>, TData,
): FieldApi<TData, TFormData> { TFormData,
TName extends unknown extends TFormData
? string
: DeepKeys<TFormData> = unknown extends TFormData
? string
: DeepKeys<TFormData>,
>(
opts: UseFieldOptions<TData, TFormData, TName>,
): FieldApi<
TData,
TFormData,
Omit<typeof opts, 'onMount'> & {
form: FormApi<TFormData>
}
> {
// Get the form API either manually or from context // Get the form API either manually or from context
const { formApi, parentFieldName } = useFormContext() const { formApi, parentFieldName } = useFormContext()
const [fieldApi] = useState<FieldApi<TData, TFormData>>(() => { const [fieldApi] = useState(() => {
const name = ( const name = (
typeof opts.index === 'number' typeof opts.index === 'number'
? [parentFieldName, opts.index, opts.name] ? [parentFieldName, opts.index, opts.name]
@@ -40,9 +54,13 @@ export function useField<TData, TFormData>(
.filter((d) => d !== undefined) .filter((d) => d !== undefined)
.join('.') .join('.')
const api = new FieldApi({ ...opts, form: formApi, name: name as any }) const api = new FieldApi({
...opts,
form: formApi,
name: name,
} as never)
api.Field = Field as any api.Field = Field as never
return api return api
}) })
@@ -56,70 +74,52 @@ export function useField<TData, TFormData>(
}) })
useStore( useStore(
fieldApi.store as any, fieldApi.store,
opts.mode === 'array' opts.mode === 'array'
? (state: any) => { ? (state: any) => {
return [state.meta, Object.keys(state.value || []).length] return [state.meta, Object.keys(state.value || []).length]
} }
: undefined, : undefined,
) )
// Instantiates field meta and removes it when unrendered // Instantiates field meta and removes it when unrendered
useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi]) useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi])
return fieldApi return fieldApi as never
} }
// export type FieldValue<TFormData, TField> = TFormData extends any[] type FieldComponentProps<
// ? TField extends `[${infer TIndex extends number | 'i'}].${infer TRest}` TParentData,
// ? DeepValue<TFormData[TIndex extends 'i' ? number : TIndex], TRest> TFormData,
// : TField extends `[${infer TIndex extends number | 'i'}]` TField,
// ? TFormData[TIndex extends 'i' ? number : TIndex] TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
// : never > = {
// : TField extends `${infer TPrefix}[${infer TIndex extends
// | number
// | 'i'}].${infer TRest}`
// ? DeepValue<
// DeepValue<TFormData, TPrefix>[TIndex extends 'i' ? number : TIndex],
// TRest
// >
// : TField extends `${infer TPrefix}[${infer TIndex extends number | 'i'}]`
// ? DeepValue<TFormData, TPrefix>[TIndex extends 'i' ? number : TIndex]
// : DeepValue<TFormData, TField>
export type FieldValue<TFormData, TField> = TFormData extends any[]
? unknown extends TField
? TFormData[number]
: DeepValue<TFormData[number], TField>
: DeepValue<TFormData, TField>
// type Test1 = FieldValue<{ foo: { bar: string }[] }, 'foo'>
// // ^?
// type Test2 = FieldValue<{ foo: { bar: string }[] }, 'foo[i]'>
// // ^?
// type Test3 = FieldValue<{ foo: { bar: string }[] }, 'foo[2].bar'>
// // ^?
export type FieldComponent<TParentData, TFormData> = <TField>({
children,
...fieldOptions
}: {
children: ( children: (
fieldApi: FieldApi<FieldValue<TParentData, TField>, TFormData>, fieldApi: FieldApi<
TField,
TFormData,
FieldApiOptions<TField, TFormData, TName>
>,
) => any ) => any
} & Omit< } & (TParentData extends any[]
UseFieldOptions<FieldValue<TParentData, TField>, TFormData>,
'name' | 'index'
> &
(TParentData extends any[]
? { ? {
name?: TField extends undefined ? TField : DeepKeys<TParentData> name?: TName
index: number index: number
} }
: { : {
name: TField extends undefined ? TField : DeepKeys<TParentData> name: TName
index?: never index?: never
})) => any }) &
Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>
export type FieldComponent<TParentData, TFormData> = <
// Type of the field
TField,
// Name of the field
TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
>({
children,
...fieldOptions
}: FieldComponentProps<TParentData, TFormData, TField, TName>) => any
export function Field<TData, TFormData>({ export function Field<TData, TFormData>({
children, children,

View File

@@ -28,10 +28,9 @@ export function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {
// @ts-ignore // @ts-ignore
const api = new FormApi<TData>(opts) const api = new FormApi<TData>(opts)
// eslint-disable-next-line react/display-name api.Provider = function Provider(props) {
api.Provider = (props) => ( return <formContext.Provider {...props} value={{ formApi: api }} />
<formContext.Provider {...props} value={{ formApi: api }} /> }
)
api.Field = Field as any api.Field = Field as any
api.useField = useField as any api.useField = useField as any
api.useStore = ( api.useStore = (

View File

@@ -1,3 +1,9 @@
export type NoInfer<T> = [T][T extends any ? 0 : never] import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
export type ReleaseVersion = 2 export type UseFieldOptions<
TData,
TFormData,
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
> = FieldOptions<TData, TFormData, TName> & {
mode?: 'value' | 'array'
}

View File

@@ -1,28 +1,22 @@
import { FieldApi } from '@tanstack/form-core' import {
import type { FieldApi,
FieldState, type FieldApiOptions,
DeepKeys, type FormApi,
DeepValue,
FieldOptions,
Narrow,
} from '@tanstack/form-core' } from '@tanstack/form-core'
import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'
import { useStore } from '@tanstack/vue-store' import { useStore } from '@tanstack/vue-store'
import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi' import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
import type { SlotsType, SetupContext, Ref } from 'vue-demi' import type { SlotsType, SetupContext, Ref } from 'vue-demi'
import { provideFormContext, useFormContext } from './formContext' import { provideFormContext, useFormContext } from './formContext'
import type { UseFieldOptions } from './types'
declare module '@tanstack/form-core' { declare module '@tanstack/form-core' {
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
interface FieldApi<TData, TFormData> { interface FieldApi<_TData, TFormData, Opts, TData> {
Field: FieldComponent<TData, TFormData> Field: FieldComponent<TFormData, TData>
} }
} }
export interface UseFieldOptions<TData, TFormData>
extends FieldOptions<TData, TFormData> {
mode?: 'value' | 'array'
}
export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>( export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(
opts?: { name: Narrow<TField> } & UseFieldOptions< opts?: { name: Narrow<TField> } & UseFieldOptions<
DeepValue<TFormData, TField>, DeepValue<TFormData, TField>,
@@ -30,25 +24,45 @@ export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(
>, >,
) => FieldApi<DeepValue<TFormData, TField>, TFormData> ) => FieldApi<DeepValue<TFormData, TField>, TFormData>
export function useField<TData, TFormData>( export function useField<
opts: UseFieldOptions<TData, TFormData>, TData,
TFormData,
TName extends unknown extends TFormData
? string
: DeepKeys<TFormData> = unknown extends TFormData
? string
: DeepKeys<TFormData>,
>(
opts: UseFieldOptions<TData, TFormData, TName>,
): { ): {
api: FieldApi<TData, TFormData> api: FieldApi<
state: Readonly<Ref<FieldApi<TData, TFormData>['state']>> TData,
TFormData,
Omit<typeof opts, 'onMount'> & {
form: FormApi<TFormData>
}
>
state: Readonly<
Ref<
FieldApi<
TData,
TFormData,
Omit<typeof opts, 'onMount'> & {
form: FormApi<TFormData>
}
>['state']
>
>
} { } {
// Get the form API either manually or from context // Get the form API either manually or from context
const { formApi, parentFieldName } = useFormContext() const { formApi, parentFieldName } = useFormContext()
const fieldApi = (() => { const fieldApi = (() => {
const name = ( const api = new FieldApi({
typeof opts.index === 'number' ...opts,
? [parentFieldName, opts.index, opts.name] form: formApi,
: [parentFieldName, opts.name] name: opts.name,
) } as never)
.filter((d) => d !== undefined)
.join('.')
const api = new FieldApi({ ...opts, form: formApi, name: name as never })
api.Field = Field as never api.Field = Field as never
@@ -77,56 +91,49 @@ export function useField<TData, TFormData>(
return { api: fieldApi, state: fieldState } as never return { api: fieldApi, state: fieldState } as never
} }
// export type FieldValue<TFormData, TField> = TFormData extends any[]
// ? TField extends `[${infer TIndex extends number | 'i'}].${infer TRest}`
// ? DeepValue<TFormData[TIndex extends 'i' ? number : TIndex], TRest>
// : TField extends `[${infer TIndex extends number | 'i'}]`
// ? TFormData[TIndex extends 'i' ? number : TIndex]
// : never
// : TField extends `${infer TPrefix}[${infer TIndex extends
// | number
// | 'i'}].${infer TRest}`
// ? DeepValue<
// DeepValue<TFormData, TPrefix>[TIndex extends 'i' ? number : TIndex],
// TRest
// >
// : TField extends `${infer TPrefix}[${infer TIndex extends number | 'i'}]`
// ? DeepValue<TFormData, TPrefix>[TIndex extends 'i' ? number : TIndex]
// : DeepValue<TFormData, TField>
export type FieldValue<TFormData, TField> = TFormData extends any[] export type FieldValue<TFormData, TField> = TFormData extends any[]
? unknown extends TField ? unknown extends TField
? TFormData[number] ? TFormData[number]
: DeepValue<TFormData[number], TField> : DeepValue<TFormData[number], TField>
: DeepValue<TFormData, TField> : DeepValue<TFormData, TField>
// type Test1 = FieldValue<{ foo: { bar: string }[] }, 'foo'> type FieldComponentProps<
// // ^? TParentData,
// type Test2 = FieldValue<{ foo: { bar: string }[] }, 'foo[i]'> TFormData,
// // ^? TField,
// type Test3 = FieldValue<{ foo: { bar: string }[] }, 'foo[2].bar'> TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
// // ^? > = (TParentData extends any[]
export type FieldComponent<TParentData, TFormData> = <TField>(
fieldOptions: Omit<
UseFieldOptions<FieldValue<TParentData, TField>, TFormData>,
'name' | 'index'
> &
(TParentData extends any[]
? { ? {
name?: TField extends undefined ? TField : DeepKeys<TParentData> name?: TName
index: number index: number
} }
: { : {
name: TField extends undefined ? TField : DeepKeys<TParentData> name: TName
index?: never index?: never
}), }) &
Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>
export type FieldComponent<TParentData, TFormData> = <
// Type of the field
TField,
// Name of the field
TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
>(
fieldOptions: FieldComponentProps<TParentData, TFormData, TField, TName>,
context: SetupContext< context: SetupContext<
{}, {},
SlotsType<{ SlotsType<{
default: { default: {
field: FieldApi<FieldValue<TParentData, TField>, TFormData> field: FieldApi<
state: FieldState<any> TField,
TFormData,
FieldApiOptions<TField, TFormData, TName>
>
state: FieldApi<
TField,
TFormData,
FieldApiOptions<TField, TFormData, TName>
>['state']
} }
}> }>
>, >,

View File

@@ -1,5 +1,5 @@
import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core' import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'
import { useStore } from '@tanstack/vue-store' import { type NoInfer, useStore } from '@tanstack/vue-store'
import { type UseField, type FieldComponent, Field, useField } from './useField' import { type UseField, type FieldComponent, Field, useField } from './useField'
import { provideFormContext } from './formContext' import { provideFormContext } from './formContext'
import { import {
@@ -8,7 +8,6 @@ import {
type SetupContext, type SetupContext,
defineComponent, defineComponent,
} from 'vue-demi' } from 'vue-demi'
import type { NoInfer } from './types'
declare module '@tanstack/form-core' { declare module '@tanstack/form-core' {
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow

420
pnpm-lock.yaml generated
View File

@@ -237,9 +237,6 @@ importers:
'@tanstack/react-form': '@tanstack/react-form':
specifier: workspace:* specifier: workspace:*
version: link:../../../packages/react-form version: link:../../../packages/react-form
'@tanstack/vue-form':
specifier: workspace:*
version: link:../../../packages/vue-form
axios: axios:
specifier: ^0.26.1 specifier: ^0.26.1
version: 0.26.1 version: 0.26.1
@@ -254,20 +251,17 @@ importers:
version: 3.21.4 version: 3.21.4
devDependencies: devDependencies:
'@vitejs/plugin-react': '@vitejs/plugin-react':
specifier: ^2.0.0 specifier: ^4.0.4
version: 2.1.0(vite@3.1.3) version: 4.0.4(vite@4.4.9)
vite: vite:
specifier: ^3.0.0 specifier: ^4.4.9
version: 3.1.3 version: 4.4.9(@types/node@17.0.45)
examples/vue/simple: examples/vue/simple:
dependencies: dependencies:
'@tanstack/form-core': '@tanstack/form-core':
specifier: workspace:* specifier: workspace:*
version: link:../../../packages/form-core version: link:../../../packages/form-core
'@tanstack/react-form':
specifier: workspace:*
version: link:../../../packages/react-form
'@tanstack/vue-form': '@tanstack/vue-form':
specifier: workspace:* specifier: workspace:*
version: link:../../../packages/vue-form version: link:../../../packages/vue-form
@@ -276,14 +270,17 @@ importers:
version: 3.3.4 version: 3.3.4
devDependencies: devDependencies:
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^4.2.3 specifier: ^4.3.4
version: 4.3.4(vite@4.4.9)(vue@3.3.4) version: 4.3.4(vite@4.4.9)(vue@3.3.4)
typescript: typescript:
specifier: ^5.0.4 specifier: ^5.0.4
version: 5.2.2 version: 5.2.2
vite: vite:
specifier: ^4.4.4 specifier: ^4.4.9
version: 4.4.9(@types/node@17.0.45) version: 4.4.9(@types/node@17.0.45)
vue-tsc:
specifier: ^1.8.10
version: 1.8.10(typescript@5.2.2)
packages/form-core: packages/form-core:
dependencies: dependencies:
@@ -676,7 +673,7 @@ packages:
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
dependencies: dependencies:
'@babel/types': 7.22.11 '@babel/types': 7.22.15
/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.22.10): /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.22.10):
resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==}
@@ -1328,6 +1325,17 @@ packages:
dependencies: dependencies:
'@babel/core': 7.22.10 '@babel/core': 7.22.10
'@babel/helper-plugin-utils': 7.22.5 '@babel/helper-plugin-utils': 7.22.5
dev: false
/@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.22.10):
resolution: {integrity: sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.22.10
'@babel/helper-plugin-utils': 7.22.5
dev: true
/@babel/plugin-transform-react-jsx-source@7.18.6(@babel/core@7.22.10): /@babel/plugin-transform-react-jsx-source@7.18.6(@babel/core@7.22.10):
resolution: {integrity: sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==} resolution: {integrity: sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==}
@@ -1337,19 +1345,16 @@ packages:
dependencies: dependencies:
'@babel/core': 7.22.10 '@babel/core': 7.22.10
'@babel/helper-plugin-utils': 7.22.5 '@babel/helper-plugin-utils': 7.22.5
dev: false
/@babel/plugin-transform-react-jsx@7.19.0(@babel/core@7.22.10): /@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.22.10):
resolution: {integrity: sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==} resolution: {integrity: sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
'@babel/core': 7.22.10 '@babel/core': 7.22.10
'@babel/helper-annotate-as-pure': 7.22.5
'@babel/helper-module-imports': 7.22.5
'@babel/helper-plugin-utils': 7.22.5 '@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.10)
'@babel/types': 7.22.15
dev: true dev: true
/@babel/plugin-transform-react-jsx@7.22.5(@babel/core@7.22.10): /@babel/plugin-transform-react-jsx@7.22.5(@babel/core@7.22.10):
@@ -1772,15 +1777,6 @@ packages:
dev: true dev: true
optional: true optional: true
/@esbuild/android-arm@0.15.18:
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm@0.18.20: /@esbuild/android-arm@0.18.20:
resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -1862,15 +1858,6 @@ packages:
dev: true dev: true
optional: true optional: true
/@esbuild/linux-loong64@0.15.18:
resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-loong64@0.18.20: /@esbuild/linux-loong64@0.18.20:
resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -3151,20 +3138,17 @@ packages:
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
dev: true dev: true
/@vitejs/plugin-react@2.1.0(vite@3.1.3): /@vitejs/plugin-react@4.0.4(vite@4.4.9):
resolution: {integrity: sha512-am6rPyyU3LzUYne3Gd9oj9c4Rzbq5hQnuGXSMT6Gujq45Il/+bunwq3lrB7wghLkiF45ygMwft37vgJ/NE8IAA==} resolution: {integrity: sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies: peerDependencies:
vite: ^3.0.0 vite: ^4.2.0
dependencies: dependencies:
'@babel/core': 7.22.10 '@babel/core': 7.22.10
'@babel/plugin-transform-react-jsx': 7.19.0(@babel/core@7.22.10) '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.10)
'@babel/plugin-transform-react-jsx-development': 7.18.6(@babel/core@7.22.10) '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.10)
'@babel/plugin-transform-react-jsx-self': 7.18.6(@babel/core@7.22.10)
'@babel/plugin-transform-react-jsx-source': 7.18.6(@babel/core@7.22.10)
magic-string: 0.26.4
react-refresh: 0.14.0 react-refresh: 0.14.0
vite: 3.1.3 vite: 4.4.9(@types/node@17.0.45)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@@ -3250,6 +3234,24 @@ packages:
pretty-format: 29.6.3 pretty-format: 29.6.3
dev: true dev: true
/@volar/language-core@1.10.1:
resolution: {integrity: sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==}
dependencies:
'@volar/source-map': 1.10.1
dev: true
/@volar/source-map@1.10.1:
resolution: {integrity: sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==}
dependencies:
muggle-string: 0.3.1
dev: true
/@volar/typescript@1.10.1:
resolution: {integrity: sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ==}
dependencies:
'@volar/language-core': 1.10.1
dev: true
/@vue/babel-helper-vue-transform-on@1.1.5: /@vue/babel-helper-vue-transform-on@1.1.5:
resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==} resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==}
dev: true dev: true
@@ -3322,6 +3324,25 @@ packages:
dependencies: dependencies:
vue: 3.3.4 vue: 3.3.4
/@vue/language-core@1.8.10(typescript@5.2.2):
resolution: {integrity: sha512-db8PtM4ZZr7SYNH30XpKxUYnUBYaTvcuJ4c2whKK04fuAjbtjAIZ2al5GzGEfUlesmvkpgdbiSviRXUxgD9Omw==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@volar/language-core': 1.10.1
'@volar/source-map': 1.10.1
'@vue/compiler-dom': 3.3.4
'@vue/reactivity': 3.3.4
'@vue/shared': 3.3.4
minimatch: 9.0.3
muggle-string: 0.3.1
typescript: 5.2.2
vue-template-compiler: 2.7.14
dev: true
/@vue/reactivity-transform@3.3.4: /@vue/reactivity-transform@3.3.4:
resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==}
dependencies: dependencies:
@@ -3375,6 +3396,15 @@ packages:
vue-component-type-helpers: 1.8.4 vue-component-type-helpers: 1.8.4
dev: true dev: true
/@vue/typescript@1.8.10(typescript@5.2.2):
resolution: {integrity: sha512-vPSpTXMk4chYwvyTGjM891cKgnx2r6vtbdANOp2mRU31f4HYGyLrZBlGgiua7SaO2cLjUg8y91OipJe0t8OFhA==}
dependencies:
'@volar/typescript': 1.10.1
'@vue/language-core': 1.8.10(typescript@5.2.2)
transitivePeerDependencies:
- typescript
dev: true
/@yarnpkg/lockfile@1.1.0: /@yarnpkg/lockfile@1.1.0:
resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==}
dev: true dev: true
@@ -4558,6 +4588,10 @@ packages:
resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==} resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==}
dev: false dev: false
/de-indent@1.0.2:
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
dev: true
/debug@2.6.9: /debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies: peerDependencies:
@@ -4972,221 +5006,11 @@ packages:
is-symbol: 1.0.4 is-symbol: 1.0.4
dev: true dev: true
/esbuild-android-64@0.15.18:
resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-android-arm64@0.15.18:
resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-64@0.15.18:
resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-arm64@0.15.18:
resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-64@0.15.18:
resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-arm64@0.15.18:
resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-32@0.15.18:
resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-64@0.15.18:
resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm64@0.15.18:
resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm@0.15.18:
resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-mips64le@0.15.18:
resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-ppc64le@0.15.18:
resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-riscv64@0.15.18:
resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-s390x@0.15.18:
resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-netbsd-64@0.15.18:
resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-openbsd-64@0.15.18:
resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-plugin-file-path-extensions@1.0.0: /esbuild-plugin-file-path-extensions@1.0.0:
resolution: {integrity: sha512-v5LpSkml+CbsC0+xAaETEGDECdvKp1wKkD4aXMdI4zLjXP0EYfK4GjGhphumt4N+kjR3A8Q+DIkpgxX1XTqO4Q==} resolution: {integrity: sha512-v5LpSkml+CbsC0+xAaETEGDECdvKp1wKkD4aXMdI4zLjXP0EYfK4GjGhphumt4N+kjR3A8Q+DIkpgxX1XTqO4Q==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'} engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
dev: true dev: true
/esbuild-sunos-64@0.15.18:
resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-32@0.15.18:
resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-64@0.15.18:
resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-arm64@0.15.18:
resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild@0.15.18:
resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.15.18
'@esbuild/linux-loong64': 0.15.18
esbuild-android-64: 0.15.18
esbuild-android-arm64: 0.15.18
esbuild-darwin-64: 0.15.18
esbuild-darwin-arm64: 0.15.18
esbuild-freebsd-64: 0.15.18
esbuild-freebsd-arm64: 0.15.18
esbuild-linux-32: 0.15.18
esbuild-linux-64: 0.15.18
esbuild-linux-arm: 0.15.18
esbuild-linux-arm64: 0.15.18
esbuild-linux-mips64le: 0.15.18
esbuild-linux-ppc64le: 0.15.18
esbuild-linux-riscv64: 0.15.18
esbuild-linux-s390x: 0.15.18
esbuild-netbsd-64: 0.15.18
esbuild-openbsd-64: 0.15.18
esbuild-sunos-64: 0.15.18
esbuild-windows-32: 0.15.18
esbuild-windows-64: 0.15.18
esbuild-windows-arm64: 0.15.18
dev: true
/esbuild@0.18.20: /esbuild@0.18.20:
resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -6039,6 +5863,11 @@ packages:
dependencies: dependencies:
function-bind: 1.1.1 function-bind: 1.1.1
/he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
dev: true
/hermes-estree@0.12.0: /hermes-estree@0.12.0:
resolution: {integrity: sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw==} resolution: {integrity: sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw==}
dev: false dev: false
@@ -7094,13 +6923,6 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/magic-string@0.26.4:
resolution: {integrity: sha512-e5uXtVJ22aEpK9u1+eQf0fSxHeqwyV19K+uGnlROCxUhzwRip9tBsaMViK/0vC3viyPd5Gtucp3UmEp/Q2cPTQ==}
engines: {node: '>=12'}
dependencies:
sourcemap-codec: 1.4.8
dev: true
/magic-string@0.27.0: /magic-string@0.27.0:
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -7680,6 +7502,10 @@ packages:
/ms@2.1.3: /ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
/muggle-string@0.3.1:
resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
dev: true
/mz@2.7.0: /mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
dependencies: dependencies:
@@ -8305,15 +8131,6 @@ packages:
yaml: 2.3.1 yaml: 2.3.1
dev: true dev: true
/postcss@8.4.16:
resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.6
picocolors: 1.0.0
source-map-js: 1.0.2
dev: true
/postcss@8.4.28: /postcss@8.4.28:
resolution: {integrity: sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==} resolution: {integrity: sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@@ -8836,14 +8653,6 @@ packages:
glob: 10.3.3 glob: 10.3.3
dev: true dev: true
/rollup@2.78.1:
resolution: {integrity: sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==}
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
fsevents: 2.3.3
dev: true
/rollup@3.28.1: /rollup@3.28.1:
resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==} resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'} engines: {node: '>=14.18.0', npm: '>=8.0.0'}
@@ -9117,11 +8926,6 @@ packages:
whatwg-url: 7.1.0 whatwg-url: 7.1.0
dev: true dev: true
/sourcemap-codec@1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
deprecated: Please use @jridgewell/sourcemap-codec instead
dev: true
/spawn-command@0.0.2: /spawn-command@0.0.2:
resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==}
dev: true dev: true
@@ -9944,33 +9748,6 @@ packages:
- terser - terser
dev: true dev: true
/vite@3.1.3:
resolution: {integrity: sha512-/3XWiktaopByM5bd8dqvHxRt5EEgRikevnnrpND0gRfNkrMrPaGGexhtLCzv15RcCMtV2CLw+BPas8YFeSG0KA==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
less: '*'
sass: '*'
stylus: '*'
terser: ^5.4.0
peerDependenciesMeta:
less:
optional: true
sass:
optional: true
stylus:
optional: true
terser:
optional: true
dependencies:
esbuild: 0.15.18
postcss: 8.4.16
resolve: 1.22.1
rollup: 2.78.1
optionalDependencies:
fsevents: 2.3.3
dev: true
/vite@4.4.9(@types/node@17.0.45): /vite@4.4.9(@types/node@17.0.45):
resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
@@ -10097,6 +9874,25 @@ packages:
vue: 3.3.4 vue: 3.3.4
dev: false dev: false
/vue-template-compiler@2.7.14:
resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==}
dependencies:
de-indent: 1.0.2
he: 1.2.0
dev: true
/vue-tsc@1.8.10(typescript@5.2.2):
resolution: {integrity: sha512-ptpTFFDoHQgkWJF7i5iERxooiQzOGtG1uKTfmAUuS3qPuSQGq+Ky/S8BFHhnFGwoOxq/PjmGN2QSZEfg1rtzQA==}
hasBin: true
peerDependencies:
typescript: '*'
dependencies:
'@vue/language-core': 1.8.10(typescript@5.2.2)
'@vue/typescript': 1.8.10(typescript@5.2.2)
semver: 7.5.4
typescript: 5.2.2
dev: true
/vue@2.6.14: /vue@2.6.14:
resolution: {integrity: sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==} resolution: {integrity: sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==}
dev: true dev: true