react-pure-modal 3.0.1 → 3.0.3

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
@@ -28,6 +28,8 @@ https://memcrab.github.io/react-pure-modal/
28
28
  ## Usage
29
29
 
30
30
  ```jsx
31
+ import Modal from "react-pure-modal";
32
+
31
33
  <Modal
32
34
  isOpen={isOpen}
33
35
  onClose={onClose}
@@ -45,21 +47,67 @@ https://memcrab.github.io/react-pure-modal/
45
47
  </Modal>
46
48
  ```
47
49
 
50
+ ## Context
51
+
52
+ Use the exported context hook when you need modal state inside custom children (for example, a custom close button passed into `Modal.Close`).
53
+
54
+ ```jsx
55
+ import Modal, { useModalContext } from "react-pure-modal";
56
+
57
+ function CustomCloseContent() {
58
+ const { onClose } = useModalContext();
59
+ return (
60
+ <button type="button" onClick={() => onClose?.()}>
61
+ Save & Close
62
+ </button>
63
+ );
64
+ }
65
+
66
+ <Modal.Close>
67
+ <CustomCloseContent />
68
+ </Modal.Close>
69
+ ```
70
+
71
+ The context provides: `isOpen`, `onClose`, `closeOnBackdropClick`, and `style`.
72
+
73
+ `Modal.Close` renders the default icon button when no children are provided.
74
+
75
+ ## Portal
76
+
77
+ Render the modal into a dedicated DOM node (for example, a `#modal-root`
78
+ mounted near `body`).
79
+
80
+ ```jsx
81
+ import Modal from "react-pure-modal";
82
+
83
+ const portalRoot = document.getElementById("modal-root");
84
+
85
+ <Modal isOpen={isOpen} onClose={onClose} portal={portalRoot}>
86
+ <Modal.Close />
87
+ <Modal.Content>Portal content</Modal.Content>
88
+ </Modal>
89
+ ```
90
+
48
91
  ## Options
49
92
 
50
- - `isOpen` (boolean, required) - controls whether the modal is rendered.
51
- - `onClose` (() => boolean | void) - called when the user clicks the close button, presses ESC, or (optionally) clicks the backdrop; set `isOpen` to `false` inside it.
93
+ - `isOpen` (boolean) - controls whether the modal is rendered; defaults to `false`.
94
+ - `onClose` (VoidFunction) - called when the user clicks the close button, presses ESC, or (optionally) clicks the backdrop; set `isOpen` to `false` inside it. Any return value is ignored.
52
95
  - `closeOnBackdropClick` (boolean) - if `true`, clicking the backdrop calls `onClose` (default is `false`).
53
- - `style` (React.CSSProperties) - inline styles applied to the backdrop element; use this to set CSS custom properties (listed below) or to tweak things like `zIndex`.
96
+ - `style` (CSS custom properties) - inline CSS variables applied to the backdrop element; use this to set the variables listed below. TypeScript users can reference the exported `ModalCssVariable` union for autocomplete.
97
+ - `portal` (Element | DocumentFragment | null) - when provided, render the modal into the target via `createPortal`. If set during SSR (no `document`) or the node is missing, the modal returns `null`.
54
98
  - `children` - compose the modal from the provided compounds: `Modal.Close`, `Modal.Header`, `Modal.Content`, and `Modal.Footer`.
55
99
 
100
+ ## Compound component props
101
+
102
+ - `Modal.Header align` (`"start" | "center" | "end"`) - horizontal alignment for header content (default: `start`).
103
+ - `Modal.Footer align` (`"start" | "center" | "end"`) - horizontal alignment for footer content (default: `start`).
104
+
56
105
  ## CSS Variables
57
106
 
58
- All variables can be provided through the `style` prop (e.g. `style={{ "--radius": "16px" }}`).
107
+ All variables can be provided through the `style` prop (e.g. `style={{ "--radius": "16px" }}`). Close button variables apply when `Modal.Close` is rendered.
59
108
 
60
109
  - `--radius` - border radius of the modal container (mobile uses `12px 12px 0 0`).
61
110
  - `--aspect-ratio` - forced aspect ratio for the modal grid.
62
- - `--backdrop-blur` - available for custom use if you want to reference a blur amount.
63
111
  - `--backdrop-filter` - value for the backdrop `backdrop-filter` property.
64
112
  - `--backdrop-color` - background color of the overlay.
65
113
  - `--box-shadow` - shadow applied to the modal panel.
