Skip to content

Commit

Permalink
release 0.2: improve performance and bundle size
Browse files Browse the repository at this point in the history
  • Loading branch information
voliva committed Feb 16, 2021
1 parent d3a88c2 commit 2d8bde8
Show file tree
Hide file tree
Showing 27 changed files with 638 additions and 439 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Because this library is thought in reactivity in mind, it just makes the recompu
const form = useForm<ModelType>();
```

Entry point of this library. Takes no parameters, but the FormModel as a generic type when using typescript.
Entry point of this library. By default, it takes no parameters, but the FormModel as a generic type when using typescript. You can also pass in the initial value if needed.

Returns an object needed to use the rest of the utilities of this library. It can be shared with children components.

Expand Down
9 changes: 3 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.1.4",
"version": "0.2.0",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand Down Expand Up @@ -64,9 +64,6 @@
"typescript": "^4.0.3"
},
"dependencies": {
"@react-rxjs/core": "^0.6.0",
"@react-rxjs/utils": "^0.3.0",
"rxjs": "^6.6.3",
"rxjs-deep-subject": "^0.1.6"
"derive-state": "^0.1.0-alpha.7"
}
}
}
13 changes: 13 additions & 0 deletions src/commands/readField.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FormRef } from '../internal/formRef';
import { getMapValue, KeySelector } from '../internal/path';

export const readField = <T, V>(
formRef: FormRef<T>,
key: KeySelector<T, V>
): V | undefined => {
try {
return getMapValue(key, formRef.values).getValue();
} catch (ex) {
return undefined;
}
};
5 changes: 3 additions & 2 deletions src/commands/readForm.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event';
import React from 'react';
import { useForm } from '../hooks/useForm';
import { useInput } from '../hooks/useInput';
import { subfield } from '../internal/subfield';
import { readForm } from './readForm';

const Form = ({ onSubmit, initialValue, validator }: any) => {
Expand Down Expand Up @@ -64,9 +65,9 @@ describe('readForm', () => {
onSubmit={onSubmit}
initialValue={{
value: 'initial0',
nested: {
nested: subfield({
value: 'initial1',
},
}),
}}
/>
);
Expand Down
17 changes: 10 additions & 7 deletions src/commands/readForm.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { FormRef } from '../internal/formRef';
import { buildObject } from '../internal/path';

export const readForm = <T>(formRef: FormRef<T>): T => {
try {
return formRef.values$.getValue();
} catch (ex) {
return {} as T;
}
};
export const readForm = <T>(formRef: FormRef<T>): T =>
buildObject(
Object.fromEntries(
Array.from(formRef.values.entries()).map(([key, value]) => [
key,
value.hasValue() ? value.getValue() : undefined,
])
)
);
34 changes: 15 additions & 19 deletions src/commands/resetForm.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import { FormRef, getControlState } from '../internal/formRef';
import { getKeys, KeysSelector, navigateDeepSubject } from '../internal/path';
import { getKeys, KeysSelector } from '../internal/path';

export const resetForm = <T>(
formRef: FormRef<T>,
keysSelector?: KeysSelector<T>
): void => {
const { values$, initialValues$, registeredKeys } = formRef;
if (!keysSelector) {
values$.next(initialValues$.getValue());
registeredKeys.getValue().forEach(key => {
getControlState(formRef, key)
.getChild('touched')
.next(false);
});
return;
}
const { values, initialValues } = formRef;

const keys = getKeys(keysSelector);
const keys = keysSelector ? getKeys(keysSelector) : Array.from(values.keys());
keys.forEach(key => {
const value$ = navigateDeepSubject(key, values$);
const initialValue$ = navigateDeepSubject(key, initialValues$);
value$.next(initialValue$.getValue());

getControlState(formRef, key)
.getChild('touched')
.next(false);
if (!values.has(key) || !initialValues.has(key)) {
return;
}
values.get(key)!.setValue(initialValues.get(key)!.getValue());
const control = getControlState(formRef, key);
const controlValue = control.getValue();
if (controlValue.touched) {
control.setValue({
...controlValue,
touched: false,
});
}
});
};
3 changes: 1 addition & 2 deletions src/commands/setFieldError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ export const setFieldError = <TValues>(
) => {
try {
getControlState(formRef, keySelector)
.getChild('manualError')
.getValue()
.next(error);
.manualError.emit(error);
} catch (ex) {
console.warn("Can't set error: Field not registered", ex);
}
Expand Down
7 changes: 3 additions & 4 deletions src/commands/setFieldValue.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { useForm } from '../hooks/useForm';
import { useInput } from '../hooks/useInput';
import { useIsValid } from '../hooks/useIsValid';
import { readForm } from './readForm';
import { setFieldValue } from './setFieldValue';
import { setFieldValue, setFormValue } from './setFieldValue';

const Form = ({ onSubmit, initialValue, validator }: any) => {
const form = useForm({
Expand Down Expand Up @@ -34,7 +33,7 @@ const Form = ({ onSubmit, initialValue, validator }: any) => {
data-testid="setMultiple"
type="button"
onClick={() =>
setFieldValue(form, v => v, {
setFormValue(form, {
nested: {
value: 'multiple set 0',
},
Expand All @@ -46,7 +45,7 @@ const Form = ({ onSubmit, initialValue, validator }: any) => {
data-testid="setMultipleIgnore"
type="button"
onClick={() =>
setFieldValue(form, v => v, {
setFormValue(form, {
nested: {
value: 'ignoring some',
},
Expand Down
31 changes: 10 additions & 21 deletions src/commands/setFieldValue.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
import { FormRef } from '../internal/formRef';
import { KeySelector, navigateDeepSubject } from '../internal/path';
import { getKeyValues, getMapValue, KeySelector } from '../internal/path';

export const setFieldValue = <TValues, T>(
formRef: FormRef<TValues>,
keySelector: KeySelector<TValues, T>,
value: T
) => {
const value$ = navigateDeepSubject(keySelector, formRef.values$);

if (
value$ === formRef.values$ &&
typeof value === 'object' &&
value !== null
) {
const keys = value$.getKeys();
const autofill = {} as any;
keys.forEach(key => {
if (value$.getChild(key).hasValue())
autofill[key] = value$.getChild(key).getValue();
});
value$.next({
...autofill,
...value,
});
return;
}
getMapValue(keySelector, formRef.values).setValue(value);
};

value$.next(value);
export const setFormValue = <TValues, T>(
formRef: FormRef<TValues>,
value: T
) => {
Object.entries(getKeyValues(value)).forEach(([key, value]) => {
getMapValue(key, formRef.values).setValue(value);
});
};
13 changes: 11 additions & 2 deletions src/commands/setInitialValue.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { FormRef } from '../internal/formRef';
import { KeySelector, navigateDeepSubject } from '../internal/path';
import { getKeyValues, getMapValue, KeySelector } from '../internal/path';

export const setInitialValue = <TValues, T>(
formRef: FormRef<TValues>,
keySelector: KeySelector<TValues, T>,
value: T
) => navigateDeepSubject(keySelector, formRef.initialValues$).next(value);
) => getMapValue(keySelector, formRef.initialValues).setValue(value);

export const setFormInitialValue = <TValues, T>(
formRef: FormRef<TValues>,
value: T
) => {
Object.entries(getKeyValues(value)).forEach(([key, value]) => {
getMapValue(key, formRef.initialValues).setValue(value);
});
};
15 changes: 10 additions & 5 deletions src/commands/touchFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ export const touchFields = <TValues>(
const keys = keysSelector
? getKeys(keysSelector)
: formRef.registeredKeys.getValue();
keys.forEach((key: string) =>
getControlState(formRef, key)
.getChild('touched')
.next(touch)
);
keys.forEach((key: string) => {
const control$ = getControlState(formRef, key);
const controlValue = control$.getValue();
if (controlValue.touched !== touch) {
control$.setValue({
...controlValue,
touched: touch,
});
}
});
};
2 changes: 1 addition & 1 deletion src/hooks/useControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const useControl = <TValues, T>(
options: ControlOptions<TValues, T>
) => {
const { subscribe, ...control } = useControlSubscription(formRef, options);
const [state, setState] = useState<T>(options.initialValue);
const [state, setState] = useState<T>(control.getValue);

useEffect(() => subscribe(setState), []);

Expand Down
34 changes: 18 additions & 16 deletions src/hooks/useControlSubscription.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { useEffect } from 'react';
import { FormRef, getControlState, ControlOptions } from '../internal/formRef';
import { getKey, navigateDeepSubject } from '../internal/path';
import { getKey, getMapValue } from '../internal/path';

export const useControlSubscription = <TValues, T>(
formRef: FormRef<TValues>,
options: ControlOptions<TValues, T>
) => {
const key = getKey(options.key);
useEffect(() => {
formRef.registerControl(options);
}, [formRef, options]);
formRef.registerControl(options);

return {
setValue: (value: T) =>
navigateDeepSubject(key, formRef.values$).next(value),
subscribe: (cb: (value: T) => void) => {
const sub = navigateDeepSubject(key, formRef.values$).subscribe(cb);
return () => {
sub.unsubscribe();
};
getValue: () => getMapValue(key, formRef.values).getValue(),
setValue: (value: T) => getMapValue(key, formRef.values).setValue(value),
subscribe: (cb: (value: T) => void) =>
getMapValue(key, formRef.values).subscribe(cb),
touch: () => {
const state$ = getControlState(formRef, key);
state$.value.then(
value => {
if (value.touched) return;
state$.setValue({
...value,
touched: true,
});
},
() => {}
);
},
touch: () =>
getControlState(formRef, key)
.getChild('touched')
.next(true),
};
};
Loading

0 comments on commit 2d8bde8

Please sign in to comment.