UNPKG

reoverlay

Version:

A tiny, typed modal manager for React.

1 lines 17.2 kB
{"version":3,"sources":["../src/constants/index.ts","../src/utils/eventManager.ts","../src/utils/utils.ts","../src/utils/validator.ts","../src/ModalContainer.tsx","../src/Reoverlay.ts","../src/ModalWrapper.tsx"],"names":["VALIDATE","EVENT","eventManager","subscribers","on","eventName","callback","off","listeners","payload","eventManager_default","getLastElement","array","isArrayUnique","isString","value","isModalLikeObject","isRenderableModal","isValidElement","validate","type","configData","item","names","throwError","ModalContainer","modals","setModals","useState","useEffect","jsx","modalKey","component","props","Fragment","cloneElement","ModalContainer_default","modalId","createModalKey","Reoverlay","modal","modalElement","snapshot","lastSnapshot","Reoverlay_default","ModalWrapper","ariaDescribedBy","ariaLabel","ariaLabelledBy","animation","children","closeOnEscape","contentContainerClassName","onClose","role","wrapperClassName","wrapperElement","useRef","handleKeyDown","event","handleClickOutside","ModalWrapper_default"],"mappings":"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","file":"index.cjs","sourcesContent":["export const VALIDATE = {\n CONFIG: 'config',\n HIDE_MODAL: 'hide_modal',\n SHOW_MODAL: 'show_modal',\n} as const\n\nexport const EVENT = {\n CHANGE_MODAL: 'change_modal',\n HIDE_ALL: 'hide_all',\n HIDE_MODAL: 'hide_modal',\n SHOW_MODAL: 'show_modal',\n} as const\n","type Listener<TPayload> = (payload: TPayload) => void\n\nconst eventManager = (() => {\n const subscribers = new Map<string, Set<Listener<unknown>>>()\n\n const on = <TPayload>(eventName: string, callback: Listener<TPayload>) => {\n if (!subscribers.has(eventName)) {\n subscribers.set(eventName, new Set())\n }\n\n const listeners = subscribers.get(eventName)\n listeners?.add(callback as Listener<unknown>)\n\n return () => off(eventName, callback)\n }\n\n const off = <TPayload>(eventName?: string, callback?: Listener<TPayload>) => {\n if (!eventName) {\n subscribers.clear()\n return\n }\n\n if (!callback) {\n subscribers.delete(eventName)\n return\n }\n\n const listeners = subscribers.get(eventName)\n listeners?.delete(callback as Listener<unknown>)\n\n if (listeners?.size === 0) {\n subscribers.delete(eventName)\n }\n }\n\n const emit = <TPayload>(eventName: string, payload: TPayload) => {\n subscribers.get(eventName)?.forEach((callback) => {\n callback(payload)\n })\n }\n\n const listenerCount = (eventName: string) => subscribers.get(eventName)?.size ?? 0\n\n return {\n emit,\n listenerCount,\n off,\n on,\n }\n})()\n\nexport default eventManager\n","export const getLastElement = <TValue>(array: TValue[]) => array[array.length - 1]\n\nexport const isArrayUnique = <TValue>(array: TValue[]) => new Set(array).size === array.length\n\nexport const isString = (value: unknown): value is string =>\n typeof value === 'string' || value instanceof String\n\nexport const isModalLikeObject = (value: unknown) =>\n typeof value === 'object' && value !== null && '$$typeof' in value\n","import { isValidElement } from 'react'\n\nimport { VALIDATE } from '../constants'\nimport type { ModalConfigItem, ModalRenderable } from '../types'\nimport { isArrayUnique, isModalLikeObject, isString } from './utils'\n\ntype ValidationType = (typeof VALIDATE)[keyof typeof VALIDATE]\n\nexport type ShowModalValidationResult = 'component' | 'string'\n\nconst isRenderableModal = (value: unknown): value is ModalRenderable =>\n typeof value === 'function' || isValidElement(value) || isModalLikeObject(value)\n\nexport const validate = (\n type: ValidationType,\n value: unknown\n): boolean | ShowModalValidationResult => {\n switch (type) {\n case VALIDATE.CONFIG: {\n if (!Array.isArray(value)) {\n throw new Error(\n 'Reoverlay: Config data must be an array. Pass an array to Reoverlay.config().'\n )\n }\n\n const configData = value as ModalConfigItem[]\n\n configData.forEach((item) => {\n if (!item.name || !item.component) {\n throw new Error(\n \"Reoverlay: Each config item must contain a 'name' and 'component' property.\"\n )\n }\n })\n\n const names = configData.map((item) => item.name)\n if (!isArrayUnique(names)) {\n throw new Error('Reoverlay: Modal config names must be unique.')\n }\n\n return true\n }\n\n case VALIDATE.SHOW_MODAL: {\n const throwError = () => {\n throw new Error(\n \"Reoverlay: Method 'showModal' requires a React component, React element, or configured modal name.\"\n )\n }\n\n if (!value) throwError()\n if (isString(value)) return 'string'\n if (isRenderableModal(value)) return 'component'\n\n throwError()\n return false\n }\n\n case VALIDATE.HIDE_MODAL: {\n if (isString(value)) return true\n\n throw new Error(\n `Reoverlay: Method 'hideModal' accepts an optional string modal name, got ${typeof value}.`\n )\n }\n\n default:\n return false\n }\n}\n","import { Fragment, cloneElement, isValidElement, useEffect, useState } from 'react'\n\nimport { EVENT } from './constants'\nimport type { ActiveModal } from './types'\nimport { eventManager } from './utils'\n\nconst ModalContainer = () => {\n const [modals, setModals] = useState<ActiveModal[]>([])\n\n useEffect(() => {\n const unsubscribe = eventManager.on<ActiveModal[]>(EVENT.CHANGE_MODAL, setModals)\n return unsubscribe\n }, [])\n\n return (\n <div className=\"reOverlay\">\n {modals.map(({ modalKey, component, props }) => {\n if (isValidElement(component)) {\n return <Fragment key={`id-${modalKey}`}>{cloneElement(component, props)}</Fragment>\n }\n\n const Component = component\n\n return (\n <Fragment key={`id-${modalKey}`}>\n <Component {...props} />\n </Fragment>\n )\n })}\n </div>\n )\n}\n\nexport default ModalContainer\n","import { EVENT, VALIDATE } from './constants'\nimport type { ActiveModal, ModalConfigItem, ModalProps, ModalRenderable } from './types'\nimport { eventManager, getLastElement, validate } from './utils'\n\ntype ModalSnapshot<P extends ModalProps = ModalProps> = Omit<ActiveModal<P>, 'modalKey'>\n\nlet modalId = 0\n\nconst createModalKey = () => {\n modalId += 1\n return `reoverlay-${modalId}`\n}\n\nconst Reoverlay = {\n modals: new Map<string, ModalRenderable>(),\n snapshots: new Map<string, ModalSnapshot<any>>(),\n\n config(configData: ModalConfigItem[] = []) {\n validate(VALIDATE.CONFIG, configData)\n\n configData.forEach((item) => {\n this.modals.set(item.name, item.component)\n })\n },\n\n showModal<P extends ModalProps = ModalProps>(\n modal: ModalRenderable<P> | string,\n props = {} as P\n ) {\n const modalType = validate(VALIDATE.SHOW_MODAL, modal)\n\n if (modalType === 'string') {\n const modalKey = modal as string\n const modalElement = this.modals.get(modalKey)\n\n if (!modalElement) {\n throw new Error(\n `Reoverlay: Modal not found. Make sure \"${modalKey}\" has been passed to Reoverlay.config().`\n )\n }\n\n this.applyModal({\n component: modalElement,\n modalKey,\n props,\n type: EVENT.SHOW_MODAL,\n })\n return\n }\n\n this.applyModal({\n component: modal as ModalRenderable<P>,\n modalKey: createModalKey(),\n props,\n type: EVENT.SHOW_MODAL,\n })\n },\n\n getSnapshotsArray() {\n return Array.from(this.snapshots.entries()).map(([modalKey, value]) => ({\n modalKey,\n ...value,\n }))\n },\n\n hideModal(modal: string | null = null) {\n if (modal) {\n validate(VALIDATE.HIDE_MODAL, modal)\n\n const modalKey = modal\n const snapshot = this.snapshots.get(modalKey)\n\n if (!snapshot) {\n throw new Error(\"Reoverlay: Snapshot not found. You're trying to hide a missing modal.\")\n }\n\n this.applyModal({\n ...snapshot,\n modalKey,\n type: EVENT.HIDE_MODAL,\n })\n return\n }\n\n const lastSnapshot = getLastElement(this.getSnapshotsArray()) ?? null\n\n if (lastSnapshot) {\n this.applyModal({ ...lastSnapshot, type: EVENT.HIDE_MODAL })\n return\n }\n\n console.error(\"Reoverlay: There's no active modal to be hidden.\")\n },\n\n hideAll() {\n this.applyModal({ type: EVENT.HIDE_ALL })\n },\n\n applyModal({\n component,\n modalKey,\n props,\n type,\n }: Partial<ActiveModal<any>> & { type: (typeof EVENT)[keyof typeof EVENT] }) {\n switch (type) {\n case EVENT.SHOW_MODAL:\n if (component && modalKey) {\n this.snapshots.set(modalKey, { component, props: props ?? {} })\n }\n break\n case EVENT.HIDE_ALL:\n this.snapshots.clear()\n break\n default:\n if (modalKey) {\n this.snapshots.delete(modalKey)\n }\n break\n }\n\n eventManager.emit(EVENT.CHANGE_MODAL, this.getSnapshotsArray())\n },\n}\n\nexport default Reoverlay\n","import { useEffect, useRef } from 'react'\nimport type React from 'react'\n\nimport Reoverlay from './Reoverlay'\nimport type { ModalWrapperProps } from './types'\n\nconst ModalWrapper = ({\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n animation = 'fade',\n children = null,\n closeOnEscape = true,\n contentContainerClassName = '',\n onClose = () => {\n Reoverlay.hideModal()\n },\n role = 'dialog',\n wrapperClassName = '',\n}: ModalWrapperProps) => {\n const wrapperElement = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!closeOnEscape) return undefined\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose(event)\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n }\n }, [closeOnEscape, onClose])\n\n const handleClickOutside = (event: React.MouseEvent<HTMLDivElement>) => {\n if (event.target === wrapperElement.current) {\n onClose(event)\n }\n }\n\n return (\n <div\n aria-describedby={ariaDescribedBy}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-modal=\"true\"\n className={`reOverlay__modalWrapper -ro-${animation} ${wrapperClassName}`.trim()}\n onClick={handleClickOutside}\n ref={wrapperElement}\n role={role}\n >\n <div className={`reOverlay__modalContainer ${contentContainerClassName}`.trim()}>\n {children}\n </div>\n </div>\n )\n}\n\nexport default ModalWrapper\n"]}