@stack-spot/portal-components 2.21.2 → 2.22.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/CHANGELOG.md +7 -0
- package/dist/components/Stepper/Stepper.d.ts +4 -0
- package/dist/components/Stepper/Stepper.d.ts.map +1 -1
- package/dist/components/Stepper/Stepper.js +2 -0
- package/dist/components/Stepper/Stepper.js.map +1 -1
- package/dist/components/form/Form/Form.d.ts +15 -0
- package/dist/components/form/Form/Form.d.ts.map +1 -0
- package/dist/components/form/Form/Form.js +48 -0
- package/dist/components/form/Form/Form.js.map +1 -0
- package/dist/components/form/Form/FormGroup.d.ts +37 -0
- package/dist/components/form/Form/FormGroup.d.ts.map +1 -0
- package/dist/components/form/Form/FormGroup.js +72 -0
- package/dist/components/form/Form/FormGroup.js.map +1 -0
- package/dist/components/form/Form/index.d.ts +3 -0
- package/dist/components/form/Form/index.d.ts.map +1 -0
- package/dist/components/form/Form/index.js +3 -0
- package/dist/components/form/Form/index.js.map +1 -0
- package/package.json +4 -2
- package/src/components/Stepper/Stepper.tsx +6 -0
- package/src/components/form/Form/Form.tsx +101 -0
- package/src/components/form/Form/FormGroup.tsx +221 -0
- package/src/components/form/Form/index.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.22.0](https://github.com/stack-spot/portal-commons/compare/portal-components@v2.21.2...portal-components@v2.22.0) (2025-04-25)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add component form ([fbc608d](https://github.com/stack-spot/portal-commons/commit/fbc608d0b2aaa8f99fc154a6a79141984c93daf3))
|
|
9
|
+
|
|
3
10
|
## [2.21.2](https://github.com/stack-spot/portal-commons/compare/portal-components@v2.21.1...portal-components@v2.21.2) (2025-04-24)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -26,6 +26,10 @@ export interface StepperContextProps {
|
|
|
26
26
|
* Navigate to the previous step.
|
|
27
27
|
*/
|
|
28
28
|
goToPreviousStep: () => void;
|
|
29
|
+
/**
|
|
30
|
+
* Navigate to the provided step.
|
|
31
|
+
*/
|
|
32
|
+
goToStep: (step: number) => void;
|
|
29
33
|
}
|
|
30
34
|
declare const StepperContext: import("react").Context<StepperContextProps>;
|
|
31
35
|
export interface StepperProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../../src/components/Stepper/Stepper.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,YAAY,EAA2B,MAAM,OAAO,CAAA;AAGjE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B;;OAEG;IACH,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/C;;OAEG;IACH,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,GAAG,IAAI,GAAG,SAAS,CAAC;IACtD;;OAEG;IACH,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,gBAAgB,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../../src/components/Stepper/Stepper.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,YAAY,EAA2B,MAAM,OAAO,CAAA;AAGjE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B;;OAEG;IACH,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/C;;OAEG;IACH,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,GAAG,IAAI,GAAG,SAAS,CAAC;IACtD;;OAEG;IACH,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B;;OAEG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,QAAA,MAAM,cAAc,8CAQlB,CAAA;AAEF,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;CACrC;AAWD;;;;GAIG;AAEH,QAAA,MAAM,OAAO,EAAE,EAAE,CAAC,YAAY,CA2C7B,CAAA;AACD,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAA"}
|
|
@@ -10,6 +10,7 @@ const StepperContext = createContext({
|
|
|
10
10
|
getStepData: () => { },
|
|
11
11
|
goToNextStep: () => { },
|
|
12
12
|
goToPreviousStep: () => { },
|
|
13
|
+
goToStep: () => { },
|
|
13
14
|
});
|
|
14
15
|
const Wrapper = styled(Box) `
|
|
15
16
|
width: 100%;
|
|
@@ -48,6 +49,7 @@ const Stepper = ({ children }) => {
|
|
|
48
49
|
getStepData,
|
|
49
50
|
goToNextStep: setNextStep,
|
|
50
51
|
goToPreviousStep: setPreviousStep,
|
|
52
|
+
goToStep: setActiveIndex,
|
|
51
53
|
};
|
|
52
54
|
return (_jsx(StepperContext.Provider, { value: contextValue, children: _jsxs(Wrapper, { children: [_jsx(StepperHeaders, { headers }), _jsx(ContentWrapper, { children: children[activeIndex] })] }) }));
|
|
53
55
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.js","sourceRoot":"","sources":["../../../src/components/Stepper/Stepper.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAoB,aAAa,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"Stepper.js","sourceRoot":"","sources":["../../../src/components/Stepper/Stepper.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAoB,aAAa,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAmC1C,MAAM,cAAc,GAAG,aAAa,CAAsB;IACxD,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,EAAE;IACb,WAAW,EAAE,GAAG,EAAE,GAAE,CAAC;IACrB,WAAW,EAAE,GAAG,EAAE,GAAE,CAAC;IACrB,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC;IACtB,gBAAgB,EAAE,GAAG,EAAE,GAAE,CAAC;IAC1B,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;CACnB,CAAC,CAAA;AAMF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;;;CAG1B,CAAA;AAED,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;;CAElC,CAAA;AAED;;;;GAIG;AAEH,MAAM,OAAO,GAAqB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IACjD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAS,CAAC,CAAC,CAAA;IACzD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAsB,EAAE,CAAC,CAAA;IACnE,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAEvE,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,IAAS,EAAE,EAAE;QAC9C,YAAY,CAAC,EAAE,GAAG,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;IACrD,CAAC,CAAA;IAED,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IAErD,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,IAAI,WAAW,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;YACxC,cAAc,CAAC,WAAW,GAAG,CAAC,CAAC,CAAA;QACjC,CAAC;IACH,CAAC,CAAA;IAED,MAAM,eAAe,GAAG,GAAG,EAAE;QAC3B,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YACpB,cAAc,CAAC,WAAW,GAAG,CAAC,CAAC,CAAA;QACjC,CAAC;IACH,CAAC,CAAA;IAED,MAAM,YAAY,GAAwB;QACxC,WAAW;QACX,SAAS;QACT,WAAW;QACX,WAAW;QACX,YAAY,EAAE,WAAW;QACzB,gBAAgB,EAAE,eAAe;QACjC,QAAQ,EAAE,cAAc;KACzB,CAAA;IAED,OAAO,CACL,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YAC1C,MAAC,OAAO,eACN,KAAC,cAAc,IAAO,OAAO,GAAM,EACnC,KAAC,cAAc,cACZ,QAAQ,CAAC,WAAW,CAAC,GACP,IACT,GACc,CAC3B,CAAA;AACH,CAAC,CAAA;AACD,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { FieldValues, UseFormReturn } from 'react-hook-form';
|
|
3
|
+
export interface FormProps {
|
|
4
|
+
id?: string;
|
|
5
|
+
name: string;
|
|
6
|
+
defaultValues?: FieldValues;
|
|
7
|
+
autoComplete?: HTMLInputElement['autocomplete'];
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
onSubmit?: (params: FieldValues) => unknown;
|
|
10
|
+
form?: UseFormReturn<any, any>;
|
|
11
|
+
style?: React.CSSProperties;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const Form: (props: FormProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=Form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Form/Form.tsx"],"names":[],"mappings":"AACA,OAAO,EAAa,SAAS,EAAE,MAAM,OAAO,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAgB,aAAa,EAA2B,MAAM,iBAAiB,CAAA;AAEnG,MAAM,WAAW,SAAS;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,YAAY,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC;IAC5C,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA4ED,eAAO,MAAM,IAAI,GAAI,OAAO,SAAS,4CASpC,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { get } from 'lodash';
|
|
3
|
+
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
|
4
|
+
function handleGraphqlErrors(error, methods) {
|
|
5
|
+
const errors = get(error, 'cause.extensions.fields');
|
|
6
|
+
if (errors) {
|
|
7
|
+
Object.keys(errors).forEach((key) => {
|
|
8
|
+
if (Object.keys(methods.control._fields).includes(key)) {
|
|
9
|
+
methods.setError(key, { type: 'server', message: errors[`${key}`] });
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const handleFormSubmit = async (data, methods, onSubmit) => {
|
|
15
|
+
if (!onSubmit) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const result = methods.handleSubmit(onSubmit)(data);
|
|
19
|
+
const isPromise = result instanceof Promise;
|
|
20
|
+
if (!isPromise) {
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
return await result;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
const isGraphqlError = error.message === 'GraphqlError';
|
|
28
|
+
if (!isGraphqlError) {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
handleGraphqlErrors(error, methods);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const BasicForm = ({ onSubmit, id, name, children, methods, autoComplete, ...props }) => (_jsx("form", { id: id, autoComplete: autoComplete, name: name, onSubmit: (data) => handleFormSubmit(data, methods, onSubmit), noValidate: true, style: props.style, className: props.className, children: children }));
|
|
35
|
+
const FormWithProvider = (props) => {
|
|
36
|
+
const methods = useForm({ defaultValues: props.defaultValues });
|
|
37
|
+
const form = props.form || methods;
|
|
38
|
+
return (_jsx(FormProvider, { ...form, children: _jsx(BasicForm, { ...props, methods: form }) }));
|
|
39
|
+
};
|
|
40
|
+
export const Form = (props) => {
|
|
41
|
+
const useFormMethods = useFormContext();
|
|
42
|
+
const hasFormProvider = !!useFormMethods;
|
|
43
|
+
if (hasFormProvider) {
|
|
44
|
+
return _jsx(BasicForm, { ...props, methods: useFormMethods });
|
|
45
|
+
}
|
|
46
|
+
return _jsx(FormWithProvider, { ...props });
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=Form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Form.js","sourceRoot":"","sources":["../../../../src/components/form/Form/Form.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SxProperties } from '@citric/core/dist/sx.js';
|
|
2
|
+
import { Tooltip } from '@citric/ui';
|
|
3
|
+
import { ChangeEvent, ComponentProps, ComponentPropsWithoutRef, ElementType, ReactElement, ReactNode } from 'react';
|
|
4
|
+
import { RegisterOptions } from 'react-hook-form';
|
|
5
|
+
interface FormGroupProps<T extends ElementType> {
|
|
6
|
+
fieldAddonAfter?: ReactNode;
|
|
7
|
+
fieldAddonBefore?: ReactNode;
|
|
8
|
+
formHelper?: ReactNode;
|
|
9
|
+
name: string;
|
|
10
|
+
id?: string;
|
|
11
|
+
component?: T;
|
|
12
|
+
label?: string | ReactElement;
|
|
13
|
+
registerOptions?: RegisterOptions;
|
|
14
|
+
formItemSx?: SxProperties;
|
|
15
|
+
formGroupSx?: SxProperties;
|
|
16
|
+
componentSx?: SxProperties;
|
|
17
|
+
fieldAddonBeforeSx?: SxProperties;
|
|
18
|
+
fieldAddonAfterSx?: SxProperties;
|
|
19
|
+
$formName?: string;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
onChange?: (event: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLSelectElement>) => void;
|
|
22
|
+
tooltipProps?: Omit<ComponentProps<typeof Tooltip>, 'children'>;
|
|
23
|
+
readOnly?: boolean;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
standalone?: boolean;
|
|
26
|
+
delay?: number;
|
|
27
|
+
hideRequiredSymbol?: boolean;
|
|
28
|
+
shouldUnregister?: boolean;
|
|
29
|
+
}
|
|
30
|
+
type Props<T extends ElementType> = FormGroupProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof FormGroupProps<T>>;
|
|
31
|
+
export declare const FormGroup: <T extends ElementType>({ fieldAddonAfter, fieldAddonBefore, formHelper, id, name, component, label, registerOptions, formGroupSx, formItemSx, componentSx, disabled, readOnly, onChange, tooltipProps, required, colorScheme: propColorScheme, fieldAddonBeforeSx, fieldAddonAfterSx, standalone, delay, hideRequiredSymbol, shouldUnregister, ...props }: Props<T>) => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
export declare const FormItemError: ({ name, id }: {
|
|
33
|
+
name: string;
|
|
34
|
+
id: string;
|
|
35
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=FormGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Form/FormGroup.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD,OAAO,EAAgD,OAAO,EAAE,MAAM,YAAY,CAAA;AAGlF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,wBAAwB,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,OAAO,CAAA;AAC9H,OAAO,EAA0B,eAAe,EAA0E,MAAM,iBAAiB,CAAA;AA2BjJ,UAAU,cAAc,CAAC,CAAC,SAAS,WAAW;IAC5C,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,CAAC,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IAC9B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAClC,iBAAiB,CAAC,EAAE,YAAY,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,GAAG,WAAW,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IAC3F,YAAY,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,KAAK,KAAK,CAAC,CAAC,SAAS,WAAW,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,MAAM,cAAc,CAAC,CAAC,CAAC,CAAC,CAAA;AAElH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,EAAE,oUAyB9C,KAAK,CAAC,CAAC,CAAC,4CA8FV,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,cAAc;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,mDAoBvE,CAAA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Flex, IconBox, Input, Label } from '@citric/core';
|
|
3
|
+
import { InfoCircle, TimesCircle } from '@citric/icons';
|
|
4
|
+
import { FieldAddon, FieldGroup, FormHelper, FormItem, Tooltip } from '@citric/ui';
|
|
5
|
+
import { useTranslate } from '@stack-spot/portal-translate';
|
|
6
|
+
import { debounce, get } from 'lodash';
|
|
7
|
+
import { useEffect } from 'react';
|
|
8
|
+
import { useFormContext } from 'react-hook-form';
|
|
9
|
+
const registerFieldWithDebounceChangeValidation = (name, delay, trigger, register, options) => {
|
|
10
|
+
const useFormRegisterReturn = register(name, options);
|
|
11
|
+
const { onChange } = useFormRegisterReturn;
|
|
12
|
+
const debouncedValidate = debounce(() => {
|
|
13
|
+
trigger(name);
|
|
14
|
+
}, delay);
|
|
15
|
+
const debouncedChange = debounce((event) => {
|
|
16
|
+
onChange?.(event);
|
|
17
|
+
}, delay);
|
|
18
|
+
return {
|
|
19
|
+
...useFormRegisterReturn,
|
|
20
|
+
onChange: (e) => {
|
|
21
|
+
debouncedChange(e);
|
|
22
|
+
debouncedValidate();
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export const FormGroup = ({ fieldAddonAfter, fieldAddonBefore, formHelper, id, name, component, label, registerOptions = {}, formGroupSx = {}, formItemSx = {}, componentSx = {}, disabled, readOnly, onChange, tooltipProps, required, colorScheme: propColorScheme, fieldAddonBeforeSx, fieldAddonAfterSx, standalone, delay, hideRequiredSymbol, shouldUnregister = false, ...props }) => {
|
|
27
|
+
const t = useTranslate(dictionary);
|
|
28
|
+
const { register, getFieldState, trigger, unregister } = useFormContext();
|
|
29
|
+
const Component = component || Input;
|
|
30
|
+
const colorScheme = propColorScheme;
|
|
31
|
+
let formRegistry = {};
|
|
32
|
+
if (!standalone) {
|
|
33
|
+
const options = {
|
|
34
|
+
onChange,
|
|
35
|
+
required: { message: hideRequiredSymbol ? t.requiredTest : t.required, value: !!required }, validate: (value) => {
|
|
36
|
+
if (required && typeof value === 'string') {
|
|
37
|
+
return !!value?.trim();
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
...registerOptions,
|
|
41
|
+
};
|
|
42
|
+
formRegistry = delay ? registerFieldWithDebounceChangeValidation(name, delay, trigger, register, options) : register(name, options);
|
|
43
|
+
}
|
|
44
|
+
useEffect(() => () => {
|
|
45
|
+
shouldUnregister && unregister(name);
|
|
46
|
+
}, [name, unregister]);
|
|
47
|
+
return (_jsxs(FormItem, { sx: formItemSx, children: [label && (_jsxs(Flex, { children: [_jsxs(Label, { appearance: "body2", htmlFor: id || name, sx: { pointerEvents: disabled || readOnly ? 'none' : undefined }, children: [label, "\u00A0", required && !hideRequiredSymbol && '*'] }), tooltipProps?.text && (_jsx(Tooltip, { ...tooltipProps, children: _jsx(IconBox, { children: _jsx(InfoCircle, {}) }) }))] })), !fieldAddonBefore && !fieldAddonAfter ? (_jsx(Component, { id: id || name, disabled: disabled, readOnly: readOnly, ...props, colorScheme, ...formRegistry, required: required, sx: componentSx, "aria-errormessage": `err${(id || name)}`, "aria-invalid": getFieldState(name).invalid })) : (_jsxs(FieldGroup, { sx: formGroupSx, children: [fieldAddonBefore && (_jsx(FieldAddon, { sx: { borderColor: colorScheme ? colorScheme : 'light.600', ...fieldAddonBeforeSx }, children: fieldAddonBefore })), _jsx(Component, { disabled: disabled, readOnly: readOnly, id: id || name, ...props, colorScheme, ...formRegistry, required: required, sx: componentSx, "aria-errormessage": `err${(id || name)}`, "aria-invalid": getFieldState(name).invalid }), fieldAddonAfter && (_jsx(FieldAddon, { sx: { borderColor: colorScheme ? colorScheme : 'light.600', ...fieldAddonAfterSx }, children: fieldAddonAfter }))] })), _jsx(FormItemError, { name: name, id: id || name }), formHelper && (_jsx(Box, { mt: "2", children: _jsx(FormHelper, { children: formHelper }) }))] }));
|
|
48
|
+
};
|
|
49
|
+
export const FormItemError = ({ name, id }) => {
|
|
50
|
+
const t = useTranslate(dictionary);
|
|
51
|
+
const { formState } = useFormContext();
|
|
52
|
+
const formItemError = get(formState.errors, name);
|
|
53
|
+
if (formItemError) {
|
|
54
|
+
return (_jsxs(Flex, { alignItems: "center", flexWrap: "nowrap", children: [_jsx(IconBox, { size: "xs", appearance: "circle", colorIcon: "danger", colorBg: "danger.500", children: _jsx(TimesCircle, {}) }), _jsx(Box, { ml: "3", children: _jsx(FormHelper, { colorScheme: "danger", "aria-live": "assertive", id: `err${id}`, children: formItemError.message?.toString() || formItemError?.root?.message?.toString() || t.invalidGenericError }) })] }));
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
};
|
|
58
|
+
const dictionary = {
|
|
59
|
+
en: {
|
|
60
|
+
invalidGenericError: 'Invalid field',
|
|
61
|
+
required: 'Required field',
|
|
62
|
+
// text for tests of usability
|
|
63
|
+
requiredTest: 'Fill in the required field to continue.',
|
|
64
|
+
},
|
|
65
|
+
pt: {
|
|
66
|
+
invalidGenericError: 'Campo inválido',
|
|
67
|
+
required: 'Campo obrigatório',
|
|
68
|
+
// text for tests of usability
|
|
69
|
+
requiredTest: 'Preencha este campo obrigatório para continuar.',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=FormGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormGroup.js","sourceRoot":"","sources":["../../../../src/components/form/Form/FormGroup.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Form/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/form/Form/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/portal-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.22.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"./FileTreeView": "./dist/components/FileTreeView/index.js",
|
|
27
27
|
"./FadingOverflow": "./dist/components/FadingOverflow.js",
|
|
28
28
|
"./Table": "./dist/components/Table/index.js",
|
|
29
|
-
"./ContentValidateFilter": "./dist/components/ContentValidateFilter.js"
|
|
29
|
+
"./ContentValidateFilter": "./dist/components/ContentValidateFilter.js",
|
|
30
|
+
"./Form": "./dist/components/form/Form/index.js"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"build": "rimraf dist && tsc && tsc-esm-fix --target='dist'",
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
"dependencies": {
|
|
69
70
|
"date-fns": "^3.6.0",
|
|
70
71
|
"lodash": "^4.17.21",
|
|
72
|
+
"react-hook-form": "^7.55.0",
|
|
71
73
|
"react-infinite-scroll-component": "^6.1.0",
|
|
72
74
|
"react-markdown": "^9.0.1",
|
|
73
75
|
"react-select": "^5.10.0",
|
|
@@ -30,6 +30,10 @@ export interface StepperContextProps {
|
|
|
30
30
|
* Navigate to the previous step.
|
|
31
31
|
*/
|
|
32
32
|
goToPreviousStep: () => void,
|
|
33
|
+
/**
|
|
34
|
+
* Navigate to the provided step.
|
|
35
|
+
*/
|
|
36
|
+
goToStep: (step: number) => void,
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
const StepperContext = createContext<StepperContextProps>({
|
|
@@ -39,6 +43,7 @@ const StepperContext = createContext<StepperContextProps>({
|
|
|
39
43
|
getStepData: () => {},
|
|
40
44
|
goToNextStep: () => {},
|
|
41
45
|
goToPreviousStep: () => {},
|
|
46
|
+
goToStep: () => {},
|
|
42
47
|
})
|
|
43
48
|
|
|
44
49
|
export interface StepperProps {
|
|
@@ -90,6 +95,7 @@ const Stepper: FC<StepperProps> = ({ children }) => {
|
|
|
90
95
|
getStepData,
|
|
91
96
|
goToNextStep: setNextStep,
|
|
92
97
|
goToPreviousStep: setPreviousStep,
|
|
98
|
+
goToStep: setActiveIndex,
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
return (
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { get } from 'lodash'
|
|
2
|
+
import { FormEvent, ReactNode } from 'react'
|
|
3
|
+
import { FieldValues, FormProvider, UseFormReturn, useForm, useFormContext } from 'react-hook-form'
|
|
4
|
+
|
|
5
|
+
export interface FormProps {
|
|
6
|
+
id?: string,
|
|
7
|
+
name: string,
|
|
8
|
+
defaultValues?: FieldValues,
|
|
9
|
+
autoComplete?: HTMLInputElement['autocomplete'],
|
|
10
|
+
children?: ReactNode,
|
|
11
|
+
onSubmit?: (params: FieldValues) => unknown,
|
|
12
|
+
form?: UseFormReturn<any, any>,
|
|
13
|
+
style?: React.CSSProperties,
|
|
14
|
+
className?: string,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
function handleGraphqlErrors(error: unknown, methods: UseFormReturn<FieldValues>) {
|
|
19
|
+
const errors: any = get(error, 'cause.extensions.fields')
|
|
20
|
+
|
|
21
|
+
if (errors) {
|
|
22
|
+
Object.keys(errors).forEach((key) => {
|
|
23
|
+
if (Object.keys(methods.control._fields).includes(key)) {
|
|
24
|
+
methods.setError(key, { type: 'server', message: errors[`${key}`] })
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const handleFormSubmit = async (
|
|
31
|
+
data: FormEvent<HTMLFormElement>,
|
|
32
|
+
methods: UseFormReturn,
|
|
33
|
+
onSubmit?: (params: Record<string, any>) => Promise<unknown> | unknown,
|
|
34
|
+
) => {
|
|
35
|
+
|
|
36
|
+
if (!onSubmit) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const result = methods.handleSubmit(onSubmit)(data)
|
|
41
|
+
const isPromise = result instanceof Promise
|
|
42
|
+
|
|
43
|
+
if (!isPromise) {
|
|
44
|
+
return result
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
return await result
|
|
49
|
+
} catch (error: any) {
|
|
50
|
+
const isGraphqlError = error.message === 'GraphqlError'
|
|
51
|
+
if (!isGraphqlError) {
|
|
52
|
+
throw error
|
|
53
|
+
}
|
|
54
|
+
handleGraphqlErrors(error, methods)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const BasicForm = ({
|
|
59
|
+
onSubmit,
|
|
60
|
+
id,
|
|
61
|
+
name,
|
|
62
|
+
children,
|
|
63
|
+
methods,
|
|
64
|
+
autoComplete,
|
|
65
|
+
...props
|
|
66
|
+
}: FormProps & { methods: UseFormReturn<FieldValues> }) => (
|
|
67
|
+
<form
|
|
68
|
+
id={id}
|
|
69
|
+
autoComplete={autoComplete}
|
|
70
|
+
name={name}
|
|
71
|
+
onSubmit={(data: FormEvent<HTMLFormElement>) => handleFormSubmit(data, methods, onSubmit)}
|
|
72
|
+
noValidate
|
|
73
|
+
style={props.style}
|
|
74
|
+
className={props.className}
|
|
75
|
+
>
|
|
76
|
+
{children}
|
|
77
|
+
</form>
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
const FormWithProvider = (props: FormProps) => {
|
|
81
|
+
const methods = useForm({ defaultValues: props.defaultValues })
|
|
82
|
+
const form = props.form || methods
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<FormProvider {...form}>
|
|
86
|
+
<BasicForm {...props} methods={form} />
|
|
87
|
+
</FormProvider>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const Form = (props: FormProps) => {
|
|
92
|
+
const useFormMethods = useFormContext()
|
|
93
|
+
const hasFormProvider = !!useFormMethods
|
|
94
|
+
|
|
95
|
+
if (hasFormProvider) {
|
|
96
|
+
return <BasicForm {...props} methods={useFormMethods} />
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return <FormWithProvider {...props} />
|
|
100
|
+
}
|
|
101
|
+
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Box, Flex, IconBox, Input, Label } from '@citric/core'
|
|
2
|
+
import { SxProperties } from '@citric/core/dist/sx'
|
|
3
|
+
import { InfoCircle, TimesCircle } from '@citric/icons'
|
|
4
|
+
import { FieldAddon, FieldGroup, FormHelper, FormItem, Tooltip } from '@citric/ui'
|
|
5
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
6
|
+
import { debounce, get } from 'lodash'
|
|
7
|
+
import { ChangeEvent, ComponentProps, ComponentPropsWithoutRef, ElementType, ReactElement, ReactNode, useEffect } from 'react'
|
|
8
|
+
import { FieldPath, FieldValues, RegisterOptions, useFormContext, UseFormRegister, UseFormRegisterReturn, UseFormTrigger } from 'react-hook-form'
|
|
9
|
+
|
|
10
|
+
const registerFieldWithDebounceChangeValidation = <T extends FieldValues>(
|
|
11
|
+
name: FieldPath<T>,
|
|
12
|
+
delay: number,
|
|
13
|
+
trigger: UseFormTrigger<T>,
|
|
14
|
+
register: UseFormRegister<T>,
|
|
15
|
+
options?: RegisterOptions<T, FieldPath<T>>,
|
|
16
|
+
) => {
|
|
17
|
+
const useFormRegisterReturn: UseFormRegisterReturn = register(name, options)
|
|
18
|
+
const { onChange } = useFormRegisterReturn
|
|
19
|
+
const debouncedValidate = debounce(() => {
|
|
20
|
+
trigger(name)
|
|
21
|
+
}, delay)
|
|
22
|
+
|
|
23
|
+
const debouncedChange = debounce((event: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLSelectElement>) => {
|
|
24
|
+
onChange?.(event)
|
|
25
|
+
}, delay)
|
|
26
|
+
return {
|
|
27
|
+
...useFormRegisterReturn,
|
|
28
|
+
onChange: (e: any) => {
|
|
29
|
+
debouncedChange(e)
|
|
30
|
+
debouncedValidate()
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface FormGroupProps<T extends ElementType> {
|
|
36
|
+
fieldAddonAfter?: ReactNode,
|
|
37
|
+
fieldAddonBefore?: ReactNode,
|
|
38
|
+
formHelper?: ReactNode,
|
|
39
|
+
name: string,
|
|
40
|
+
id?: string,
|
|
41
|
+
component?: T,
|
|
42
|
+
label?: string | ReactElement,
|
|
43
|
+
registerOptions?: RegisterOptions,
|
|
44
|
+
formItemSx?: SxProperties,
|
|
45
|
+
formGroupSx?: SxProperties,
|
|
46
|
+
componentSx?: SxProperties,
|
|
47
|
+
fieldAddonBeforeSx?: SxProperties,
|
|
48
|
+
fieldAddonAfterSx?: SxProperties,
|
|
49
|
+
$formName?: string,
|
|
50
|
+
required?: boolean,
|
|
51
|
+
onChange?: (event: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLSelectElement>) => void,
|
|
52
|
+
tooltipProps?: Omit<ComponentProps<typeof Tooltip>, 'children'>,
|
|
53
|
+
readOnly?: boolean,
|
|
54
|
+
disabled?: boolean,
|
|
55
|
+
// When true, input will not be registered on form
|
|
56
|
+
standalone?: boolean,
|
|
57
|
+
delay?: number,
|
|
58
|
+
// prop for tests of usability
|
|
59
|
+
hideRequiredSymbol?: boolean,
|
|
60
|
+
shouldUnregister?: boolean,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type Props<T extends ElementType> = FormGroupProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof FormGroupProps<T>>
|
|
64
|
+
|
|
65
|
+
export const FormGroup = <T extends ElementType>({
|
|
66
|
+
fieldAddonAfter,
|
|
67
|
+
fieldAddonBefore,
|
|
68
|
+
formHelper,
|
|
69
|
+
id,
|
|
70
|
+
name,
|
|
71
|
+
component,
|
|
72
|
+
label,
|
|
73
|
+
registerOptions = {},
|
|
74
|
+
formGroupSx = {},
|
|
75
|
+
formItemSx = {},
|
|
76
|
+
componentSx = {},
|
|
77
|
+
disabled,
|
|
78
|
+
readOnly,
|
|
79
|
+
onChange,
|
|
80
|
+
tooltipProps,
|
|
81
|
+
required,
|
|
82
|
+
colorScheme: propColorScheme,
|
|
83
|
+
fieldAddonBeforeSx,
|
|
84
|
+
fieldAddonAfterSx,
|
|
85
|
+
standalone,
|
|
86
|
+
delay,
|
|
87
|
+
hideRequiredSymbol,
|
|
88
|
+
shouldUnregister = false,
|
|
89
|
+
...props
|
|
90
|
+
}: Props<T>) => {
|
|
91
|
+
const t = useTranslate(dictionary)
|
|
92
|
+
const { register, getFieldState, trigger, unregister } = useFormContext()
|
|
93
|
+
const Component = component || Input
|
|
94
|
+
const colorScheme = propColorScheme
|
|
95
|
+
|
|
96
|
+
let formRegistry = {}
|
|
97
|
+
|
|
98
|
+
if (!standalone) {
|
|
99
|
+
const options = {
|
|
100
|
+
onChange,
|
|
101
|
+
required: { message: hideRequiredSymbol ? t.requiredTest : t.required, value: !!required }, validate: (value: string) => {
|
|
102
|
+
if (required && typeof value === 'string') {
|
|
103
|
+
return !!value?.trim()
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
...registerOptions,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
formRegistry = delay ? registerFieldWithDebounceChangeValidation(name, delay, trigger, register, options) : register(name, options)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
useEffect(() => () => {
|
|
113
|
+
shouldUnregister && unregister(name)
|
|
114
|
+
}, [name, unregister])
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<FormItem sx={formItemSx}>
|
|
118
|
+
{label && (
|
|
119
|
+
<Flex>
|
|
120
|
+
<Label appearance="body2" htmlFor={id || name} sx={{ pointerEvents: disabled || readOnly ? 'none' : undefined }}>
|
|
121
|
+
{label}
|
|
122
|
+
|
|
123
|
+
{required && !hideRequiredSymbol && '*'}
|
|
124
|
+
</Label>
|
|
125
|
+
{tooltipProps?.text && (
|
|
126
|
+
<Tooltip {...(tooltipProps as typeof tooltipProps & { text: string })}>
|
|
127
|
+
<IconBox>
|
|
128
|
+
<InfoCircle />
|
|
129
|
+
</IconBox>
|
|
130
|
+
</Tooltip>
|
|
131
|
+
)}
|
|
132
|
+
</Flex>
|
|
133
|
+
)}
|
|
134
|
+
|
|
135
|
+
{!fieldAddonBefore && !fieldAddonAfter ? (
|
|
136
|
+
<Component
|
|
137
|
+
id={id || name}
|
|
138
|
+
disabled={disabled}
|
|
139
|
+
readOnly={readOnly}
|
|
140
|
+
{...props}
|
|
141
|
+
{...{ colorScheme }}
|
|
142
|
+
{...formRegistry}
|
|
143
|
+
required={required}
|
|
144
|
+
sx={componentSx}
|
|
145
|
+
aria-errormessage={`err${(id || name)}`}
|
|
146
|
+
aria-invalid={getFieldState(name).invalid}
|
|
147
|
+
/>
|
|
148
|
+
) : (
|
|
149
|
+
<FieldGroup sx={formGroupSx}>
|
|
150
|
+
{fieldAddonBefore && (
|
|
151
|
+
<FieldAddon sx={{ borderColor: colorScheme ? colorScheme : 'light.600', ...fieldAddonBeforeSx }}>
|
|
152
|
+
{fieldAddonBefore}
|
|
153
|
+
</FieldAddon>
|
|
154
|
+
)}
|
|
155
|
+
|
|
156
|
+
<Component
|
|
157
|
+
disabled={disabled}
|
|
158
|
+
readOnly={readOnly}
|
|
159
|
+
id={id || name}
|
|
160
|
+
{...props}
|
|
161
|
+
{...{ colorScheme }}
|
|
162
|
+
{...formRegistry}
|
|
163
|
+
required={required}
|
|
164
|
+
sx={componentSx}
|
|
165
|
+
aria-errormessage={`err${(id || name)}`}
|
|
166
|
+
aria-invalid={getFieldState(name).invalid}
|
|
167
|
+
/>
|
|
168
|
+
|
|
169
|
+
{fieldAddonAfter && (
|
|
170
|
+
<FieldAddon sx={{ borderColor: colorScheme ? colorScheme : 'light.600', ...fieldAddonAfterSx }}>
|
|
171
|
+
{fieldAddonAfter}
|
|
172
|
+
</FieldAddon>
|
|
173
|
+
)}
|
|
174
|
+
</FieldGroup>
|
|
175
|
+
)}
|
|
176
|
+
<FormItemError name={name} id={id || name} />
|
|
177
|
+
{formHelper && (
|
|
178
|
+
<Box mt="2">
|
|
179
|
+
<FormHelper>{formHelper}</FormHelper>
|
|
180
|
+
</Box>
|
|
181
|
+
)}
|
|
182
|
+
</FormItem>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export const FormItemError = ({ name, id }: { name: string, id: string }) => {
|
|
187
|
+
const t = useTranslate(dictionary)
|
|
188
|
+
const { formState } = useFormContext()
|
|
189
|
+
const formItemError = get(formState.errors, name)
|
|
190
|
+
|
|
191
|
+
if (formItemError) {
|
|
192
|
+
return (
|
|
193
|
+
<Flex alignItems="center" flexWrap="nowrap">
|
|
194
|
+
<IconBox size="xs" appearance="circle" colorIcon="danger" colorBg="danger.500">
|
|
195
|
+
<TimesCircle />
|
|
196
|
+
</IconBox>
|
|
197
|
+
<Box ml="3">
|
|
198
|
+
<FormHelper colorScheme="danger" aria-live="assertive" id={`err${id}`}>
|
|
199
|
+
{formItemError.message?.toString() || formItemError?.root?.message?.toString() || t.invalidGenericError}
|
|
200
|
+
</FormHelper>
|
|
201
|
+
</Box>
|
|
202
|
+
</Flex>
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
return null
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const dictionary = {
|
|
209
|
+
en: {
|
|
210
|
+
invalidGenericError: 'Invalid field',
|
|
211
|
+
required: 'Required field',
|
|
212
|
+
// text for tests of usability
|
|
213
|
+
requiredTest: 'Fill in the required field to continue.',
|
|
214
|
+
},
|
|
215
|
+
pt: {
|
|
216
|
+
invalidGenericError: 'Campo inválido',
|
|
217
|
+
required: 'Campo obrigatório',
|
|
218
|
+
// text for tests of usability
|
|
219
|
+
requiredTest: 'Preencha este campo obrigatório para continuar.',
|
|
220
|
+
},
|
|
221
|
+
} satisfies Dictionary
|