@bit.rhplus/draggable-modal 0.0.16 → 0.0.18

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.
@@ -0,0 +1,344 @@
1
+ # Návod: Resize modálního okna bez knihovny
2
+
3
+ Kompletní průvodce implementací resize (změna velikosti myší) na Ant Design 5 modálním okně v Reactu — bez použití jakékoliv resize knihovny.
4
+
5
+ ---
6
+
7
+ ## Kontext
8
+
9
+ Komponenta `DraggableModal` rozšiřuje Ant Design `<Modal>` o drag (přetahování) pomocí `react-draggable`. Cílem bylo přidat i resize — změnu velikosti táhnutím za hrany/rohy.
10
+
11
+ **Důležité:** `react-draggable` je výhradně pro drag. Resize nenabízí. Musíme ho implementovat ručně.
12
+
13
+ ---
14
+
15
+ ## Jak resize funguje — princip
16
+
17
+ Resize funguje na třech fázích mouse eventů:
18
+
19
+ ```
20
+ mousedown na handle → zapamatuj startovní pozici a rozměry
21
+
22
+ mousemove na document → počítej delta, aktualizuj stav
23
+
24
+ mouseup na document → ukonči resize, odregistruj listenery
25
+ ```
26
+
27
+ Klíč je přidávat `mousemove`/`mouseup` na **`document`**, ne na handle. Jinak by myš opuštění handle resize přerušila.
28
+
29
+ ---
30
+
31
+ ## Krok 1: Stav pro rozměry
32
+
33
+ ```js
34
+ const parseWidth = (w) => {
35
+ if (typeof w === 'number') return w;
36
+ if (typeof w === 'string') { const n = parseInt(w, 10); return isNaN(n) ? 520 : n; }
37
+ return 520;
38
+ };
39
+
40
+ const [modalSize, setModalSize] = React.useState({
41
+ width: parseWidth(props.width), // vždy číslo (ne "1400px")
42
+ height: null, // null = auto výška z obsahu
43
+ });
44
+ ```
45
+
46
+ **Proč `parseWidth`?**
47
+ Ant Design přijímá `width` jako číslo i string (`"1400px"`). My potřebujeme číslo pro matematiku (`startW + dx`). Parsujeme hned při inicializaci.
48
+
49
+ **Proč `height: null`?**
50
+ Výchozí výška modalu je `auto` — určená obsahem. Výšku začínáme sledovat až při prvním resize (pak ji fixujeme na pixely).
51
+
52
+ ---
53
+
54
+ ## Krok 2: Resize handles — průhledné aktivní zóny
55
+
56
+ Handles jsou prázdné `<div>` elementy bez viditelného obsahu. Stačí jim nastavit správný `cursor` a dostatečnou plochu pro klik.
57
+
58
+ ```css
59
+ .drm-handle {
60
+ position: absolute;
61
+ z-index: 10;
62
+ user-select: none;
63
+ pointer-events: auto; /* KRITICKÉ — viz sekce Nástrahy */
64
+ }
65
+
66
+ /* Pravá hrana */
67
+ .drm-handle-e { top: 12px; right: -4px; width: 8px; height: calc(100% - 24px); cursor: e-resize; }
68
+
69
+ /* Levá hrana */
70
+ .drm-handle-w { top: 12px; left: -4px; width: 8px; height: calc(100% - 24px); cursor: w-resize; }
71
+
72
+ /* Spodní hrana */
73
+ .drm-handle-s { bottom: -4px; left: 12px; width: calc(100% - 24px); height: 8px; cursor: s-resize; }
74
+
75
+ /* Pravý dolní roh */
76
+ .drm-handle-se { bottom: -4px; right: -4px; width: 16px; height: 16px; cursor: se-resize; }
77
+
78
+ /* Levý dolní roh */
79
+ .drm-handle-sw { bottom: -4px; left: -4px; width: 16px; height: 16px; cursor: sw-resize; }
80
+ ```
81
+
82
+ Handles jsou umístěny na `-4px` vně okna (polovina šířky 8px přesahuje). To vytváří přirozený aktivní prostor na samé hraně.
83
+
84
+ ---
85
+
86
+ ## Krok 3: Logika resize
87
+
88
+ ```js
89
+ const handleResizeStart = (e, direction) => {
90
+ e.preventDefault();
91
+ e.stopPropagation(); // zabrání spuštění drag při tahu za handle
92
+
93
+ // Změříme aktuální rozměry z DOM (ne ze stavu — stav může být zaostalý)
94
+ const modalEl = draggleRef.current?.querySelector('.ant-modal');
95
+ const contentEl = draggleRef.current?.querySelector('.ant-modal-content');
96
+ const startX = e.clientX;
97
+ const startY = e.clientY;
98
+ const startW = modalEl?.offsetWidth || modalSize.width;
99
+ const startH = contentEl?.offsetHeight || modalSize.height || 400;
100
+
101
+ const onMouseMove = (moveEvent) => {
102
+ const dx = moveEvent.clientX - startX; // kolik px jsme se posunuli
103
+ const dy = moveEvent.clientY - startY;
104
+
105
+ setModalSize(prev => {
106
+ let newW = prev.width;
107
+ let newH = prev.height !== null ? prev.height : startH;
108
+
109
+ if (direction.includes('e')) newW = Math.max(300, startW + dx); // tah doprava
110
+ if (direction.includes('w')) newW = Math.max(300, startW - dx); // tah doleva
111
+ if (direction.includes('s')) newH = Math.max(200, startH + dy); // tah dolů
112
+
113
+ return { width: newW, height: newH };
114
+ });
115
+ };
116
+
117
+ const onMouseUp = () => {
118
+ document.removeEventListener('mousemove', onMouseMove);
119
+ document.removeEventListener('mouseup', onMouseUp);
120
+ };
121
+
122
+ // DŮLEŽITÉ: listenery na document, ne na handle
123
+ document.addEventListener('mousemove', onMouseMove);
124
+ document.addEventListener('mouseup', onMouseUp);
125
+ };
126
+ ```
127
+
128
+ **Proč čteme z DOM a ne ze stavu?**
129
+ Při zahájení resize chceme **aktuální vizuální rozměry**. Stav `modalSize` může být zaostalý o render cyklus. `offsetWidth`/`offsetHeight` vrací vždy aktuální hodnotu z DOM.
130
+
131
+ **Minimální rozměry:**
132
+ `Math.max(300, ...)` a `Math.max(200, ...)` zabrání zborcení layoutu.
133
+
134
+ ---
135
+
136
+ ## Krok 4: Aplikace rozměrů na modal
137
+
138
+ ```jsx
139
+ <Modal
140
+ {...props}
141
+ width={resizable ? modalSize.width : props.width}
142
+ styles={resolveStyles()}
143
+ >
144
+ ```
145
+
146
+ ```js
147
+ const resolveStyles = () => {
148
+ if (resizable && modalSize.height !== null) {
149
+ return {
150
+ body: {
151
+ paddingBottom: '30px',
152
+ height: `calc(${modalSize.height}px - 110px)`, // odečteme header + footer
153
+ overflow: 'auto',
154
+ display: 'flex',
155
+ flexDirection: 'column',
156
+ },
157
+ content: {
158
+ height: `${modalSize.height}px`,
159
+ display: 'flex',
160
+ flexDirection: 'column',
161
+ },
162
+ };
163
+ }
164
+ // ... fallback pro statický height prop
165
+ };
166
+ ```
167
+
168
+ `110px` je odhadovaná výška headeru + footeru. `overflow: auto` na body zajistí scrollování při přetečení obsahu.
169
+
170
+ ---
171
+
172
+ ## Krok 5: Kam umístit handles — nástraha Ant Design
173
+
174
+ Naivní přístup: vložit handles přímo do `modalRender` wrapperu:
175
+
176
+ ```jsx
177
+ // ❌ NEFUNGUJE
178
+ modalRender={(modal) => (
179
+ <Draggable>
180
+ <div ref={draggleRef}>
181
+ {modal}
182
+ {resizeHandles} {/* <-- tady NE */}
183
+ </div>
184
+ </Draggable>
185
+ )}
186
+ ```
187
+
188
+ **Proč ne?** Wrapper div je block-level element — má šířku `100% viewportu`. Handles s `position: absolute; right: -4px` se zobrazí na okraji viewportu, ne modálního okna. Uživatel je nevidí.
189
+
190
+ ```
191
+ .ant-modal-wrap (100vw)
192
+ [draggleRef div = 100vw] ← handles jsou tady → špatně
193
+ .ant-modal (1400px, margin:auto)
194
+ .ant-modal-content
195
+ ```
196
+
197
+ ### Správné řešení: ReactDOM.createPortal do `.ant-modal-content`
198
+
199
+ ```jsx
200
+ // ✅ SPRÁVNĚ
201
+ {resizable && antModalEl && ReactDOM.createPortal(resizeHandles, antModalEl)}
202
+ // antModalEl = element .ant-modal-content
203
+ ```
204
+
205
+ `.ant-modal-content` má `position: relative` → handles s `position: absolute` jsou relativní k němu. Handles jsou přesně na hranách viditelného okna.
206
+
207
+ ```
208
+ .ant-modal-content (position: relative) ← portal target
209
+ .ant-modal-header
210
+ .ant-modal-body
211
+ .ant-modal-footer
212
+ [drm-handle-e] ← position: absolute, right: -4px ✓
213
+ [drm-handle-se] ← position: absolute, bottom: -4px, right: -4px ✓
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Krok 6: Detekce `.ant-modal-content` elementu
219
+
220
+ Portal cíl musíme najít v DOM poté, co Ant Design modal narenduje. Použijeme `useLayoutEffect` — běží synchronně po DOM mutaci:
221
+
222
+ ```js
223
+ const [antModalEl, setAntModalEl] = React.useState(null);
224
+
225
+ React.useLayoutEffect(() => {
226
+ if (resizable && open && draggleRef.current) {
227
+ setAntModalEl(draggleRef.current.querySelector('.ant-modal-content'));
228
+ } else {
229
+ setAntModalEl(null);
230
+ }
231
+ }, [resizable, open]);
232
+ ```
233
+
234
+ **Proč `useLayoutEffect` a ne `useEffect`?**
235
+ `useEffect` běží asynchronně po paint — uživatel by na první render viděl modal bez handles. `useLayoutEffect` běží synchronně před paint, takže handles se objeví ihned s modalem (druhý render, ale bez vizuálního bliknutí).
236
+
237
+ **Tok na první otevření:**
238
+ 1. `open` změní na `true` → první render → `antModalEl` je `null` → handles se nevykreslí
239
+ 2. `useLayoutEffect` najde `.ant-modal-content`, zavolá `setAntModalEl`
240
+ 3. Druhý render → handles se vykreslí přes portal
241
+ 4. Vše synchronní — uživatel nevidí blikání
242
+
243
+ ---
244
+
245
+ ## Nástraha: `pointer-events: none` na `.ant-modal`
246
+
247
+ Ant Design 5 nastavuje na `.ant-modal`:
248
+
249
+ ```js
250
+ // node_modules/antd/es/modal/style/index.js
251
+ '.ant-modal': {
252
+ pointerEvents: 'none', // ← zabraňuje klikům mimo .ant-modal-content
253
+ }
254
+ '.ant-modal-content': {
255
+ pointerEvents: 'auto', // ← re-aktivuje pro obsah
256
+ }
257
+ ```
258
+
259
+ Pokud bychom portálovali handles do `.ant-modal` (ne do `.ant-modal-content`), handles by dědily `pointer-events: none` → `onMouseDown` by se nikdy nespustil.
260
+
261
+ Proto portálujeme do `.ant-modal-content` (má `pointer-events: auto`) + přidáme `pointer-events: auto` na `.drm-handle` jako pojistku.
262
+
263
+ ---
264
+
265
+ ## Nástraha: `e.stopPropagation()` na resize handle
266
+
267
+ Draggable wrapper obaluje celý modal. Bez `stopPropagation` by `mousedown` na resize handle také spustil drag. Výsledek: modal se táhne místo resize.
268
+
269
+ ```js
270
+ const handleResizeStart = (e, direction) => {
271
+ e.preventDefault();
272
+ e.stopPropagation(); // zabrání bubblingu k Draggable
273
+ // ...
274
+ };
275
+ ```
276
+
277
+ ---
278
+
279
+ ## Výsledný strom v DOM
280
+
281
+ ```
282
+ [draggleRef div] ← Draggable wrapper (full-width)
283
+ .ant-modal ← width prop → kontroluje vizuální šířku
284
+ .ant-modal-content ← portal target (position: relative)
285
+ .ant-modal-header
286
+ .ant-modal-body
287
+ .ant-modal-footer
288
+ .drm-handle-e ← right: -4px, výška okna
289
+ .drm-handle-w ← left: -4px, výška okna
290
+ .drm-handle-s ← bottom: -4px, šířka okna
291
+ .drm-handle-se ← bottom: -4px, right: -4px
292
+ .drm-handle-sw ← bottom: -4px, left: -4px
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Kompletní flow resize
298
+
299
+ ```
300
+ Uživatel → mousedown na .drm-handle-se
301
+
302
+ handleResizeStart('se')
303
+ - e.stopPropagation() → Draggable nezačne drag
304
+ - uloží: startX, startY, startW (.ant-modal.offsetWidth), startH (.ant-modal-content.offsetHeight)
305
+ - registruje: document.onmousemove, document.onmouseup
306
+
307
+ Uživatel táhne myší
308
+
309
+ onMouseMove
310
+ - dx = clientX - startX, dy = clientY - startY
311
+ - 'se' → newW = max(300, startW + dx), newH = max(200, startH + dy)
312
+ - setModalSize({ width: newW, height: newH })
313
+
314
+ React re-render
315
+ - <Modal width={newW}> → .ant-modal dostane novou šířku
316
+ - styles.content.height = newH → .ant-modal-content dostane novou výšku
317
+ - handles v portalu se přesunou s .ant-modal-content
318
+
319
+ Uživatel pustí myš
320
+
321
+ onMouseUp → removeEventListener (cleanup)
322
+ ```
323
+
324
+ ---
325
+
326
+ ## Použití
327
+
328
+ ```jsx
329
+ // Resize zapnut (default)
330
+ <DraggableModal open={open} onCancel={onClose} title="Okno" width={800}>
331
+ obsah
332
+ </DraggableModal>
333
+
334
+ // Resize vypnut
335
+ <DraggableModal resizable={false} open={open} onCancel={onClose} title="Okno">
336
+ obsah
337
+ </DraggableModal>
338
+ ```
339
+
340
+ ---
341
+
342
+ ## Proč ne knihovna (re-resizable, react-resizable)?
343
+
344
+ Obě fungují na principu wrapperu kolem elementu. Pro Ant Design Modal je problém, že wrapper musí obalit `.ant-modal`, ale `.ant-modal` je renderován interně knihovnou — nemáme nad ním přímou kontrolu z JSX. Ruční implementace pomocí mouse eventů je přímočařejší a nevyžaduje nové závislosti.
@@ -0,0 +1,2 @@
1
+ export default DraggableModal;
2
+ declare function DraggableModal(props: any): import("react/jsx-runtime").JSX.Element;
package/dist/index.js ADDED
@@ -0,0 +1,160 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable */
3
+ import * as React from 'react';
4
+ import { default as Modal } from 'antd/es/modal';
5
+ import { default as ConfigProvider } from 'antd/es/config-provider';
6
+ import Draggable from 'react-draggable';
7
+ import ReactDOM from 'react-dom';
8
+ import './style.css';
9
+ const parseWidth = (w) => {
10
+ if (typeof w === 'number')
11
+ return w;
12
+ if (typeof w === 'string') {
13
+ const n = parseInt(w, 10);
14
+ return isNaN(n) ? 520 : n;
15
+ }
16
+ return 520;
17
+ };
18
+ // Wrapper – podmíněné renderování = destroy on close (kompletní unmount při zavření)
19
+ const DraggableModal = (props) => {
20
+ if (!props.open)
21
+ return null;
22
+ return _jsx(DraggableModalInner, { ...props });
23
+ };
24
+ // Inner komponenta – obsahuje veškerou logiku a stav
25
+ // Při zavření se kompletně unmountuje → všechny hooks a stav jsou zničeny
26
+ // Při otevření se vytvoří čerstvá instance → žádný starý stav
27
+ const DraggableModalInner = (props) => {
28
+ const { open, onOk, onCancel, isInteractive = false, title, children, getContainer, height, resizable = true } = props;
29
+ const draggleRef = React.useRef(null);
30
+ const [disabled, setDisabled] = React.useState(true);
31
+ const [bounds, setBounds] = React.useState({
32
+ left: 0,
33
+ top: 0,
34
+ bottom: 0,
35
+ right: 0,
36
+ });
37
+ const [modalSize, setModalSize] = React.useState({
38
+ width: parseWidth(props.width),
39
+ height: null,
40
+ });
41
+ const [antModalEl, setAntModalEl] = React.useState(null);
42
+ const [dragPos, setDragPos] = React.useState({ x: 0, y: 0 });
43
+ React.useEffect(() => {
44
+ if (isInteractive) {
45
+ import('./interactiveStyle.css');
46
+ }
47
+ }, [isInteractive]);
48
+ React.useLayoutEffect(() => {
49
+ if (resizable && open && draggleRef.current) {
50
+ setAntModalEl(draggleRef.current.querySelector('.ant-modal-content'));
51
+ }
52
+ else {
53
+ setAntModalEl(null);
54
+ }
55
+ }, [resizable, open]);
56
+ const onStart = (_event, uiData) => {
57
+ const { clientWidth, clientHeight } = window.document.documentElement;
58
+ const targetRect = draggleRef.current?.getBoundingClientRect();
59
+ if (!targetRect) {
60
+ return;
61
+ }
62
+ setBounds({
63
+ left: -targetRect.left + uiData.x,
64
+ right: clientWidth - (targetRect.right - uiData.x),
65
+ top: -targetRect.top + uiData.y,
66
+ bottom: clientHeight - (targetRect.bottom - uiData.y),
67
+ });
68
+ };
69
+ const handleResizeStart = (e, direction) => {
70
+ e.preventDefault();
71
+ e.stopPropagation();
72
+ const modalEl = draggleRef.current?.querySelector('.ant-modal');
73
+ const contentEl = draggleRef.current?.querySelector('.ant-modal-content');
74
+ const startX = e.clientX;
75
+ const startY = e.clientY;
76
+ const startW = modalEl?.offsetWidth || modalSize.width;
77
+ const startH = contentEl?.offsetHeight || modalSize.height || 400;
78
+ const startDragX = dragPos.x;
79
+ const onMouseMove = (moveEvent) => {
80
+ const dx = moveEvent.clientX - startX;
81
+ const dy = moveEvent.clientY - startY;
82
+ setModalSize(prev => {
83
+ let newW = prev.width;
84
+ let newH = prev.height !== null ? prev.height : startH;
85
+ if (direction.includes('e'))
86
+ newW = Math.max(300, startW + dx);
87
+ if (direction.includes('w'))
88
+ newW = Math.max(300, startW - dx);
89
+ if (direction.includes('s'))
90
+ newH = Math.max(200, startH + dy);
91
+ return { width: newW, height: newH };
92
+ });
93
+ // Kompenzace: Ant Design centruje modal přes margin:auto.
94
+ // Při změně width se levý okraj posune o dx/2 — opravíme pozici Draggable.
95
+ if (direction.includes('e') || direction.includes('w')) {
96
+ setDragPos(prev => ({ ...prev, x: startDragX + dx / 2 }));
97
+ }
98
+ };
99
+ const onMouseUp = () => {
100
+ document.removeEventListener('mousemove', onMouseMove);
101
+ document.removeEventListener('mouseup', onMouseUp);
102
+ };
103
+ document.addEventListener('mousemove', onMouseMove);
104
+ document.addEventListener('mouseup', onMouseUp);
105
+ };
106
+ const resolveStyles = () => {
107
+ if (resizable && modalSize.height !== null) {
108
+ return {
109
+ body: {
110
+ paddingBottom: '30px',
111
+ height: `calc(${modalSize.height}px - 110px)`,
112
+ overflow: 'auto',
113
+ display: 'flex',
114
+ flexDirection: 'column',
115
+ boxSizing: 'border-box',
116
+ },
117
+ content: {
118
+ height: `${modalSize.height}px`,
119
+ display: 'flex',
120
+ flexDirection: 'column',
121
+ },
122
+ };
123
+ }
124
+ return {
125
+ body: {
126
+ paddingBottom: '30px',
127
+ ...(height && {
128
+ height: `calc(${height} - 110px)`,
129
+ overflow: 'hidden',
130
+ display: 'flex',
131
+ flexDirection: 'column',
132
+ boxSizing: 'border-box',
133
+ }),
134
+ },
135
+ content: height ? {
136
+ height: height,
137
+ display: 'flex',
138
+ flexDirection: 'column',
139
+ } : {},
140
+ };
141
+ };
142
+ const resizeHandles = (_jsxs(_Fragment, { children: [_jsx("div", { className: "drm-handle drm-handle-e", onMouseDown: (e) => handleResizeStart(e, 'e') }), _jsx("div", { className: "drm-handle drm-handle-w", onMouseDown: (e) => handleResizeStart(e, 'w') }), _jsx("div", { className: "drm-handle drm-handle-s", onMouseDown: (e) => handleResizeStart(e, 's') }), _jsx("div", { className: "drm-handle drm-handle-se", onMouseDown: (e) => handleResizeStart(e, 'se') }), _jsx("div", { className: "drm-handle drm-handle-sw", onMouseDown: (e) => handleResizeStart(e, 'sw') })] }));
143
+ const effectiveZIndex = props.zIndex || 99999999;
144
+ // Sdílený Modal komponent
145
+ const modalContent = (_jsx(Modal, { ...props, mask: !isInteractive, getContainer: getContainer || false, zIndex: effectiveZIndex, width: resizable ? modalSize.width : props.width, title: _jsx("div", { style: { width: '100%', cursor: 'move' }, onMouseOver: () => {
146
+ if (disabled) {
147
+ setDisabled(false);
148
+ }
149
+ }, onMouseOut: () => {
150
+ setDisabled(true);
151
+ }, onFocus: () => { }, onBlur: () => { }, children: title }), open: open, onOk: onOk, onCancel: onCancel, styles: resolveStyles(), modalRender: (modal) => (_jsx(Draggable, { disabled: disabled, bounds: bounds, position: dragPos, onDrag: (e, data) => setDragPos({ x: data.x, y: data.y }), onStart: (event, uiData) => onStart(event, uiData), children: _jsx("div", { ref: draggleRef, style: { position: 'relative' }, children: modal }) })), children: _jsx(_Fragment, { children: children }) }));
152
+ // Pokud je getContainer funkce, použijeme portal
153
+ // Jinak renderujeme přímo (zachová React context)
154
+ // ConfigProvider obaluje celý return — context se propaguje přes všechny vnořené portaly
155
+ return (_jsx(ConfigProvider, { theme: { token: { zIndexPopupBase: effectiveZIndex + 1 } }, getPopupContainer: () => document.body, children: _jsxs(_Fragment, { children: [typeof getContainer === 'function'
156
+ ? ReactDOM.createPortal(modalContent, getContainer())
157
+ : modalContent, resizable && antModalEl && ReactDOM.createPortal(resizeHandles, antModalEl)] }) }));
158
+ };
159
+ export default DraggableModal;
160
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.jsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ .ant-modal-wrap {
2
+ pointer-events: none !important;
3
+ }
@@ -0,0 +1,7 @@
1
+ ;
2
+ ;
3
+
4
+ export const compositions = [];
5
+ export const overview = [];
6
+
7
+ export const compositions_metadata = {"compositions":[]};
package/dist/style.css ADDED
@@ -0,0 +1,58 @@
1
+ .ant-modal-content {
2
+ box-shadow: 0px 0px 56px 0px rgba(0, 0, 0, 2.15) !important;
3
+ }
4
+
5
+ .ant-modal-footer {
6
+ display: flex;
7
+ justify-content: flex-end; /* Tlačítka na pravou stranu */
8
+ gap: 8px; /* Mezery mezi tlačítky */
9
+ padding-top: 50px;
10
+ }
11
+
12
+ /* Resize handles */
13
+ .drm-handle {
14
+ position: absolute;
15
+ z-index: 10;
16
+ user-select: none;
17
+ pointer-events: auto;
18
+ }
19
+
20
+ .drm-handle-e {
21
+ top: 12px;
22
+ right: -4px;
23
+ width: 8px;
24
+ height: calc(100% - 24px);
25
+ cursor: e-resize;
26
+ }
27
+
28
+ .drm-handle-w {
29
+ top: 12px;
30
+ left: -4px;
31
+ width: 8px;
32
+ height: calc(100% - 24px);
33
+ cursor: w-resize;
34
+ }
35
+
36
+ .drm-handle-s {
37
+ bottom: -4px;
38
+ left: 12px;
39
+ width: calc(100% - 24px);
40
+ height: 8px;
41
+ cursor: s-resize;
42
+ }
43
+
44
+ .drm-handle-se {
45
+ bottom: -4px;
46
+ right: -4px;
47
+ width: 16px;
48
+ height: 16px;
49
+ cursor: se-resize;
50
+ }
51
+
52
+ .drm-handle-sw {
53
+ bottom: -4px;
54
+ left: -4px;
55
+ width: 16px;
56
+ height: 16px;
57
+ cursor: sw-resize;
58
+ }
package/index.jsx CHANGED
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable */
2
2
  import * as React from 'react';
