useModal doest register only open and close
This commit is contained in:
parent
49a163482c
commit
4a283c5982
14 changed files with 45 additions and 50 deletions
|
@ -3,7 +3,7 @@ import { omit } from 'ramda';
|
||||||
import { format as formatFn } from 'date-fns';
|
import { format as formatFn } from 'date-fns';
|
||||||
|
|
||||||
import { TodayIcon } from '@procyon/components/Icons/Today';
|
import { TodayIcon } from '@procyon/components/Icons/Today';
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
import { useModal } from '@procyon/components/Modal/useModal';
|
||||||
import { InputElementType } from '@procyon/types/form';
|
import { InputElementType } from '@procyon/types/form';
|
||||||
|
|
||||||
import { TextField } from '../../TextField';
|
import { TextField } from '../../TextField';
|
||||||
|
@ -21,7 +21,7 @@ export type DatePickerProps<V = Date> = Omit<
|
||||||
export const DatePicker: React.FC<DatePickerProps> = (props) => {
|
export const DatePicker: React.FC<DatePickerProps> = (props) => {
|
||||||
const { onChange, label, name, format, ...others } = props;
|
const { onChange, label, name, format, ...others } = props;
|
||||||
|
|
||||||
const [openModal, { closeModal }] = useModal(name, {
|
const [openModal, closeModal] = useModal(name, {
|
||||||
title: label,
|
title: label,
|
||||||
style: { width: 400 },
|
style: { width: 400 },
|
||||||
});
|
});
|
||||||
|
@ -34,8 +34,6 @@ export const DatePicker: React.FC<DatePickerProps> = (props) => {
|
||||||
}
|
}
|
||||||
}, [props.value]);
|
}, [props.value]);
|
||||||
|
|
||||||
const handleCloseModal = () => closeModal(name);
|
|
||||||
|
|
||||||
const handleDateClick = (value: Date): void => {
|
const handleDateClick = (value: Date): void => {
|
||||||
setValue(value);
|
setValue(value);
|
||||||
onChange?.(value, null);
|
onChange?.(value, null);
|
||||||
|
@ -47,7 +45,7 @@ export const DatePicker: React.FC<DatePickerProps> = (props) => {
|
||||||
format={format ?? DefaultDateFormat}
|
format={format ?? DefaultDateFormat}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
value={value}
|
||||||
closeModal={handleCloseModal}
|
closeModal={closeModal}
|
||||||
onChange={handleDateClick}
|
onChange={handleDateClick}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,6 +11,10 @@ export enum GridSizeEnum {
|
||||||
xl = 'xl'
|
xl = 'xl'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
sm, md, lg, xl
|
||||||
|
} = GridSizeEnum;
|
||||||
|
|
||||||
export enum GridVerticalAlignEnum {
|
export enum GridVerticalAlignEnum {
|
||||||
bottom = 'bottom',
|
bottom = 'bottom',
|
||||||
center = 'center',
|
center = 'center',
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { StatusEnum } from '@procyon/types/enums';
|
||||||
|
|
||||||
import { Button } from '../../Button';
|
import { Button } from '../../Button';
|
||||||
import { Modal } from '../context';
|
import { Modal } from '../context';
|
||||||
import { useModal } from '../hooks';
|
import { useModal } from '../useModal';
|
||||||
|
|
||||||
export type AddModalButtonProps = {
|
export type AddModalButtonProps = {
|
||||||
modalTitle: string;
|
modalTitle: string;
|
||||||
|
|
|
@ -3,10 +3,10 @@ import React, { MouseEvent, useEffect } from 'react';
|
||||||
import { isNilOrEmpty } from '@procyon/utils';
|
import { isNilOrEmpty } from '@procyon/utils';
|
||||||
|
|
||||||
import { ModalId } from '../context';
|
import { ModalId } from '../context';
|
||||||
import { useModal } from '../hooks';
|
import { useModal } from '../useModal';
|
||||||
|
|
||||||
export const Modals = () => {
|
export const Modals = () => {
|
||||||
const [, { modals, opened, closeModal }] = useModal();
|
const [, , { modals, opened, closeModal }] = useModal();
|
||||||
|
|
||||||
const handleCloseModal = (modalId: ModalId) => {
|
const handleCloseModal = (modalId: ModalId) => {
|
||||||
modals[modalId]?.props?.onClose?.();
|
modals[modalId]?.props?.onClose?.();
|
||||||
|
@ -36,7 +36,8 @@ export const Modals = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{opened.map((modalId) => {
|
{opened.map((modalId) => {
|
||||||
const { id, style, title, Component, props } = modals[modalId];
|
const { id, style, title, Component, props } = modals[modalId] ?? {};
|
||||||
|
if (!id) return null;
|
||||||
return (
|
return (
|
||||||
<div key={id} className="modal-wrapper bg-black bg-opacity-70" onClick={() => handleCloseModal(id)}>
|
<div key={id} className="modal-wrapper bg-black bg-opacity-70" onClick={() => handleCloseModal(id)}>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -33,32 +33,32 @@ export const ModalContext = createContext<ModalContextType>({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ModalWrapper: FC<{ children: ReactNode }> = ({ children }) => {
|
export const ModalWrapper: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
const [modals, setModals] = useState<Record<ModalId, Modal<any>>>({});
|
const [registered, setRegistered] = useState<Record<ModalId, Modal<any>>>({});
|
||||||
const [opened, setOpened] = useState<ModalId[]>([]);
|
const [opened, setOpened] = useState<ModalId[]>([]);
|
||||||
|
|
||||||
const register = function <P>(modal: Modal<P>) {
|
const register = function <P>(modal: Modal<P>) {
|
||||||
setModals({
|
setRegistered((modals) => ({
|
||||||
...modals,
|
...modals,
|
||||||
[modal.id]: {
|
[modal.id]: {
|
||||||
...modals[modal.id],
|
...modals[modal.id],
|
||||||
...modal,
|
...modal,
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const unregister = (modalId: ModalId) => {
|
const unregister = (modalId: ModalId) => {
|
||||||
setModals(omit([modalId], modals));
|
setRegistered((modals) => omit([modalId], modals));
|
||||||
};
|
};
|
||||||
|
|
||||||
const open = function <P>(modalId: ModalId, modal: Modal<P> | undefined) {
|
const open = function <P>(modalId: ModalId, modal: Modal<P> | undefined) {
|
||||||
if (modal) {
|
if (!registered[modalId]) {
|
||||||
register({ ...modal, id: modalId });
|
register({ ...modal, id: modalId });
|
||||||
}
|
}
|
||||||
setOpened((opened) => [...opened, modalId]);
|
setOpened((opened) => [...opened, modalId]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const close = (modalId: ModalId) => {
|
const close = (modalId: ModalId) => {
|
||||||
setOpened(opened.filter((id) => id !== modalId));
|
setOpened((opened) => opened.filter((id) => id !== modalId));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -72,14 +72,14 @@ export const ModalWrapper: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
|
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
registered: modals,
|
registered: registered,
|
||||||
opened,
|
opened,
|
||||||
unregister,
|
unregister,
|
||||||
register,
|
register,
|
||||||
open,
|
open,
|
||||||
close,
|
close,
|
||||||
}),
|
}),
|
||||||
[modals, opened],
|
[registered, opened],
|
||||||
);
|
);
|
||||||
|
|
||||||
return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;
|
return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;
|
||||||
|
|
|
@ -1,22 +1,16 @@
|
||||||
import { useContext, useEffect } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { Modal, ModalContext } from './context';
|
import { Modal, ModalContext } from './context';
|
||||||
|
|
||||||
export const useModal = <P>(id?: Modal<P>['id'], modal?: Omit<Modal<P>, 'id'>) => {
|
export const useModal = <P>(id?: Modal<P>['id'], options?: Omit<Modal<P>, 'id'>) => {
|
||||||
const { registered, close, open, opened, register, unregister } = useContext(ModalContext);
|
const { registered, close, open, opened, register, unregister } = useContext(ModalContext);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (id && modal) {
|
|
||||||
register({
|
|
||||||
id,
|
|
||||||
...modal,
|
|
||||||
});
|
|
||||||
return () => unregister(id);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(modal?: Omit<Modal<P>, 'id'>) => open(id!, modal),
|
(newOptions?: Omit<Modal<P>, 'id'>) =>
|
||||||
|
open(id!, {
|
||||||
|
...options,
|
||||||
|
...newOptions,
|
||||||
|
}),
|
||||||
|
() => close(id!),
|
||||||
{
|
{
|
||||||
modals: registered,
|
modals: registered,
|
||||||
opened: opened,
|
opened: opened,
|
|
@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { find, propEq, propOr } from 'ramda';
|
import { find, propEq, propOr } from 'ramda';
|
||||||
|
|
||||||
import { ButtonCursorIcon } from '@procyon/components/Icons/ButtonCursor';
|
import { ButtonCursorIcon } from '@procyon/components/Icons/ButtonCursor';
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
import { useModal } from '@procyon/components/Modal/useModal';
|
||||||
import { InputElementType } from '@procyon/types/form';
|
import { InputElementType } from '@procyon/types/form';
|
||||||
import { Option } from '@procyon/types/options';
|
import { Option } from '@procyon/types/options';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export type SelectBoxProps<V = Option> = Omit<
|
||||||
export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
||||||
const { value, options, onChange, name, label, autoComplete, ...others } = props;
|
const { value, options, onChange, name, label, autoComplete, ...others } = props;
|
||||||
|
|
||||||
const [openModal, { closeModal }] = useModal(name, {
|
const [openModal, closeModal] = useModal(name, {
|
||||||
title: label,
|
title: label,
|
||||||
style: { width: 300 },
|
style: { width: 300 },
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { ModalId } from '../../Modal/context';
|
||||||
|
|
||||||
export type SelectboxModalProps = {
|
export type SelectboxModalProps = {
|
||||||
autoComplete?: boolean;
|
autoComplete?: boolean;
|
||||||
closeModal: (id: ModalId) => void;
|
closeModal: () => void;
|
||||||
name: ModalId;
|
name: ModalId;
|
||||||
onChange: (options: Option) => void;
|
onChange: (options: Option) => void;
|
||||||
onRemove: () => void;
|
onRemove: () => void;
|
||||||
|
@ -27,12 +27,12 @@ export const SelectboxModal: React.FC<SelectboxModalProps> = (props) => {
|
||||||
|
|
||||||
const handleChange = (option: Option) => {
|
const handleChange = (option: Option) => {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
closeModal(name);
|
closeModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeActiveOption = (): void => {
|
const removeActiveOption = (): void => {
|
||||||
onRemove();
|
onRemove();
|
||||||
closeModal(name);
|
closeModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
import { ClockTimeIcon } from '@procyon/components/Icons/ClockTime';
|
import { ClockTimeIcon } from '@procyon/components/Icons/ClockTime';
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
import { useModal } from '@procyon/components/Modal/useModal';
|
||||||
import { InputElementType } from '@procyon/types/form';
|
import { InputElementType } from '@procyon/types/form';
|
||||||
import { Option } from '@procyon/types/options';
|
import { Option } from '@procyon/types/options';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Button } from '@procyon/components/Button';
|
||||||
import { Grid, GridSizeEnum } from '@procyon/components/Grid';
|
import { Grid, GridSizeEnum } from '@procyon/components/Grid';
|
||||||
import { GridCol } from '@procyon/components/GridCol';
|
import { GridCol } from '@procyon/components/GridCol';
|
||||||
import { TrashIcon } from '@procyon/components/Icons/Trash';
|
import { TrashIcon } from '@procyon/components/Icons/Trash';
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
import { useModal } from '@procyon/components/Modal/useModal';
|
||||||
import { SizeEnum, StatusEnum } from '@procyon/types/enums';
|
import { SizeEnum, StatusEnum } from '@procyon/types/enums';
|
||||||
import { Option } from '@procyon/types/options';
|
import { Option } from '@procyon/types/options';
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ const { base } = GridSizeEnum;
|
||||||
export const TimePickerModal: React.FC<TimePickerModalProps> = (props) => {
|
export const TimePickerModal: React.FC<TimePickerModalProps> = (props) => {
|
||||||
const { onChange, modalName, scrollToCode } = props;
|
const { onChange, modalName, scrollToCode } = props;
|
||||||
|
|
||||||
const [, { closeModal }] = useModal(props.modalName);
|
const [, closeModal] = useModal(modalName);
|
||||||
|
|
||||||
const [hour, setHour] = useState<number | null>();
|
const [hour, setHour] = useState<number | null>();
|
||||||
const [minute, setMinute] = useState<number | null>();
|
const [minute, setMinute] = useState<number | null>();
|
||||||
|
@ -62,14 +62,14 @@ export const TimePickerModal: React.FC<TimePickerModalProps> = (props) => {
|
||||||
value = setMinutes(value, minute ?? 0);
|
value = setMinutes(value, minute ?? 0);
|
||||||
value = setSeconds(value, 0);
|
value = setSeconds(value, 0);
|
||||||
onChange(value);
|
onChange(value);
|
||||||
closeModal(modalName);
|
closeModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClearValue = () => {
|
const handleClearValue = () => {
|
||||||
setHour(null);
|
setHour(null);
|
||||||
setMinute(null);
|
setMinute(null);
|
||||||
onChange(undefined);
|
onChange(undefined);
|
||||||
closeModal(modalName);
|
closeModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedHour = hour ? hour : undefined;
|
const selectedHour = hour ? hour : undefined;
|
||||||
|
|
|
@ -11,7 +11,7 @@ type IProps<FormData extends FieldValues> = {
|
||||||
onSubmit: SubmitHandler<FormData>;
|
onSubmit: SubmitHandler<FormData>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function Form<FormData extends FieldValues>(props: IProps<FormData>) {
|
export function Form<FormData extends FieldValues>(props: IProps<FormData>) {
|
||||||
const { onSubmit, onFail = always(noop), methods } = props;
|
const { onSubmit, onFail = always(noop), methods } = props;
|
||||||
return (
|
return (
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
|
@ -19,5 +19,3 @@ function Form<FormData extends FieldValues>(props: IProps<FormData>) {
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Form;
|
|
||||||
|
|
|
@ -30,12 +30,12 @@ import { AddModalButton } from '@procyon/components/Modal/components/AddModalBut
|
||||||
return <AddModalButton />;
|
return <AddModalButton />;
|
||||||
```
|
```
|
||||||
|
|
||||||
<Canvas of={ModalStories.Default} withToolbar />
|
<Canvas of={ModalStories.Default} withToolbar className='h-80' />
|
||||||
|
|
||||||
## Use hook `useModal()`
|
## Use hook `useModal()`
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
import { useModal } from '@procyon/components/Modal/useModal';
|
||||||
|
|
||||||
const [openModal] = useModal({
|
const [openModal] = useModal({
|
||||||
component: <div>Modal content</div>,
|
component: <div>Modal content</div>,
|
||||||
|
@ -48,7 +48,7 @@ const [openModal] = useModal({
|
||||||
openModal();
|
openModal();
|
||||||
```
|
```
|
||||||
|
|
||||||
<Canvas of={ModalStories.Hook} withToolbar />
|
<Canvas of={ModalStories.Hook} withToolbar className='h-80' />
|
||||||
|
|
||||||
## Use function `openModal()`
|
## Use function `openModal()`
|
||||||
|
|
||||||
|
@ -60,4 +60,4 @@ import { openModal } from '@procyon/components/Modal/context';
|
||||||
openModal('modal1');
|
openModal('modal1');
|
||||||
```
|
```
|
||||||
|
|
||||||
<Canvas of={ModalStories.OutsideReact} withToolbar />
|
<Canvas of={ModalStories.OutsideReact} withToolbar className='h-80' />
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Button } from '@procyon/components/Button';
|
||||||
import { Modals } from '@procyon/components/Modal';
|
import { Modals } from '@procyon/components/Modal';
|
||||||
import { AddModalButton } from '@procyon/components/Modal/components/AddModalButton';
|
import { AddModalButton } from '@procyon/components/Modal/components/AddModalButton';
|
||||||
import { ModalWrapper, openModal as openOutsideReactModal } from '@procyon/components/Modal/context';
|
import { ModalWrapper, openModal as openOutsideReactModal } from '@procyon/components/Modal/context';
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
import { useModal } from '@procyon/components/Modal/useModal';
|
||||||
import { TextField } from '@procyon/components/TextField';
|
import { TextField } from '@procyon/components/TextField';
|
||||||
|
|
||||||
type Story = StoryObj<typeof Modals>;
|
type Story = StoryObj<typeof Modals>;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Grid, GridSizeEnum } from '@procyon/components/Grid';
|
||||||
import { GridCol } from '@procyon/components/GridCol';
|
import { GridCol } from '@procyon/components/GridCol';
|
||||||
import { BuildingStoreIcon } from '@procyon/components/Icons/BuildingStore';
|
import { BuildingStoreIcon } from '@procyon/components/Icons/BuildingStore';
|
||||||
import { Field } from '@procyon/forms/Field';
|
import { Field } from '@procyon/forms/Field';
|
||||||
import Form from '@procyon/forms/Form';
|
import { Form } from '@procyon/forms/Form';
|
||||||
import { FormSubmit } from '@procyon/forms/types';
|
import { FormSubmit } from '@procyon/forms/types';
|
||||||
import useForm from '@procyon/forms/useForm';
|
import useForm from '@procyon/forms/useForm';
|
||||||
import { StatusEnum } from '@procyon/types/enums';
|
import { StatusEnum } from '@procyon/types/enums';
|
||||||
|
|
Loading…
Add table
Reference in a new issue