@versini/ui-modal 3.3.1 → 3.3.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/dist/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import { JSX } from 'react/jsx-runtime';
2
2
  import * as React_2 from 'react';
3
3
 
4
- export declare function Modal({ children, ...options }: {
4
+ /**
5
+ * Modal component that supports proper nesting with ESC key handling.
6
+ * Automatically wraps root modals in FloatingTree for nested modal support.
7
+ */
8
+ export declare function Modal(props: {
5
9
  children: React_2.ReactNode;
6
10
  } & ModalTypes.Options): JSX.Element;
7
11
 
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /*!
2
- @versini/ui-modal v3.3.1
2
+ @versini/ui-modal v3.3.3
3
3
  © 2025 gizmette.com
4
4
  */
5
5
 
6
6
  import { jsx } from "react/jsx-runtime";
7
- import { FloatingFocusManager, FloatingOverlay, FloatingPortal, useClick, useDismiss, useFloating, useInteractions, useMergeRefs, useRole } from "@floating-ui/react";
7
+ import { FloatingFocusManager, FloatingNode, FloatingOverlay, FloatingPortal, FloatingTree, useClick, useDismiss, useFloating, useFloatingNodeId, useFloatingParentNodeId, useInteractions, useMergeRefs, useRole } from "@floating-ui/react";
8
8
  import clsx from "clsx";
9
9
  import { cloneElement, createContext, forwardRef, useCallback, useContext, useId, useLayoutEffect, useMemo, useState } from "react";
10
10
 
@@ -30,7 +30,10 @@ function useModal({ initialOpen = false, open: controlledOpen, onOpenChange: set
30
30
  const [descriptionId, setDescriptionId] = useState();
31
31
  /* v8 ignore start */ const open = controlledOpen ?? uncontrolledOpen;
32
32
  const setOpen = setControlledOpen ?? setUncontrolledOpen;
33
- /* v8 ignore stop */ const data = useFloating({
33
+ /* v8 ignore stop */ // Subscribe this modal to the FloatingTree for nested modal support
34
+ const nodeId = useFloatingNodeId();
35
+ const data = useFloating({
36
+ nodeId,
34
37
  open,
35
38
  onOpenChange: setOpen
36
39
  });
@@ -40,7 +43,10 @@ function useModal({ initialOpen = false, open: controlledOpen, onOpenChange: set
40
43
  });
41
44
  const dismiss = useDismiss(context, {
42
45
  outsidePress: false,
43
- outsidePressEvent: "mousedown"
46
+ outsidePressEvent: "mousedown",
47
+ bubbles: {
48
+ escapeKey: false
49
+ }
44
50
  });
45
51
  const role = useRole(context);
46
52
  const interactions = useInteractions([
@@ -57,7 +63,8 @@ function useModal({ initialOpen = false, open: controlledOpen, onOpenChange: set
57
63
  descriptionId,
58
64
  setLabelId,
59
65
  setDescriptionId,
60
- initialFocus
66
+ initialFocus,
67
+ nodeId
61
68
  }), [
62
69
  open,
63
70
  setOpen,
@@ -65,7 +72,8 @@ function useModal({ initialOpen = false, open: controlledOpen, onOpenChange: set
65
72
  data,
66
73
  labelId,
67
74
  descriptionId,
68
- initialFocus
75
+ initialFocus,
76
+ nodeId
69
77
  ]);
70
78
  }
71
79
  const useModalContext = ()=>{
@@ -84,15 +92,33 @@ const useModalContext = ()=>{
84
92
 
85
93
 
86
94
 
87
- function Modal({ children, ...options }) {
95
+ function ModalComponent({ children, ...options }) {
88
96
  const dialog = useModal(options);
89
97
  return /*#__PURE__*/ jsx(ModalContext.Provider, {
90
98
  value: dialog,
91
99
  children: children
92
100
  });
93
101
  }
102
+ /**
103
+ * Modal component that supports proper nesting with ESC key handling.
104
+ * Automatically wraps root modals in FloatingTree for nested modal support.
105
+ */ function Modal(props) {
106
+ const parentId = useFloatingParentNodeId();
107
+ // If this is a root modal (no parent), wrap with FloatingTree
108
+ if (parentId === null) {
109
+ return /*#__PURE__*/ jsx(FloatingTree, {
110
+ children: /*#__PURE__*/ jsx(ModalComponent, {
111
+ ...props
112
+ })
113
+ });
114
+ }
115
+ // Nested modal - FloatingTree already exists
116
+ return /*#__PURE__*/ jsx(ModalComponent, {
117
+ ...props
118
+ });
119
+ }
94
120
  const Modal_ModalContent = /*#__PURE__*/ forwardRef(function ModalContent(props, propRef) {
95
- const { context: floatingContext, ...context } = useModalContext();
121
+ const { context: floatingContext, nodeId, ...context } = useModalContext();
96
122
  const ref = useMergeRefs([
97
123
  context.refs.setFloating,
98
124
  propRef
@@ -105,19 +131,22 @@ const Modal_ModalContent = /*#__PURE__*/ forwardRef(function ModalContent(props,
105
131
  [`${overlayBackground}`]: overlayBackground,
106
132
  "bg-black sm:bg-black/[.8]": !overlayBackground
107
133
  });
108
- return /*#__PURE__*/ jsx(FloatingPortal, {
109
- children: /*#__PURE__*/ jsx(FloatingOverlay, {
110
- className: overlayClass,
111
- lockScroll: true,
112
- children: /*#__PURE__*/ jsx(FloatingFocusManager, {
113
- context: floatingContext,
114
- initialFocus: context.initialFocus,
115
- children: /*#__PURE__*/ jsx("div", {
116
- ref: ref,
117
- "aria-labelledby": context.labelId,
118
- "aria-describedby": context.descriptionId,
119
- ...context.getFloatingProps(rest),
120
- children: rest.children
134
+ return /*#__PURE__*/ jsx(FloatingNode, {
135
+ id: nodeId,
136
+ children: /*#__PURE__*/ jsx(FloatingPortal, {
137
+ children: /*#__PURE__*/ jsx(FloatingOverlay, {
138
+ className: overlayClass,
139
+ lockScroll: true,
140
+ children: /*#__PURE__*/ jsx(FloatingFocusManager, {
141
+ context: floatingContext,
142
+ initialFocus: context.initialFocus,
143
+ children: /*#__PURE__*/ jsx("div", {
144
+ ref: ref,
145
+ "aria-labelledby": context.labelId,
146
+ "aria-describedby": context.descriptionId,
147
+ ...context.getFloatingProps(rest),
148
+ children: rest.children
149
+ })
121
150
  })
122
151
  })
123
152
  })
@@ -178,6 +207,6 @@ const Modal_ModalClose = /*#__PURE__*/ forwardRef(function ModalClose(props, ref
178
207
  });
179
208
 
180
209
  ;// CONCATENATED MODULE: ./src/components/index.ts
181
- /* v8 ignore start */ /* v8 ignore stop */
210
+
182
211
 
183
212
  export { Modal, Modal_ModalClose as ModalClose, Modal_ModalContent as ModalContent, Modal_ModalDescription as ModalDescription, Modal_ModalHeading as ModalHeading };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versini/ui-modal",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
@@ -36,11 +36,13 @@
36
36
  "@versini/ui-types": "8.1.1"
37
37
  },
38
38
  "dependencies": {
39
- "@floating-ui/react": "0.27.16",
40
39
  "clsx": "2.1.1"
41
40
  },
41
+ "peerDependencies": {
42
+ "@floating-ui/react": ">=0.27.16"
43
+ },
42
44
  "sideEffects": [
43
45
  "**/*.css"
44
46
  ],
45
- "gitHead": "a3730974df8fcea3c016bd83844c4243dbb10208"
47
+ "gitHead": "9fedab179e688f845d193b1f0b5365639dd4beb0"
46
48
  }