react-imperial-modal 2.0.1 → 3.0.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.
@@ -5,3 +5,4 @@ export declare const withResolvers: <T>() => {
5
5
  };
6
6
  export declare const ESC_KEY = "Escape";
7
7
  export declare const focusableSelector: string;
8
+ export declare const modalId: () => string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ModalProvider } from './ModalProvider';
2
2
  import { useModal } from './useModal';
3
+ import { useModalDangerously } from './useModalDangerously';
3
4
  import { ModalProps, ModalProviderConfig } from './types';
4
- export { ModalProvider, useModal };
5
+ export { ModalProvider, useModal, useModalDangerously };
5
6
  export type { ModalProps, ModalProviderConfig };
@@ -1,11 +1,11 @@
1
- import { jsx as C, jsxs as O } from "react/jsx-runtime";
2
- import I, { useRef as P, useContext as A, useLayoutEffect as K, useCallback as u, useState as L, useMemo as R } from "react";
3
- const q = () => {
4
- let s, t;
5
- return { promise: new Promise((i, l) => {
6
- s = i, t = l;
7
- }), resolve: s, reject: t };
8
- }, D = "Escape", N = [
1
+ import { jsx as j, jsxs as A } from "react/jsx-runtime";
2
+ import D, { useRef as R, useContext as O, useLayoutEffect as K, useCallback as m, useState as L, useMemo as q } from "react";
3
+ const S = () => {
4
+ let s, o;
5
+ return { promise: new Promise((l, n) => {
6
+ s = l, o = n;
7
+ }), resolve: s, reject: o };
8
+ }, N = "Escape", _ = [
9
9
  "a[href]:not([tabindex='-1'])",
10
10
  "area[href]:not([tabindex='-1'])",
11
11
  "input:not([disabled]):not([tabindex='-1'])",
@@ -15,128 +15,141 @@ const q = () => {
15
15
  "iframe:not([tabindex='-1'])",
16
16
  "[tabindex]:not([tabindex='-1'])",
17
17
  "[contentEditable=true]:not([tabindex='-1'])"
18
- ].join(", "), B = function({ className: s, entry: t }) {
19
- const { role: a = "dialog", label: i, labelledby: l, componentProps: d, Component: M } = t, n = P(null), { removeModal: m } = A(S);
18
+ ].join(", "), k = /* @__PURE__ */ (() => {
19
+ let s = 1;
20
+ return () => "modal_" + (s++ * 1664525 + 1013904223 >>> 0).toString(36);
21
+ })(), B = function({ className: s, entry: o }) {
22
+ const { role: M = "dialog", label: l, labelledby: n, componentProps: v, Component: b } = o, d = R(null), { removeModal: c } = O(C);
20
23
  K(() => {
21
24
  requestAnimationFrame(() => {
22
- var r;
23
- n.current && (n.current.showModal(), (r = n.current.querySelector(N)) == null || r.focus());
25
+ var a;
26
+ d.current && (d.current.showModal(), (a = d.current.querySelector(_)) == null || a.focus());
24
27
  });
25
28
  }, []);
26
- const f = u(
27
- (r) => {
28
- r.key === D && !t.ignoreEscape && m(t.instanceId);
29
+ const f = m(
30
+ (a) => {
31
+ a.key === N && !o.ignoreEscape && c(o.id);
29
32
  },
30
- [t, m]
33
+ [o, c]
31
34
  );
32
- return /* @__PURE__ */ C(
35
+ return /* @__PURE__ */ j(
33
36
  "dialog",
34
37
  {
35
- ref: n,
36
- role: a,
37
- "aria-label": i,
38
- "aria-labelledby": l,
38
+ ref: d,
39
+ role: M,
40
+ "aria-label": l,
41
+ "aria-labelledby": n,
39
42
  className: s,
40
43
  onKeyDown: f,
41
- children: /* @__PURE__ */ C(
42
- M,
44
+ children: /* @__PURE__ */ j(
45
+ b,
43
46
  {
44
- close: t.closeModal,
45
- resolve: t.resolveModal,
46
- reject: t.rejectModal,
47
- ...d
47
+ close: o.closeModal,
48
+ resolve: o.resolveModal,
49
+ reject: o.rejectModal,
50
+ ...v
48
51
  }
49
52
  )
50
53
  }
51
54
  );
52
- }, g = () => {
55
+ }, y = () => {
53
56
  throw new Error(
54
57
  "Attempted to call useModal outside of modal context. Make sure your component is inside ModalProvider."
55
58
  );
56
- }, S = I.createContext({
57
- addModal: g,
58
- removeModal: g,
59
- resolveModal: g,
60
- rejectModal: g
61
- }), F = {
62
- bodyOpenClass: "modal-open",
63
- modalContainerClass: "modals",
64
- modalClass: "modal"
65
- }, w = document.documentElement, k = document.body, Y = ({ children: s, config: t = {} }) => {
66
- const [a, i] = L([]), l = R(() => ({ ...F, ...t }), [t]), d = P(null), M = P([]), n = a.at(-1), m = u(() => {
59
+ }, C = D.createContext({
60
+ addModal: y,
61
+ removeModal: y,
62
+ resolveModal: y,
63
+ rejectModal: y
64
+ }), g = document.documentElement, P = document.body, T = ({ children: s, config: o = {} }) => {
65
+ const [M, l] = L([]), n = R(null), v = R([]), b = m(() => {
67
66
  var e;
68
- k.classList.add(l.bodyOpenClass), (e = d == null ? void 0 : d.current) == null || e.setAttribute("aria-hidden", "true"), w.style.overflow = "hidden";
69
- }, [l]), f = u(() => {
67
+ o.bodyOpenClass && P.classList.add(o.bodyOpenClass), (e = n == null ? void 0 : n.current) == null || e.setAttribute("aria-hidden", "true"), g.style.overflow = "hidden";
68
+ }, [o]), d = m(() => {
70
69
  var e;
71
- k.classList.remove(l.bodyOpenClass), (e = d == null ? void 0 : d.current) == null || e.removeAttribute("aria-hidden"), w.style.overflow = "";
72
- }, [l]), r = u(
70
+ o.bodyOpenClass && P.classList.remove(o.bodyOpenClass), (e = n == null ? void 0 : n.current) == null || e.removeAttribute("aria-hidden"), g.style.overflow = "";
71
+ }, [o]), c = m(
73
72
  (e) => {
74
- i((o) => o.includes(e) ? o : (o.length === 0 && m(), M.current.push(document.activeElement), [...o, e]));
73
+ l((t) => t.includes(e) ? t : (t.length === 0 && b(), v.current.push(document.activeElement), [...t, e]));
75
74
  },
76
- [m]
77
- ), p = u(
75
+ [b]
76
+ ), f = m(
78
77
  (e) => {
79
- i((o) => {
80
- const E = o.find((y) => y.instanceId === e), c = e === void 0 ? n : E, v = o.length === 1, j = M.current.pop();
81
- return !c || !o.includes(c) ? o : (v && j && w.contains(j) && j.focus(), v && f(), o.filter((y) => c !== y));
78
+ l((t) => {
79
+ const u = t.at(-1), E = t.find((w) => w.id === e), x = e === void 0 ? u : E, r = t.length === 1, h = v.current.pop();
80
+ return !x || !t.includes(x) ? t : (r && h && g.contains(h) && h.focus(), r && d(), t.filter((w) => x !== w));
82
81
  });
83
82
  },
84
- [f, n]
85
- ), b = u(
86
- (e, o) => {
87
- const E = a.find((v) => v.instanceId === o), c = o === void 0 ? n : E;
88
- c == null || c.resolveModal(e || null);
89
- },
90
- [a, n]
91
- ), x = u(
92
- (e, o) => {
93
- const E = a.find((v) => v.instanceId === o), c = o === void 0 ? n : E;
94
- c == null || c.rejectModal(e || null);
95
- },
96
- [a, n]
97
- ), h = R(
98
- () => ({ addModal: r, removeModal: p, resolveModal: b, rejectModal: x }),
99
- [r, p, b, x]
83
+ [d]
84
+ ), a = m((e, t) => {
85
+ l((u) => {
86
+ const E = u.at(-1), x = u.find((h) => h.id === t), r = t === void 0 ? E : x;
87
+ return r == null || r.resolveModal(e || null), u;
88
+ });
89
+ }, []), i = m((e, t) => {
90
+ l((u) => {
91
+ const E = u.at(-1), x = u.find((h) => h.id === t), r = t === void 0 ? E : x;
92
+ return r == null || r.rejectModal(e), u;
93
+ });
94
+ }, []), p = q(
95
+ () => ({ addModal: c, removeModal: f, resolveModal: a, rejectModal: i }),
96
+ [c, f, a, i]
100
97
  );
101
- return /* @__PURE__ */ O(S.Provider, { value: h, children: [
102
- /* @__PURE__ */ C("div", { ref: d, children: s }),
103
- /* @__PURE__ */ C("div", { className: l.modalContainerClass, children: a.map((e) => /* @__PURE__ */ C(
104
- B,
105
- {
106
- className: l.modalClass,
107
- entry: e
108
- },
109
- e.instanceId
110
- )) })
98
+ return /* @__PURE__ */ A(C.Provider, { value: p, children: [
99
+ /* @__PURE__ */ j("div", { ref: n, children: s }),
100
+ /* @__PURE__ */ j("div", { className: o.modalContainerClass, children: M.map((e) => /* @__PURE__ */ j(B, { className: o.modalClass, entry: e }, e.id)) })
111
101
  ] });
112
- };
113
- let T = 1;
114
- const _ = () => {
115
- const s = A(S);
116
- return [u(
117
- (a, i, l = !1, d, M, n = "dialog") => {
118
- const { promise: m, resolve: f, reject: r } = q(), p = (T++ / 5).toString(32), b = () => s.removeModal(p), x = Object.assign(m, {
119
- instanceId: p,
120
- Component: a,
121
- componentProps: i,
102
+ }, V = () => {
103
+ const s = O(C);
104
+ return m(
105
+ (o, M, l = !1, n, v, b = "dialog") => {
106
+ const { promise: d, resolve: c, reject: f } = S(), a = k(), i = () => s.removeModal(a), p = Object.assign(d, {
107
+ id: a,
108
+ Component: o,
109
+ componentProps: M,
122
110
  ignoreEscape: l,
123
- labelledby: M,
124
- label: d,
125
- role: n,
126
- resolveModal: (h) => {
127
- f(h), b();
111
+ labelledby: v,
112
+ label: n,
113
+ role: b,
114
+ resolveModal: (e) => {
115
+ c(e), i();
116
+ },
117
+ rejectModal: (e) => {
118
+ f(e), i();
119
+ },
120
+ closeModal: i
121
+ });
122
+ return s.addModal(p), p;
123
+ },
124
+ [s]
125
+ );
126
+ }, W = () => {
127
+ const s = O(C);
128
+ return [m(
129
+ (M, l, n = !1, v, b, d = "dialog") => {
130
+ const { promise: c, resolve: f, reject: a } = S(), i = k(), p = () => s.removeModal(i), e = Object.assign(c, {
131
+ id: i,
132
+ Component: M,
133
+ componentProps: l,
134
+ ignoreEscape: n,
135
+ labelledby: b,
136
+ label: v,
137
+ role: d,
138
+ resolveModal: (t) => {
139
+ f(t), p();
128
140
  },
129
- rejectModal: (h) => {
130
- r(h), b();
141
+ rejectModal: (t) => {
142
+ a(t), p();
131
143
  },
132
- closeModal: b
144
+ closeModal: p
133
145
  });
134
- return s.addModal(x), x;
146
+ return s.addModal(e), e;
135
147
  },
136
148
  [s]
137
- ), s.resolveModal, s.rejectModal];
149
+ ), s.removeModal, s.resolveModal, s.rejectModal];
138
150
  };
139
151
  export {
140
- Y as ModalProvider,
141
- _ as useModal
152
+ T as ModalProvider,
153
+ V as useModal,
154
+ W as useModalDangerously
142
155
  };
@@ -1 +1 @@
1
- (function(u,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],c):(u=typeof globalThis<"u"?globalThis:u||self,c(u["react-imperial-modal"]={},u.jsxRuntime,u.React))})(this,(function(u,c,e){"use strict";const O=()=>{let l,n;return{promise:new Promise((f,d)=>{l=f,n=d}),resolve:l,reject:n}},q="Escape",A=["a[href]:not([tabindex='-1'])","area[href]:not([tabindex='-1'])","input:not([disabled]):not([tabindex='-1'])","select:not([disabled]):not([tabindex='-1'])","textarea:not([disabled]):not([tabindex='-1'])","button:not([disabled]):not([tabindex='-1'])","iframe:not([tabindex='-1'])","[tabindex]:not([tabindex='-1'])","[contentEditable=true]:not([tabindex='-1'])"].join(", "),T=function({className:l,entry:n}){const{role:a="dialog",label:f,labelledby:d,componentProps:r,Component:M}=n,s=e.useRef(null),{removeModal:b}=e.useContext(g);e.useLayoutEffect(()=>{requestAnimationFrame(()=>{var m;s.current&&(s.current.showModal(),(m=s.current.querySelector(A))==null||m.focus())})},[]);const v=e.useCallback(m=>{m.key===q&&!n.ignoreEscape&&b(n.instanceId)},[n,b]);return c.jsx("dialog",{ref:s,role:a,"aria-label":f,"aria-labelledby":d,className:l,onKeyDown:v,children:c.jsx(M,{close:n.closeModal,resolve:n.resolveModal,reject:n.rejectModal,...r})})},y=()=>{throw new Error("Attempted to call useModal outside of modal context. Make sure your component is inside ModalProvider.")},g=e.createContext({addModal:y,removeModal:y,resolveModal:y,rejectModal:y}),I={bodyOpenClass:"modal-open",modalContainerClass:"modals",modalClass:"modal"},k=document.documentElement,S=document.body,K=({children:l,config:n={}})=>{const[a,f]=e.useState([]),d=e.useMemo(()=>({...I,...n}),[n]),r=e.useRef(null),M=e.useRef([]),s=a.at(-1),b=e.useCallback(()=>{var o;S.classList.add(d.bodyOpenClass),(o=r==null?void 0:r.current)==null||o.setAttribute("aria-hidden","true"),k.style.overflow="hidden"},[d]),v=e.useCallback(()=>{var o;S.classList.remove(d.bodyOpenClass),(o=r==null?void 0:r.current)==null||o.removeAttribute("aria-hidden"),k.style.overflow=""},[d]),m=e.useCallback(o=>{f(t=>t.includes(o)?t:(t.length===0&&b(),M.current.push(document.activeElement),[...t,o]))},[b]),h=e.useCallback(o=>{f(t=>{const E=t.find(P=>P.instanceId===o),i=o===void 0?s:E,x=t.length===1,w=M.current.pop();return!i||!t.includes(i)?t:(x&&w&&k.contains(w)&&w.focus(),x&&v(),t.filter(P=>i!==P))})},[v,s]),p=e.useCallback((o,t)=>{const E=a.find(x=>x.instanceId===t),i=t===void 0?s:E;i==null||i.resolveModal(o||null)},[a,s]),C=e.useCallback((o,t)=>{const E=a.find(x=>x.instanceId===t),i=t===void 0?s:E;i==null||i.rejectModal(o||null)},[a,s]),j=e.useMemo(()=>({addModal:m,removeModal:h,resolveModal:p,rejectModal:C}),[m,h,p,C]);return c.jsxs(g.Provider,{value:j,children:[c.jsx("div",{ref:r,children:l}),c.jsx("div",{className:d.modalContainerClass,children:a.map(o=>c.jsx(T,{className:d.modalClass,entry:o},o.instanceId))})]})};let L=1;const D=()=>{const l=e.useContext(g);return[e.useCallback((a,f,d=!1,r,M,s="dialog")=>{const{promise:b,resolve:v,reject:m}=O(),h=(L++/5).toString(32),p=()=>l.removeModal(h),C=Object.assign(b,{instanceId:h,Component:a,componentProps:f,ignoreEscape:d,labelledby:M,label:r,role:s,resolveModal:j=>{v(j),p()},rejectModal:j=>{m(j),p()},closeModal:p});return l.addModal(C),C},[l]),l.resolveModal,l.rejectModal]};u.ModalProvider=K,u.useModal=D,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(c,i){typeof exports=="object"&&typeof module<"u"?i(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],i):(c=typeof globalThis<"u"?globalThis:c||self,i(c["react-imperial-modal"]={},c.jsxRuntime,c.React))})(this,(function(c,i,s){"use strict";const P=()=>{let l,o;return{promise:new Promise((d,n)=>{l=d,o=n}),resolve:l,reject:o}},q="Escape",A=["a[href]:not([tabindex='-1'])","area[href]:not([tabindex='-1'])","input:not([disabled]):not([tabindex='-1'])","select:not([disabled]):not([tabindex='-1'])","textarea:not([disabled]):not([tabindex='-1'])","button:not([disabled]):not([tabindex='-1'])","iframe:not([tabindex='-1'])","[tabindex]:not([tabindex='-1'])","[contentEditable=true]:not([tabindex='-1'])"].join(", "),S=(()=>{let l=1;return()=>"modal_"+(l++*1664525+1013904223>>>0).toString(36)})(),D=function({className:l,entry:o}){const{role:f="dialog",label:d,labelledby:n,componentProps:v,Component:p}=o,r=s.useRef(null),{removeModal:m}=s.useContext(k);s.useLayoutEffect(()=>{requestAnimationFrame(()=>{var a;r.current&&(r.current.showModal(),(a=r.current.querySelector(A))==null||a.focus())})},[]);const x=s.useCallback(a=>{a.key===q&&!o.ignoreEscape&&m(o.id)},[o,m]);return i.jsx("dialog",{ref:r,role:f,"aria-label":d,"aria-labelledby":n,className:l,onKeyDown:x,children:i.jsx(p,{close:o.closeModal,resolve:o.resolveModal,reject:o.rejectModal,...v})})},E=()=>{throw new Error("Attempted to call useModal outside of modal context. Make sure your component is inside ModalProvider.")},k=s.createContext({addModal:E,removeModal:E,resolveModal:E,rejectModal:E}),g=document.documentElement,O=document.body,T=({children:l,config:o={}})=>{const[f,d]=s.useState([]),n=s.useRef(null),v=s.useRef([]),p=s.useCallback(()=>{var e;o.bodyOpenClass&&O.classList.add(o.bodyOpenClass),(e=n==null?void 0:n.current)==null||e.setAttribute("aria-hidden","true"),g.style.overflow="hidden"},[o]),r=s.useCallback(()=>{var e;o.bodyOpenClass&&O.classList.remove(o.bodyOpenClass),(e=n==null?void 0:n.current)==null||e.removeAttribute("aria-hidden"),g.style.overflow=""},[o]),m=s.useCallback(e=>{d(t=>t.includes(e)?t:(t.length===0&&p(),v.current.push(document.activeElement),[...t,e]))},[p]),x=s.useCallback(e=>{d(t=>{const b=t.at(-1),y=t.find(w=>w.id===e),j=e===void 0?b:y,u=t.length===1,C=v.current.pop();return!j||!t.includes(j)?t:(u&&C&&g.contains(C)&&C.focus(),u&&r(),t.filter(w=>j!==w))})},[r]),a=s.useCallback((e,t)=>{d(b=>{const y=b.at(-1),j=b.find(C=>C.id===t),u=t===void 0?y:j;return u==null||u.resolveModal(e||null),b})},[]),M=s.useCallback((e,t)=>{d(b=>{const y=b.at(-1),j=b.find(C=>C.id===t),u=t===void 0?y:j;return u==null||u.rejectModal(e),b})},[]),h=s.useMemo(()=>({addModal:m,removeModal:x,resolveModal:a,rejectModal:M}),[m,x,a,M]);return i.jsxs(k.Provider,{value:h,children:[i.jsx("div",{ref:n,children:l}),i.jsx("div",{className:o.modalContainerClass,children:f.map(e=>i.jsx(D,{className:o.modalClass,entry:e},e.id))})]})},K=()=>{const l=s.useContext(k);return s.useCallback((o,f,d=!1,n,v,p="dialog")=>{const{promise:r,resolve:m,reject:x}=P(),a=S(),M=()=>l.removeModal(a),h=Object.assign(r,{id:a,Component:o,componentProps:f,ignoreEscape:d,labelledby:v,label:n,role:p,resolveModal:e=>{m(e),M()},rejectModal:e=>{x(e),M()},closeModal:M});return l.addModal(h),h},[l])},L=()=>{const l=s.useContext(k);return[s.useCallback((f,d,n=!1,v,p,r="dialog")=>{const{promise:m,resolve:x,reject:a}=P(),M=S(),h=()=>l.removeModal(M),e=Object.assign(m,{id:M,Component:f,componentProps:d,ignoreEscape:n,labelledby:p,label:v,role:r,resolveModal:t=>{x(t),h()},rejectModal:t=>{a(t),h()},closeModal:h});return l.addModal(e),e},[l]),l.removeModal,l.resolveModal,l.rejectModal]};c.ModalProvider=T,c.useModal=K,c.useModalDangerously=L,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
package/dist/types.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ReactNode } from 'react';
2
- export interface ModalProps<T> {
2
+ export interface ModalProps<T = void> {
3
3
  resolve: (val: T | null) => void;
4
4
  reject: (reason?: unknown) => void;
5
5
  close: () => void;
6
6
  }
7
7
  export type ModalEntry<T, P> = Promise<T | null> & {
8
- instanceId: string;
8
+ id: string;
9
9
  Component: React.ComponentType<P & ModalProps<T>>;
10
10
  componentProps: P;
11
11
  resolveModal: (val: T | null) => void;
@@ -27,7 +27,7 @@ export type ModalProviderProps = {
27
27
  };
28
28
  export type ModalContextValue = {
29
29
  addModal: (entry: ModalEntry<unknown, unknown>) => void;
30
- removeModal: (instanceId?: string) => void;
31
- resolveModal: (val: unknown | null, instanceId?: string) => void;
32
- rejectModal: (val: unknown | null, instanceId?: string) => void;
30
+ removeModal: (id?: string) => void;
31
+ resolveModal: (val: unknown | null, id?: string) => void;
32
+ rejectModal: (reason?: unknown, id?: string) => void;
33
33
  };
@@ -1,2 +1,2 @@
1
1
  import { ModalEntry, ModalProps } from './types';
2
- export declare const useModal: () => readonly [<T, P>(Component: React.ComponentType<P & ModalProps<T>>, componentProps: P, ignoreEscape?: boolean, label?: string, labelledby?: string, role?: string) => ModalEntry<T, P>, (val: unknown | null, instanceId?: string) => void, (val: unknown | null, instanceId?: string) => void];
2
+ export declare const useModal: () => <T, P>(Component: React.ComponentType<P & ModalProps<T>>, componentProps: P, ignoreEscape?: boolean, label?: string, labelledby?: string, role?: string) => ModalEntry<T, P>;
@@ -0,0 +1,2 @@
1
+ import { ModalEntry, ModalProps } from './types';
2
+ export declare const useModalDangerously: () => readonly [<T, P>(Component: React.ComponentType<P & ModalProps<T>>, componentProps: P, ignoreEscape?: boolean, label?: string, labelledby?: string, role?: string) => ModalEntry<T, P>, (id?: string) => void, (val: unknown | null, id?: string) => void, (reason?: unknown, id?: string) => void];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-imperial-modal",
3
- "version": "2.0.1",
3
+ "version": "3.0.0",
4
4
  "description": "imperative modal api for react",
5
5
  "author": "Greg Archer (greg.taff@gmail.com)",
6
6
  "license": "MIT",