neko-popup 3.0.8 → 3.1.0

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/README.md CHANGED
@@ -59,14 +59,18 @@ function App() {
59
59
 
60
60
  ## ⚙️ API
61
61
  ```ts
62
- export type PopupWindowDisabledType = 'onEscape' | 'onLayer';
63
- export type StateSetter<S = any> = React.Dispatch<React.SetStateAction<S>>
64
62
  type PopupWindowAnimationType = 'fade' | 'scale' | null
63
+ export type PopupWindowDisabledType = 'onEscape' | 'onLayer';
65
64
 
66
- interface IPopupLayerProps {
65
+ export interface IPopupLayerProps {
66
+ /** React children */
67
67
  children?: ReactNode
68
68
 
69
- /** @default 10000 */
69
+ /**
70
+ * Base z-index of the popups container
71
+ *
72
+ * @default 10000
73
+ */
70
74
  baseZIndex?: number
71
75
 
72
76
  /**
@@ -78,6 +82,7 @@ interface IPopupLayerProps {
78
82
  }
79
83
 
80
84
  export interface IPopupButtonProps {
85
+ /** Popup id */
81
86
  popupId: string
82
87
 
83
88
  /**
@@ -87,23 +92,42 @@ export interface IPopupButtonProps {
87
92
  */
88
93
  as?: 'button' | 'div'
89
94
 
95
+ /** Whether is disabled */
90
96
  disabled?: boolean
97
+
98
+ /** Button content */
91
99
  children?: ReactNode
100
+
101
+ /** Class name */
92
102
  className?: string
103
+
104
+ /** Button id */
93
105
  id?: string
94
106
 
107
+ /** On click handler */
95
108
  onClick?(e: React.MouseEvent): void
96
109
  }
97
110
 
98
111
  export interface IPopupWindowProps {
112
+ /** Popip id */
99
113
  id: string
114
+
115
+ /** Popup content */
100
116
  children: ReactNode
101
117
 
118
+ /** Whether is popup open state */
102
119
  isOpen?: boolean
120
+
121
+ /** Whether is popup open state setter */
103
122
  setIsOpen?: StateSetter<boolean>
104
123
 
124
+ /** Popup window class name */
105
125
  className?: string
126
+
127
+ /** Popup backdrop class name */
106
128
  layerClassName?: string
129
+
130
+ /** Disable state change on specified actions or disable fully */
107
131
  disabled?: PopupWindowDisabledType[] | boolean
108
132
 
109
133
  /**
@@ -113,6 +137,9 @@ export interface IPopupWindowProps {
113
137
  */
114
138
  animation?: 'fade' | 'scale' | null
115
139
 
140
+ /** Keep popup in the DOM and do not unmount on close */
141
+ keep?: boolean
142
+
116
143
  /**
117
144
  * Fire callback when popup is mounting
118
145
  */
@@ -135,8 +162,5 @@ export interface IPopupWindowProps {
135
162
  }
136
163
  ```
137
164
 
138
- ## ☁️ Migration Guides
139
- - [Migration from @fullkekw/popup](./docs/migration.md#fullkekwpopup)
140
-
141
165
  ## ©️ License
142
166
  Licensed under MIT ©️ nekomiclub 2026
@@ -1,5 +1,6 @@
1
1
  import { FC, ReactNode } from 'react';
2
2
  export interface IPopupButtonProps {
3
+ /** Popup id */
3
4
  popupId: string;
4
5
  /**
5
6
  * Element tag
@@ -7,10 +8,20 @@ export interface IPopupButtonProps {
7
8
  * @default "button"
8
9
  */
9
10
  as?: 'button' | 'div';
11
+ /** Whether is disabled */
10
12
  disabled?: boolean;
13
+ /** Button content */
11
14
  children?: ReactNode;
15
+ /** Class name */
12
16
  className?: string;
17
+ /** Button id */
13
18
  id?: string;
19
+ /** On click handler */
14
20
  onClick?(e: React.MouseEvent): void;
15
21
  }
22
+ /**
23
+ * Button to natively change popup state
24
+ *
25
+ * @requires PopupLayer context
26
+ */
16
27
  export declare const PopupButton: FC<IPopupButtonProps>;
@@ -1,7 +1,12 @@
1
1
  import { FC, ReactNode } from 'react';
2
2
  export interface IPopupLayerProps {
3
+ /** React children */
3
4
  children?: ReactNode;
4
- /** @default 10000 */
5
+ /**
6
+ * Base z-index of the popups container
7
+ *
8
+ * @default 10000
9
+ */
5
10
  baseZIndex?: number;
6
11
  /**
7
12
  * Disable body scroll when there is at least one open popup
@@ -10,4 +15,7 @@ export interface IPopupLayerProps {
10
15
  */
11
16
  disableBodyScrollOnActivePopup?: boolean;
12
17
  }
18
+ /**
19
+ * Popup layer provides context & container for all popup windows & buttons
20
+ */
13
21
  export declare const PopupLayer: FC<IPopupLayerProps>;
@@ -2,12 +2,19 @@ import { FC, ReactNode } from 'react';
2
2
  import { PopupWindowDisabledType, StateSetter } from './Interfaces';
3
3
  export type PopupWindowAnimationType = 'fade' | 'scale' | null;
4
4
  export interface IPopupWindowProps {
5
+ /** Popip id */
5
6
  id: string;
7
+ /** Popup content */
6
8
  children: ReactNode;
9
+ /** Whether is popup open state */
7
10
  isOpen?: boolean;
11
+ /** Whether is popup open state setter */
8
12
  setIsOpen?: StateSetter<boolean>;
13
+ /** Popup window class name */
9
14
  className?: string;
15
+ /** Popup backdrop class name */
10
16
  layerClassName?: string;
17
+ /** Disable state change on specified actions or disable fully */
11
18
  disabled?: PopupWindowDisabledType[] | boolean;
12
19
  /**
13
20
  * Popup dialog animation type
@@ -15,6 +22,8 @@ export interface IPopupWindowProps {
15
22
  * @default "fade"
16
23
  */
17
24
  animation?: 'fade' | 'scale' | null;
25
+ /** Keep popup in the DOM and do not unmount on close */
26
+ keep?: boolean;
18
27
  /**
19
28
  * Fire callback when popup is mounting
20
29
  */
@@ -32,4 +41,9 @@ export interface IPopupWindowProps {
32
41
  */
33
42
  onAfterExit?(ev: React.TransitionEvent): void;
34
43
  }
44
+ /**
45
+ * Popup window component
46
+ *
47
+ * @requires PopupLayer context provided
48
+ */
35
49
  export declare const PopupWindow: FC<IPopupWindowProps>;
package/dist/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as E, jsxs as w } from "react/jsx-runtime";
2
- import { createContext as B, useContext as O, useState as f, useEffect as l, useRef as g, useMemo as L, useLayoutEffect as N } from "react";
2
+ import { createContext as B, useContext as O, useState as f, useEffect as l, useRef as P, useMemo as L, useLayoutEffect as N } from "react";
3
3
  import { createPortal as z } from "react-dom";
4
4
  function C(e) {
5
5
  var o, s, t = "";
@@ -14,13 +14,13 @@ 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({}), A = M, T = (e) => {
17
+ const I = B({}), g = M, T = (e) => {
18
18
  const o = O(I), [s, t] = f(!1), a = e.as ?? "button";
19
19
  l(() => {
20
- const c = o.nodes.find((y) => y.id === e.popupId);
20
+ const c = o.nodes.find((b) => b.id === e.popupId);
21
21
  c && t(c.isOpen);
22
22
  }, [o]);
23
- function b(c) {
23
+ function p(c) {
24
24
  o.invokePopup(e.popupId), e.onClick && e.onClick(c);
25
25
  }
26
26
  return /* @__PURE__ */ E(
@@ -31,8 +31,8 @@ const I = B({}), A = M, T = (e) => {
31
31
  "aria-disabled": e.disabled,
32
32
  "aria-haspopup": "dialog",
33
33
  id: e.id,
34
- className: A("neko-popup-button", s && "neko-popup-button--active", e.className),
35
- onClick: b,
34
+ className: g("neko-popup-button", s && "neko-popup-button--active", e.className),
35
+ onClick: p,
36
36
  children: e.children
37
37
  }
38
38
  );
@@ -43,7 +43,7 @@ class S extends Error {
43
43
  }
44
44
  }
45
45
  const Z = (e) => {
46
- const o = e.baseZIndex ?? 1e4, s = e.disableBodyScrollOnActivePopup ?? !0, [t, a] = f([]), [b, c] = f(!1), [y, m] = f(!1), x = g(null);
46
+ const o = e.baseZIndex ?? 1e4, s = e.disableBodyScrollOnActivePopup ?? !0, [t, a] = f([]), [p, c] = f(!1), [b, m] = f(!1), x = P(null);
47
47
  l(() => {
48
48
  const i = new AbortController();
49
49
  if (window.addEventListener("keydown", (d) => {
@@ -62,31 +62,31 @@ const Z = (e) => {
62
62
  }, [t]), l(() => {
63
63
  m(t.some((i) => i.isOpen));
64
64
  }, [t]), l(() => {
65
- b ? document.body.classList.add("neko-popup--noScroll") : document.body.classList.remove("neko-popup--noScroll");
66
- }, [b]);
65
+ p ? document.body.classList.add("neko-popup--noScroll") : document.body.classList.remove("neko-popup--noScroll");
66
+ }, [p]);
67
67
  function k(i, d) {
68
68
  const n = typeof i == "string" ? t.find((u) => u.id === i) : i;
69
69
  if (!n) throw new S(typeof i == "string" ? `Cannot find popup node with id #${i}` : "Entity is not assigned to the node");
70
70
  const r = d ?? !n.isOpen;
71
71
  n.isOpen = r, n.zIndex = r ? Math.max(...t.map((u) => u.zIndex), 0) + 1 : -1, v(n);
72
72
  }
73
- function P(i, d, n) {
73
+ function A(i, d, n) {
74
74
  const r = t.find((u) => u.id === i);
75
75
  r && (r[d] = n, v(r));
76
76
  }
77
77
  function v(i) {
78
78
  a((d) => [...d.filter((n) => n.id !== i.id), i]);
79
79
  }
80
- const p = ({ id: i, isOpen: d, disabled: n }) => k({ id: i, isOpen: !1, disabled: n, zIndex: -1 }, d);
80
+ const y = ({ id: i, isOpen: d, disabled: n }) => k({ id: i, isOpen: !1, disabled: n, zIndex: -1 }, d);
81
81
  return /* @__PURE__ */ w(I.Provider, { value: {
82
82
  nodes: t,
83
83
  containerRef: x,
84
84
  invokePopup: k,
85
- mountNode: p,
86
- updateNodeProperty: P
85
+ mountNode: y,
86
+ updateNodeProperty: A
87
87
  }, children: [
88
88
  e.children,
89
- /* @__PURE__ */ E("section", { className: A("neko-popup-layer", y && "neko-popup-layer--active"), style: { zIndex: o }, ref: x })
89
+ /* @__PURE__ */ E("section", { className: g("neko-popup-layer", b && "neko-popup-layer--active"), style: { zIndex: o }, ref: x })
90
90
  ] });
91
91
  };
92
92
  function F(e, o) {
@@ -99,11 +99,17 @@ function F(e, o) {
99
99
  ] : [t, a];
100
100
  }
101
101
  const W = (e) => {
102
- const o = O(I), [s, t] = f(null), [a, b] = F(e.isOpen ?? !1, e.setIsOpen), [c, y] = f(!!e.isOpen), [m, x] = f(!!e.isOpen), [k, P] = f([]), v = g(null), p = g(!0), i = e.animation !== void 0 ? e.animation : "fade";
102
+ const o = O(I), [s, t] = f(null), [a, p] = F(e.isOpen ?? !1, e.setIsOpen), [c, b] = f(!!e.isOpen), [m, x] = f(!!e.isOpen), [k, A] = f([]), v = P(null), y = P(!0), i = e.animation !== void 0 ? e.animation : "fade";
103
103
  N(() => {
104
104
  let n = [];
105
105
  typeof e.disabled == "boolean" ? n = e.disabled ? ["onEscape", "onLayer"] : [] : n = e.disabled ?? [], o.updateNodeProperty(e.id, "disabled", n);
106
- }, [e.disabled]), l(() => {
106
+ }, [e.disabled]), N(() => {
107
+ if (!c || !a) return;
108
+ const n = requestAnimationFrame(() => {
109
+ x(!0);
110
+ });
111
+ return () => cancelAnimationFrame(n);
112
+ }, [c, a]), l(() => {
107
113
  const n = o.containerRef.current;
108
114
  n && (t(n), o.mountNode({
109
115
  id: e.id,
@@ -114,28 +120,22 @@ const W = (e) => {
114
120
  o.nodes.some((n) => n.id === e.id) && o.invokePopup(e.id, e.isOpen);
115
121
  }, [e.isOpen]), l(() => {
116
122
  const n = o.nodes.find((r) => r.id === e.id);
117
- n && (b(n.isOpen), P(n.disabled));
123
+ n && (p(n.isOpen), A(n.disabled));
118
124
  }, [o.nodes]), l(() => {
119
- p.current = !1, a ? (e.onBeforeEnter && e.onBeforeEnter(), y(!0)) : (e.onBeforeExit && e.onBeforeExit(), x(!1));
125
+ y.current = !1, a ? (e.onBeforeEnter && e.onBeforeEnter(), b(!0)) : (e.onBeforeExit && e.onBeforeExit(), x(!1));
120
126
  }, [a]), l(() => {
121
127
  const n = v.current;
122
128
  n && n.addEventListener("mousedown", (r) => {
123
129
  r.target.closest(".neko-popup") || o.invokePopup(e.id, !1);
124
130
  });
125
- }, [c]), N(() => {
126
- if (!c || !a) return;
127
- const n = requestAnimationFrame(() => {
128
- x(!0);
129
- });
130
- return () => cancelAnimationFrame(n);
131
- }, [c, a]);
131
+ }, [c]);
132
132
  function d(n) {
133
- m && a && (e.onAfterEnter && !p.current && e.onAfterEnter(n), p.current = !0), !m && !a && (e.onAfterExit && !p.current && e.onAfterExit(n), y(!1), p.current = !0);
133
+ n.target?.className.includes("neko-popup-backdrop") && (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
- return c ? s && z(/* @__PURE__ */ E(
135
+ return !e.keep && !c ? null : s && z(/* @__PURE__ */ E(
136
136
  "section",
137
137
  {
138
- className: A("neko-popup-backdrop", m && "neko-popup-backdrop--active", e.layerClassName),
138
+ className: g("neko-popup-backdrop", m && "neko-popup-backdrop--active", e.layerClassName),
139
139
  "aria-hidden": !m,
140
140
  style: { cursor: k.includes("onLayer") ? "default" : "pointer" },
141
141
  onTransitionEnd: d,
@@ -144,7 +144,7 @@ const W = (e) => {
144
144
  "article",
145
145
  {
146
146
  id: e.id,
147
- className: A("neko-popup", m && "neko-popup--active", i && `neko-popup--animation_${i}`, e.className),
147
+ className: g("neko-popup", m && "neko-popup--active", i && `neko-popup--animation_${i}`, e.className),
148
148
  role: "dialog",
149
149
  "aria-modal": !0,
150
150
  onClick: (n) => n.stopPropagation(),
@@ -152,7 +152,7 @@ const W = (e) => {
152
152
  }
153
153
  )
154
154
  }
155
- ), s) : null;
155
+ ), s);
156
156
  };
157
157
  export {
158
158
  T as PopupButton,
@@ -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?(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\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 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\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 on open moun and on close animation exit\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 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 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 function handleTransitionEnd(ev: React.TransitionEvent) {\n // On After Enter\n if (isVisible && isOpen) {\n if (props.onAfterEnter && !isAnimationFinished.current) props.onAfterEnter(ev);\n\n isAnimationFinished.current = true;\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 isAnimationFinished.current = true;\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","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 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]}
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,I){"use strict";function O(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=O(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=O(e))&&(t&&(t+=" "),t+=i);return t}const A=o.createContext({}),P=S,N=e=>{const i=o.useContext(A),[d,t]=o.useState(!1),u=e.as??"button";o.useEffect(()=>{const l=i.nodes.find(E=>E.id===e.popupId);l&&t(l.isOpen)},[i]);function y(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:y,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([]),[y,l]=o.useState(!1),[E,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(h=>h.isOpen).map(h=>h.zIndex)),p=t.find(h=>h.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(()=>{y?document.body.classList.add("neko-popup--noScroll"):document.body.classList.remove("neko-popup--noScroll")},[y]);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,v(n)}function g(s,a,n){const f=t.find(p=>p.id===s);f&&(f[a]=n,v(f))}function v(s){u(a=>[...a.filter(n=>n.id!==s.id),s])}const b=({id:s,isOpen:a,disabled:n})=>k({id:s,isOpen:!1,disabled:n,zIndex:-1},a);return r.jsxs(A.Provider,{value:{nodes:t,containerRef:x,invokePopup:k,mountNode:b,updateNodeProperty:g},children:[e.children,r.jsx("section",{className:P("neko-popup-layer",E&&"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(A),[d,t]=o.useState(null),[u,y]=B(e.isOpen??!1,e.setIsOpen),[l,E]=o.useState(!!e.isOpen),[m,x]=o.useState(!!e.isOpen),[k,g]=o.useState([]),v=o.useRef(null),b=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.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&&(y(n.isOpen),g(n.disabled))},[i.nodes]),o.useEffect(()=>{b.current=!1,u?(e.onBeforeEnter&&e.onBeforeEnter(),E(!0)):(e.onBeforeExit&&e.onBeforeExit(),x(!1))},[u]),o.useEffect(()=>{const n=v.current;n&&n.addEventListener("mousedown",f=>{f.target.closest(".neko-popup")||i.invokePopup(e.id,!1)})},[l]),o.useLayoutEffect(()=>{if(!l||!u)return;const n=requestAnimationFrame(()=>{x(!0)});return()=>cancelAnimationFrame(n)},[l,u]);function a(n){m&&u&&(e.onAfterEnter&&!b.current&&e.onAfterEnter(n),b.current=!0),!m&&!u&&(e.onAfterExit&&!b.current&&e.onAfterExit(n),E(!1),b.current=!0)}return l?d&&I.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"},onTransitionEnd:a,ref:v,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):null};c.PopupButton=N,c.PopupLayer=w,c.PopupWindow=L,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
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,I){"use strict";function O(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=O(e[i]))&&(t&&(t+=" "),t+=d)}else for(d in e)e[d]&&(t&&(t+=" "),t+=d);return t}function N(){for(var e,i,d=0,t="",u=arguments.length;d<u;d++)(e=arguments[d])&&(i=O(e))&&(t&&(t+=" "),t+=i);return t}const A=o.createContext({}),P=N,S=e=>{const i=o.useContext(A),[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 g(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(A.Provider,{value:{nodes:t,containerRef:x,invokePopup:k,mountNode:E,updateNodeProperty:g},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(A),[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,g]=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),g(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?.className.includes("neko-popup-backdrop")&&(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&&I.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"},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=S,c.PopupLayer=w,c.PopupWindow=L,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
2
2
  //# sourceMappingURL=index.umd.js.map
@@ -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?(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\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 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\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 on open moun and on close animation exit\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 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 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 function handleTransitionEnd(ev: React.TransitionEvent) {\n // On After Enter\n if (isVisible && isOpen) {\n if (props.onAfterEnter && !isAnimationFinished.current) props.onAfterEnter(ev);\n\n isAnimationFinished.current = true;\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 isAnimationFinished.current = true;\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","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 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]}
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;display:flex;align-items:center;justify-content:center;transition:.2s ease-in-out}.neko-popup-backdrop:not(.neko-popup-backdrop--active){visibility:hidden;opacity:0}.neko-popup-button{cursor:pointer}.neko-popup--noScroll{overflow:hidden;scrollbar-gutter:stable}
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;transition:.2s ease-in-out}.neko-popup-backdrop:not(.neko-popup-backdrop--active){visibility:hidden;opacity:0;touch-action:none!important;pointer-events:none!important}.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.8",
3
+ "version": "3.1.0",
4
4
  "description": "Simple and cool react popup package 🚀",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",