cross-state 0.17.0 → 0.18.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/dist/cjs/react/index.cjs +60 -4
- package/dist/cjs/react/index.cjs.map +1 -1
- package/dist/es/index.mjs +9 -9
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/react/index.mjs +63 -7
- package/dist/es/react/index.mjs.map +1 -1
- package/dist/es/store.mjs +7 -7
- package/dist/es/useCache.mjs +1 -1
- package/dist/types/react/form/form.d.ts +13 -3
- package/dist/types/react/form/formArray.d.ts +21 -0
- package/dist/types/react/form/formField.d.ts +5 -20
- package/package.json +15 -13
package/dist/cjs/react/index.cjs
CHANGED
|
@@ -38,6 +38,41 @@ function getWildCardMatches(object, path) {
|
|
|
38
38
|
}
|
|
39
39
|
return matches;
|
|
40
40
|
}
|
|
41
|
+
function FormArray({ name, renderElement, children }) {
|
|
42
|
+
const form = this.useForm();
|
|
43
|
+
const names = this.useFormState((form2) => {
|
|
44
|
+
const field = form2.getField(name);
|
|
45
|
+
return field.names;
|
|
46
|
+
});
|
|
47
|
+
const append = require$$0.useCallback((...newEntries) => {
|
|
48
|
+
const field = form.getField(name);
|
|
49
|
+
field.append(...newEntries);
|
|
50
|
+
}, []);
|
|
51
|
+
const remove = require$$0.useCallback((index) => {
|
|
52
|
+
const field = form.getField(name);
|
|
53
|
+
field.remove(index);
|
|
54
|
+
}, []);
|
|
55
|
+
const setValue = require$$0.useCallback(
|
|
56
|
+
(value) => {
|
|
57
|
+
const field = form.getField(name);
|
|
58
|
+
field.setValue(value);
|
|
59
|
+
},
|
|
60
|
+
[]
|
|
61
|
+
);
|
|
62
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63
|
+
renderElement && names.map((name2, index) => /* @__PURE__ */ jsxRuntime.jsx(require$$0.Fragment, { children: renderElement({
|
|
64
|
+
name: name2,
|
|
65
|
+
index,
|
|
66
|
+
remove: () => remove(index)
|
|
67
|
+
}) }, index)),
|
|
68
|
+
children == null ? void 0 : children({
|
|
69
|
+
names,
|
|
70
|
+
append,
|
|
71
|
+
remove,
|
|
72
|
+
setValue
|
|
73
|
+
})
|
|
74
|
+
] });
|
|
75
|
+
}
|
|
41
76
|
function FormError({ name }) {
|
|
42
77
|
const { errors, isDirty } = this.useField(name);
|
|
43
78
|
return isDirty ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: errors.join(", ") }) : null;
|
|
@@ -45,6 +80,7 @@ function FormError({ name }) {
|
|
|
45
80
|
function FormField({
|
|
46
81
|
// id,
|
|
47
82
|
name,
|
|
83
|
+
component,
|
|
48
84
|
commitOnBlur,
|
|
49
85
|
commitDebounce,
|
|
50
86
|
inputFilter,
|
|
@@ -53,7 +89,6 @@ function FormField({
|
|
|
53
89
|
...restProps
|
|
54
90
|
}) {
|
|
55
91
|
const id = "";
|
|
56
|
-
const component = ("component" in restProps ? restProps.component : "children" in restProps ? restProps.children : void 0) ?? "input";
|
|
57
92
|
const form = this.useForm();
|
|
58
93
|
const state = useCache.useScope(this.state);
|
|
59
94
|
const { value, setValue, errors } = this.useField(name);
|
|
@@ -90,8 +125,6 @@ function FormField({
|
|
|
90
125
|
}, [_id, errorString]);
|
|
91
126
|
const props = {
|
|
92
127
|
...restProps,
|
|
93
|
-
component: void 0,
|
|
94
|
-
children: void 0,
|
|
95
128
|
id: _id,
|
|
96
129
|
name,
|
|
97
130
|
value: localValue ?? serialize(value),
|
|
@@ -133,10 +166,12 @@ function FormContainer({
|
|
|
133
166
|
...formProps
|
|
134
167
|
}) {
|
|
135
168
|
const _form = form.useForm();
|
|
169
|
+
const hasTriggeredValidations = form.useFormState((state) => state.hasTriggeredValidations);
|
|
136
170
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
137
171
|
"form",
|
|
138
172
|
{
|
|
139
173
|
...formProps,
|
|
174
|
+
className: [formProps.className, hasTriggeredValidations ? "validated" : void 0].filter(Boolean).join(" "),
|
|
140
175
|
noValidate: true,
|
|
141
176
|
onSubmit: (event) => {
|
|
142
177
|
event.preventDefault();
|
|
@@ -193,6 +228,20 @@ function getFormInstance(original, options, state) {
|
|
|
193
228
|
}
|
|
194
229
|
}
|
|
195
230
|
return errors;
|
|
231
|
+
},
|
|
232
|
+
get names() {
|
|
233
|
+
const { value } = this;
|
|
234
|
+
return Array.isArray(value) ? value.map((_, index) => `${path}.${index}`) : [];
|
|
235
|
+
},
|
|
236
|
+
append(...elements) {
|
|
237
|
+
this.setValue(
|
|
238
|
+
(value) => Array.isArray(value) ? [...value, ...elements] : elements
|
|
239
|
+
);
|
|
240
|
+
},
|
|
241
|
+
remove(index) {
|
|
242
|
+
this.setValue(
|
|
243
|
+
(value) => Array.isArray(value) ? [...value.slice(0, index), ...value.slice(index + 1)] : value
|
|
244
|
+
);
|
|
196
245
|
}
|
|
197
246
|
};
|
|
198
247
|
},
|
|
@@ -230,8 +279,12 @@ function getFormInstance(original, options, state) {
|
|
|
230
279
|
state.set("hasTriggeredValidations", true);
|
|
231
280
|
return instance.isValid;
|
|
232
281
|
},
|
|
282
|
+
get hasTriggeredValidations() {
|
|
283
|
+
return state.get().hasTriggeredValidations;
|
|
284
|
+
},
|
|
233
285
|
reset() {
|
|
234
286
|
state.set("draft", void 0);
|
|
287
|
+
state.set("hasTriggeredValidations", false);
|
|
235
288
|
}
|
|
236
289
|
};
|
|
237
290
|
return instance;
|
|
@@ -324,7 +377,10 @@ class Form {
|
|
|
324
377
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children(selectedState) });
|
|
325
378
|
}
|
|
326
379
|
Field(props) {
|
|
327
|
-
return Reflect.apply(FormField, this, [props]);
|
|
380
|
+
return Reflect.apply(FormField, this, [{ component: "input", ...props }]);
|
|
381
|
+
}
|
|
382
|
+
Array(props) {
|
|
383
|
+
return Reflect.apply(FormArray, this, [props]);
|
|
328
384
|
}
|
|
329
385
|
Error({ name }) {
|
|
330
386
|
return Reflect.apply(FormError, this, [{ name }]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../../src/lib/wildcardMatch.ts","../../../src/react/form/formError.tsx","../../../src/react/form/formField.tsx","../../../src/react/form/form.tsx","../../../src/react/read.ts","../../../src/react/useDecoupledState.ts","../../../src/lib/castArray.ts","../../../src/react/useUrlParamScope.ts"],"sourcesContent":["import { type KeyType } from './path';\nimport { castArrayPath } from './propAccess';\n\nexport function wildcardMatch(s: KeyType[] | string, w: KeyType[] | string): boolean {\n if (typeof s === 'string') {\n s = castArrayPath(s);\n }\n\n if (typeof w === 'string') {\n w = castArrayPath(w);\n }\n\n return s.length === w.length && s.every((s, i) => w[i] === '*' || s === w[i]);\n}\n\nexport function getWildCardMatches(\n object: any,\n path: [KeyType, ...KeyType[]] | string,\n): Record<KeyType, any> {\n const matches: Record<KeyType, any> = {};\n const [first, second, ...rest] = castArrayPath(path);\n\n if (first === undefined) {\n throw new Error('Path is empty');\n }\n\n if (!(object instanceof Object)) {\n throw new Error('Object is not an object');\n }\n\n for (const [key, value] of Object.entries(object)) {\n if (first !== '*' && first !== key) {\n continue;\n }\n\n if (second === undefined) {\n matches[key] = value;\n continue;\n }\n\n for (const [subKey, subValue] of Object.entries(getWildCardMatches(value, [second, ...rest]))) {\n matches[`${key}.${subKey}`] = subValue;\n }\n }\n\n return matches;\n}\n","import { type Form } from './form';\nimport { type PathAsString } from '@lib/path';\n\nexport type FormErrorProps<TDraft, TPath extends PathAsString<TDraft>> = {\n name: TPath;\n};\n\nexport function FormError<TDraft, TPath extends PathAsString<TDraft>>(\n this: Form<TDraft, any>,\n { name }: FormErrorProps<TDraft, TPath>,\n) {\n const { errors, isDirty } = this.useField(name);\n\n return isDirty ? <>{errors.join(', ')}</> : null;\n}\n","import { type PathAsString } from '@index';\nimport { type Value } from '@lib/path';\nimport { useScope } from '@react/scope';\nimport {\n createElement,\n useEffect,\n useMemo,\n useState,\n type Component,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\nimport { type Form } from './form';\n\ninterface FormFieldComponentProps<TValue, TPath> {\n id: string;\n name: TPath;\n value: TValue;\n onChange: (event: { target: { value: TValue } } | TValue | undefined, ...args: any[]) => void;\n onFocus: (...args: any[]) => void;\n onBlur: (...args: any[]) => void;\n}\n\ntype NativeInputType = 'input' | 'select' | 'textarea';\n\ntype PartialComponentType<P> =\n | (new (props: P, context?: any) => Component<P, any>)\n | ((props: P, context?: any) => ReactNode);\n\nexport type FormFieldComponent<TValue, TPath> =\n | (string | number extends TValue ? NativeInputType : never)\n | PartialComponentType<FormFieldComponentProps<TValue, TPath>>;\n\ntype FieldValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<\n T & 'input'\n> extends {\n value: infer U;\n}\n ? U\n : ComponentPropsWithoutRef<T & 'input'> extends {\n value?: infer U;\n }\n ? U | undefined\n : never;\n\ntype FieldChangeValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<\n T & 'input'\n> extends {\n onChange?: (update: infer U) => void;\n}\n ? U extends { target: { value: infer V } }\n ? V\n : U\n : never;\n\nexport type FormFieldProps<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath>,\n> = {\n name: TPath;\n commitOnBlur?: boolean;\n commitDebounce?: number;\n inputFilter?: (value: FieldChangeValue<TComponent>) => boolean;\n onChange?: ComponentPropsWithoutRef<TComponent>['onChange'];\n onBlur?: ComponentPropsWithoutRef<TComponent>['onBlur'];\n} & (TComponent extends\n | 'input'\n | ((props: ComponentPropsWithoutRef<'input'> & { name: TPath }) => JSX.Element)\n ? { component?: TComponent } | { children?: TComponent }\n : { component: TComponent } | { children: TComponent }) &\n Omit<\n ComponentPropsWithoutRef<TComponent>,\n | 'form'\n | 'name'\n | 'component'\n | 'commitOnBlur'\n | 'commitDebounce'\n | 'value'\n | 'onChange'\n | 'onBlur'\n | 'children'\n > &\n (Value<TDraft, TPath> extends FieldValue<TComponent>\n ? { serialize?: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }\n : { serialize: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }) &\n (FieldChangeValue<TComponent> extends Value<TDraft, TPath>\n ? { deserialize?: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> }\n : { deserialize: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> });\n\nexport function FormField<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, any>,\n>(\n this: Form<TDraft, any>,\n {\n // id,\n name,\n commitOnBlur,\n commitDebounce,\n inputFilter,\n serialize = (x) => x as FieldValue<TComponent>,\n deserialize = (x) => x as Value<TDraft, TPath>,\n ...restProps\n }: FormFieldProps<TDraft, TPath, TComponent>,\n): JSX.Element {\n type T = FieldChangeValue<TComponent>;\n const id = '';\n const component = (('component' in restProps\n ? restProps.component\n : 'children' in restProps\n ? restProps.children\n : undefined) ?? 'input') as TComponent;\n\n const form = this.useForm();\n const state = useScope(this.state);\n const { value, setValue, errors } = this.useField(name);\n\n const errorString = useMemo(\n () => errors.map((error) => form.options.localizeError?.(error, name) ?? error).join('\\n'),\n [errors, form.options.localizeError],\n );\n const [localValue, setLocalValue] = useState<T>();\n const _id = useMemo(\n () =>\n id || `f${Math.random().toString(36).slice(2, 15)}${Math.random().toString(36).slice(2, 15)}`,\n\n [id],\n );\n\n useEffect(() => {\n if (localValue === undefined || !commitDebounce) {\n return;\n }\n\n const timeout = setTimeout(() => {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }, commitDebounce);\n\n return () => clearTimeout(timeout);\n }, [localValue, commitDebounce]);\n\n useEffect(() => {\n const element = document.querySelector(\n [`#${_id} input`, `#${_id} select`, `#${_id} textarea`, `#${_id}`].join(','),\n );\n\n if (\n !(\n element instanceof HTMLInputElement ||\n element instanceof HTMLSelectElement ||\n element instanceof HTMLTextAreaElement\n )\n ) {\n return;\n }\n\n element.setCustomValidity(errorString);\n }, [_id, errorString]);\n\n const props = {\n ...restProps,\n component: undefined,\n children: undefined,\n id: _id,\n name,\n value: localValue ?? serialize(value),\n onChange: (event: { target: { value: T } } | T, ...moreArgs: any[]) => {\n const value =\n typeof event === 'object' && event !== null && 'target' in event\n ? event.target.value\n : event;\n\n if (inputFilter && !inputFilter(value)) {\n return;\n }\n\n if (commitOnBlur || commitDebounce) {\n setLocalValue(value);\n } else {\n setValue(deserialize(value));\n }\n\n restProps.onChange?.(event, ...moreArgs);\n },\n onFocus(...args: any[]) {\n state.set('touched', (touched) => {\n touched = new Set(touched);\n touched.add(_id);\n return touched;\n });\n\n restProps.onFocus?.apply(null, args);\n },\n onBlur(...args: any[]) {\n if (localValue !== undefined) {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }\n\n restProps.onBlur?.apply(null, args);\n },\n };\n\n return createElement(component, props);\n}\n","import { Scope, type Store, connectUrl, createStore, type UrlStoreOptions } from '@core';\nimport { autobind } from '@lib/autobind';\nimport { deepEqual } from '@lib/equals';\nimport { hash } from '@lib/hash';\nimport {\n type PathAsString,\n type Value,\n type WildcardPathAsString,\n type WildcardValue,\n} from '@lib/path';\nimport { get } from '@lib/propAccess';\nimport { getWildCardMatches, wildcardMatch } from '@lib/wildcardMatch';\nimport {\n type ReactNode,\n createContext,\n useContext,\n useEffect,\n useMemo,\n type ComponentPropsWithoutRef,\n type HTMLProps,\n} from 'react';\nimport { ScopeProvider, useScope } from '../scope';\nimport { useStore, type UseStoreOptions } from '../useStore';\nimport { FormError, type FormErrorProps } from './formError';\nimport { FormField, type FormFieldComponent, type FormFieldProps } from './formField';\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Form types\n/// /////////////////////////////////////////////////////////////////////////////\n\nexport interface FormOptions<TDraft, TOriginal> {\n defaultValue: TDraft;\n validations?: Validations<TDraft, TOriginal>;\n localizeError?: (error: string, field: string) => string | undefined;\n urlState?: boolean | UrlStoreOptions<TDraft>;\n}\n\nexport type Validations<TDraft, TOriginal> = {\n [P in WildcardPathAsString<TDraft>]?: Record<\n string,\n Validation<WildcardValue<TDraft, P>, TDraft, TOriginal>\n >;\n} & Record<string, Record<string, Validation<any, TDraft, TOriginal>>>;\n\nexport type Validation<TValue, TDraft, TOriginal> = (\n value: TValue,\n context: { draft: TDraft; original: TOriginal; field: PathAsString<TDraft> },\n) => boolean;\n\nexport interface Field<TDraft, TOriginal, TPath extends PathAsString<TDraft>> {\n originalValue: Value<TOriginal, TPath> | undefined;\n value: Value<TDraft, TPath>;\n setValue: (\n value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>),\n ) => void;\n isDirty: boolean;\n errors: string[];\n}\n\ninterface FormState<TDraft> {\n draft?: TDraft;\n touched: Set<string>;\n errors: Map<string, string[]>;\n hasTriggeredValidations?: boolean;\n}\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Implementation\n/// /////////////////////////////////////////////////////////////////////////////\n\nfunction FormContainer({\n form,\n ...formProps\n}: { form: Form<any, any> } & Omit<HTMLProps<HTMLFormElement>, 'form'>) {\n const _form = form.useForm();\n\n return (\n <form\n {...formProps}\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n\n _form.validate();\n\n let button;\n\n if (\n event.nativeEvent instanceof SubmitEvent &&\n (button = event.nativeEvent.submitter) &&\n (button instanceof HTMLButtonElement || button instanceof HTMLInputElement) &&\n button.setCustomValidity\n ) {\n const errors = _form.errors.map(\n ({ field, error }) => _form.options.localizeError?.(error, field) ?? error,\n );\n button.setCustomValidity(errors.join('\\n'));\n }\n event.currentTarget.reportValidity();\n }}\n />\n );\n}\n\nfunction getFormInstance<TDraft, TOriginal extends TDraft>(\n original: TOriginal | undefined,\n options: FormOptions<TDraft, TOriginal>,\n state: Store<FormState<TDraft>>,\n) {\n const instance = {\n original,\n\n draft: state.map(\n (state) => state.draft ?? original ?? options.defaultValue,\n (draft) => (state) => ({ ...state, draft }),\n ),\n\n options,\n\n getField: <TPath extends PathAsString<TDraft>>(\n path: TPath,\n ): Field<TDraft, TOriginal, TPath> => {\n const { draft } = instance;\n\n return {\n get originalValue() {\n return original !== undefined ? get(original as any, path as any) : undefined;\n },\n\n get value() {\n return get(draft.get(), path);\n },\n\n setValue(update) {\n draft.set(path, update);\n },\n\n get isDirty() {\n const comparisonValue = this.originalValue ?? get(options.defaultValue, path);\n\n return state.get().hasTriggeredValidations || !deepEqual(comparisonValue, this.value);\n },\n\n get errors() {\n const blocks: (Validation<any, any, any> | Record<string, Validation<any, any, any>>)[] =\n Object.entries(options.validations ?? {})\n .filter(([key]) => wildcardMatch(path, key))\n .map(([, value]) => value);\n\n const value = this.value;\n const draftValue = draft.get();\n const errors: string[] = [];\n\n for (const block of blocks ?? []) {\n for (const [validationName, validate] of Object.entries(block)) {\n if (!validate(value, { draft: draftValue, original, field: path })) {\n errors.push(validationName);\n }\n }\n }\n\n return errors;\n },\n };\n },\n\n get hasChanges() {\n const { draft } = state.get();\n return !!draft && !deepEqual(draft, original ?? options.defaultValue);\n },\n\n get errors() {\n const draft = instance.draft.get();\n const errors = new Set<{ field: string; error: string }>();\n\n for (const [path, block] of Object.entries(options.validations ?? {})) {\n for (const [validationName, validate] of Object.entries(\n block as Record<string, Validation<any, any, any>>,\n )) {\n let matched = false;\n\n for (const [field, value] of Object.entries(getWildCardMatches(draft, path))) {\n matched = true;\n if (!validate(value, { draft, original, field })) {\n errors.add({ field, error: validationName });\n }\n }\n\n if (!matched && !path.includes('*')) {\n if (!validate(undefined, { draft, original, field: path })) {\n errors.add({ field: path, error: validationName });\n }\n }\n }\n }\n\n return [...errors];\n },\n\n get isValid() {\n return instance.errors.length === 0;\n },\n\n validate: () => {\n state.set('hasTriggeredValidations', true);\n return instance.isValid;\n },\n\n reset() {\n state.set('draft', undefined);\n },\n };\n\n return instance;\n}\n\nexport class Form<TDraft, TOriginal extends TDraft = TDraft> {\n context = createContext({\n original: undefined as TOriginal | undefined,\n options: this.options,\n });\n\n state = new Scope<FormState<TDraft>>({\n touched: new Set(),\n errors: new Map(),\n });\n\n constructor(public readonly options: FormOptions<TDraft, TOriginal>) {\n autobind(Form);\n }\n\n useForm() {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useMemo(() => getFormInstance(original, options, state), [original, options, state]);\n }\n\n useFormState<S>(selector: (state: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S) {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useStore(state.map(() => selector(getFormInstance(original, options, state))));\n }\n\n useField<TPath extends PathAsString<TDraft>>(path: TPath, useStoreOptions?: UseStoreOptions) {\n const form = this.useForm();\n const state = useScope(this.state);\n\n useStore(\n form.draft.map((draft) => get(draft, path)),\n useStoreOptions,\n );\n\n useStore(\n state.map((state) => state.hasTriggeredValidations),\n useStoreOptions,\n );\n\n return form.getField(path);\n }\n\n useHasChanges() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.hasChanges));\n }\n\n useIsValid() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.isValid));\n }\n\n // ///////////////////////////////////////////////////////////////////////////\n // React Components\n // ///////////////////////////////////////////////////////////////////////////\n\n Form({\n original,\n defaultValue,\n validations,\n localizeError,\n urlState,\n ...formProps\n }: {\n original?: TOriginal;\n } & Partial<FormOptions<TDraft, TOriginal>> &\n Omit<HTMLProps<HTMLFormElement>, 'defaultValue'>) {\n const value = useMemo(\n () => ({\n original,\n options: {\n defaultValue: { ...this.options.defaultValue, ...defaultValue },\n validations: { ...this.options.validations, ...validations } as Validations<\n TDraft,\n TOriginal\n >,\n localizeError: localizeError ?? this.options.localizeError,\n },\n }),\n [original, defaultValue, validations],\n );\n\n const store = useMemo(() => {\n return createStore(this.state.defaultValue);\n }, []);\n\n useEffect(() => {\n if (urlState) {\n return connectUrl(\n store.map('draft'),\n typeof urlState === 'object' ? urlState : { key: 'form' },\n );\n }\n\n return undefined;\n }, [store, hash(urlState)]);\n\n return (\n <this.context.Provider value={value}>\n <ScopeProvider scope={this.state} store={store}>\n <FormContainer {...formProps} form={this} />\n </ScopeProvider>\n </this.context.Provider>\n );\n }\n\n Subscribe<S>({\n selector,\n children,\n }: {\n selector: (form: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S;\n children: (selectedState: S) => ReactNode;\n }) {\n const selectedState = this.useFormState(selector);\n return <>{children(selectedState)}</>;\n }\n\n Field<\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath> = (\n props: ComponentPropsWithoutRef<'input'> & { name: TPath },\n ) => JSX.Element,\n >(props: FormFieldProps<TDraft, TPath, TComponent>): JSX.Element {\n return Reflect.apply(FormField, this, [props]);\n }\n\n Error<TPath extends PathAsString<TDraft>>({ name }: FormErrorProps<TDraft, TPath>) {\n return Reflect.apply(FormError, this, [{ name }]);\n }\n}\n\nexport function createForm<TDraft, TOriginal extends TDraft = TDraft>(\n options: FormOptions<TDraft, TOriginal>,\n) {\n return new Form(options);\n}\n","import { useCache } from './useCache';\nimport type { UseStoreOptions } from './useStore';\nimport type { Cache } from '@core';\n\nexport function read<T>(cache: Cache<T>, options?: UseStoreOptions): T {\n const { status, value, error } = useCache(cache, options);\n\n if (status === 'value') {\n return value;\n }\n\n if (status === 'error') {\n throw error;\n }\n\n throw cache.state.once((state) => state.status !== 'pending');\n}\n","import { startTransition, useEffect, useMemo, useRef, useState } from 'react';\nimport { type Duration } from '@core';\nimport { debounce } from '@lib/debounce';\nimport { hash } from '@lib/hash';\nimport { throttle } from '@lib/throttle';\n\nexport interface UseDecoupledStateOptions<T> {\n debounce?: Duration;\n throttle?: Duration;\n onCommit?: (value: T) => void;\n}\n\nexport function useDecoupledState<T>(\n value: T,\n onChange: (value: T) => void,\n options: UseDecoupledStateOptions<T> = {},\n): [state: T, setState: (value: T) => void] {\n const [dirty, setDirty] = useState<{ v: T }>();\n const ref = useRef({ onChange, onCommit: options.onCommit });\n\n useEffect(() => {\n ref.current = { onChange, onCommit: options.onCommit };\n }, [onChange]);\n\n const update = useMemo(() => {\n const { onChange, onCommit } = ref.current;\n\n const update = (value: T) => {\n onChange(value);\n setDirty(undefined);\n onCommit?.(value);\n };\n\n let delayedUpdate: (value: T) => void;\n\n if (options.debounce) {\n delayedUpdate = debounce(update, options.debounce);\n } else if (options.throttle) {\n delayedUpdate = throttle(update, options.throttle);\n } else {\n delayedUpdate = (value) => startTransition(() => update(value));\n }\n\n return (value: T) => {\n setDirty({ v: value });\n delayedUpdate(value);\n };\n }, [hash([options.debounce, options.throttle])]);\n\n return [dirty ? dirty.v : value, update];\n}\n","export function castArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value];\n}\n","import { type ReactNode, useEffect } from 'react';\nimport { castArray } from '@lib/castArray';\nimport { hash } from '@lib/hash';\n\nexport function useUrlParamScope({\n key,\n type = 'search',\n}: {\n key: string | string[];\n type?: 'search' | 'hash';\n}) {\n useEffect(\n () => () => {\n const url = new URL(window.location.href);\n const parameters = new URLSearchParams(url[type].slice(1));\n\n for (const _key of castArray(key)) {\n parameters.delete(_key);\n }\n\n url[type] = parameters.toString();\n window.history.replaceState(null, '', url.toString());\n },\n [hash(key), type],\n );\n}\n"],"names":["castArrayPath","s","jsx","Fragment","useScope","useMemo","useState","useEffect","value","createElement","state","get","deepEqual","createContext","Scope","autobind","useContext","useStore","store","createStore","connectUrl","hash","ScopeProvider","useCache","useRef","onChange","update","debounce","throttle","startTransition"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../src/lib/wildcardMatch.ts","../../../src/react/form/formArray.tsx","../../../src/react/form/formError.tsx","../../../src/react/form/formField.tsx","../../../src/react/form/form.tsx","../../../src/react/read.ts","../../../src/react/useDecoupledState.ts","../../../src/lib/castArray.ts","../../../src/react/useUrlParamScope.ts"],"sourcesContent":["import { type KeyType } from './path';\nimport { castArrayPath } from './propAccess';\n\nexport function wildcardMatch(s: KeyType[] | string, w: KeyType[] | string): boolean {\n if (typeof s === 'string') {\n s = castArrayPath(s);\n }\n\n if (typeof w === 'string') {\n w = castArrayPath(w);\n }\n\n return s.length === w.length && s.every((s, i) => w[i] === '*' || s === w[i]);\n}\n\nexport function getWildCardMatches(\n object: any,\n path: [KeyType, ...KeyType[]] | string,\n): Record<KeyType, any> {\n const matches: Record<KeyType, any> = {};\n const [first, second, ...rest] = castArrayPath(path);\n\n if (first === undefined) {\n throw new Error('Path is empty');\n }\n\n if (!(object instanceof Object)) {\n throw new Error('Object is not an object');\n }\n\n for (const [key, value] of Object.entries(object)) {\n if (first !== '*' && first !== key) {\n continue;\n }\n\n if (second === undefined) {\n matches[key] = value;\n continue;\n }\n\n for (const [subKey, subValue] of Object.entries(getWildCardMatches(value, [second, ...rest]))) {\n matches[`${key}.${subKey}`] = subValue;\n }\n }\n\n return matches;\n}\n","import { type PathAsString, type Value } from '@lib/path';\nimport { Fragment, useCallback, type ReactNode } from 'react';\nimport { type ArrayFieldMethods, type Field, type Form } from './form';\n\nexport type ArrayPath<T> = keyof {\n [P in PathAsString<T> as Value<T, P> extends readonly any[] | undefined ? P : never]: never;\n} &\n PathAsString<T> &\n string;\n\nexport interface FormArrayProps<TDraft, TPath extends ArrayPath<TDraft>> {\n name: TPath;\n renderElement?: (props: {\n name: `${TPath}.${number}`;\n index: number;\n remove: () => void;\n }) => ReactNode;\n children?: (props: {\n names: `${TPath}.${number}`[];\n append: (...elements: Value<TDraft, `${TPath}.${number}`>[]) => void;\n remove: (index: number) => void;\n setValue: (\n value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>),\n ) => void;\n }) => ReactNode;\n}\n\nexport function FormArray<TDraft, TPath extends ArrayPath<TDraft>>(\n this: Form<TDraft, any>,\n { name, renderElement, children }: FormArrayProps<TDraft, TPath>,\n) {\n const form = this.useForm();\n\n const names = this.useFormState((form) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n return field.names;\n });\n\n const append = useCallback((...newEntries: Value<TDraft, `${TPath}.${number}`>[]) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n field.append(...newEntries);\n }, []);\n\n const remove = useCallback((index: number) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n field.remove(index);\n }, []);\n\n const setValue = useCallback(\n (value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>)) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n field.setValue(value);\n },\n [],\n );\n\n return (\n <>\n {renderElement &&\n names.map((name, index) => (\n <Fragment key={index}>\n {renderElement({\n name,\n index,\n remove: () => remove(index),\n })}\n </Fragment>\n ))}\n\n {children?.({\n names,\n append,\n remove,\n setValue,\n })}\n </>\n );\n}\n","import { type Form } from './form';\nimport { type PathAsString } from '@lib/path';\n\nexport type FormErrorProps<TDraft, TPath extends PathAsString<TDraft>> = {\n name: TPath;\n};\n\nexport function FormError<TDraft, TPath extends PathAsString<TDraft>>(\n this: Form<TDraft, any>,\n { name }: FormErrorProps<TDraft, TPath>,\n) {\n const { errors, isDirty } = this.useField(name);\n\n return isDirty ? <>{errors.join(', ')}</> : null;\n}\n","import { type PathAsString } from '@index';\nimport { type Value } from '@lib/path';\nimport { useScope } from '@react/scope';\nimport {\n createElement,\n useEffect,\n useMemo,\n useState,\n type Component,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\nimport { type Form } from './form';\n\ninterface FormFieldComponentProps<TValue, TPath> {\n id: string;\n name: TPath;\n value: TValue;\n onChange: (event: { target: { value: TValue } } | TValue | undefined, ...args: any[]) => void;\n onFocus: (...args: any[]) => void;\n onBlur: (...args: any[]) => void;\n}\n\ntype NativeInputType = 'input' | 'select' | 'textarea';\n\ntype PartialComponentType<P> =\n | (new (props: P, context?: any) => Component<P, any>)\n | ((props: P, context?: any) => ReactNode);\n\nexport type FormFieldComponent<TValue, TPath> =\n | (string | number extends TValue ? NativeInputType : never)\n | PartialComponentType<FormFieldComponentProps<TValue, TPath>>;\n\ntype FieldValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<T>['value'];\n\ntype FieldChangeValue<T extends FormFieldComponent<any, any>> =\n ComponentPropsWithoutRef<T> extends {\n onChange?: (update: infer U) => void;\n }\n ? U extends { target: { value: infer V } }\n ? V\n : U\n : never;\n\nexport type FormFieldProps<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath>,\n> = {\n name: TPath;\n component: TComponent;\n commitOnBlur?: boolean;\n commitDebounce?: number;\n inputFilter?: (value: FieldChangeValue<TComponent>) => boolean;\n} & Omit<\n ComponentPropsWithoutRef<TComponent>,\n | 'name'\n | 'component'\n | 'commitOnBlur'\n | 'commitDebounce'\n | 'inputFilter'\n | keyof FormFieldComponentProps<any, any>\n> &\n Partial<Pick<ComponentPropsWithoutRef<TComponent>, keyof FormFieldComponentProps<any, any>>> &\n (Value<TDraft, TPath> extends FieldValue<TComponent>\n ? { serialize?: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }\n : { serialize: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }) &\n (FieldChangeValue<TComponent> extends Value<TDraft, TPath>\n ? { deserialize?: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> }\n : { deserialize: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> });\n\nexport function FormField<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, any>,\n>(\n this: Form<TDraft, any>,\n {\n // id,\n name,\n component,\n commitOnBlur,\n commitDebounce,\n inputFilter,\n serialize = (x) => x as FieldValue<TComponent>,\n deserialize = (x) => x as Value<TDraft, TPath>,\n ...restProps\n }: FormFieldProps<TDraft, TPath, TComponent>,\n): JSX.Element {\n type T = FieldChangeValue<TComponent>;\n const id = '';\n\n const form = this.useForm();\n const state = useScope(this.state);\n const { value, setValue, errors } = this.useField(name);\n\n const errorString = useMemo(\n () => errors.map((error) => form.options.localizeError?.(error, name) ?? error).join('\\n'),\n [errors, form.options.localizeError],\n );\n const [localValue, setLocalValue] = useState<T>();\n const _id = useMemo(\n () =>\n id || `f${Math.random().toString(36).slice(2, 15)}${Math.random().toString(36).slice(2, 15)}`,\n\n [id],\n );\n\n useEffect(() => {\n if (localValue === undefined || !commitDebounce) {\n return;\n }\n\n const timeout = setTimeout(() => {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }, commitDebounce);\n\n return () => clearTimeout(timeout);\n }, [localValue, commitDebounce]);\n\n useEffect(() => {\n const element = document.querySelector(\n [`#${_id} input`, `#${_id} select`, `#${_id} textarea`, `#${_id}`].join(','),\n );\n\n if (\n !(\n element instanceof HTMLInputElement ||\n element instanceof HTMLSelectElement ||\n element instanceof HTMLTextAreaElement\n )\n ) {\n return;\n }\n\n element.setCustomValidity(errorString);\n }, [_id, errorString]);\n\n const props = {\n ...restProps,\n id: _id,\n name,\n value: localValue ?? serialize(value as Value<TDraft, TPath>),\n onChange: (event: { target: { value: T } } | T, ...moreArgs: any[]) => {\n const value =\n typeof event === 'object' && event !== null && 'target' in event\n ? event.target.value\n : event;\n\n if (inputFilter && !inputFilter(value)) {\n return;\n }\n\n if (commitOnBlur || commitDebounce) {\n setLocalValue(value);\n } else {\n setValue(deserialize(value));\n }\n\n restProps.onChange?.(event, ...moreArgs);\n },\n onFocus(...args: any[]) {\n state.set('touched', (touched) => {\n touched = new Set(touched);\n touched.add(_id);\n return touched;\n });\n\n restProps.onFocus?.apply(null, args);\n },\n onBlur(...args: any[]) {\n if (localValue !== undefined) {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }\n\n restProps.onBlur?.apply(null, args);\n },\n };\n\n return createElement(component, props);\n}\n","import { Scope, connectUrl, createStore, type Store, type UrlStoreOptions } from '@core';\nimport { autobind } from '@lib/autobind';\nimport { deepEqual } from '@lib/equals';\nimport { hash } from '@lib/hash';\nimport {\n type PathAsString,\n type Value,\n type WildcardPathAsString,\n type WildcardValue,\n} from '@lib/path';\nimport { get } from '@lib/propAccess';\nimport { getWildCardMatches, wildcardMatch } from '@lib/wildcardMatch';\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n type ComponentPropsWithoutRef,\n type HTMLProps,\n type ReactNode,\n} from 'react';\nimport { ScopeProvider, useScope } from '../scope';\nimport { useStore, type UseStoreOptions } from '../useStore';\nimport { FormArray, type ArrayPath, type FormArrayProps } from './formArray';\nimport { FormError, type FormErrorProps } from './formError';\nimport { FormField, type FormFieldComponent, type FormFieldProps } from './formField';\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Form types\n/// /////////////////////////////////////////////////////////////////////////////\n\nexport interface FormOptions<TDraft, TOriginal> {\n defaultValue: TDraft;\n validations?: Validations<TDraft, TOriginal>;\n localizeError?: (error: string, field: string) => string | undefined;\n urlState?: boolean | UrlStoreOptions<TDraft>;\n}\n\nexport type Validations<TDraft, TOriginal> = {\n [P in WildcardPathAsString<TDraft>]?: Record<\n string,\n Validation<WildcardValue<TDraft, P>, TDraft, TOriginal>\n >;\n} & Record<string, Record<string, Validation<any, TDraft, TOriginal>>>;\n\nexport type Validation<TValue, TDraft, TOriginal> = (\n value: TValue,\n context: { draft: TDraft; original: TOriginal; field: PathAsString<TDraft> },\n) => boolean;\n\nexport type Field<TDraft, TOriginal, TPath extends PathAsString<TDraft>> = {\n originalValue: Value<TOriginal, TPath> | undefined;\n value: Value<TDraft, TPath>;\n setValue: (\n value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>),\n ) => void;\n isDirty: boolean;\n errors: string[];\n} & (Value<TDraft, TPath> extends Array<any> ? ArrayFieldMethods<TDraft, TPath> : {});\n\nexport type ArrayFieldMethods<TPath, TValue> = {\n names: TPath[];\n append: (...elements: TValue[]) => void;\n remove: (index: number) => void;\n};\n\ninterface FormState<TDraft> {\n draft?: TDraft;\n touched: Set<string>;\n errors: Map<string, string[]>;\n hasTriggeredValidations?: boolean;\n}\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Implementation\n/// /////////////////////////////////////////////////////////////////////////////\n\nfunction FormContainer({\n form,\n ...formProps\n}: { form: Form<any, any> } & Omit<HTMLProps<HTMLFormElement>, 'form'>) {\n const _form = form.useForm();\n const hasTriggeredValidations = form.useFormState((state) => state.hasTriggeredValidations);\n\n return (\n <form\n {...formProps}\n className={[formProps.className, hasTriggeredValidations ? 'validated' : undefined]\n .filter(Boolean)\n .join(' ')}\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n\n _form.validate();\n\n let button;\n\n if (\n event.nativeEvent instanceof SubmitEvent &&\n (button = event.nativeEvent.submitter) &&\n (button instanceof HTMLButtonElement || button instanceof HTMLInputElement) &&\n button.setCustomValidity\n ) {\n const errors = _form.errors.map(\n ({ field, error }) => _form.options.localizeError?.(error, field) ?? error,\n );\n button.setCustomValidity(errors.join('\\n'));\n }\n event.currentTarget.reportValidity();\n }}\n />\n );\n}\n\nfunction getFormInstance<TDraft, TOriginal extends TDraft>(\n original: TOriginal | undefined,\n options: FormOptions<TDraft, TOriginal>,\n state: Store<FormState<TDraft>>,\n) {\n const instance = {\n original,\n\n draft: state.map(\n (state) => state.draft ?? original ?? options.defaultValue,\n (draft) => (state) => ({ ...state, draft }),\n ),\n\n options,\n\n getField: <TPath extends PathAsString<TDraft>>(\n path: TPath,\n ): Field<TDraft, TOriginal, TPath> => {\n const { draft } = instance;\n\n return {\n get originalValue() {\n return original !== undefined ? get(original as any, path as any) : undefined;\n },\n\n get value() {\n return get(draft.get(), path);\n },\n\n setValue(update) {\n draft.set(path, update);\n },\n\n get isDirty() {\n const comparisonValue = this.originalValue ?? get(options.defaultValue, path);\n\n return state.get().hasTriggeredValidations || !deepEqual(comparisonValue, this.value);\n },\n\n get errors() {\n const blocks: (Validation<any, any, any> | Record<string, Validation<any, any, any>>)[] =\n Object.entries(options.validations ?? {})\n .filter(([key]) => wildcardMatch(path, key))\n .map(([, value]) => value);\n\n const value = this.value;\n const draftValue = draft.get();\n const errors: string[] = [];\n\n for (const block of blocks ?? []) {\n for (const [validationName, validate] of Object.entries(block)) {\n if (!validate(value, { draft: draftValue, original, field: path })) {\n errors.push(validationName);\n }\n }\n }\n\n return errors;\n },\n\n get names() {\n const { value } = this;\n return (Array.isArray(value) ? value.map((_, index) => `${path}.${index}`) : []) as any;\n },\n\n append(...elements: any[]) {\n this.setValue(\n (value) => (Array.isArray(value) ? [...value, ...elements] : elements) as any,\n );\n },\n\n remove(index) {\n this.setValue(\n (value) =>\n (Array.isArray(value)\n ? [...value.slice(0, index), ...value.slice(index + 1)]\n : value) as any,\n );\n },\n };\n },\n\n get hasChanges() {\n const { draft } = state.get();\n return !!draft && !deepEqual(draft, original ?? options.defaultValue);\n },\n\n get errors() {\n const draft = instance.draft.get();\n const errors = new Set<{ field: string; error: string }>();\n\n for (const [path, block] of Object.entries(options.validations ?? {})) {\n for (const [validationName, validate] of Object.entries(\n block as Record<string, Validation<any, any, any>>,\n )) {\n let matched = false;\n\n for (const [field, value] of Object.entries(getWildCardMatches(draft, path))) {\n matched = true;\n if (!validate(value, { draft, original, field })) {\n errors.add({ field, error: validationName });\n }\n }\n\n if (!matched && !path.includes('*')) {\n if (!validate(undefined, { draft, original, field: path })) {\n errors.add({ field: path, error: validationName });\n }\n }\n }\n }\n\n return [...errors];\n },\n\n get isValid() {\n return instance.errors.length === 0;\n },\n\n validate: () => {\n state.set('hasTriggeredValidations', true);\n return instance.isValid;\n },\n\n get hasTriggeredValidations() {\n return state.get().hasTriggeredValidations;\n },\n\n reset() {\n state.set('draft', undefined);\n state.set('hasTriggeredValidations', false);\n },\n };\n\n return instance;\n}\n\nexport class Form<TDraft, TOriginal extends TDraft = TDraft> {\n context = createContext({\n original: undefined as TOriginal | undefined,\n options: this.options,\n });\n\n state = new Scope<FormState<TDraft>>({\n touched: new Set(),\n errors: new Map(),\n });\n\n constructor(public readonly options: FormOptions<TDraft, TOriginal>) {\n autobind(Form);\n }\n\n useForm() {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useMemo(() => getFormInstance(original, options, state), [original, options, state]);\n }\n\n useFormState<S>(selector: (state: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S) {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useStore(state.map(() => selector(getFormInstance(original, options, state))));\n }\n\n useField<TPath extends PathAsString<TDraft>>(path: TPath, useStoreOptions?: UseStoreOptions) {\n const form = this.useForm();\n const state = useScope(this.state);\n\n useStore(\n form.draft.map((draft) => get(draft, path)),\n useStoreOptions,\n );\n\n useStore(\n state.map((state) => state.hasTriggeredValidations),\n useStoreOptions,\n );\n\n return form.getField(path);\n }\n\n useHasChanges() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.hasChanges));\n }\n\n useIsValid() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.isValid));\n }\n\n // ///////////////////////////////////////////////////////////////////////////\n // React Components\n // ///////////////////////////////////////////////////////////////////////////\n\n Form({\n original,\n defaultValue,\n validations,\n localizeError,\n urlState,\n ...formProps\n }: {\n original?: TOriginal;\n } & Partial<FormOptions<TDraft, TOriginal>> &\n Omit<HTMLProps<HTMLFormElement>, 'defaultValue'>) {\n const value = useMemo(\n () => ({\n original,\n options: {\n defaultValue: { ...this.options.defaultValue, ...defaultValue },\n validations: { ...this.options.validations, ...validations } as Validations<\n TDraft,\n TOriginal\n >,\n localizeError: localizeError ?? this.options.localizeError,\n },\n }),\n [original, defaultValue, validations],\n );\n\n const store = useMemo(() => {\n return createStore(this.state.defaultValue);\n }, []);\n\n useEffect(() => {\n if (urlState) {\n return connectUrl(\n store.map('draft'),\n typeof urlState === 'object' ? urlState : { key: 'form' },\n );\n }\n\n return undefined;\n }, [store, hash(urlState)]);\n\n return (\n <this.context.Provider value={value}>\n <ScopeProvider scope={this.state} store={store}>\n <FormContainer {...formProps} form={this} />\n </ScopeProvider>\n </this.context.Provider>\n );\n }\n\n Subscribe<S>({\n selector,\n children,\n }: {\n selector: (form: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S;\n children: (selectedState: S) => ReactNode;\n }) {\n const selectedState = this.useFormState(selector);\n return <>{children(selectedState)}</>;\n }\n\n Field<TPath extends PathAsString<TDraft>>(\n props: Omit<FormFieldProps<TDraft, TPath, 'input'>, 'component'>,\n ): JSX.Element;\n Field<\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath> = (\n props: ComponentPropsWithoutRef<'input'> & { name: TPath },\n ) => JSX.Element,\n >(props: FormFieldProps<TDraft, TPath, TComponent>): JSX.Element;\n Field(props: any): JSX.Element {\n return Reflect.apply(FormField, this, [{ component: 'input', ...props }]);\n }\n\n Array<TPath extends ArrayPath<TDraft>>(props: FormArrayProps<TDraft, TPath>) {\n return Reflect.apply(FormArray, this, [props]);\n }\n\n Error<TPath extends PathAsString<TDraft>>({ name }: FormErrorProps<TDraft, TPath>) {\n return Reflect.apply(FormError, this, [{ name }]);\n }\n}\n\nexport function createForm<TDraft, TOriginal extends TDraft = TDraft>(\n options: FormOptions<TDraft, TOriginal>,\n) {\n return new Form(options);\n}\n","import { useCache } from './useCache';\nimport type { UseStoreOptions } from './useStore';\nimport type { Cache } from '@core';\n\nexport function read<T>(cache: Cache<T>, options?: UseStoreOptions): T {\n const { status, value, error } = useCache(cache, options);\n\n if (status === 'value') {\n return value;\n }\n\n if (status === 'error') {\n throw error;\n }\n\n throw cache.state.once((state) => state.status !== 'pending');\n}\n","import { startTransition, useEffect, useMemo, useRef, useState } from 'react';\nimport { type Duration } from '@core';\nimport { debounce } from '@lib/debounce';\nimport { hash } from '@lib/hash';\nimport { throttle } from '@lib/throttle';\n\nexport interface UseDecoupledStateOptions<T> {\n debounce?: Duration;\n throttle?: Duration;\n onCommit?: (value: T) => void;\n}\n\nexport function useDecoupledState<T>(\n value: T,\n onChange: (value: T) => void,\n options: UseDecoupledStateOptions<T> = {},\n): [state: T, setState: (value: T) => void] {\n const [dirty, setDirty] = useState<{ v: T }>();\n const ref = useRef({ onChange, onCommit: options.onCommit });\n\n useEffect(() => {\n ref.current = { onChange, onCommit: options.onCommit };\n }, [onChange]);\n\n const update = useMemo(() => {\n const { onChange, onCommit } = ref.current;\n\n const update = (value: T) => {\n onChange(value);\n setDirty(undefined);\n onCommit?.(value);\n };\n\n let delayedUpdate: (value: T) => void;\n\n if (options.debounce) {\n delayedUpdate = debounce(update, options.debounce);\n } else if (options.throttle) {\n delayedUpdate = throttle(update, options.throttle);\n } else {\n delayedUpdate = (value) => startTransition(() => update(value));\n }\n\n return (value: T) => {\n setDirty({ v: value });\n delayedUpdate(value);\n };\n }, [hash([options.debounce, options.throttle])]);\n\n return [dirty ? dirty.v : value, update];\n}\n","export function castArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value];\n}\n","import { type ReactNode, useEffect } from 'react';\nimport { castArray } from '@lib/castArray';\nimport { hash } from '@lib/hash';\n\nexport function useUrlParamScope({\n key,\n type = 'search',\n}: {\n key: string | string[];\n type?: 'search' | 'hash';\n}) {\n useEffect(\n () => () => {\n const url = new URL(window.location.href);\n const parameters = new URLSearchParams(url[type].slice(1));\n\n for (const _key of castArray(key)) {\n parameters.delete(_key);\n }\n\n url[type] = parameters.toString();\n window.history.replaceState(null, '', url.toString());\n },\n [hash(key), type],\n );\n}\n"],"names":["castArrayPath","s","form","useCallback","jsxs","Fragment","name","jsx","useScope","useMemo","useState","useEffect","value","createElement","state","get","deepEqual","createContext","Scope","autobind","useContext","useStore","store","createStore","connectUrl","hash","ScopeProvider","useCache","useRef","onChange","update","debounce","throttle","startTransition"],"mappings":"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"}
|
package/dist/es/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as Store, c as createStore, b as calcDuration, r as remove, s as set, q as queue, d as castArrayPath,
|
|
2
|
-
import {
|
|
1
|
+
import { S as Store, c as createStore, b as calcDuration, r as remove, s as set, q as queue, d as castArrayPath, e as shallowEqual, g as get } from "./store.mjs";
|
|
2
|
+
import { f, h, i, j } from "./store.mjs";
|
|
3
3
|
import { I as InstanceCache, a as allResources } from "./cache.mjs";
|
|
4
4
|
import { C, R, c, b } from "./cache.mjs";
|
|
5
5
|
import { S, c as c2 } from "./scope.mjs";
|
|
@@ -346,11 +346,11 @@ class Persist {
|
|
|
346
346
|
return maybeAsync(this.storage.setItem(key, serializedValue), () => {
|
|
347
347
|
this.channel.postMessage(path);
|
|
348
348
|
return maybeAsync(this.storage.keys(), (keys) => {
|
|
349
|
-
const toRemove = keys.filter((
|
|
350
|
-
const parsedKey = JSON.parse(
|
|
349
|
+
const toRemove = keys.filter((k) => {
|
|
350
|
+
const parsedKey = JSON.parse(k);
|
|
351
351
|
return parsedKey.length > path.length && isAncestor(path, parsedKey);
|
|
352
352
|
});
|
|
353
|
-
return maybeAsyncArray(toRemove.map((
|
|
353
|
+
return maybeAsyncArray(toRemove.map((k) => () => this.storage.removeItem(k)));
|
|
354
354
|
});
|
|
355
355
|
});
|
|
356
356
|
}
|
|
@@ -420,7 +420,7 @@ export {
|
|
|
420
420
|
Sync,
|
|
421
421
|
allResources,
|
|
422
422
|
applyPatches,
|
|
423
|
-
|
|
423
|
+
f as arrayMethods,
|
|
424
424
|
calcDuration,
|
|
425
425
|
c3 as connectUrl,
|
|
426
426
|
c as createCache,
|
|
@@ -433,10 +433,10 @@ export {
|
|
|
433
433
|
diff,
|
|
434
434
|
findOrDefault,
|
|
435
435
|
get,
|
|
436
|
-
|
|
436
|
+
h as mapMethods,
|
|
437
437
|
persist,
|
|
438
|
-
|
|
438
|
+
i as recordMethods,
|
|
439
439
|
set,
|
|
440
|
-
|
|
440
|
+
j as setMethods
|
|
441
441
|
};
|
|
442
442
|
//# sourceMappingURL=index.mjs.map
|
package/dist/es/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../src/core/subscriptionCache.ts","../../src/lib/applyPatches.ts","../../src/lib/diff.ts","../../src/lib/updateHelpers.ts","../../src/persist/persistPathHelpers.ts","../../src/lib/maybeAsync.ts","../../src/persist/persistStorage.ts","../../src/persist/persist.ts","../../src/sync/sync.ts"],"sourcesContent":["import {\n type CalculationHelpers,\n type Cancel,\n type ConnectionState,\n type Duration,\n type Selector,\n} from './commonTypes';\nimport { allResources, type ResourceGroup } from './resourceGroup';\nimport { createStore, Store } from './store';\nimport { calcDuration } from '@lib/calcDuration';\nimport { InstanceCache } from '@lib/instanceCache';\nimport { type Path } from '@lib/path';\n\nexport interface SubscriptionCacheFunction<T, Args extends any[] = []> {\n (\n this: CalculationHelpers<T>,\n ...args: Args\n ): Cancel | void | ((cache: CalculationHelpers<T>) => Cancel | void);\n}\n\nexport type SubstriptionCacheOptions<T> = {\n clearOnInvalidate?: boolean;\n clearUnusedAfter?: Duration | null;\n resourceGroup?: ResourceGroup | ResourceGroup[];\n retain?: Duration;\n} & (T extends undefined ? { default?: T } : { default: T });\n\nexport class SubstriptionCache<T> extends Store<T> {\n readonly state = createStore({\n connectionState: 'closed' as ConnectionState,\n error: undefined as unknown | undefined,\n });\n\n constructor(\n public readonly connectFunction: SubscriptionCacheFunction<T>,\n public readonly options: SubstriptionCacheOptions<T>,\n public readonly derivedFromSubscriptionCache?: {\n subscriptionCache: SubstriptionCache<any>;\n selectors: (Selector<any, any> | Path<any>)[];\n },\n _call?: (...args: any[]) => any,\n ) {\n super(options.default as T, options, undefined, _call);\n\n this.calculationHelper.options = {\n ...this.calculationHelper.options,\n calculate: (helpers) => {\n let result = connectFunction.apply(helpers);\n\n if (result instanceof Function && result.length > 0) {\n result = result(helpers);\n }\n\n return result as Cancel | void;\n },\n onValue: (value) => {\n this.set(value);\n },\n onError: (error) => {\n this.state.set('error', error);\n },\n onConnectionState: (state) => {\n this.state.set('connectionState', state);\n },\n onInvalidate: () => {\n this.invalidate();\n },\n };\n }\n\n invalidate({ invalidateDependencies = true }: { invalidateDependencies?: boolean } = {}) {\n const { clearOnInvalidate = defaultOptions.clearOnInvalidate } = this.options;\n\n if (clearOnInvalidate) {\n return this.clear({ invalidateDependencies });\n }\n\n if (invalidateDependencies) {\n this.calculationHelper.invalidateDependencies();\n }\n\n this.calculationHelper.stop();\n\n if (this.isActive()) {\n this.calculationHelper.execute();\n }\n }\n\n clear({ invalidateDependencies = true }: { invalidateDependencies?: boolean } = {}): void {\n if (invalidateDependencies) {\n this.calculationHelper.invalidateDependencies();\n }\n\n this.calculationHelper.stop();\n\n if (this.isActive()) {\n this.calculationHelper.execute();\n }\n }\n}\n\nconst defaultOptions: SubstriptionCacheOptions<any> = {\n clearUnusedAfter: { days: 1 },\n retain: { seconds: 1 },\n};\n\ntype CreateReturnType<T, Args extends any[]> = {\n (...args: Args): SubstriptionCache<T>;\n invalidateAll: () => void;\n clearAll: () => void;\n} & ([] extends Args ? SubstriptionCache<T> : {});\n\nfunction create<T, Args extends any[] = []>(\n cacheFunction: SubscriptionCacheFunction<T, Args>,\n ...[options = {} as SubstriptionCacheOptions<T>]: undefined extends T\n ? [options?: SubstriptionCacheOptions<T>]\n : [options: SubstriptionCacheOptions<T>]\n): CreateReturnType<T, Args> {\n const { clearUnusedAfter = defaultOptions.clearUnusedAfter, resourceGroup } = options;\n\n let baseInstance: CreateReturnType<T, Args> & SubstriptionCache<T>;\n\n const instanceCache = new InstanceCache<Args, SubstriptionCache<T>>(\n (...args: Args): SubstriptionCache<T> => {\n if (args.length === 0 && baseInstance) {\n return baseInstance;\n }\n\n return new SubstriptionCache<T>(function () {\n return cacheFunction.apply(this, args);\n }, options);\n },\n clearUnusedAfter ? calcDuration(clearUnusedAfter) : undefined,\n );\n\n const get = (...args: Args) => {\n return instanceCache.get(...args);\n };\n\n const invalidateAll = () => {\n for (const instance of instanceCache.values()) {\n instance.invalidate();\n }\n };\n\n const clearAll = () => {\n for (const instance of instanceCache.values()) {\n instance.clear();\n }\n };\n\n baseInstance = Object.assign(\n new SubstriptionCache<T>(\n function () {\n return cacheFunction.apply(this);\n },\n options,\n undefined,\n get,\n ),\n {\n invalidateAll,\n clearAll,\n },\n ) as CreateReturnType<T, Args> & SubstriptionCache<T>;\n\n const groups = Array.isArray(resourceGroup)\n ? resourceGroup\n : resourceGroup\n ? [resourceGroup]\n : [];\n for (const group of groups.concat(allResources)) {\n group.add(baseInstance);\n }\n\n get(...([] as any));\n\n return baseInstance;\n}\n\nexport const createSubscriptionCache = /* @__PURE__ */ Object.assign(create, {\n defaultOptions,\n});\n","import type { Patch } from './diff';\nimport { remove, set } from './propAccess';\n\nfunction applySinglePatch<T>(target: T, patch: Patch): T {\n if (patch.op === 'remove') {\n return remove(target, patch.path as any);\n }\n\n return set(target, patch.path as any, patch.value);\n}\n\nexport function applyPatches<T>(target: T, ...patches: Patch[]): T {\n for (const patch of patches) {\n target = applySinglePatch(target, patch);\n }\n\n return target;\n}\n","import type { KeyType } from './path';\n\nexport type Patch =\n | { op: 'add'; path: KeyType[]; value: any }\n | { op: 'remove'; path: KeyType[] }\n | { op: 'replace'; path: KeyType[]; value: any };\n\nexport function diff(a: any, b: any): [patches: Patch[], reversePatches: Patch[]] {\n const result = [..._diff(a, b)];\n const patches = result.map(([patch]) => patch);\n const reversePatches = result.map(([, reversePatch]) => reversePatch);\n\n return [patches, reversePatches];\n}\n\nfunction* _diff(\n a: any,\n b: any,\n prefix: KeyType[] = [],\n): Iterable<[patch: Patch, reversePatch: Patch]> {\n if (a === b) {\n return;\n }\n\n if (a instanceof Map && b instanceof Map) {\n return yield* mapDiff(a, b, prefix);\n }\n\n if (a instanceof Set && b instanceof Set) {\n a = [...a];\n b = [...b];\n }\n\n if (a instanceof Object && b instanceof Object && Array.isArray(a) === Array.isArray(b)) {\n return yield* objectDiff(a, b, prefix);\n }\n\n yield [\n { op: 'replace', path: prefix, value: b },\n { op: 'replace', path: prefix, value: a },\n ];\n}\n\nfunction* mapDiff(\n a: Map<any, any>,\n b: Map<any, any>,\n prefix: KeyType[],\n): Iterable<[patch: Patch, reversePatch: Patch]> {\n for (const [key, value] of a) {\n if (!b.has(key)) {\n yield [\n { op: 'remove', path: [...prefix, key] },\n { op: 'add', path: [...prefix, key], value },\n ];\n } else {\n yield* _diff(value, b.get(key), [...prefix, key]);\n }\n }\n\n for (const [key, value] of b) {\n if (!a.has(key)) {\n yield [\n { op: 'add', path: [...prefix, key], value },\n { op: 'remove', path: [...prefix, key] },\n ];\n }\n }\n}\n\nfunction* objectDiff(\n a: any,\n b: any,\n prefix: KeyType[],\n): Iterable<[patch: Patch, reversePatch: Patch]> {\n const castKey = (key: string) => (Array.isArray(a) ? Number(key) : key);\n\n for (const [key, value] of Object.entries(a)) {\n if (!(key in b)) {\n yield [\n { op: 'remove', path: [...prefix, castKey(key)] },\n { op: 'add', path: [...prefix, castKey(key)], value },\n ];\n } else {\n yield* _diff(value, b[key], [...prefix, castKey(key)]);\n }\n }\n\n for (const [key, value] of Object.entries(b)) {\n if (!(key in a)) {\n yield [\n { op: 'add', path: [...prefix, castKey(key)], value },\n { op: 'remove', path: [...prefix, castKey(key)] },\n ];\n }\n }\n}\n","export function findOrDefault<T>(\n array: T[],\n predicate: (item: T) => boolean,\n defaultValue: T | (() => T),\n): T {\n const index = array.findIndex(predicate);\n\n if (index >= 0) {\n return array[index]!;\n }\n\n const value = defaultValue instanceof Function ? defaultValue() : defaultValue;\n array.push(value);\n return value;\n}\n","import type { KeyType } from '@lib/path';\n\nexport const isAncestor = (ancestor: KeyType[], path: KeyType[]): boolean => {\n return (\n ancestor.length <= path.length &&\n ancestor.every((v, i) => v === '*' || path[i] === '*' || v === path[i])\n );\n};\n\nexport const split = (\n value: any,\n path: KeyType[],\n): [value: unknown, subValues: { path: KeyType[]; value: unknown }[]] => {\n const [first, ...rest] = path;\n if (first === undefined) return [value, []];\n\n if (rest.length === 0) {\n if (first === '*')\n return [{}, Object.entries(value).map(([k, v]) => ({ path: [k], value: v }))];\n if (!(first in value)) return [value, []];\n const { [first]: subValue, ...newValue } = value;\n return [newValue, [{ path: [first], value: subValue }]];\n }\n\n const newValue = { ...value };\n const subValues = new Array<{ path: KeyType[]; value: unknown }>();\n for (const key of first === '*' ? Object.keys(value) : [first]) {\n if (!(newValue[key] instanceof Object)) return [value, []];\n const result = split(newValue[key], rest);\n newValue[key] = result[0];\n subValues.push(...result[1].map((s) => ({ path: [key, ...s.path], value: s.value })));\n }\n return [newValue, subValues];\n};\n","import type { MaybePromise } from './maybePromise';\n\nexport function maybeAsync<T, R>(\n value: MaybePromise<T>,\n action: (value: T) => MaybePromise<R>,\n): MaybePromise<R> {\n if (value instanceof Promise) {\n return value.then(action);\n }\n return action(value);\n}\n\nexport function maybeAsyncArray<T>(values: (() => MaybePromise<T>)[]): MaybePromise<T[]> {\n const run = (remainingValues: (() => MaybePromise<T>)[], results: T[]): MaybePromise<T[]> => {\n const [first, ...rest] = remainingValues;\n if (!first) {\n return results;\n }\n\n return maybeAsync(first(), (result) => run(rest, results.concat(result)));\n };\n\n return run(values, []);\n}\n","import { maybeAsync, maybeAsyncArray } from '@lib/maybeAsync';\n\nexport interface PersistStorageBase {\n getItem: (key: string) => string | null | Promise<string | null>;\n setItem: (key: string, value: string) => unknown | Promise<unknown>;\n removeItem: (key: string) => unknown | Promise<unknown>;\n}\n\nexport interface PersistStorageWithKeys extends PersistStorageBase {\n keys: () => string[] | Promise<string[]>;\n}\n\nexport interface PersistStorageWithLength extends PersistStorageBase {\n length: number | (() => number | Promise<number>);\n key: (keyIndex: number) => string | null | Promise<string | null>;\n}\n\nexport type PersistStorage = PersistStorageBase &\n (PersistStorageWithKeys | PersistStorageWithLength);\n\nexport function normalizeStorage(storage: PersistStorage): PersistStorageWithKeys {\n return {\n getItem: storage.getItem.bind(storage),\n setItem: storage.setItem.bind(storage),\n removeItem: storage.removeItem.bind(storage),\n\n keys(): string[] | Promise<string[]> {\n if ('keys' in storage) {\n return storage.keys();\n }\n\n return maybeAsync(\n storage.length instanceof Function ? storage.length() : storage.length,\n (length) => {\n const keyPromises = maybeAsyncArray(\n Array.from({ length }, (_, index) => () => storage.key(index)),\n );\n\n return maybeAsync(keyPromises, (keys) =>\n keys.filter((key): key is string => typeof key === 'string'),\n );\n },\n );\n },\n };\n}\n","import { isAncestor } from './persistPathHelpers';\nimport {\n normalizeStorage,\n type PersistStorage,\n type PersistStorageWithKeys,\n} from './persistStorage';\nimport { type Cancel, type Store } from '@core';\nimport { diff } from '@lib/diff';\nimport { shallowEqual } from '@lib/equals';\nimport { maybeAsync, maybeAsyncArray } from '@lib/maybeAsync';\nimport type { KeyType, WildcardPath } from '@lib/path';\nimport { castArrayPath, get, set } from '@lib/propAccess';\nimport { queue } from '@lib/queue';\n\ntype PathOption<T> =\n | WildcardPath<T>\n | {\n path: WildcardPath<T>;\n throttleMs?: number;\n };\n\nexport interface PersistOptions<T> {\n id: string;\n storage: PersistStorage;\n paths?: PathOption<T>[];\n throttleMs?: number;\n}\n\nexport class Persist<T> {\n readonly storage: PersistStorageWithKeys;\n\n readonly paths: {\n path: KeyType[];\n throttleMs?: number;\n }[];\n\n readonly initialized: Promise<void>;\n\n private resolveInitialized?: () => void;\n\n private channel: BroadcastChannel;\n\n private queue = queue();\n\n private handles = new Set<Cancel>();\n\n private stopped = false;\n\n private updateInProgress?: [any, any];\n\n constructor(public readonly store: Store<T>, public readonly options: PersistOptions<T>) {\n this.storage = normalizeStorage(options.storage);\n this.channel = new BroadcastChannel(`cross-state-persist_${options.id}`);\n\n this.paths = (options.paths ?? [])\n .map<{\n path: KeyType[];\n throttleMs?: number;\n }>((p) => {\n if (isPlainPath(p)) {\n return { path: castArrayPath(p) };\n }\n\n const _p = p as { path: KeyType[]; throttleMs?: number };\n\n return {\n path: castArrayPath(_p.path),\n throttleMs: _p.throttleMs,\n };\n })\n .sort((a, b) => b.path.length - a.path.length);\n\n if (this.paths.length === 0) {\n this.paths.push({ path: ['*'] });\n }\n\n this.initialized = new Promise((resolve) => {\n this.resolveInitialized = resolve;\n });\n\n this.watchStore();\n this.watchStorage();\n }\n\n private watchStore() {\n let committed = this.store.get();\n\n const cancel = this.store.subscribe(\n (value) => {\n const [patches] = diff(committed, value);\n committed = value;\n\n for (const patch of patches) {\n if (\n this.updateInProgress &&\n shallowEqual(this.updateInProgress[0], patch.path) &&\n this.updateInProgress[1] === (patch.op === 'remove' ? undefined : patch.value)\n ) {\n continue;\n }\n\n const ancestor = this.paths.find((p) => isAncestor(p.path, patch.path));\n\n if (!ancestor) {\n continue;\n }\n\n const pathToSave = patch.path.slice(0, ancestor.path.length);\n this.queue(() => this.save(pathToSave), pathToSave);\n }\n },\n { runNow: false },\n );\n\n this.handles.add(cancel);\n }\n\n private async watchStorage() {\n let keys = this.storage.keys();\n if (keys instanceof Promise) {\n keys = await keys;\n }\n\n if (this.stopped) {\n return;\n }\n\n for (const key of keys) {\n const path = JSON.parse(key);\n this.queue(() => this.load(path));\n }\n\n this.queue(() => this.resolveInitialized?.());\n\n const listener = (event: MessageEvent) => {\n this.queue(() => this.load(event.data));\n };\n\n this.channel.addEventListener('message', listener);\n this.handles.add(() => this.channel.removeEventListener('message', listener));\n }\n\n private load(path: KeyType[]) {\n const matchingPath = this.paths.find(\n (p) => p.path.length === path.length && isAncestor(p.path, path),\n );\n if (!matchingPath) {\n return;\n }\n\n const key = JSON.stringify(path);\n\n return maybeAsync(this.storage.getItem(key), (value) => {\n if (this.stopped || !value) {\n return;\n }\n\n const inSaveQueue = this.queue\n .getRefs()\n .find((ref) => isAncestor(ref, path) || isAncestor(path, ref));\n if (inSaveQueue) {\n return;\n }\n\n const parsedValue = value === 'undefined' ? undefined : JSON.parse(value);\n\n this.updateInProgress = [path, parsedValue];\n this.store.set((state) => set(state, path as any, parsedValue));\n this.updateInProgress = undefined;\n });\n }\n\n private save(path: KeyType[]) {\n const key = JSON.stringify(path);\n const value = get(this.store.get(), path as any);\n const serializedValue = value === undefined ? 'undefined' : JSON.stringify(value);\n\n return maybeAsync(this.storage.setItem(key, serializedValue), () => {\n this.channel.postMessage(path);\n\n return maybeAsync(this.storage.keys(), (keys) => {\n const toRemove = keys.filter((k) => {\n const parsedKey = JSON.parse(k);\n return (\n parsedKey.length > path.length && isAncestor(path, parsedKey)\n // !this.queue.getRefs().find((ref) => isAncestor(ref, parsedKey))\n );\n });\n\n return maybeAsyncArray(toRemove.map((k) => () => this.storage.removeItem(k)));\n });\n });\n }\n\n async stop() {\n this.stopped = true;\n\n for (const handle of this.handles) {\n handle();\n }\n\n await this.queue.whenDone();\n this.channel.close();\n }\n}\n\nexport function persist<T>(store: Store<T>, options: PersistOptions<T>): Persist<T> {\n return new Persist<T>(store, options);\n}\n\nfunction isPlainPath<T>(p: PathOption<T>): p is WildcardPath<T> & (KeyType[] | string) {\n return typeof p === 'string' || Array.isArray(p);\n}\n","import { type Store } from '@core';\nimport { applyPatches } from '@lib/applyPatches';\nimport { type Patch, diff } from '@lib/diff';\n\nexport interface Message<T> {\n id: string;\n previousId?: string;\n patches: Patch[];\n}\n\nconst genId = () => Math.random().toString(36).slice(2);\n\nexport class Sync<T> {\n private previousId = genId();\n private previousState = this.store.get();\n\n private patchStream = this.store.map((state) => {\n const id = genId();\n const previousId = this.previousId;\n const patches = diff(this.previousState, state)[0];\n\n this.previousId = id;\n this.previousState = state;\n return { id, previousId, patches };\n });\n\n constructor(public readonly store: Store<T>) {\n this.patchStream.addEffect(() => {\n this.previousId = genId();\n this.previousState = this.store.get();\n });\n }\n\n connectToClient(listener: (message: Message<T>) => void) {\n const cancel = this.patchStream.subscribe(listener, { runNow: false });\n\n listener({\n id: this.previousId,\n patches: [{ op: 'replace', path: [], value: this.previousState }],\n });\n\n return cancel;\n }\n\n async connectToServer(stream: AsyncIterable<Message<T>>) {\n let previousId;\n\n for await (const message of stream) {\n if (message.previousId && message.previousId !== previousId) {\n throw new Error('previousId mismatch');\n }\n\n previousId = message.id;\n this.store.set((state) => applyPatches(state, ...message.patches));\n }\n }\n}\n\nexport function createSync<T>(store: Store<T>) {\n return new Sync(store);\n}\n"],"names":["get","a","b","i","k"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/core/subscriptionCache.ts","../../src/lib/applyPatches.ts","../../src/lib/diff.ts","../../src/lib/updateHelpers.ts","../../src/persist/persistPathHelpers.ts","../../src/lib/maybeAsync.ts","../../src/persist/persistStorage.ts","../../src/persist/persist.ts","../../src/sync/sync.ts"],"sourcesContent":["import {\n type CalculationHelpers,\n type Cancel,\n type ConnectionState,\n type Duration,\n type Selector,\n} from './commonTypes';\nimport { allResources, type ResourceGroup } from './resourceGroup';\nimport { createStore, Store } from './store';\nimport { calcDuration } from '@lib/calcDuration';\nimport { InstanceCache } from '@lib/instanceCache';\nimport { type Path } from '@lib/path';\n\nexport interface SubscriptionCacheFunction<T, Args extends any[] = []> {\n (\n this: CalculationHelpers<T>,\n ...args: Args\n ): Cancel | void | ((cache: CalculationHelpers<T>) => Cancel | void);\n}\n\nexport type SubstriptionCacheOptions<T> = {\n clearOnInvalidate?: boolean;\n clearUnusedAfter?: Duration | null;\n resourceGroup?: ResourceGroup | ResourceGroup[];\n retain?: Duration;\n} & (T extends undefined ? { default?: T } : { default: T });\n\nexport class SubstriptionCache<T> extends Store<T> {\n readonly state = createStore({\n connectionState: 'closed' as ConnectionState,\n error: undefined as unknown | undefined,\n });\n\n constructor(\n public readonly connectFunction: SubscriptionCacheFunction<T>,\n public readonly options: SubstriptionCacheOptions<T>,\n public readonly derivedFromSubscriptionCache?: {\n subscriptionCache: SubstriptionCache<any>;\n selectors: (Selector<any, any> | Path<any>)[];\n },\n _call?: (...args: any[]) => any,\n ) {\n super(options.default as T, options, undefined, _call);\n\n this.calculationHelper.options = {\n ...this.calculationHelper.options,\n calculate: (helpers) => {\n let result = connectFunction.apply(helpers);\n\n if (result instanceof Function && result.length > 0) {\n result = result(helpers);\n }\n\n return result as Cancel | void;\n },\n onValue: (value) => {\n this.set(value);\n },\n onError: (error) => {\n this.state.set('error', error);\n },\n onConnectionState: (state) => {\n this.state.set('connectionState', state);\n },\n onInvalidate: () => {\n this.invalidate();\n },\n };\n }\n\n invalidate({ invalidateDependencies = true }: { invalidateDependencies?: boolean } = {}) {\n const { clearOnInvalidate = defaultOptions.clearOnInvalidate } = this.options;\n\n if (clearOnInvalidate) {\n return this.clear({ invalidateDependencies });\n }\n\n if (invalidateDependencies) {\n this.calculationHelper.invalidateDependencies();\n }\n\n this.calculationHelper.stop();\n\n if (this.isActive()) {\n this.calculationHelper.execute();\n }\n }\n\n clear({ invalidateDependencies = true }: { invalidateDependencies?: boolean } = {}): void {\n if (invalidateDependencies) {\n this.calculationHelper.invalidateDependencies();\n }\n\n this.calculationHelper.stop();\n\n if (this.isActive()) {\n this.calculationHelper.execute();\n }\n }\n}\n\nconst defaultOptions: SubstriptionCacheOptions<any> = {\n clearUnusedAfter: { days: 1 },\n retain: { seconds: 1 },\n};\n\ntype CreateReturnType<T, Args extends any[]> = {\n (...args: Args): SubstriptionCache<T>;\n invalidateAll: () => void;\n clearAll: () => void;\n} & ([] extends Args ? SubstriptionCache<T> : {});\n\nfunction create<T, Args extends any[] = []>(\n cacheFunction: SubscriptionCacheFunction<T, Args>,\n ...[options = {} as SubstriptionCacheOptions<T>]: undefined extends T\n ? [options?: SubstriptionCacheOptions<T>]\n : [options: SubstriptionCacheOptions<T>]\n): CreateReturnType<T, Args> {\n const { clearUnusedAfter = defaultOptions.clearUnusedAfter, resourceGroup } = options;\n\n let baseInstance: CreateReturnType<T, Args> & SubstriptionCache<T>;\n\n const instanceCache = new InstanceCache<Args, SubstriptionCache<T>>(\n (...args: Args): SubstriptionCache<T> => {\n if (args.length === 0 && baseInstance) {\n return baseInstance;\n }\n\n return new SubstriptionCache<T>(function () {\n return cacheFunction.apply(this, args);\n }, options);\n },\n clearUnusedAfter ? calcDuration(clearUnusedAfter) : undefined,\n );\n\n const get = (...args: Args) => {\n return instanceCache.get(...args);\n };\n\n const invalidateAll = () => {\n for (const instance of instanceCache.values()) {\n instance.invalidate();\n }\n };\n\n const clearAll = () => {\n for (const instance of instanceCache.values()) {\n instance.clear();\n }\n };\n\n baseInstance = Object.assign(\n new SubstriptionCache<T>(\n function () {\n return cacheFunction.apply(this);\n },\n options,\n undefined,\n get,\n ),\n {\n invalidateAll,\n clearAll,\n },\n ) as CreateReturnType<T, Args> & SubstriptionCache<T>;\n\n const groups = Array.isArray(resourceGroup)\n ? resourceGroup\n : resourceGroup\n ? [resourceGroup]\n : [];\n for (const group of groups.concat(allResources)) {\n group.add(baseInstance);\n }\n\n get(...([] as any));\n\n return baseInstance;\n}\n\nexport const createSubscriptionCache = /* @__PURE__ */ Object.assign(create, {\n defaultOptions,\n});\n","import type { Patch } from './diff';\nimport { remove, set } from './propAccess';\n\nfunction applySinglePatch<T>(target: T, patch: Patch): T {\n if (patch.op === 'remove') {\n return remove(target, patch.path as any);\n }\n\n return set(target, patch.path as any, patch.value);\n}\n\nexport function applyPatches<T>(target: T, ...patches: Patch[]): T {\n for (const patch of patches) {\n target = applySinglePatch(target, patch);\n }\n\n return target;\n}\n","import type { KeyType } from './path';\n\nexport type Patch =\n | { op: 'add'; path: KeyType[]; value: any }\n | { op: 'remove'; path: KeyType[] }\n | { op: 'replace'; path: KeyType[]; value: any };\n\nexport function diff(a: any, b: any): [patches: Patch[], reversePatches: Patch[]] {\n const result = [..._diff(a, b)];\n const patches = result.map(([patch]) => patch);\n const reversePatches = result.map(([, reversePatch]) => reversePatch);\n\n return [patches, reversePatches];\n}\n\nfunction* _diff(\n a: any,\n b: any,\n prefix: KeyType[] = [],\n): Iterable<[patch: Patch, reversePatch: Patch]> {\n if (a === b) {\n return;\n }\n\n if (a instanceof Map && b instanceof Map) {\n return yield* mapDiff(a, b, prefix);\n }\n\n if (a instanceof Set && b instanceof Set) {\n a = [...a];\n b = [...b];\n }\n\n if (a instanceof Object && b instanceof Object && Array.isArray(a) === Array.isArray(b)) {\n return yield* objectDiff(a, b, prefix);\n }\n\n yield [\n { op: 'replace', path: prefix, value: b },\n { op: 'replace', path: prefix, value: a },\n ];\n}\n\nfunction* mapDiff(\n a: Map<any, any>,\n b: Map<any, any>,\n prefix: KeyType[],\n): Iterable<[patch: Patch, reversePatch: Patch]> {\n for (const [key, value] of a) {\n if (!b.has(key)) {\n yield [\n { op: 'remove', path: [...prefix, key] },\n { op: 'add', path: [...prefix, key], value },\n ];\n } else {\n yield* _diff(value, b.get(key), [...prefix, key]);\n }\n }\n\n for (const [key, value] of b) {\n if (!a.has(key)) {\n yield [\n { op: 'add', path: [...prefix, key], value },\n { op: 'remove', path: [...prefix, key] },\n ];\n }\n }\n}\n\nfunction* objectDiff(\n a: any,\n b: any,\n prefix: KeyType[],\n): Iterable<[patch: Patch, reversePatch: Patch]> {\n const castKey = (key: string) => (Array.isArray(a) ? Number(key) : key);\n\n for (const [key, value] of Object.entries(a)) {\n if (!(key in b)) {\n yield [\n { op: 'remove', path: [...prefix, castKey(key)] },\n { op: 'add', path: [...prefix, castKey(key)], value },\n ];\n } else {\n yield* _diff(value, b[key], [...prefix, castKey(key)]);\n }\n }\n\n for (const [key, value] of Object.entries(b)) {\n if (!(key in a)) {\n yield [\n { op: 'add', path: [...prefix, castKey(key)], value },\n { op: 'remove', path: [...prefix, castKey(key)] },\n ];\n }\n }\n}\n","export function findOrDefault<T>(\n array: T[],\n predicate: (item: T) => boolean,\n defaultValue: T | (() => T),\n): T {\n const index = array.findIndex(predicate);\n\n if (index >= 0) {\n return array[index]!;\n }\n\n const value = defaultValue instanceof Function ? defaultValue() : defaultValue;\n array.push(value);\n return value;\n}\n","import type { KeyType } from '@lib/path';\n\nexport const isAncestor = (ancestor: KeyType[], path: KeyType[]): boolean => {\n return (\n ancestor.length <= path.length &&\n ancestor.every((v, i) => v === '*' || path[i] === '*' || v === path[i])\n );\n};\n\nexport const split = (\n value: any,\n path: KeyType[],\n): [value: unknown, subValues: { path: KeyType[]; value: unknown }[]] => {\n const [first, ...rest] = path;\n if (first === undefined) return [value, []];\n\n if (rest.length === 0) {\n if (first === '*')\n return [{}, Object.entries(value).map(([k, v]) => ({ path: [k], value: v }))];\n if (!(first in value)) return [value, []];\n const { [first]: subValue, ...newValue } = value;\n return [newValue, [{ path: [first], value: subValue }]];\n }\n\n const newValue = { ...value };\n const subValues = new Array<{ path: KeyType[]; value: unknown }>();\n for (const key of first === '*' ? Object.keys(value) : [first]) {\n if (!(newValue[key] instanceof Object)) return [value, []];\n const result = split(newValue[key], rest);\n newValue[key] = result[0];\n subValues.push(...result[1].map((s) => ({ path: [key, ...s.path], value: s.value })));\n }\n return [newValue, subValues];\n};\n","import type { MaybePromise } from './maybePromise';\n\nexport function maybeAsync<T, R>(\n value: MaybePromise<T>,\n action: (value: T) => MaybePromise<R>,\n): MaybePromise<R> {\n if (value instanceof Promise) {\n return value.then(action);\n }\n return action(value);\n}\n\nexport function maybeAsyncArray<T>(values: (() => MaybePromise<T>)[]): MaybePromise<T[]> {\n const run = (remainingValues: (() => MaybePromise<T>)[], results: T[]): MaybePromise<T[]> => {\n const [first, ...rest] = remainingValues;\n if (!first) {\n return results;\n }\n\n return maybeAsync(first(), (result) => run(rest, results.concat(result)));\n };\n\n return run(values, []);\n}\n","import { maybeAsync, maybeAsyncArray } from '@lib/maybeAsync';\n\nexport interface PersistStorageBase {\n getItem: (key: string) => string | null | Promise<string | null>;\n setItem: (key: string, value: string) => unknown | Promise<unknown>;\n removeItem: (key: string) => unknown | Promise<unknown>;\n}\n\nexport interface PersistStorageWithKeys extends PersistStorageBase {\n keys: () => string[] | Promise<string[]>;\n}\n\nexport interface PersistStorageWithLength extends PersistStorageBase {\n length: number | (() => number | Promise<number>);\n key: (keyIndex: number) => string | null | Promise<string | null>;\n}\n\nexport type PersistStorage = PersistStorageBase &\n (PersistStorageWithKeys | PersistStorageWithLength);\n\nexport function normalizeStorage(storage: PersistStorage): PersistStorageWithKeys {\n return {\n getItem: storage.getItem.bind(storage),\n setItem: storage.setItem.bind(storage),\n removeItem: storage.removeItem.bind(storage),\n\n keys(): string[] | Promise<string[]> {\n if ('keys' in storage) {\n return storage.keys();\n }\n\n return maybeAsync(\n storage.length instanceof Function ? storage.length() : storage.length,\n (length) => {\n const keyPromises = maybeAsyncArray(\n Array.from({ length }, (_, index) => () => storage.key(index)),\n );\n\n return maybeAsync(keyPromises, (keys) =>\n keys.filter((key): key is string => typeof key === 'string'),\n );\n },\n );\n },\n };\n}\n","import { isAncestor } from './persistPathHelpers';\nimport {\n normalizeStorage,\n type PersistStorage,\n type PersistStorageWithKeys,\n} from './persistStorage';\nimport { type Cancel, type Store } from '@core';\nimport { diff } from '@lib/diff';\nimport { shallowEqual } from '@lib/equals';\nimport { maybeAsync, maybeAsyncArray } from '@lib/maybeAsync';\nimport type { KeyType, WildcardPath } from '@lib/path';\nimport { castArrayPath, get, set } from '@lib/propAccess';\nimport { queue } from '@lib/queue';\n\ntype PathOption<T> =\n | WildcardPath<T>\n | {\n path: WildcardPath<T>;\n throttleMs?: number;\n };\n\nexport interface PersistOptions<T> {\n id: string;\n storage: PersistStorage;\n paths?: PathOption<T>[];\n throttleMs?: number;\n}\n\nexport class Persist<T> {\n readonly storage: PersistStorageWithKeys;\n\n readonly paths: {\n path: KeyType[];\n throttleMs?: number;\n }[];\n\n readonly initialized: Promise<void>;\n\n private resolveInitialized?: () => void;\n\n private channel: BroadcastChannel;\n\n private queue = queue();\n\n private handles = new Set<Cancel>();\n\n private stopped = false;\n\n private updateInProgress?: [any, any];\n\n constructor(public readonly store: Store<T>, public readonly options: PersistOptions<T>) {\n this.storage = normalizeStorage(options.storage);\n this.channel = new BroadcastChannel(`cross-state-persist_${options.id}`);\n\n this.paths = (options.paths ?? [])\n .map<{\n path: KeyType[];\n throttleMs?: number;\n }>((p) => {\n if (isPlainPath(p)) {\n return { path: castArrayPath(p) };\n }\n\n const _p = p as { path: KeyType[]; throttleMs?: number };\n\n return {\n path: castArrayPath(_p.path),\n throttleMs: _p.throttleMs,\n };\n })\n .sort((a, b) => b.path.length - a.path.length);\n\n if (this.paths.length === 0) {\n this.paths.push({ path: ['*'] });\n }\n\n this.initialized = new Promise((resolve) => {\n this.resolveInitialized = resolve;\n });\n\n this.watchStore();\n this.watchStorage();\n }\n\n private watchStore() {\n let committed = this.store.get();\n\n const cancel = this.store.subscribe(\n (value) => {\n const [patches] = diff(committed, value);\n committed = value;\n\n for (const patch of patches) {\n if (\n this.updateInProgress &&\n shallowEqual(this.updateInProgress[0], patch.path) &&\n this.updateInProgress[1] === (patch.op === 'remove' ? undefined : patch.value)\n ) {\n continue;\n }\n\n const ancestor = this.paths.find((p) => isAncestor(p.path, patch.path));\n\n if (!ancestor) {\n continue;\n }\n\n const pathToSave = patch.path.slice(0, ancestor.path.length);\n this.queue(() => this.save(pathToSave), pathToSave);\n }\n },\n { runNow: false },\n );\n\n this.handles.add(cancel);\n }\n\n private async watchStorage() {\n let keys = this.storage.keys();\n if (keys instanceof Promise) {\n keys = await keys;\n }\n\n if (this.stopped) {\n return;\n }\n\n for (const key of keys) {\n const path = JSON.parse(key);\n this.queue(() => this.load(path));\n }\n\n this.queue(() => this.resolveInitialized?.());\n\n const listener = (event: MessageEvent) => {\n this.queue(() => this.load(event.data));\n };\n\n this.channel.addEventListener('message', listener);\n this.handles.add(() => this.channel.removeEventListener('message', listener));\n }\n\n private load(path: KeyType[]) {\n const matchingPath = this.paths.find(\n (p) => p.path.length === path.length && isAncestor(p.path, path),\n );\n if (!matchingPath) {\n return;\n }\n\n const key = JSON.stringify(path);\n\n return maybeAsync(this.storage.getItem(key), (value) => {\n if (this.stopped || !value) {\n return;\n }\n\n const inSaveQueue = this.queue\n .getRefs()\n .find((ref) => isAncestor(ref, path) || isAncestor(path, ref));\n if (inSaveQueue) {\n return;\n }\n\n const parsedValue = value === 'undefined' ? undefined : JSON.parse(value);\n\n this.updateInProgress = [path, parsedValue];\n this.store.set((state) => set(state, path as any, parsedValue));\n this.updateInProgress = undefined;\n });\n }\n\n private save(path: KeyType[]) {\n const key = JSON.stringify(path);\n const value = get(this.store.get(), path as any);\n const serializedValue = value === undefined ? 'undefined' : JSON.stringify(value);\n\n return maybeAsync(this.storage.setItem(key, serializedValue), () => {\n this.channel.postMessage(path);\n\n return maybeAsync(this.storage.keys(), (keys) => {\n const toRemove = keys.filter((k) => {\n const parsedKey = JSON.parse(k);\n return (\n parsedKey.length > path.length && isAncestor(path, parsedKey)\n // !this.queue.getRefs().find((ref) => isAncestor(ref, parsedKey))\n );\n });\n\n return maybeAsyncArray(toRemove.map((k) => () => this.storage.removeItem(k)));\n });\n });\n }\n\n async stop() {\n this.stopped = true;\n\n for (const handle of this.handles) {\n handle();\n }\n\n await this.queue.whenDone();\n this.channel.close();\n }\n}\n\nexport function persist<T>(store: Store<T>, options: PersistOptions<T>): Persist<T> {\n return new Persist<T>(store, options);\n}\n\nfunction isPlainPath<T>(p: PathOption<T>): p is WildcardPath<T> & (KeyType[] | string) {\n return typeof p === 'string' || Array.isArray(p);\n}\n","import { type Store } from '@core';\nimport { applyPatches } from '@lib/applyPatches';\nimport { type Patch, diff } from '@lib/diff';\n\nexport interface Message<T> {\n id: string;\n previousId?: string;\n patches: Patch[];\n}\n\nconst genId = () => Math.random().toString(36).slice(2);\n\nexport class Sync<T> {\n private previousId = genId();\n private previousState = this.store.get();\n\n private patchStream = this.store.map((state) => {\n const id = genId();\n const previousId = this.previousId;\n const patches = diff(this.previousState, state)[0];\n\n this.previousId = id;\n this.previousState = state;\n return { id, previousId, patches };\n });\n\n constructor(public readonly store: Store<T>) {\n this.patchStream.addEffect(() => {\n this.previousId = genId();\n this.previousState = this.store.get();\n });\n }\n\n connectToClient(listener: (message: Message<T>) => void) {\n const cancel = this.patchStream.subscribe(listener, { runNow: false });\n\n listener({\n id: this.previousId,\n patches: [{ op: 'replace', path: [], value: this.previousState }],\n });\n\n return cancel;\n }\n\n async connectToServer(stream: AsyncIterable<Message<T>>) {\n let previousId;\n\n for await (const message of stream) {\n if (message.previousId && message.previousId !== previousId) {\n throw new Error('previousId mismatch');\n }\n\n previousId = message.id;\n this.store.set((state) => applyPatches(state, ...message.patches));\n }\n }\n}\n\nexport function createSync<T>(store: Store<T>) {\n return new Sync(store);\n}\n"],"names":["get","a","b","i"],"mappings":"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"}
|
package/dist/es/react/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as useScope, d as useStore, S as ScopeProvider, u as useCache } from "../useCache.mjs";
|
|
2
2
|
import { r, e } from "../useCache.mjs";
|
|
3
|
-
import { useMemo, useState, useEffect, createElement, createContext, useContext, useRef, startTransition } from "react";
|
|
4
|
-
import { d as castArrayPath, a as autobind, g as get, c as createStore,
|
|
3
|
+
import { useCallback, Fragment as Fragment$1, useMemo, useState, useEffect, createElement, createContext, useContext, useRef, startTransition } from "react";
|
|
4
|
+
import { d as castArrayPath, a as autobind, g as get, c as createStore, k as deepEqual, l as debounce, t as throttle } from "../store.mjs";
|
|
5
5
|
import { S as Scope, h as hash } from "../scope.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
7
7
|
import { c as connectUrl } from "../urlStore.mjs";
|
|
8
8
|
function wildcardMatch(s, w) {
|
|
9
9
|
if (typeof s === "string") {
|
|
@@ -37,6 +37,41 @@ function getWildCardMatches(object, path) {
|
|
|
37
37
|
}
|
|
38
38
|
return matches;
|
|
39
39
|
}
|
|
40
|
+
function FormArray({ name, renderElement, children }) {
|
|
41
|
+
const form = this.useForm();
|
|
42
|
+
const names = this.useFormState((form2) => {
|
|
43
|
+
const field = form2.getField(name);
|
|
44
|
+
return field.names;
|
|
45
|
+
});
|
|
46
|
+
const append = useCallback((...newEntries) => {
|
|
47
|
+
const field = form.getField(name);
|
|
48
|
+
field.append(...newEntries);
|
|
49
|
+
}, []);
|
|
50
|
+
const remove = useCallback((index) => {
|
|
51
|
+
const field = form.getField(name);
|
|
52
|
+
field.remove(index);
|
|
53
|
+
}, []);
|
|
54
|
+
const setValue = useCallback(
|
|
55
|
+
(value) => {
|
|
56
|
+
const field = form.getField(name);
|
|
57
|
+
field.setValue(value);
|
|
58
|
+
},
|
|
59
|
+
[]
|
|
60
|
+
);
|
|
61
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
62
|
+
renderElement && names.map((name2, index) => /* @__PURE__ */ jsx(Fragment$1, { children: renderElement({
|
|
63
|
+
name: name2,
|
|
64
|
+
index,
|
|
65
|
+
remove: () => remove(index)
|
|
66
|
+
}) }, index)),
|
|
67
|
+
children == null ? void 0 : children({
|
|
68
|
+
names,
|
|
69
|
+
append,
|
|
70
|
+
remove,
|
|
71
|
+
setValue
|
|
72
|
+
})
|
|
73
|
+
] });
|
|
74
|
+
}
|
|
40
75
|
function FormError({ name }) {
|
|
41
76
|
const { errors, isDirty } = this.useField(name);
|
|
42
77
|
return isDirty ? /* @__PURE__ */ jsx(Fragment, { children: errors.join(", ") }) : null;
|
|
@@ -44,6 +79,7 @@ function FormError({ name }) {
|
|
|
44
79
|
function FormField({
|
|
45
80
|
// id,
|
|
46
81
|
name,
|
|
82
|
+
component,
|
|
47
83
|
commitOnBlur,
|
|
48
84
|
commitDebounce,
|
|
49
85
|
inputFilter,
|
|
@@ -52,7 +88,6 @@ function FormField({
|
|
|
52
88
|
...restProps
|
|
53
89
|
}) {
|
|
54
90
|
const id = "";
|
|
55
|
-
const component = ("component" in restProps ? restProps.component : "children" in restProps ? restProps.children : void 0) ?? "input";
|
|
56
91
|
const form = this.useForm();
|
|
57
92
|
const state = useScope(this.state);
|
|
58
93
|
const { value, setValue, errors } = this.useField(name);
|
|
@@ -89,8 +124,6 @@ function FormField({
|
|
|
89
124
|
}, [_id, errorString]);
|
|
90
125
|
const props = {
|
|
91
126
|
...restProps,
|
|
92
|
-
component: void 0,
|
|
93
|
-
children: void 0,
|
|
94
127
|
id: _id,
|
|
95
128
|
name,
|
|
96
129
|
value: localValue ?? serialize(value),
|
|
@@ -132,10 +165,12 @@ function FormContainer({
|
|
|
132
165
|
...formProps
|
|
133
166
|
}) {
|
|
134
167
|
const _form = form.useForm();
|
|
168
|
+
const hasTriggeredValidations = form.useFormState((state) => state.hasTriggeredValidations);
|
|
135
169
|
return /* @__PURE__ */ jsx(
|
|
136
170
|
"form",
|
|
137
171
|
{
|
|
138
172
|
...formProps,
|
|
173
|
+
className: [formProps.className, hasTriggeredValidations ? "validated" : void 0].filter(Boolean).join(" "),
|
|
139
174
|
noValidate: true,
|
|
140
175
|
onSubmit: (event) => {
|
|
141
176
|
event.preventDefault();
|
|
@@ -192,6 +227,20 @@ function getFormInstance(original, options, state) {
|
|
|
192
227
|
}
|
|
193
228
|
}
|
|
194
229
|
return errors;
|
|
230
|
+
},
|
|
231
|
+
get names() {
|
|
232
|
+
const { value } = this;
|
|
233
|
+
return Array.isArray(value) ? value.map((_, index) => `${path}.${index}`) : [];
|
|
234
|
+
},
|
|
235
|
+
append(...elements) {
|
|
236
|
+
this.setValue(
|
|
237
|
+
(value) => Array.isArray(value) ? [...value, ...elements] : elements
|
|
238
|
+
);
|
|
239
|
+
},
|
|
240
|
+
remove(index) {
|
|
241
|
+
this.setValue(
|
|
242
|
+
(value) => Array.isArray(value) ? [...value.slice(0, index), ...value.slice(index + 1)] : value
|
|
243
|
+
);
|
|
195
244
|
}
|
|
196
245
|
};
|
|
197
246
|
},
|
|
@@ -229,8 +278,12 @@ function getFormInstance(original, options, state) {
|
|
|
229
278
|
state.set("hasTriggeredValidations", true);
|
|
230
279
|
return instance.isValid;
|
|
231
280
|
},
|
|
281
|
+
get hasTriggeredValidations() {
|
|
282
|
+
return state.get().hasTriggeredValidations;
|
|
283
|
+
},
|
|
232
284
|
reset() {
|
|
233
285
|
state.set("draft", void 0);
|
|
286
|
+
state.set("hasTriggeredValidations", false);
|
|
234
287
|
}
|
|
235
288
|
};
|
|
236
289
|
return instance;
|
|
@@ -323,7 +376,10 @@ class Form {
|
|
|
323
376
|
return /* @__PURE__ */ jsx(Fragment, { children: children(selectedState) });
|
|
324
377
|
}
|
|
325
378
|
Field(props) {
|
|
326
|
-
return Reflect.apply(FormField, this, [props]);
|
|
379
|
+
return Reflect.apply(FormField, this, [{ component: "input", ...props }]);
|
|
380
|
+
}
|
|
381
|
+
Array(props) {
|
|
382
|
+
return Reflect.apply(FormArray, this, [props]);
|
|
327
383
|
}
|
|
328
384
|
Error({ name }) {
|
|
329
385
|
return Reflect.apply(FormError, this, [{ name }]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../../src/lib/wildcardMatch.ts","../../../src/react/form/formError.tsx","../../../src/react/form/formField.tsx","../../../src/react/form/form.tsx","../../../src/react/read.ts","../../../src/react/useDecoupledState.ts","../../../src/lib/castArray.ts","../../../src/react/useUrlParamScope.ts"],"sourcesContent":["import { type KeyType } from './path';\nimport { castArrayPath } from './propAccess';\n\nexport function wildcardMatch(s: KeyType[] | string, w: KeyType[] | string): boolean {\n if (typeof s === 'string') {\n s = castArrayPath(s);\n }\n\n if (typeof w === 'string') {\n w = castArrayPath(w);\n }\n\n return s.length === w.length && s.every((s, i) => w[i] === '*' || s === w[i]);\n}\n\nexport function getWildCardMatches(\n object: any,\n path: [KeyType, ...KeyType[]] | string,\n): Record<KeyType, any> {\n const matches: Record<KeyType, any> = {};\n const [first, second, ...rest] = castArrayPath(path);\n\n if (first === undefined) {\n throw new Error('Path is empty');\n }\n\n if (!(object instanceof Object)) {\n throw new Error('Object is not an object');\n }\n\n for (const [key, value] of Object.entries(object)) {\n if (first !== '*' && first !== key) {\n continue;\n }\n\n if (second === undefined) {\n matches[key] = value;\n continue;\n }\n\n for (const [subKey, subValue] of Object.entries(getWildCardMatches(value, [second, ...rest]))) {\n matches[`${key}.${subKey}`] = subValue;\n }\n }\n\n return matches;\n}\n","import { type Form } from './form';\nimport { type PathAsString } from '@lib/path';\n\nexport type FormErrorProps<TDraft, TPath extends PathAsString<TDraft>> = {\n name: TPath;\n};\n\nexport function FormError<TDraft, TPath extends PathAsString<TDraft>>(\n this: Form<TDraft, any>,\n { name }: FormErrorProps<TDraft, TPath>,\n) {\n const { errors, isDirty } = this.useField(name);\n\n return isDirty ? <>{errors.join(', ')}</> : null;\n}\n","import { type PathAsString } from '@index';\nimport { type Value } from '@lib/path';\nimport { useScope } from '@react/scope';\nimport {\n createElement,\n useEffect,\n useMemo,\n useState,\n type Component,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\nimport { type Form } from './form';\n\ninterface FormFieldComponentProps<TValue, TPath> {\n id: string;\n name: TPath;\n value: TValue;\n onChange: (event: { target: { value: TValue } } | TValue | undefined, ...args: any[]) => void;\n onFocus: (...args: any[]) => void;\n onBlur: (...args: any[]) => void;\n}\n\ntype NativeInputType = 'input' | 'select' | 'textarea';\n\ntype PartialComponentType<P> =\n | (new (props: P, context?: any) => Component<P, any>)\n | ((props: P, context?: any) => ReactNode);\n\nexport type FormFieldComponent<TValue, TPath> =\n | (string | number extends TValue ? NativeInputType : never)\n | PartialComponentType<FormFieldComponentProps<TValue, TPath>>;\n\ntype FieldValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<\n T & 'input'\n> extends {\n value: infer U;\n}\n ? U\n : ComponentPropsWithoutRef<T & 'input'> extends {\n value?: infer U;\n }\n ? U | undefined\n : never;\n\ntype FieldChangeValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<\n T & 'input'\n> extends {\n onChange?: (update: infer U) => void;\n}\n ? U extends { target: { value: infer V } }\n ? V\n : U\n : never;\n\nexport type FormFieldProps<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath>,\n> = {\n name: TPath;\n commitOnBlur?: boolean;\n commitDebounce?: number;\n inputFilter?: (value: FieldChangeValue<TComponent>) => boolean;\n onChange?: ComponentPropsWithoutRef<TComponent>['onChange'];\n onBlur?: ComponentPropsWithoutRef<TComponent>['onBlur'];\n} & (TComponent extends\n | 'input'\n | ((props: ComponentPropsWithoutRef<'input'> & { name: TPath }) => JSX.Element)\n ? { component?: TComponent } | { children?: TComponent }\n : { component: TComponent } | { children: TComponent }) &\n Omit<\n ComponentPropsWithoutRef<TComponent>,\n | 'form'\n | 'name'\n | 'component'\n | 'commitOnBlur'\n | 'commitDebounce'\n | 'value'\n | 'onChange'\n | 'onBlur'\n | 'children'\n > &\n (Value<TDraft, TPath> extends FieldValue<TComponent>\n ? { serialize?: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }\n : { serialize: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }) &\n (FieldChangeValue<TComponent> extends Value<TDraft, TPath>\n ? { deserialize?: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> }\n : { deserialize: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> });\n\nexport function FormField<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, any>,\n>(\n this: Form<TDraft, any>,\n {\n // id,\n name,\n commitOnBlur,\n commitDebounce,\n inputFilter,\n serialize = (x) => x as FieldValue<TComponent>,\n deserialize = (x) => x as Value<TDraft, TPath>,\n ...restProps\n }: FormFieldProps<TDraft, TPath, TComponent>,\n): JSX.Element {\n type T = FieldChangeValue<TComponent>;\n const id = '';\n const component = (('component' in restProps\n ? restProps.component\n : 'children' in restProps\n ? restProps.children\n : undefined) ?? 'input') as TComponent;\n\n const form = this.useForm();\n const state = useScope(this.state);\n const { value, setValue, errors } = this.useField(name);\n\n const errorString = useMemo(\n () => errors.map((error) => form.options.localizeError?.(error, name) ?? error).join('\\n'),\n [errors, form.options.localizeError],\n );\n const [localValue, setLocalValue] = useState<T>();\n const _id = useMemo(\n () =>\n id || `f${Math.random().toString(36).slice(2, 15)}${Math.random().toString(36).slice(2, 15)}`,\n\n [id],\n );\n\n useEffect(() => {\n if (localValue === undefined || !commitDebounce) {\n return;\n }\n\n const timeout = setTimeout(() => {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }, commitDebounce);\n\n return () => clearTimeout(timeout);\n }, [localValue, commitDebounce]);\n\n useEffect(() => {\n const element = document.querySelector(\n [`#${_id} input`, `#${_id} select`, `#${_id} textarea`, `#${_id}`].join(','),\n );\n\n if (\n !(\n element instanceof HTMLInputElement ||\n element instanceof HTMLSelectElement ||\n element instanceof HTMLTextAreaElement\n )\n ) {\n return;\n }\n\n element.setCustomValidity(errorString);\n }, [_id, errorString]);\n\n const props = {\n ...restProps,\n component: undefined,\n children: undefined,\n id: _id,\n name,\n value: localValue ?? serialize(value),\n onChange: (event: { target: { value: T } } | T, ...moreArgs: any[]) => {\n const value =\n typeof event === 'object' && event !== null && 'target' in event\n ? event.target.value\n : event;\n\n if (inputFilter && !inputFilter(value)) {\n return;\n }\n\n if (commitOnBlur || commitDebounce) {\n setLocalValue(value);\n } else {\n setValue(deserialize(value));\n }\n\n restProps.onChange?.(event, ...moreArgs);\n },\n onFocus(...args: any[]) {\n state.set('touched', (touched) => {\n touched = new Set(touched);\n touched.add(_id);\n return touched;\n });\n\n restProps.onFocus?.apply(null, args);\n },\n onBlur(...args: any[]) {\n if (localValue !== undefined) {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }\n\n restProps.onBlur?.apply(null, args);\n },\n };\n\n return createElement(component, props);\n}\n","import { Scope, type Store, connectUrl, createStore, type UrlStoreOptions } from '@core';\nimport { autobind } from '@lib/autobind';\nimport { deepEqual } from '@lib/equals';\nimport { hash } from '@lib/hash';\nimport {\n type PathAsString,\n type Value,\n type WildcardPathAsString,\n type WildcardValue,\n} from '@lib/path';\nimport { get } from '@lib/propAccess';\nimport { getWildCardMatches, wildcardMatch } from '@lib/wildcardMatch';\nimport {\n type ReactNode,\n createContext,\n useContext,\n useEffect,\n useMemo,\n type ComponentPropsWithoutRef,\n type HTMLProps,\n} from 'react';\nimport { ScopeProvider, useScope } from '../scope';\nimport { useStore, type UseStoreOptions } from '../useStore';\nimport { FormError, type FormErrorProps } from './formError';\nimport { FormField, type FormFieldComponent, type FormFieldProps } from './formField';\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Form types\n/// /////////////////////////////////////////////////////////////////////////////\n\nexport interface FormOptions<TDraft, TOriginal> {\n defaultValue: TDraft;\n validations?: Validations<TDraft, TOriginal>;\n localizeError?: (error: string, field: string) => string | undefined;\n urlState?: boolean | UrlStoreOptions<TDraft>;\n}\n\nexport type Validations<TDraft, TOriginal> = {\n [P in WildcardPathAsString<TDraft>]?: Record<\n string,\n Validation<WildcardValue<TDraft, P>, TDraft, TOriginal>\n >;\n} & Record<string, Record<string, Validation<any, TDraft, TOriginal>>>;\n\nexport type Validation<TValue, TDraft, TOriginal> = (\n value: TValue,\n context: { draft: TDraft; original: TOriginal; field: PathAsString<TDraft> },\n) => boolean;\n\nexport interface Field<TDraft, TOriginal, TPath extends PathAsString<TDraft>> {\n originalValue: Value<TOriginal, TPath> | undefined;\n value: Value<TDraft, TPath>;\n setValue: (\n value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>),\n ) => void;\n isDirty: boolean;\n errors: string[];\n}\n\ninterface FormState<TDraft> {\n draft?: TDraft;\n touched: Set<string>;\n errors: Map<string, string[]>;\n hasTriggeredValidations?: boolean;\n}\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Implementation\n/// /////////////////////////////////////////////////////////////////////////////\n\nfunction FormContainer({\n form,\n ...formProps\n}: { form: Form<any, any> } & Omit<HTMLProps<HTMLFormElement>, 'form'>) {\n const _form = form.useForm();\n\n return (\n <form\n {...formProps}\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n\n _form.validate();\n\n let button;\n\n if (\n event.nativeEvent instanceof SubmitEvent &&\n (button = event.nativeEvent.submitter) &&\n (button instanceof HTMLButtonElement || button instanceof HTMLInputElement) &&\n button.setCustomValidity\n ) {\n const errors = _form.errors.map(\n ({ field, error }) => _form.options.localizeError?.(error, field) ?? error,\n );\n button.setCustomValidity(errors.join('\\n'));\n }\n event.currentTarget.reportValidity();\n }}\n />\n );\n}\n\nfunction getFormInstance<TDraft, TOriginal extends TDraft>(\n original: TOriginal | undefined,\n options: FormOptions<TDraft, TOriginal>,\n state: Store<FormState<TDraft>>,\n) {\n const instance = {\n original,\n\n draft: state.map(\n (state) => state.draft ?? original ?? options.defaultValue,\n (draft) => (state) => ({ ...state, draft }),\n ),\n\n options,\n\n getField: <TPath extends PathAsString<TDraft>>(\n path: TPath,\n ): Field<TDraft, TOriginal, TPath> => {\n const { draft } = instance;\n\n return {\n get originalValue() {\n return original !== undefined ? get(original as any, path as any) : undefined;\n },\n\n get value() {\n return get(draft.get(), path);\n },\n\n setValue(update) {\n draft.set(path, update);\n },\n\n get isDirty() {\n const comparisonValue = this.originalValue ?? get(options.defaultValue, path);\n\n return state.get().hasTriggeredValidations || !deepEqual(comparisonValue, this.value);\n },\n\n get errors() {\n const blocks: (Validation<any, any, any> | Record<string, Validation<any, any, any>>)[] =\n Object.entries(options.validations ?? {})\n .filter(([key]) => wildcardMatch(path, key))\n .map(([, value]) => value);\n\n const value = this.value;\n const draftValue = draft.get();\n const errors: string[] = [];\n\n for (const block of blocks ?? []) {\n for (const [validationName, validate] of Object.entries(block)) {\n if (!validate(value, { draft: draftValue, original, field: path })) {\n errors.push(validationName);\n }\n }\n }\n\n return errors;\n },\n };\n },\n\n get hasChanges() {\n const { draft } = state.get();\n return !!draft && !deepEqual(draft, original ?? options.defaultValue);\n },\n\n get errors() {\n const draft = instance.draft.get();\n const errors = new Set<{ field: string; error: string }>();\n\n for (const [path, block] of Object.entries(options.validations ?? {})) {\n for (const [validationName, validate] of Object.entries(\n block as Record<string, Validation<any, any, any>>,\n )) {\n let matched = false;\n\n for (const [field, value] of Object.entries(getWildCardMatches(draft, path))) {\n matched = true;\n if (!validate(value, { draft, original, field })) {\n errors.add({ field, error: validationName });\n }\n }\n\n if (!matched && !path.includes('*')) {\n if (!validate(undefined, { draft, original, field: path })) {\n errors.add({ field: path, error: validationName });\n }\n }\n }\n }\n\n return [...errors];\n },\n\n get isValid() {\n return instance.errors.length === 0;\n },\n\n validate: () => {\n state.set('hasTriggeredValidations', true);\n return instance.isValid;\n },\n\n reset() {\n state.set('draft', undefined);\n },\n };\n\n return instance;\n}\n\nexport class Form<TDraft, TOriginal extends TDraft = TDraft> {\n context = createContext({\n original: undefined as TOriginal | undefined,\n options: this.options,\n });\n\n state = new Scope<FormState<TDraft>>({\n touched: new Set(),\n errors: new Map(),\n });\n\n constructor(public readonly options: FormOptions<TDraft, TOriginal>) {\n autobind(Form);\n }\n\n useForm() {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useMemo(() => getFormInstance(original, options, state), [original, options, state]);\n }\n\n useFormState<S>(selector: (state: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S) {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useStore(state.map(() => selector(getFormInstance(original, options, state))));\n }\n\n useField<TPath extends PathAsString<TDraft>>(path: TPath, useStoreOptions?: UseStoreOptions) {\n const form = this.useForm();\n const state = useScope(this.state);\n\n useStore(\n form.draft.map((draft) => get(draft, path)),\n useStoreOptions,\n );\n\n useStore(\n state.map((state) => state.hasTriggeredValidations),\n useStoreOptions,\n );\n\n return form.getField(path);\n }\n\n useHasChanges() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.hasChanges));\n }\n\n useIsValid() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.isValid));\n }\n\n // ///////////////////////////////////////////////////////////////////////////\n // React Components\n // ///////////////////////////////////////////////////////////////////////////\n\n Form({\n original,\n defaultValue,\n validations,\n localizeError,\n urlState,\n ...formProps\n }: {\n original?: TOriginal;\n } & Partial<FormOptions<TDraft, TOriginal>> &\n Omit<HTMLProps<HTMLFormElement>, 'defaultValue'>) {\n const value = useMemo(\n () => ({\n original,\n options: {\n defaultValue: { ...this.options.defaultValue, ...defaultValue },\n validations: { ...this.options.validations, ...validations } as Validations<\n TDraft,\n TOriginal\n >,\n localizeError: localizeError ?? this.options.localizeError,\n },\n }),\n [original, defaultValue, validations],\n );\n\n const store = useMemo(() => {\n return createStore(this.state.defaultValue);\n }, []);\n\n useEffect(() => {\n if (urlState) {\n return connectUrl(\n store.map('draft'),\n typeof urlState === 'object' ? urlState : { key: 'form' },\n );\n }\n\n return undefined;\n }, [store, hash(urlState)]);\n\n return (\n <this.context.Provider value={value}>\n <ScopeProvider scope={this.state} store={store}>\n <FormContainer {...formProps} form={this} />\n </ScopeProvider>\n </this.context.Provider>\n );\n }\n\n Subscribe<S>({\n selector,\n children,\n }: {\n selector: (form: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S;\n children: (selectedState: S) => ReactNode;\n }) {\n const selectedState = this.useFormState(selector);\n return <>{children(selectedState)}</>;\n }\n\n Field<\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath> = (\n props: ComponentPropsWithoutRef<'input'> & { name: TPath },\n ) => JSX.Element,\n >(props: FormFieldProps<TDraft, TPath, TComponent>): JSX.Element {\n return Reflect.apply(FormField, this, [props]);\n }\n\n Error<TPath extends PathAsString<TDraft>>({ name }: FormErrorProps<TDraft, TPath>) {\n return Reflect.apply(FormError, this, [{ name }]);\n }\n}\n\nexport function createForm<TDraft, TOriginal extends TDraft = TDraft>(\n options: FormOptions<TDraft, TOriginal>,\n) {\n return new Form(options);\n}\n","import { useCache } from './useCache';\nimport type { UseStoreOptions } from './useStore';\nimport type { Cache } from '@core';\n\nexport function read<T>(cache: Cache<T>, options?: UseStoreOptions): T {\n const { status, value, error } = useCache(cache, options);\n\n if (status === 'value') {\n return value;\n }\n\n if (status === 'error') {\n throw error;\n }\n\n throw cache.state.once((state) => state.status !== 'pending');\n}\n","import { startTransition, useEffect, useMemo, useRef, useState } from 'react';\nimport { type Duration } from '@core';\nimport { debounce } from '@lib/debounce';\nimport { hash } from '@lib/hash';\nimport { throttle } from '@lib/throttle';\n\nexport interface UseDecoupledStateOptions<T> {\n debounce?: Duration;\n throttle?: Duration;\n onCommit?: (value: T) => void;\n}\n\nexport function useDecoupledState<T>(\n value: T,\n onChange: (value: T) => void,\n options: UseDecoupledStateOptions<T> = {},\n): [state: T, setState: (value: T) => void] {\n const [dirty, setDirty] = useState<{ v: T }>();\n const ref = useRef({ onChange, onCommit: options.onCommit });\n\n useEffect(() => {\n ref.current = { onChange, onCommit: options.onCommit };\n }, [onChange]);\n\n const update = useMemo(() => {\n const { onChange, onCommit } = ref.current;\n\n const update = (value: T) => {\n onChange(value);\n setDirty(undefined);\n onCommit?.(value);\n };\n\n let delayedUpdate: (value: T) => void;\n\n if (options.debounce) {\n delayedUpdate = debounce(update, options.debounce);\n } else if (options.throttle) {\n delayedUpdate = throttle(update, options.throttle);\n } else {\n delayedUpdate = (value) => startTransition(() => update(value));\n }\n\n return (value: T) => {\n setDirty({ v: value });\n delayedUpdate(value);\n };\n }, [hash([options.debounce, options.throttle])]);\n\n return [dirty ? dirty.v : value, update];\n}\n","export function castArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value];\n}\n","import { type ReactNode, useEffect } from 'react';\nimport { castArray } from '@lib/castArray';\nimport { hash } from '@lib/hash';\n\nexport function useUrlParamScope({\n key,\n type = 'search',\n}: {\n key: string | string[];\n type?: 'search' | 'hash';\n}) {\n useEffect(\n () => () => {\n const url = new URL(window.location.href);\n const parameters = new URLSearchParams(url[type].slice(1));\n\n for (const _key of castArray(key)) {\n parameters.delete(_key);\n }\n\n url[type] = parameters.toString();\n window.history.replaceState(null, '', url.toString());\n },\n [hash(key), type],\n );\n}\n"],"names":["s","value","state","onChange","update"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../../src/lib/wildcardMatch.ts","../../../src/react/form/formArray.tsx","../../../src/react/form/formError.tsx","../../../src/react/form/formField.tsx","../../../src/react/form/form.tsx","../../../src/react/read.ts","../../../src/react/useDecoupledState.ts","../../../src/lib/castArray.ts","../../../src/react/useUrlParamScope.ts"],"sourcesContent":["import { type KeyType } from './path';\nimport { castArrayPath } from './propAccess';\n\nexport function wildcardMatch(s: KeyType[] | string, w: KeyType[] | string): boolean {\n if (typeof s === 'string') {\n s = castArrayPath(s);\n }\n\n if (typeof w === 'string') {\n w = castArrayPath(w);\n }\n\n return s.length === w.length && s.every((s, i) => w[i] === '*' || s === w[i]);\n}\n\nexport function getWildCardMatches(\n object: any,\n path: [KeyType, ...KeyType[]] | string,\n): Record<KeyType, any> {\n const matches: Record<KeyType, any> = {};\n const [first, second, ...rest] = castArrayPath(path);\n\n if (first === undefined) {\n throw new Error('Path is empty');\n }\n\n if (!(object instanceof Object)) {\n throw new Error('Object is not an object');\n }\n\n for (const [key, value] of Object.entries(object)) {\n if (first !== '*' && first !== key) {\n continue;\n }\n\n if (second === undefined) {\n matches[key] = value;\n continue;\n }\n\n for (const [subKey, subValue] of Object.entries(getWildCardMatches(value, [second, ...rest]))) {\n matches[`${key}.${subKey}`] = subValue;\n }\n }\n\n return matches;\n}\n","import { type PathAsString, type Value } from '@lib/path';\nimport { Fragment, useCallback, type ReactNode } from 'react';\nimport { type ArrayFieldMethods, type Field, type Form } from './form';\n\nexport type ArrayPath<T> = keyof {\n [P in PathAsString<T> as Value<T, P> extends readonly any[] | undefined ? P : never]: never;\n} &\n PathAsString<T> &\n string;\n\nexport interface FormArrayProps<TDraft, TPath extends ArrayPath<TDraft>> {\n name: TPath;\n renderElement?: (props: {\n name: `${TPath}.${number}`;\n index: number;\n remove: () => void;\n }) => ReactNode;\n children?: (props: {\n names: `${TPath}.${number}`[];\n append: (...elements: Value<TDraft, `${TPath}.${number}`>[]) => void;\n remove: (index: number) => void;\n setValue: (\n value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>),\n ) => void;\n }) => ReactNode;\n}\n\nexport function FormArray<TDraft, TPath extends ArrayPath<TDraft>>(\n this: Form<TDraft, any>,\n { name, renderElement, children }: FormArrayProps<TDraft, TPath>,\n) {\n const form = this.useForm();\n\n const names = this.useFormState((form) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n return field.names;\n });\n\n const append = useCallback((...newEntries: Value<TDraft, `${TPath}.${number}`>[]) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n field.append(...newEntries);\n }, []);\n\n const remove = useCallback((index: number) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n field.remove(index);\n }, []);\n\n const setValue = useCallback(\n (value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>)) => {\n const field = form.getField(name) as Field<any, any, any> & ArrayFieldMethods<any, any>;\n field.setValue(value);\n },\n [],\n );\n\n return (\n <>\n {renderElement &&\n names.map((name, index) => (\n <Fragment key={index}>\n {renderElement({\n name,\n index,\n remove: () => remove(index),\n })}\n </Fragment>\n ))}\n\n {children?.({\n names,\n append,\n remove,\n setValue,\n })}\n </>\n );\n}\n","import { type Form } from './form';\nimport { type PathAsString } from '@lib/path';\n\nexport type FormErrorProps<TDraft, TPath extends PathAsString<TDraft>> = {\n name: TPath;\n};\n\nexport function FormError<TDraft, TPath extends PathAsString<TDraft>>(\n this: Form<TDraft, any>,\n { name }: FormErrorProps<TDraft, TPath>,\n) {\n const { errors, isDirty } = this.useField(name);\n\n return isDirty ? <>{errors.join(', ')}</> : null;\n}\n","import { type PathAsString } from '@index';\nimport { type Value } from '@lib/path';\nimport { useScope } from '@react/scope';\nimport {\n createElement,\n useEffect,\n useMemo,\n useState,\n type Component,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\nimport { type Form } from './form';\n\ninterface FormFieldComponentProps<TValue, TPath> {\n id: string;\n name: TPath;\n value: TValue;\n onChange: (event: { target: { value: TValue } } | TValue | undefined, ...args: any[]) => void;\n onFocus: (...args: any[]) => void;\n onBlur: (...args: any[]) => void;\n}\n\ntype NativeInputType = 'input' | 'select' | 'textarea';\n\ntype PartialComponentType<P> =\n | (new (props: P, context?: any) => Component<P, any>)\n | ((props: P, context?: any) => ReactNode);\n\nexport type FormFieldComponent<TValue, TPath> =\n | (string | number extends TValue ? NativeInputType : never)\n | PartialComponentType<FormFieldComponentProps<TValue, TPath>>;\n\ntype FieldValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<T>['value'];\n\ntype FieldChangeValue<T extends FormFieldComponent<any, any>> =\n ComponentPropsWithoutRef<T> extends {\n onChange?: (update: infer U) => void;\n }\n ? U extends { target: { value: infer V } }\n ? V\n : U\n : never;\n\nexport type FormFieldProps<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath>,\n> = {\n name: TPath;\n component: TComponent;\n commitOnBlur?: boolean;\n commitDebounce?: number;\n inputFilter?: (value: FieldChangeValue<TComponent>) => boolean;\n} & Omit<\n ComponentPropsWithoutRef<TComponent>,\n | 'name'\n | 'component'\n | 'commitOnBlur'\n | 'commitDebounce'\n | 'inputFilter'\n | keyof FormFieldComponentProps<any, any>\n> &\n Partial<Pick<ComponentPropsWithoutRef<TComponent>, keyof FormFieldComponentProps<any, any>>> &\n (Value<TDraft, TPath> extends FieldValue<TComponent>\n ? { serialize?: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }\n : { serialize: (value: Value<TDraft, TPath>) => FieldValue<TComponent> }) &\n (FieldChangeValue<TComponent> extends Value<TDraft, TPath>\n ? { deserialize?: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> }\n : { deserialize: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath> });\n\nexport function FormField<\n TDraft,\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, any>,\n>(\n this: Form<TDraft, any>,\n {\n // id,\n name,\n component,\n commitOnBlur,\n commitDebounce,\n inputFilter,\n serialize = (x) => x as FieldValue<TComponent>,\n deserialize = (x) => x as Value<TDraft, TPath>,\n ...restProps\n }: FormFieldProps<TDraft, TPath, TComponent>,\n): JSX.Element {\n type T = FieldChangeValue<TComponent>;\n const id = '';\n\n const form = this.useForm();\n const state = useScope(this.state);\n const { value, setValue, errors } = this.useField(name);\n\n const errorString = useMemo(\n () => errors.map((error) => form.options.localizeError?.(error, name) ?? error).join('\\n'),\n [errors, form.options.localizeError],\n );\n const [localValue, setLocalValue] = useState<T>();\n const _id = useMemo(\n () =>\n id || `f${Math.random().toString(36).slice(2, 15)}${Math.random().toString(36).slice(2, 15)}`,\n\n [id],\n );\n\n useEffect(() => {\n if (localValue === undefined || !commitDebounce) {\n return;\n }\n\n const timeout = setTimeout(() => {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }, commitDebounce);\n\n return () => clearTimeout(timeout);\n }, [localValue, commitDebounce]);\n\n useEffect(() => {\n const element = document.querySelector(\n [`#${_id} input`, `#${_id} select`, `#${_id} textarea`, `#${_id}`].join(','),\n );\n\n if (\n !(\n element instanceof HTMLInputElement ||\n element instanceof HTMLSelectElement ||\n element instanceof HTMLTextAreaElement\n )\n ) {\n return;\n }\n\n element.setCustomValidity(errorString);\n }, [_id, errorString]);\n\n const props = {\n ...restProps,\n id: _id,\n name,\n value: localValue ?? serialize(value as Value<TDraft, TPath>),\n onChange: (event: { target: { value: T } } | T, ...moreArgs: any[]) => {\n const value =\n typeof event === 'object' && event !== null && 'target' in event\n ? event.target.value\n : event;\n\n if (inputFilter && !inputFilter(value)) {\n return;\n }\n\n if (commitOnBlur || commitDebounce) {\n setLocalValue(value);\n } else {\n setValue(deserialize(value));\n }\n\n restProps.onChange?.(event, ...moreArgs);\n },\n onFocus(...args: any[]) {\n state.set('touched', (touched) => {\n touched = new Set(touched);\n touched.add(_id);\n return touched;\n });\n\n restProps.onFocus?.apply(null, args);\n },\n onBlur(...args: any[]) {\n if (localValue !== undefined) {\n setValue(deserialize(localValue));\n setLocalValue(undefined);\n }\n\n restProps.onBlur?.apply(null, args);\n },\n };\n\n return createElement(component, props);\n}\n","import { Scope, connectUrl, createStore, type Store, type UrlStoreOptions } from '@core';\nimport { autobind } from '@lib/autobind';\nimport { deepEqual } from '@lib/equals';\nimport { hash } from '@lib/hash';\nimport {\n type PathAsString,\n type Value,\n type WildcardPathAsString,\n type WildcardValue,\n} from '@lib/path';\nimport { get } from '@lib/propAccess';\nimport { getWildCardMatches, wildcardMatch } from '@lib/wildcardMatch';\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n type ComponentPropsWithoutRef,\n type HTMLProps,\n type ReactNode,\n} from 'react';\nimport { ScopeProvider, useScope } from '../scope';\nimport { useStore, type UseStoreOptions } from '../useStore';\nimport { FormArray, type ArrayPath, type FormArrayProps } from './formArray';\nimport { FormError, type FormErrorProps } from './formError';\nimport { FormField, type FormFieldComponent, type FormFieldProps } from './formField';\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Form types\n/// /////////////////////////////////////////////////////////////////////////////\n\nexport interface FormOptions<TDraft, TOriginal> {\n defaultValue: TDraft;\n validations?: Validations<TDraft, TOriginal>;\n localizeError?: (error: string, field: string) => string | undefined;\n urlState?: boolean | UrlStoreOptions<TDraft>;\n}\n\nexport type Validations<TDraft, TOriginal> = {\n [P in WildcardPathAsString<TDraft>]?: Record<\n string,\n Validation<WildcardValue<TDraft, P>, TDraft, TOriginal>\n >;\n} & Record<string, Record<string, Validation<any, TDraft, TOriginal>>>;\n\nexport type Validation<TValue, TDraft, TOriginal> = (\n value: TValue,\n context: { draft: TDraft; original: TOriginal; field: PathAsString<TDraft> },\n) => boolean;\n\nexport type Field<TDraft, TOriginal, TPath extends PathAsString<TDraft>> = {\n originalValue: Value<TOriginal, TPath> | undefined;\n value: Value<TDraft, TPath>;\n setValue: (\n value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>),\n ) => void;\n isDirty: boolean;\n errors: string[];\n} & (Value<TDraft, TPath> extends Array<any> ? ArrayFieldMethods<TDraft, TPath> : {});\n\nexport type ArrayFieldMethods<TPath, TValue> = {\n names: TPath[];\n append: (...elements: TValue[]) => void;\n remove: (index: number) => void;\n};\n\ninterface FormState<TDraft> {\n draft?: TDraft;\n touched: Set<string>;\n errors: Map<string, string[]>;\n hasTriggeredValidations?: boolean;\n}\n\n/// /////////////////////////////////////////////////////////////////////////////\n// Implementation\n/// /////////////////////////////////////////////////////////////////////////////\n\nfunction FormContainer({\n form,\n ...formProps\n}: { form: Form<any, any> } & Omit<HTMLProps<HTMLFormElement>, 'form'>) {\n const _form = form.useForm();\n const hasTriggeredValidations = form.useFormState((state) => state.hasTriggeredValidations);\n\n return (\n <form\n {...formProps}\n className={[formProps.className, hasTriggeredValidations ? 'validated' : undefined]\n .filter(Boolean)\n .join(' ')}\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n\n _form.validate();\n\n let button;\n\n if (\n event.nativeEvent instanceof SubmitEvent &&\n (button = event.nativeEvent.submitter) &&\n (button instanceof HTMLButtonElement || button instanceof HTMLInputElement) &&\n button.setCustomValidity\n ) {\n const errors = _form.errors.map(\n ({ field, error }) => _form.options.localizeError?.(error, field) ?? error,\n );\n button.setCustomValidity(errors.join('\\n'));\n }\n event.currentTarget.reportValidity();\n }}\n />\n );\n}\n\nfunction getFormInstance<TDraft, TOriginal extends TDraft>(\n original: TOriginal | undefined,\n options: FormOptions<TDraft, TOriginal>,\n state: Store<FormState<TDraft>>,\n) {\n const instance = {\n original,\n\n draft: state.map(\n (state) => state.draft ?? original ?? options.defaultValue,\n (draft) => (state) => ({ ...state, draft }),\n ),\n\n options,\n\n getField: <TPath extends PathAsString<TDraft>>(\n path: TPath,\n ): Field<TDraft, TOriginal, TPath> => {\n const { draft } = instance;\n\n return {\n get originalValue() {\n return original !== undefined ? get(original as any, path as any) : undefined;\n },\n\n get value() {\n return get(draft.get(), path);\n },\n\n setValue(update) {\n draft.set(path, update);\n },\n\n get isDirty() {\n const comparisonValue = this.originalValue ?? get(options.defaultValue, path);\n\n return state.get().hasTriggeredValidations || !deepEqual(comparisonValue, this.value);\n },\n\n get errors() {\n const blocks: (Validation<any, any, any> | Record<string, Validation<any, any, any>>)[] =\n Object.entries(options.validations ?? {})\n .filter(([key]) => wildcardMatch(path, key))\n .map(([, value]) => value);\n\n const value = this.value;\n const draftValue = draft.get();\n const errors: string[] = [];\n\n for (const block of blocks ?? []) {\n for (const [validationName, validate] of Object.entries(block)) {\n if (!validate(value, { draft: draftValue, original, field: path })) {\n errors.push(validationName);\n }\n }\n }\n\n return errors;\n },\n\n get names() {\n const { value } = this;\n return (Array.isArray(value) ? value.map((_, index) => `${path}.${index}`) : []) as any;\n },\n\n append(...elements: any[]) {\n this.setValue(\n (value) => (Array.isArray(value) ? [...value, ...elements] : elements) as any,\n );\n },\n\n remove(index) {\n this.setValue(\n (value) =>\n (Array.isArray(value)\n ? [...value.slice(0, index), ...value.slice(index + 1)]\n : value) as any,\n );\n },\n };\n },\n\n get hasChanges() {\n const { draft } = state.get();\n return !!draft && !deepEqual(draft, original ?? options.defaultValue);\n },\n\n get errors() {\n const draft = instance.draft.get();\n const errors = new Set<{ field: string; error: string }>();\n\n for (const [path, block] of Object.entries(options.validations ?? {})) {\n for (const [validationName, validate] of Object.entries(\n block as Record<string, Validation<any, any, any>>,\n )) {\n let matched = false;\n\n for (const [field, value] of Object.entries(getWildCardMatches(draft, path))) {\n matched = true;\n if (!validate(value, { draft, original, field })) {\n errors.add({ field, error: validationName });\n }\n }\n\n if (!matched && !path.includes('*')) {\n if (!validate(undefined, { draft, original, field: path })) {\n errors.add({ field: path, error: validationName });\n }\n }\n }\n }\n\n return [...errors];\n },\n\n get isValid() {\n return instance.errors.length === 0;\n },\n\n validate: () => {\n state.set('hasTriggeredValidations', true);\n return instance.isValid;\n },\n\n get hasTriggeredValidations() {\n return state.get().hasTriggeredValidations;\n },\n\n reset() {\n state.set('draft', undefined);\n state.set('hasTriggeredValidations', false);\n },\n };\n\n return instance;\n}\n\nexport class Form<TDraft, TOriginal extends TDraft = TDraft> {\n context = createContext({\n original: undefined as TOriginal | undefined,\n options: this.options,\n });\n\n state = new Scope<FormState<TDraft>>({\n touched: new Set(),\n errors: new Map(),\n });\n\n constructor(public readonly options: FormOptions<TDraft, TOriginal>) {\n autobind(Form);\n }\n\n useForm() {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useMemo(() => getFormInstance(original, options, state), [original, options, state]);\n }\n\n useFormState<S>(selector: (state: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S) {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useStore(state.map(() => selector(getFormInstance(original, options, state))));\n }\n\n useField<TPath extends PathAsString<TDraft>>(path: TPath, useStoreOptions?: UseStoreOptions) {\n const form = this.useForm();\n const state = useScope(this.state);\n\n useStore(\n form.draft.map((draft) => get(draft, path)),\n useStoreOptions,\n );\n\n useStore(\n state.map((state) => state.hasTriggeredValidations),\n useStoreOptions,\n );\n\n return form.getField(path);\n }\n\n useHasChanges() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.hasChanges));\n }\n\n useIsValid() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.isValid));\n }\n\n // ///////////////////////////////////////////////////////////////////////////\n // React Components\n // ///////////////////////////////////////////////////////////////////////////\n\n Form({\n original,\n defaultValue,\n validations,\n localizeError,\n urlState,\n ...formProps\n }: {\n original?: TOriginal;\n } & Partial<FormOptions<TDraft, TOriginal>> &\n Omit<HTMLProps<HTMLFormElement>, 'defaultValue'>) {\n const value = useMemo(\n () => ({\n original,\n options: {\n defaultValue: { ...this.options.defaultValue, ...defaultValue },\n validations: { ...this.options.validations, ...validations } as Validations<\n TDraft,\n TOriginal\n >,\n localizeError: localizeError ?? this.options.localizeError,\n },\n }),\n [original, defaultValue, validations],\n );\n\n const store = useMemo(() => {\n return createStore(this.state.defaultValue);\n }, []);\n\n useEffect(() => {\n if (urlState) {\n return connectUrl(\n store.map('draft'),\n typeof urlState === 'object' ? urlState : { key: 'form' },\n );\n }\n\n return undefined;\n }, [store, hash(urlState)]);\n\n return (\n <this.context.Provider value={value}>\n <ScopeProvider scope={this.state} store={store}>\n <FormContainer {...formProps} form={this} />\n </ScopeProvider>\n </this.context.Provider>\n );\n }\n\n Subscribe<S>({\n selector,\n children,\n }: {\n selector: (form: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S;\n children: (selectedState: S) => ReactNode;\n }) {\n const selectedState = this.useFormState(selector);\n return <>{children(selectedState)}</>;\n }\n\n Field<TPath extends PathAsString<TDraft>>(\n props: Omit<FormFieldProps<TDraft, TPath, 'input'>, 'component'>,\n ): JSX.Element;\n Field<\n TPath extends PathAsString<TDraft>,\n TComponent extends FormFieldComponent<any, TPath> = (\n props: ComponentPropsWithoutRef<'input'> & { name: TPath },\n ) => JSX.Element,\n >(props: FormFieldProps<TDraft, TPath, TComponent>): JSX.Element;\n Field(props: any): JSX.Element {\n return Reflect.apply(FormField, this, [{ component: 'input', ...props }]);\n }\n\n Array<TPath extends ArrayPath<TDraft>>(props: FormArrayProps<TDraft, TPath>) {\n return Reflect.apply(FormArray, this, [props]);\n }\n\n Error<TPath extends PathAsString<TDraft>>({ name }: FormErrorProps<TDraft, TPath>) {\n return Reflect.apply(FormError, this, [{ name }]);\n }\n}\n\nexport function createForm<TDraft, TOriginal extends TDraft = TDraft>(\n options: FormOptions<TDraft, TOriginal>,\n) {\n return new Form(options);\n}\n","import { useCache } from './useCache';\nimport type { UseStoreOptions } from './useStore';\nimport type { Cache } from '@core';\n\nexport function read<T>(cache: Cache<T>, options?: UseStoreOptions): T {\n const { status, value, error } = useCache(cache, options);\n\n if (status === 'value') {\n return value;\n }\n\n if (status === 'error') {\n throw error;\n }\n\n throw cache.state.once((state) => state.status !== 'pending');\n}\n","import { startTransition, useEffect, useMemo, useRef, useState } from 'react';\nimport { type Duration } from '@core';\nimport { debounce } from '@lib/debounce';\nimport { hash } from '@lib/hash';\nimport { throttle } from '@lib/throttle';\n\nexport interface UseDecoupledStateOptions<T> {\n debounce?: Duration;\n throttle?: Duration;\n onCommit?: (value: T) => void;\n}\n\nexport function useDecoupledState<T>(\n value: T,\n onChange: (value: T) => void,\n options: UseDecoupledStateOptions<T> = {},\n): [state: T, setState: (value: T) => void] {\n const [dirty, setDirty] = useState<{ v: T }>();\n const ref = useRef({ onChange, onCommit: options.onCommit });\n\n useEffect(() => {\n ref.current = { onChange, onCommit: options.onCommit };\n }, [onChange]);\n\n const update = useMemo(() => {\n const { onChange, onCommit } = ref.current;\n\n const update = (value: T) => {\n onChange(value);\n setDirty(undefined);\n onCommit?.(value);\n };\n\n let delayedUpdate: (value: T) => void;\n\n if (options.debounce) {\n delayedUpdate = debounce(update, options.debounce);\n } else if (options.throttle) {\n delayedUpdate = throttle(update, options.throttle);\n } else {\n delayedUpdate = (value) => startTransition(() => update(value));\n }\n\n return (value: T) => {\n setDirty({ v: value });\n delayedUpdate(value);\n };\n }, [hash([options.debounce, options.throttle])]);\n\n return [dirty ? dirty.v : value, update];\n}\n","export function castArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value];\n}\n","import { type ReactNode, useEffect } from 'react';\nimport { castArray } from '@lib/castArray';\nimport { hash } from '@lib/hash';\n\nexport function useUrlParamScope({\n key,\n type = 'search',\n}: {\n key: string | string[];\n type?: 'search' | 'hash';\n}) {\n useEffect(\n () => () => {\n const url = new URL(window.location.href);\n const parameters = new URLSearchParams(url[type].slice(1));\n\n for (const _key of castArray(key)) {\n parameters.delete(_key);\n }\n\n url[type] = parameters.toString();\n window.history.replaceState(null, '', url.toString());\n },\n [hash(key), type],\n );\n}\n"],"names":["s","form","name","Fragment","value","state","onChange","update"],"mappings":"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"}
|
package/dist/es/store.mjs
CHANGED
|
@@ -778,14 +778,14 @@ export {
|
|
|
778
778
|
calcDuration as b,
|
|
779
779
|
createStore as c,
|
|
780
780
|
castArrayPath as d,
|
|
781
|
-
|
|
782
|
-
|
|
781
|
+
shallowEqual as e,
|
|
782
|
+
arrayMethods as f,
|
|
783
783
|
get as g,
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
784
|
+
mapMethods as h,
|
|
785
|
+
recordMethods as i,
|
|
786
|
+
setMethods as j,
|
|
787
|
+
deepEqual as k,
|
|
788
|
+
debounce as l,
|
|
789
789
|
makeSelector as m,
|
|
790
790
|
queue as q,
|
|
791
791
|
remove as r,
|
package/dist/es/useCache.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import require$$0, { useRef, useMemo, useCallback, useLayoutEffect, useDebugValue, useContext, createContext, useEffect } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { k as deepEqual, m as makeSelector, c as createStore } from "./store.mjs";
|
|
4
4
|
import { h as hash } from "./scope.mjs";
|
|
5
5
|
var withSelector = { exports: {} };
|
|
6
6
|
var withSelector_production_min = {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Scope, type Store, type UrlStoreOptions } from '../../core';
|
|
2
2
|
import { type PathAsString, type Value, type WildcardPathAsString, type WildcardValue } from '../../lib/path';
|
|
3
|
-
import { type
|
|
3
|
+
import { type ComponentPropsWithoutRef, type HTMLProps, type ReactNode } from 'react';
|
|
4
4
|
import { type UseStoreOptions } from '../useStore';
|
|
5
|
+
import { type ArrayPath, type FormArrayProps } from './formArray';
|
|
5
6
|
import { type FormErrorProps } from './formError';
|
|
6
7
|
import { type FormFieldComponent, type FormFieldProps } from './formField';
|
|
7
8
|
export interface FormOptions<TDraft, TOriginal> {
|
|
@@ -18,13 +19,18 @@ export type Validation<TValue, TDraft, TOriginal> = (value: TValue, context: {
|
|
|
18
19
|
original: TOriginal;
|
|
19
20
|
field: PathAsString<TDraft>;
|
|
20
21
|
}) => boolean;
|
|
21
|
-
export
|
|
22
|
+
export type Field<TDraft, TOriginal, TPath extends PathAsString<TDraft>> = {
|
|
22
23
|
originalValue: Value<TOriginal, TPath> | undefined;
|
|
23
24
|
value: Value<TDraft, TPath>;
|
|
24
25
|
setValue: (value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>)) => void;
|
|
25
26
|
isDirty: boolean;
|
|
26
27
|
errors: string[];
|
|
27
|
-
}
|
|
28
|
+
} & (Value<TDraft, TPath> extends Array<any> ? ArrayFieldMethods<TDraft, TPath> : {});
|
|
29
|
+
export type ArrayFieldMethods<TPath, TValue> = {
|
|
30
|
+
names: TPath[];
|
|
31
|
+
append: (...elements: TValue[]) => void;
|
|
32
|
+
remove: (index: number) => void;
|
|
33
|
+
};
|
|
28
34
|
interface FormState<TDraft> {
|
|
29
35
|
draft?: TDraft;
|
|
30
36
|
touched: Set<string>;
|
|
@@ -43,6 +49,7 @@ declare function getFormInstance<TDraft, TOriginal extends TDraft>(original: TOr
|
|
|
43
49
|
}[];
|
|
44
50
|
readonly isValid: boolean;
|
|
45
51
|
validate: () => boolean;
|
|
52
|
+
readonly hasTriggeredValidations: boolean | undefined;
|
|
46
53
|
reset(): void;
|
|
47
54
|
};
|
|
48
55
|
export declare class Form<TDraft, TOriginal extends TDraft = TDraft> {
|
|
@@ -65,6 +72,7 @@ export declare class Form<TDraft, TOriginal extends TDraft = TDraft> {
|
|
|
65
72
|
}[];
|
|
66
73
|
readonly isValid: boolean;
|
|
67
74
|
validate: () => boolean;
|
|
75
|
+
readonly hasTriggeredValidations: boolean | undefined;
|
|
68
76
|
reset(): void;
|
|
69
77
|
};
|
|
70
78
|
useFormState<S>(selector: (state: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S): S;
|
|
@@ -78,9 +86,11 @@ export declare class Form<TDraft, TOriginal extends TDraft = TDraft> {
|
|
|
78
86
|
selector: (form: ReturnType<typeof getFormInstance<TDraft, TOriginal>>) => S;
|
|
79
87
|
children: (selectedState: S) => ReactNode;
|
|
80
88
|
}): import("react/jsx-runtime").JSX.Element;
|
|
89
|
+
Field<TPath extends PathAsString<TDraft>>(props: Omit<FormFieldProps<TDraft, TPath, 'input'>, 'component'>): JSX.Element;
|
|
81
90
|
Field<TPath extends PathAsString<TDraft>, TComponent extends FormFieldComponent<any, TPath> = (props: ComponentPropsWithoutRef<'input'> & {
|
|
82
91
|
name: TPath;
|
|
83
92
|
}) => JSX.Element>(props: FormFieldProps<TDraft, TPath, TComponent>): JSX.Element;
|
|
93
|
+
Array<TPath extends ArrayPath<TDraft>>(props: FormArrayProps<TDraft, TPath>): any;
|
|
84
94
|
Error<TPath extends PathAsString<TDraft>>({ name }: FormErrorProps<TDraft, TPath>): any;
|
|
85
95
|
}
|
|
86
96
|
export declare function createForm<TDraft, TOriginal extends TDraft = TDraft>(options: FormOptions<TDraft, TOriginal>): Form<TDraft, TOriginal>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type PathAsString, type Value } from '../../lib/path';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import { type Form } from './form';
|
|
4
|
+
export type ArrayPath<T> = keyof {
|
|
5
|
+
[P in PathAsString<T> as Value<T, P> extends readonly any[] | undefined ? P : never]: never;
|
|
6
|
+
} & PathAsString<T> & string;
|
|
7
|
+
export interface FormArrayProps<TDraft, TPath extends ArrayPath<TDraft>> {
|
|
8
|
+
name: TPath;
|
|
9
|
+
renderElement?: (props: {
|
|
10
|
+
name: `${TPath}.${number}`;
|
|
11
|
+
index: number;
|
|
12
|
+
remove: () => void;
|
|
13
|
+
}) => ReactNode;
|
|
14
|
+
children?: (props: {
|
|
15
|
+
names: `${TPath}.${number}`[];
|
|
16
|
+
append: (...elements: Value<TDraft, `${TPath}.${number}`>[]) => void;
|
|
17
|
+
remove: (index: number) => void;
|
|
18
|
+
setValue: (value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>)) => void;
|
|
19
|
+
}) => ReactNode;
|
|
20
|
+
}
|
|
21
|
+
export declare function FormArray<TDraft, TPath extends ArrayPath<TDraft>>(this: Form<TDraft, any>, { name, renderElement, children }: FormArrayProps<TDraft, TPath>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -17,12 +17,8 @@ interface FormFieldComponentProps<TValue, TPath> {
|
|
|
17
17
|
type NativeInputType = 'input' | 'select' | 'textarea';
|
|
18
18
|
type PartialComponentType<P> = (new (props: P, context?: any) => Component<P, any>) | ((props: P, context?: any) => ReactNode);
|
|
19
19
|
export type FormFieldComponent<TValue, TPath> = (string | number extends TValue ? NativeInputType : never) | PartialComponentType<FormFieldComponentProps<TValue, TPath>>;
|
|
20
|
-
type FieldValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<T
|
|
21
|
-
|
|
22
|
-
} ? U : ComponentPropsWithoutRef<T & 'input'> extends {
|
|
23
|
-
value?: infer U;
|
|
24
|
-
} ? U | undefined : never;
|
|
25
|
-
type FieldChangeValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<T & 'input'> extends {
|
|
20
|
+
type FieldValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<T>['value'];
|
|
21
|
+
type FieldChangeValue<T extends FormFieldComponent<any, any>> = ComponentPropsWithoutRef<T> extends {
|
|
26
22
|
onChange?: (update: infer U) => void;
|
|
27
23
|
} ? U extends {
|
|
28
24
|
target: {
|
|
@@ -31,22 +27,11 @@ type FieldChangeValue<T extends FormFieldComponent<any, any>> = ComponentPropsWi
|
|
|
31
27
|
} ? V : U : never;
|
|
32
28
|
export type FormFieldProps<TDraft, TPath extends PathAsString<TDraft>, TComponent extends FormFieldComponent<any, TPath>> = {
|
|
33
29
|
name: TPath;
|
|
30
|
+
component: TComponent;
|
|
34
31
|
commitOnBlur?: boolean;
|
|
35
32
|
commitDebounce?: number;
|
|
36
33
|
inputFilter?: (value: FieldChangeValue<TComponent>) => boolean;
|
|
37
|
-
|
|
38
|
-
onBlur?: ComponentPropsWithoutRef<TComponent>['onBlur'];
|
|
39
|
-
} & (TComponent extends 'input' | ((props: ComponentPropsWithoutRef<'input'> & {
|
|
40
|
-
name: TPath;
|
|
41
|
-
}) => JSX.Element) ? {
|
|
42
|
-
component?: TComponent;
|
|
43
|
-
} | {
|
|
44
|
-
children?: TComponent;
|
|
45
|
-
} : {
|
|
46
|
-
component: TComponent;
|
|
47
|
-
} | {
|
|
48
|
-
children: TComponent;
|
|
49
|
-
}) & Omit<ComponentPropsWithoutRef<TComponent>, 'form' | 'name' | 'component' | 'commitOnBlur' | 'commitDebounce' | 'value' | 'onChange' | 'onBlur' | 'children'> & (Value<TDraft, TPath> extends FieldValue<TComponent> ? {
|
|
34
|
+
} & Omit<ComponentPropsWithoutRef<TComponent>, 'name' | 'component' | 'commitOnBlur' | 'commitDebounce' | 'inputFilter' | keyof FormFieldComponentProps<any, any>> & Partial<Pick<ComponentPropsWithoutRef<TComponent>, keyof FormFieldComponentProps<any, any>>> & (Value<TDraft, TPath> extends FieldValue<TComponent> ? {
|
|
50
35
|
serialize?: (value: Value<TDraft, TPath>) => FieldValue<TComponent>;
|
|
51
36
|
} : {
|
|
52
37
|
serialize: (value: Value<TDraft, TPath>) => FieldValue<TComponent>;
|
|
@@ -55,5 +40,5 @@ export type FormFieldProps<TDraft, TPath extends PathAsString<TDraft>, TComponen
|
|
|
55
40
|
} : {
|
|
56
41
|
deserialize: (value: FieldChangeValue<TComponent>) => Value<TDraft, TPath>;
|
|
57
42
|
});
|
|
58
|
-
export declare function FormField<TDraft, TPath extends PathAsString<TDraft>, TComponent extends FormFieldComponent<any, any>>(this: Form<TDraft, any>, { name, commitOnBlur, commitDebounce, inputFilter, serialize, deserialize, ...restProps }: FormFieldProps<TDraft, TPath, TComponent>): JSX.Element;
|
|
43
|
+
export declare function FormField<TDraft, TPath extends PathAsString<TDraft>, TComponent extends FormFieldComponent<any, any>>(this: Form<TDraft, any>, { name, component, commitOnBlur, commitDebounce, inputFilter, serialize, deserialize, ...restProps }: FormFieldProps<TDraft, TPath, TComponent>): JSX.Element;
|
|
59
44
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cross-state",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "(React) state library",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"repository": "schummar/cross-state",
|
|
@@ -74,16 +74,16 @@
|
|
|
74
74
|
},
|
|
75
75
|
"scripts": {
|
|
76
76
|
"start": "tsc --watch",
|
|
77
|
-
"build": "runp -
|
|
77
|
+
"build": "runp -i build:clean :p build:compile:*",
|
|
78
78
|
"build:clean": "rimraf dist",
|
|
79
79
|
"build:compile:js": "vite build",
|
|
80
80
|
"build:compile:types": "tsc && tsc-alias",
|
|
81
|
-
"lint": "runp lint:*",
|
|
81
|
+
"lint": "runp -i lint:*",
|
|
82
82
|
"lint:eslint": "lint",
|
|
83
83
|
"lint:tsc": "tsc --noEmit --emitDeclarationOnly false",
|
|
84
84
|
"lint:tsc:tests": "tsc --noEmit --emitDeclarationOnly false -p test/tsconfig.json",
|
|
85
85
|
"size": "size-limit",
|
|
86
|
-
"prepublishOnly": "runp lint test build :p size publint",
|
|
86
|
+
"prepublishOnly": "runp -i lint test build :p size publint",
|
|
87
87
|
"test": "pnpm test:watch run --coverage",
|
|
88
88
|
"test:watch": "node --expose-gc node_modules/vitest/vitest.mjs",
|
|
89
89
|
"test:ui": "node --expose-gc node_modules/vitest/vitest.mjs --ui",
|
|
@@ -106,25 +106,27 @@
|
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
"devDependencies": {
|
|
109
|
+
"@emotion/styled": "11.11.0",
|
|
110
|
+
"@mantine/core": "6.0.19",
|
|
111
|
+
"@mui/material": "5.14.5",
|
|
109
112
|
"@schummar/eslint-config": "github:schummar/eslint-config",
|
|
110
113
|
"@schummar/prettier-config": "github:schummar/prettier-config",
|
|
111
|
-
"@schummar/runp": "1.
|
|
114
|
+
"@schummar/runp": "1.13.2",
|
|
112
115
|
"@size-limit/preset-small-lib": "8.2.6",
|
|
113
116
|
"@testing-library/react": "14.0.0",
|
|
114
|
-
"@types/react": "18.2.
|
|
117
|
+
"@types/react": "18.2.20",
|
|
115
118
|
"@types/react-dom": "18.2.7",
|
|
116
119
|
"@types/seedrandom": "3.0.5",
|
|
117
120
|
"@types/use-sync-external-store": "0.0.3",
|
|
118
121
|
"@types/ws": "8.5.5",
|
|
119
122
|
"@vitejs/plugin-react": "4.0.4",
|
|
120
|
-
"@vitest/coverage-v8": "0.34.
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"happy-dom": "10.9.0",
|
|
123
|
+
"@vitest/coverage-v8": "0.34.2",
|
|
124
|
+
"esbuild": "0.19.2",
|
|
125
|
+
"eslint": "8.47.0",
|
|
126
|
+
"happy-dom": "10.10.4",
|
|
125
127
|
"immer": "10.0.2",
|
|
126
128
|
"jsdom": "22.1.0",
|
|
127
|
-
"prettier": "3.0.
|
|
129
|
+
"prettier": "3.0.2",
|
|
128
130
|
"publint": "0.2.0",
|
|
129
131
|
"react": "18.2.0",
|
|
130
132
|
"react-dom": "18.2.0",
|
|
@@ -137,7 +139,7 @@
|
|
|
137
139
|
"use-sync-external-store": "1.2.0",
|
|
138
140
|
"vite": "4.4.9",
|
|
139
141
|
"vite-tsconfig-paths": "4.2.0",
|
|
140
|
-
"vitest": "0.34.
|
|
142
|
+
"vitest": "0.34.2"
|
|
141
143
|
},
|
|
142
144
|
"volta": {
|
|
143
145
|
"node": "18.16.1",
|