3
3
  import { default as Modal } from 'antd/es/modal';
4
+ import { default as ConfigProvider } from 'antd/es/config-provider';
4
5
  import Draggable from 'react-draggable';
5
6
  import ReactDOM from 'react-dom';
6
7
  import './style.css';
@@ -156,13 +157,15 @@ const DraggableModalInner = (props) => {
156
157
  </>
157
158
  );
158
159
 
160
+ const effectiveZIndex = props.zIndex || 99999999;
161
+
159
162
  // Sdílený Modal komponent
160
163
  const modalContent = (
161
164
  <Modal
162
165
  {...props}
163
166
  mask={!isInteractive}
164
167
  getContainer={getContainer || false} // false = renderovat v místě
165
- zIndex={props.zIndex || 99999999}
168
+ zIndex={effectiveZIndex}
166
169
  width={resizable ? modalSize.width : props.width}
167
170
  title={
168
171
  <div
@@ -205,13 +208,19 @@ const DraggableModalInner = (props) => {
205
208
 
206
209
  // Pokud je getContainer funkce, použijeme portal
207
210
  // Jinak renderujeme přímo (zachová React context)
211
+ // ConfigProvider obaluje celý return — context se propaguje přes všechny vnořené portaly
208
212
  return (
209
- <>
210
- {typeof getContainer === 'function'
211
- ? ReactDOM.createPortal(modalContent, getContainer())
212
- : modalContent}
213
- {resizable && antModalEl && ReactDOM.createPortal(resizeHandles, antModalEl)}
214
- </>
213
+ <ConfigProvider
214
+ theme={{ token: { zIndexPopupBase: effectiveZIndex + 1 } }}
215
+ getPopupContainer={() => document.body}
216
+ >
217
+ <>
218
+ {typeof getContainer === 'function'
219
+ ? ReactDOM.createPortal(modalContent, getContainer())
220
+ : modalContent}
221
+ {resizable && antModalEl && ReactDOM.createPortal(resizeHandles, antModalEl)}
222
+ </>
223
+ </ConfigProvider>
215
224
  );
216
225
  };
217
226
 
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@bit.rhplus/draggable-modal",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "homepage": "https://bit.cloud/remote-scope/draggable-modal",
5
5
  "main": "dist/index.js",
6
6
  "componentId": {
7
7
  "scope": "remote-scope",
8
8
  "name": "draggable-modal",
9
- "version": "0.0.16"
9
+ "version": "0.0.18"
10
10
  },
11
11
  "dependencies": {
12
12
  "antd": "^5.20.6",
13
13
  "react-draggable": "^4.4.6"
14
14
  },
15
15
  "devDependencies": {
16
- "@bitdev/react.react-env": "4.0.14"
16
+ "@bitdev/react.react-env": "5.0.5"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
@@ -0,0 +1,43 @@
1
+ declare module '*.png' {
2
+ const value: any;
3
+ export = value;
4
+ }
5
+ declare module '*.svg' {
6
+ import type { FunctionComponent, SVGProps } from 'react';
7
+
8
+ export const ReactComponent: FunctionComponent<
9
+ SVGProps<SVGSVGElement> & { title?: string }
10
+ >;
11
+ const src: string;
12
+ export default src;
13
+ }
14
+
15
+ // @TODO Gilad
16
+ declare module '*.jpg' {
17
+ const value: any;
18
+ export = value;
19
+ }
20
+ declare module '*.jpeg' {
21
+ const value: any;
22
+ export = value;
23
+ }
24
+ declare module '*.gif' {
25
+ const value: any;
26
+ export = value;
27
+ }
28
+ declare module '*.bmp' {
29
+ const value: any;
30
+ export = value;
31
+ }
32
+ declare module '*.otf' {
33
+ const value: any;
34
+ export = value;
35
+ }
36
+ declare module '*.woff' {
37
+ const value: any;
38
+ export = value;
39
+ }
40
+ declare module '*.woff2' {
41
+ const value: any;
42
+ export = value;
43
+ }
package/types/env.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ export type ImportMetaEnv = Record<string, string>;
4
+
5
+ interface ImportMeta {
6
+ readonly env: ImportMetaEnv
7
+ }
8
+
9
+ declare global {
10
+ namespace NodeJS {
11
+ interface ProcessEnv {
12
+ [key: string]: string;
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,42 @@
1
+ declare module '*.module.css' {
2
+ const classes: { readonly [key: string]: string };
3
+ export default classes;
4
+ }
5
+ declare module '*.module.scss' {
6
+ const classes: { readonly [key: string]: string };
7
+ export default classes;
8
+ }
9
+ declare module '*.module.sass' {
10
+ const classes: { readonly [key: string]: string };
11
+ export default classes;
12
+ }
13
+
14
+ declare module '*.module.less' {
15
+ const classes: { readonly [key: string]: string };
16
+ export default classes;
17
+ }
18
+
19
+ declare module '*.less' {
20
+ const classes: { readonly [key: string]: string };
21
+ export default classes;
22
+ }
23
+
24
+ declare module '*.css' {
25
+ const classes: { readonly [key: string]: string };
26
+ export default classes;
27
+ }
28
+
29
+ declare module '*.sass' {
30
+ const classes: { readonly [key: string]: string };
31
+ export default classes;
32
+ }
33
+
34
+ declare module '*.scss' {
35
+ const classes: { readonly [key: string]: string };
36
+ export default classes;
37
+ }
38
+
39
+ declare module '*.mdx' {
40
+ const component: any;
41
+ export default component;
42
+ }