neko-popup 3.0.6 → 3.0.7
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 +70 -71
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +7 -7
package/dist/index.es.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { createContext as
|
|
3
|
-
import { createPortal as
|
|
4
|
-
function
|
|
5
|
-
var
|
|
1
|
+
import { jsx as h, jsxs as C } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as w, useContext as I, useState as u, useEffect as c, useRef as N, useMemo as B, useLayoutEffect as L } from "react";
|
|
3
|
+
import { createPortal as z } from "react-dom";
|
|
4
|
+
function O(e) {
|
|
5
|
+
var o, i, n = "";
|
|
6
6
|
if (typeof e == "string" || typeof e == "number") n += e;
|
|
7
7
|
else if (typeof e == "object") if (Array.isArray(e)) {
|
|
8
8
|
var d = e.length;
|
|
9
|
-
for (
|
|
9
|
+
for (o = 0; o < d; o++) e[o] && (i = O(e[o])) && (n && (n += " "), n += i);
|
|
10
10
|
} else for (i in e) e[i] && (n && (n += " "), n += i);
|
|
11
11
|
return n;
|
|
12
12
|
}
|
|
13
|
-
function
|
|
14
|
-
for (var e,
|
|
13
|
+
function M() {
|
|
14
|
+
for (var e, o, i = 0, n = "", d = arguments.length; i < d; i++) (e = arguments[i]) && (o = O(e)) && (n && (n += " "), n += o);
|
|
15
15
|
return n;
|
|
16
16
|
}
|
|
17
|
-
const A =
|
|
18
|
-
const
|
|
17
|
+
const A = w({}), P = M, T = (e) => {
|
|
18
|
+
const o = I(A), [i, n] = u(!1), d = e.as ?? "button";
|
|
19
19
|
c(() => {
|
|
20
|
-
const l =
|
|
20
|
+
const l = o.nodes.find((p) => p.id === e.popupId);
|
|
21
21
|
l && n(l.isOpen);
|
|
22
|
-
}, [
|
|
23
|
-
function
|
|
24
|
-
|
|
22
|
+
}, [o]);
|
|
23
|
+
function m(l) {
|
|
24
|
+
o.invokePopup(e.popupId), e.onClick && e.onClick(l);
|
|
25
25
|
}
|
|
26
|
-
return /* @__PURE__ */
|
|
26
|
+
return /* @__PURE__ */ h(
|
|
27
27
|
d,
|
|
28
28
|
{
|
|
29
29
|
tabIndex: 0,
|
|
@@ -31,30 +31,30 @@ const A = C({}), h = z, T = (e) => {
|
|
|
31
31
|
"aria-disabled": e.disabled,
|
|
32
32
|
"aria-haspopup": "dialog",
|
|
33
33
|
id: e.id,
|
|
34
|
-
className:
|
|
35
|
-
onClick:
|
|
34
|
+
className: P("neko-popup-button", i && "neko-popup-button--active", e.className),
|
|
35
|
+
onClick: m,
|
|
36
36
|
children: e.children
|
|
37
37
|
}
|
|
38
38
|
);
|
|
39
39
|
};
|
|
40
|
-
class
|
|
41
|
-
constructor(
|
|
42
|
-
super(
|
|
40
|
+
class S extends Error {
|
|
41
|
+
constructor(o) {
|
|
42
|
+
super(o), this.name = "error at [neko-popup]";
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
const Z = (e) => {
|
|
46
|
-
const
|
|
46
|
+
const o = e.baseZIndex ?? 1e4, i = e.disableBodyScrollOnActivePopup ?? !0, [n, d] = u([]), [m, l] = u(!1), [p, b] = u(!1), k = N(null);
|
|
47
47
|
c(() => {
|
|
48
48
|
const s = new AbortController();
|
|
49
|
-
if (window.addEventListener("keydown", (
|
|
50
|
-
if (
|
|
49
|
+
if (window.addEventListener("keydown", (t) => {
|
|
50
|
+
if (t.key === "Escape") {
|
|
51
51
|
const f = Math.max(...n.filter((v) => v.isOpen).map((v) => v.zIndex)), r = n.find((v) => v.zIndex === f);
|
|
52
52
|
if (!r || r.disabled.includes("onEscape")) return;
|
|
53
|
-
|
|
53
|
+
y(r.id, !1);
|
|
54
54
|
}
|
|
55
55
|
}, { signal: s.signal }), i) {
|
|
56
|
-
let
|
|
57
|
-
n.forEach((a) => a.isOpen ?
|
|
56
|
+
let t = !1;
|
|
57
|
+
n.forEach((a) => a.isOpen ? t = !0 : null), l(t);
|
|
58
58
|
}
|
|
59
59
|
return () => {
|
|
60
60
|
s.abort();
|
|
@@ -62,91 +62,90 @@ const Z = (e) => {
|
|
|
62
62
|
}, [n]), c(() => {
|
|
63
63
|
b(n.some((s) => s.isOpen));
|
|
64
64
|
}, [n]), c(() => {
|
|
65
|
-
|
|
66
|
-
}, [
|
|
67
|
-
function
|
|
65
|
+
m ? document.body.classList.add("neko-popup--noScroll") : document.body.classList.remove("neko-popup--noScroll");
|
|
66
|
+
}, [m]);
|
|
67
|
+
function y(s, t) {
|
|
68
68
|
const a = typeof s == "string" ? n.find((r) => r.id === s) : s;
|
|
69
|
-
if (!a) throw new
|
|
70
|
-
const f =
|
|
69
|
+
if (!a) throw new S(typeof s == "string" ? `Cannot find popup node with id #${s}` : "Entity is not assigned to the node");
|
|
70
|
+
const f = t ?? !a.isOpen;
|
|
71
71
|
a.isOpen = f, a.zIndex = f ? Math.max(...n.map((r) => r.zIndex), 0) + 1 : -1, x(a);
|
|
72
72
|
}
|
|
73
|
-
function g(s,
|
|
73
|
+
function g(s, t, a) {
|
|
74
74
|
const f = n.find((r) => r.id === s);
|
|
75
|
-
f && (f[
|
|
75
|
+
f && (f[t] = a, x(f));
|
|
76
76
|
}
|
|
77
77
|
function x(s) {
|
|
78
|
-
d((
|
|
78
|
+
d((t) => [...t.filter((a) => a.id !== s.id), s]);
|
|
79
79
|
}
|
|
80
|
-
const E = ({ id: s, isOpen:
|
|
81
|
-
return /* @__PURE__ */
|
|
80
|
+
const E = ({ id: s, isOpen: t, disabled: a }) => y({ id: s, isOpen: !1, disabled: a, zIndex: -1 }, t);
|
|
81
|
+
return /* @__PURE__ */ C(A.Provider, { value: {
|
|
82
82
|
nodes: n,
|
|
83
|
-
containerRef:
|
|
84
|
-
invokePopup:
|
|
83
|
+
containerRef: k,
|
|
84
|
+
invokePopup: y,
|
|
85
85
|
mountNode: E,
|
|
86
86
|
updateNodeProperty: g
|
|
87
87
|
}, children: [
|
|
88
88
|
e.children,
|
|
89
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ h("section", { className: P("neko-popup-layer", p && "neko-popup-layer--active"), style: { zIndex: o }, ref: k })
|
|
90
90
|
] });
|
|
91
91
|
};
|
|
92
|
-
function
|
|
93
|
-
const i = B(() => arguments.length === 2 &&
|
|
92
|
+
function R(e, o) {
|
|
93
|
+
const i = B(() => arguments.length === 2 && o !== void 0, []), [n, d] = u(e);
|
|
94
94
|
return c(() => {
|
|
95
95
|
i || d(e);
|
|
96
96
|
}, [e]), i ? [
|
|
97
97
|
e,
|
|
98
|
-
|
|
98
|
+
o
|
|
99
99
|
] : [n, d];
|
|
100
100
|
}
|
|
101
|
-
const
|
|
102
|
-
const
|
|
101
|
+
const q = (e) => {
|
|
102
|
+
const o = I(A), [i, n] = u(null), [d, m] = R(e.isOpen ?? !1, e.setIsOpen), [l, p] = u(!!e.isOpen), [b, k] = u(!!e.isOpen), [y, g] = u([]), x = N(null), E = e.animation !== void 0 ? e.animation : "fade";
|
|
103
103
|
L(() => {
|
|
104
|
-
let
|
|
105
|
-
typeof e.disabled == "boolean" ?
|
|
104
|
+
let t = [];
|
|
105
|
+
typeof e.disabled == "boolean" ? t = e.disabled ? ["onEscape", "onLayer"] : [] : t = e.disabled ?? [], o.updateNodeProperty(e.id, "disabled", t);
|
|
106
106
|
}, [e.disabled]), c(() => {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
n(o), t.mountNode({
|
|
107
|
+
const t = o.containerRef.current;
|
|
108
|
+
t && (n(t), o.mountNode({
|
|
110
109
|
id: e.id,
|
|
111
110
|
isOpen: !!e.isOpen,
|
|
112
|
-
disabled:
|
|
113
|
-
});
|
|
111
|
+
disabled: y
|
|
112
|
+
}));
|
|
114
113
|
}, []), c(() => {
|
|
115
|
-
|
|
114
|
+
o.nodes.some((t) => t.id === e.id) && o.invokePopup(e.id, e.isOpen);
|
|
116
115
|
}, [e.isOpen]), c(() => {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
116
|
+
const t = o.nodes.find((a) => a.id === e.id);
|
|
117
|
+
t && (m(t.isOpen), g(t.disabled));
|
|
118
|
+
}, [o.nodes]), c(() => {
|
|
119
|
+
d ? (e.onBeforeEnter && e.onBeforeEnter(), p(!0), requestAnimationFrame(() => {
|
|
120
|
+
requestAnimationFrame(() => {
|
|
121
|
+
k(!0), e.onAfterEnter && e.onAfterEnter();
|
|
122
|
+
});
|
|
123
|
+
})) : (k(!1), e.onBeforeExit && e.onBeforeExit());
|
|
124
124
|
}, [d]), c(() => {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
a.target.closest(".neko-popup") || t.invokePopup(e.id, !1);
|
|
125
|
+
const t = x.current;
|
|
126
|
+
t && t.addEventListener("mousedown", (a) => {
|
|
127
|
+
a.target.closest(".neko-popup") || o.invokePopup(e.id, !1);
|
|
129
128
|
});
|
|
130
129
|
}, [l]);
|
|
131
130
|
function s() {
|
|
132
|
-
b || (
|
|
131
|
+
b || (p(!1), e.onAfterExit && e.onAfterExit());
|
|
133
132
|
}
|
|
134
|
-
return l ? i &&
|
|
133
|
+
return l ? i && z(/* @__PURE__ */ h(
|
|
135
134
|
"section",
|
|
136
135
|
{
|
|
137
|
-
className:
|
|
136
|
+
className: P("neko-popup-backdrop", b && "neko-popup-backdrop--active", e.layerClassName),
|
|
138
137
|
"aria-hidden": !b,
|
|
139
|
-
style: { cursor:
|
|
138
|
+
style: { cursor: y.includes("onLayer") ? "default" : "pointer" },
|
|
140
139
|
onTransitionEnd: s,
|
|
141
140
|
ref: x,
|
|
142
|
-
children: /* @__PURE__ */
|
|
141
|
+
children: /* @__PURE__ */ h(
|
|
143
142
|
"article",
|
|
144
143
|
{
|
|
145
144
|
id: e.id,
|
|
146
|
-
className:
|
|
145
|
+
className: P("neko-popup", b && "neko-popup--active", E && `neko-popup--animation_${E}`, e.className),
|
|
147
146
|
role: "dialog",
|
|
148
147
|
"aria-modal": !0,
|
|
149
|
-
onClick: (
|
|
148
|
+
onClick: (t) => t.stopPropagation(),
|
|
150
149
|
children: e.children
|
|
151
150
|
}
|
|
152
151
|
)
|
|
@@ -156,6 +155,6 @@ const F = (e) => {
|
|
|
156
155
|
export {
|
|
157
156
|
T as PopupButton,
|
|
158
157
|
Z as PopupLayer,
|
|
159
|
-
|
|
158
|
+
q as PopupWindow
|
|
160
159
|
};
|
|
161
160
|
//# sourceMappingURL=index.es.js.map
|
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 popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n disabled?: boolean\n children?: ReactNode\n className?: string\n id?: string\n\n onClick?(e: React.MouseEvent): void\n}\n\n\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 children?: ReactNode\n\n /** @default 10000 */\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\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 id: string\n children: ReactNode\n\n isOpen?: boolean\n setIsOpen?: StateSetter<boolean>\n\n className?: string\n layerClassName?: string\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\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?(): void\n\n /** \n * Fire callback when popup started hide animation\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(): void\n}\n\n\n\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen);\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen));\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen));\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]);\n\n const layerRef = useRef<HTMLDivElement>(null);\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\n\n // Mount\n useEffect(() => {\n const container = ctx.containerRef.current;\n if (!container) return console.warn(`[neko-popup]: Popup layer container is not found in DOM`);;\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 console.warn(`[neko-popup]: Popup node (#${props.id}) is not exist`);\n\n setIsOpen(node.isOpen);\n setDisabled(node.disabled);\n }, [ctx.nodes]);\n\n // Handle events (onBeforeEnter, etc)\n useEffect(() => {\n if (isOpen) {\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n\n requestAnimationFrame(() => {\n setIsVisible(true);\n\n if (props.onAfterEnter) props.onAfterEnter();\n });\n } else {\n setIsVisible(false);\n\n if (props.onBeforeExit) props.onBeforeExit();\n }\n }, [isOpen]);\n\n // Handle layer clicks\n useEffect(() => {\n const layer = layerRef.current;\n if (!layer) return console.warn(`[neko-popup]: Popup (#${props.id}) layer is not found in DOM`);\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 layerOnClick() {\n if (disabled.includes('onLayer')) return;\n\n ctx.invokePopup(props.id, false);\n }\n\n function handleTransitionEnd() {\n if (!isVisible) {\n setIsMounted(false);\n\n if (props.onAfterExit) props.onAfterExit();\n }\n }\n\n\n\n if (!isMounted) return null;\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","f","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","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 popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n disabled?: boolean\n children?: ReactNode\n className?: string\n id?: string\n\n onClick?(e: React.MouseEvent): void\n}\n\n\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 children?: ReactNode\n\n /** @default 10000 */\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\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 id: string\n children: ReactNode\n\n isOpen?: boolean\n setIsOpen?: StateSetter<boolean>\n\n className?: string\n layerClassName?: string\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\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?(): void\n\n /** \n * Fire callback when popup started hide animation\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(): void\n}\n\n\n\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen);\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen));\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen));\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]);\n\n const layerRef = useRef<HTMLDivElement>(null);\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\n\n // Mount\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 events (onBeforeEnter, etc)\n useEffect(() => {\n if (isOpen) {\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setIsVisible(true);\n\n if (props.onAfterEnter) props.onAfterEnter();\n });\n });\n } else {\n setIsVisible(false);\n\n if (props.onBeforeExit) props.onBeforeExit();\n }\n }, [isOpen]);\n\n // Handle layer 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() {\n if (!isVisible) {\n setIsMounted(false);\n\n if (props.onAfterExit) props.onAfterExit();\n }\n }\n\n\n\n if (!isMounted) return null;\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","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","animation","useLayoutEffect","layer","ev","handleTransitionEnd","createPortal"],"mappings":"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","x_google_ignoreList":[0]}
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(f,
|
|
1
|
+
(function(f,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react"),require("react-dom")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom"],c):(f=typeof globalThis<"u"?globalThis:f||self,c(f["neko-popup"]={},f.jsxRuntime,f.React,f.ReactDOM))})(this,(function(f,c,i,I){"use strict";function O(e){var o,s,n="";if(typeof e=="string"||typeof e=="number")n+=e;else if(typeof e=="object")if(Array.isArray(e)){var a=e.length;for(o=0;o<a;o++)e[o]&&(s=O(e[o]))&&(n&&(n+=" "),n+=s)}else for(s in e)e[s]&&(n&&(n+=" "),n+=s);return n}function S(){for(var e,o,s=0,n="",a=arguments.length;s<a;s++)(e=arguments[s])&&(o=O(e))&&(n&&(n+=" "),n+=o);return n}const A=i.createContext({}),h=S,N=e=>{const o=i.useContext(A),[s,n]=i.useState(!1),a=e.as??"button";i.useEffect(()=>{const l=o.nodes.find(b=>b.id===e.popupId);l&&n(l.isOpen)},[o]);function m(l){o.invokePopup(e.popupId),e.onClick&&e.onClick(l)}return c.jsx(a,{tabIndex:0,disabled:e.disabled,"aria-disabled":e.disabled,"aria-haspopup":"dialog",id:e.id,className:h("neko-popup-button",s&&"neko-popup-button--active",e.className),onClick:m,children:e.children})};class C extends Error{constructor(o){super(o),this.name="error at [neko-popup]"}}const w=e=>{const o=e.baseZIndex??1e4,s=e.disableBodyScrollOnActivePopup??!0,[n,a]=i.useState([]),[m,l]=i.useState(!1),[b,y]=i.useState(!1),k=i.useRef(null);i.useEffect(()=>{const d=new AbortController;if(window.addEventListener("keydown",t=>{if(t.key==="Escape"){const p=Math.max(...n.filter(v=>v.isOpen).map(v=>v.zIndex)),r=n.find(v=>v.zIndex===p);if(!r||r.disabled.includes("onEscape"))return;E(r.id,!1)}},{signal:d.signal}),s){let t=!1;n.forEach(u=>u.isOpen?t=!0:null),l(t)}return()=>{d.abort()}},[n]),i.useEffect(()=>{y(n.some(d=>d.isOpen))},[n]),i.useEffect(()=>{m?document.body.classList.add("neko-popup--noScroll"):document.body.classList.remove("neko-popup--noScroll")},[m]);function E(d,t){const u=typeof d=="string"?n.find(r=>r.id===d):d;if(!u)throw new C(typeof d=="string"?`Cannot find popup node with id #${d}`:"Entity is not assigned to the node");const p=t??!u.isOpen;u.isOpen=p,u.zIndex=p?Math.max(...n.map(r=>r.zIndex),0)+1:-1,x(u)}function g(d,t,u){const p=n.find(r=>r.id===d);p&&(p[t]=u,x(p))}function x(d){a(t=>[...t.filter(u=>u.id!==d.id),d])}const P=({id:d,isOpen:t,disabled:u})=>E({id:d,isOpen:!1,disabled:u,zIndex:-1},t);return c.jsxs(A.Provider,{value:{nodes:n,containerRef:k,invokePopup:E,mountNode:P,updateNodeProperty:g},children:[e.children,c.jsx("section",{className:h("neko-popup-layer",b&&"neko-popup-layer--active"),style:{zIndex:o},ref:k})]})};function B(e,o){const s=i.useMemo(()=>arguments.length===2&&o!==void 0,[]),[n,a]=i.useState(e);return i.useEffect(()=>{s||a(e)},[e]),s?[e,o]:[n,a]}const L=e=>{const o=i.useContext(A),[s,n]=i.useState(null),[a,m]=B(e.isOpen??!1,e.setIsOpen),[l,b]=i.useState(!!e.isOpen),[y,k]=i.useState(!!e.isOpen),[E,g]=i.useState([]),x=i.useRef(null),P=e.animation!==void 0?e.animation:"fade";i.useLayoutEffect(()=>{let t=[];typeof e.disabled=="boolean"?t=e.disabled?["onEscape","onLayer"]:[]:t=e.disabled??[],o.updateNodeProperty(e.id,"disabled",t)},[e.disabled]),i.useEffect(()=>{const t=o.containerRef.current;t&&(n(t),o.mountNode({id:e.id,isOpen:!!e.isOpen,disabled:E}))},[]),i.useEffect(()=>{o.nodes.some(t=>t.id===e.id)&&o.invokePopup(e.id,e.isOpen)},[e.isOpen]),i.useEffect(()=>{const t=o.nodes.find(u=>u.id===e.id);t&&(m(t.isOpen),g(t.disabled))},[o.nodes]),i.useEffect(()=>{a?(e.onBeforeEnter&&e.onBeforeEnter(),b(!0),requestAnimationFrame(()=>{requestAnimationFrame(()=>{k(!0),e.onAfterEnter&&e.onAfterEnter()})})):(k(!1),e.onBeforeExit&&e.onBeforeExit())},[a]),i.useEffect(()=>{const t=x.current;t&&t.addEventListener("mousedown",u=>{u.target.closest(".neko-popup")||o.invokePopup(e.id,!1)})},[l]);function d(){y||(b(!1),e.onAfterExit&&e.onAfterExit())}return l?s&&I.createPortal(c.jsx("section",{className:h("neko-popup-backdrop",y&&"neko-popup-backdrop--active",e.layerClassName),"aria-hidden":!y,style:{cursor:E.includes("onLayer")?"default":"pointer"},onTransitionEnd:d,ref:x,children:c.jsx("article",{id:e.id,className:h("neko-popup",y&&"neko-popup--active",P&&`neko-popup--animation_${P}`,e.className),role:"dialog","aria-modal":!0,onClick:t=>t.stopPropagation(),children:e.children})}),s):null};f.PopupButton=N,f.PopupLayer=w,f.PopupWindow=L,Object.defineProperty(f,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 popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n disabled?: boolean\n children?: ReactNode\n className?: string\n id?: string\n\n onClick?(e: React.MouseEvent): void\n}\n\n\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 children?: ReactNode\n\n /** @default 10000 */\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\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 id: string\n children: ReactNode\n\n isOpen?: boolean\n setIsOpen?: StateSetter<boolean>\n\n className?: string\n layerClassName?: string\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\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?(): void\n\n /** \n * Fire callback when popup started hide animation\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(): void\n}\n\n\n\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen);\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen));\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen));\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]);\n\n const layerRef = useRef<HTMLDivElement>(null);\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\n\n // Mount\n useEffect(() => {\n const container = ctx.containerRef.current;\n if (!container) return console.warn(`[neko-popup]: Popup layer container is not found in DOM`);;\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 console.warn(`[neko-popup]: Popup node (#${props.id}) is not exist`);\n\n setIsOpen(node.isOpen);\n setDisabled(node.disabled);\n }, [ctx.nodes]);\n\n // Handle events (onBeforeEnter, etc)\n useEffect(() => {\n if (isOpen) {\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n\n requestAnimationFrame(() => {\n setIsVisible(true);\n\n if (props.onAfterEnter) props.onAfterEnter();\n });\n } else {\n setIsVisible(false);\n\n if (props.onBeforeExit) props.onBeforeExit();\n }\n }, [isOpen]);\n\n // Handle layer clicks\n useEffect(() => {\n const layer = layerRef.current;\n if (!layer) return console.warn(`[neko-popup]: Popup (#${props.id}) layer is not found in DOM`);\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 layerOnClick() {\n if (disabled.includes('onLayer')) return;\n\n ctx.invokePopup(props.id, false);\n }\n\n function handleTransitionEnd() {\n if (!isVisible) {\n setIsMounted(false);\n\n if (props.onAfterExit) props.onAfterExit();\n }\n }\n\n\n\n if (!isMounted) return null;\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","f","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","animation","useLayoutEffect","layer","ev","handleTransitionEnd","createPortal"],"mappings":"uXAAA,SAASA,EAAE,EAAE,CAAC,IAAI,EAAEC,EAAE,EAAE,GAAG,GAAa,OAAO,GAAjB,UAA8B,OAAO,GAAjB,SAAmB,GAAG,UAAoB,OAAO,GAAjB,SAAmB,GAAG,MAAM,QAAQ,CAAC,EAAE,CAAC,IAAIC,EAAE,EAAE,OAAO,IAAI,EAAE,EAAE,EAAEA,EAAE,IAAI,EAAE,CAAC,IAAID,EAAED,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG,KAAK,GAAGC,EAAE,KAAM,KAAIA,KAAK,EAAE,EAAEA,CAAC,IAAI,IAAI,GAAG,KAAK,GAAGA,GAAG,OAAO,CAAC,CAAQ,SAASE,GAAM,CAAC,QAAQ,EAAE,EAAEF,EAAE,EAAE,EAAE,GAAGC,EAAE,UAAU,OAAOD,EAAEC,EAAED,KAAK,EAAE,UAAUA,CAAC,KAAK,EAAED,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,GAAG,GAAG,OAAO,CAAC,CC0CxW,MAAMI,EAAeC,EAAAA,cAA6B,EAAmB,EAC/DC,EAAKH,ECfLI,EAAsCC,GAAU,CAC3D,MAAMC,EAAMC,EAAAA,WAAWN,CAAY,EAE7B,CAACO,EAAUC,CAAW,EAAIC,EAAAA,SAAS,EAAK,EAExCC,EAAmCN,EAAM,IAAM,SAKrDO,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAOP,EAAI,MAAM,QAAWQ,EAAG,KAAOT,EAAM,OAAO,EACpDQ,GAELJ,EAAYI,EAAK,MAAM,CACzB,EAAG,CAACP,CAAG,CAAC,EAIR,SAASS,EAAYC,EAAqB,CACxCV,EAAI,YAAYD,EAAM,OAAO,EAEzBA,EAAM,SAASA,EAAM,QAAQW,CAAC,CACpC,CAIA,OAAOC,EAAAA,IAACN,EAAA,CACN,SAAU,EACV,SAAUN,EAAM,SAChB,gBAAeA,EAAM,SACrB,gBAAe,SACf,GAAIA,EAAM,GACV,UAAWF,EAAG,oBAAqBK,GAAY,4BAA6BH,EAAM,SAAS,EAC3F,QAASU,EAER,SAAAV,EAAM,QAAA,CAAA,CAEX,EClEA,MAAMa,UAAa,KAAM,CACvB,YAAYC,EAAa,CACvB,MAAMA,CAAG,EAET,KAAK,KAAO,uBACd,CACF,CCmBO,MAAMC,EAAoCf,GAAU,CACzD,MAAMgB,EAAahB,EAAM,YAAc,IACjCiB,EAAiCjB,EAAM,gCAAkC,GAEzE,CAACkB,EAAOC,CAAQ,EAAId,EAAAA,SAAuB,CAAA,CAAE,EAC7C,CAACe,EAAkBC,CAAmB,EAAIhB,EAAAA,SAAS,EAAK,EACxD,CAACiB,EAAkBC,CAAmB,EAAIlB,EAAAA,SAAS,EAAK,EAExDmB,EAAeC,EAAAA,OAAuB,IAAI,EAKhDlB,EAAAA,UAAU,IAAM,CAEd,MAAMmB,EAAa,IAAI,gBAkBvB,GAhBA,OAAO,iBAAiB,UAAWf,GAAK,CAGtC,GAFYA,EAAE,MAEF,SAAU,CACpB,MAAMgB,EAAY,KAAK,IAAI,GAAGT,EAAM,OAAOT,GAAMA,EAAG,MAAM,EAAE,IAAIA,GAAMA,EAAG,MAAM,CAAC,EAC1ED,EAAOU,EAAM,KAAKT,GAAMA,EAAG,SAAWkB,CAAS,EACrD,GAAI,CAACnB,GAAQA,EAAK,SAAS,SAAS,UAAU,EAAG,OAGjDE,EAAYF,EAAK,GAAI,EAAK,CAC5B,CACF,EAAG,CAAE,OAAQkB,EAAW,OAAQ,EAK5BT,EAAgC,CAClC,IAAIW,EAAc,GAClBV,EAAM,QAAQT,GAAMA,EAAG,OAASmB,EAAc,GAAO,IAAI,EAEzDP,EAAoBO,CAAW,CACjC,CAIA,MAAO,IAAM,CACXF,EAAW,MAAA,CACb,CACF,EAAG,CAACR,CAAK,CAAC,EAGVX,EAAAA,UAAU,IAAM,CACdgB,EAAoBL,EAAM,KAAKT,GAAMA,EAAG,MAAM,CAAC,CACjD,EAAG,CAACS,CAAK,CAAC,EAGVX,EAAAA,UAAU,IAAM,CACVa,EAAkB,SAAS,KAAK,UAAU,IAAI,sBAAsB,EACnE,SAAS,KAAK,UAAU,OAAO,sBAAsB,CAC5D,EAAG,CAACA,CAAgB,CAAC,EAKrB,SAASV,EAAYmB,EAAiCC,EAAsB,CAC1E,MAAMtB,EAAO,OAAOqB,GAAe,SAAWX,EAAM,KAAKT,GAAMA,EAAG,KAAOoB,CAAU,EAAIA,EACvF,GAAI,CAACrB,EAAM,MAAM,IAAIK,EAAK,OAAOgB,GAAe,SAAW,mCAAmCA,CAAU,GAAK,oCAAoC,EAEjJ,MAAME,EAAWD,GAAc,CAACtB,EAAK,OAGrCA,EAAK,OAASuB,EACdvB,EAAK,OAASuB,EAAW,KAAK,IAAI,GAAGb,EAAM,IAAIT,GAAMA,EAAG,MAAM,EAAG,CAAC,EAAI,EAAI,GAE1EuB,EAAYxB,CAAI,CAClB,CAGA,SAASyB,EAA+CC,EAAYC,EAAQC,EAAqC,CAC/G,MAAM5B,EAAOU,EAAM,KAAKT,GAAMA,EAAG,KAAOyB,CAAE,EACrC1B,IAELA,EAAK2B,CAAG,EAAIC,EAEZJ,EAAYxB,CAAI,EAClB,CAGA,SAASwB,EAAYxB,EAAkB,CACrCW,EAASkB,GAAQ,CAAC,GAAGA,EAAK,OAAO5B,GAAMA,EAAG,KAAOD,EAAK,EAAE,EAAGA,CAAI,CAAC,CAClE,CAGA,MAAM8B,EAAY,CAAC,CAAE,GAAAJ,EAAI,OAAAK,EAAQ,SAAAC,KAA8B9B,EAAY,CAAE,GAAAwB,EAAI,OAAQ,GAAO,SAAAM,EAAU,OAAQ,EAAA,EAAMD,CAAM,EAI9H,OAAOE,OAAC7C,EAAa,SAAb,CAAsB,MAAO,CACnC,MAAAsB,EACA,aAAAM,EACA,YAAAd,EACA,UAAA4B,EACA,mBAAAL,CAAA,EAEC,SAAA,CAAAjC,EAAM,SAEPY,EAAAA,IAAC,UAAA,CAAQ,UAAWd,EAAG,mBAAoBwB,GAAoB,0BAA0B,EAAG,MAAO,CAAE,OAAQN,CAAA,EAAc,IAAKQ,CAAA,CAAc,CAAA,EAChJ,CACF,EC5GA,SAAwBkB,EAAiBC,EAAuCC,EAAiC,CAC/G,MAAMC,EAAeC,EAAAA,QAAQ,IAAM,UAAU,SAAW,GAAKF,IAAmB,OAAW,EAAE,EAEvF,CAACG,EAAOC,CAAM,EAAI3C,EAAAA,SAAwBsC,CAAmB,EAcnE,OATApC,EAAAA,UAAU,IAAM,CACTsC,GAEHG,EAAOL,CAAmB,CAE9B,EAAG,CAACA,CAAmB,CAAC,EAIpBE,EACK,CACLF,EACAC,CAAA,EAIG,CAACG,EAAOC,CAAM,CACvB,CCQO,MAAMC,EAAsCjD,GAAU,CAC3D,MAAMC,EAAMC,EAAAA,WAAWN,CAAY,EAE7B,CAACsD,EAAWC,CAAY,EAAI9C,EAAAA,SAAgC,IAAI,EAChE,CAACkC,EAAQa,CAAS,EAAIV,EAAc1C,EAAM,QAAU,GAAOA,EAAM,SAAS,EAC1E,CAACqD,EAAWC,CAAY,EAAIjD,EAAAA,SAAS,EAAQL,EAAM,MAAO,EAC1D,CAACuD,EAAWC,CAAY,EAAInD,EAAAA,SAAS,EAAQL,EAAM,MAAO,EAC1D,CAACwC,EAAUiB,CAAW,EAAIpD,EAAAA,SAAoC,CAAA,CAAE,EAEhEqD,EAAWjC,EAAAA,OAAuB,IAAI,EAEtCkC,EAAsC3D,EAAM,YAAc,OAAYA,EAAM,UAAY,OAK9F4D,EAAAA,gBAAgB,IAAM,CACpB,IAAIpB,EAAsC,CAAA,EAEtC,OAAOxC,EAAM,UAAa,UAAWwC,EAAWxC,EAAM,SAAW,CAAC,WAAY,SAAS,EAAI,CAAA,EAC1FwC,EAAWxC,EAAM,UAAY,CAAA,EAElCC,EAAI,mBAAmBD,EAAM,GAAI,WAAYwC,CAAQ,CACvD,EAAG,CAACxC,EAAM,QAAQ,CAAC,EAKnBO,EAAAA,UAAU,IAAM,CACd,MAAM2C,EAAYjD,EAAI,aAAa,QACnC,GAAI,CAACiD,EAAW,OAAO,QAAQ,KAAK,yDAAyD,EAE7FC,EAAaD,CAAS,EAEtBjD,EAAI,UAAU,CACZ,GAAID,EAAM,GACV,OAAQ,EAAQA,EAAM,OACtB,SAAAwC,CAAA,CACD,CACH,EAAG,CAAA,CAAE,EAGLjC,EAAAA,UAAU,IAAM,CAETN,EAAI,MAAM,QAAWQ,EAAG,KAAOT,EAAM,EAAE,GAE5CC,EAAI,YAAYD,EAAM,GAAIA,EAAM,MAAM,CACxC,EAAG,CAACA,EAAM,MAAM,CAAC,EAGjBO,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAOP,EAAI,MAAM,QAAWQ,EAAG,KAAOT,EAAM,EAAE,EACpD,GAAI,CAACQ,EAAM,OAAO,QAAQ,KAAK,8BAA8BR,EAAM,EAAE,gBAAgB,EAErFoD,EAAU5C,EAAK,MAAM,EACrBiD,EAAYjD,EAAK,QAAQ,CAC3B,EAAG,CAACP,EAAI,KAAK,CAAC,EAGdM,EAAAA,UAAU,IAAM,CACVgC,GACEvC,EAAM,eAAeA,EAAM,cAAA,EAE/BsD,EAAa,EAAI,EAEjB,sBAAsB,IAAM,CAC1BE,EAAa,EAAI,EAEbxD,EAAM,cAAcA,EAAM,aAAA,CAChC,CAAC,IAEDwD,EAAa,EAAK,EAEdxD,EAAM,cAAcA,EAAM,aAAA,EAElC,EAAG,CAACuC,CAAM,CAAC,EAGXhC,EAAAA,UAAU,IAAM,CACd,MAAMsD,EAAQH,EAAS,QACvB,GAAI,CAACG,EAAO,OAAO,QAAQ,KAAK,yBAAyB7D,EAAM,EAAE,6BAA6B,EAE9F6D,EAAM,iBAAiB,YAAaC,GAAM,CAEnCA,EAAG,OAAuB,QAAQ,aAAa,GAEpD7D,EAAI,YAAYD,EAAM,GAAI,EAAK,CACjC,CAAC,CACH,EAAG,CAACqD,CAAS,CAAC,EAUd,SAASU,GAAsB,CACxBR,IACHD,EAAa,EAAK,EAEdtD,EAAM,aAAaA,EAAM,YAAA,EAEjC,CAIA,OAAKqD,EAEEH,GAAac,EAAAA,aAAapD,EAAAA,IAAC,UAAA,CAChC,UAAWd,EAAG,sBAAuByD,GAAa,8BAA+BvD,EAAM,cAAc,EACrG,cAAa,CAACuD,EACd,MAAO,CAAE,OAAQf,EAAS,SAAS,SAAS,EAAI,UAAY,SAAA,EAC5D,gBAAiBuB,EACjB,IAAKL,EAEL,SAAA9C,EAAAA,IAAC,UAAA,CACC,GAAIZ,EAAM,GACV,UAAWF,EAAG,aAAcyD,GAAa,qBAAsBI,GAAa,yBAAyBA,CAAS,GAAI3D,EAAM,SAAS,EACjI,KAAK,SACL,aAAU,GACV,QAASW,GAAKA,EAAE,gBAAA,EAEf,SAAAX,EAAM,QAAA,CAAA,CACT,CAAA,EACUkD,CAAS,EAlBE,IAmBzB","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 popupId: string\n\n /** \n * Element tag\n * \n * @default \"button\"\n */\n as?: 'button' | 'div'\n\n disabled?: boolean\n children?: ReactNode\n className?: string\n id?: string\n\n onClick?(e: React.MouseEvent): void\n}\n\n\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 children?: ReactNode\n\n /** @default 10000 */\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\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 id: string\n children: ReactNode\n\n isOpen?: boolean\n setIsOpen?: StateSetter<boolean>\n\n className?: string\n layerClassName?: string\n disabled?: PopupWindowDisabledType[] | boolean\n\n /** \n * Popup dialog animation type\n * \n * @default \"fade\"\n */\n animation?: 'fade' | 'scale' | null\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?(): void\n\n /** \n * Fire callback when popup started hide animation\n */\n onBeforeExit?(): void\n\n /** \n * Fire callback when popup become unmount\n */\n onAfterExit?(): void\n}\n\n\n\nexport const PopupWindow: FC<IPopupWindowProps> = (props) => {\n const ctx = useContext(PopupContext);\n\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const [isOpen, setIsOpen] = useMixedState(props.isOpen ?? false, props.setIsOpen);\n const [isMounted, setIsMounted] = useState(Boolean(props.isOpen));\n const [isVisible, setIsVisible] = useState(Boolean(props.isOpen));\n const [disabled, setDisabled] = useState<PopupWindowDisabledType[]>([]);\n\n const layerRef = useRef<HTMLDivElement>(null);\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\n\n // Mount\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 events (onBeforeEnter, etc)\n useEffect(() => {\n if (isOpen) {\n if (props.onBeforeEnter) props.onBeforeEnter();\n\n setIsMounted(true);\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setIsVisible(true);\n\n if (props.onAfterEnter) props.onAfterEnter();\n });\n });\n } else {\n setIsVisible(false);\n\n if (props.onBeforeExit) props.onBeforeExit();\n }\n }, [isOpen]);\n\n // Handle layer 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() {\n if (!isVisible) {\n setIsMounted(false);\n\n if (props.onAfterExit) props.onAfterExit();\n }\n }\n\n\n\n if (!isMounted) return null;\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","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","animation","useLayoutEffect","layer","ev","handleTransitionEnd","createPortal"],"mappings":"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","x_google_ignoreList":[0]}
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.neko-popup{cursor:auto;max-height:100%;overflow-y:auto}.neko-popup--animation_fade{transition:inherit}.neko-popup--animation_scale{transition:inherit;scale:.8}.neko-popup--animation_scale.neko-popup--active{scale:1}.neko-popup-layer{position:fixed;inset:0;visibility:hidden}.neko-popup-layer--active{visibility:visible}.neko-popup-backdrop{position:fixed;inset:0;width:100%;height:100%;max-height:100%;background:#0003;-webkit-tap-highlight-color:transparent;contain:paint;
|
|
1
|
+
.neko-popup{cursor:auto;max-height:100%;overflow-y:auto}.neko-popup--animation_fade{transition:inherit}.neko-popup--animation_scale{transition:inherit;scale:.8}.neko-popup--animation_scale.neko-popup--active{scale:1}.neko-popup-layer{position:fixed;inset:0;visibility:hidden}.neko-popup-layer--active{visibility:visible}.neko-popup-backdrop{position:fixed;inset:0;width:100%;height:100%;max-height:100%;background:#0003;-webkit-tap-highlight-color:transparent;contain:paint;display:flex;align-items:center;justify-content:center;touch-action:none;pointer-events:none;visibility:hidden;opacity:0;transition:.2s ease-in-out}.neko-popup-backdrop--active{opacity:1;visibility:visible;touch-action:auto;pointer-events:auto}.neko-popup-button{cursor:pointer}.neko-popup--noScroll{overflow:hidden;scrollbar-gutter:stable}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neko-popup",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.7",
|
|
4
4
|
"description": "Simple and cool react popup package 🚀",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.umd.js",
|
|
@@ -47,6 +47,8 @@
|
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@eslint/js": "^9.32.0",
|
|
49
49
|
"@tailwindcss/vite": "^4.1.16",
|
|
50
|
+
"@types/react": "19.1.9",
|
|
51
|
+
"@types/react-dom": "19.1.7",
|
|
50
52
|
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
51
53
|
"@vitejs/plugin-react": "^4.7.0",
|
|
52
54
|
"clsx": "^2.1.1",
|
|
@@ -58,20 +60,18 @@
|
|
|
58
60
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
59
61
|
"eslint-plugin-unused-imports": "^4.1.4",
|
|
60
62
|
"husky": "^9.1.7",
|
|
63
|
+
"react": "19.2.4",
|
|
64
|
+
"react-dom": "19.2.4",
|
|
61
65
|
"rimraf": "^6.0.1",
|
|
62
66
|
"sass": "^1.97.3",
|
|
63
67
|
"tailwindcss": "^4.1.16",
|
|
64
68
|
"typescript": "^5.9.3",
|
|
65
69
|
"typescript-eslint": "^8.56.1",
|
|
66
70
|
"vite": "^7.3.1",
|
|
67
|
-
"vite-plugin-dts": "^4.5.4"
|
|
68
|
-
"@types/react": "19.1.9",
|
|
69
|
-
"@types/react-dom": "19.1.7",
|
|
70
|
-
"react": "19.2.4",
|
|
71
|
-
"react-dom": "19.2.4"
|
|
71
|
+
"vite-plugin-dts": "^4.5.4"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"react": ">=19",
|
|
75
75
|
"react-dom": ">=19"
|
|
76
76
|
}
|
|
77
|
-
}
|
|
77
|
+
}
|