@strictly/react-form 0.0.4 → 0.0.6
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/.out/core/mobx/field_adapter_builder.d.ts +1 -1
- package/.out/core/mobx/field_adapter_builder.js +1 -2
- package/.out/core/mobx/hooks.d.ts +10 -0
- package/.out/core/mobx/hooks.js +47 -0
- package/.out/core/props.d.ts +2 -2
- package/.out/index.d.ts +1 -0
- package/.out/index.js +1 -0
- package/.out/mantine/create_fields_view.d.ts +7 -0
- package/.out/mantine/{create_sub_form.js → create_fields_view.js} +4 -5
- package/.out/mantine/create_form.d.ts +7 -0
- package/.out/mantine/create_form.js +13 -0
- package/.out/mantine/create_list.d.ts +5 -4
- package/.out/mantine/create_list.js +4 -2
- package/.out/mantine/hooks.d.ts +8 -5
- package/.out/mantine/hooks.js +17 -7
- package/.out/mantine/specs/checkbox_hooks.stories.d.ts +2 -2
- package/.out/mantine/specs/checkbox_hooks.stories.js +2 -2
- package/.out/mantine/specs/{sub_form_hooks.stories.d.ts → fields_view_hooks.stories.d.ts} +2 -2
- package/.out/mantine/specs/{sub_form_hooks.stories.js → fields_view_hooks.stories.js} +9 -8
- package/.out/mantine/specs/fields_view_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/fields_view_hooks.tests.js +12 -0
- package/.out/mantine/specs/form_hooks.stories.d.ts +12 -0
- package/.out/mantine/specs/form_hooks.stories.js +60 -0
- package/.out/mantine/specs/form_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/form_hooks.tests.js +12 -0
- package/.out/mantine/specs/list_hooks.stories.d.ts +2 -2
- package/.out/mantine/specs/list_hooks.stories.js +8 -8
- package/.out/mantine/specs/radio_group_hooks.stories.d.ts +2 -2
- package/.out/mantine/specs/radio_group_hooks.stories.js +2 -2
- package/.out/mantine/specs/select_hooks.stories.d.ts +2 -2
- package/.out/mantine/specs/select_hooks.stories.js +2 -2
- package/.out/mantine/specs/text_input_hooks.stories.d.ts +2 -2
- package/.out/mantine/specs/text_input_hooks.stories.js +2 -2
- package/.out/mantine/specs/value_input_hooks.stories.d.ts +2 -2
- package/.out/mantine/specs/value_input_hooks.stories.js +2 -2
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.turbo/turbo-build.log +7 -7
- package/.turbo/turbo-check-types.log +1 -1
- package/core/mobx/field_adapter_builder.ts +3 -4
- package/core/mobx/hooks.ts +94 -0
- package/core/props.ts +2 -2
- package/dist/index.cjs +175 -95
- package/dist/index.d.cts +48 -39
- package/dist/index.d.ts +48 -39
- package/dist/index.js +170 -86
- package/index.ts +1 -0
- package/mantine/{create_sub_form.tsx → create_fields_view.tsx} +27 -16
- package/mantine/create_form.tsx +43 -0
- package/mantine/create_list.tsx +10 -4
- package/mantine/hooks.tsx +51 -16
- package/mantine/specs/__snapshots__/fields_view_hooks.tests.tsx.snap +460 -0
- package/mantine/specs/__snapshots__/form_hooks.tests.tsx.snap +273 -0
- package/mantine/specs/__snapshots__/list_hooks.tests.tsx.snap +56 -8
- package/mantine/specs/checkbox_hooks.stories.tsx +4 -4
- package/mantine/specs/{sub_form_hooks.stories.tsx → fields_view_hooks.stories.tsx} +23 -11
- package/mantine/specs/fields_view_hooks.tests.tsx +15 -0
- package/mantine/specs/form_hooks.stories.tsx +107 -0
- package/mantine/specs/form_hooks.tests.tsx +15 -0
- package/mantine/specs/list_hooks.stories.tsx +20 -10
- package/mantine/specs/radio_group_hooks.stories.tsx +4 -4
- package/mantine/specs/select_hooks.stories.tsx +4 -4
- package/mantine/specs/text_input_hooks.stories.tsx +4 -4
- package/mantine/specs/value_input_hooks.stories.tsx +4 -4
- package/package.json +1 -1
- package/.out/field_converters/list_converter.d.ts +0 -2
- package/.out/field_converters/list_converter.js +0 -13
- package/.out/mantine/create_sub_form.d.ts +0 -6
- package/field_converters/list_converter.ts +0 -20
|
@@ -17,5 +17,5 @@ export declare function adapterFromTwoWayConverter<From, To, E, ValuePath extend
|
|
|
17
17
|
export declare function adapterFromPrototype<From, To, ValuePath extends string, Context>(converter: AnnotatedFieldConverter<From, To, ValuePath, Context>, prototype: From): FieldAdapterBuilder<From, To, never, ValuePath, Context>;
|
|
18
18
|
export declare function adapterFromPrototype<From, To, E, ValuePath extends string, Context>(converter: TwoWayFieldConverter<From, To, E, ValuePath, Context>, prototype: From): FieldAdapterBuilder<From, To, E, ValuePath, Context>;
|
|
19
19
|
export declare function identityAdapter<V, ValuePath extends string, Context>(prototype: V, required?: boolean): FieldAdapterBuilder<V, V, never, ValuePath, Context>;
|
|
20
|
-
export declare function listAdapter<E,
|
|
20
|
+
export declare function listAdapter<E, ValuePath extends string, Context>(): FieldAdapterBuilder<readonly E[], readonly E[], never, ValuePath, Context>;
|
|
21
21
|
export {};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { chainAnnotatedFieldConverter, chainUnreliableFieldConverter, } from 'field_converters/chain_field_converter';
|
|
2
2
|
import { annotatedIdentityConverter, unreliableIdentityConverter, } from 'field_converters/identity_converter';
|
|
3
|
-
import { listConverter } from 'field_converters/list_converter';
|
|
4
3
|
import { MaybeIdentityConverter } from 'field_converters/maybe_identity_converter';
|
|
5
4
|
import { prototypingFieldValueFactory } from 'field_value_factories/prototyping_field_value_factory';
|
|
6
5
|
class FieldAdapterBuilder {
|
|
@@ -48,5 +47,5 @@ export function identityAdapter(prototype, required) {
|
|
|
48
47
|
return new FieldAdapterBuilder(annotatedIdentityConverter(required), prototypingFieldValueFactory(prototype), unreliableIdentityConverter());
|
|
49
48
|
}
|
|
50
49
|
export function listAdapter() {
|
|
51
|
-
return new FieldAdapterBuilder(
|
|
50
|
+
return new FieldAdapterBuilder(annotatedIdentityConverter(false), prototypingFieldValueFactory([]), unreliableIdentityConverter());
|
|
52
51
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReadonlyTypeOfType, type ValueOfType } from '@strictly/define';
|
|
2
|
+
import { type FieldsViewProps } from 'core/props';
|
|
3
|
+
import { type FormPresenter } from './form_presenter';
|
|
4
|
+
import { type ValuePathsOfPresenter } from './types';
|
|
5
|
+
type ValueOfPresenter<P extends FormPresenter<any, any, any, any>> = P extends FormPresenter<infer T, any, any, any> ? ValueOfType<ReadonlyTypeOfType<T>> : never;
|
|
6
|
+
type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<P['createModel']>;
|
|
7
|
+
export declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(presenter: P, value: ValueOfPresenter<P>, onValidSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void): {
|
|
8
|
+
model: ModelOfPresenter<P>;
|
|
9
|
+
} & Omit<FieldsViewProps<ModelOfPresenter<P>['fields']>, 'fields'>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useCallback, useMemo, } from 'react';
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3
|
+
export function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
|
|
4
|
+
const model = useMemo(function () {
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
6
|
+
return presenter.createModel(value);
|
|
7
|
+
}, [
|
|
8
|
+
presenter,
|
|
9
|
+
value,
|
|
10
|
+
]);
|
|
11
|
+
const onFieldValueChange = useCallback(function (path, value) {
|
|
12
|
+
presenter.clearFieldError(model, path);
|
|
13
|
+
presenter.setFieldValue(model, path, value);
|
|
14
|
+
}, [
|
|
15
|
+
presenter,
|
|
16
|
+
model,
|
|
17
|
+
]);
|
|
18
|
+
const onFieldSubmit = useCallback(function (valuePath) {
|
|
19
|
+
if (presenter.validateField(model, valuePath)) {
|
|
20
|
+
onValidSubmit?.(model, valuePath);
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}, [
|
|
24
|
+
presenter,
|
|
25
|
+
model,
|
|
26
|
+
onValidSubmit,
|
|
27
|
+
]);
|
|
28
|
+
const onFieldBlur = useCallback(function (path) {
|
|
29
|
+
// work around potential loss of focus prior to state potentially invalidating change triggering
|
|
30
|
+
// (e.g. changing a discriminator)
|
|
31
|
+
// TODO debounce?
|
|
32
|
+
setTimeout(function () {
|
|
33
|
+
if (presenter.isValuePathActive(model, path)) {
|
|
34
|
+
presenter.validateField(model, path);
|
|
35
|
+
}
|
|
36
|
+
}, 100);
|
|
37
|
+
}, [
|
|
38
|
+
presenter,
|
|
39
|
+
model,
|
|
40
|
+
]);
|
|
41
|
+
return {
|
|
42
|
+
model,
|
|
43
|
+
onFieldValueChange,
|
|
44
|
+
onFieldSubmit,
|
|
45
|
+
onFieldBlur,
|
|
46
|
+
};
|
|
47
|
+
}
|
package/.out/core/props.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type Fields } from 'types/field';
|
|
2
|
-
export type
|
|
2
|
+
export type FieldsViewProps<F extends Fields> = {
|
|
3
3
|
fields: F;
|
|
4
4
|
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void;
|
|
5
5
|
onFieldFocus?(this: void, key: keyof F): void;
|
|
6
6
|
onFieldBlur?(this: void, key: keyof F): void;
|
|
7
7
|
onFieldSubmit?(this: void, key: keyof F): boolean | void;
|
|
8
8
|
};
|
|
9
|
-
export type
|
|
9
|
+
export type FormProps<O> = {
|
|
10
10
|
value: O;
|
|
11
11
|
onValueChange: (value: O) => void;
|
|
12
12
|
};
|
package/.out/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './core/mobx/field_adapters_of_values';
|
|
|
4
4
|
export * from './core/mobx/flattened_adapters_of_fields';
|
|
5
5
|
export * from './core/mobx/form_fields_of_field_adapters';
|
|
6
6
|
export * from './core/mobx/form_presenter';
|
|
7
|
+
export * from './core/mobx/hooks';
|
|
7
8
|
export * from './core/mobx/merge_field_adapters_with_two_way_converter';
|
|
8
9
|
export * from './core/mobx/merge_field_adapters_with_validators';
|
|
9
10
|
export * from './core/mobx/sub_form_field_adapters';
|
package/.out/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './core/mobx/field_adapters_of_values';
|
|
|
4
4
|
export * from './core/mobx/flattened_adapters_of_fields';
|
|
5
5
|
export * from './core/mobx/form_fields_of_field_adapters';
|
|
6
6
|
export * from './core/mobx/form_presenter';
|
|
7
|
+
export * from './core/mobx/hooks';
|
|
7
8
|
export * from './core/mobx/merge_field_adapters_with_two_way_converter';
|
|
8
9
|
export * from './core/mobx/merge_field_adapters_with_validators';
|
|
9
10
|
export * from './core/mobx/sub_form_field_adapters';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FieldsViewProps } from 'core/props';
|
|
2
|
+
import type { ComponentType } from 'react';
|
|
3
|
+
import type { AllFieldsOfFields } from 'types/all_fields_of_fields';
|
|
4
|
+
import type { Fields } from 'types/field';
|
|
5
|
+
import type { SubFormFields } from 'types/sub_form_fields';
|
|
6
|
+
import type { MantineFieldComponent } from './types';
|
|
7
|
+
export declare function createFieldsView<F extends Fields, K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>, observableProps: FieldsViewProps<F>): MantineFieldComponent<FieldsViewProps<P['fields']>, P>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
|
-
export function
|
|
3
|
+
export function createFieldsView(valuePath, FieldsView, observableProps) {
|
|
4
4
|
function toKey(subKey) {
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
6
6
|
return subKey.replace('$', valuePath);
|
|
@@ -22,7 +22,8 @@ export function createSubForm(valuePath, SubForm, observableProps) {
|
|
|
22
22
|
function onFieldSubmit(subKey) {
|
|
23
23
|
observableProps.onFieldSubmit?.(toKey(subKey));
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
26
|
+
return observer(function (props) {
|
|
26
27
|
// convert fields to sub-fields
|
|
27
28
|
const subFields = Object.entries(observableProps.fields).reduce((acc, [fieldKey, fieldValue,]) => {
|
|
28
29
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -31,9 +32,7 @@ export function createSubForm(valuePath, SubForm, observableProps) {
|
|
|
31
32
|
}
|
|
32
33
|
return acc;
|
|
33
34
|
}, {});
|
|
34
|
-
return (_jsx(
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
36
|
-
, {
|
|
35
|
+
return (_jsx(FieldsView, { ...props,
|
|
37
36
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
38
37
|
fields: subFields, onFieldBlur: onFieldBlur, onFieldFocus: onFieldFocus, onFieldSubmit: onFieldSubmit, onFieldValueChange: onFieldValueChange }));
|
|
39
38
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type FieldsViewProps, type FormProps } from 'core/props';
|
|
2
|
+
import { type ComponentType } from 'react';
|
|
3
|
+
import { type AllFieldsOfFields } from 'types/all_fields_of_fields';
|
|
4
|
+
import { type Fields } from 'types/field';
|
|
5
|
+
import { type ValueTypeOfField } from 'types/value_type_of_field';
|
|
6
|
+
import { type MantineFieldComponent } from './types';
|
|
7
|
+
export declare function createForm<F extends Fields, K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>, observableProps: FieldsViewProps<F>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { observer } from 'mobx-react';
|
|
3
|
+
import { useCallback, } from 'react';
|
|
4
|
+
export function createForm(valuePath, Form, observableProps) {
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
6
|
+
return observer((props) => {
|
|
7
|
+
const { value } = observableProps.fields[valuePath];
|
|
8
|
+
const onValueChange = useCallback((value) => {
|
|
9
|
+
observableProps.onFieldValueChange(valuePath, value);
|
|
10
|
+
}, []);
|
|
11
|
+
return (_jsx(Form, { ...props, onValueChange: onValueChange, value: value }));
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -4,12 +4,13 @@ import { type Fields } from 'types/field';
|
|
|
4
4
|
import { type ListFieldsOfFields } from 'types/list_fields_of_fields';
|
|
5
5
|
import { type ValueTypeOfField } from 'types/value_type_of_field';
|
|
6
6
|
import { type MantineFieldComponent, type MantineForm } from './types';
|
|
7
|
-
export type SuppliedListProps<Value = any> = {
|
|
7
|
+
export type SuppliedListProps<Value = any, ListPath extends string = string> = {
|
|
8
8
|
values: readonly Value[];
|
|
9
|
+
listPath: ListPath;
|
|
9
10
|
};
|
|
10
11
|
export declare function createList<F extends Fields, K extends keyof ListFieldsOfFields<F>, Props extends SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>> & {
|
|
11
|
-
children: (value: ElementOfArray<ValueTypeOfField<F[K]>>, index: number) => React.ReactNode;
|
|
12
|
+
children: (valuePath: `${K}.${number}`, value: ElementOfArray<ValueTypeOfField<F[K]>>, index: number) => React.ReactNode;
|
|
12
13
|
}>(this: MantineForm<F>, valuePath: K, List: ComponentType<Props>): MantineFieldComponent<SuppliedListProps<ElementOfArray<ValueTypeOfField<F[K]>>>, Props>;
|
|
13
|
-
export declare function DefaultList<Value>({ values, children, }: SuppliedListProps<Value> & {
|
|
14
|
-
children: (value: Value, index: number) => React.ReactNode;
|
|
14
|
+
export declare function DefaultList<Value, ListPath extends string>({ values, listPath, children, }: SuppliedListProps<Value, ListPath> & {
|
|
15
|
+
children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
|
|
15
16
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -5,12 +5,14 @@ export function createList(valuePath, List) {
|
|
|
5
5
|
const values = [...this.fields[valuePath].value];
|
|
6
6
|
return {
|
|
7
7
|
values,
|
|
8
|
+
listPath: valuePath,
|
|
8
9
|
};
|
|
9
10
|
};
|
|
10
11
|
return createUnsafePartialObserverComponent(List, propSource);
|
|
11
12
|
}
|
|
12
|
-
export function DefaultList({ values, children, }) {
|
|
13
|
+
export function DefaultList({ values, listPath, children, }) {
|
|
13
14
|
return (_jsx(_Fragment, { children: values.map(function (value, index) {
|
|
14
|
-
|
|
15
|
+
const valuePath = `${listPath}.${index}`;
|
|
16
|
+
return children(valuePath, value, index);
|
|
15
17
|
}) }));
|
|
16
18
|
}
|
package/.out/mantine/hooks.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CheckboxProps, type PillProps, type RadioGroupProps, type RadioProps, type SelectProps, type TextInputProps } from '@mantine/core';
|
|
2
|
-
import { type
|
|
2
|
+
import { type ElementOfArray } from '@strictly/base';
|
|
3
|
+
import { type FieldsViewProps, type FormProps } from 'core/props';
|
|
3
4
|
import { type ComponentProps, type ComponentType } from 'react';
|
|
4
5
|
import { type AllFieldsOfFields } from 'types/all_fields_of_fields';
|
|
5
6
|
import { type BooleanFieldsOfFields } from 'types/boolean_fields_of_fields';
|
|
@@ -20,7 +21,7 @@ import { type MantineFieldComponent, type MantineForm } from './types';
|
|
|
20
21
|
declare function SimpleSelect(props: SelectProps & {
|
|
21
22
|
onChange?: (value: string | null) => void;
|
|
22
23
|
}): import("react/jsx-runtime").JSX.Element;
|
|
23
|
-
export declare function
|
|
24
|
+
export declare function useMantineFormFields<F extends Fields>({ onFieldValueChange, onFieldBlur, onFieldFocus, onFieldSubmit, fields, }: FieldsViewProps<F>): MantineFormImpl<F>;
|
|
24
25
|
declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
|
|
25
26
|
private readonly textInputCache;
|
|
26
27
|
private readonly valueInputCache;
|
|
@@ -29,7 +30,8 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
|
|
|
29
30
|
private readonly radioCache;
|
|
30
31
|
private readonly pillCache;
|
|
31
32
|
private readonly listCache;
|
|
32
|
-
private readonly
|
|
33
|
+
private readonly fieldsViewCache;
|
|
34
|
+
private readonly formCache;
|
|
33
35
|
accessor fields: F;
|
|
34
36
|
onFieldValueChange: <K extends keyof F>(this: void, key: K, value: F[K]['value']) => void;
|
|
35
37
|
onFieldFocus: ((this: void, key: keyof F) => void) | undefined;
|
|
@@ -48,7 +50,8 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
|
|
|
48
50
|
radio<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioProps>(valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<P>): MantineFieldComponent<SuppliedRadioProps, P, ErrorOfField<F[K]>>;
|
|
49
51
|
pill<K extends keyof AllFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedPillProps, PillProps, ErrorOfField<F[K]>>;
|
|
50
52
|
pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P>;
|
|
51
|
-
list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList
|
|
52
|
-
|
|
53
|
+
list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>>;
|
|
54
|
+
fieldsView<K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>): MantineFieldComponent<FieldsViewProps<P['fields']>, P>;
|
|
55
|
+
form<K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P>;
|
|
53
56
|
}
|
|
54
57
|
export {};
|
package/.out/mantine/hooks.js
CHANGED
|
@@ -4,17 +4,18 @@ import { Cache, } from '@strictly/base';
|
|
|
4
4
|
import { observable, runInAction, } from 'mobx';
|
|
5
5
|
import { useEffect, useMemo, } from 'react';
|
|
6
6
|
import { createCheckbox, } from './create_checkbox';
|
|
7
|
+
import { createFieldsView } from './create_fields_view';
|
|
8
|
+
import { createForm } from './create_form';
|
|
7
9
|
import { createList, DefaultList, } from './create_list';
|
|
8
10
|
import { createPill, } from './create_pill';
|
|
9
11
|
import { createRadio, } from './create_radio';
|
|
10
12
|
import { createRadioGroup, } from './create_radio_group';
|
|
11
|
-
import { createSubForm } from './create_sub_form';
|
|
12
13
|
import { createTextInput, } from './create_text_input';
|
|
13
14
|
import { createValueInput, } from './create_value_input';
|
|
14
15
|
function SimpleSelect(props) {
|
|
15
16
|
return _jsx(Select, { ...props });
|
|
16
17
|
}
|
|
17
|
-
export function
|
|
18
|
+
export function useMantineFormFields({ onFieldValueChange, onFieldBlur, onFieldFocus, onFieldSubmit, fields, }) {
|
|
18
19
|
const form = useMemo(function () {
|
|
19
20
|
return new MantineFormImpl(fields);
|
|
20
21
|
},
|
|
@@ -63,7 +64,8 @@ class MantineFormImpl {
|
|
|
63
64
|
radioCache = new Cache(createRadio.bind(this));
|
|
64
65
|
pillCache = new Cache(createPill.bind(this));
|
|
65
66
|
listCache = new Cache(createList.bind(this));
|
|
66
|
-
|
|
67
|
+
fieldsViewCache = new Cache(createFieldsView.bind(this));
|
|
68
|
+
formCache = new Cache(createForm.bind(this));
|
|
67
69
|
@observable.ref
|
|
68
70
|
accessor fields;
|
|
69
71
|
onFieldValueChange;
|
|
@@ -129,11 +131,19 @@ class MantineFormImpl {
|
|
|
129
131
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
130
132
|
return this.listCache.retrieveOrCreate(valuePath, DefaultList);
|
|
131
133
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return this.
|
|
134
|
+
fieldsView(valuePath, FieldsView) {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
136
|
+
return this.fieldsViewCache.retrieveOrCreate(valuePath,
|
|
137
|
+
// strip props from component since we lose information in the cache
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
139
|
+
FieldsView, this);
|
|
140
|
+
}
|
|
141
|
+
form(valuePath, Form) {
|
|
142
|
+
// strip props from component since we lose information in the cache
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
144
|
+
return this.formCache.retrieveOrCreate(valuePath,
|
|
135
145
|
// strip props from component since we lose information in the cache
|
|
136
146
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
137
|
-
|
|
147
|
+
Form, this);
|
|
138
148
|
}
|
|
139
149
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type FieldsViewProps } from 'core/props';
|
|
3
3
|
import { type ErrorRenderer } from 'mantine/error_renderer';
|
|
4
4
|
import { type Field } from 'types/field';
|
|
5
|
-
declare function Component({ ErrorRenderer, ...props }:
|
|
5
|
+
declare function Component({ ErrorRenderer, ...props }: FieldsViewProps<{
|
|
6
6
|
$: Field<boolean, string>;
|
|
7
7
|
}> & {
|
|
8
8
|
ErrorRenderer?: ErrorRenderer;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { action } from '@storybook/addon-actions';
|
|
3
|
-
import {
|
|
3
|
+
import { useMantineFormFields } from 'mantine/hooks';
|
|
4
4
|
import { CHECKBOX_LABEL } from './checkbox_constants';
|
|
5
5
|
function Component({ ErrorRenderer, ...props }) {
|
|
6
|
-
const inputProps =
|
|
6
|
+
const inputProps = useMantineFormFields(props);
|
|
7
7
|
const CheckboxComponent = inputProps.checkbox('$');
|
|
8
8
|
return (_jsx(CheckboxComponent, { ErrorRenderer: ErrorRenderer, label: CHECKBOX_LABEL }));
|
|
9
9
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type FieldsViewProps } from 'core/props';
|
|
3
3
|
import { type Field } from 'types/field';
|
|
4
|
-
declare function Component(props:
|
|
4
|
+
declare function Component(props: FieldsViewProps<{
|
|
5
5
|
$: Field<string, string>;
|
|
6
6
|
'$.a': Field<string, string>;
|
|
7
7
|
}>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Stack, } from '@mantine/core';
|
|
2
|
+
import { Button, Stack, } from '@mantine/core';
|
|
3
3
|
import { action } from '@storybook/addon-actions';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { useMantineFormFields } from 'mantine/hooks';
|
|
5
|
+
const onClick = action('some button clicked');
|
|
6
|
+
function SubFieldsView(props) {
|
|
7
|
+
const form = useMantineFormFields(props);
|
|
7
8
|
const TextInput = form.textInput('$');
|
|
8
|
-
return _jsx(TextInput, { label: 'sub
|
|
9
|
+
return (_jsxs(Stack, { children: [_jsx(TextInput, { label: 'sub fields view' }), _jsx(Button, { onClick: props.onClick, children: "Bonus Button" })] }));
|
|
9
10
|
}
|
|
10
11
|
function Component(props) {
|
|
11
|
-
const form =
|
|
12
|
-
const
|
|
12
|
+
const form = useMantineFormFields(props);
|
|
13
|
+
const FieldsView = form.fieldsView('$.a', SubFieldsView);
|
|
13
14
|
const TextInput = form.textInput('$');
|
|
14
|
-
return (_jsxs(Stack, { children: [_jsx(TextInput, { label: '
|
|
15
|
+
return (_jsxs(Stack, { children: [_jsx(TextInput, { label: 'fields view' }), _jsx(FieldsView, { onClick: onClick })] }));
|
|
15
16
|
}
|
|
16
17
|
const meta = {
|
|
17
18
|
component: Component,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { composeStories } from '@storybook/react';
|
|
3
|
+
import { toArray } from '@strictly/base';
|
|
4
|
+
import { render, } from '@testing-library/react';
|
|
5
|
+
import * as stories from './fields_view_hooks.stories';
|
|
6
|
+
const composedStories = composeStories(stories);
|
|
7
|
+
describe('field view hooks', function () {
|
|
8
|
+
it.each(toArray(composedStories))('renders %s', function (_name, Story) {
|
|
9
|
+
const wrapper = render(_jsx(Story, {}));
|
|
10
|
+
expect(wrapper.container).toMatchSnapshot();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Meta, type StoryObj } from '@storybook/react';
|
|
2
|
+
import { type FieldsViewProps } from 'core/props';
|
|
3
|
+
import { type Field } from 'types/field';
|
|
4
|
+
declare function Component(props: FieldsViewProps<{
|
|
5
|
+
$: Field<string>;
|
|
6
|
+
'$.a': Field<number>;
|
|
7
|
+
}>): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare const meta: Meta<typeof Component>;
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof Component>;
|
|
11
|
+
export declare const Empty: Story;
|
|
12
|
+
export declare const Populated: Story;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, NumberInput, Stack, } from '@mantine/core';
|
|
3
|
+
import { action } from '@storybook/addon-actions';
|
|
4
|
+
import { useMantineFormFields } from 'mantine/hooks';
|
|
5
|
+
import { useCallback } from 'react';
|
|
6
|
+
const onCancel = action('canceled');
|
|
7
|
+
function SubForm({ value, onValueChange, onCancel, }) {
|
|
8
|
+
const onChange = useCallback((v) => {
|
|
9
|
+
onValueChange(Number.parseInt(`${v}`));
|
|
10
|
+
}, [onValueChange]);
|
|
11
|
+
return (_jsxs(Stack, { children: [_jsx(NumberInput, { allowDecimal: false, label: 'sub form', onChange: onChange, value: value }), _jsx(Button, { onClick: onCancel, children: "Cancel" })] }));
|
|
12
|
+
}
|
|
13
|
+
function Component(props) {
|
|
14
|
+
const form = useMantineFormFields(props);
|
|
15
|
+
const Form = form.form('$.a', SubForm);
|
|
16
|
+
const TextInput = form.textInput('$');
|
|
17
|
+
return (_jsxs(Stack, { children: [_jsx(TextInput, { label: 'fields view' }), _jsx(Form, { onCancel: onCancel })] }));
|
|
18
|
+
}
|
|
19
|
+
const meta = {
|
|
20
|
+
component: Component,
|
|
21
|
+
args: {
|
|
22
|
+
onFieldBlur: action('onFieldBlur'),
|
|
23
|
+
onFieldFocus: action('onFieldFocus'),
|
|
24
|
+
onFieldSubmit: action('onFieldSubmit'),
|
|
25
|
+
onFieldValueChange: action('onFieldValueChange'),
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
export default meta;
|
|
29
|
+
export const Empty = {
|
|
30
|
+
args: {
|
|
31
|
+
fields: {
|
|
32
|
+
$: {
|
|
33
|
+
readonly: false,
|
|
34
|
+
required: false,
|
|
35
|
+
value: '',
|
|
36
|
+
},
|
|
37
|
+
'$.a': {
|
|
38
|
+
readonly: false,
|
|
39
|
+
required: false,
|
|
40
|
+
value: 0,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
export const Populated = {
|
|
46
|
+
args: {
|
|
47
|
+
fields: {
|
|
48
|
+
$: {
|
|
49
|
+
readonly: false,
|
|
50
|
+
required: false,
|
|
51
|
+
value: 'Hello',
|
|
52
|
+
},
|
|
53
|
+
'$.a': {
|
|
54
|
+
readonly: false,
|
|
55
|
+
required: false,
|
|
56
|
+
value: 2,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { composeStories } from '@storybook/react';
|
|
3
|
+
import { toArray } from '@strictly/base';
|
|
4
|
+
import { render, } from '@testing-library/react';
|
|
5
|
+
import * as stories from './form_hooks.stories';
|
|
6
|
+
const composedStories = composeStories(stories);
|
|
7
|
+
describe('form hooks', function () {
|
|
8
|
+
it.each(toArray(composedStories))('renders %s', function (_name, Story) {
|
|
9
|
+
const wrapper = render(_jsx(Story, {}));
|
|
10
|
+
expect(wrapper.container).toMatchSnapshot();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type FieldsViewProps } from 'core/props';
|
|
3
3
|
import { type Field } from 'types/field';
|
|
4
|
-
declare function Component(props:
|
|
4
|
+
declare function Component(props: FieldsViewProps<{
|
|
5
5
|
$: Field<string[], string>;
|
|
6
6
|
}>): import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
declare const meta: Meta<typeof Component>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Code, Paper, Stack, } from '@mantine/core';
|
|
3
3
|
import { action } from '@storybook/addon-actions';
|
|
4
|
-
import {
|
|
4
|
+
import { useMantineFormFields } from 'mantine/hooks';
|
|
5
5
|
function Component(props) {
|
|
6
|
-
const form =
|
|
6
|
+
const form = useMantineFormFields(props);
|
|
7
7
|
const List = form.list('$');
|
|
8
|
-
return (_jsx(Paper, { p: 'sm', withBorder: true, children: _jsx(Stack, { children: _jsx(List, { children: function (valuePath) {
|
|
9
|
-
return (_jsxs(Code, { children: ["ValuePath: ", valuePath] }, valuePath));
|
|
8
|
+
return (_jsx(Paper, { p: 'sm', withBorder: true, children: _jsx(Stack, { children: _jsx(List, { children: function (valuePath, value, index) {
|
|
9
|
+
return (_jsxs(Code, { children: [_jsxs("span", { children: ["ValuePath: ", valuePath] }), _jsx("br", {}), _jsxs("span", { children: ["Value: ", value] }), _jsx("br", {}), _jsxs("span", { children: ["Index: ", index] })] }, valuePath));
|
|
10
10
|
} }) }) }));
|
|
11
11
|
}
|
|
12
12
|
const meta = {
|
|
@@ -37,10 +37,10 @@ export const Populated = {
|
|
|
37
37
|
readonly: false,
|
|
38
38
|
required: false,
|
|
39
39
|
value: [
|
|
40
|
-
'
|
|
41
|
-
'
|
|
42
|
-
'
|
|
43
|
-
'
|
|
40
|
+
'A',
|
|
41
|
+
'B',
|
|
42
|
+
'C',
|
|
43
|
+
'D',
|
|
44
44
|
],
|
|
45
45
|
},
|
|
46
46
|
},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type FieldsViewProps } from 'core/props';
|
|
3
3
|
import { type ErrorRenderer } from 'mantine/error_renderer';
|
|
4
4
|
import { type Field } from 'types/field';
|
|
5
5
|
import { type RadioValue } from './radio_group_constants';
|
|
6
|
-
declare function Component({ ErrorRenderer, ...props }:
|
|
6
|
+
declare function Component({ ErrorRenderer, ...props }: FieldsViewProps<{
|
|
7
7
|
$: Field<RadioValue | null, string>;
|
|
8
8
|
}> & {
|
|
9
9
|
ErrorRenderer?: ErrorRenderer;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Stack, } from '@mantine/core';
|
|
3
3
|
import { action } from '@storybook/addon-actions';
|
|
4
|
-
import {
|
|
4
|
+
import { useMantineFormFields } from 'mantine/hooks';
|
|
5
5
|
import { RADIO_GROUP_LABEL, RADIO_LABELS, RADIO_VALUES, } from './radio_group_constants';
|
|
6
6
|
function Component({ ErrorRenderer, ...props }) {
|
|
7
|
-
const form =
|
|
7
|
+
const form = useMantineFormFields(props);
|
|
8
8
|
const RadioGroupComponent = form.radioGroup('$');
|
|
9
9
|
return (_jsx(RadioGroupComponent, { ErrorRenderer: ErrorRenderer, label: RADIO_GROUP_LABEL, children: _jsx(Stack, { children: RADIO_VALUES.map(function (value) {
|
|
10
10
|
const label = RADIO_LABELS[value];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type FieldsViewProps } from 'core/props';
|
|
3
3
|
import { type ErrorRenderer } from 'mantine/error_renderer';
|
|
4
4
|
import { type Field } from 'types/field';
|
|
5
|
-
declare function Component({ ErrorRenderer, ...props }:
|
|
5
|
+
declare function Component({ ErrorRenderer, ...props }: FieldsViewProps<{
|
|
6
6
|
$: Field<string | null, string>;
|
|
7
7
|
}> & {
|
|
8
8
|
ErrorRenderer?: ErrorRenderer;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { action } from '@storybook/addon-actions';
|
|
3
|
-
import {
|
|
3
|
+
import { useMantineFormFields } from 'mantine/hooks';
|
|
4
4
|
import { SELECT_LABEL } from './select_hooks_constant';
|
|
5
5
|
function Component({ ErrorRenderer, ...props }) {
|
|
6
|
-
const form =
|
|
6
|
+
const form = useMantineFormFields(props);
|
|
7
7
|
const SelectComponent = form.select('$');
|
|
8
8
|
return (_jsx(SelectComponent, { ErrorRenderer: ErrorRenderer, data: [
|
|
9
9
|
'a',
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type TextInputProps } from '@mantine/core';
|
|
2
2
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
3
|
-
import { type
|
|
3
|
+
import { type FieldsViewProps } from 'core/props';
|
|
4
4
|
import { type SuppliedTextInputProps, type TextInputTarget } from 'mantine/create_text_input';
|
|
5
5
|
import { type ErrorRenderer } from 'mantine/error_renderer';
|
|
6
6
|
import { type ComponentType } from 'react';
|
|
7
7
|
import { type Field } from 'types/field';
|
|
8
8
|
type StoryTextInputProps<T extends TextInputTarget> = SuppliedTextInputProps<T> & Pick<TextInputProps, 'label'>;
|
|
9
|
-
declare function Component<T extends TextInputTarget>({ TextInput, ErrorRenderer, ...props }:
|
|
9
|
+
declare function Component<T extends TextInputTarget>({ TextInput, ErrorRenderer, ...props }: FieldsViewProps<{
|
|
10
10
|
$: Field<string, string>;
|
|
11
11
|
}> & {
|
|
12
12
|
TextInput?: ComponentType<StoryTextInputProps<T>>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { PillsInputField, Textarea, } from '@mantine/core';
|
|
3
3
|
import { action } from '@storybook/addon-actions';
|
|
4
|
-
import {
|
|
4
|
+
import { useMantineFormFields } from 'mantine/hooks';
|
|
5
5
|
import { TEXT_INPUT_LABEL } from './text_input_constants';
|
|
6
6
|
function Component({ TextInput, ErrorRenderer, ...props }) {
|
|
7
|
-
const form =
|
|
7
|
+
const form = useMantineFormFields(props);
|
|
8
8
|
const TextInputComponent = form.textInput('$', TextInput);
|
|
9
9
|
return (_jsx(TextInputComponent, { ErrorRenderer: ErrorRenderer, label: TEXT_INPUT_LABEL }));
|
|
10
10
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type JsonInputProps, type NumberInputProps, type RatingProps, type SliderProps } from '@mantine/core';
|
|
2
2
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
3
|
-
import { type
|
|
3
|
+
import { type FieldsViewProps } from 'core/props';
|
|
4
4
|
import { type SuppliedValueInputProps } from 'mantine/create_value_input';
|
|
5
5
|
import { type ErrorRenderer } from 'mantine/error_renderer';
|
|
6
6
|
import { type ComponentType } from 'react';
|
|
7
7
|
import { type Field } from 'types/field';
|
|
8
8
|
type StoryValueInputProps<V> = SuppliedValueInputProps<V, any>;
|
|
9
|
-
declare function Component<V, P extends StoryValueInputProps<V>>({ ValueInput, ErrorRenderer, inputProps, ...props }:
|
|
9
|
+
declare function Component<V, P extends StoryValueInputProps<V>>({ ValueInput, ErrorRenderer, inputProps, ...props }: FieldsViewProps<{
|
|
10
10
|
$: Field<V, string>;
|
|
11
11
|
}> & {
|
|
12
12
|
ValueInput: ComponentType<P>;
|