@@ -68,14 +116,21 @@ All variables can be provided through the `style` prop (e.g. `style={{ "--radius
68
116
  - `--min-width` - minimum width of the modal.
69
117
  - `--background` - modal surface background.
70
118
  - `--background-panels` - background for header and footer panels.
71
- - `--contrast-color` - high-contrast color derived from `--background-panels` (used to build borders and hover states); override to steer the automatic mix.
119
+ - `--close-button-background` - background for the close icon circle.
120
+ - `--close-button-border` - border applied to the close icon circle (defaults to `var(--dividers-border)`).
121
+ - `--close-button-size` - diameter of the close icon circle.
122
+ - `--close-button-container-transform` - transform applied to the close button container (for positional nudges).
123
+ - `--close-button-place-self` - `place-self` value for the close button container (defaults to `start end`).
124
+ - `--close-button-grid-row` - grid row for the close button container (defaults to `1`).
125
+ - `--close-button-hover-transform` - transform applied to the close icon on hover.
72
126
  - `--z-index` - base stacking level for the backdrop (panel uses `+1`).
73
127
  - `--top-content-padding` / `--bottom-content-padding` - vertical padding for the content area.
74
128
  - `--top-header-padding` / `--bottom-header-padding` - vertical padding for the header.
129
+ - `--header-left-padding` / `--header-right-padding` - horizontal padding for the header (defaults to `--left-padding`/`--right-padding`).
75
130
  - `--top-footer-padding` / `--bottom-footer-padding` - vertical padding for the footer.
76
131
  - `--left-padding` / `--right-padding` - horizontal padding shared across sections.
77
- - `--dividers-color` - border tone mixed from `--background-panels` and `--contrast-color` by default; override to force a specific divider color.
78
- - `--border` - border applied to header, footer, and close button; defaults to `1px solid var(--dividers-color)`.
132
+ - `--dividers-color` - border color for header/footer dividers (also used as the default close icon border).
133
+ - `--dividers-border` - border applied to header/footer dividers (defaults to `1px solid var(--dividers-color)`).
79
134
 
80
135
 
81
136
  ## Changelog (latest on top)
@@ -127,6 +182,12 @@ Build the library in watch mode:
127
182
  pnpm dev
128
183
  ```
129
184
 
185
+ Run type checks:
186
+
187
+ ```bash
188
+ pnpm typecheck
189
+ ```
190
+
130
191
  ## Publishing a new version
131
192
 
132
193
  1. Bump the package version and rebuild: `npm version <patch|minor|major>` then `npm run build`; commit the updated files (including `dist`) and push to `master`/`main`.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{jsx as e}from"react/jsx-runtime";import{createContext as o,useCallback as r,useContext as t,useEffect as n,useId as a,useLayoutEffect as d,useMemo as i,useRef as l}from"react";var s={"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/index.js??ruleSet[1].rules[1].use[1]!builtin:lightningcss-loader??ruleSet[1].rules[1].use[2]!./src/compounds/Modal.module.css":function(e,o,r){r.d(o,{A:()=>i});var t=r("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/noSourceMaps.js"),n=r.n(t),a=r("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/api.js"),d=r.n(a)()(n());d.push([e.id,"body:has(.pureModalBackdrop-RW7tAF){overflow:hidden}.pureModalBackdrop-RW7tAF{--radius:12px;--aspect-ratio:auto;--backdrop-blur:2px;--backdrop-color:#0006;--box-shadow:0px 1px 2px #00000024,0px 8px 20px #0000002e,0px 20px 48px #00000038;--max-width:95vw;--max-height:90vh;--min-width:320px;--background:white;--background-panels:#ffffffe6;--z-index:1041;--top-content-padding:16px;--bottom-content-padding:16px;--top-header-padding:16px;--bottom-header-padding:16px;--top-footer-padding:16px;--bottom-footer-padding:16px;--left-padding:24px;--base-right-padding:24px;--right-padding:var(--base-right-padding);--close-button-background:var(--background-panels,white);--close-button-size:30px;--close-button-hit-padding:calc(var(--right-padding)/2);--close-button-space:var(--close-button-size);--contrast-color:oklch(from var(--background-panels)clamp(.08,calc(1 - l),.92)c h);--dividers-color:color-mix(in oklch,var(--background-panels)78%,var(--contrast-color)22%);--border:1px solid var(--dividers-color);--backdrop-filter:blur(3px);backdrop-filter:var(--backdrop-filter);z-index:var(--z-index);background-color:var(--backdrop-color);flex-direction:column;justify-content:center;align-items:center;animation:.26s cubic-bezier(.16,.84,.44,1) both backdropFadeSmooth-ZnEuSQ;display:flex;position:fixed;inset:0;overflow:auto}@keyframes backdropFadeSmooth-ZnEuSQ{0%{opacity:0;-webkit-backdrop-filter:blur();background-color:#0000}to{opacity:1;backdrop-filter:var(--backdrop-filter);background-color:var(--backdrop-color)}}.pureModal-Hr1gWI{z-index:calc(var(--z-index) + 1);background:var(--background);box-shadow:var(--box-shadow);border-radius:var(--radius);max-height:var(--max-height);max-width:max(320px,var(--max-width));min-width:var(--min-width);aspect-ratio:var(--aspect-ratio);grid-template-rows:auto minmax(0,1fr) minmax(0,max-content);grid-template-columns:1fr;grid-auto-flow:row;display:grid;overflow:auto;&:has(>.pureModalHeader-DahjVw)>.pureModalContent-t7nwPr{grid-row:2}animation:.24s cubic-bezier(.18,.77,.42,1) both panelSoftPop-JNSB6U}@keyframes panelSoftPop-JNSB6U{0%{opacity:0;transform:translateY(8px)scale(.97)}to{opacity:1;transform:translateY(0)scale(1)}}.pureModalHeader-DahjVw{padding:var(--top-header-padding)var(--right-padding)var(--bottom-header-padding)var(--left-padding);border-bottom:var(--border);background:var(--background-panels);box-sizing:border-box;grid-area:1/1;align-items:center;width:100%;display:flex}.pureModalContent-t7nwPr{padding:var(--top-content-padding)var(--right-padding)var(--bottom-content-padding)var(--left-padding);box-sizing:border-box;overscroll-behavior:contain;width:100%;grid-area:1/1/2/-1;min-block-size:0;overflow:auto}.pureModalFooter-hj8jgh{padding:var(--top-footer-padding)var(--right-padding)calc(var(--bottom-footer-padding) + env(safe-area-inset-bottom))var(--left-padding);border-top:var(--border);background:var(--background-panels);box-sizing:border-box;grid-area:3/1/auto/-1;width:100%;display:block}@media (width<=600px){.pureModalBackdrop-RW7tAF{--radius:12px 12px 0 0;justify-content:end}.pureModal-Hr1gWI{--aspect-ratio:auto;min-width:var(--max-width);animation:.28s cubic-bezier(.25,.85,.35,1) panelSheetIn-loLXeB}@keyframes panelSheetIn-loLXeB{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}}.pureModal-Hr1gWI:has(.pureCloseButton-Ac2K32) .pureModalHeader-DahjVw{--right-padding:calc(var(--base-right-padding) + var(--close-button-space))}.pureCloseButton-Ac2K32{padding:var(--close-button-hit-padding);z-index:3;grid-area:1/1/auto/-1;place-self:start end;align-items:center;display:flex}.pureCloseButtonIcon-m_tk65{font-weight:700;font-size:calc(var(--close-button-size)/2);height:var(--close-button-size);color:var(--dividers-color);width:var(--close-button-size);cursor:pointer;text-align:center;line-height:calc(var(--close-button-size) - 1px);aspect-ratio:1;border:var(--border);background:var(--close-button-background);border-radius:50%;padding:0;transition:all .1s ease-in-out;&:hover{color:var(--contrast-color);border-color:var(--contrast-color)}}",""]),d.locals={pureModalBackdrop:"pureModalBackdrop-RW7tAF",backdropFadeSmooth:"backdropFadeSmooth-ZnEuSQ",pureModal:"pureModal-Hr1gWI",panelSoftPop:"panelSoftPop-JNSB6U",pureModalHeader:"pureModalHeader-DahjVw",pureModalContent:"pureModalContent-t7nwPr",pureModalFooter:"pureModalFooter-hj8jgh",panelSheetIn:"panelSheetIn-loLXeB",pureCloseButton:"pureCloseButton-Ac2K32",pureCloseButtonIcon:"pureCloseButtonIcon-m_tk65"};let i=d},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/api.js":function(e){e.exports=function(e){var o=[];return o.toString=function(){return this.map(function(o){var r="",t=void 0!==o[5];return o[4]&&(r+="@supports (".concat(o[4],") {")),o[2]&&(r+="@media ".concat(o[2]," {")),t&&(r+="@layer".concat(o[5].length>0?" ".concat(o[5]):""," {")),r+=e(o),t&&(r+="}"),o[2]&&(r+="}"),o[4]&&(r+="}"),r}).join("")},o.i=function(e,r,t,n,a){"string"==typeof e&&(e=[[null,e,void 0]]);var d={};if(t)for(var i=0;i<this.length;i++){var l=this[i][0];null!=l&&(d[l]=!0)}for(var s=0;s<e.length;s++){var c=[].concat(e[s]);t&&d[c[0]]||(void 0!==a&&(void 0===c[5]||(c[1]="@layer".concat(c[5].length>0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=a),r&&(c[2]&&(c[1]="@media ".concat(c[2]," {").concat(c[1],"}")),c[2]=r),n&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=n):c[4]="".concat(n)),o.push(c))}},o}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/noSourceMaps.js":function(e){e.exports=function(e){return e[1]}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/injectStylesIntoStyleTag.js":function(e){var o=[];function r(e){for(var r=-1,t=0;t<o.length;t++)if(o[t].identifier===e){r=t;break}return r}function t(e,t){for(var n={},a=[],d=0;d<e.length;d++){var i=e[d],l=t.base?i[0]+t.base:i[0],s=n[l]||0,c="".concat(l," ").concat(s);n[l]=s+1;var u=r(c),p={css:i[1],media:i[2],sourceMap:i[3],supports:i[4],layer:i[5]};if(-1!==u)o[u].references++,o[u].updater(p);else{var m=function(e,o){var r=o.domAPI(o);return r.update(e),function(o){o?(o.css!==e.css||o.media!==e.media||o.sourceMap!==e.sourceMap||o.supports!==e.supports||o.layer!==e.layer)&&r.update(e=o):r.remove()}}(p,t);t.byIndex=d,o.splice(d,0,{identifier:c,updater:m,references:1})}a.push(c)}return a}e.exports=function(e,n){var a=t(e=e||[],n=n||{});return function(e){e=e||[];for(var d=0;d<a.length;d++){var i=r(a[d]);o[i].references--}for(var l=t(e,n),s=0;s<a.length;s++){var c=r(a[s]);0===o[c].references&&(o[c].updater(),o.splice(c,1))}a=l}}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertBySelector.js":function(e){var o={};e.exports=function(e,r){var t=function(e){if(void 0===o[e]){var r=document.querySelector(e);if(window.HTMLIFrameElement&&r instanceof window.HTMLIFrameElement)try{r=r.contentDocument.head}catch(e){r=null}o[e]=r}return o[e]}(e);if(!t)throw Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");t.appendChild(r)}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertStyleElement.js":function(e){e.exports=function(e){var o=document.createElement("style");return e.setAttributes(o,e.attributes),e.insert(o,e.options),o}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/setAttributesWithoutAttributes.js":function(e,o,r){e.exports=function(e){var o=r.nc;o&&e.setAttribute("nonce",o)}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleDomAPI.js":function(e){e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var o=e.insertStyleElement(e);return{update:function(r){var t,n,a;t="",r.supports&&(t+="@supports (".concat(r.supports,") {")),r.media&&(t+="@media ".concat(r.media," {")),(n=void 0!==r.layer)&&(t+="@layer".concat(r.layer.length>0?" ".concat(r.layer):""," {")),t+=r.css,n&&(t+="}"),r.media&&(t+="}"),r.supports&&(t+="}"),(a=r.sourceMap)&&"undefined"!=typeof btoa&&(t+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),e.styleTagTransform(t,o,e.options)},remove:function(){var e;null===(e=o).parentNode||e.parentNode.removeChild(e)}}}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleTagTransform.js":function(e){e.exports=function(e,o){if(o.styleSheet)o.styleSheet.cssText=e;else{for(;o.firstChild;)o.removeChild(o.firstChild);o.appendChild(document.createTextNode(e))}}}},c={};function u(e){var o=c[e];if(void 0!==o)return o.exports;var r=c[e]={id:e,exports:{}};return s[e](r,r.exports,u),r.exports}u.n=e=>{var o=e&&e.__esModule?()=>e.default:()=>e;return u.d(o,{a:o}),o},u.d=(e,o)=>{for(var r in o)u.o(o,r)&&!u.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:o[r]})},u.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),u.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},u.nc=void 0;var p={};u.r(p),u.d(p,{default:()=>N});var m=u("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/injectStylesIntoStyleTag.js"),b=u.n(m),f=u("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleDomAPI.js"),v=u.n(f),g=u("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertBySelector.js"),h=u.n(g),x=u("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/setAttributesWithoutAttributes.js"),y=u.n(x),k=u("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertStyleElement.js"),M=u.n(k),S=u("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleTagTransform.js"),w=u.n(S),_=u("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/index.js??ruleSet[1].rules[1].use[1]!builtin:lightningcss-loader??ruleSet[1].rules[1].use[2]!./src/compounds/Modal.module.css"),j={};j.styleTagTransform=w(),j.setAttributes=y(),j.insert=h().bind(null,"head"),j.domAPI=v(),j.insertStyleElement=M(),b()(_.A,j);let C=_.A&&_.A.locals?_.A.locals:void 0,B=o(void 0);function I(e){if(!e)return -99999;let o=Number.parseInt(getComputedStyle(e).zIndex||"0",10);return Number.isNaN(o)?-99999:o}function z(e){return Math.max(Math.max(...Array.from(document.querySelectorAll(e)).map(e=>I(e))),1)}function A({children:o}){let{isOpen:a,onClose:i,style:s,closeOnBackdropClick:c}=t(B)??{},u=l(null),p=r(e=>{if(function(e){if(!e)return!1;let o=e.tagName.toLowerCase();return"input"===o||"textarea"===o||"select"===o||!!e.isContentEditable}(document.activeElement))return;let o=I(u.current),r=z(`.${C.pureModalBackdrop}`);return!!i&&"Escape"===e.key&&o===r&&(i(),!0)},[i]);return n(()=>{if(a)return document.addEventListener("keydown",p),()=>{document.removeEventListener("keydown",p)}},[a,p]),d(()=>{let e="number"==typeof s?.zIndex?s.zIndex:z(`.${C.pureModalBackdrop}`);u.current&&(u.current.style.zIndex=String(e+1))},[s?.zIndex]),e("div",{ref:u,className:C.pureModalBackdrop,onMouseDown:e=>{if(c){if(e){if(!e.target.classList.contains(C.pureModalBackdrop))return;e.stopPropagation(),e.preventDefault()}i?.()}},"aria-modal":"true",role:"dialog",style:s,children:o})}function N(o){let r=a(),t=i(()=>({isOpen:!!o.isOpen,onClose:o.onClose,closeOnBackdropClick:!!o.closeOnBackdropClick,style:o.style}),[o.isOpen,o.onClose,o.closeOnBackdropClick,o.style]);return t.isOpen?e(B.Provider,{value:t,children:e(A,{children:e("div",{id:`pure-modal-${r}`,className:C.pureModal,children:o.children})})}):null}N.Footer=function({children:o}){return e("div",{className:C.pureModalFooter,children:o})},N.Header=function({children:o}){return e("div",{className:C.pureModalHeader,children:o})},N.Backdrop=A,N.Content=function({children:o}){return e("div",{className:C.pureModalContent,children:o})},N.Close=function({children:o}){let{onClose:r}=t(B)??{};return e("div",{className:C.pureCloseButton,children:o||e("button",{type:"button",onClick:r,className:C.pureCloseButtonIcon,children:"✕"})})};export{p as Modal};
1
+ import{jsx as e}from"react/jsx-runtime";import{createContext as r,useCallback as o,useContext as t,useEffect as n,useId as a,useLayoutEffect as d,useMemo as i,useRef as l}from"react";import{createPortal as s}from"react-dom";var c={"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/index.js??ruleSet[1].rules[1].use[1]!builtin:lightningcss-loader??ruleSet[1].rules[1].use[2]!./src/compounds/Modal.module.css":function(e,r,o){o.d(r,{A:()=>i});var t=o("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/noSourceMaps.js"),n=o.n(t),a=o("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/api.js"),d=o.n(a)()(n());d.push([e.id,"body:has(.pureModalBackdrop-RW7tAF){overflow:hidden}.pureModalBackdrop-RW7tAF{--radius:12px;--aspect-ratio:auto;--backdrop-color:#0006;--box-shadow:0px 1px 2px #00000024,0px 8px 20px #0000002e,0px 20px 48px #00000038;--max-width:95vw;--max-height:90vh;--min-width:320px;--background:white;--background-panels:#ffffffe6;--top-content-padding:16px;--bottom-content-padding:16px;--top-footer-padding:16px;--bottom-footer-padding:16px;--left-padding:24px;--right-padding:24px;--header-right-padding:var(--right-padding);--header-left-padding:var(--left-padding);--z-index:1041;--backdrop-filter:blur(3px);--top-header-padding:16px;--bottom-header-padding:16px;--dividers-color:silver;--dividers-border:1px solid var(--dividers-color);--close-button-background:var(--background-panels,white);--close-button-size:30px;--close-button-container-transform:translate(calc(0px - var(--radius)),var(--radius));--close-button-place-self:start end;--close-button-border:var(--dividers-border);--close-button-hover-transform:scale(1.05);--close-button-grid-row:1;backdrop-filter:var(--backdrop-filter);z-index:var(--z-index);background-color:var(--backdrop-color);flex-direction:column;justify-content:center;align-items:center;animation:.26s cubic-bezier(.16,.84,.44,1) both backdropFadeSmooth-ZnEuSQ;display:flex;position:fixed;inset:0;overflow:auto}@keyframes backdropFadeSmooth-ZnEuSQ{0%{opacity:0;-webkit-backdrop-filter:blur();background-color:#0000}to{opacity:1;backdrop-filter:var(--backdrop-filter);background-color:var(--backdrop-color)}}.pureModal-Hr1gWI{z-index:calc(var(--z-index) + 1);background:var(--background);box-shadow:var(--box-shadow);border-radius:var(--radius);max-height:var(--max-height);max-width:max(320px,var(--max-width));min-width:var(--min-width);aspect-ratio:var(--aspect-ratio);grid-template-rows:auto minmax(0,1fr) minmax(0,max-content);grid-template-columns:1fr;grid-auto-flow:row;display:grid;overflow:visible;&:has(>.pureModalHeader-DahjVw)>.pureModalContent-t7nwPr{grid-row:2}animation:.24s cubic-bezier(.18,.77,.42,1) both panelSoftPop-JNSB6U}@keyframes panelSoftPop-JNSB6U{0%{opacity:0;transform:translateY(8px)scale(.97)}to{opacity:1;transform:translateY(0)scale(1)}}.pureModalHeader-DahjVw{padding:var(--top-header-padding)var(--header-right-padding)var(--bottom-header-padding)var(--header-left-padding);border-bottom:var(--dividers-border);border-radius:var(--radius)var(--radius)0 0;background:var(--background-panels);width:100%;max-width:max(320px,var(--max-width));box-sizing:border-box;text-align:left;grid-area:1/1;justify-content:flex-start;align-items:center;display:flex}.pureModalHeader-DahjVw[data-align=center]{text-align:center;justify-content:center}.pureModalHeader-DahjVw[data-align=end]{text-align:right;justify-content:flex-end}.pureModalContent-t7nwPr{padding:var(--top-content-padding)var(--right-padding)var(--bottom-content-padding)var(--left-padding);box-sizing:border-box;overscroll-behavior:contain;width:100%;grid-area:1/1/2/-1;min-block-size:0;overflow:auto}.pureModalFooter-hj8jgh{padding:var(--top-footer-padding)var(--right-padding)calc(var(--bottom-footer-padding) + env(safe-area-inset-bottom))var(--left-padding);border-top:var(--dividers-border);border-radius:0 0 var(--radius)var(--radius);background:var(--background-panels);text-align:left;width:100%;max-width:max(320px,var(--max-width));box-sizing:border-box;grid-area:3/1/auto/-1;display:block}.pureModalFooter-hj8jgh[data-align=center]{text-align:center;justify-content:center}.pureModalFooter-hj8jgh[data-align=end]{text-align:right;justify-content:flex-end}@media (width<=600px){.pureModalBackdrop-RW7tAF{--radius:12px 12px 0 0;justify-content:end}.pureModal-Hr1gWI{--aspect-ratio:auto;min-width:var(--max-width);animation:.28s cubic-bezier(.25,.85,.35,1) panelSheetIn-loLXeB}@keyframes panelSheetIn-loLXeB{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}}.pureCloseButton-Ac2K32{grid-row:var(--close-button-grid-row,1);place-self:var(--close-button-place-self,start end);transform:var(--close-button-container-transform,none);z-index:3;grid-column:1/-1;align-items:center;display:flex}.pureCloseButtonIcon-m_tk65{border-radius:calc(var(--radius)*2);font-weight:700;font-size:calc(var(--close-button-size)/2);line-height:calc(var(--close-button-size) - 1px);height:var(--close-button-size);color:var(--dividers-color);width:var(--close-button-size);cursor:pointer;text-align:center;aspect-ratio:1;border:var(--close-button-border);background:var(--close-button-background);padding:0;transition:all .1s ease-in-out;&:hover{transform:var(--close-button-hover-transform)}}",""]),d.locals={pureModalBackdrop:"pureModalBackdrop-RW7tAF",backdropFadeSmooth:"backdropFadeSmooth-ZnEuSQ",pureModal:"pureModal-Hr1gWI",panelSoftPop:"panelSoftPop-JNSB6U",pureModalHeader:"pureModalHeader-DahjVw",pureModalContent:"pureModalContent-t7nwPr",pureModalFooter:"pureModalFooter-hj8jgh",panelSheetIn:"panelSheetIn-loLXeB",pureCloseButton:"pureCloseButton-Ac2K32",pureCloseButtonIcon:"pureCloseButtonIcon-m_tk65"};let i=d},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/api.js":function(e){e.exports=function(e){var r=[];return r.toString=function(){return this.map(function(r){var o="",t=void 0!==r[5];return r[4]&&(o+="@supports (".concat(r[4],") {")),r[2]&&(o+="@media ".concat(r[2]," {")),t&&(o+="@layer".concat(r[5].length>0?" ".concat(r[5]):""," {")),o+=e(r),t&&(o+="}"),r[2]&&(o+="}"),r[4]&&(o+="}"),o}).join("")},r.i=function(e,o,t,n,a){"string"==typeof e&&(e=[[null,e,void 0]]);var d={};if(t)for(var i=0;i<this.length;i++){var l=this[i][0];null!=l&&(d[l]=!0)}for(var s=0;s<e.length;s++){var c=[].concat(e[s]);t&&d[c[0]]||(void 0!==a&&(void 0===c[5]||(c[1]="@layer".concat(c[5].length>0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=a),o&&(c[2]&&(c[1]="@media ".concat(c[2]," {").concat(c[1],"}")),c[2]=o),n&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=n):c[4]="".concat(n)),r.push(c))}},r}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/noSourceMaps.js":function(e){e.exports=function(e){return e[1]}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/injectStylesIntoStyleTag.js":function(e){var r=[];function o(e){for(var o=-1,t=0;t<r.length;t++)if(r[t].identifier===e){o=t;break}return o}function t(e,t){for(var n={},a=[],d=0;d<e.length;d++){var i=e[d],l=t.base?i[0]+t.base:i[0],s=n[l]||0,c="".concat(l," ").concat(s);n[l]=s+1;var u=o(c),p={css:i[1],media:i[2],sourceMap:i[3],supports:i[4],layer:i[5]};if(-1!==u)r[u].references++,r[u].updater(p);else{var m=function(e,r){var o=r.domAPI(r);return o.update(e),function(r){r?(r.css!==e.css||r.media!==e.media||r.sourceMap!==e.sourceMap||r.supports!==e.supports||r.layer!==e.layer)&&o.update(e=r):o.remove()}}(p,t);t.byIndex=d,r.splice(d,0,{identifier:c,updater:m,references:1})}a.push(c)}return a}e.exports=function(e,n){var a=t(e=e||[],n=n||{});return function(e){e=e||[];for(var d=0;d<a.length;d++){var i=o(a[d]);r[i].references--}for(var l=t(e,n),s=0;s<a.length;s++){var c=o(a[s]);0===r[c].references&&(r[c].updater(),r.splice(c,1))}a=l}}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertBySelector.js":function(e){var r={};e.exports=function(e,o){var t=function(e){if(void 0===r[e]){var o=document.querySelector(e);if(window.HTMLIFrameElement&&o instanceof window.HTMLIFrameElement)try{o=o.contentDocument.head}catch(e){o=null}r[e]=o}return r[e]}(e);if(!t)throw Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");t.appendChild(o)}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertStyleElement.js":function(e){e.exports=function(e){var r=document.createElement("style");return e.setAttributes(r,e.attributes),e.insert(r,e.options),r}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/setAttributesWithoutAttributes.js":function(e,r,o){e.exports=function(e){var r=o.nc;r&&e.setAttribute("nonce",r)}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleDomAPI.js":function(e){e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var r=e.insertStyleElement(e);return{update:function(o){var t,n,a;t="",o.supports&&(t+="@supports (".concat(o.supports,") {")),o.media&&(t+="@media ".concat(o.media," {")),(n=void 0!==o.layer)&&(t+="@layer".concat(o.layer.length>0?" ".concat(o.layer):""," {")),t+=o.css,n&&(t+="}"),o.media&&(t+="}"),o.supports&&(t+="}"),(a=o.sourceMap)&&"undefined"!=typeof btoa&&(t+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),e.styleTagTransform(t,r,e.options)},remove:function(){var e;null===(e=r).parentNode||e.parentNode.removeChild(e)}}}},"./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleTagTransform.js":function(e){e.exports=function(e,r){if(r.styleSheet)r.styleSheet.cssText=e;else{for(;r.firstChild;)r.removeChild(r.firstChild);r.appendChild(document.createTextNode(e))}}}},u={};function p(e){var r=u[e];if(void 0!==r)return r.exports;var o=u[e]={id:e,exports:{}};return c[e](o,o.exports,p),o.exports}p.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return p.d(r,{a:r}),r},p.d=(e,r)=>{for(var o in r)p.o(r,o)&&!p.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},p.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),p.nc=void 0;var m=p("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/injectStylesIntoStyleTag.js"),f=p.n(m),b=p("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleDomAPI.js"),v=p.n(b),h=p("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertBySelector.js"),g=p.n(h),x=p("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/setAttributesWithoutAttributes.js"),y=p.n(x),k=p("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/insertStyleElement.js"),w=p.n(k),M=p("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/style-loader/runtime/styleTagTransform.js"),j=p.n(M),S=p("./node_modules/@rslib/core/node_modules/@rsbuild/core/compiled/css-loader/index.js??ruleSet[1].rules[1].use[1]!builtin:lightningcss-loader??ruleSet[1].rules[1].use[2]!./src/compounds/Modal.module.css"),_={};_.styleTagTransform=j(),_.setAttributes=y(),_.insert=g().bind(null,"head"),_.domAPI=v(),_.insertStyleElement=w(),f()(S.A,_);let C=S.A&&S.A.locals?S.A.locals:void 0,B=r(void 0);function A(){return t(B)??{}}function I(e){if(!e)return -99999;let r=Number.parseInt(getComputedStyle(e).zIndex||"0",10);return Number.isNaN(r)?-99999:r}function z(e){return Math.max(Math.max(...Array.from(document.querySelectorAll(e)).map(e=>I(e))),1)}function N({children:r}){let{isOpen:t,onClose:a,style:i,closeOnBackdropClick:s}=A(),c=l(null),u=o(e=>{if(function(e){if(!e)return!1;let r=e.tagName.toLowerCase();return"input"===r||"textarea"===r||"select"===r||!!e.isContentEditable}(document.activeElement))return;let r=I(c.current),o=z(`.${C.pureModalBackdrop}`);return!!a&&"Escape"===e.key&&r===o&&(a(),!0)},[a]);return n(()=>{if(t)return document.addEventListener("keydown",u),()=>{document.removeEventListener("keydown",u)}},[t,u]),d(()=>{let e=i?.["--z-index"],r="number"==typeof e?e:"string"==typeof e?Number.parseFloat(e):NaN,o=Number.isFinite(r)?r:z(`.${C.pureModalBackdrop}`);c.current&&(c.current.style.zIndex=String(o+1))},[i?.["--z-index"]]),e("div",{ref:c,className:C.pureModalBackdrop,onMouseDown:e=>{if(s){if(e){if(!e.target.classList.contains(C.pureModalBackdrop))return;e.stopPropagation(),e.preventDefault()}a?.()}},"aria-modal":"true",role:"dialog",style:i,children:r})}function F(r){let o=a(),t=i(()=>({isOpen:!!r.isOpen,onClose:r.onClose,closeOnBackdropClick:!!r.closeOnBackdropClick,style:r.style}),[r.isOpen,r.onClose,r.closeOnBackdropClick,r.style]);if(!t.isOpen)return null;let n=e(B.Provider,{value:t,children:e(N,{children:e("div",{id:`pure-modal-${o}`,className:C.pureModal,children:r.children})})});return void 0!==r.portal?"undefined"!=typeof document&&r.portal?s(n,r.portal):null:n}F.Footer=function({align:r,children:o}){return e("div",{className:C.pureModalFooter,"data-align":r,children:o})},F.Header=function({align:r,children:o}){return e("div",{className:C.pureModalHeader,"data-align":r,children:o})},F.Content=function({children:r}){return e("div",{className:C.pureModalContent,children:r})},F.Close=function({children:r}){let{onClose:o}=A();return e("div",{className:C.pureCloseButton,children:r||e("button",{type:"button",onClick:o,className:C.pureCloseButtonIcon,children:"✕"})})};let E=F;export{B as ModalContext,E as default,A as useModalContext};
@@ -1,5 +1,7 @@
1
+ import type { ModalSectionAlign } from "./Modal.types";
1
2
  type ModalFooterProps = {
3
+ align?: ModalSectionAlign;
2
4
  children?: React.ReactNode;
3
5
  };
4
- export declare function ModalFooter({ children }: ModalFooterProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function ModalFooter({ align, children }: ModalFooterProps): import("react/jsx-runtime").JSX.Element;
5
7
  export {};
@@ -1,5 +1,7 @@
1
+ import type { ModalSectionAlign } from "./Modal.types";
1
2
  type ModalHeaderProps = {
3
+ align?: ModalSectionAlign;
2
4
  children?: React.ReactNode;
3
5
  };
4
- export declare function ModalHeader({ children }: ModalHeaderProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function ModalHeader({ align, children }: ModalHeaderProps): import("react/jsx-runtime").JSX.Element;
5
7
  export {};
@@ -1,5 +1,4 @@
1
1
  import { ModalContent } from "./Content";
2
- import { ModalBackdrop } from "./Backdrop";
3
2
  import { ModalFooter } from "./Footer";
4
3
  import { ModalHeader } from "./Header";
5
4
  import { ModalClose } from "./Close";
@@ -8,7 +7,6 @@ declare function Modal(props: ModalProps): import("react/jsx-runtime").JSX.Eleme
8
7
  declare namespace Modal {
9
8
  var Footer: typeof ModalFooter;
10
9
  var Header: typeof ModalHeader;
11
- var Backdrop: typeof ModalBackdrop;
12
10
  var Content: typeof ModalContent;
13
11
  var Close: typeof ModalClose;
14
12
  }
@@ -6,10 +6,14 @@ import type { ModalFooter } from "./Footer";
6
6
  import type { ModalHeader } from "./Header";
7
7
  export type ModalCompoundElement = ReactElement<typeof ModalBackdrop> | ReactElement<typeof ModalClose> | ReactElement<typeof ModalHeader> | ReactElement<typeof ModalContent> | ReactElement<typeof ModalFooter>;
8
8
  export type ModalChildren = ModalCompoundElement | ModalCompoundElement[];
9
+ export type ModalSectionAlign = "start" | "center" | "end";
10
+ export type ModalCssVariable = "--radius" | "--aspect-ratio" | "--backdrop-color" | "--box-shadow" | "--max-width" | "--max-height" | "--min-width" | "--background" | "--background-panels" | "--z-index" | "--top-content-padding" | "--bottom-content-padding" | "--top-header-padding" | "--bottom-header-padding" | "--header-left-padding" | "--header-right-padding" | "--top-footer-padding" | "--bottom-footer-padding" | "--left-padding" | "--right-padding" | "--close-button-background" | "--close-button-border" | "--close-button-size" | "--close-button-container-transform" | "--close-button-place-self" | "--close-button-grid-row" | "--close-button-hover-transform" | "--dividers-color" | "--dividers-border" | "--backdrop-filter";
11
+ export type ModalStyle = Partial<Record<ModalCssVariable, string | number>>;
9
12
  export type ModalProps = {
10
13
  children: ModalChildren;
11
14
  isOpen?: boolean;
12
- style?: React.CSSProperties;
13
- onClose?: () => boolean | undefined;
15
+ style?: ModalStyle;
16
+ onClose?: VoidFunction;
14
17
  closeOnBackdropClick?: boolean;
18
+ portal?: Element | DocumentFragment | null;
15
19
  };
@@ -1 +1,6 @@
1
- export * as Modal from "./compounds/Modal";
1
+ import Modal from "./compounds/Modal";
2
+ import { ModalContext, useModalContext } from "./compounds/ModalContext";
3
+ export default Modal;
4
+ export { ModalContext, useModalContext };
5
+ export type { ModalCompoundElement, ModalProps, ModalCssVariable, ModalSectionAlign, } from "./compounds/Modal.types";
6
+ export type { ModalContextType } from "./compounds/ModalContext";
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "react-pure-modal",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "React modal",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
8
- "types": "./dist/index.d.ts",
8
+ "types": "./dist/src/index.d.ts",
9
9
  "import": "./dist/index.js"
10
10
  }
11
11
  },
@@ -14,7 +14,7 @@
14
14
  "*.module.css",
15
15
  "**/*.css"
16
16
  ],
17
- "types": "./dist/index.d.ts",
17
+ "types": "./dist/src/index.d.ts",
18
18
  "files": [
19
19
  "dist"
20
20
  ],
@@ -36,6 +36,7 @@
36
36
  "scripts": {
37
37
  "build": "rslib build",
38
38
  "dev": "rslib build --watch",
39
+ "typecheck": "tsc -p tsconfig.types.json",
39
40
  "storybook": "npx storybook dev",
40
41
  "storybook:build": "storybook build -o storybook-static",
41
42
  "storybook:deploy": "npm run storybook:build"