neko-popup 3.1.0 → 3.1.1
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/index.es.js +7 -4
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -14,7 +14,7 @@ function M() {
|
|
|
14
14
|
for (var e, o, s = 0, t = "", a = arguments.length; s < a; s++) (e = arguments[s]) && (o = C(e)) && (t && (t += " "), t += o);
|
|
15
15
|
return t;
|
|
16
16
|
}
|
|
17
|
-
const I = B({}), g = M,
|
|
17
|
+
const I = B({}), g = M, D = (e) => {
|
|
18
18
|
const o = O(I), [s, t] = f(!1), a = e.as ?? "button";
|
|
19
19
|
l(() => {
|
|
20
20
|
const c = o.nodes.find((b) => b.id === e.popupId);
|
|
@@ -130,14 +130,17 @@ const W = (e) => {
|
|
|
130
130
|
});
|
|
131
131
|
}, [c]);
|
|
132
132
|
function d(n) {
|
|
133
|
-
n.target
|
|
133
|
+
n.target === n.currentTarget && (m && a && e.onAfterEnter && !y.current && e.onAfterEnter(n), !m && !a && (e.onAfterExit && !y.current && e.onAfterExit(n), b(!1)), y.current = !0);
|
|
134
134
|
}
|
|
135
135
|
return !e.keep && !c ? null : s && z(/* @__PURE__ */ E(
|
|
136
136
|
"section",
|
|
137
137
|
{
|
|
138
138
|
className: g("neko-popup-backdrop", m && "neko-popup-backdrop--active", e.layerClassName),
|
|
139
139
|
"aria-hidden": !m,
|
|
140
|
-
style: {
|
|
140
|
+
style: {
|
|
141
|
+
cursor: k.includes("onLayer") ? "default" : "pointer",
|
|
142
|
+
zIndex: e.keep ? 100 : void 0
|
|
143
|
+
},
|
|
141
144
|
onTransitionEnd: d,
|
|
142
145
|
ref: v,
|
|
143
146
|
children: /* @__PURE__ */ E(
|
|
@@ -155,7 +158,7 @@ const W = (e) => {
|
|
|
155
158
|
), s);
|
|
156
159
|
};
|
|
157
160
|
export {
|
|
158
|
-
|
|
161
|
+
D as PopupButton,
|
|
159
162
|
Z as PopupLayer,
|
|
160
163
|
W as PopupWindow
|
|
161
164
|
};
|
package/dist/index.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../node_modules/clsx/dist/clsx.mjs","../src/_package/Interfaces.ts","../src/_package/PopupButton.tsx","../src/_package/components/ErrorComponents.ts","../src/_package/PopupLayer.tsx","../src/_package/hooks/useMixedState.ts","../src/_package/PopupWindow.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import React, { createContext, RefObject } from 'react';\nimport clsx from 'clsx';\n\n\n\n\nexport type PopupWindowDisabledType = 'onEscape' | 'onLayer';\nexport type StateSetter<S = any> = React.Dispatch<React.SetStateAction<S>>\nexport type MountNodeArgs = Pick<IPopupNode, 'id' | 'isOpen' | 'disabled'>\n\n/** Get value type from nested object path */\nexport type ValueFromPath<T, P> =\n P extends `${infer K}.${infer R}`\n ? K extends keyof T\n ? R extends keyof T[K]\n ? T[K][R]\n : never\n : never\n : P extends keyof T\n ? T[P]\n : never;\n\n\n\nexport interface IPopupNode {\n id: string\n isOpen: boolean\n zIndex: number\n disabled: PopupWindowDisabledType[]\n}\n\nexport interface IPopupContext {\n nodes: IPopupNode[]\n containerRef: RefObject<HTMLDivElement | null>\n\n invokePopup(id: string, forceState?: boolean): void\n mountNode(args: MountNodeArgs): void\n updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>): void\n}\n\n\n\nexport const PopupContext = createContext<IPopupContext>({} as IPopupContext);\nexport const cn = clsx;","'use client';\n\nimport { FC, JSX, ReactNode, useContext, useEffect, useState } from 'react';\n\nimport { cn, PopupContext } from './Interfaces';\n\n\n\nexport interface IPopupButtonProps {\n /** Popup id */\n popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n /** Whether is disabled */\n disabled?: boolean\n\n /** Button content */\n children?: ReactNode\n\n /** Class name */\n className?: string\n\n /** Button id */\n id?: string\n\n /** On click handler */\n onClick?(e: React.MouseEvent): void\n}\n\n\n\n/**\n * Button to natively change popup state\n * \n * @requires PopupLayer context\n */\nexport const PopupButton: FC<IPopupButtonProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [isActive, setIsActive] = useState(false);\n\n const Tag: keyof JSX.IntrinsicElements = props.as ?? 'button';\n\n\n\n // Handle isActive on context change\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.popupId);\n if (!node) return;\n\n setIsActive(node.isOpen);\n }, [ctx]);\n\n\n\n function invokePopup(e: React.MouseEvent) {\n ctx.invokePopup(props.popupId);\n\n if (props.onClick) props.onClick(e);\n }\n\n\n\n return <Tag\n tabIndex={0}\n disabled={props.disabled}\n aria-disabled={props.disabled}\n aria-haspopup={'dialog'}\n id={props.id}\n className={cn(`neko-popup-button`, isActive && 'neko-popup-button--active', props.className)}\n onClick={invokePopup}\n >\n {props.children}\n </Tag>;\n};","class EFKW extends Error {\n constructor(msg: string) {\n super(msg);\n\n this.name = 'error at [neko-popup]';\n }\n}\n\nexport default EFKW;","'use client';\n\nimport { FC, ReactNode, useEffect, useRef, useState } from 'react';\n\nimport EFKW from './components/ErrorComponents';\nimport { cn, IPopupNode, MountNodeArgs, PopupContext, ValueFromPath } from './Interfaces';\n\n\n\nexport interface IPopupLayerProps {\n /** React children */\n children?: ReactNode\n\n /** \n * Base z-index of the popups container\n * \n * @default 10000\n */\n baseZIndex?: number\n\n /**\n * Disable body scroll when there is at least one open popup\n * \n * @default true\n */\n disableBodyScrollOnActivePopup?: boolean\n}\n\n\n\n/**\n * Popup layer provides context & container for all popup windows & buttons\n */\nexport const PopupLayer: FC<IPopupLayerProps> = (props) => {\n const baseZIndex = props.baseZIndex ?? 10000;\n const disableBodyScrollOnActivePopup = props.disableBodyScrollOnActivePopup ?? true;\n\n const [nodes, setNodes] = useState<IPopupNode[]>([]);\n const [isScrollDisabled, setIsScrollDisabled] = useState(false);\n const [isAnyPopupActive, setIsAnyPopupActive] = useState(false);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n\n\n // Handle close closest to user popup on escape & scroll\n useEffect(() => {\n // === Handle close closest popup on escape\n const controller = new AbortController();\n\n window.addEventListener('keydown', e => {\n const key = e.key;\n\n if (key === 'Escape') {\n const maxZIndex = Math.max(...nodes.filter(el => el.isOpen).map(el => el.zIndex));\n const node = nodes.find(el => el.zIndex === maxZIndex);\n if (!node || node.disabled.includes('onEscape')) return;\n\n\n invokePopup(node.id, false);\n }\n }, { signal: controller.signal });\n\n\n\n // === Disable body scroll on active popup\n if (disableBodyScrollOnActivePopup) {\n let anyOpenNode = false;\n nodes.forEach(el => el.isOpen ? anyOpenNode = true : null);\n\n setIsScrollDisabled(anyOpenNode);\n }\n\n\n\n return () => {\n controller.abort();\n };\n }, [nodes]);\n\n // Handle isAnyPopupActive\n useEffect(() => {\n setIsAnyPopupActive(nodes.some(el => el.isOpen));\n }, [nodes]);\n\n // Handle body scroll\n useEffect(() => {\n if (isScrollDisabled) document.body.classList.add('neko-popup--noScroll');\n else document.body.classList.remove('neko-popup--noScroll');\n }, [isScrollDisabled]);\n\n\n\n /** Toggle popup state */\n function invokePopup(entityOrId: string | IPopupNode, forceState?: boolean) {\n const node = typeof entityOrId === 'string' ? nodes.find(el => el.id === entityOrId) : entityOrId;\n if (!node) throw new EFKW(typeof entityOrId === 'string' ? `Cannot find popup node with id #${entityOrId}` : `Entity is not assigned to the node`);\n\n const newState = forceState ?? !node.isOpen;\n\n // === Update node\n node.isOpen = newState;\n node.zIndex = newState ? Math.max(...nodes.map(el => el.zIndex), 0) + 1 : -1; // Make new popup invocation closer to user using larger z-index\n\n _updateNode(node);\n }\n\n /** Update node property */\n function updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>) {\n const node = nodes.find(el => el.id === id);\n if (!node) return;\n\n node[key] = value;\n\n _updateNode(node);\n }\n\n /** Update node in nodes array */\n function _updateNode(node: IPopupNode) {\n setNodes(prev => [...prev.filter(el => el.id !== node.id), node]);\n }\n\n /** Add new popup window to state */\n const mountNode = ({ id, isOpen, disabled }: MountNodeArgs) => invokePopup({ id, isOpen: false, disabled, zIndex: -1 }, isOpen);\n\n\n\n return <PopupContext.Provider value={{\n nodes,\n containerRef,\n invokePopup,\n mountNode,\n updateNodeProperty\n }}>\n {props.children}\n\n <section className={cn(`neko-popup-layer`, isAnyPopupActive && 'neko-popup-layer--active')} style={{ zIndex: baseZIndex }} ref={containerRef} />\n </PopupContext.Provider>;\n};","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\n\n\n\ntype StateSetter<S> = React.Dispatch<React.SetStateAction<S>>;\ntype InitialState<S> = S | (() => S);\n\nexport default function useMixedState<S = undefined>(): [S | undefined, StateSetter<S | undefined>];\nexport default function useMixedState<S>(initialState: InitialState<S>): [S, StateSetter<S>];\nexport default function useMixedState<S>(state: S, setter?: StateSetter<S>): [S, StateSetter<S>];\n\n\n\n/** \n * Use mixed state hook\n * \n * @param initialStateOrValue Initial state, can be undefined, value or function. If externalSetter not specified, will return default state\n * @param externalSetter External state setter. If specified will return external state\n */\nexport default function useMixedState<S>(initialStateOrValue?: InitialState<S>, externalSetter?: StateSetter<S>) {\n const isControlled = useMemo(() => arguments.length === 2 && externalSetter !== undefined, []);\n\n const [state, setter] = useState<S | undefined>(initialStateOrValue);\n\n\n\n // Propagate state update on external state update even if external setter is not provided\n useEffect(() => {\n if (!isControlled) {\n \n setter(initialStateOrValue);\n }\n }, [initialStateOrValue]);\n\n\n\n if (isControlled) {\n return [\n initialStateOrValue as S,\n externalSetter as StateSetter<S>\n ];\n }\n\n return [state, setter];\n}","'use client';\n\nimport { FC, ReactNode, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport useMixedState from './hooks/useMixedState';\nimport { cn, PopupContext, PopupWindowDisabledType, StateSetter } from './Interfaces';\n\n\n\nexport type PopupWindowAnimationType = 'fade' | 'scale' | null\n\n\n\nexport interface IPopupWindowProps {\n /** Popip id */\n id: string\n\n /** Popup content */\n children: ReactNode\n\n /** Whether is popup open state */\n isOpen?: boolean\n\n /** Whether is popup open state setter */\n setIsOpen?: StateSetter<boolean>\n\n /** Popup window class name */\n className?: string\n\n /** Popup backdrop class name */\n layerClassName?: string\n\n /** Disable state change on specified actions or disable fully */\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\n\n /** Keep popup in the DOM and do not unmount on close */\n keep?: boolean\n\n /** \n * Fire callback when popup is mounting\n */\n onBeforeEnter?(): void\n\n /** \n * Fire callback when popup appear animation finished\n */\n onAfterEnter?(ev: React.TransitionEvent): void\n\n /** \n * Fire callback when popup started hide animation or at initial mount\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(ev: React.TransitionEvent): void\n}\n\n\n\n/** \n * Popup window component\n * \n * @requires PopupLayer context provided\n */\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null); // React portal container\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen); // Whether is popup open\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen)); // Whether is popup mounted in DOM\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen)); // Whether is popup currently visible\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]); // Disabled events\n\n const layerRef = useRef<HTMLDivElement>(null);\n const isAnimationFinished = useRef(true);\n\n const animation: PopupWindowAnimationType = props.animation !== undefined ? props.animation : 'fade';\n\n\n\n // Handle disabled\n useLayoutEffect(() => {\n let disabled: PopupWindowDisabledType[] = [];\n\n if (typeof props.disabled === 'boolean') disabled = props.disabled ? ['onEscape', 'onLayer'] : [];\n else disabled = props.disabled ?? [];\n\n ctx.updateNodeProperty(props.id, 'disabled', disabled);\n }, [props.disabled]);\n\n // Handle enter/exit animation\n useLayoutEffect(() => {\n if (!isMounted || !isOpen) return;\n\n const id = requestAnimationFrame(() => {\n setIsVisible(true);\n });\n\n return () => cancelAnimationFrame(id);\n }, [isMounted, isOpen]);\n\n\n\n // Retrieve react portal and mount popup node in context\n useEffect(() => {\n const container = ctx.containerRef.current;\n if (!container) return;\n\n setContainer(container);\n\n ctx.mountNode({\n id: props.id,\n isOpen: Boolean(props.isOpen),\n disabled\n });\n }, []);\n\n // Handle toggle node on external isOpen update\n useEffect(() => {\n // Skip if node is not mounted yet\n if (!ctx.nodes.some(el => el.id === props.id)) return;\n\n ctx.invokePopup(props.id, props.isOpen);\n }, [props.isOpen]);\n\n // Handle node sync with context\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.id);\n if (!node) return;\n\n setIsOpen(node.isOpen);\n setDisabled(node.disabled);\n }, [ctx.nodes]);\n\n // Handle mount on open and exit animation on close\n useEffect(() => {\n isAnimationFinished.current = false;\n\n if (isOpen) {\n // On Before Enter\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n } else {\n // On Before Exit\n if (props.onBeforeExit) props.onBeforeExit();\n\n setIsVisible(false);\n }\n }, [isOpen]);\n\n // Handle backdrop clicks\n useEffect(() => {\n const layer = layerRef.current;\n if (!layer) return;\n\n layer.addEventListener('mousedown', ev => {\n // Pass inbound clicks\n if ((ev.target as HTMLElement).closest('.neko-popup')) return;\n\n ctx.invokePopup(props.id, false);\n });\n }, [isMounted]);\n\n\n\n function handleTransitionEnd(ev: React.TransitionEvent) {\n // Skip buble events\n if (!(ev.target as HTMLElement | undefined)?.className.includes('neko-popup-backdrop')) return;\n\n // On After Enter\n if (isVisible && isOpen) {\n if (props.onAfterEnter && !isAnimationFinished.current) props.onAfterEnter(ev);\n }\n\n // On After Exit\n if (!isVisible && !isOpen) {\n if (props.onAfterExit && !isAnimationFinished.current) props.onAfterExit(ev);\n\n setIsMounted(false);\n }\n\n isAnimationFinished.current = true;\n }\n\n\n\n if (!props.keep) {\n // Unmount if doNotUnmount is disabled (default state)\n if (!isMounted) return null;\n }\n\n return container && createPortal(<section\n className={cn(`neko-popup-backdrop`, isVisible && 'neko-popup-backdrop--active', props.layerClassName)}\n aria-hidden={!isVisible}\n style={{ cursor: disabled.includes('onLayer') ? 'default' : 'pointer' }}\n onTransitionEnd={handleTransitionEnd}\n ref={layerRef}\n >\n <article\n id={props.id}\n className={cn(`neko-popup`, isVisible && 'neko-popup--active', animation && `neko-popup--animation_${animation}`, props.className)}\n role=\"dialog\"\n aria-modal\n onClick={e => e.stopPropagation()}\n >\n {props.children}\n </article>\n </section>, container);\n};"],"names":["r","t","f","n","o","clsx","PopupContext","createContext","cn","PopupButton","props","ctx","useContext","isActive","setIsActive","useState","Tag","useEffect","node","el","invokePopup","e","jsx","EFKW","msg","PopupLayer","baseZIndex","disableBodyScrollOnActivePopup","nodes","setNodes","isScrollDisabled","setIsScrollDisabled","isAnyPopupActive","setIsAnyPopupActive","containerRef","useRef","controller","maxZIndex","anyOpenNode","entityOrId","forceState","newState","_updateNode","updateNodeProperty","id","key","value","prev","mountNode","isOpen","disabled","jsxs","useMixedState","initialStateOrValue","externalSetter","isControlled","useMemo","state","setter","PopupWindow","container","setContainer","setIsOpen","isMounted","setIsMounted","isVisible","setIsVisible","setDisabled","layerRef","isAnimationFinished","animation","useLayoutEffect","layer","ev","handleTransitionEnd","createPortal"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"index.es.js","sources":["../node_modules/clsx/dist/clsx.mjs","../src/_package/Interfaces.ts","../src/_package/PopupButton.tsx","../src/_package/components/ErrorComponents.ts","../src/_package/PopupLayer.tsx","../src/_package/hooks/useMixedState.ts","../src/_package/PopupWindow.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import React, { createContext, RefObject } from 'react';\nimport clsx from 'clsx';\n\n\n\n\nexport type PopupWindowDisabledType = 'onEscape' | 'onLayer';\nexport type StateSetter<S = any> = React.Dispatch<React.SetStateAction<S>>\nexport type MountNodeArgs = Pick<IPopupNode, 'id' | 'isOpen' | 'disabled'>\n\n/** Get value type from nested object path */\nexport type ValueFromPath<T, P> =\n P extends `${infer K}.${infer R}`\n ? K extends keyof T\n ? R extends keyof T[K]\n ? T[K][R]\n : never\n : never\n : P extends keyof T\n ? T[P]\n : never;\n\n\n\nexport interface IPopupNode {\n id: string\n isOpen: boolean\n zIndex: number\n disabled: PopupWindowDisabledType[]\n}\n\nexport interface IPopupContext {\n nodes: IPopupNode[]\n containerRef: RefObject<HTMLDivElement | null>\n\n invokePopup(id: string, forceState?: boolean): void\n mountNode(args: MountNodeArgs): void\n updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>): void\n}\n\n\n\nexport const PopupContext = createContext<IPopupContext>({} as IPopupContext);\nexport const cn = clsx;","'use client';\n\nimport { FC, JSX, ReactNode, useContext, useEffect, useState } from 'react';\n\nimport { cn, PopupContext } from './Interfaces';\n\n\n\nexport interface IPopupButtonProps {\n /** Popup id */\n popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n /** Whether is disabled */\n disabled?: boolean\n\n /** Button content */\n children?: ReactNode\n\n /** Class name */\n className?: string\n\n /** Button id */\n id?: string\n\n /** On click handler */\n onClick?(e: React.MouseEvent): void\n}\n\n\n\n/**\n * Button to natively change popup state\n * \n * @requires PopupLayer context\n */\nexport const PopupButton: FC<IPopupButtonProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [isActive, setIsActive] = useState(false);\n\n const Tag: keyof JSX.IntrinsicElements = props.as ?? 'button';\n\n\n\n // Handle isActive on context change\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.popupId);\n if (!node) return;\n\n setIsActive(node.isOpen);\n }, [ctx]);\n\n\n\n function invokePopup(e: React.MouseEvent) {\n ctx.invokePopup(props.popupId);\n\n if (props.onClick) props.onClick(e);\n }\n\n\n\n return <Tag\n tabIndex={0}\n disabled={props.disabled}\n aria-disabled={props.disabled}\n aria-haspopup={'dialog'}\n id={props.id}\n className={cn(`neko-popup-button`, isActive && 'neko-popup-button--active', props.className)}\n onClick={invokePopup}\n >\n {props.children}\n </Tag>;\n};","class EFKW extends Error {\n constructor(msg: string) {\n super(msg);\n\n this.name = 'error at [neko-popup]';\n }\n}\n\nexport default EFKW;","'use client';\n\nimport { FC, ReactNode, useEffect, useRef, useState } from 'react';\n\nimport EFKW from './components/ErrorComponents';\nimport { cn, IPopupNode, MountNodeArgs, PopupContext, ValueFromPath } from './Interfaces';\n\n\n\nexport interface IPopupLayerProps {\n /** React children */\n children?: ReactNode\n\n /** \n * Base z-index of the popups container\n * \n * @default 10000\n */\n baseZIndex?: number\n\n /**\n * Disable body scroll when there is at least one open popup\n * \n * @default true\n */\n disableBodyScrollOnActivePopup?: boolean\n}\n\n\n\n/**\n * Popup layer provides context & container for all popup windows & buttons\n */\nexport const PopupLayer: FC<IPopupLayerProps> = (props) => {\n const baseZIndex = props.baseZIndex ?? 10000;\n const disableBodyScrollOnActivePopup = props.disableBodyScrollOnActivePopup ?? true;\n\n const [nodes, setNodes] = useState<IPopupNode[]>([]);\n const [isScrollDisabled, setIsScrollDisabled] = useState(false);\n const [isAnyPopupActive, setIsAnyPopupActive] = useState(false);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n\n\n // Handle close closest to user popup on escape & scroll\n useEffect(() => {\n // === Handle close closest popup on escape\n const controller = new AbortController();\n\n window.addEventListener('keydown', e => {\n const key = e.key;\n\n if (key === 'Escape') {\n const maxZIndex = Math.max(...nodes.filter(el => el.isOpen).map(el => el.zIndex));\n const node = nodes.find(el => el.zIndex === maxZIndex);\n if (!node || node.disabled.includes('onEscape')) return;\n\n\n invokePopup(node.id, false);\n }\n }, { signal: controller.signal });\n\n\n\n // === Disable body scroll on active popup\n if (disableBodyScrollOnActivePopup) {\n let anyOpenNode = false;\n nodes.forEach(el => el.isOpen ? anyOpenNode = true : null);\n\n setIsScrollDisabled(anyOpenNode);\n }\n\n\n\n return () => {\n controller.abort();\n };\n }, [nodes]);\n\n // Handle isAnyPopupActive\n useEffect(() => {\n setIsAnyPopupActive(nodes.some(el => el.isOpen));\n }, [nodes]);\n\n // Handle body scroll\n useEffect(() => {\n if (isScrollDisabled) document.body.classList.add('neko-popup--noScroll');\n else document.body.classList.remove('neko-popup--noScroll');\n }, [isScrollDisabled]);\n\n\n\n /** Toggle popup state */\n function invokePopup(entityOrId: string | IPopupNode, forceState?: boolean) {\n const node = typeof entityOrId === 'string' ? nodes.find(el => el.id === entityOrId) : entityOrId;\n if (!node) throw new EFKW(typeof entityOrId === 'string' ? `Cannot find popup node with id #${entityOrId}` : `Entity is not assigned to the node`);\n\n const newState = forceState ?? !node.isOpen;\n\n // === Update node\n node.isOpen = newState;\n node.zIndex = newState ? Math.max(...nodes.map(el => el.zIndex), 0) + 1 : -1; // Make new popup invocation closer to user using larger z-index\n\n _updateNode(node);\n }\n\n /** Update node property */\n function updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>) {\n const node = nodes.find(el => el.id === id);\n if (!node) return;\n\n node[key] = value;\n\n _updateNode(node);\n }\n\n /** Update node in nodes array */\n function _updateNode(node: IPopupNode) {\n setNodes(prev => [...prev.filter(el => el.id !== node.id), node]);\n }\n\n /** Add new popup window to state */\n const mountNode = ({ id, isOpen, disabled }: MountNodeArgs) => invokePopup({ id, isOpen: false, disabled, zIndex: -1 }, isOpen);\n\n\n\n return <PopupContext.Provider value={{\n nodes,\n containerRef,\n invokePopup,\n mountNode,\n updateNodeProperty\n }}>\n {props.children}\n\n <section className={cn(`neko-popup-layer`, isAnyPopupActive && 'neko-popup-layer--active')} style={{ zIndex: baseZIndex }} ref={containerRef} />\n </PopupContext.Provider>;\n};","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\n\n\n\ntype StateSetter<S> = React.Dispatch<React.SetStateAction<S>>;\ntype InitialState<S> = S | (() => S);\n\nexport default function useMixedState<S = undefined>(): [S | undefined, StateSetter<S | undefined>];\nexport default function useMixedState<S>(initialState: InitialState<S>): [S, StateSetter<S>];\nexport default function useMixedState<S>(state: S, setter?: StateSetter<S>): [S, StateSetter<S>];\n\n\n\n/** \n * Use mixed state hook\n * \n * @param initialStateOrValue Initial state, can be undefined, value or function. If externalSetter not specified, will return default state\n * @param externalSetter External state setter. If specified will return external state\n */\nexport default function useMixedState<S>(initialStateOrValue?: InitialState<S>, externalSetter?: StateSetter<S>) {\n const isControlled = useMemo(() => arguments.length === 2 && externalSetter !== undefined, []);\n\n const [state, setter] = useState<S | undefined>(initialStateOrValue);\n\n\n\n // Propagate state update on external state update even if external setter is not provided\n useEffect(() => {\n if (!isControlled) {\n \n setter(initialStateOrValue);\n }\n }, [initialStateOrValue]);\n\n\n\n if (isControlled) {\n return [\n initialStateOrValue as S,\n externalSetter as StateSetter<S>\n ];\n }\n\n return [state, setter];\n}","'use client';\n\nimport { FC, ReactNode, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport useMixedState from './hooks/useMixedState';\nimport { cn, PopupContext, PopupWindowDisabledType, StateSetter } from './Interfaces';\n\n\n\nexport type PopupWindowAnimationType = 'fade' | 'scale' | null\n\n\n\nexport interface IPopupWindowProps {\n /** Popip id */\n id: string\n\n /** Popup content */\n children: ReactNode\n\n /** Whether is popup open state */\n isOpen?: boolean\n\n /** Whether is popup open state setter */\n setIsOpen?: StateSetter<boolean>\n\n /** Popup window class name */\n className?: string\n\n /** Popup backdrop class name */\n layerClassName?: string\n\n /** Disable state change on specified actions or disable fully */\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\n\n /** Keep popup in the DOM and do not unmount on close */\n keep?: boolean\n\n /** \n * Fire callback when popup is mounting\n */\n onBeforeEnter?(): void\n\n /** \n * Fire callback when popup appear animation finished\n */\n onAfterEnter?(ev: React.TransitionEvent): void\n\n /** \n * Fire callback when popup started hide animation or at initial mount\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(ev: React.TransitionEvent): void\n}\n\n\n\n/** \n * Popup window component\n * \n * @requires PopupLayer context provided\n */\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null); // React portal container\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen); // Whether is popup open\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen)); // Whether is popup mounted in DOM\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen)); // Whether is popup currently visible\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]); // Disabled events\n\n const layerRef = useRef<HTMLDivElement>(null);\n const isAnimationFinished = useRef(true);\n\n const animation: PopupWindowAnimationType = props.animation !== undefined ? props.animation : 'fade';\n\n\n\n // Handle disabled\n useLayoutEffect(() => {\n let disabled: PopupWindowDisabledType[] = [];\n\n if (typeof props.disabled === 'boolean') disabled = props.disabled ? ['onEscape', 'onLayer'] : [];\n else disabled = props.disabled ?? [];\n\n ctx.updateNodeProperty(props.id, 'disabled', disabled);\n }, [props.disabled]);\n\n // Handle enter/exit animation\n useLayoutEffect(() => {\n if (!isMounted || !isOpen) return;\n\n const id = requestAnimationFrame(() => {\n setIsVisible(true);\n });\n\n return () => cancelAnimationFrame(id);\n }, [isMounted, isOpen]);\n\n\n\n // Retrieve react portal and mount popup node in context\n useEffect(() => {\n const container = ctx.containerRef.current;\n if (!container) return;\n\n setContainer(container);\n\n ctx.mountNode({\n id: props.id,\n isOpen: Boolean(props.isOpen),\n disabled\n });\n }, []);\n\n // Handle toggle node on external isOpen update\n useEffect(() => {\n // Skip if node is not mounted yet\n if (!ctx.nodes.some(el => el.id === props.id)) return;\n\n ctx.invokePopup(props.id, props.isOpen);\n }, [props.isOpen]);\n\n // Handle node sync with context\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.id);\n if (!node) return;\n\n setIsOpen(node.isOpen);\n setDisabled(node.disabled);\n }, [ctx.nodes]);\n\n // Handle mount on open and exit animation on close\n useEffect(() => {\n isAnimationFinished.current = false;\n\n if (isOpen) {\n // On Before Enter\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n } else {\n // On Before Exit\n if (props.onBeforeExit) props.onBeforeExit();\n\n setIsVisible(false);\n }\n }, [isOpen]);\n\n // Handle backdrop clicks\n useEffect(() => {\n const layer = layerRef.current;\n if (!layer) return;\n\n layer.addEventListener('mousedown', ev => {\n // Pass inbound clicks\n if ((ev.target as HTMLElement).closest('.neko-popup')) return;\n\n ctx.invokePopup(props.id, false);\n });\n }, [isMounted]);\n\n\n\n function handleTransitionEnd(ev: React.TransitionEvent) {\n // Skip buble events\n if (ev.target !== ev.currentTarget) return;\n\n // On After Enter\n if (isVisible && isOpen) {\n if (props.onAfterEnter && !isAnimationFinished.current) props.onAfterEnter(ev);\n }\n\n // On After Exit\n if (!isVisible && !isOpen) {\n if (props.onAfterExit && !isAnimationFinished.current) props.onAfterExit(ev);\n\n setIsMounted(false);\n }\n\n isAnimationFinished.current = true;\n }\n\n\n\n if (!props.keep) {\n // Unmount if doNotUnmount is disabled (default state)\n if (!isMounted) return null;\n }\n\n return container && createPortal(<section\n className={cn(`neko-popup-backdrop`, isVisible && 'neko-popup-backdrop--active', props.layerClassName)}\n aria-hidden={!isVisible}\n style={{\n cursor: disabled.includes('onLayer') ? 'default' : 'pointer',\n zIndex: props.keep ? 100 : undefined\n }}\n onTransitionEnd={handleTransitionEnd}\n ref={layerRef}\n >\n <article\n id={props.id}\n className={cn(`neko-popup`, isVisible && 'neko-popup--active', animation && `neko-popup--animation_${animation}`, props.className)}\n role=\"dialog\"\n aria-modal\n onClick={e => e.stopPropagation()}\n >\n {props.children}\n </article>\n </section>, container);\n};"],"names":["r","t","f","n","o","clsx","PopupContext","createContext","cn","PopupButton","props","ctx","useContext","isActive","setIsActive","useState","Tag","useEffect","node","el","invokePopup","e","jsx","EFKW","msg","PopupLayer","baseZIndex","disableBodyScrollOnActivePopup","nodes","setNodes","isScrollDisabled","setIsScrollDisabled","isAnyPopupActive","setIsAnyPopupActive","containerRef","useRef","controller","maxZIndex","anyOpenNode","entityOrId","forceState","newState","_updateNode","updateNodeProperty","id","key","value","prev","mountNode","isOpen","disabled","jsxs","useMixedState","initialStateOrValue","externalSetter","isControlled","useMemo","state","setter","PopupWindow","container","setContainer","setIsOpen","isMounted","setIsMounted","isVisible","setIsVisible","setDisabled","layerRef","isAnimationFinished","animation","useLayoutEffect","layer","ev","handleTransitionEnd","createPortal"],"mappings":";;;AAAA,SAASA,EAAE,GAAE;AAAC,MAAIC,GAAEC,GAAEC,IAAE;AAAG,MAAa,OAAO,KAAjB,YAA8B,OAAO,KAAjB,SAAmB,CAAAA,KAAG;AAAA,WAAoB,OAAO,KAAjB,SAAmB,KAAG,MAAM,QAAQ,CAAC,GAAE;AAAC,QAAIC,IAAE,EAAE;AAAO,SAAIH,IAAE,GAAEA,IAAEG,GAAEH,IAAI,GAAEA,CAAC,MAAIC,IAAEF,EAAE,EAAEC,CAAC,CAAC,OAAKE,MAAIA,KAAG,MAAKA,KAAGD;AAAA,EAAE,MAAM,MAAIA,KAAK,EAAE,GAAEA,CAAC,MAAIC,MAAIA,KAAG,MAAKA,KAAGD;AAAG,SAAOC;AAAC;AAAQ,SAASE,IAAM;AAAC,WAAQ,GAAEJ,GAAEC,IAAE,GAAEC,IAAE,IAAGC,IAAE,UAAU,QAAOF,IAAEE,GAAEF,IAAI,EAAC,IAAE,UAAUA,CAAC,OAAKD,IAAED,EAAE,CAAC,OAAKG,MAAIA,KAAG,MAAKA,KAAGF;AAAG,SAAOE;AAAC;AC0CxW,MAAMG,IAAeC,EAA6B,EAAmB,GAC/DC,IAAKH,GCDLI,IAAqC,CAACC,MAAU;AAC3D,QAAMC,IAAMC,EAAWN,CAAY,GAE7B,CAACO,GAAUC,CAAW,IAAIC,EAAS,EAAK,GAExCC,IAAmCN,EAAM,MAAM;AAKrD,EAAAO,EAAU,MAAM;AACd,UAAMC,IAAOP,EAAI,MAAM,KAAK,OAAMQ,EAAG,OAAOT,EAAM,OAAO;AACzD,IAAKQ,KAELJ,EAAYI,EAAK,MAAM;AAAA,EACzB,GAAG,CAACP,CAAG,CAAC;AAIR,WAASS,EAAYC,GAAqB;AACxC,IAAAV,EAAI,YAAYD,EAAM,OAAO,GAEzBA,EAAM,WAASA,EAAM,QAAQW,CAAC;AAAA,EACpC;AAIA,SAAO,gBAAAC;AAAA,IAACN;AAAA,IAAA;AAAA,MACN,UAAU;AAAA,MACV,UAAUN,EAAM;AAAA,MAChB,iBAAeA,EAAM;AAAA,MACrB,iBAAe;AAAA,MACf,IAAIA,EAAM;AAAA,MACV,WAAWF,EAAG,qBAAqBK,KAAY,6BAA6BH,EAAM,SAAS;AAAA,MAC3F,SAASU;AAAA,MAER,UAAAV,EAAM;AAAA,IAAA;AAAA,EAAA;AAEX;AChFA,MAAMa,UAAa,MAAM;AAAA,EACvB,YAAYC,GAAa;AACvB,UAAMA,CAAG,GAET,KAAK,OAAO;AAAA,EACd;AACF;AC2BO,MAAMC,IAAmC,CAACf,MAAU;AACzD,QAAMgB,IAAahB,EAAM,cAAc,KACjCiB,IAAiCjB,EAAM,kCAAkC,IAEzE,CAACkB,GAAOC,CAAQ,IAAId,EAAuB,CAAA,CAAE,GAC7C,CAACe,GAAkBC,CAAmB,IAAIhB,EAAS,EAAK,GACxD,CAACiB,GAAkBC,CAAmB,IAAIlB,EAAS,EAAK,GAExDmB,IAAeC,EAAuB,IAAI;AAKhD,EAAAlB,EAAU,MAAM;AAEd,UAAMmB,IAAa,IAAI,gBAAA;AAkBvB,QAhBA,OAAO,iBAAiB,WAAW,CAAAf,MAAK;AAGtC,UAFYA,EAAE,QAEF,UAAU;AACpB,cAAMgB,IAAY,KAAK,IAAI,GAAGT,EAAM,OAAO,CAAAT,MAAMA,EAAG,MAAM,EAAE,IAAI,CAAAA,MAAMA,EAAG,MAAM,CAAC,GAC1ED,IAAOU,EAAM,KAAK,CAAAT,MAAMA,EAAG,WAAWkB,CAAS;AACrD,YAAI,CAACnB,KAAQA,EAAK,SAAS,SAAS,UAAU,EAAG;AAGjD,QAAAE,EAAYF,EAAK,IAAI,EAAK;AAAA,MAC5B;AAAA,IACF,GAAG,EAAE,QAAQkB,EAAW,QAAQ,GAK5BT,GAAgC;AAClC,UAAIW,IAAc;AAClB,MAAAV,EAAM,QAAQ,CAAAT,MAAMA,EAAG,SAASmB,IAAc,KAAO,IAAI,GAEzDP,EAAoBO,CAAW;AAAA,IACjC;AAIA,WAAO,MAAM;AACX,MAAAF,EAAW,MAAA;AAAA,IACb;AAAA,EACF,GAAG,CAACR,CAAK,CAAC,GAGVX,EAAU,MAAM;AACd,IAAAgB,EAAoBL,EAAM,KAAK,CAAAT,MAAMA,EAAG,MAAM,CAAC;AAAA,EACjD,GAAG,CAACS,CAAK,CAAC,GAGVX,EAAU,MAAM;AACd,IAAIa,IAAkB,SAAS,KAAK,UAAU,IAAI,sBAAsB,IACnE,SAAS,KAAK,UAAU,OAAO,sBAAsB;AAAA,EAC5D,GAAG,CAACA,CAAgB,CAAC;AAKrB,WAASV,EAAYmB,GAAiCC,GAAsB;AAC1E,UAAMtB,IAAO,OAAOqB,KAAe,WAAWX,EAAM,KAAK,CAAAT,MAAMA,EAAG,OAAOoB,CAAU,IAAIA;AACvF,QAAI,CAACrB,EAAM,OAAM,IAAIK,EAAK,OAAOgB,KAAe,WAAW,mCAAmCA,CAAU,KAAK,oCAAoC;AAEjJ,UAAME,IAAWD,KAAc,CAACtB,EAAK;AAGrC,IAAAA,EAAK,SAASuB,GACdvB,EAAK,SAASuB,IAAW,KAAK,IAAI,GAAGb,EAAM,IAAI,CAAAT,MAAMA,EAAG,MAAM,GAAG,CAAC,IAAI,IAAI,IAE1EuB,EAAYxB,CAAI;AAAA,EAClB;AAGA,WAASyB,EAA+CC,GAAYC,GAAQC,GAAqC;AAC/G,UAAM5B,IAAOU,EAAM,KAAK,CAAAT,MAAMA,EAAG,OAAOyB,CAAE;AAC1C,IAAK1B,MAELA,EAAK2B,CAAG,IAAIC,GAEZJ,EAAYxB,CAAI;AAAA,EAClB;AAGA,WAASwB,EAAYxB,GAAkB;AACrC,IAAAW,EAAS,CAAAkB,MAAQ,CAAC,GAAGA,EAAK,OAAO,CAAA5B,MAAMA,EAAG,OAAOD,EAAK,EAAE,GAAGA,CAAI,CAAC;AAAA,EAClE;AAGA,QAAM8B,IAAY,CAAC,EAAE,IAAAJ,GAAI,QAAAK,GAAQ,UAAAC,QAA8B9B,EAAY,EAAE,IAAAwB,GAAI,QAAQ,IAAO,UAAAM,GAAU,QAAQ,GAAA,GAAMD,CAAM;AAI9H,SAAO,gBAAAE,EAAC7C,EAAa,UAAb,EAAsB,OAAO;AAAA,IACnC,OAAAsB;AAAA,IACA,cAAAM;AAAA,IACA,aAAAd;AAAA,IACA,WAAA4B;AAAA,IACA,oBAAAL;AAAA,EAAA,GAEC,UAAA;AAAA,IAAAjC,EAAM;AAAA,IAEP,gBAAAY,EAAC,WAAA,EAAQ,WAAWd,EAAG,oBAAoBwB,KAAoB,0BAA0B,GAAG,OAAO,EAAE,QAAQN,EAAA,GAAc,KAAKQ,EAAA,CAAc;AAAA,EAAA,GAChJ;AACF;ACpHA,SAAwBkB,EAAiBC,GAAuCC,GAAiC;AAC/G,QAAMC,IAAeC,EAAQ,MAAM,UAAU,WAAW,KAAKF,MAAmB,QAAW,EAAE,GAEvF,CAACG,GAAOC,CAAM,IAAI3C,EAAwBsC,CAAmB;AAcnE,SATApC,EAAU,MAAM;AACd,IAAKsC,KAEHG,EAAOL,CAAmB;AAAA,EAE9B,GAAG,CAACA,CAAmB,CAAC,GAIpBE,IACK;AAAA,IACLF;AAAA,IACAC;AAAA,EAAA,IAIG,CAACG,GAAOC,CAAM;AACvB;AC2BO,MAAMC,IAAqC,CAACjD,MAAU;AAC3D,QAAMC,IAAMC,EAAWN,CAAY,GAE7B,CAACsD,GAAWC,CAAY,IAAI9C,EAAgC,IAAI,GAChE,CAACkC,GAAQa,CAAS,IAAIV,EAAc1C,EAAM,UAAU,IAAOA,EAAM,SAAS,GAC1E,CAACqD,GAAWC,CAAY,IAAIjD,EAAS,EAAQL,EAAM,MAAO,GAC1D,CAACuD,GAAWC,CAAY,IAAInD,EAAS,EAAQL,EAAM,MAAO,GAC1D,CAACwC,GAAUiB,CAAW,IAAIpD,EAAoC,CAAA,CAAE,GAEhEqD,IAAWjC,EAAuB,IAAI,GACtCkC,IAAsBlC,EAAO,EAAI,GAEjCmC,IAAsC5D,EAAM,cAAc,SAAYA,EAAM,YAAY;AAK9F,EAAA6D,EAAgB,MAAM;AACpB,QAAIrB,IAAsC,CAAA;AAE1C,IAAI,OAAOxC,EAAM,YAAa,YAAWwC,IAAWxC,EAAM,WAAW,CAAC,YAAY,SAAS,IAAI,CAAA,IAC1FwC,IAAWxC,EAAM,YAAY,CAAA,GAElCC,EAAI,mBAAmBD,EAAM,IAAI,YAAYwC,CAAQ;AAAA,EACvD,GAAG,CAACxC,EAAM,QAAQ,CAAC,GAGnB6D,EAAgB,MAAM;AACpB,QAAI,CAACR,KAAa,CAACd,EAAQ;AAE3B,UAAML,IAAK,sBAAsB,MAAM;AACrC,MAAAsB,EAAa,EAAI;AAAA,IACnB,CAAC;AAED,WAAO,MAAM,qBAAqBtB,CAAE;AAAA,EACtC,GAAG,CAACmB,GAAWd,CAAM,CAAC,GAKtBhC,EAAU,MAAM;AACd,UAAM2C,IAAYjD,EAAI,aAAa;AACnC,IAAKiD,MAELC,EAAaD,CAAS,GAEtBjD,EAAI,UAAU;AAAA,MACZ,IAAID,EAAM;AAAA,MACV,QAAQ,EAAQA,EAAM;AAAA,MACtB,UAAAwC;AAAA,IAAA,CACD;AAAA,EACH,GAAG,CAAA,CAAE,GAGLjC,EAAU,MAAM;AAEd,IAAKN,EAAI,MAAM,KAAK,OAAMQ,EAAG,OAAOT,EAAM,EAAE,KAE5CC,EAAI,YAAYD,EAAM,IAAIA,EAAM,MAAM;AAAA,EACxC,GAAG,CAACA,EAAM,MAAM,CAAC,GAGjBO,EAAU,MAAM;AACd,UAAMC,IAAOP,EAAI,MAAM,KAAK,OAAMQ,EAAG,OAAOT,EAAM,EAAE;AACpD,IAAKQ,MAEL4C,EAAU5C,EAAK,MAAM,GACrBiD,EAAYjD,EAAK,QAAQ;AAAA,EAC3B,GAAG,CAACP,EAAI,KAAK,CAAC,GAGdM,EAAU,MAAM;AACd,IAAAoD,EAAoB,UAAU,IAE1BpB,KAEEvC,EAAM,iBAAeA,EAAM,cAAA,GAE/BsD,EAAa,EAAI,MAGbtD,EAAM,gBAAcA,EAAM,aAAA,GAE9BwD,EAAa,EAAK;AAAA,EAEtB,GAAG,CAACjB,CAAM,CAAC,GAGXhC,EAAU,MAAM;AACd,UAAMuD,IAAQJ,EAAS;AACvB,IAAKI,KAELA,EAAM,iBAAiB,aAAa,CAAAC,MAAM;AAExC,MAAKA,EAAG,OAAuB,QAAQ,aAAa,KAEpD9D,EAAI,YAAYD,EAAM,IAAI,EAAK;AAAA,IACjC,CAAC;AAAA,EACH,GAAG,CAACqD,CAAS,CAAC;AAId,WAASW,EAAoBD,GAA2B;AAEtD,IAAIA,EAAG,WAAWA,EAAG,kBAGjBR,KAAahB,KACXvC,EAAM,gBAAgB,CAAC2D,EAAoB,WAAS3D,EAAM,aAAa+D,CAAE,GAI3E,CAACR,KAAa,CAAChB,MACbvC,EAAM,eAAe,CAAC2D,EAAoB,WAAS3D,EAAM,YAAY+D,CAAE,GAE3ET,EAAa,EAAK,IAGpBK,EAAoB,UAAU;AAAA,EAChC;AAIA,SAAI,CAAC3D,EAAM,QAEL,CAACqD,IAAkB,OAGlBH,KAAae,EAAa,gBAAArD;AAAA,IAAC;AAAA,IAAA;AAAA,MAChC,WAAWd,EAAG,uBAAuByD,KAAa,+BAA+BvD,EAAM,cAAc;AAAA,MACrG,eAAa,CAACuD;AAAA,MACd,OAAO;AAAA,QACL,QAAQf,EAAS,SAAS,SAAS,IAAI,YAAY;AAAA,QACnD,QAAQxC,EAAM,OAAO,MAAM;AAAA,MAAA;AAAA,MAE7B,iBAAiBgE;AAAA,MACjB,KAAKN;AAAA,MAEL,UAAA,gBAAA9C;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAIZ,EAAM;AAAA,UACV,WAAWF,EAAG,cAAcyD,KAAa,sBAAsBK,KAAa,yBAAyBA,CAAS,IAAI5D,EAAM,SAAS;AAAA,UACjI,MAAK;AAAA,UACL,cAAU;AAAA,UACV,SAAS,CAAAW,MAAKA,EAAE,gBAAA;AAAA,UAEf,UAAAX,EAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IACT;AAAA,EAAA,GACUkD,CAAS;AACvB;","x_google_ignoreList":[0]}
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(c,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("react/jsx-runtime"),require("react"),require("react-dom")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom"],r):(c=typeof globalThis<"u"?globalThis:c||self,r(c["neko-popup"]={},c.jsxRuntime,c.React,c.ReactDOM))})(this,(function(c,r,o,
|
|
1
|
+
(function(c,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("react/jsx-runtime"),require("react"),require("react-dom")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom"],r):(c=typeof globalThis<"u"?globalThis:c||self,r(c["neko-popup"]={},c.jsxRuntime,c.React,c.ReactDOM))})(this,(function(c,r,o,O){"use strict";function I(e){var i,d,t="";if(typeof e=="string"||typeof e=="number")t+=e;else if(typeof e=="object")if(Array.isArray(e)){var u=e.length;for(i=0;i<u;i++)e[i]&&(d=I(e[i]))&&(t&&(t+=" "),t+=d)}else for(d in e)e[d]&&(t&&(t+=" "),t+=d);return t}function S(){for(var e,i,d=0,t="",u=arguments.length;d<u;d++)(e=arguments[d])&&(i=I(e))&&(t&&(t+=" "),t+=i);return t}const g=o.createContext({}),P=S,N=e=>{const i=o.useContext(g),[d,t]=o.useState(!1),u=e.as??"button";o.useEffect(()=>{const l=i.nodes.find(y=>y.id===e.popupId);l&&t(l.isOpen)},[i]);function b(l){i.invokePopup(e.popupId),e.onClick&&e.onClick(l)}return r.jsx(u,{tabIndex:0,disabled:e.disabled,"aria-disabled":e.disabled,"aria-haspopup":"dialog",id:e.id,className:P("neko-popup-button",d&&"neko-popup-button--active",e.className),onClick:b,children:e.children})};class C extends Error{constructor(i){super(i),this.name="error at [neko-popup]"}}const w=e=>{const i=e.baseZIndex??1e4,d=e.disableBodyScrollOnActivePopup??!0,[t,u]=o.useState([]),[b,l]=o.useState(!1),[y,m]=o.useState(!1),x=o.useRef(null);o.useEffect(()=>{const s=new AbortController;if(window.addEventListener("keydown",a=>{if(a.key==="Escape"){const f=Math.max(...t.filter(v=>v.isOpen).map(v=>v.zIndex)),p=t.find(v=>v.zIndex===f);if(!p||p.disabled.includes("onEscape"))return;k(p.id,!1)}},{signal:s.signal}),d){let a=!1;t.forEach(n=>n.isOpen?a=!0:null),l(a)}return()=>{s.abort()}},[t]),o.useEffect(()=>{m(t.some(s=>s.isOpen))},[t]),o.useEffect(()=>{b?document.body.classList.add("neko-popup--noScroll"):document.body.classList.remove("neko-popup--noScroll")},[b]);function k(s,a){const n=typeof s=="string"?t.find(p=>p.id===s):s;if(!n)throw new C(typeof s=="string"?`Cannot find popup node with id #${s}`:"Entity is not assigned to the node");const f=a??!n.isOpen;n.isOpen=f,n.zIndex=f?Math.max(...t.map(p=>p.zIndex),0)+1:-1,h(n)}function A(s,a,n){const f=t.find(p=>p.id===s);f&&(f[a]=n,h(f))}function h(s){u(a=>[...a.filter(n=>n.id!==s.id),s])}const E=({id:s,isOpen:a,disabled:n})=>k({id:s,isOpen:!1,disabled:n,zIndex:-1},a);return r.jsxs(g.Provider,{value:{nodes:t,containerRef:x,invokePopup:k,mountNode:E,updateNodeProperty:A},children:[e.children,r.jsx("section",{className:P("neko-popup-layer",y&&"neko-popup-layer--active"),style:{zIndex:i},ref:x})]})};function B(e,i){const d=o.useMemo(()=>arguments.length===2&&i!==void 0,[]),[t,u]=o.useState(e);return o.useEffect(()=>{d||u(e)},[e]),d?[e,i]:[t,u]}const L=e=>{const i=o.useContext(g),[d,t]=o.useState(null),[u,b]=B(e.isOpen??!1,e.setIsOpen),[l,y]=o.useState(!!e.isOpen),[m,x]=o.useState(!!e.isOpen),[k,A]=o.useState([]),h=o.useRef(null),E=o.useRef(!0),s=e.animation!==void 0?e.animation:"fade";o.useLayoutEffect(()=>{let n=[];typeof e.disabled=="boolean"?n=e.disabled?["onEscape","onLayer"]:[]:n=e.disabled??[],i.updateNodeProperty(e.id,"disabled",n)},[e.disabled]),o.useLayoutEffect(()=>{if(!l||!u)return;const n=requestAnimationFrame(()=>{x(!0)});return()=>cancelAnimationFrame(n)},[l,u]),o.useEffect(()=>{const n=i.containerRef.current;n&&(t(n),i.mountNode({id:e.id,isOpen:!!e.isOpen,disabled:k}))},[]),o.useEffect(()=>{i.nodes.some(n=>n.id===e.id)&&i.invokePopup(e.id,e.isOpen)},[e.isOpen]),o.useEffect(()=>{const n=i.nodes.find(f=>f.id===e.id);n&&(b(n.isOpen),A(n.disabled))},[i.nodes]),o.useEffect(()=>{E.current=!1,u?(e.onBeforeEnter&&e.onBeforeEnter(),y(!0)):(e.onBeforeExit&&e.onBeforeExit(),x(!1))},[u]),o.useEffect(()=>{const n=h.current;n&&n.addEventListener("mousedown",f=>{f.target.closest(".neko-popup")||i.invokePopup(e.id,!1)})},[l]);function a(n){n.target===n.currentTarget&&(m&&u&&e.onAfterEnter&&!E.current&&e.onAfterEnter(n),!m&&!u&&(e.onAfterExit&&!E.current&&e.onAfterExit(n),y(!1)),E.current=!0)}return!e.keep&&!l?null:d&&O.createPortal(r.jsx("section",{className:P("neko-popup-backdrop",m&&"neko-popup-backdrop--active",e.layerClassName),"aria-hidden":!m,style:{cursor:k.includes("onLayer")?"default":"pointer",zIndex:e.keep?100:void 0},onTransitionEnd:a,ref:h,children:r.jsx("article",{id:e.id,className:P("neko-popup",m&&"neko-popup--active",s&&`neko-popup--animation_${s}`,e.className),role:"dialog","aria-modal":!0,onClick:n=>n.stopPropagation(),children:e.children})}),d)};c.PopupButton=N,c.PopupLayer=w,c.PopupWindow=L,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
|
|
2
2
|
//# sourceMappingURL=index.umd.js.map
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../node_modules/clsx/dist/clsx.mjs","../src/_package/Interfaces.ts","../src/_package/PopupButton.tsx","../src/_package/components/ErrorComponents.ts","../src/_package/PopupLayer.tsx","../src/_package/hooks/useMixedState.ts","../src/_package/PopupWindow.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import React, { createContext, RefObject } from 'react';\nimport clsx from 'clsx';\n\n\n\n\nexport type PopupWindowDisabledType = 'onEscape' | 'onLayer';\nexport type StateSetter<S = any> = React.Dispatch<React.SetStateAction<S>>\nexport type MountNodeArgs = Pick<IPopupNode, 'id' | 'isOpen' | 'disabled'>\n\n/** Get value type from nested object path */\nexport type ValueFromPath<T, P> =\n P extends `${infer K}.${infer R}`\n ? K extends keyof T\n ? R extends keyof T[K]\n ? T[K][R]\n : never\n : never\n : P extends keyof T\n ? T[P]\n : never;\n\n\n\nexport interface IPopupNode {\n id: string\n isOpen: boolean\n zIndex: number\n disabled: PopupWindowDisabledType[]\n}\n\nexport interface IPopupContext {\n nodes: IPopupNode[]\n containerRef: RefObject<HTMLDivElement | null>\n\n invokePopup(id: string, forceState?: boolean): void\n mountNode(args: MountNodeArgs): void\n updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>): void\n}\n\n\n\nexport const PopupContext = createContext<IPopupContext>({} as IPopupContext);\nexport const cn = clsx;","'use client';\n\nimport { FC, JSX, ReactNode, useContext, useEffect, useState } from 'react';\n\nimport { cn, PopupContext } from './Interfaces';\n\n\n\nexport interface IPopupButtonProps {\n /** Popup id */\n popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n /** Whether is disabled */\n disabled?: boolean\n\n /** Button content */\n children?: ReactNode\n\n /** Class name */\n className?: string\n\n /** Button id */\n id?: string\n\n /** On click handler */\n onClick?(e: React.MouseEvent): void\n}\n\n\n\n/**\n * Button to natively change popup state\n * \n * @requires PopupLayer context\n */\nexport const PopupButton: FC<IPopupButtonProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [isActive, setIsActive] = useState(false);\n\n const Tag: keyof JSX.IntrinsicElements = props.as ?? 'button';\n\n\n\n // Handle isActive on context change\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.popupId);\n if (!node) return;\n\n setIsActive(node.isOpen);\n }, [ctx]);\n\n\n\n function invokePopup(e: React.MouseEvent) {\n ctx.invokePopup(props.popupId);\n\n if (props.onClick) props.onClick(e);\n }\n\n\n\n return <Tag\n tabIndex={0}\n disabled={props.disabled}\n aria-disabled={props.disabled}\n aria-haspopup={'dialog'}\n id={props.id}\n className={cn(`neko-popup-button`, isActive && 'neko-popup-button--active', props.className)}\n onClick={invokePopup}\n >\n {props.children}\n </Tag>;\n};","class EFKW extends Error {\n constructor(msg: string) {\n super(msg);\n\n this.name = 'error at [neko-popup]';\n }\n}\n\nexport default EFKW;","'use client';\n\nimport { FC, ReactNode, useEffect, useRef, useState } from 'react';\n\nimport EFKW from './components/ErrorComponents';\nimport { cn, IPopupNode, MountNodeArgs, PopupContext, ValueFromPath } from './Interfaces';\n\n\n\nexport interface IPopupLayerProps {\n /** React children */\n children?: ReactNode\n\n /** \n * Base z-index of the popups container\n * \n * @default 10000\n */\n baseZIndex?: number\n\n /**\n * Disable body scroll when there is at least one open popup\n * \n * @default true\n */\n disableBodyScrollOnActivePopup?: boolean\n}\n\n\n\n/**\n * Popup layer provides context & container for all popup windows & buttons\n */\nexport const PopupLayer: FC<IPopupLayerProps> = (props) => {\n const baseZIndex = props.baseZIndex ?? 10000;\n const disableBodyScrollOnActivePopup = props.disableBodyScrollOnActivePopup ?? true;\n\n const [nodes, setNodes] = useState<IPopupNode[]>([]);\n const [isScrollDisabled, setIsScrollDisabled] = useState(false);\n const [isAnyPopupActive, setIsAnyPopupActive] = useState(false);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n\n\n // Handle close closest to user popup on escape & scroll\n useEffect(() => {\n // === Handle close closest popup on escape\n const controller = new AbortController();\n\n window.addEventListener('keydown', e => {\n const key = e.key;\n\n if (key === 'Escape') {\n const maxZIndex = Math.max(...nodes.filter(el => el.isOpen).map(el => el.zIndex));\n const node = nodes.find(el => el.zIndex === maxZIndex);\n if (!node || node.disabled.includes('onEscape')) return;\n\n\n invokePopup(node.id, false);\n }\n }, { signal: controller.signal });\n\n\n\n // === Disable body scroll on active popup\n if (disableBodyScrollOnActivePopup) {\n let anyOpenNode = false;\n nodes.forEach(el => el.isOpen ? anyOpenNode = true : null);\n\n setIsScrollDisabled(anyOpenNode);\n }\n\n\n\n return () => {\n controller.abort();\n };\n }, [nodes]);\n\n // Handle isAnyPopupActive\n useEffect(() => {\n setIsAnyPopupActive(nodes.some(el => el.isOpen));\n }, [nodes]);\n\n // Handle body scroll\n useEffect(() => {\n if (isScrollDisabled) document.body.classList.add('neko-popup--noScroll');\n else document.body.classList.remove('neko-popup--noScroll');\n }, [isScrollDisabled]);\n\n\n\n /** Toggle popup state */\n function invokePopup(entityOrId: string | IPopupNode, forceState?: boolean) {\n const node = typeof entityOrId === 'string' ? nodes.find(el => el.id === entityOrId) : entityOrId;\n if (!node) throw new EFKW(typeof entityOrId === 'string' ? `Cannot find popup node with id #${entityOrId}` : `Entity is not assigned to the node`);\n\n const newState = forceState ?? !node.isOpen;\n\n // === Update node\n node.isOpen = newState;\n node.zIndex = newState ? Math.max(...nodes.map(el => el.zIndex), 0) + 1 : -1; // Make new popup invocation closer to user using larger z-index\n\n _updateNode(node);\n }\n\n /** Update node property */\n function updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>) {\n const node = nodes.find(el => el.id === id);\n if (!node) return;\n\n node[key] = value;\n\n _updateNode(node);\n }\n\n /** Update node in nodes array */\n function _updateNode(node: IPopupNode) {\n setNodes(prev => [...prev.filter(el => el.id !== node.id), node]);\n }\n\n /** Add new popup window to state */\n const mountNode = ({ id, isOpen, disabled }: MountNodeArgs) => invokePopup({ id, isOpen: false, disabled, zIndex: -1 }, isOpen);\n\n\n\n return <PopupContext.Provider value={{\n nodes,\n containerRef,\n invokePopup,\n mountNode,\n updateNodeProperty\n }}>\n {props.children}\n\n <section className={cn(`neko-popup-layer`, isAnyPopupActive && 'neko-popup-layer--active')} style={{ zIndex: baseZIndex }} ref={containerRef} />\n </PopupContext.Provider>;\n};","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\n\n\n\ntype StateSetter<S> = React.Dispatch<React.SetStateAction<S>>;\ntype InitialState<S> = S | (() => S);\n\nexport default function useMixedState<S = undefined>(): [S | undefined, StateSetter<S | undefined>];\nexport default function useMixedState<S>(initialState: InitialState<S>): [S, StateSetter<S>];\nexport default function useMixedState<S>(state: S, setter?: StateSetter<S>): [S, StateSetter<S>];\n\n\n\n/** \n * Use mixed state hook\n * \n * @param initialStateOrValue Initial state, can be undefined, value or function. If externalSetter not specified, will return default state\n * @param externalSetter External state setter. If specified will return external state\n */\nexport default function useMixedState<S>(initialStateOrValue?: InitialState<S>, externalSetter?: StateSetter<S>) {\n const isControlled = useMemo(() => arguments.length === 2 && externalSetter !== undefined, []);\n\n const [state, setter] = useState<S | undefined>(initialStateOrValue);\n\n\n\n // Propagate state update on external state update even if external setter is not provided\n useEffect(() => {\n if (!isControlled) {\n \n setter(initialStateOrValue);\n }\n }, [initialStateOrValue]);\n\n\n\n if (isControlled) {\n return [\n initialStateOrValue as S,\n externalSetter as StateSetter<S>\n ];\n }\n\n return [state, setter];\n}","'use client';\n\nimport { FC, ReactNode, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport useMixedState from './hooks/useMixedState';\nimport { cn, PopupContext, PopupWindowDisabledType, StateSetter } from './Interfaces';\n\n\n\nexport type PopupWindowAnimationType = 'fade' | 'scale' | null\n\n\n\nexport interface IPopupWindowProps {\n /** Popip id */\n id: string\n\n /** Popup content */\n children: ReactNode\n\n /** Whether is popup open state */\n isOpen?: boolean\n\n /** Whether is popup open state setter */\n setIsOpen?: StateSetter<boolean>\n\n /** Popup window class name */\n className?: string\n\n /** Popup backdrop class name */\n layerClassName?: string\n\n /** Disable state change on specified actions or disable fully */\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\n\n /** Keep popup in the DOM and do not unmount on close */\n keep?: boolean\n\n /** \n * Fire callback when popup is mounting\n */\n onBeforeEnter?(): void\n\n /** \n * Fire callback when popup appear animation finished\n */\n onAfterEnter?(ev: React.TransitionEvent): void\n\n /** \n * Fire callback when popup started hide animation or at initial mount\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(ev: React.TransitionEvent): void\n}\n\n\n\n/** \n * Popup window component\n * \n * @requires PopupLayer context provided\n */\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null); // React portal container\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen); // Whether is popup open\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen)); // Whether is popup mounted in DOM\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen)); // Whether is popup currently visible\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]); // Disabled events\n\n const layerRef = useRef<HTMLDivElement>(null);\n const isAnimationFinished = useRef(true);\n\n const animation: PopupWindowAnimationType = props.animation !== undefined ? props.animation : 'fade';\n\n\n\n // Handle disabled\n useLayoutEffect(() => {\n let disabled: PopupWindowDisabledType[] = [];\n\n if (typeof props.disabled === 'boolean') disabled = props.disabled ? ['onEscape', 'onLayer'] : [];\n else disabled = props.disabled ?? [];\n\n ctx.updateNodeProperty(props.id, 'disabled', disabled);\n }, [props.disabled]);\n\n // Handle enter/exit animation\n useLayoutEffect(() => {\n if (!isMounted || !isOpen) return;\n\n const id = requestAnimationFrame(() => {\n setIsVisible(true);\n });\n\n return () => cancelAnimationFrame(id);\n }, [isMounted, isOpen]);\n\n\n\n // Retrieve react portal and mount popup node in context\n useEffect(() => {\n const container = ctx.containerRef.current;\n if (!container) return;\n\n setContainer(container);\n\n ctx.mountNode({\n id: props.id,\n isOpen: Boolean(props.isOpen),\n disabled\n });\n }, []);\n\n // Handle toggle node on external isOpen update\n useEffect(() => {\n // Skip if node is not mounted yet\n if (!ctx.nodes.some(el => el.id === props.id)) return;\n\n ctx.invokePopup(props.id, props.isOpen);\n }, [props.isOpen]);\n\n // Handle node sync with context\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.id);\n if (!node) return;\n\n setIsOpen(node.isOpen);\n setDisabled(node.disabled);\n }, [ctx.nodes]);\n\n // Handle mount on open and exit animation on close\n useEffect(() => {\n isAnimationFinished.current = false;\n\n if (isOpen) {\n // On Before Enter\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n } else {\n // On Before Exit\n if (props.onBeforeExit) props.onBeforeExit();\n\n setIsVisible(false);\n }\n }, [isOpen]);\n\n // Handle backdrop clicks\n useEffect(() => {\n const layer = layerRef.current;\n if (!layer) return;\n\n layer.addEventListener('mousedown', ev => {\n // Pass inbound clicks\n if ((ev.target as HTMLElement).closest('.neko-popup')) return;\n\n ctx.invokePopup(props.id, false);\n });\n }, [isMounted]);\n\n\n\n function handleTransitionEnd(ev: React.TransitionEvent) {\n // Skip buble events\n if (!(ev.target as HTMLElement | undefined)?.className.includes('neko-popup-backdrop')) return;\n\n // On After Enter\n if (isVisible && isOpen) {\n if (props.onAfterEnter && !isAnimationFinished.current) props.onAfterEnter(ev);\n }\n\n // On After Exit\n if (!isVisible && !isOpen) {\n if (props.onAfterExit && !isAnimationFinished.current) props.onAfterExit(ev);\n\n setIsMounted(false);\n }\n\n isAnimationFinished.current = true;\n }\n\n\n\n if (!props.keep) {\n // Unmount if doNotUnmount is disabled (default state)\n if (!isMounted) return null;\n }\n\n return container && createPortal(<section\n className={cn(`neko-popup-backdrop`, isVisible && 'neko-popup-backdrop--active', props.layerClassName)}\n aria-hidden={!isVisible}\n style={{ cursor: disabled.includes('onLayer') ? 'default' : 'pointer' }}\n onTransitionEnd={handleTransitionEnd}\n ref={layerRef}\n >\n <article\n id={props.id}\n className={cn(`neko-popup`, isVisible && 'neko-popup--active', animation && `neko-popup--animation_${animation}`, props.className)}\n role=\"dialog\"\n aria-modal\n onClick={e => e.stopPropagation()}\n >\n {props.children}\n </article>\n </section>, container);\n};"],"names":["r","t","f","n","o","clsx","PopupContext","createContext","cn","PopupButton","props","ctx","useContext","isActive","setIsActive","useState","Tag","useEffect","node","el","invokePopup","e","jsx","EFKW","msg","PopupLayer","baseZIndex","disableBodyScrollOnActivePopup","nodes","setNodes","isScrollDisabled","setIsScrollDisabled","isAnyPopupActive","setIsAnyPopupActive","containerRef","useRef","controller","maxZIndex","anyOpenNode","entityOrId","forceState","newState","_updateNode","updateNodeProperty","id","key","value","prev","mountNode","isOpen","disabled","jsxs","useMixedState","initialStateOrValue","externalSetter","isControlled","useMemo","state","setter","PopupWindow","container","setContainer","setIsOpen","isMounted","setIsMounted","isVisible","setIsVisible","setDisabled","layerRef","isAnimationFinished","animation","useLayoutEffect","layer","ev","handleTransitionEnd","createPortal"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../node_modules/clsx/dist/clsx.mjs","../src/_package/Interfaces.ts","../src/_package/PopupButton.tsx","../src/_package/components/ErrorComponents.ts","../src/_package/PopupLayer.tsx","../src/_package/hooks/useMixedState.ts","../src/_package/PopupWindow.tsx"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import React, { createContext, RefObject } from 'react';\nimport clsx from 'clsx';\n\n\n\n\nexport type PopupWindowDisabledType = 'onEscape' | 'onLayer';\nexport type StateSetter<S = any> = React.Dispatch<React.SetStateAction<S>>\nexport type MountNodeArgs = Pick<IPopupNode, 'id' | 'isOpen' | 'disabled'>\n\n/** Get value type from nested object path */\nexport type ValueFromPath<T, P> =\n P extends `${infer K}.${infer R}`\n ? K extends keyof T\n ? R extends keyof T[K]\n ? T[K][R]\n : never\n : never\n : P extends keyof T\n ? T[P]\n : never;\n\n\n\nexport interface IPopupNode {\n id: string\n isOpen: boolean\n zIndex: number\n disabled: PopupWindowDisabledType[]\n}\n\nexport interface IPopupContext {\n nodes: IPopupNode[]\n containerRef: RefObject<HTMLDivElement | null>\n\n invokePopup(id: string, forceState?: boolean): void\n mountNode(args: MountNodeArgs): void\n updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>): void\n}\n\n\n\nexport const PopupContext = createContext<IPopupContext>({} as IPopupContext);\nexport const cn = clsx;","'use client';\n\nimport { FC, JSX, ReactNode, useContext, useEffect, useState } from 'react';\n\nimport { cn, PopupContext } from './Interfaces';\n\n\n\nexport interface IPopupButtonProps {\n /** Popup id */\n popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n /** Whether is disabled */\n disabled?: boolean\n\n /** Button content */\n children?: ReactNode\n\n /** Class name */\n className?: string\n\n /** Button id */\n id?: string\n\n /** On click handler */\n onClick?(e: React.MouseEvent): void\n}\n\n\n\n/**\n * Button to natively change popup state\n * \n * @requires PopupLayer context\n */\nexport const PopupButton: FC<IPopupButtonProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [isActive, setIsActive] = useState(false);\n\n const Tag: keyof JSX.IntrinsicElements = props.as ?? 'button';\n\n\n\n // Handle isActive on context change\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.popupId);\n if (!node) return;\n\n setIsActive(node.isOpen);\n }, [ctx]);\n\n\n\n function invokePopup(e: React.MouseEvent) {\n ctx.invokePopup(props.popupId);\n\n if (props.onClick) props.onClick(e);\n }\n\n\n\n return <Tag\n tabIndex={0}\n disabled={props.disabled}\n aria-disabled={props.disabled}\n aria-haspopup={'dialog'}\n id={props.id}\n className={cn(`neko-popup-button`, isActive && 'neko-popup-button--active', props.className)}\n onClick={invokePopup}\n >\n {props.children}\n </Tag>;\n};","class EFKW extends Error {\n constructor(msg: string) {\n super(msg);\n\n this.name = 'error at [neko-popup]';\n }\n}\n\nexport default EFKW;","'use client';\n\nimport { FC, ReactNode, useEffect, useRef, useState } from 'react';\n\nimport EFKW from './components/ErrorComponents';\nimport { cn, IPopupNode, MountNodeArgs, PopupContext, ValueFromPath } from './Interfaces';\n\n\n\nexport interface IPopupLayerProps {\n /** React children */\n children?: ReactNode\n\n /** \n * Base z-index of the popups container\n * \n * @default 10000\n */\n baseZIndex?: number\n\n /**\n * Disable body scroll when there is at least one open popup\n * \n * @default true\n */\n disableBodyScrollOnActivePopup?: boolean\n}\n\n\n\n/**\n * Popup layer provides context & container for all popup windows & buttons\n */\nexport const PopupLayer: FC<IPopupLayerProps> = (props) => {\n const baseZIndex = props.baseZIndex ?? 10000;\n const disableBodyScrollOnActivePopup = props.disableBodyScrollOnActivePopup ?? true;\n\n const [nodes, setNodes] = useState<IPopupNode[]>([]);\n const [isScrollDisabled, setIsScrollDisabled] = useState(false);\n const [isAnyPopupActive, setIsAnyPopupActive] = useState(false);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n\n\n // Handle close closest to user popup on escape & scroll\n useEffect(() => {\n // === Handle close closest popup on escape\n const controller = new AbortController();\n\n window.addEventListener('keydown', e => {\n const key = e.key;\n\n if (key === 'Escape') {\n const maxZIndex = Math.max(...nodes.filter(el => el.isOpen).map(el => el.zIndex));\n const node = nodes.find(el => el.zIndex === maxZIndex);\n if (!node || node.disabled.includes('onEscape')) return;\n\n\n invokePopup(node.id, false);\n }\n }, { signal: controller.signal });\n\n\n\n // === Disable body scroll on active popup\n if (disableBodyScrollOnActivePopup) {\n let anyOpenNode = false;\n nodes.forEach(el => el.isOpen ? anyOpenNode = true : null);\n\n setIsScrollDisabled(anyOpenNode);\n }\n\n\n\n return () => {\n controller.abort();\n };\n }, [nodes]);\n\n // Handle isAnyPopupActive\n useEffect(() => {\n setIsAnyPopupActive(nodes.some(el => el.isOpen));\n }, [nodes]);\n\n // Handle body scroll\n useEffect(() => {\n if (isScrollDisabled) document.body.classList.add('neko-popup--noScroll');\n else document.body.classList.remove('neko-popup--noScroll');\n }, [isScrollDisabled]);\n\n\n\n /** Toggle popup state */\n function invokePopup(entityOrId: string | IPopupNode, forceState?: boolean) {\n const node = typeof entityOrId === 'string' ? nodes.find(el => el.id === entityOrId) : entityOrId;\n if (!node) throw new EFKW(typeof entityOrId === 'string' ? `Cannot find popup node with id #${entityOrId}` : `Entity is not assigned to the node`);\n\n const newState = forceState ?? !node.isOpen;\n\n // === Update node\n node.isOpen = newState;\n node.zIndex = newState ? Math.max(...nodes.map(el => el.zIndex), 0) + 1 : -1; // Make new popup invocation closer to user using larger z-index\n\n _updateNode(node);\n }\n\n /** Update node property */\n function updateNodeProperty<K extends keyof IPopupNode>(id: string, key: K, value: ValueFromPath<IPopupNode, K>) {\n const node = nodes.find(el => el.id === id);\n if (!node) return;\n\n node[key] = value;\n\n _updateNode(node);\n }\n\n /** Update node in nodes array */\n function _updateNode(node: IPopupNode) {\n setNodes(prev => [...prev.filter(el => el.id !== node.id), node]);\n }\n\n /** Add new popup window to state */\n const mountNode = ({ id, isOpen, disabled }: MountNodeArgs) => invokePopup({ id, isOpen: false, disabled, zIndex: -1 }, isOpen);\n\n\n\n return <PopupContext.Provider value={{\n nodes,\n containerRef,\n invokePopup,\n mountNode,\n updateNodeProperty\n }}>\n {props.children}\n\n <section className={cn(`neko-popup-layer`, isAnyPopupActive && 'neko-popup-layer--active')} style={{ zIndex: baseZIndex }} ref={containerRef} />\n </PopupContext.Provider>;\n};","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\n\n\n\ntype StateSetter<S> = React.Dispatch<React.SetStateAction<S>>;\ntype InitialState<S> = S | (() => S);\n\nexport default function useMixedState<S = undefined>(): [S | undefined, StateSetter<S | undefined>];\nexport default function useMixedState<S>(initialState: InitialState<S>): [S, StateSetter<S>];\nexport default function useMixedState<S>(state: S, setter?: StateSetter<S>): [S, StateSetter<S>];\n\n\n\n/** \n * Use mixed state hook\n * \n * @param initialStateOrValue Initial state, can be undefined, value or function. If externalSetter not specified, will return default state\n * @param externalSetter External state setter. If specified will return external state\n */\nexport default function useMixedState<S>(initialStateOrValue?: InitialState<S>, externalSetter?: StateSetter<S>) {\n const isControlled = useMemo(() => arguments.length === 2 && externalSetter !== undefined, []);\n\n const [state, setter] = useState<S | undefined>(initialStateOrValue);\n\n\n\n // Propagate state update on external state update even if external setter is not provided\n useEffect(() => {\n if (!isControlled) {\n \n setter(initialStateOrValue);\n }\n }, [initialStateOrValue]);\n\n\n\n if (isControlled) {\n return [\n initialStateOrValue as S,\n externalSetter as StateSetter<S>\n ];\n }\n\n return [state, setter];\n}","'use client';\n\nimport { FC, ReactNode, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport useMixedState from './hooks/useMixedState';\nimport { cn, PopupContext, PopupWindowDisabledType, StateSetter } from './Interfaces';\n\n\n\nexport type PopupWindowAnimationType = 'fade' | 'scale' | null\n\n\n\nexport interface IPopupWindowProps {\n /** Popip id */\n id: string\n\n /** Popup content */\n children: ReactNode\n\n /** Whether is popup open state */\n isOpen?: boolean\n\n /** Whether is popup open state setter */\n setIsOpen?: StateSetter<boolean>\n\n /** Popup window class name */\n className?: string\n\n /** Popup backdrop class name */\n layerClassName?: string\n\n /** Disable state change on specified actions or disable fully */\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\n\n /** Keep popup in the DOM and do not unmount on close */\n keep?: boolean\n\n /** \n * Fire callback when popup is mounting\n */\n onBeforeEnter?(): void\n\n /** \n * Fire callback when popup appear animation finished\n */\n onAfterEnter?(ev: React.TransitionEvent): void\n\n /** \n * Fire callback when popup started hide animation or at initial mount\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(ev: React.TransitionEvent): void\n}\n\n\n\n/** \n * Popup window component\n * \n * @requires PopupLayer context provided\n */\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null); // React portal container\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen); // Whether is popup open\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen)); // Whether is popup mounted in DOM\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen)); // Whether is popup currently visible\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]); // Disabled events\n\n const layerRef = useRef<HTMLDivElement>(null);\n const isAnimationFinished = useRef(true);\n\n const animation: PopupWindowAnimationType = props.animation !== undefined ? props.animation : 'fade';\n\n\n\n // Handle disabled\n useLayoutEffect(() => {\n let disabled: PopupWindowDisabledType[] = [];\n\n if (typeof props.disabled === 'boolean') disabled = props.disabled ? ['onEscape', 'onLayer'] : [];\n else disabled = props.disabled ?? [];\n\n ctx.updateNodeProperty(props.id, 'disabled', disabled);\n }, [props.disabled]);\n\n // Handle enter/exit animation\n useLayoutEffect(() => {\n if (!isMounted || !isOpen) return;\n\n const id = requestAnimationFrame(() => {\n setIsVisible(true);\n });\n\n return () => cancelAnimationFrame(id);\n }, [isMounted, isOpen]);\n\n\n\n // Retrieve react portal and mount popup node in context\n useEffect(() => {\n const container = ctx.containerRef.current;\n if (!container) return;\n\n setContainer(container);\n\n ctx.mountNode({\n id: props.id,\n isOpen: Boolean(props.isOpen),\n disabled\n });\n }, []);\n\n // Handle toggle node on external isOpen update\n useEffect(() => {\n // Skip if node is not mounted yet\n if (!ctx.nodes.some(el => el.id === props.id)) return;\n\n ctx.invokePopup(props.id, props.isOpen);\n }, [props.isOpen]);\n\n // Handle node sync with context\n useEffect(() => {\n const node = ctx.nodes.find(el => el.id === props.id);\n if (!node) return;\n\n setIsOpen(node.isOpen);\n setDisabled(node.disabled);\n }, [ctx.nodes]);\n\n // Handle mount on open and exit animation on close\n useEffect(() => {\n isAnimationFinished.current = false;\n\n if (isOpen) {\n // On Before Enter\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n } else {\n // On Before Exit\n if (props.onBeforeExit) props.onBeforeExit();\n\n setIsVisible(false);\n }\n }, [isOpen]);\n\n // Handle backdrop clicks\n useEffect(() => {\n const layer = layerRef.current;\n if (!layer) return;\n\n layer.addEventListener('mousedown', ev => {\n // Pass inbound clicks\n if ((ev.target as HTMLElement).closest('.neko-popup')) return;\n\n ctx.invokePopup(props.id, false);\n });\n }, [isMounted]);\n\n\n\n function handleTransitionEnd(ev: React.TransitionEvent) {\n // Skip buble events\n if (ev.target !== ev.currentTarget) return;\n\n // On After Enter\n if (isVisible && isOpen) {\n if (props.onAfterEnter && !isAnimationFinished.current) props.onAfterEnter(ev);\n }\n\n // On After Exit\n if (!isVisible && !isOpen) {\n if (props.onAfterExit && !isAnimationFinished.current) props.onAfterExit(ev);\n\n setIsMounted(false);\n }\n\n isAnimationFinished.current = true;\n }\n\n\n\n if (!props.keep) {\n // Unmount if doNotUnmount is disabled (default state)\n if (!isMounted) return null;\n }\n\n return container && createPortal(<section\n className={cn(`neko-popup-backdrop`, isVisible && 'neko-popup-backdrop--active', props.layerClassName)}\n aria-hidden={!isVisible}\n style={{\n cursor: disabled.includes('onLayer') ? 'default' : 'pointer',\n zIndex: props.keep ? 100 : undefined\n }}\n onTransitionEnd={handleTransitionEnd}\n ref={layerRef}\n >\n <article\n id={props.id}\n className={cn(`neko-popup`, isVisible && 'neko-popup--active', animation && `neko-popup--animation_${animation}`, props.className)}\n role=\"dialog\"\n aria-modal\n onClick={e => e.stopPropagation()}\n >\n {props.children}\n </article>\n </section>, container);\n};"],"names":["r","t","f","n","o","clsx","PopupContext","createContext","cn","PopupButton","props","ctx","useContext","isActive","setIsActive","useState","Tag","useEffect","node","el","invokePopup","e","jsx","EFKW","msg","PopupLayer","baseZIndex","disableBodyScrollOnActivePopup","nodes","setNodes","isScrollDisabled","setIsScrollDisabled","isAnyPopupActive","setIsAnyPopupActive","containerRef","useRef","controller","maxZIndex","anyOpenNode","entityOrId","forceState","newState","_updateNode","updateNodeProperty","id","key","value","prev","mountNode","isOpen","disabled","jsxs","useMixedState","initialStateOrValue","externalSetter","isControlled","useMemo","state","setter","PopupWindow","container","setContainer","setIsOpen","isMounted","setIsMounted","isVisible","setIsVisible","setDisabled","layerRef","isAnimationFinished","animation","useLayoutEffect","layer","ev","handleTransitionEnd","createPortal"],"mappings":"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","x_google_ignoreList":[0]}
|