@versini/ui-panel 8.1.4 → 8.1.5
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.js +198 -9
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
@versini/ui-panel v8.1.
|
|
2
|
+
@versini/ui-panel v8.1.5
|
|
3
3
|
© 2025 gizmette.com
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { cloneElement, createContext, forwardRef, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { FloatingFocusManager, FloatingNode, FloatingOverlay, FloatingPortal, FloatingTree, useClick, useDismiss, useFloating, useFloatingNodeId, useFloatingParentNodeId, useInteractions, useMergeRefs, useRole } from "@floating-ui/react";
|
|
9
9
|
import clsx from "clsx";
|
|
10
10
|
|
|
11
11
|
;// CONCATENATED MODULE: ./src/common/constants.ts
|
|
@@ -22,12 +22,201 @@ const NONE = "none";
|
|
|
22
22
|
|
|
23
23
|
;// CONCATENATED MODULE: external "react/jsx-runtime"
|
|
24
24
|
|
|
25
|
-
;// CONCATENATED MODULE: external "@versini/ui-modal"
|
|
26
|
-
|
|
27
25
|
;// CONCATENATED MODULE: external "react"
|
|
28
26
|
|
|
27
|
+
;// CONCATENATED MODULE: external "@floating-ui/react"
|
|
28
|
+
|
|
29
29
|
;// CONCATENATED MODULE: external "clsx"
|
|
30
30
|
|
|
31
|
+
;// CONCATENATED MODULE: ./src/components/Modal/ModalContext.tsx
|
|
32
|
+
|
|
33
|
+
const ModalContext = /*#__PURE__*/ createContext(null);
|
|
34
|
+
|
|
35
|
+
;// CONCATENATED MODULE: ./src/components/Modal/ModalHooks.tsx
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
function useModal({ initialOpen = false, open: controlledOpen, onOpenChange: setControlledOpen, initialFocus } = {}) {
|
|
40
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(initialOpen);
|
|
41
|
+
const [labelId, setLabelId] = useState();
|
|
42
|
+
const [descriptionId, setDescriptionId] = useState();
|
|
43
|
+
/* v8 ignore start */ const open = controlledOpen ?? uncontrolledOpen;
|
|
44
|
+
const setOpen = setControlledOpen ?? setUncontrolledOpen;
|
|
45
|
+
/* v8 ignore stop */ // Subscribe this modal to the FloatingTree for nested modal support
|
|
46
|
+
const nodeId = useFloatingNodeId();
|
|
47
|
+
const data = useFloating({
|
|
48
|
+
nodeId,
|
|
49
|
+
open,
|
|
50
|
+
onOpenChange: setOpen
|
|
51
|
+
});
|
|
52
|
+
const context = data.context;
|
|
53
|
+
const click = useClick(context, {
|
|
54
|
+
enabled: controlledOpen == null
|
|
55
|
+
});
|
|
56
|
+
const dismiss = useDismiss(context, {
|
|
57
|
+
outsidePress: false,
|
|
58
|
+
outsidePressEvent: "mousedown",
|
|
59
|
+
bubbles: {
|
|
60
|
+
escapeKey: false
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const role = useRole(context);
|
|
64
|
+
const interactions = useInteractions([
|
|
65
|
+
click,
|
|
66
|
+
dismiss,
|
|
67
|
+
role
|
|
68
|
+
]);
|
|
69
|
+
return useMemo(()=>({
|
|
70
|
+
open,
|
|
71
|
+
setOpen,
|
|
72
|
+
...interactions,
|
|
73
|
+
...data,
|
|
74
|
+
labelId,
|
|
75
|
+
descriptionId,
|
|
76
|
+
setLabelId,
|
|
77
|
+
setDescriptionId,
|
|
78
|
+
initialFocus,
|
|
79
|
+
nodeId
|
|
80
|
+
}), [
|
|
81
|
+
open,
|
|
82
|
+
setOpen,
|
|
83
|
+
interactions,
|
|
84
|
+
data,
|
|
85
|
+
labelId,
|
|
86
|
+
descriptionId,
|
|
87
|
+
initialFocus,
|
|
88
|
+
nodeId
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
91
|
+
const useModalContext = ()=>{
|
|
92
|
+
const context = useContext(ModalContext);
|
|
93
|
+
/* v8 ignore start */ if (context == null) {
|
|
94
|
+
throw new Error("Modal components must be wrapped in <Modal />");
|
|
95
|
+
}
|
|
96
|
+
/* v8 ignore stop */ return context;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
;// CONCATENATED MODULE: ./src/components/Modal/Modal.tsx
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
function ModalComponent({ children, ...options }) {
|
|
108
|
+
const dialog = useModal(options);
|
|
109
|
+
return /*#__PURE__*/ jsx(ModalContext.Provider, {
|
|
110
|
+
value: dialog,
|
|
111
|
+
children: children
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Modal component that supports proper nesting with ESC key handling.
|
|
116
|
+
* Automatically wraps root modals in FloatingTree for nested modal support.
|
|
117
|
+
*/ function Modal(props) {
|
|
118
|
+
const parentId = useFloatingParentNodeId();
|
|
119
|
+
/* v8 ignore start - Branch coverage for nested modal case */ // If this is a root modal (no parent), wrap with FloatingTree
|
|
120
|
+
if (parentId === null) {
|
|
121
|
+
/* v8 ignore stop */ return /*#__PURE__*/ jsx(FloatingTree, {
|
|
122
|
+
children: /*#__PURE__*/ jsx(ModalComponent, {
|
|
123
|
+
...props
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/* v8 ignore start - Nested modal case requires complex floating-ui setup */ // Nested modal - FloatingTree already exists
|
|
128
|
+
return /*#__PURE__*/ jsx(ModalComponent, {
|
|
129
|
+
...props
|
|
130
|
+
});
|
|
131
|
+
/* v8 ignore stop */ }
|
|
132
|
+
const Modal_ModalContent = /*#__PURE__*/ forwardRef(function ModalContent(props, propRef) {
|
|
133
|
+
const { context: floatingContext, nodeId, ...context } = useModalContext();
|
|
134
|
+
const ref = useMergeRefs([
|
|
135
|
+
context.refs.setFloating,
|
|
136
|
+
propRef
|
|
137
|
+
]);
|
|
138
|
+
/* v8 ignore start */ if (!floatingContext.open) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
/* v8 ignore stop */ const { overlayBackground, ...rest } = props;
|
|
142
|
+
const overlayClass = clsx("grid place-items-center", {
|
|
143
|
+
"bg-black sm:bg-black/80": !overlayBackground
|
|
144
|
+
});
|
|
145
|
+
return /*#__PURE__*/ jsx(FloatingNode, {
|
|
146
|
+
id: nodeId,
|
|
147
|
+
children: /*#__PURE__*/ jsx(FloatingPortal, {
|
|
148
|
+
children: /*#__PURE__*/ jsx(FloatingOverlay, {
|
|
149
|
+
className: overlayClass,
|
|
150
|
+
lockScroll: true,
|
|
151
|
+
children: /*#__PURE__*/ jsx(FloatingFocusManager, {
|
|
152
|
+
context: floatingContext,
|
|
153
|
+
initialFocus: context.initialFocus,
|
|
154
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
155
|
+
ref: ref,
|
|
156
|
+
"aria-labelledby": context.labelId,
|
|
157
|
+
"aria-describedby": context.descriptionId,
|
|
158
|
+
...context.getFloatingProps(rest),
|
|
159
|
+
children: rest.children
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
const Modal_ModalHeading = /*#__PURE__*/ forwardRef(function ModalHeading({ children, ...props }, ref) {
|
|
167
|
+
const { setLabelId } = useModalContext();
|
|
168
|
+
const id = useId();
|
|
169
|
+
// Only sets `aria-labelledby` on the Modal root element
|
|
170
|
+
// if this component is mounted inside it.
|
|
171
|
+
useLayoutEffect(()=>{
|
|
172
|
+
setLabelId(id);
|
|
173
|
+
return ()=>setLabelId(undefined);
|
|
174
|
+
}, [
|
|
175
|
+
id,
|
|
176
|
+
setLabelId
|
|
177
|
+
]);
|
|
178
|
+
return /*#__PURE__*/ jsx("h1", {
|
|
179
|
+
...props,
|
|
180
|
+
ref: ref,
|
|
181
|
+
id: id,
|
|
182
|
+
children: children
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
const Modal_ModalDescription = /*#__PURE__*/ forwardRef(function ModalDescription({ children, ...props }, ref) {
|
|
186
|
+
const { setDescriptionId } = useModalContext();
|
|
187
|
+
const id = useId();
|
|
188
|
+
// Only sets `aria-describedby` on the Modal root element
|
|
189
|
+
// if this component is mounted inside it.
|
|
190
|
+
useLayoutEffect(()=>{
|
|
191
|
+
setDescriptionId(id);
|
|
192
|
+
return ()=>setDescriptionId(undefined);
|
|
193
|
+
}, [
|
|
194
|
+
id,
|
|
195
|
+
setDescriptionId
|
|
196
|
+
]);
|
|
197
|
+
return /*#__PURE__*/ jsx("div", {
|
|
198
|
+
...props,
|
|
199
|
+
ref: ref,
|
|
200
|
+
id: id,
|
|
201
|
+
children: children
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
const Modal_ModalClose = /*#__PURE__*/ forwardRef(function ModalClose(props, ref) {
|
|
205
|
+
const { setOpen } = useModalContext();
|
|
206
|
+
const { trigger, className, ...rest } = props;
|
|
207
|
+
const handleClose = useCallback(()=>setOpen(false), [
|
|
208
|
+
setOpen
|
|
209
|
+
]);
|
|
210
|
+
return /*#__PURE__*/ jsx("div", {
|
|
211
|
+
className: className,
|
|
212
|
+
children: /*#__PURE__*/ cloneElement(trigger, {
|
|
213
|
+
ref,
|
|
214
|
+
onClick: handleClose,
|
|
215
|
+
...rest
|
|
216
|
+
})
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
31
220
|
;// CONCATENATED MODULE: ./src/components/Panel/utilities.ts
|
|
32
221
|
|
|
33
222
|
|
|
@@ -178,18 +367,18 @@ const Panel = ({ open, onOpenChange, title, children, footer, borderMode = "ligh
|
|
|
178
367
|
open: open,
|
|
179
368
|
onOpenChange: onOpenChange,
|
|
180
369
|
initialFocus: initialFocus,
|
|
181
|
-
children: /*#__PURE__*/ jsx(
|
|
370
|
+
children: /*#__PURE__*/ jsx(Modal_ModalContent, {
|
|
182
371
|
className: panelClassName.outerWrapper,
|
|
183
372
|
style: {
|
|
184
373
|
...animationStyles
|
|
185
374
|
},
|
|
186
|
-
children: /*#__PURE__*/ jsxs(
|
|
375
|
+
children: /*#__PURE__*/ jsxs(Modal_ModalDescription, {
|
|
187
376
|
className: panelClassName.innerWrapper,
|
|
188
377
|
children: [
|
|
189
378
|
/*#__PURE__*/ jsxs("div", {
|
|
190
379
|
className: panelClassName.header,
|
|
191
380
|
children: [
|
|
192
|
-
/*#__PURE__*/ jsx(
|
|
381
|
+
/*#__PURE__*/ jsx(Modal_ModalClose, {
|
|
193
382
|
className: panelClassName.closeWrapper,
|
|
194
383
|
trigger: /*#__PURE__*/ jsx("button", {
|
|
195
384
|
className: panelClassName.closeButton,
|
|
@@ -212,7 +401,7 @@ const Panel = ({ open, onOpenChange, title, children, footer, borderMode = "ligh
|
|
|
212
401
|
})
|
|
213
402
|
})
|
|
214
403
|
}),
|
|
215
|
-
/*#__PURE__*/ jsx(
|
|
404
|
+
/*#__PURE__*/ jsx(Modal_ModalHeading, {
|
|
216
405
|
className: panelClassName.title,
|
|
217
406
|
children: title
|
|
218
407
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versini/ui-panel",
|
|
3
|
-
"version": "8.1.
|
|
3
|
+
"version": "8.1.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"publishConfig": {
|
|
@@ -42,19 +42,19 @@
|
|
|
42
42
|
"test": "vitest run"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@testing-library/jest-dom": "6.9.1"
|
|
45
|
+
"@testing-library/jest-dom": "6.9.1",
|
|
46
|
+
"@versini/ui-types": "8.1.1"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"@tailwindcss/typography": "0.5.19",
|
|
49
|
-
"@versini/ui-modal": "3.3.3",
|
|
50
50
|
"clsx": "2.1.1",
|
|
51
51
|
"tailwindcss": "4.1.18"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@floating-ui/react": "
|
|
54
|
+
"@floating-ui/react": "0.27.16"
|
|
55
55
|
},
|
|
56
56
|
"sideEffects": [
|
|
57
57
|
"**/*.css"
|
|
58
58
|
],
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "346a00c58643c5f3d6fcbbacfb05f64c85308394"
|
|
60
60
|
}
|