useModal doest register only open and close
All checks were successful
forgejo/Procyon/procyon/pipeline/pr-develop This commit looks good
forgejo/Procyon/procyon/pipeline/head This commit looks good

This commit is contained in:
Roman Jaroš 2023-11-21 07:16:14 +01:00 committed by Roman Jaroš
parent 49a163482c
commit 4a283c5982
14 changed files with 45 additions and 50 deletions

View file

@ -3,7 +3,7 @@ import { omit } from 'ramda';
import { format as formatFn } from 'date-fns';
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 { TextField } from '../../TextField';
@ -21,7 +21,7 @@ export type DatePickerProps<V = Date> = Omit<
export const DatePicker: React.FC<DatePickerProps> = (props) => {
const { onChange, label, name, format, ...others } = props;
const [openModal, { closeModal }] = useModal(name, {
const [openModal, closeModal] = useModal(name, {
title: label,
style: { width: 400 },
});
@ -34,8 +34,6 @@ export const DatePicker: React.FC<DatePickerProps> = (props) => {
}
}, [props.value]);
const handleCloseModal = () => closeModal(name);
const handleDateClick = (value: Date): void => {
setValue(value);
onChange?.(value, null);
@ -47,7 +45,7 @@ export const DatePicker: React.FC<DatePickerProps> = (props) => {
format={format ?? DefaultDateFormat}
name={name}
value={value}
closeModal={handleCloseModal}
closeModal={closeModal}
onChange={handleDateClick}
{...props}
/>

View file

@ -11,6 +11,10 @@ export enum GridSizeEnum {
xl = 'xl'
}
export const {
sm, md, lg, xl
} = GridSizeEnum;
export enum GridVerticalAlignEnum {
bottom = 'bottom',
center = 'center',

View file

@ -4,7 +4,7 @@ import { StatusEnum } from '@procyon/types/enums';
import { Button } from '../../Button';
import { Modal } from '../context';
import { useModal } from '../hooks';
import { useModal } from '../useModal';
export type AddModalButtonProps = {
modalTitle: string;

View file

@ -3,10 +3,10 @@ import React, { MouseEvent, useEffect } from 'react';
import { isNilOrEmpty } from '@procyon/utils';
import { ModalId } from '../context';
import { useModal } from '../hooks';
import { useModal } from '../useModal';
export const Modals = () => {
const [, { modals, opened, closeModal }] = useModal();
const [, , { modals, opened, closeModal }] = useModal();
const handleCloseModal = (modalId: ModalId) => {
modals[modalId]?.props?.onClose?.();
@ -36,7 +36,8 @@ export const Modals = () => {
return (
<>
{opened.map((modalId) => {
const { id, style, title, Component, props } = modals[modalId];
const { id, style, title, Component, props } = modals[modalId] ?? {};
if (!id) return null;
return (
<div key={id} className="modal-wrapper bg-black bg-opacity-70" onClick={() => handleCloseModal(id)}>
<div

View file

@ -33,32 +33,32 @@ export const ModalContext = createContext<ModalContextType>({
});
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 register = function <P>(modal: Modal<P>) {
setModals({
setRegistered((modals) => ({
...modals,
[modal.id]: {
...modals[modal.id],
...modal,
},
});
}));
};
const unregister = (modalId: ModalId) => {
setModals(omit([modalId], modals));
setRegistered((modals) => omit([modalId], modals));
};
const open = function <P>(modalId: ModalId, modal: Modal<P> | undefined) {
if (modal) {
if (!registered[modalId]) {
register({ ...modal, id: modalId });
}
setOpened((opened) => [...opened, modalId]);
};
const close = (modalId: ModalId) => {
setOpened(opened.filter((id) => id !== modalId));
setOpened((opened) => opened.filter((id) => id !== modalId));
};
useEffect(() => {
@ -72,14 +72,14 @@ export const ModalWrapper: FC<{ children: ReactNode }> = ({ children }) => {
const value = useMemo(
() => ({
registered: modals,
registered: registered,
opened,
unregister,
register,
open,
close,
}),
[modals, opened],
[registered, opened],
);
return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;

View file

@ -1,22 +1,16 @@
import { useContext, useEffect } from 'react';
import { useContext } from 'react';
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);
useEffect(() => {
if (id && modal) {
register({
id,
...modal,
});
return () => unregister(id);
}
}, []);
return [
(modal?: Omit<Modal<P>, 'id'>) => open(id!, modal),
(newOptions?: Omit<Modal<P>, 'id'>) =>
open(id!, {
...options,
...newOptions,
}),
() => close(id!),
{
modals: registered,
opened: opened,

View file

@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react';
import { find, propEq, propOr } from 'ramda';
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 { Option } from '@procyon/types/options';
@ -20,7 +20,7 @@ export type SelectBoxProps<V = Option> = Omit<
export const Selectbox: React.FC<SelectBoxProps> = (props) => {
const { value, options, onChange, name, label, autoComplete, ...others } = props;
const [openModal, { closeModal }] = useModal(name, {
const [openModal, closeModal] = useModal(name, {
title: label,
style: { width: 300 },
});

View file

@ -12,7 +12,7 @@ import { ModalId } from '../../Modal/context';
export type SelectboxModalProps = {
autoComplete?: boolean;
closeModal: (id: ModalId) => void;
closeModal: () => void;
name: ModalId;
onChange: (options: Option) => void;
onRemove: () => void;
@ -27,12 +27,12 @@ export const SelectboxModal: React.FC<SelectboxModalProps> = (props) => {
const handleChange = (option: Option) => {
onChange(option);
closeModal(name);
closeModal();
};
const removeActiveOption = (): void => {
onRemove();
closeModal(name);
closeModal();
};
return (

View file

@ -2,7 +2,7 @@ import React, { FC, useCallback, useEffect, useState } from 'react';
import { format } from 'date-fns';
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 { Option } from '@procyon/types/options';

View file

@ -5,7 +5,7 @@ import { Button } from '@procyon/components/Button';
import { Grid, GridSizeEnum } from '@procyon/components/Grid';
import { GridCol } from '@procyon/components/GridCol';
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 { Option } from '@procyon/types/options';
@ -33,7 +33,7 @@ const { base } = GridSizeEnum;
export const TimePickerModal: React.FC<TimePickerModalProps> = (props) => {
const { onChange, modalName, scrollToCode } = props;
const [, { closeModal }] = useModal(props.modalName);
const [, closeModal] = useModal(modalName);
const [hour, setHour] = 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 = setSeconds(value, 0);
onChange(value);
closeModal(modalName);
closeModal();
};
const handleClearValue = () => {
setHour(null);
setMinute(null);
onChange(undefined);
closeModal(modalName);
closeModal();
};
const selectedHour = hour ? hour : undefined;

View file

@ -11,7 +11,7 @@ type IProps<FormData extends FieldValues> = {
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;
return (
<FormProvider {...methods}>
@ -19,5 +19,3 @@ function Form<FormData extends FieldValues>(props: IProps<FormData>) {
</FormProvider>
);
}
export default Form;

View file

@ -30,12 +30,12 @@ import { AddModalButton } from '@procyon/components/Modal/components/AddModalBut
return <AddModalButton />;
```
<Canvas of={ModalStories.Default} withToolbar />
<Canvas of={ModalStories.Default} withToolbar className='h-80' />
## Use hook `useModal()`
```tsx
import { useModal } from '@procyon/components/Modal/hooks';
import { useModal } from '@procyon/components/Modal/useModal';
const [openModal] = useModal({
component: <div>Modal content</div>,
@ -48,7 +48,7 @@ const [openModal] = useModal({
openModal();
```
<Canvas of={ModalStories.Hook} withToolbar />
<Canvas of={ModalStories.Hook} withToolbar className='h-80' />
## Use function `openModal()`
@ -60,4 +60,4 @@ import { openModal } from '@procyon/components/Modal/context';
openModal('modal1');
```
<Canvas of={ModalStories.OutsideReact} withToolbar />
<Canvas of={ModalStories.OutsideReact} withToolbar className='h-80' />

View file

@ -6,7 +6,7 @@ import { Button } from '@procyon/components/Button';
import { Modals } from '@procyon/components/Modal';
import { AddModalButton } from '@procyon/components/Modal/components/AddModalButton';
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';
type Story = StoryObj<typeof Modals>;

View file

@ -6,7 +6,7 @@ import { Grid, GridSizeEnum } from '@procyon/components/Grid';
import { GridCol } from '@procyon/components/GridCol';
import { BuildingStoreIcon } from '@procyon/components/Icons/BuildingStore';
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 useForm from '@procyon/forms/useForm';
import { StatusEnum } from '@procyon/types/enums';