@sqrzro/ui 4.0.0-alpha.0 → 4.0.0-alpha.2
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/components/buttons/ActionButton/index.d.ts +7 -0
- package/dist/components/buttons/ActionButton/index.js +33 -0
- package/dist/components/buttons/Button/index.d.ts +65 -0
- package/dist/components/buttons/Button/index.js +50 -0
- package/dist/components/buttons/ConfirmableButton/index.d.ts +7 -0
- package/dist/components/buttons/ConfirmableButton/index.js +13 -0
- package/dist/components/buttons/TextButton/index.d.ts +5 -0
- package/dist/components/buttons/TextButton/index.js +6 -0
- package/dist/components/collections/Collection/index.d.ts +15 -0
- package/dist/components/collections/Collection/index.js +45 -0
- package/dist/components/collections/EmptyMessage/index.d.ts +26 -0
- package/dist/components/collections/EmptyMessage/index.js +17 -0
- package/dist/components/collections/EmptyMessageAction/index.d.ts +6 -0
- package/dist/components/collections/EmptyMessageAction/index.js +19 -0
- package/dist/components/collections/List/index.d.ts +6 -0
- package/dist/components/collections/List/index.js +13 -0
- package/dist/components/collections/ListClientComponent/index.d.ts +7 -0
- package/dist/components/collections/ListClientComponent/index.js +9 -0
- package/dist/components/collections/ListItem/index.d.ts +14 -0
- package/dist/components/collections/ListItem/index.js +28 -0
- package/dist/components/collections/ListItemMeta/index.d.ts +11 -0
- package/dist/components/collections/ListItemMeta/index.js +22 -0
- package/dist/components/collections/ListItemSecondary/index.d.ts +6 -0
- package/dist/components/collections/ListItemSecondary/index.js +16 -0
- package/dist/components/collections/Pagination/index.d.ts +19 -0
- package/dist/components/collections/Pagination/index.js +17 -0
- package/dist/components/collections/Table/index.d.ts +9 -0
- package/dist/components/collections/Table/index.js +13 -0
- package/dist/components/collections/TableClientComponent/index.d.ts +14 -0
- package/dist/components/collections/TableClientComponent/index.js +30 -0
- package/dist/components/collections/interfaces.d.ts +57 -0
- package/dist/components/collections/interfaces.js +1 -0
- package/dist/components/collections/lang.d.ts +4 -0
- package/dist/components/collections/lang.js +4 -0
- package/dist/components/collections/utility/filter-columns.d.ts +3 -0
- package/dist/components/collections/utility/filter-columns.js +8 -0
- package/dist/components/collections/utility/get-selected-from-search-params.d.ts +2 -0
- package/dist/components/collections/utility/get-selected-from-search-params.js +5 -0
- package/dist/components/collections/utility/is-paginated.d.ts +3 -0
- package/dist/components/collections/utility/is-paginated.js +4 -0
- package/dist/components/collections/utility/set-selected-to-search-params.d.ts +2 -0
- package/dist/components/collections/utility/set-selected-to-search-params.js +4 -0
- package/dist/components/index.d.ts +16 -0
- package/dist/components/index.js +9 -0
- package/dist/components/modals/ConfirmModal/index.d.ts +7 -0
- package/dist/components/modals/ConfirmModal/index.js +23 -0
- package/dist/components/modals/Modal/index.d.ts +19 -0
- package/dist/components/modals/Modal/index.js +17 -0
- package/dist/components/modals/ModalActions/index.d.ts +9 -0
- package/dist/components/modals/ModalActions/index.js +8 -0
- package/dist/components/modals/ModalLauncher/index.d.ts +5 -0
- package/dist/components/modals/ModalLauncher/index.js +14 -0
- package/dist/components/utility/ActionList/index.d.ts +12 -0
- package/dist/components/utility/ActionList/index.js +9 -0
- package/dist/components/utility/Assistive/index.d.ts +8 -0
- package/dist/components/utility/Assistive/index.js +8 -0
- package/dist/components/utility/ClassNames/index.d.ts +6 -0
- package/dist/components/utility/ClassNames/index.js +7 -0
- package/dist/components/utility/Container/index.d.ts +9 -0
- package/dist/components/utility/Container/index.js +8 -0
- package/dist/components/utility/Link/index.d.ts +19 -0
- package/dist/components/utility/Link/index.js +33 -0
- package/dist/components/utility/Loader/index.d.ts +8 -0
- package/dist/components/utility/Loader/index.js +9 -0
- package/dist/components/utility/Page/index.d.ts +18 -0
- package/dist/components/utility/Page/index.js +34 -0
- package/dist/components/utility/Popover/index.d.ts +14 -0
- package/dist/components/utility/Popover/index.js +71 -0
- package/dist/components/utility/RootLayout/index.d.ts +12 -0
- package/dist/components/utility/RootLayout/index.js +14 -0
- package/dist/components/utility/Toast/index.d.ts +11 -0
- package/dist/components/utility/Toast/index.js +11 -0
- package/dist/components/utility/Toaster/index.d.ts +8 -0
- package/dist/components/utility/Toaster/index.js +57 -0
- package/dist/filters/components/FilterBar/index.d.ts +9 -0
- package/dist/filters/components/FilterBar/index.js +9 -0
- package/dist/filters/components/FilterBarClientComponent/index.d.ts +12 -0
- package/dist/filters/components/FilterBarClientComponent/index.js +68 -0
- package/dist/filters/components/FilterClearButton/index.d.ts +5 -0
- package/dist/filters/components/FilterClearButton/index.js +6 -0
- package/dist/filters/components/FilterControl/index.d.ts +12 -0
- package/dist/filters/components/FilterControl/index.js +10 -0
- package/dist/filters/components/FilterItem/index.d.ts +14 -0
- package/dist/filters/components/FilterItem/index.js +43 -0
- package/dist/filters/components/FilterPanel/index.d.ts +19 -0
- package/dist/filters/components/FilterPanel/index.js +36 -0
- package/dist/filters/filters/BooleanFilter/index.d.ts +3 -0
- package/dist/filters/filters/BooleanFilter/index.js +10 -0
- package/dist/filters/filters/CalendarFilter/index.d.ts +3 -0
- package/dist/filters/filters/CalendarFilter/index.js +10 -0
- package/dist/filters/filters/DateFilter/index.d.ts +3 -0
- package/dist/filters/filters/DateFilter/index.js +21 -0
- package/dist/filters/filters/DropdownFilter/index.d.ts +3 -0
- package/dist/filters/filters/DropdownFilter/index.js +10 -0
- package/dist/filters/filters/Filter/index.d.ts +16 -0
- package/dist/filters/filters/Filter/index.js +13 -0
- package/dist/filters/filters/MultiFilter/index.d.ts +3 -0
- package/dist/filters/filters/MultiFilter/index.js +9 -0
- package/dist/filters/filters/SearchFilter/index.d.ts +4 -0
- package/dist/filters/filters/SearchFilter/index.js +30 -0
- package/dist/filters/filters/interfaces.d.ts +10 -0
- package/dist/filters/filters/interfaces.js +1 -0
- package/dist/filters/hooks/useFilters.d.ts +5 -0
- package/dist/filters/hooks/useFilters.js +25 -0
- package/dist/filters/index.d.ts +2 -0
- package/dist/filters/index.js +2 -0
- package/dist/filters/interfaces.d.ts +28 -0
- package/dist/filters/interfaces.js +1 -0
- package/dist/filters/lang.d.ts +1 -0
- package/dist/filters/lang.js +1 -0
- package/dist/filters/utility/check-has-filters.d.ts +2 -0
- package/dist/filters/utility/check-has-filters.js +8 -0
- package/dist/filters/utility/create-client-filter-map.d.ts +3 -0
- package/dist/filters/utility/create-client-filter-map.js +14 -0
- package/dist/filters/utility/filter.d.ts +16 -0
- package/dist/filters/utility/filter.js +120 -0
- package/dist/filters/utility/get-quick-dates.d.ts +3 -0
- package/dist/filters/utility/get-quick-dates.js +90 -0
- package/dist/filters/utility/parse-filters.d.ts +3 -0
- package/dist/filters/utility/parse-filters.js +16 -0
- package/dist/filters/utility/parse-page.d.ts +2 -0
- package/dist/filters/utility/parse-page.js +8 -0
- package/dist/filters/utility/render-value.d.ts +3 -0
- package/dist/filters/utility/render-value.js +57 -0
- package/dist/filters/utility/transform-boolean.d.ts +2 -0
- package/dist/filters/utility/transform-boolean.js +10 -0
- package/dist/filters/utility/transform-date.d.ts +2 -0
- package/dist/filters/utility/transform-date.js +29 -0
- package/dist/filters/utility/transform-multi.d.ts +2 -0
- package/dist/filters/utility/transform-multi.js +9 -0
- package/dist/forms/components/Dropdown/index.d.ts +22 -0
- package/dist/forms/components/Dropdown/index.js +41 -0
- package/dist/forms/components/DropdownList/index.d.ts +8 -0
- package/dist/forms/components/DropdownList/index.js +20 -0
- package/dist/forms/components/EditableForm/index.d.ts +24 -0
- package/dist/forms/components/EditableForm/index.js +23 -0
- package/dist/forms/components/EditableFormField/index.d.ts +14 -0
- package/dist/forms/components/EditableFormField/index.js +37 -0
- package/dist/forms/components/EditableFormFields/index.d.ts +7 -0
- package/dist/forms/components/EditableFormFields/index.js +20 -0
- package/dist/forms/components/Form/index.d.ts +12 -0
- package/dist/forms/components/Form/index.js +9 -0
- package/dist/forms/components/FormError/index.d.ts +9 -0
- package/dist/forms/components/FormError/index.js +8 -0
- package/dist/forms/components/FormField/index.d.ts +25 -0
- package/dist/forms/components/FormField/index.js +37 -0
- package/dist/forms/components/FormFields/index.d.ts +10 -0
- package/dist/forms/components/FormFields/index.js +22 -0
- package/dist/forms/components/FormLabel/index.d.ts +10 -0
- package/dist/forms/components/FormLabel/index.js +8 -0
- package/dist/forms/components/FormSubmit/index.d.ts +4 -0
- package/dist/forms/components/FormSubmit/index.js +9 -0
- package/dist/forms/components/ModalForm/index.d.ts +13 -0
- package/dist/forms/components/ModalForm/index.js +25 -0
- package/dist/forms/components/PasswordInput/index.d.ts +11 -0
- package/dist/forms/components/PasswordInput/index.js +17 -0
- package/dist/forms/components/StaticTextInput/index.d.ts +22 -0
- package/dist/forms/components/StaticTextInput/index.js +22 -0
- package/dist/forms/components/Switch/index.d.ts +11 -0
- package/dist/forms/components/Switch/index.js +17 -0
- package/dist/forms/components/TextInput/index.d.ts +34 -0
- package/dist/forms/components/TextInput/index.js +30 -0
- package/dist/forms/hooks/useDropdown.d.ts +10 -0
- package/dist/forms/hooks/useDropdown.js +14 -0
- package/dist/forms/hooks/useEditableForm.d.ts +24 -0
- package/dist/forms/hooks/useEditableForm.js +34 -0
- package/dist/forms/hooks/useForm.d.ts +136 -0
- package/dist/forms/hooks/useForm.js +209 -0
- package/dist/forms/hooks/useModalForm.d.ts +14 -0
- package/dist/forms/hooks/useModalForm.js +29 -0
- package/dist/forms/index.d.ts +27 -0
- package/dist/forms/index.js +17 -0
- package/dist/forms/interfaces.d.ts +32 -0
- package/dist/forms/interfaces.js +1 -0
- package/dist/forms/utility/extract-editable-input-props.d.ts +8 -0
- package/dist/forms/utility/extract-editable-input-props.js +19 -0
- package/dist/forms/utility/extract-input-props.d.ts +9 -0
- package/dist/forms/utility/extract-input-props.js +37 -0
- package/dist/hooks/index.d.ts +0 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useClickOutside.d.ts +93 -0
- package/dist/hooks/useClickOutside.js +124 -0
- package/dist/hooks/usePagination.d.ts +17 -0
- package/dist/hooks/usePagination.js +46 -0
- package/dist/hooks/useSearchParamsHref.d.ts +6 -0
- package/dist/hooks/useSearchParamsHref.js +33 -0
- package/dist/hooks/useToast.d.ts +18 -0
- package/dist/hooks/useToast.js +25 -0
- package/dist/navigation/components/AppNavigation/index.d.ts +13 -0
- package/dist/navigation/components/AppNavigation/index.js +15 -0
- package/dist/navigation/components/AppNavigationItem/index.d.ts +6 -0
- package/dist/navigation/components/AppNavigationItem/index.js +9 -0
- package/dist/navigation/components/Tabs/index.d.ts +7 -0
- package/dist/navigation/components/Tabs/index.js +9 -0
- package/dist/navigation/hooks/useNavigation.d.ts +10 -0
- package/dist/navigation/hooks/useNavigation.js +38 -0
- package/dist/navigation/index.d.ts +5 -0
- package/dist/navigation/index.js +3 -0
- package/dist/navigation/interfaces.d.ts +7 -0
- package/dist/navigation/interfaces.js +1 -0
- package/dist/styles/config.d.ts +64 -0
- package/dist/styles/config.js +43 -0
- package/dist/styles/icons.d.ts +15 -0
- package/dist/styles/icons.js +7 -0
- package/dist/styles/index.d.ts +2 -0
- package/dist/styles/index.js +1 -0
- package/dist/styles/interfaces.d.ts +41 -0
- package/dist/styles/interfaces.js +1 -0
- package/dist/styles/tw.d.ts +9 -0
- package/dist/styles/tw.js +15 -0
- package/dist/utility/index.d.ts +1 -0
- package/dist/utility/index.js +1 -0
- package/dist/utility/interfaces.d.ts +35 -0
- package/dist/utility/interfaces.js +1 -1
- package/package.json +55 -8
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -1
- package/dist/lists/List/index.d.ts +0 -5
- package/dist/lists/List/index.js +0 -6
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ClassNameProps } from '../../../styles/interfaces';
|
|
2
|
+
import type { FormFieldClassNames } from '../FormField';
|
|
3
|
+
interface FormErrorProps extends ClassNameProps<FormFieldClassNames> {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
id: string;
|
|
6
|
+
isAssistive?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare function FormError({ children, classNames, classNameProps, id, isAssistive, }: Readonly<FormErrorProps>): React.ReactElement;
|
|
9
|
+
export default FormError;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getClassNames } from '../../../styles/config';
|
|
3
|
+
import tw from '../../../styles/tw';
|
|
4
|
+
function FormError({ children, classNames, classNameProps, id, isAssistive, }) {
|
|
5
|
+
const componentClassNames = classNames || getClassNames('formField')?.(classNameProps);
|
|
6
|
+
return (_jsx("div", { className: tw(componentClassNames?.error, isAssistive ? 'sr-only' : null), id: `${id}_err`, children: children }));
|
|
7
|
+
}
|
|
8
|
+
export default FormError;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { InputEvent, InputProps } from '../../../forms/interfaces';
|
|
2
|
+
import type { ClassNameProps, ErrorableClassName } from '../../../styles/interfaces';
|
|
3
|
+
import { Action } from '../../../utility/interfaces';
|
|
4
|
+
export interface FormFieldClassNames {
|
|
5
|
+
root: ErrorableClassName;
|
|
6
|
+
label: string;
|
|
7
|
+
details: string;
|
|
8
|
+
optional: string;
|
|
9
|
+
field: string;
|
|
10
|
+
error: string;
|
|
11
|
+
}
|
|
12
|
+
export interface FormFieldProps<T, V extends T> extends ClassNameProps<FormFieldClassNames>, InputProps<T, V> {
|
|
13
|
+
action?: Action | null;
|
|
14
|
+
details?: string | null;
|
|
15
|
+
error?: Record<string, string> | null;
|
|
16
|
+
hasAssistiveError?: boolean;
|
|
17
|
+
hasAssistiveLabel?: boolean;
|
|
18
|
+
isContentOnly?: boolean;
|
|
19
|
+
isOptional?: boolean;
|
|
20
|
+
label?: React.ReactNode;
|
|
21
|
+
onChange?: (event: InputEvent<T>) => void;
|
|
22
|
+
render: (props: InputProps<T>) => React.ReactElement | null;
|
|
23
|
+
}
|
|
24
|
+
declare function FormField<T, V extends T>({ action, classNameProps, details, error, hasAssistiveError, hasAssistiveLabel, id, isContentOnly, isDisabled, isOptional, label, name, onChange, onKeyDown, render, value, }: Readonly<FormFieldProps<T, V>>): React.ReactElement | null;
|
|
25
|
+
export default FormField;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { getClassNames } from '../../../styles/config';
|
|
5
|
+
import tw from '../../../styles/tw';
|
|
6
|
+
import FormError from '../FormError';
|
|
7
|
+
import FormLabel from '../FormLabel';
|
|
8
|
+
import ActionButton from '../../../components/buttons/ActionButton';
|
|
9
|
+
function checkHasError(error) {
|
|
10
|
+
return Boolean(error && Object.keys(error).length > 0 && Object.values(error).some(Boolean));
|
|
11
|
+
}
|
|
12
|
+
function FormField({ action, classNameProps, details, error, hasAssistiveError, hasAssistiveLabel, id, isContentOnly, isDisabled, isOptional, label, name, onChange, onKeyDown, render, value, }) {
|
|
13
|
+
const classNames = getClassNames('formField')?.(classNameProps);
|
|
14
|
+
const inputId = id || `ff_${name}`;
|
|
15
|
+
const [inputError, setInputError] = useState(null);
|
|
16
|
+
function handleError(message) {
|
|
17
|
+
setInputError(message);
|
|
18
|
+
}
|
|
19
|
+
const renderProps = {
|
|
20
|
+
classNameProps,
|
|
21
|
+
error,
|
|
22
|
+
hasError: checkHasError(error),
|
|
23
|
+
id: inputId,
|
|
24
|
+
isDisabled,
|
|
25
|
+
label,
|
|
26
|
+
name,
|
|
27
|
+
onChange,
|
|
28
|
+
onError: handleError,
|
|
29
|
+
onKeyDown,
|
|
30
|
+
value,
|
|
31
|
+
};
|
|
32
|
+
if (isContentOnly) {
|
|
33
|
+
return render(renderProps);
|
|
34
|
+
}
|
|
35
|
+
return (_jsxs("div", { className: tw(classNames?.root?.default, error ? classNames?.root?.error : null), children: [label ? (_jsx(FormLabel, { classNameProps: classNameProps, htmlFor: inputId, isAssistive: hasAssistiveLabel, isOptional: isOptional, children: label })) : null, details && label ? _jsx("div", { className: classNames?.details, children: details }) : null, _jsx("div", { className: classNames?.field, children: render(renderProps) }), action ? (_jsx("div", { children: _jsx(ActionButton, { ...action, isDisabled: Boolean(isDisabled || action.isDisabled) }) })) : null, inputError || error?.[name] ? (_jsx(FormError, { classNameProps: classNameProps, id: inputId, isAssistive: hasAssistiveError, children: inputError || error?.[name] })) : null] }));
|
|
36
|
+
}
|
|
37
|
+
export default FormField;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FormFieldComponentProps } from '../../interfaces';
|
|
2
|
+
import type { DropdownComponentProps } from '../Dropdown';
|
|
3
|
+
import type { PasswordInputComponentProps } from '../PasswordInput';
|
|
4
|
+
import type { TextInputComponentProps } from '../TextInput';
|
|
5
|
+
export type DropdownFormFieldProps<T> = FormFieldComponentProps<T | null> & DropdownComponentProps<T>;
|
|
6
|
+
export declare function DropdownFormField<T>(props: Readonly<DropdownFormFieldProps<T>>): React.ReactElement;
|
|
7
|
+
export type PasswordFormFieldProps = FormFieldComponentProps<string> & PasswordInputComponentProps;
|
|
8
|
+
export declare function PasswordFormField(props: Readonly<PasswordFormFieldProps>): React.ReactElement;
|
|
9
|
+
export type TextFormFieldProps = FormFieldComponentProps<string> & TextInputComponentProps;
|
|
10
|
+
export declare function TextFormField(props: Readonly<TextFormFieldProps>): React.ReactElement;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import extractInputProps from '../../utility/extract-input-props';
|
|
4
|
+
import Dropdown from '../Dropdown';
|
|
5
|
+
import FormField from '../FormField';
|
|
6
|
+
import PasswordInput from '../PasswordInput';
|
|
7
|
+
import TextInput from '../TextInput';
|
|
8
|
+
export function DropdownFormField(props) {
|
|
9
|
+
const { fieldProps, inputProps } = extractInputProps(props);
|
|
10
|
+
const renderInput = useCallback((renderProps) => (_jsx(Dropdown, { ...renderProps, ...inputProps })), [inputProps]);
|
|
11
|
+
return _jsx(FormField, { ...fieldProps, render: renderInput });
|
|
12
|
+
}
|
|
13
|
+
export function PasswordFormField(props) {
|
|
14
|
+
const { fieldProps, inputProps } = extractInputProps(props);
|
|
15
|
+
const renderInput = useCallback((renderProps) => (_jsx(PasswordInput, { ...renderProps, ...inputProps })), [inputProps]);
|
|
16
|
+
return _jsx(FormField, { ...fieldProps, render: renderInput });
|
|
17
|
+
}
|
|
18
|
+
export function TextFormField(props) {
|
|
19
|
+
const { fieldProps, inputProps } = extractInputProps(props);
|
|
20
|
+
const renderInput = useCallback((renderProps) => (_jsx(TextInput, { ...renderProps, ...inputProps })), [inputProps]);
|
|
21
|
+
return _jsx(FormField, { ...fieldProps, render: renderInput });
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ClassNameProps } from '../../../styles/interfaces';
|
|
2
|
+
import type { FormFieldClassNames } from '../FormField';
|
|
3
|
+
interface FormLabelProps extends ClassNameProps<FormFieldClassNames> {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
htmlFor: string;
|
|
6
|
+
isAssistive?: boolean;
|
|
7
|
+
isOptional?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function FormLabel({ children, classNames, classNameProps, htmlFor, isAssistive, isOptional, }: Readonly<FormLabelProps>): React.ReactElement;
|
|
10
|
+
export default FormLabel;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getClassNames } from '../../../styles/config';
|
|
3
|
+
import tw from '../../../styles/tw';
|
|
4
|
+
function FormLabel({ children, classNames, classNameProps, htmlFor, isAssistive, isOptional, }) {
|
|
5
|
+
const componentClassNames = classNames || getClassNames('formField')?.(classNameProps);
|
|
6
|
+
return (_jsxs("label", { className: tw(componentClassNames?.label, isAssistive ? 'sr-only' : null), htmlFor: htmlFor, children: [children, isOptional ? _jsx("small", { className: componentClassNames?.optional, children: "Optional" }) : null] }));
|
|
7
|
+
}
|
|
8
|
+
export default FormLabel;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ButtonProps } from '../../../components/buttons/Button';
|
|
2
|
+
export type FormSubmitProps = Omit<ButtonProps, 'href' | 'isNewWindow' | 'isText'>;
|
|
3
|
+
declare function FormSubmit({ isLoading, ...props }: Readonly<FormSubmitProps>): React.ReactElement;
|
|
4
|
+
export default FormSubmit;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useFormStatus } from 'react-dom';
|
|
4
|
+
import Button from '../../../components/buttons/Button';
|
|
5
|
+
function FormSubmit({ isLoading, ...props }) {
|
|
6
|
+
const { pending } = useFormStatus();
|
|
7
|
+
return _jsx(Button, { ...props, isLoading: isLoading || pending, type: "submit", variant: "primary" });
|
|
8
|
+
}
|
|
9
|
+
export default FormSubmit;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ModalProps } from '../../../components/modals/Modal';
|
|
2
|
+
import type { FormProps } from '../Form';
|
|
3
|
+
export interface ModalFormProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
formProps: Omit<FormProps, 'children'>;
|
|
6
|
+
hasServerError?: boolean;
|
|
7
|
+
hasSubmit?: boolean;
|
|
8
|
+
isDisabled?: boolean;
|
|
9
|
+
modalProps: Omit<ModalProps, 'children'>;
|
|
10
|
+
submitLabel?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function ModalForm({ children, formProps, hasServerError, hasSubmit, isDisabled, modalProps, submitLabel, }: Readonly<ModalFormProps>): React.ReactElement;
|
|
13
|
+
export default ModalForm;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Modal from '../../../components/modals/Modal';
|
|
4
|
+
import ModalActions from '../../../components/modals/ModalActions';
|
|
5
|
+
import useSearchParamsHref from '../../../hooks/useSearchParamsHref';
|
|
6
|
+
import Form from '../Form';
|
|
7
|
+
function ModalForm({ children, formProps, hasServerError, hasSubmit = true, isDisabled, modalProps, submitLabel, }) {
|
|
8
|
+
const { setSearchParamsHref } = useSearchParamsHref();
|
|
9
|
+
function handleCancel() {
|
|
10
|
+
setSearchParamsHref('action', null);
|
|
11
|
+
}
|
|
12
|
+
return (_jsx(Modal, { ...modalProps, children: _jsxs(Form, { ...formProps, children: [children, hasServerError ? _jsx("div", { children: "SERVER ERROR" }) : null, _jsx(ModalActions, { actions: [
|
|
13
|
+
{ label: 'Cancel', onClick: handleCancel, variant: 'link' },
|
|
14
|
+
...(modalProps.actions || []),
|
|
15
|
+
hasSubmit
|
|
16
|
+
? {
|
|
17
|
+
isDisabled,
|
|
18
|
+
isLoading: modalProps.isLoading,
|
|
19
|
+
isSubmittable: true,
|
|
20
|
+
label: submitLabel || 'Submit',
|
|
21
|
+
}
|
|
22
|
+
: null,
|
|
23
|
+
] })] }) }));
|
|
24
|
+
}
|
|
25
|
+
export default ModalForm;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InputProps } from '../../../forms/interfaces';
|
|
2
|
+
import type { ClassNameProps, SelectableClassName } from '../../../styles/interfaces';
|
|
3
|
+
import type { TextInputComponentProps } from '../TextInput';
|
|
4
|
+
export interface PasswordInputClassNames {
|
|
5
|
+
action: string;
|
|
6
|
+
icon: SelectableClassName;
|
|
7
|
+
}
|
|
8
|
+
export type PasswordInputComponentProps = TextInputComponentProps;
|
|
9
|
+
export type PasswordInputProps = ClassNameProps<PasswordInputClassNames> & InputProps<string> & PasswordInputComponentProps;
|
|
10
|
+
declare function PasswordInput({ classNameProps, classNames, ...props }: Readonly<PasswordInputProps>): React.ReactElement;
|
|
11
|
+
export default PasswordInput;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { getClassNames } from '../../../styles/config';
|
|
5
|
+
import { getIcon } from '../../../styles/icons';
|
|
6
|
+
import tw from '../../../styles/tw';
|
|
7
|
+
import TextInput from '../TextInput';
|
|
8
|
+
function PasswordInput({ classNameProps, classNames, ...props }) {
|
|
9
|
+
const componentClassNames = classNames || getClassNames('passwordInput')?.(classNameProps);
|
|
10
|
+
const Icon = getIcon('password');
|
|
11
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
12
|
+
function toggleVisible() {
|
|
13
|
+
setIsVisible(!isVisible);
|
|
14
|
+
}
|
|
15
|
+
return (_jsxs("div", { className: "relative", children: [_jsx(TextInput, { type: isVisible ? 'text' : 'password', ...props }), _jsx("div", { className: componentClassNames?.action, children: _jsxs("button", { className: tw(componentClassNames?.icon?.default, isVisible ? componentClassNames?.icon?.selected : null), onClick: toggleVisible, type: "button", children: [Icon ? _jsx(Icon, {}) : null, isVisible ? 'Hide' : 'Show'] }) })] }));
|
|
16
|
+
}
|
|
17
|
+
export default PasswordInput;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { InputProps } from '../../../forms/interfaces';
|
|
2
|
+
import type { ClassNameProps, ErrorableClassName } from '../../../styles/interfaces';
|
|
3
|
+
export interface StaticTextInputClassNames {
|
|
4
|
+
root: ErrorableClassName;
|
|
5
|
+
placeholder: string;
|
|
6
|
+
label: string;
|
|
7
|
+
details: string;
|
|
8
|
+
icon: string;
|
|
9
|
+
clear: string;
|
|
10
|
+
}
|
|
11
|
+
export interface StaticTextInputProps extends ClassNameProps<StaticTextInputClassNames>, Omit<InputProps<string[] | string, string[] | string>, 'onChange'> {
|
|
12
|
+
details?: string | null;
|
|
13
|
+
label: string;
|
|
14
|
+
icon?: React.ReactNode;
|
|
15
|
+
isOpen?: boolean;
|
|
16
|
+
isOptional?: boolean;
|
|
17
|
+
onClear?: () => void;
|
|
18
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
}
|
|
21
|
+
declare function StaticTextInput({ classNames, classNameProps, details, hasError, icon, isDisabled, isOpen, isOptional, label, name, onClear, onClick, onKeyDown, placeholder, value, }: Readonly<StaticTextInputProps>): React.ReactElement;
|
|
22
|
+
export default StaticTextInput;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment } from 'react';
|
|
3
|
+
import Assistive from '../../../components/utility/Assistive';
|
|
4
|
+
import { getClassNames } from '../../../styles/config';
|
|
5
|
+
import tw from '../../../styles/tw';
|
|
6
|
+
function hasValue(value) {
|
|
7
|
+
if (Array.isArray(value)) {
|
|
8
|
+
return Boolean(value.filter((item) => Boolean(item)).length);
|
|
9
|
+
}
|
|
10
|
+
return Boolean(value);
|
|
11
|
+
}
|
|
12
|
+
function StaticTextInput({ classNames, classNameProps, details, hasError, icon, isDisabled, isOpen, isOptional, label, name, onClear, onClick, onKeyDown, placeholder = 'Select...', value, }) {
|
|
13
|
+
const componentClassNames = {
|
|
14
|
+
...getClassNames('staticTextInput')?.(classNameProps),
|
|
15
|
+
...classNames,
|
|
16
|
+
};
|
|
17
|
+
function handleClear() {
|
|
18
|
+
onClear?.();
|
|
19
|
+
}
|
|
20
|
+
return (_jsxs("div", { className: tw('relative', isDisabled ? 'pointer-events-none opacity-30' : null, componentClassNames.root?.default, hasError ? componentClassNames.root?.error : null), children: [_jsx("input", { name: name, type: "hidden", value: value ? value.toString() : '' }), label ? (_jsxs(Fragment, { children: [_jsx("span", { className: tw(componentClassNames.label), children: label }), details ? (_jsx("small", { className: tw(componentClassNames.details), children: details })) : null] })) : (_jsx("span", { className: tw(componentClassNames.placeholder), children: placeholder })), onClick ? (_jsx("button", { className: "absolute -bottom-px -left-px -right-px -top-px", disabled: isDisabled, onClick: onClick, onKeyDown: onKeyDown, tabIndex: 0, type: "button", children: _jsx(Assistive, { children: isOpen ? 'Close' : 'Open' }) })) : null, _jsxs("div", { className: "absolute bottom-0 right-0 top-0 flex w-0 items-center justify-end", children: [isOptional && hasValue(value) ? (_jsx("button", { className: tw('flex-none', componentClassNames.clear), onClick: handleClear, type: "button", children: _jsx(Assistive, { children: "Clear" }) })) : null, icon && !isDisabled ? (_jsx("i", { className: tw('pointer-events-none flex-none', componentClassNames.icon) })) : null] })] }));
|
|
21
|
+
}
|
|
22
|
+
export default StaticTextInput;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { InputProps } from '../../../forms/interfaces';
|
|
2
|
+
import { CheckableClassName, ClassNameProps } from '../../../styles/interfaces';
|
|
3
|
+
export interface SwitchClassNames {
|
|
4
|
+
root: string;
|
|
5
|
+
control: string;
|
|
6
|
+
input: CheckableClassName;
|
|
7
|
+
icon: CheckableClassName;
|
|
8
|
+
}
|
|
9
|
+
export type SwitchProps = ClassNameProps<SwitchClassNames> & InputProps<boolean>;
|
|
10
|
+
declare function Switch({ classNameProps, classNames, id, isDisabled, name, onChange, value, }: Readonly<SwitchProps>): React.ReactElement;
|
|
11
|
+
export default Switch;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment } from 'react';
|
|
3
|
+
import { getClassNames } from '../../../styles/config';
|
|
4
|
+
import tw from '../../../styles/tw';
|
|
5
|
+
function Switch({ classNameProps, classNames, id, isDisabled, name, onChange, value, }) {
|
|
6
|
+
const componentClassNames = classNames || getClassNames('switch')?.(classNameProps);
|
|
7
|
+
function handleChange(event) {
|
|
8
|
+
if (onChange) {
|
|
9
|
+
const inputEvent = {
|
|
10
|
+
target: { name, value: event.target.checked },
|
|
11
|
+
};
|
|
12
|
+
onChange(inputEvent);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return (_jsxs(Fragment, { children: [_jsx("input", { name: name, type: "hidden", value: "false" }), _jsx("div", { className: tw('block', componentClassNames?.root), children: _jsxs("div", { className: tw('relative', componentClassNames?.control), children: [_jsx("input", { "aria-checked": Boolean(value), checked: Boolean(value), className: tw('appearance-none', componentClassNames?.input?.default, value ? componentClassNames?.input?.checked : null), disabled: isDisabled, id: id || name, name: name, onChange: handleChange, type: "checkbox", value: "true" }), _jsx("i", { className: tw(componentClassNames?.icon?.default, value ? componentClassNames?.icon?.checked : null) })] }) })] }));
|
|
16
|
+
}
|
|
17
|
+
export default Switch;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { InputProps } from '../../../forms/interfaces';
|
|
2
|
+
import type { ClassNameProps, ErrorableClassName } from '../../../styles/interfaces';
|
|
3
|
+
export interface TextInputClassNames {
|
|
4
|
+
loading: string;
|
|
5
|
+
prefix: ErrorableClassName;
|
|
6
|
+
root: ErrorableClassName;
|
|
7
|
+
suffix: ErrorableClassName;
|
|
8
|
+
clear: string;
|
|
9
|
+
}
|
|
10
|
+
export interface TextInputComponentProps {
|
|
11
|
+
isAutocomplete?: boolean;
|
|
12
|
+
isLoading?: boolean;
|
|
13
|
+
onBlur?: React.EventHandler<React.FocusEvent>;
|
|
14
|
+
onFocus?: React.EventHandler<React.FocusEvent>;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
prefix?: string | null;
|
|
17
|
+
suffix?: string | null;
|
|
18
|
+
type?: React.HTMLInputTypeAttribute;
|
|
19
|
+
}
|
|
20
|
+
export type TextInputProps = ClassNameProps<TextInputClassNames> & InputProps<string> & TextInputComponentProps;
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* ## ClassNames
|
|
24
|
+
*
|
|
25
|
+
* | Name | Description | Type |
|
|
26
|
+
* | ---- | ----------- | ---- |
|
|
27
|
+
* | root | The input element itself | `ErrorableClassName` |
|
|
28
|
+
* | prefix | The prefix element of the input, if one exists | `ErrorableClassName` |
|
|
29
|
+
* | suffix | The suffix element of the input, if one exists | `ErrorableClassName` |
|
|
30
|
+
* | clear | The wrapper around the 'clear' button of the input, if one exists. The style of the
|
|
31
|
+
* button itself is handled by the `renderClear` prop. | `string` |
|
|
32
|
+
*/
|
|
33
|
+
declare function TextInput({ classNames, classNameProps, hasError, id, isAutocomplete, isDisabled, name, onBlur, onChange, onFocus, onKeyDown, placeholder, prefix, suffix, type, value, }: Readonly<TextInputProps>): React.ReactElement;
|
|
34
|
+
export default TextInput;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getClassNames } from '../../../styles/config';
|
|
3
|
+
import tw from '../../../styles/tw';
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* ## ClassNames
|
|
7
|
+
*
|
|
8
|
+
* | Name | Description | Type |
|
|
9
|
+
* | ---- | ----------- | ---- |
|
|
10
|
+
* | root | The input element itself | `ErrorableClassName` |
|
|
11
|
+
* | prefix | The prefix element of the input, if one exists | `ErrorableClassName` |
|
|
12
|
+
* | suffix | The suffix element of the input, if one exists | `ErrorableClassName` |
|
|
13
|
+
* | clear | The wrapper around the 'clear' button of the input, if one exists. The style of the
|
|
14
|
+
* button itself is handled by the `renderClear` prop. | `string` |
|
|
15
|
+
*/
|
|
16
|
+
function TextInput({ classNames, classNameProps, hasError, id, isAutocomplete, isDisabled, name, onBlur, onChange, onFocus, onKeyDown, placeholder, prefix, suffix, type, value, }) {
|
|
17
|
+
const componentClassNames = classNames || getClassNames('textInput')?.(classNameProps);
|
|
18
|
+
function handleChange(event) {
|
|
19
|
+
if (onChange) {
|
|
20
|
+
const target = { name, value: event.target.value };
|
|
21
|
+
onChange({ target });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return (_jsxs("div", { className: tw('relative', prefix ? 'flex flex-row-reverse' : null, (!prefix && suffix) || value ? 'flex' : null, isDisabled ? 'pointer-events-none opacity-30' : null), children: [prefix ? _jsx("div", { children: prefix }) : null, _jsx("input", { "aria-invalid": hasError, "aria-labelledby": hasError
|
|
25
|
+
? `${id || name}_err`
|
|
26
|
+
: undefined /* eslint-disable-line no-undefined */, autoComplete: isAutocomplete === false
|
|
27
|
+
? 'one-time-code'
|
|
28
|
+
: undefined /* eslint-disable-line no-undefined */, className: tw('peer w-full focus-visible:outline-0', prefix ? 'border-l-0' : null, (!prefix && suffix) || value ? 'border-r-0' : null, componentClassNames?.root?.default, hasError ? componentClassNames?.root?.error : null), disabled: isDisabled, formNoValidate: true, id: id || name, name: name, onBlur: onBlur, onChange: handleChange, onFocus: onFocus, onKeyDown: onKeyDown, placeholder: placeholder, type: type, value: value || '' }), suffix ? _jsx("div", { children: suffix }) : null] }));
|
|
29
|
+
}
|
|
30
|
+
export default TextInput;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DropdownObject } from '../interfaces';
|
|
2
|
+
interface UseDropdownArgs<T extends string> {
|
|
3
|
+
deps?: unknown[];
|
|
4
|
+
fn: (...args: unknown[]) => Promise<DropdownObject<T>[]>;
|
|
5
|
+
}
|
|
6
|
+
interface UseDropdownReturn<T extends string> {
|
|
7
|
+
data: DropdownObject<T>[];
|
|
8
|
+
}
|
|
9
|
+
declare function useDropdown<T extends string>({ deps, fn }: UseDropdownArgs<T>): UseDropdownReturn<T>;
|
|
10
|
+
export default useDropdown;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
function useDropdown({ deps, fn }) {
|
|
4
|
+
const [data, setData] = useState([]);
|
|
5
|
+
async function getData() {
|
|
6
|
+
const response = await (deps ? fn(...deps) : fn());
|
|
7
|
+
setData(response);
|
|
8
|
+
}
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
void getData();
|
|
11
|
+
}, deps || []);
|
|
12
|
+
return { data };
|
|
13
|
+
}
|
|
14
|
+
export default useDropdown;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { EditableFormProps } from '../components/EditableForm';
|
|
2
|
+
import type { EditingStatus } from '../interfaces';
|
|
3
|
+
import type { FieldPropsReturn, UseFormArgs, UseFormReturn } from './useForm';
|
|
4
|
+
export interface EditableFieldPropsReturn<Request, K extends keyof Request = keyof Request> extends FieldPropsReturn<Request, K> {
|
|
5
|
+
status: EditingStatus | null;
|
|
6
|
+
}
|
|
7
|
+
export type UseEditableFormArgs<Request, Response> = UseFormArgs<Request, Response> & {
|
|
8
|
+
defaultStatus?: EditingStatus;
|
|
9
|
+
onCancel?: () => void;
|
|
10
|
+
onEdit?: () => void;
|
|
11
|
+
title?: string;
|
|
12
|
+
};
|
|
13
|
+
export interface UseEditableFormReturn<Request> extends Omit<UseFormReturn<Request>, 'fieldProps' | 'formProps'> {
|
|
14
|
+
actionProps: {
|
|
15
|
+
setStatus: React.Dispatch<React.SetStateAction<EditingStatus | null>>;
|
|
16
|
+
status: EditingStatus | null;
|
|
17
|
+
};
|
|
18
|
+
fieldProps: <K extends keyof Request>(name: K, label?: string) => FieldPropsReturn<Request, K>;
|
|
19
|
+
formProps: Omit<EditableFormProps, 'children'>;
|
|
20
|
+
setStatus: React.Dispatch<React.SetStateAction<EditingStatus | null>>;
|
|
21
|
+
status: EditingStatus | null;
|
|
22
|
+
}
|
|
23
|
+
declare function useEditableForm<Request extends object, Response = Request>({ defaultStatus, onCancel, onEdit, onSuccess, title, ...args }: UseEditableFormArgs<Request, Response>): UseEditableFormReturn<Request>;
|
|
24
|
+
export default useEditableForm;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import useForm from './useForm';
|
|
3
|
+
function useEditableForm({ defaultStatus, onCancel, onEdit, onSuccess, title, ...args }) {
|
|
4
|
+
const [status, setStatus] = useState(defaultStatus ?? null);
|
|
5
|
+
async function onEditableSuccess(response) {
|
|
6
|
+
if (onSuccess) {
|
|
7
|
+
await onSuccess(response);
|
|
8
|
+
}
|
|
9
|
+
setStatus('SAVED');
|
|
10
|
+
}
|
|
11
|
+
const useFormReturn = useForm({
|
|
12
|
+
...args,
|
|
13
|
+
refreshOnSuccess: true,
|
|
14
|
+
onSuccess: onEditableSuccess,
|
|
15
|
+
});
|
|
16
|
+
function editableFieldProps(name, label) {
|
|
17
|
+
const fieldProps = useFormReturn.fieldProps(name, label);
|
|
18
|
+
return { ...fieldProps, status };
|
|
19
|
+
}
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (status === 'CANCELLED') {
|
|
22
|
+
useFormReturn.setErrors(null);
|
|
23
|
+
}
|
|
24
|
+
}, [status]);
|
|
25
|
+
return {
|
|
26
|
+
...useFormReturn,
|
|
27
|
+
actionProps: { status, setStatus },
|
|
28
|
+
fieldProps: editableFieldProps,
|
|
29
|
+
formProps: { formProps: useFormReturn.formProps, onCancel, onEdit, status, setStatus, title },
|
|
30
|
+
status,
|
|
31
|
+
setStatus,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export default useEditableForm;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { Default, InputEvent } from '../../forms/interfaces';
|
|
2
|
+
import type { FormProps } from '../components/Form';
|
|
3
|
+
interface AwaitedFormResponse<M> {
|
|
4
|
+
data: M | null;
|
|
5
|
+
error: string | null;
|
|
6
|
+
validation: Record<string, string> | null;
|
|
7
|
+
}
|
|
8
|
+
export type FormResponse<M> = Promise<AwaitedFormResponse<M>>;
|
|
9
|
+
export interface FieldPropsReturn<Request, K extends keyof Request = keyof Request> {
|
|
10
|
+
error: Record<string, string> | null;
|
|
11
|
+
isDisabled?: boolean;
|
|
12
|
+
label?: string;
|
|
13
|
+
name: string;
|
|
14
|
+
onChange: (event: InputEvent<Request[K]>) => void;
|
|
15
|
+
value: Request[K];
|
|
16
|
+
}
|
|
17
|
+
export interface ToastsArgs {
|
|
18
|
+
server?: string | false;
|
|
19
|
+
success?: string | false;
|
|
20
|
+
validation?: string | false;
|
|
21
|
+
}
|
|
22
|
+
export interface UseFormArgs<Request, Response> {
|
|
23
|
+
defaults?: Default<Request>;
|
|
24
|
+
onError?: (message: string) => void;
|
|
25
|
+
onSubmit?: (formData: Request) => FormResponse<Response>;
|
|
26
|
+
onSuccess?: (response: Response) => Promise<void> | void;
|
|
27
|
+
onValidation?: (errors: Record<string, string>) => void;
|
|
28
|
+
redirectOnSuccess?: string | false | ((response: Response) => string | false);
|
|
29
|
+
refreshOnSuccess?: boolean;
|
|
30
|
+
toasts?: ToastsArgs | false;
|
|
31
|
+
}
|
|
32
|
+
export interface UseFormReturn<Request> {
|
|
33
|
+
errors: Record<string, string> | null;
|
|
34
|
+
fieldProps: <K extends keyof Request>(name: K, label?: string) => FieldPropsReturn<Request, K>;
|
|
35
|
+
formData: Partial<Request>;
|
|
36
|
+
formProps: Omit<FormProps, 'children'>;
|
|
37
|
+
isLoading: boolean;
|
|
38
|
+
resetForm: () => void;
|
|
39
|
+
setErrors: (errors: Record<string, string> | null) => void;
|
|
40
|
+
setFormData: (key: keyof Request, value: Request[keyof Request]) => void;
|
|
41
|
+
submitForm: () => void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* ## Overview
|
|
45
|
+
*
|
|
46
|
+
* `useForm` is a custom React hook that facilitates handling server-side form submission,
|
|
47
|
+
* including state management, error handling, and form data processing. It's designed to work
|
|
48
|
+
* with forms where the data is submitted to and validated by a server.
|
|
49
|
+
*
|
|
50
|
+
* ## Type Parameters
|
|
51
|
+
*
|
|
52
|
+
* - `Request extends object`: The shape of the request data.
|
|
53
|
+
* - `Response = Request`: The shape of the response data, defaulting to the same type as `Request`.
|
|
54
|
+
*
|
|
55
|
+
* ## Arguments
|
|
56
|
+
*
|
|
57
|
+
* `useForm` takes an object with the following properties:
|
|
58
|
+
*
|
|
59
|
+
* - `defaults`: Initial default values for the form data.
|
|
60
|
+
* - `hiddenFields`: Fields that should be included in the form submission but not displayed.
|
|
61
|
+
* - `onError`: Callback function for handling errors during form submission.
|
|
62
|
+
* - `onSubmit`: Function to handle the form submission. Expected to return a promise.
|
|
63
|
+
* - `onSuccess`: Callback function to be called upon a successful submission.
|
|
64
|
+
* - `onValidationError`: Callback function for handling validation errors.
|
|
65
|
+
* - `toasts`: Configuration for displaying success or error toasts.
|
|
66
|
+
*
|
|
67
|
+
* ## Returns
|
|
68
|
+
*
|
|
69
|
+
* `useForm` returns an object with the following properties:
|
|
70
|
+
*
|
|
71
|
+
* - `errors`: An object containing any form errors.
|
|
72
|
+
* - `fieldProps`: Function to generate props for a form field.
|
|
73
|
+
* - `formData`: Current form data.
|
|
74
|
+
* - `formProps`: Props for the form element including the submit handler.
|
|
75
|
+
* - `isLoading`: Boolean indicating if the form submission is in progress.
|
|
76
|
+
* - `resetForm`: Function to reset the form to its initial state.
|
|
77
|
+
* - `setFormData`: Function to update a specific piece of form data.
|
|
78
|
+
*
|
|
79
|
+
* ## Functionality
|
|
80
|
+
*
|
|
81
|
+
* - **Form Data Management:**
|
|
82
|
+
* - Manages form data state and provides handleChange and setFormData functions to update form
|
|
83
|
+
* data.
|
|
84
|
+
*
|
|
85
|
+
* - **Form Submission:**
|
|
86
|
+
* - Handles form submission, including displaying loading state, submitting data to the provided
|
|
87
|
+
* onSubmit function, and handling server-side validation errors or other errors.
|
|
88
|
+
*
|
|
89
|
+
* - **Error Handling:**
|
|
90
|
+
* - Manages form error state and handles displaying error messages.
|
|
91
|
+
*
|
|
92
|
+
* - **Toasts:**
|
|
93
|
+
* - Optionally displays success or error toasts based on the form submission outcome.
|
|
94
|
+
*
|
|
95
|
+
* - **Reset Form:**
|
|
96
|
+
* - Provides a function to reset the form to its default state.
|
|
97
|
+
*
|
|
98
|
+
* ## Example
|
|
99
|
+
*
|
|
100
|
+
* ```jsx
|
|
101
|
+
* import React from 'react';
|
|
102
|
+
* import { useForm } from './path-to-useForm';
|
|
103
|
+
*
|
|
104
|
+
* const MyFormComponent = () => {
|
|
105
|
+
* const { fieldProps, formProps, isLoading, resetForm } = useForm<MyFormData>({
|
|
106
|
+
* defaults: { name: '', email: '' },
|
|
107
|
+
* onSubmit: async (formData) => {
|
|
108
|
+
* // Submit form data to the server
|
|
109
|
+
* },
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* return (
|
|
113
|
+
* <form {...formProps}>
|
|
114
|
+
* <input {...fieldProps('name', 'Name')} />
|
|
115
|
+
* <input {...fieldProps('email', 'Email')} />
|
|
116
|
+
* <button type="submit" disabled={isLoading}>Submit</button>
|
|
117
|
+
* <button type="button" onClick={resetForm}>Reset</button>
|
|
118
|
+
* </form>
|
|
119
|
+
* );
|
|
120
|
+
* };
|
|
121
|
+
*
|
|
122
|
+
* export default MyFormComponent;
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* In this example, `MyFormComponent` uses the `useForm` hook to manage form state, handle
|
|
126
|
+
* submissions, display errors, and reset the form.
|
|
127
|
+
*
|
|
128
|
+
* ## Notes
|
|
129
|
+
*
|
|
130
|
+
* - Ensure proper types are passed to the useForm hook to align with the expected structure
|
|
131
|
+
* of your form data and server responses.
|
|
132
|
+
* - The hook's functionality can be extended or customized based on specific use cases, such as
|
|
133
|
+
* handling additional form events or integrating with different server APIs.
|
|
134
|
+
*/
|
|
135
|
+
declare function useForm<Request extends object, Response = Request>({ defaults, onError, onSubmit, onSuccess, onValidation, redirectOnSuccess, refreshOnSuccess, toasts, }: UseFormArgs<Request, Response>): UseFormReturn<Request>;
|
|
136
|
+
export default useForm;
|