@tanstack/form-core 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/legacy/FieldApi.cjs +256 -0
- package/build/legacy/FieldApi.cjs.map +1 -0
- package/build/legacy/FieldApi.d.cts +3 -0
- package/build/legacy/FieldApi.d.ts +3 -0
- package/build/legacy/FieldApi.js +223 -0
- package/build/legacy/FieldApi.js.map +1 -0
- package/build/legacy/FormApi.cjs +255 -0
- package/build/legacy/FormApi.cjs.map +1 -0
- package/build/legacy/FormApi.d.cts +3 -0
- package/build/legacy/FormApi.d.ts +3 -0
- package/build/legacy/FormApi.js +232 -0
- package/build/legacy/FormApi.js.map +1 -0
- package/build/legacy/chunk-4QZDOMDG.js +19 -0
- package/build/legacy/chunk-4QZDOMDG.js.map +1 -0
- package/build/legacy/index.cjs +29 -0
- package/build/legacy/index.cjs.map +1 -0
- package/build/legacy/index.d.cts +171 -0
- package/build/legacy/index.d.ts +171 -0
- package/build/legacy/index.js +5 -0
- package/build/legacy/index.js.map +1 -0
- package/build/legacy/utils.cjs +98 -0
- package/build/legacy/utils.cjs.map +1 -0
- package/build/legacy/utils.d.cts +32 -0
- package/build/legacy/utils.d.ts +32 -0
- package/build/legacy/utils.js +73 -0
- package/build/legacy/utils.js.map +1 -0
- package/build/modern/FieldApi.cjs +238 -0
- package/build/modern/FieldApi.cjs.map +1 -0
- package/build/modern/FieldApi.d.cts +3 -0
- package/build/modern/FieldApi.d.ts +3 -0
- package/build/modern/FieldApi.js +213 -0
- package/build/modern/FieldApi.js.map +1 -0
- package/build/modern/FormApi.cjs +249 -0
- package/build/modern/FormApi.cjs.map +1 -0
- package/build/modern/FormApi.d.cts +3 -0
- package/build/modern/FormApi.d.ts +3 -0
- package/build/modern/FormApi.js +224 -0
- package/build/modern/FormApi.js.map +1 -0
- package/build/modern/index.cjs +29 -0
- package/build/modern/index.cjs.map +1 -0
- package/build/modern/index.d.cts +171 -0
- package/build/modern/index.d.ts +171 -0
- package/build/modern/index.js +5 -0
- package/build/modern/index.js.map +1 -0
- package/build/modern/utils.cjs +98 -0
- package/build/modern/utils.cjs.map +1 -0
- package/build/modern/utils.d.cts +32 -0
- package/build/modern/utils.d.ts +32 -0
- package/build/modern/utils.js +71 -0
- package/build/modern/utils.js.map +1 -0
- package/package.json +23 -12
- package/src/FieldApi.ts +11 -18
- package/src/tests/FieldApi.spec.ts +17 -0
- package/build/lib/FieldApi.cjs +0 -296
- package/build/lib/FieldApi.cjs.map +0 -1
- package/build/lib/FieldApi.d.ts +0 -95
- package/build/lib/FieldApi.d.ts.map +0 -1
- package/build/lib/FieldApi.js +0 -294
- package/build/lib/FieldApi.js.map +0 -1
- package/build/lib/FieldApi.legacy.cjs +0 -296
- package/build/lib/FieldApi.legacy.cjs.map +0 -1
- package/build/lib/FieldApi.legacy.js +0 -294
- package/build/lib/FieldApi.legacy.js.map +0 -1
- package/build/lib/FormApi.cjs +0 -239
- package/build/lib/FormApi.cjs.map +0 -1
- package/build/lib/FormApi.d.ts +0 -78
- package/build/lib/FormApi.d.ts.map +0 -1
- package/build/lib/FormApi.js +0 -237
- package/build/lib/FormApi.js.map +0 -1
- package/build/lib/FormApi.legacy.cjs +0 -239
- package/build/lib/FormApi.legacy.cjs.map +0 -1
- package/build/lib/FormApi.legacy.js +0 -237
- package/build/lib/FormApi.legacy.js.map +0 -1
- package/build/lib/_virtual/_rollupPluginBabelHelpers.cjs +0 -65
- package/build/lib/_virtual/_rollupPluginBabelHelpers.cjs.map +0 -1
- package/build/lib/_virtual/_rollupPluginBabelHelpers.js +0 -56
- package/build/lib/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.cjs +0 -65
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.cjs.map +0 -1
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.js +0 -56
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.js.map +0 -1
- package/build/lib/index.cjs +0 -14
- package/build/lib/index.cjs.map +0 -1
- package/build/lib/index.d.ts +0 -4
- package/build/lib/index.d.ts.map +0 -1
- package/build/lib/index.js +0 -4
- package/build/lib/index.js.map +0 -1
- package/build/lib/index.legacy.cjs +0 -14
- package/build/lib/index.legacy.cjs.map +0 -1
- package/build/lib/index.legacy.js +0 -4
- package/build/lib/index.legacy.js.map +0 -1
- package/build/lib/tests/FieldApi.spec.d.ts +0 -2
- package/build/lib/tests/FieldApi.spec.d.ts.map +0 -1
- package/build/lib/tests/FieldApi.test-d.d.ts +0 -2
- package/build/lib/tests/FieldApi.test-d.d.ts.map +0 -1
- package/build/lib/tests/FormApi.spec.d.ts +0 -2
- package/build/lib/tests/FormApi.spec.d.ts.map +0 -1
- package/build/lib/tests/utils.d.ts +0 -2
- package/build/lib/tests/utils.d.ts.map +0 -1
- package/build/lib/utils.cjs +0 -81
- package/build/lib/utils.cjs.map +0 -1
- package/build/lib/utils.d.ts +0 -32
- package/build/lib/utils.d.ts.map +0 -1
- package/build/lib/utils.js +0 -77
- package/build/lib/utils.js.map +0 -1
- package/build/lib/utils.legacy.cjs +0 -81
- package/build/lib/utils.legacy.cjs.map +0 -1
- package/build/lib/utils.legacy.js +0 -77
- package/build/lib/utils.legacy.js.map +0 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { Store } from '@tanstack/store';
|
|
2
|
+
import { DeepKeys, DeepValue, Updater } from './utils.cjs';
|
|
3
|
+
export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, setBy } from './utils.cjs';
|
|
4
|
+
|
|
5
|
+
type FormOptions<TData> = {
|
|
6
|
+
defaultValues?: TData;
|
|
7
|
+
defaultState?: Partial<FormState<TData>>;
|
|
8
|
+
asyncDebounceMs?: number;
|
|
9
|
+
onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError;
|
|
10
|
+
onMountAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
|
|
11
|
+
onMountAsyncDebounceMs?: number;
|
|
12
|
+
onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError;
|
|
13
|
+
onChangeAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
|
|
14
|
+
onChangeAsyncDebounceMs?: number;
|
|
15
|
+
onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError;
|
|
16
|
+
onBlurAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
|
|
17
|
+
onBlurAsyncDebounceMs?: number;
|
|
18
|
+
onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>;
|
|
19
|
+
onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void;
|
|
20
|
+
};
|
|
21
|
+
type FieldInfo<TFormData> = {
|
|
22
|
+
instances: Record<string, FieldApi<any, TFormData>>;
|
|
23
|
+
} & ValidationMeta;
|
|
24
|
+
type ValidationMeta = {
|
|
25
|
+
validationCount?: number;
|
|
26
|
+
validationAsyncCount?: number;
|
|
27
|
+
validationPromise?: Promise<ValidationError>;
|
|
28
|
+
validationResolve?: (error: ValidationError) => void;
|
|
29
|
+
validationReject?: (error: unknown) => void;
|
|
30
|
+
};
|
|
31
|
+
type ValidationError = undefined | false | null | string;
|
|
32
|
+
type FormState<TData> = {
|
|
33
|
+
values: TData;
|
|
34
|
+
isFormValidating: boolean;
|
|
35
|
+
formValidationCount: number;
|
|
36
|
+
isFormValid: boolean;
|
|
37
|
+
formError?: ValidationError;
|
|
38
|
+
fieldMeta: Record<DeepKeys<TData>, FieldMeta>;
|
|
39
|
+
isFieldsValidating: boolean;
|
|
40
|
+
isFieldsValid: boolean;
|
|
41
|
+
isSubmitting: boolean;
|
|
42
|
+
isTouched: boolean;
|
|
43
|
+
isSubmitted: boolean;
|
|
44
|
+
isValidating: boolean;
|
|
45
|
+
isValid: boolean;
|
|
46
|
+
canSubmit: boolean;
|
|
47
|
+
submissionAttempts: number;
|
|
48
|
+
};
|
|
49
|
+
declare class FormApi<TFormData> {
|
|
50
|
+
options: FormOptions<TFormData>;
|
|
51
|
+
store: Store<FormState<TFormData>>;
|
|
52
|
+
state: FormState<TFormData>;
|
|
53
|
+
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>;
|
|
54
|
+
fieldName?: string;
|
|
55
|
+
validationMeta: ValidationMeta;
|
|
56
|
+
constructor(opts?: FormOptions<TFormData>);
|
|
57
|
+
update: (options?: FormOptions<TFormData>) => void;
|
|
58
|
+
reset: () => void;
|
|
59
|
+
validateAllFields: (cause: ValidationCause) => Promise<ValidationError[]>;
|
|
60
|
+
handleSubmit: () => Promise<void>;
|
|
61
|
+
getFieldValue: <TField extends DeepKeys<TFormData>>(field: TField) => DeepValue<TFormData, TField>;
|
|
62
|
+
getFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField) => FieldMeta | undefined;
|
|
63
|
+
getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => Record<DeepKeys<TFormData>, FieldInfo<TFormData>>[TField];
|
|
64
|
+
setFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<FieldMeta>) => void;
|
|
65
|
+
setFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<DeepValue<TFormData, TField>>, opts?: {
|
|
66
|
+
touch?: boolean;
|
|
67
|
+
}) => void;
|
|
68
|
+
pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField>[number], opts?: {
|
|
69
|
+
touch?: boolean;
|
|
70
|
+
}) => void;
|
|
71
|
+
insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField>[number], opts?: {
|
|
72
|
+
touch?: boolean;
|
|
73
|
+
}) => void;
|
|
74
|
+
removeFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, opts?: {
|
|
75
|
+
touch?: boolean;
|
|
76
|
+
}) => void;
|
|
77
|
+
swapFieldValues: <TField extends DeepKeys<TFormData>>(field: TField, index1: number, index2: number) => void;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type ValidationCause = 'change' | 'blur' | 'submit';
|
|
81
|
+
type ValidateFn<TData, TFormData> = (value: TData, fieldApi: FieldApi<TData, TFormData>) => ValidationError;
|
|
82
|
+
type ValidateAsyncFn<TData, TFormData> = (value: TData, fieldApi: FieldApi<TData, TFormData>) => ValidationError | Promise<ValidationError>;
|
|
83
|
+
interface FieldOptions<_TData, TFormData,
|
|
84
|
+
/**
|
|
85
|
+
* This allows us to restrict the name to only be a valid field name while
|
|
86
|
+
* also assigning it to a generic
|
|
87
|
+
*/
|
|
88
|
+
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
|
|
89
|
+
/**
|
|
90
|
+
* If TData is unknown, we can use the TName generic to determine the type
|
|
91
|
+
*/
|
|
92
|
+
TData = unknown extends _TData ? DeepValue<TFormData, TName> : _TData> {
|
|
93
|
+
name: TName;
|
|
94
|
+
index?: TData extends any[] ? number : never;
|
|
95
|
+
defaultValue?: TData;
|
|
96
|
+
asyncDebounceMs?: number;
|
|
97
|
+
asyncAlways?: boolean;
|
|
98
|
+
onMount?: (formApi: FieldApi<TData, TFormData>) => void;
|
|
99
|
+
onChange?: ValidateFn<TData, TFormData>;
|
|
100
|
+
onChangeAsync?: ValidateAsyncFn<TData, TFormData>;
|
|
101
|
+
onChangeAsyncDebounceMs?: number;
|
|
102
|
+
onBlur?: ValidateFn<TData, TFormData>;
|
|
103
|
+
onBlurAsync?: ValidateAsyncFn<TData, TFormData>;
|
|
104
|
+
onBlurAsyncDebounceMs?: number;
|
|
105
|
+
onSubmitAsync?: ValidateAsyncFn<TData, TFormData>;
|
|
106
|
+
defaultMeta?: Partial<FieldMeta>;
|
|
107
|
+
}
|
|
108
|
+
type FieldApiOptions<TData, TFormData> = FieldOptions<TData, TFormData> & {
|
|
109
|
+
form: FormApi<TFormData>;
|
|
110
|
+
};
|
|
111
|
+
type FieldMeta = {
|
|
112
|
+
isTouched: boolean;
|
|
113
|
+
touchedError?: ValidationError;
|
|
114
|
+
error?: ValidationError;
|
|
115
|
+
isValidating: boolean;
|
|
116
|
+
};
|
|
117
|
+
type FieldState<TData> = {
|
|
118
|
+
value: TData;
|
|
119
|
+
meta: FieldMeta;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* TData may not be known at the time of FieldApi construction, so we need to
|
|
123
|
+
* use a conditional type to determine if TData is known or not.
|
|
124
|
+
*
|
|
125
|
+
* If TData is not known, we use the TFormData type to determine the type of
|
|
126
|
+
* the field value based on the field name.
|
|
127
|
+
*/
|
|
128
|
+
type GetTData<Name, TData, TFormData> = unknown extends TData ? DeepValue<TFormData, Name> : TData;
|
|
129
|
+
declare class FieldApi<TData, TFormData> {
|
|
130
|
+
#private;
|
|
131
|
+
uid: number;
|
|
132
|
+
form: FormApi<TFormData>;
|
|
133
|
+
name: DeepKeys<TFormData>;
|
|
134
|
+
/**
|
|
135
|
+
* This is a hack that allows us to use `GetTData` without calling it everywhere
|
|
136
|
+
*
|
|
137
|
+
* Unfortunately this hack appears to be needed alongside the `TName` hack
|
|
138
|
+
* further up in this file. This properly types all of the internal methods,
|
|
139
|
+
* while the `TName` hack types the options properly
|
|
140
|
+
*/
|
|
141
|
+
_tdata: GetTData<typeof this$1.name, TData, TFormData>;
|
|
142
|
+
store: Store<FieldState<typeof this$1._tdata>>;
|
|
143
|
+
state: FieldState<typeof this$1._tdata>;
|
|
144
|
+
prevState: FieldState<typeof this$1._tdata>;
|
|
145
|
+
options: FieldOptions<typeof this$1._tdata, TFormData>;
|
|
146
|
+
constructor(opts: FieldApiOptions<TData, TFormData>);
|
|
147
|
+
mount: () => () => void;
|
|
148
|
+
update: (opts: FieldApiOptions<typeof this$1._tdata, TFormData>) => void;
|
|
149
|
+
getValue: () => typeof this$1._tdata;
|
|
150
|
+
setValue: (updater: Updater<typeof this$1._tdata>, options?: {
|
|
151
|
+
touch?: boolean;
|
|
152
|
+
notify?: boolean;
|
|
153
|
+
}) => void;
|
|
154
|
+
_getMeta: () => FieldMeta | undefined;
|
|
155
|
+
getMeta: () => FieldMeta;
|
|
156
|
+
setMeta: (updater: Updater<FieldMeta>) => void;
|
|
157
|
+
getInfo: () => Record<DeepKeys<TFormData>, FieldInfo<TFormData>>[DeepKeys<TFormData>];
|
|
158
|
+
pushValue: (value: typeof this$1._tdata extends any[] ? (typeof this$1._tdata)[number] : never) => void;
|
|
159
|
+
insertValue: (index: number, value: typeof this$1._tdata extends any[] ? (typeof this$1._tdata)[number] : never) => void;
|
|
160
|
+
removeValue: (index: number) => void;
|
|
161
|
+
swapValues: (aIndex: number, bIndex: number) => void;
|
|
162
|
+
getSubField: <TName extends DeepKeys<GetTData<DeepKeys<TFormData>, TData, TFormData>>>(name: TName) => FieldApi<DeepValue<GetTData<DeepKeys<TFormData>, TData, TFormData>, TName>, TFormData>;
|
|
163
|
+
validateSync: (value: GetTData<DeepKeys<TFormData>, TData, TFormData> | undefined, cause: ValidationCause) => void;
|
|
164
|
+
cancelValidateAsync: () => void;
|
|
165
|
+
validateAsync: (value: GetTData<DeepKeys<TFormData>, TData, TFormData> | undefined, cause: ValidationCause) => Promise<ValidationError>;
|
|
166
|
+
validate: (cause: ValidationCause, value?: typeof this$1._tdata) => ValidationError | Promise<ValidationError>;
|
|
167
|
+
handleChange: (updater: Updater<typeof this$1._tdata>) => void;
|
|
168
|
+
handleBlur: () => void;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, Updater, ValidationCause, ValidationError, ValidationMeta };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { Store } from '@tanstack/store';
|
|
2
|
+
import { DeepKeys, DeepValue, Updater } from './utils.js';
|
|
3
|
+
export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, setBy } from './utils.js';
|
|
4
|
+
|
|
5
|
+
type FormOptions<TData> = {
|
|
6
|
+
defaultValues?: TData;
|
|
7
|
+
defaultState?: Partial<FormState<TData>>;
|
|
8
|
+
asyncDebounceMs?: number;
|
|
9
|
+
onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError;
|
|
10
|
+
onMountAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
|
|
11
|
+
onMountAsyncDebounceMs?: number;
|
|
12
|
+
onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError;
|
|
13
|
+
onChangeAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
|
|
14
|
+
onChangeAsyncDebounceMs?: number;
|
|
15
|
+
onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError;
|
|
16
|
+
onBlurAsync?: (values: TData, formApi: FormApi<TData>) => ValidationError | Promise<ValidationError>;
|
|
17
|
+
onBlurAsyncDebounceMs?: number;
|
|
18
|
+
onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>;
|
|
19
|
+
onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void;
|
|
20
|
+
};
|
|
21
|
+
type FieldInfo<TFormData> = {
|
|
22
|
+
instances: Record<string, FieldApi<any, TFormData>>;
|
|
23
|
+
} & ValidationMeta;
|
|
24
|
+
type ValidationMeta = {
|
|
25
|
+
validationCount?: number;
|
|
26
|
+
validationAsyncCount?: number;
|
|
27
|
+
validationPromise?: Promise<ValidationError>;
|
|
28
|
+
validationResolve?: (error: ValidationError) => void;
|
|
29
|
+
validationReject?: (error: unknown) => void;
|
|
30
|
+
};
|
|
31
|
+
type ValidationError = undefined | false | null | string;
|
|
32
|
+
type FormState<TData> = {
|
|
33
|
+
values: TData;
|
|
34
|
+
isFormValidating: boolean;
|
|
35
|
+
formValidationCount: number;
|
|
36
|
+
isFormValid: boolean;
|
|
37
|
+
formError?: ValidationError;
|
|
38
|
+
fieldMeta: Record<DeepKeys<TData>, FieldMeta>;
|
|
39
|
+
isFieldsValidating: boolean;
|
|
40
|
+
isFieldsValid: boolean;
|
|
41
|
+
isSubmitting: boolean;
|
|
42
|
+
isTouched: boolean;
|
|
43
|
+
isSubmitted: boolean;
|
|
44
|
+
isValidating: boolean;
|
|
45
|
+
isValid: boolean;
|
|
46
|
+
canSubmit: boolean;
|
|
47
|
+
submissionAttempts: number;
|
|
48
|
+
};
|
|
49
|
+
declare class FormApi<TFormData> {
|
|
50
|
+
options: FormOptions<TFormData>;
|
|
51
|
+
store: Store<FormState<TFormData>>;
|
|
52
|
+
state: FormState<TFormData>;
|
|
53
|
+
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>;
|
|
54
|
+
fieldName?: string;
|
|
55
|
+
validationMeta: ValidationMeta;
|
|
56
|
+
constructor(opts?: FormOptions<TFormData>);
|
|
57
|
+
update: (options?: FormOptions<TFormData>) => void;
|
|
58
|
+
reset: () => void;
|
|
59
|
+
validateAllFields: (cause: ValidationCause) => Promise<ValidationError[]>;
|
|
60
|
+
handleSubmit: () => Promise<void>;
|
|
61
|
+
getFieldValue: <TField extends DeepKeys<TFormData>>(field: TField) => DeepValue<TFormData, TField>;
|
|
62
|
+
getFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField) => FieldMeta | undefined;
|
|
63
|
+
getFieldInfo: <TField extends DeepKeys<TFormData>>(field: TField) => Record<DeepKeys<TFormData>, FieldInfo<TFormData>>[TField];
|
|
64
|
+
setFieldMeta: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<FieldMeta>) => void;
|
|
65
|
+
setFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<DeepValue<TFormData, TField>>, opts?: {
|
|
66
|
+
touch?: boolean;
|
|
67
|
+
}) => void;
|
|
68
|
+
pushFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField>[number], opts?: {
|
|
69
|
+
touch?: boolean;
|
|
70
|
+
}) => void;
|
|
71
|
+
insertFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField>[number], opts?: {
|
|
72
|
+
touch?: boolean;
|
|
73
|
+
}) => void;
|
|
74
|
+
removeFieldValue: <TField extends DeepKeys<TFormData>>(field: TField, index: number, opts?: {
|
|
75
|
+
touch?: boolean;
|
|
76
|
+
}) => void;
|
|
77
|
+
swapFieldValues: <TField extends DeepKeys<TFormData>>(field: TField, index1: number, index2: number) => void;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type ValidationCause = 'change' | 'blur' | 'submit';
|
|
81
|
+
type ValidateFn<TData, TFormData> = (value: TData, fieldApi: FieldApi<TData, TFormData>) => ValidationError;
|
|
82
|
+
type ValidateAsyncFn<TData, TFormData> = (value: TData, fieldApi: FieldApi<TData, TFormData>) => ValidationError | Promise<ValidationError>;
|
|
83
|
+
interface FieldOptions<_TData, TFormData,
|
|
84
|
+
/**
|
|
85
|
+
* This allows us to restrict the name to only be a valid field name while
|
|
86
|
+
* also assigning it to a generic
|
|
87
|
+
*/
|
|
88
|
+
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
|
|
89
|
+
/**
|
|
90
|
+
* If TData is unknown, we can use the TName generic to determine the type
|
|
91
|
+
*/
|
|
92
|
+
TData = unknown extends _TData ? DeepValue<TFormData, TName> : _TData> {
|
|
93
|
+
name: TName;
|
|
94
|
+
index?: TData extends any[] ? number : never;
|
|
95
|
+
defaultValue?: TData;
|
|
96
|
+
asyncDebounceMs?: number;
|
|
97
|
+
asyncAlways?: boolean;
|
|
98
|
+
onMount?: (formApi: FieldApi<TData, TFormData>) => void;
|
|
99
|
+
onChange?: ValidateFn<TData, TFormData>;
|
|
100
|
+
onChangeAsync?: ValidateAsyncFn<TData, TFormData>;
|
|
101
|
+
onChangeAsyncDebounceMs?: number;
|
|
102
|
+
onBlur?: ValidateFn<TData, TFormData>;
|
|
103
|
+
onBlurAsync?: ValidateAsyncFn<TData, TFormData>;
|
|
104
|
+
onBlurAsyncDebounceMs?: number;
|
|
105
|
+
onSubmitAsync?: ValidateAsyncFn<TData, TFormData>;
|
|
106
|
+
defaultMeta?: Partial<FieldMeta>;
|
|
107
|
+
}
|
|
108
|
+
type FieldApiOptions<TData, TFormData> = FieldOptions<TData, TFormData> & {
|
|
109
|
+
form: FormApi<TFormData>;
|
|
110
|
+
};
|
|
111
|
+
type FieldMeta = {
|
|
112
|
+
isTouched: boolean;
|
|
113
|
+
touchedError?: ValidationError;
|
|
114
|
+
error?: ValidationError;
|
|
115
|
+
isValidating: boolean;
|
|
116
|
+
};
|
|
117
|
+
type FieldState<TData> = {
|
|
118
|
+
value: TData;
|
|
119
|
+
meta: FieldMeta;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* TData may not be known at the time of FieldApi construction, so we need to
|
|
123
|
+
* use a conditional type to determine if TData is known or not.
|
|
124
|
+
*
|
|
125
|
+
* If TData is not known, we use the TFormData type to determine the type of
|
|
126
|
+
* the field value based on the field name.
|
|
127
|
+
*/
|
|
128
|
+
type GetTData<Name, TData, TFormData> = unknown extends TData ? DeepValue<TFormData, Name> : TData;
|
|
129
|
+
declare class FieldApi<TData, TFormData> {
|
|
130
|
+
#private;
|
|
131
|
+
uid: number;
|
|
132
|
+
form: FormApi<TFormData>;
|
|
133
|
+
name: DeepKeys<TFormData>;
|
|
134
|
+
/**
|
|
135
|
+
* This is a hack that allows us to use `GetTData` without calling it everywhere
|
|
136
|
+
*
|
|
137
|
+
* Unfortunately this hack appears to be needed alongside the `TName` hack
|
|
138
|
+
* further up in this file. This properly types all of the internal methods,
|
|
139
|
+
* while the `TName` hack types the options properly
|
|
140
|
+
*/
|
|
141
|
+
_tdata: GetTData<typeof this$1.name, TData, TFormData>;
|
|
142
|
+
store: Store<FieldState<typeof this$1._tdata>>;
|
|
143
|
+
state: FieldState<typeof this$1._tdata>;
|
|
144
|
+
prevState: FieldState<typeof this$1._tdata>;
|
|
145
|
+
options: FieldOptions<typeof this$1._tdata, TFormData>;
|
|
146
|
+
constructor(opts: FieldApiOptions<TData, TFormData>);
|
|
147
|
+
mount: () => () => void;
|
|
148
|
+
update: (opts: FieldApiOptions<typeof this$1._tdata, TFormData>) => void;
|
|
149
|
+
getValue: () => typeof this$1._tdata;
|
|
150
|
+
setValue: (updater: Updater<typeof this$1._tdata>, options?: {
|
|
151
|
+
touch?: boolean;
|
|
152
|
+
notify?: boolean;
|
|
153
|
+
}) => void;
|
|
154
|
+
_getMeta: () => FieldMeta | undefined;
|
|
155
|
+
getMeta: () => FieldMeta;
|
|
156
|
+
setMeta: (updater: Updater<FieldMeta>) => void;
|
|
157
|
+
getInfo: () => Record<DeepKeys<TFormData>, FieldInfo<TFormData>>[DeepKeys<TFormData>];
|
|
158
|
+
pushValue: (value: typeof this$1._tdata extends any[] ? (typeof this$1._tdata)[number] : never) => void;
|
|
159
|
+
insertValue: (index: number, value: typeof this$1._tdata extends any[] ? (typeof this$1._tdata)[number] : never) => void;
|
|
160
|
+
removeValue: (index: number) => void;
|
|
161
|
+
swapValues: (aIndex: number, bIndex: number) => void;
|
|
162
|
+
getSubField: <TName extends DeepKeys<GetTData<DeepKeys<TFormData>, TData, TFormData>>>(name: TName) => FieldApi<DeepValue<GetTData<DeepKeys<TFormData>, TData, TFormData>, TName>, TFormData>;
|
|
163
|
+
validateSync: (value: GetTData<DeepKeys<TFormData>, TData, TFormData> | undefined, cause: ValidationCause) => void;
|
|
164
|
+
cancelValidateAsync: () => void;
|
|
165
|
+
validateAsync: (value: GetTData<DeepKeys<TFormData>, TData, TFormData> | undefined, cause: ValidationCause) => Promise<ValidationError>;
|
|
166
|
+
validate: (cause: ValidationCause, value?: typeof this$1._tdata) => ValidationError | Promise<ValidationError>;
|
|
167
|
+
handleChange: (updater: Updater<typeof this$1._tdata>) => void;
|
|
168
|
+
handleBlur: () => void;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export { DeepKeys, DeepValue, FieldApi, FieldApiOptions, FieldInfo, FieldMeta, FieldOptions, FieldState, FormApi, FormOptions, FormState, Updater, ValidationCause, ValidationError, ValidationMeta };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './FormApi'\nexport * from './FieldApi'\nexport * from './utils'\n"],"mappings":";AAAA,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/utils.ts
|
|
21
|
+
var utils_exports = {};
|
|
22
|
+
__export(utils_exports, {
|
|
23
|
+
functionalUpdate: () => functionalUpdate,
|
|
24
|
+
getBy: () => getBy,
|
|
25
|
+
setBy: () => setBy
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(utils_exports);
|
|
28
|
+
function functionalUpdate(updater, input) {
|
|
29
|
+
return typeof updater === "function" ? updater(input) : updater;
|
|
30
|
+
}
|
|
31
|
+
function getBy(obj, path) {
|
|
32
|
+
const pathArray = makePathArray(path);
|
|
33
|
+
const pathObj = pathArray;
|
|
34
|
+
return pathObj.reduce((current, pathPart) => {
|
|
35
|
+
if (typeof current !== "undefined") {
|
|
36
|
+
return current[pathPart];
|
|
37
|
+
}
|
|
38
|
+
return void 0;
|
|
39
|
+
}, obj);
|
|
40
|
+
}
|
|
41
|
+
function setBy(obj, _path, updater) {
|
|
42
|
+
const path = makePathArray(_path);
|
|
43
|
+
function doSet(parent) {
|
|
44
|
+
if (!path.length) {
|
|
45
|
+
return functionalUpdate(updater, parent);
|
|
46
|
+
}
|
|
47
|
+
const key = path.shift();
|
|
48
|
+
if (typeof key === "string") {
|
|
49
|
+
if (typeof parent === "object") {
|
|
50
|
+
return {
|
|
51
|
+
...parent,
|
|
52
|
+
[key]: doSet(parent[key])
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
[key]: doSet()
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (typeof key === "number") {
|
|
60
|
+
if (Array.isArray(parent)) {
|
|
61
|
+
const prefix = parent.slice(0, key);
|
|
62
|
+
return [
|
|
63
|
+
...prefix.length ? prefix : new Array(key),
|
|
64
|
+
doSet(parent[key]),
|
|
65
|
+
...parent.slice(key + 1)
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
return [...new Array(key), doSet()];
|
|
69
|
+
}
|
|
70
|
+
throw new Error("Uh oh!");
|
|
71
|
+
}
|
|
72
|
+
return doSet(obj);
|
|
73
|
+
}
|
|
74
|
+
var reFindNumbers0 = /^(\d*)$/gm;
|
|
75
|
+
var reFindNumbers1 = /\.(\d*)\./gm;
|
|
76
|
+
var reFindNumbers2 = /^(\d*)\./gm;
|
|
77
|
+
var reFindNumbers3 = /\.(\d*$)/gm;
|
|
78
|
+
var reFindMultiplePeriods = /\.{2,}/gm;
|
|
79
|
+
var intPrefix = "__int__";
|
|
80
|
+
var intReplace = `${intPrefix}$1`;
|
|
81
|
+
function makePathArray(str) {
|
|
82
|
+
if (typeof str !== "string") {
|
|
83
|
+
throw new Error("Path must be a string.");
|
|
84
|
+
}
|
|
85
|
+
return str.replace("[", ".").replace("]", "").replace(reFindNumbers0, intReplace).replace(reFindNumbers1, `.${intReplace}.`).replace(reFindNumbers2, `${intReplace}.`).replace(reFindNumbers3, `.${intReplace}`).replace(reFindMultiplePeriods, ".").split(".").map((d) => {
|
|
86
|
+
if (d.indexOf(intPrefix) === 0) {
|
|
87
|
+
return parseInt(d.substring(intPrefix.length), 10);
|
|
88
|
+
}
|
|
89
|
+
return d;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
93
|
+
0 && (module.exports = {
|
|
94
|
+
functionalUpdate,
|
|
95
|
+
getBy,
|
|
96
|
+
setBy
|
|
97
|
+
});
|
|
98
|
+
//# sourceMappingURL=utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils.ts"],"sourcesContent":["export type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput\n\nexport type Updater<TInput, TOutput = TInput> =\n | TOutput\n | UpdaterFn<TInput, TOutput>\n\nexport function functionalUpdate<TInput, TOutput = TInput>(\n updater: Updater<TInput, TOutput>,\n input: TInput,\n): TOutput {\n return typeof updater === 'function'\n ? (updater as UpdaterFn<TInput, TOutput>)(input)\n : updater\n}\n\n/**\n * Get a value from an object using a path, including dot notation.\n */\nexport function getBy(obj: any, path: any) {\n const pathArray = makePathArray(path)\n const pathObj = pathArray\n return pathObj.reduce((current: any, pathPart: any) => {\n if (typeof current !== 'undefined') {\n return current[pathPart]\n }\n return undefined\n }, obj)\n}\n\n/**\n * Set a value on an object using a path, including dot notation.\n */\nexport function setBy(obj: any, _path: any, updater: Updater<any>) {\n const path = makePathArray(_path)\n\n function doSet(parent?: any): any {\n if (!path.length) {\n return functionalUpdate(updater, parent)\n }\n\n const key = path.shift()\n\n if (typeof key === 'string') {\n if (typeof parent === 'object') {\n return {\n ...parent,\n [key]: doSet(parent[key]),\n }\n }\n return {\n [key]: doSet(),\n }\n }\n\n if (typeof key === 'number') {\n if (Array.isArray(parent)) {\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doSet(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n return [...new Array(key), doSet()]\n }\n\n throw new Error('Uh oh!')\n }\n\n return doSet(obj)\n}\n\nconst reFindNumbers0 = /^(\\d*)$/gm\nconst reFindNumbers1 = /\\.(\\d*)\\./gm\nconst reFindNumbers2 = /^(\\d*)\\./gm\nconst reFindNumbers3 = /\\.(\\d*$)/gm\nconst reFindMultiplePeriods = /\\.{2,}/gm\n\nconst intPrefix = '__int__'\nconst intReplace = `${intPrefix}$1`\n\nfunction makePathArray(str: string) {\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return str\n .replace('[', '.')\n .replace(']', '')\n .replace(reFindNumbers0, intReplace)\n .replace(reFindNumbers1, `.${intReplace}.`)\n .replace(reFindNumbers2, `${intReplace}.`)\n .replace(reFindNumbers3, `.${intReplace}`)\n .replace(reFindMultiplePeriods, '.')\n .split('.')\n .map((d) => {\n if (d.indexOf(intPrefix) === 0) {\n return parseInt(d.substring(intPrefix.length), 10)\n }\n return d\n })\n}\n\nexport type RequiredByKey<T, K extends keyof T> = Omit<T, K> &\n Required<Pick<T, K>>\n\ntype ComputeRange<\n N extends number,\n Result extends Array<unknown> = [],\n> = Result['length'] extends N\n ? Result\n : ComputeRange<N, [...Result, Result['length']]>\ntype Index40 = ComputeRange<40>[number]\n\n// Is this type a tuple?\ntype IsTuple<T> = T extends readonly any[] & { length: infer Length }\n ? Length extends Index40\n ? T\n : never\n : never\n\n// If this type is a tuple, what indices are allowed?\ntype AllowedIndexes<\n Tuple extends ReadonlyArray<any>,\n Keys extends number = never,\n> = Tuple extends readonly []\n ? Keys\n : Tuple extends readonly [infer _, ...infer Tail]\n ? AllowedIndexes<Tail, Keys | Tail['length']>\n : Keys\n\nexport type DeepKeys<T> = unknown extends T\n ? keyof T\n : object extends T\n ? string\n : T extends readonly any[] & IsTuple<T>\n ? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>>\n : T extends any[]\n ? DeepKeys<T[number]>\n : T extends Date\n ? never\n : T extends object\n ? (keyof T & string) | DeepKeysPrefix<T, keyof T>\n : never\n\ntype DeepKeysPrefix<T, TPrefix> = TPrefix extends keyof T & (number | string)\n ? `${TPrefix}.${DeepKeys<T[TPrefix]> & string}`\n : never\n\nexport type DeepValue<T, TProp> = T extends Record<string | number, any>\n ? TProp extends `${infer TBranch}.${infer TDeepProp}`\n ? DeepValue<T[TBranch], TDeepProp>\n : T[TProp & string]\n : never\n\ntype Narrowable = string | number | bigint | boolean\n\ntype NarrowRaw<A> =\n | (A extends [] ? [] : never)\n | (A extends Narrowable ? A : never)\n | {\n [K in keyof A]: A[K] extends Function ? A[K] : NarrowRaw<A[K]>\n }\n\nexport type Narrow<A> = Try<A, [], NarrowRaw<A>>\n\ntype Try<A1, A2, Catch = never> = A1 extends A2 ? A1 : Catch\n\n// Hack to get TypeScript to show simplified types in error messages\nexport type Pretty<T> = { [K in keyof T]: T[K] } & {}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,SAAS,iBACd,SACA,OACS;AACT,SAAO,OAAO,YAAY,aACrB,QAAuC,KAAK,IAC7C;AACN;AAKO,SAAS,MAAM,KAAU,MAAW;AACzC,QAAM,YAAY,cAAc,IAAI;AACpC,QAAM,UAAU;AAChB,SAAO,QAAQ,OAAO,CAAC,SAAc,aAAkB;AACrD,QAAI,OAAO,YAAY,aAAa;AAClC,aAAO,QAAQ,QAAQ;AAAA,IACzB;AACA,WAAO;AAAA,EACT,GAAG,GAAG;AACR;AAKO,SAAS,MAAM,KAAU,OAAY,SAAuB;AACjE,QAAM,OAAO,cAAc,KAAK;AAEhC,WAAS,MAAM,QAAmB;AAChC,QAAI,CAAC,KAAK,QAAQ;AAChB,aAAO,iBAAiB,SAAS,MAAM;AAAA,IACzC;AAEA,UAAM,MAAM,KAAK,MAAM;AAEvB,QAAI,OAAO,QAAQ,UAAU;AAC3B,UAAI,OAAO,WAAW,UAAU;AAC9B,eAAO;AAAA,UACL,GAAG;AAAA,UACH,CAAC,GAAG,GAAG,MAAM,OAAO,GAAG,CAAC;AAAA,QAC1B;AAAA,MACF;AACA,aAAO;AAAA,QACL,CAAC,GAAG,GAAG,MAAM;AAAA,MACf;AAAA,IACF;AAEA,QAAI,OAAO,QAAQ,UAAU;AAC3B,UAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,cAAM,SAAS,OAAO,MAAM,GAAG,GAAG;AAClC,eAAO;AAAA,UACL,GAAI,OAAO,SAAS,SAAS,IAAI,MAAM,GAAG;AAAA,UAC1C,MAAM,OAAO,GAAG,CAAC;AAAA,UACjB,GAAG,OAAO,MAAM,MAAM,CAAC;AAAA,QACzB;AAAA,MACF;AACA,aAAO,CAAC,GAAG,IAAI,MAAM,GAAG,GAAG,MAAM,CAAC;AAAA,IACpC;AAEA,UAAM,IAAI,MAAM,QAAQ;AAAA,EAC1B;AAEA,SAAO,MAAM,GAAG;AAClB;AAEA,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAE9B,IAAM,YAAY;AAClB,IAAM,aAAa,GAAG,SAAS;AAE/B,SAAS,cAAc,KAAa;AAClC,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,SAAO,IACJ,QAAQ,KAAK,GAAG,EAChB,QAAQ,KAAK,EAAE,EACf,QAAQ,gBAAgB,UAAU,EAClC,QAAQ,gBAAgB,IAAI,UAAU,GAAG,EACzC,QAAQ,gBAAgB,GAAG,UAAU,GAAG,EACxC,QAAQ,gBAAgB,IAAI,UAAU,EAAE,EACxC,QAAQ,uBAAuB,GAAG,EAClC,MAAM,GAAG,EACT,IAAI,CAAC,MAAM;AACV,QAAI,EAAE,QAAQ,SAAS,MAAM,GAAG;AAC9B,aAAO,SAAS,EAAE,UAAU,UAAU,MAAM,GAAG,EAAE;AAAA,IACnD;AACA,WAAO;AAAA,EACT,CAAC;AACL;","names":[]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput;
|
|
2
|
+
type Updater<TInput, TOutput = TInput> = TOutput | UpdaterFn<TInput, TOutput>;
|
|
3
|
+
declare function functionalUpdate<TInput, TOutput = TInput>(updater: Updater<TInput, TOutput>, input: TInput): TOutput;
|
|
4
|
+
/**
|
|
5
|
+
* Get a value from an object using a path, including dot notation.
|
|
6
|
+
*/
|
|
7
|
+
declare function getBy(obj: any, path: any): any;
|
|
8
|
+
/**
|
|
9
|
+
* Set a value on an object using a path, including dot notation.
|
|
10
|
+
*/
|
|
11
|
+
declare function setBy(obj: any, _path: any, updater: Updater<any>): any;
|
|
12
|
+
type RequiredByKey<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
13
|
+
type ComputeRange<N extends number, Result extends Array<unknown> = []> = Result['length'] extends N ? Result : ComputeRange<N, [...Result, Result['length']]>;
|
|
14
|
+
type Index40 = ComputeRange<40>[number];
|
|
15
|
+
type IsTuple<T> = T extends readonly any[] & {
|
|
16
|
+
length: infer Length;
|
|
17
|
+
} ? Length extends Index40 ? T : never : never;
|
|
18
|
+
type AllowedIndexes<Tuple extends ReadonlyArray<any>, Keys extends number = never> = Tuple extends readonly [] ? Keys : Tuple extends readonly [infer _, ...infer Tail] ? AllowedIndexes<Tail, Keys | Tail['length']> : Keys;
|
|
19
|
+
type DeepKeys<T> = unknown extends T ? keyof T : object extends T ? string : T extends readonly any[] & IsTuple<T> ? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>> : T extends any[] ? DeepKeys<T[number]> : T extends Date ? never : T extends object ? (keyof T & string) | DeepKeysPrefix<T, keyof T> : never;
|
|
20
|
+
type DeepKeysPrefix<T, TPrefix> = TPrefix extends keyof T & (number | string) ? `${TPrefix}.${DeepKeys<T[TPrefix]> & string}` : never;
|
|
21
|
+
type DeepValue<T, TProp> = T extends Record<string | number, any> ? TProp extends `${infer TBranch}.${infer TDeepProp}` ? DeepValue<T[TBranch], TDeepProp> : T[TProp & string] : never;
|
|
22
|
+
type Narrowable = string | number | bigint | boolean;
|
|
23
|
+
type NarrowRaw<A> = (A extends [] ? [] : never) | (A extends Narrowable ? A : never) | {
|
|
24
|
+
[K in keyof A]: A[K] extends Function ? A[K] : NarrowRaw<A[K]>;
|
|
25
|
+
};
|
|
26
|
+
type Narrow<A> = Try<A, [], NarrowRaw<A>>;
|
|
27
|
+
type Try<A1, A2, Catch = never> = A1 extends A2 ? A1 : Catch;
|
|
28
|
+
type Pretty<T> = {
|
|
29
|
+
[K in keyof T]: T[K];
|
|
30
|
+
} & {};
|
|
31
|
+
|
|
32
|
+
export { DeepKeys, DeepValue, Narrow, Pretty, RequiredByKey, Updater, UpdaterFn, functionalUpdate, getBy, setBy };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput;
|
|
2
|
+
type Updater<TInput, TOutput = TInput> = TOutput | UpdaterFn<TInput, TOutput>;
|
|
3
|
+
declare function functionalUpdate<TInput, TOutput = TInput>(updater: Updater<TInput, TOutput>, input: TInput): TOutput;
|
|
4
|
+
/**
|
|
5
|
+
* Get a value from an object using a path, including dot notation.
|
|
6
|
+
*/
|
|
7
|
+
declare function getBy(obj: any, path: any): any;
|
|
8
|
+
/**
|
|
9
|
+
* Set a value on an object using a path, including dot notation.
|
|
10
|
+
*/
|
|
11
|
+
declare function setBy(obj: any, _path: any, updater: Updater<any>): any;
|
|
12
|
+
type RequiredByKey<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
13
|
+
type ComputeRange<N extends number, Result extends Array<unknown> = []> = Result['length'] extends N ? Result : ComputeRange<N, [...Result, Result['length']]>;
|
|
14
|
+
type Index40 = ComputeRange<40>[number];
|
|
15
|
+
type IsTuple<T> = T extends readonly any[] & {
|
|
16
|
+
length: infer Length;
|
|
17
|
+
} ? Length extends Index40 ? T : never : never;
|
|
18
|
+
type AllowedIndexes<Tuple extends ReadonlyArray<any>, Keys extends number = never> = Tuple extends readonly [] ? Keys : Tuple extends readonly [infer _, ...infer Tail] ? AllowedIndexes<Tail, Keys | Tail['length']> : Keys;
|
|
19
|
+
type DeepKeys<T> = unknown extends T ? keyof T : object extends T ? string : T extends readonly any[] & IsTuple<T> ? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>> : T extends any[] ? DeepKeys<T[number]> : T extends Date ? never : T extends object ? (keyof T & string) | DeepKeysPrefix<T, keyof T> : never;
|
|
20
|
+
type DeepKeysPrefix<T, TPrefix> = TPrefix extends keyof T & (number | string) ? `${TPrefix}.${DeepKeys<T[TPrefix]> & string}` : never;
|
|
21
|
+
type DeepValue<T, TProp> = T extends Record<string | number, any> ? TProp extends `${infer TBranch}.${infer TDeepProp}` ? DeepValue<T[TBranch], TDeepProp> : T[TProp & string] : never;
|
|
22
|
+
type Narrowable = string | number | bigint | boolean;
|
|
23
|
+
type NarrowRaw<A> = (A extends [] ? [] : never) | (A extends Narrowable ? A : never) | {
|
|
24
|
+
[K in keyof A]: A[K] extends Function ? A[K] : NarrowRaw<A[K]>;
|
|
25
|
+
};
|
|
26
|
+
type Narrow<A> = Try<A, [], NarrowRaw<A>>;
|
|
27
|
+
type Try<A1, A2, Catch = never> = A1 extends A2 ? A1 : Catch;
|
|
28
|
+
type Pretty<T> = {
|
|
29
|
+
[K in keyof T]: T[K];
|
|
30
|
+
} & {};
|
|
31
|
+
|
|
32
|
+
export { DeepKeys, DeepValue, Narrow, Pretty, RequiredByKey, Updater, UpdaterFn, functionalUpdate, getBy, setBy };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import "./chunk-4QZDOMDG.js";
|
|
2
|
+
|
|
3
|
+
// src/utils.ts
|
|
4
|
+
function functionalUpdate(updater, input) {
|
|
5
|
+
return typeof updater === "function" ? updater(input) : updater;
|
|
6
|
+
}
|
|
7
|
+
function getBy(obj, path) {
|
|
8
|
+
const pathArray = makePathArray(path);
|
|
9
|
+
const pathObj = pathArray;
|
|
10
|
+
return pathObj.reduce((current, pathPart) => {
|
|
11
|
+
if (typeof current !== "undefined") {
|
|
12
|
+
return current[pathPart];
|
|
13
|
+
}
|
|
14
|
+
return void 0;
|
|
15
|
+
}, obj);
|
|
16
|
+
}
|
|
17
|
+
function setBy(obj, _path, updater) {
|
|
18
|
+
const path = makePathArray(_path);
|
|
19
|
+
function doSet(parent) {
|
|
20
|
+
if (!path.length) {
|
|
21
|
+
return functionalUpdate(updater, parent);
|
|
22
|
+
}
|
|
23
|
+
const key = path.shift();
|
|
24
|
+
if (typeof key === "string") {
|
|
25
|
+
if (typeof parent === "object") {
|
|
26
|
+
return {
|
|
27
|
+
...parent,
|
|
28
|
+
[key]: doSet(parent[key])
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
[key]: doSet()
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (typeof key === "number") {
|
|
36
|
+
if (Array.isArray(parent)) {
|
|
37
|
+
const prefix = parent.slice(0, key);
|
|
38
|
+
return [
|
|
39
|
+
...prefix.length ? prefix : new Array(key),
|
|
40
|
+
doSet(parent[key]),
|
|
41
|
+
...parent.slice(key + 1)
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
return [...new Array(key), doSet()];
|
|
45
|
+
}
|
|
46
|
+
throw new Error("Uh oh!");
|
|
47
|
+
}
|
|
48
|
+
return doSet(obj);
|
|
49
|
+
}
|
|
50
|
+
var reFindNumbers0 = /^(\d*)$/gm;
|
|
51
|
+
var reFindNumbers1 = /\.(\d*)\./gm;
|
|
52
|
+
var reFindNumbers2 = /^(\d*)\./gm;
|
|
53
|
+
var reFindNumbers3 = /\.(\d*$)/gm;
|
|
54
|
+
var reFindMultiplePeriods = /\.{2,}/gm;
|
|
55
|
+
var intPrefix = "__int__";
|
|
56
|
+
var intReplace = `${intPrefix}$1`;
|
|
57
|
+
function makePathArray(str) {
|
|
58
|
+
if (typeof str !== "string") {
|
|
59
|
+
throw new Error("Path must be a string.");
|
|
60
|
+
}
|
|
61
|
+
return str.replace("[", ".").replace("]", "").replace(reFindNumbers0, intReplace).replace(reFindNumbers1, `.${intReplace}.`).replace(reFindNumbers2, `${intReplace}.`).replace(reFindNumbers3, `.${intReplace}`).replace(reFindMultiplePeriods, ".").split(".").map((d) => {
|
|
62
|
+
if (d.indexOf(intPrefix) === 0) {
|
|
63
|
+
return parseInt(d.substring(intPrefix.length), 10);
|
|
64
|
+
}
|
|
65
|
+
return d;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
functionalUpdate,
|
|
70
|
+
getBy,
|
|
71
|
+
setBy
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils.ts"],"sourcesContent":["export type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput\n\nexport type Updater<TInput, TOutput = TInput> =\n | TOutput\n | UpdaterFn<TInput, TOutput>\n\nexport function functionalUpdate<TInput, TOutput = TInput>(\n updater: Updater<TInput, TOutput>,\n input: TInput,\n): TOutput {\n return typeof updater === 'function'\n ? (updater as UpdaterFn<TInput, TOutput>)(input)\n : updater\n}\n\n/**\n * Get a value from an object using a path, including dot notation.\n */\nexport function getBy(obj: any, path: any) {\n const pathArray = makePathArray(path)\n const pathObj = pathArray\n return pathObj.reduce((current: any, pathPart: any) => {\n if (typeof current !== 'undefined') {\n return current[pathPart]\n }\n return undefined\n }, obj)\n}\n\n/**\n * Set a value on an object using a path, including dot notation.\n */\nexport function setBy(obj: any, _path: any, updater: Updater<any>) {\n const path = makePathArray(_path)\n\n function doSet(parent?: any): any {\n if (!path.length) {\n return functionalUpdate(updater, parent)\n }\n\n const key = path.shift()\n\n if (typeof key === 'string') {\n if (typeof parent === 'object') {\n return {\n ...parent,\n [key]: doSet(parent[key]),\n }\n }\n return {\n [key]: doSet(),\n }\n }\n\n if (typeof key === 'number') {\n if (Array.isArray(parent)) {\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doSet(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n return [...new Array(key), doSet()]\n }\n\n throw new Error('Uh oh!')\n }\n\n return doSet(obj)\n}\n\nconst reFindNumbers0 = /^(\\d*)$/gm\nconst reFindNumbers1 = /\\.(\\d*)\\./gm\nconst reFindNumbers2 = /^(\\d*)\\./gm\nconst reFindNumbers3 = /\\.(\\d*$)/gm\nconst reFindMultiplePeriods = /\\.{2,}/gm\n\nconst intPrefix = '__int__'\nconst intReplace = `${intPrefix}$1`\n\nfunction makePathArray(str: string) {\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return str\n .replace('[', '.')\n .replace(']', '')\n .replace(reFindNumbers0, intReplace)\n .replace(reFindNumbers1, `.${intReplace}.`)\n .replace(reFindNumbers2, `${intReplace}.`)\n .replace(reFindNumbers3, `.${intReplace}`)\n .replace(reFindMultiplePeriods, '.')\n .split('.')\n .map((d) => {\n if (d.indexOf(intPrefix) === 0) {\n return parseInt(d.substring(intPrefix.length), 10)\n }\n return d\n })\n}\n\nexport type RequiredByKey<T, K extends keyof T> = Omit<T, K> &\n Required<Pick<T, K>>\n\ntype ComputeRange<\n N extends number,\n Result extends Array<unknown> = [],\n> = Result['length'] extends N\n ? Result\n : ComputeRange<N, [...Result, Result['length']]>\ntype Index40 = ComputeRange<40>[number]\n\n// Is this type a tuple?\ntype IsTuple<T> = T extends readonly any[] & { length: infer Length }\n ? Length extends Index40\n ? T\n : never\n : never\n\n// If this type is a tuple, what indices are allowed?\ntype AllowedIndexes<\n Tuple extends ReadonlyArray<any>,\n Keys extends number = never,\n> = Tuple extends readonly []\n ? Keys\n : Tuple extends readonly [infer _, ...infer Tail]\n ? AllowedIndexes<Tail, Keys | Tail['length']>\n : Keys\n\nexport type DeepKeys<T> = unknown extends T\n ? keyof T\n : object extends T\n ? string\n : T extends readonly any[] & IsTuple<T>\n ? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>>\n : T extends any[]\n ? DeepKeys<T[number]>\n : T extends Date\n ? never\n : T extends object\n ? (keyof T & string) | DeepKeysPrefix<T, keyof T>\n : never\n\ntype DeepKeysPrefix<T, TPrefix> = TPrefix extends keyof T & (number | string)\n ? `${TPrefix}.${DeepKeys<T[TPrefix]> & string}`\n : never\n\nexport type DeepValue<T, TProp> = T extends Record<string | number, any>\n ? TProp extends `${infer TBranch}.${infer TDeepProp}`\n ? DeepValue<T[TBranch], TDeepProp>\n : T[TProp & string]\n : never\n\ntype Narrowable = string | number | bigint | boolean\n\ntype NarrowRaw<A> =\n | (A extends [] ? [] : never)\n | (A extends Narrowable ? A : never)\n | {\n [K in keyof A]: A[K] extends Function ? A[K] : NarrowRaw<A[K]>\n }\n\nexport type Narrow<A> = Try<A, [], NarrowRaw<A>>\n\ntype Try<A1, A2, Catch = never> = A1 extends A2 ? A1 : Catch\n\n// Hack to get TypeScript to show simplified types in error messages\nexport type Pretty<T> = { [K in keyof T]: T[K] } & {}\n"],"mappings":";;;AAMO,SAAS,iBACd,SACA,OACS;AACT,SAAO,OAAO,YAAY,aACrB,QAAuC,KAAK,IAC7C;AACN;AAKO,SAAS,MAAM,KAAU,MAAW;AACzC,QAAM,YAAY,cAAc,IAAI;AACpC,QAAM,UAAU;AAChB,SAAO,QAAQ,OAAO,CAAC,SAAc,aAAkB;AACrD,QAAI,OAAO,YAAY,aAAa;AAClC,aAAO,QAAQ,QAAQ;AAAA,IACzB;AACA,WAAO;AAAA,EACT,GAAG,GAAG;AACR;AAKO,SAAS,MAAM,KAAU,OAAY,SAAuB;AACjE,QAAM,OAAO,cAAc,KAAK;AAEhC,WAAS,MAAM,QAAmB;AAChC,QAAI,CAAC,KAAK,QAAQ;AAChB,aAAO,iBAAiB,SAAS,MAAM;AAAA,IACzC;AAEA,UAAM,MAAM,KAAK,MAAM;AAEvB,QAAI,OAAO,QAAQ,UAAU;AAC3B,UAAI,OAAO,WAAW,UAAU;AAC9B,eAAO;AAAA,UACL,GAAG;AAAA,UACH,CAAC,GAAG,GAAG,MAAM,OAAO,GAAG,CAAC;AAAA,QAC1B;AAAA,MACF;AACA,aAAO;AAAA,QACL,CAAC,GAAG,GAAG,MAAM;AAAA,MACf;AAAA,IACF;AAEA,QAAI,OAAO,QAAQ,UAAU;AAC3B,UAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,cAAM,SAAS,OAAO,MAAM,GAAG,GAAG;AAClC,eAAO;AAAA,UACL,GAAI,OAAO,SAAS,SAAS,IAAI,MAAM,GAAG;AAAA,UAC1C,MAAM,OAAO,GAAG,CAAC;AAAA,UACjB,GAAG,OAAO,MAAM,MAAM,CAAC;AAAA,QACzB;AAAA,MACF;AACA,aAAO,CAAC,GAAG,IAAI,MAAM,GAAG,GAAG,MAAM,CAAC;AAAA,IACpC;AAEA,UAAM,IAAI,MAAM,QAAQ;AAAA,EAC1B;AAEA,SAAO,MAAM,GAAG;AAClB;AAEA,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAE9B,IAAM,YAAY;AAClB,IAAM,aAAa,GAAG,SAAS;AAE/B,SAAS,cAAc,KAAa;AAClC,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,SAAO,IACJ,QAAQ,KAAK,GAAG,EAChB,QAAQ,KAAK,EAAE,EACf,QAAQ,gBAAgB,UAAU,EAClC,QAAQ,gBAAgB,IAAI,UAAU,GAAG,EACzC,QAAQ,gBAAgB,GAAG,UAAU,GAAG,EACxC,QAAQ,gBAAgB,IAAI,UAAU,EAAE,EACxC,QAAQ,uBAAuB,GAAG,EAClC,MAAM,GAAG,EACT,IAAI,CAAC,MAAM;AACV,QAAI,EAAE,QAAQ,SAAS,MAAM,GAAG;AAC9B,aAAO,SAAS,EAAE,UAAU,UAAU,MAAM,GAAG,EAAE;AAAA,IACnD;AACA,WAAO;AAAA,EACT,CAAC;AACL;","names":[]}
|