@rokku-x/react-hook-dialog 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist/README.md +38 -0
- package/dist/components/BaseDialogRenderer.cjs.js +1 -1
- package/dist/components/BaseDialogRenderer.esm.js +1 -1
- package/dist/hooks/useHookDialog.cjs.js +1 -1
- package/dist/hooks/useHookDialog.esm.js +1 -1
- package/dist/index.cjs.js +1 -0
- package/dist/index.esm.js +1 -0
- package/dist/store/dialog.cjs.js +1 -1
- package/dist/store/dialog.d.ts +4 -12
- package/dist/store/dialog.esm.js +1 -1
- package/dist/types/index.d.ts +2 -0
- package/package.json +19 -3
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/rokku-x/react-hook-dialog/actions/workflows/ci.yml) [](https://www.npmjs.com/package/@rokku-x/react-hook-dialog) [](https://www.npmjs.com/package/@rokku-x/react-hook-dialog) [](https://www.npmjs.com/package/@rokku-x/react-hook-dialog) 
|
|
4
4
|
|
|
5
|
+
<p><a href="https://jgd.qzz.io/rhd.png"><img src="https://jgd.qzz.io/rhd.png" alt="react-hook-dialog Logo" width="600"/></a></p>
|
|
6
|
+
|
|
5
7
|
A lightweight, powerful, and flexible React dialog hook library for confirmation dialogs, alerts, and modals. Built on top of `@rokku-x/react-hook-modal` with a focus on dialog-specific features like action buttons, variants, and customizable styling.
|
|
6
8
|
|
|
7
9
|
## Features
|
|
@@ -299,6 +301,42 @@ import { BaseDialogRenderer } from '@rokku-x/react-hook-dialog';
|
|
|
299
301
|
|
|
300
302
|
> Note: `BaseModalRenderer` from `@rokku-x/react-hook-modal` can still be used directly if you prefer — this wrapper only adds `defaultConfig` convenience.
|
|
301
303
|
|
|
304
|
+
### Multiple renderer instances 🔁
|
|
305
|
+
|
|
306
|
+
You can mount multiple modal renderers (either `BaseDialogRenderer` from this package or the upstream `BaseModalRenderer`) and give each a unique `id`. Use the `instanceId` option (in the hook's `defaultConfig` or per-call `ConfirmConfig`) to target which renderer/store should manage the dialog.
|
|
307
|
+
|
|
308
|
+
- Mount two renderers:
|
|
309
|
+
|
|
310
|
+
```tsx
|
|
311
|
+
<BaseDialogRenderer id="primary" defaultConfig={{ showCloseButton: false }} />
|
|
312
|
+
<BaseDialogRenderer id="secondary" defaultConfig={{ showCloseButton: true }} />
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- Use the hook with a default instance:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
const [requestDialog] = useHookDialog({ instanceId: 'secondary' });
|
|
319
|
+
await requestDialog({ title: 'Settings' });
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
- Or target a renderer per call:
|
|
323
|
+
|
|
324
|
+
```tsx
|
|
325
|
+
const [requestDialog] = useHookDialog();
|
|
326
|
+
await requestDialog({ title: 'Switch', instanceId: 'primary' });
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
- Programmatic store access:
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
import storeDialog from '@rokku-x/react-hook-dialog';
|
|
333
|
+
const primaryStore = storeDialog('primary'); // returns the zustand store hook
|
|
334
|
+
const state = primaryStore.getState();
|
|
335
|
+
primaryStore.setState({ rendererDefaultConfig: { /* ... */ } });
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
> Note: The default instance id is `"default"`. Make sure you mount a renderer with the same `id` if you want dialogs to be visible. If a renderer with the requested id is not mounted, the store will still be created and you can use it programmatically, but dialogs will not be rendered until a matching renderer is mounted.
|
|
339
|
+
|
|
302
340
|
### Backdrop
|
|
303
341
|
|
|
304
342
|
Overlay component that wraps dialog windows.
|
package/dist/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/rokku-x/react-hook-dialog/actions/workflows/ci.yml) [](https://www.npmjs.com/package/@rokku-x/react-hook-dialog) [](https://www.npmjs.com/package/@rokku-x/react-hook-dialog) [](https://www.npmjs.com/package/@rokku-x/react-hook-dialog) 
|
|
4
4
|
|
|
5
|
+
<p><a href="https://jgd.qzz.io/rhd.png"><img src="https://jgd.qzz.io/rhd.png" alt="react-hook-dialog Logo" width="600"/></a></p>
|
|
6
|
+
|
|
5
7
|
A lightweight, powerful, and flexible React dialog hook library for confirmation dialogs, alerts, and modals. Built on top of `@rokku-x/react-hook-modal` with a focus on dialog-specific features like action buttons, variants, and customizable styling.
|
|
6
8
|
|
|
7
9
|
## Features
|
|
@@ -299,6 +301,42 @@ import { BaseDialogRenderer } from '@rokku-x/react-hook-dialog';
|
|
|
299
301
|
|
|
300
302
|
> Note: `BaseModalRenderer` from `@rokku-x/react-hook-modal` can still be used directly if you prefer — this wrapper only adds `defaultConfig` convenience.
|
|
301
303
|
|
|
304
|
+
### Multiple renderer instances 🔁
|
|
305
|
+
|
|
306
|
+
You can mount multiple modal renderers (either `BaseDialogRenderer` from this package or the upstream `BaseModalRenderer`) and give each a unique `id`. Use the `instanceId` option (in the hook's `defaultConfig` or per-call `ConfirmConfig`) to target which renderer/store should manage the dialog.
|
|
307
|
+
|
|
308
|
+
- Mount two renderers:
|
|
309
|
+
|
|
310
|
+
```tsx
|
|
311
|
+
<BaseDialogRenderer id="primary" defaultConfig={{ showCloseButton: false }} />
|
|
312
|
+
<BaseDialogRenderer id="secondary" defaultConfig={{ showCloseButton: true }} />
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- Use the hook with a default instance:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
const [requestDialog] = useHookDialog({ instanceId: 'secondary' });
|
|
319
|
+
await requestDialog({ title: 'Settings' });
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
- Or target a renderer per call:
|
|
323
|
+
|
|
324
|
+
```tsx
|
|
325
|
+
const [requestDialog] = useHookDialog();
|
|
326
|
+
await requestDialog({ title: 'Switch', instanceId: 'primary' });
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
- Programmatic store access:
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
import storeDialog from '@rokku-x/react-hook-dialog';
|
|
333
|
+
const primaryStore = storeDialog('primary'); // returns the zustand store hook
|
|
334
|
+
const state = primaryStore.getState();
|
|
335
|
+
primaryStore.setState({ rendererDefaultConfig: { /* ... */ } });
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
> Note: The default instance id is `"default"`. Make sure you mount a renderer with the same `id` if you want dialogs to be visible. If a renderer with the requested id is not mounted, the store will still be created and you can use it programmatically, but dialogs will not be rendered until a matching renderer is mounted.
|
|
339
|
+
|
|
302
340
|
### Backdrop
|
|
303
341
|
|
|
304
342
|
Overlay component that wraps dialog windows.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("react/jsx-runtime"),r=require("../store/dialog.cjs.js"),t=require("@rokku-x/react-hook-modal"),o=require("react");exports.default=function({defaultConfig:u,...s}){const{setDefaultConfig:a}=r.default();return o.useEffect(()=>{a(u||{})},[u]),e.jsx(t.BaseModalRenderer,{...s})};
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("react/jsx-runtime"),r=require("../store/dialog.cjs.js"),t=require("@rokku-x/react-hook-modal"),o=require("react");exports.default=function({defaultConfig:u,...s}){const{setDefaultConfig:a}=r.default(s.id)();return o.useEffect(()=>{a(u||{})},[u]),e.jsx(t.BaseModalRenderer,{...s})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as o}from"react/jsx-runtime";import r from"../store/dialog.esm.js";import{BaseModalRenderer as t}from"@rokku-x/react-hook-modal";import{useEffect as e}from"react";function m({defaultConfig:m,...f}){const{setDefaultConfig:
|
|
1
|
+
import{jsx as o}from"react/jsx-runtime";import r from"../store/dialog.esm.js";import{BaseModalRenderer as t}from"@rokku-x/react-hook-modal";import{useEffect as e}from"react";function m({defaultConfig:m,...f}){const{setDefaultConfig:i}=r(f.id)();return e(()=>{i(m||{})},[m]),/* @__PURE__ */o(t,{...f})}export{m as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("react"),s=require("@rokku-x/react-hook-modal"),t=require("../components/ModalWindow.cjs.js"),a=require("../store/dialog.cjs.js");exports.default=function(
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("react"),s=require("@rokku-x/react-hook-modal"),t=require("../components/ModalWindow.cjs.js"),a=require("../store/dialog.cjs.js");exports.default=function(n){const r=s.useBaseModal({rendererId:n?.instanceId}),{addInstance:o,handleAction:l,handleClose:d,rendererDefaultConfig:i}=a.default(n?.instanceId)();return[function(s){return new Promise((a,c)=>{const u=Math.random().toString(36).substring(2,6),m={...i,...n,...s,classNames:{...i?.classNames,...n?.classNames,...s.classNames},styles:{...i?.styles,...n?.styles,...s.styles},variantStyles:{...i?.variantStyles,...n?.variantStyles,...s.variantStyles}},f={id:u,config:m,resolve:a,reject:c};o(f),f.id=r.pushModal(u,e.createElement(t.default,{config:m,modalWindowId:u,handleClose:d,handleAction:l}))})}]};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"react";import{useBaseModal as s}from"@rokku-x/react-hook-modal";import t from"../components/ModalWindow.esm.js";import
|
|
1
|
+
import e from"react";import{useBaseModal as s}from"@rokku-x/react-hook-modal";import t from"../components/ModalWindow.esm.js";import n from"../store/dialog.esm.js";function a(a){const o=s({rendererId:a?.instanceId}),{addInstance:r,handleAction:l,handleClose:i,rendererDefaultConfig:d}=n(a?.instanceId)();return[function(s){return new Promise((n,c)=>{const m=Math.random().toString(36).substring(2,6),f={...d,...a,...s,classNames:{...d?.classNames,...a?.classNames,...s.classNames},styles:{...d?.styles,...a?.styles,...s.styles},variantStyles:{...d?.variantStyles,...a?.variantStyles,...s.variantStyles}},u={id:m,config:f,resolve:n,reject:c};r(u),u.id=o.pushModal(m,e.createElement(t,{config:f,modalWindowId:m,handleClose:i,handleAction:l}))})}]}export{a as default};
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@rokku-x/react-hook-modal"),o=require("./components/BaseDialogRenderer.cjs.js"),r=require("./hooks/useHookDialog.cjs.js");Object.defineProperty(exports,"BaseModalRenderer",{enumerable:!0,get:()=>e.BaseModalRenderer}),exports.BaseDialogRenderer=o.default,exports.useHookDialog=r.default;
|
|
2
3
|
|
|
3
4
|
if (typeof document !== 'undefined') { const style = document.createElement('style'); style.textContent = ".hook-dialog-close-button{position:absolute;top:0;right:0;transform:translate(75%,-75%);width:32px;height:32px;background:none;border:none;font-size:21px;cursor:pointer;line-height:1;color:#555}.hook-dialog-title{margin:0 0 15px;font-size:20px}.hook-dialog-content{margin-bottom:15px;color:#555}.hook-dialog-actions{display:flex;flex-direction:column;gap:10px;padding-top:15px}.hook-dialog-actions-row{display:flex;gap:8px;justify-content:space-between}.hook-dialog-actions-left,.hook-dialog-actions-right{display:flex;gap:8px}.hook-dialog-action-button{border:none;border-radius:15px;padding:10px 18px;font-size:14px;font-weight:800;cursor:pointer}\n"; document.head.appendChild(style); }
|
package/dist/index.esm.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import{BaseModalRenderer as o}from"@rokku-x/react-hook-modal";import{default as e}from"./components/BaseDialogRenderer.esm.js";import{default as a}from"./hooks/useHookDialog.esm.js";export{e as BaseDialogRenderer,o as BaseModalRenderer,a as useHookDialog};
|
|
2
3
|
|
|
3
4
|
if (typeof document !== 'undefined') { const style = document.createElement('style'); style.textContent = ".hook-dialog-close-button{position:absolute;top:0;right:0;transform:translate(75%,-75%);width:32px;height:32px;background:none;border:none;font-size:21px;cursor:pointer;line-height:1;color:#555}.hook-dialog-title{margin:0 0 15px;font-size:20px}.hook-dialog-content{margin-bottom:15px;color:#555}.hook-dialog-actions{display:flex;flex-direction:column;gap:10px;padding-top:15px}.hook-dialog-actions-row{display:flex;gap:8px;justify-content:space-between}.hook-dialog-actions-left,.hook-dialog-actions-right{display:flex;gap:8px}.hook-dialog-action-button{border:none;border-radius:15px;padding:10px 18px;font-size:14px;font-weight:800;cursor:pointer}\n"; document.head.appendChild(style); }
|
package/dist/store/dialog.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("../components/ModalWindow.cjs.js"),n=require("@rokku-x/react-hook-modal"),t=require("react"),o=require("zustand").
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("../components/ModalWindow.cjs.js"),n=require("@rokku-x/react-hook-modal"),t=require("react"),o=require("zustand");const a=new Map;exports.default=function(c="default"){return a.has(c)||a.set(c,function(a="default"){const c=n.storeBaseModal(a);return o.create((n,o)=>({instances:[],rendererDefaultConfig:{},setDefaultConfig:e=>{n(()=>({rendererDefaultConfig:e}))},addInstance:a=>{n(e=>({instances:[...e.instances,a]})),a.id=c.getState().actions.pushModal(a.id,t.createElement(e.default,{config:a.config,modalWindowId:a.id,handleClose:o().handleClose,handleAction:o().handleAction}))},removeInstance:e=>n(n=>({instances:n.instances.filter(n=>n.id!==e)})),handleClose:(e,n=!1)=>{const t=o().getInstance(e);t&&(c.getState().actions.popModal(e),!1!==t.config.rejectOnCancel||n?t.reject(t.config.defaultCancelValue):t.resolve(t.config.defaultCancelValue),o().removeInstance(e))},handleAction:(e,n)=>{const t=o().getInstance(e);t&&(c.getState().actions.popModal(e),n.isCancel&&!1!==t.config.rejectOnCancel?t.reject(n.value):t.resolve(n.value),o().removeInstance(e))},getContext:e=>{const n=o().getInstance(e);if(!n)throw new Error(`Dialog instance with id "${e}" not found.`);return{id:n.id,config:n.config,forceCancel:(n=!0)=>o().handleClose(e,n),forceAction:n=>{o().handleAction(e,n)},forceDefault:()=>{const t=n.config.actions?.flat().find(e=>e.isFocused);if(!t)throw new Error(`No default action (isFocused) defined for dialog instance with id "${e}".`);o().handleAction(e,t)}}},getInstance:e=>o().instances.find(n=>n.id===e)}))}(c)),a.get(c)};
|
package/dist/store/dialog.d.ts
CHANGED
|
@@ -28,15 +28,7 @@ interface DialogStore<T = ValidValue> {
|
|
|
28
28
|
forceCancel: () => void;
|
|
29
29
|
} | undefined;
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* @internal
|
|
36
|
-
* @example
|
|
37
|
-
* ```tsx
|
|
38
|
-
* const { addInstance, removeInstance, getInstance } = useDialogStore();
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
declare const storeDialog: import('zustand').UseBoundStore<import('zustand').StoreApi<DialogStore<any>>>;
|
|
42
|
-
export default storeDialog;
|
|
31
|
+
declare function createStore(instanceId?: string): import('zustand').UseBoundStore<import('zustand').StoreApi<DialogStore<any>>>;
|
|
32
|
+
export type BaseDialogStoreInstance = ReturnType<typeof createStore>;
|
|
33
|
+
export default function BaseDialogStore(instanceId?: string): BaseDialogStoreInstance;
|
|
34
|
+
export {};
|
package/dist/store/dialog.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"../components/ModalWindow.esm.js";import{storeBaseModal as n}from"@rokku-x/react-hook-modal";import t from"react";import{create as o}from"zustand";const a=
|
|
1
|
+
import e from"../components/ModalWindow.esm.js";import{storeBaseModal as n}from"@rokku-x/react-hook-modal";import t from"react";import{create as o}from"zustand";const a=/* @__PURE__ */new Map;function c(c="default"){return a.has(c)||a.set(c,function(a="default"){const c=n(a);return o((n,o)=>({instances:[],rendererDefaultConfig:{},setDefaultConfig:e=>{n(()=>({rendererDefaultConfig:e}))},addInstance:a=>{n(e=>({instances:[...e.instances,a]})),a.id=c.getState().actions.pushModal(a.id,t.createElement(e,{config:a.config,modalWindowId:a.id,handleClose:o().handleClose,handleAction:o().handleAction}))},removeInstance:e=>n(n=>({instances:n.instances.filter(n=>n.id!==e)})),handleClose:(e,n=!1)=>{const t=o().getInstance(e);t&&(c.getState().actions.popModal(e),!1!==t.config.rejectOnCancel||n?t.reject(t.config.defaultCancelValue):t.resolve(t.config.defaultCancelValue),o().removeInstance(e))},handleAction:(e,n)=>{const t=o().getInstance(e);t&&(c.getState().actions.popModal(e),n.isCancel&&!1!==t.config.rejectOnCancel?t.reject(n.value):t.resolve(n.value),o().removeInstance(e))},getContext:e=>{const n=o().getInstance(e);if(!n)throw new Error(`Dialog instance with id "${e}" not found.`);return{id:n.id,config:n.config,forceCancel:(n=!0)=>o().handleClose(e,n),forceAction:n=>{o().handleAction(e,n)},forceDefault:()=>{const t=n.config.actions?.flat().find(e=>e.isFocused);if(!t)throw new Error(`No default action (isFocused) defined for dialog instance with id "${e}".`);o().handleAction(e,t)}}},getInstance:e=>o().instances.find(n=>n.id===e)}))}(c)),a.get(c)}export{c as default};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -183,6 +183,8 @@ export interface ConfirmConfig {
|
|
|
183
183
|
* ```
|
|
184
184
|
*/
|
|
185
185
|
export interface UseHookDialogConfig {
|
|
186
|
+
/** Optional instance ID for the dialog store (default: 'default') */
|
|
187
|
+
instanceId?: string;
|
|
186
188
|
/** If true, allows closing dialogs by clicking the backdrop (default: false) */
|
|
187
189
|
backdropCancel?: boolean;
|
|
188
190
|
/** If true, rejects the promise on cancel instead of resolving (default: true) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokku-x/react-hook-dialog",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"author": "rokku-x",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"react": "^18.0.0",
|
|
13
13
|
"react-dom": "^18.0.0",
|
|
14
14
|
"zustand": "^5.0.10",
|
|
15
|
-
"@rokku-x/react-hook-modal": "^0.
|
|
15
|
+
"@rokku-x/react-hook-modal": "^0.10.0"
|
|
16
16
|
},
|
|
17
17
|
"exports": {
|
|
18
18
|
".": {
|
|
@@ -50,7 +50,23 @@
|
|
|
50
50
|
"dialog-box",
|
|
51
51
|
"confirmation-dialog",
|
|
52
52
|
"react-dialog",
|
|
53
|
-
"react-modal"
|
|
53
|
+
"react-modal",
|
|
54
|
+
"hooks",
|
|
55
|
+
"modal-dialog",
|
|
56
|
+
"modal-window",
|
|
57
|
+
"overlay",
|
|
58
|
+
"overlays",
|
|
59
|
+
"popup",
|
|
60
|
+
"toast",
|
|
61
|
+
"form",
|
|
62
|
+
"spinner",
|
|
63
|
+
"loading",
|
|
64
|
+
"ui-blocker",
|
|
65
|
+
"blocker",
|
|
66
|
+
"portal",
|
|
67
|
+
"accessibility",
|
|
68
|
+
"a11y",
|
|
69
|
+
"library"
|
|
54
70
|
],
|
|
55
71
|
"license": "MIT",
|
|
56
72
|
"sideEffects": [
|