@react95/core
Version:
Windows 95 styleguide
162 lines (161 loc) • 4.68 kB
JavaScript
import { nanoid } from "nanoid";
import React, { useState, useEffect, useRef, useImperativeHandle } from "react";
import { useDraggable } from "@neodrag/react";
import { Button } from "../Button/Button.mjs";
import { fixedForwardRef, Frame } from "../Frame/Frame.mjs";
import { TitleBar } from "../TitleBar/TitleBar.mjs";
import { content, modalWrapper, menuWrapper, menuItem, buttonWrapper } from "./Modal.css.mjs";
import cn from "classnames";
import { useOnClickOutside } from "usehooks-ts";
import { modals, ModalEvents } from "../shared/events.mjs";
const ModalContent = fixedForwardRef(
(rest, ref) => /* @__PURE__ */ React.createElement(Frame, { ...rest, ref, className: cn(content, rest.className) })
);
const ModalMinimize = fixedForwardRef(
(props, ref) => {
const [id, setId] = useState("");
useEffect(() => {
const handleVisibilityChange = ({ id: activeId }) => {
setId(activeId);
};
modals.on(ModalEvents.ModalVisibilityChanged, handleVisibilityChange);
return () => {
modals.off(ModalEvents.ModalVisibilityChanged, handleVisibilityChange);
};
}, []);
const handleMinimize = () => {
modals.emit(ModalEvents.MinimizeModal, { id });
modals.emit(ModalEvents.ModalVisibilityChanged, { id: "no id" });
};
return /* @__PURE__ */ React.createElement(TitleBar.Minimize, { ...props, ref, onClick: handleMinimize });
}
);
const ModalRenderer = ({
hasWindowButton: hasButton = true,
buttons = [],
buttonsAlignment = "flex-end",
children,
icon,
menu = [],
title,
dragOptions,
titleBarOptions,
className,
...rest
}, ref) => {
const [id] = useState(nanoid());
const [menuOpened, setMenuOpened] = useState("");
const [isActive, setIsActive] = useState(false);
const [isModalMinimized, setIsModalMinimized] = useState(false);
const draggableRef = useRef(null);
useDraggable(draggableRef, {
...dragOptions,
handle: ".draggable"
});
const menuRef = useRef(null);
useOnClickOutside(menuRef, () => {
setMenuOpened("");
});
useEffect(() => {
modals.emit(ModalEvents.AddModal, {
icon,
title,
id,
hasButton
});
modals.on(ModalEvents.ModalVisibilityChanged, ({ id: activeId }) => {
setIsActive(activeId === id);
});
modals.emit(ModalEvents.ModalVisibilityChanged, { id });
return () => {
modals.emit(ModalEvents.RemoveModal, { id });
};
}, []);
useEffect(() => {
modals.on(ModalEvents.MinimizeModal, ({ id: activeId }) => {
if (activeId === id) {
setIsModalMinimized(true);
}
});
modals.on(ModalEvents.RestoreModal, ({ id: activeId }) => {
if (activeId === id) {
setIsModalMinimized(false);
}
});
return () => {
modals.off(ModalEvents.MinimizeModal, () => {
});
modals.off(ModalEvents.RestoreModal, () => {
});
};
}, [id]);
useImperativeHandle(ref, () => {
return draggableRef.current;
});
return /* @__PURE__ */ React.createElement(
Frame,
{
...rest,
className: cn(
modalWrapper({ active: isActive, minimized: isModalMinimized }),
className
),
role: "dialog",
"aria-hidden": isModalMinimized,
ref: draggableRef,
onMouseDown: () => {
modals.emit(ModalEvents.ModalVisibilityChanged, { id });
}
},
/* @__PURE__ */ React.createElement(
TitleBar,
{
active: isActive,
icon,
title,
className: "draggable"
},
titleBarOptions && /* @__PURE__ */ React.createElement(TitleBar.OptionsBox, null, titleBarOptions)
),
menu && menu.length > 0 && /* @__PURE__ */ React.createElement("ul", { className: menuWrapper, ref: menuRef }, menu.map(({ name, list }) => {
const active = menuOpened === name;
return /* @__PURE__ */ React.createElement(
"li",
{
key: name,
onMouseDown: () => setMenuOpened(name),
className: menuItem({ active })
},
name,
active && list
);
})),
children,
buttons && buttons.length > 0 && /* @__PURE__ */ React.createElement(
Frame,
{
className: buttonWrapper,
justifyContent: buttonsAlignment
},
buttons.map((button) => /* @__PURE__ */ React.createElement(
Button,
{
key: button.value,
onClick: button.onClick,
value: button.value
},
button.value
))
)
);
};
const Modal = Object.assign(
fixedForwardRef(ModalRenderer),
{
Content: ModalContent,
Minimize: ModalMinimize
}
);
export {
Modal
};