qbs-react-grid 2.2.12 → 2.2.14

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.
@@ -1,4 +1,5 @@
1
1
  import React, { useCallback, useEffect, useId, useRef, useState } from 'react';
2
+ import ReactDOM from 'react-dom';
2
3
 
3
4
  import { QbsColumnProps } from '../commontypes';
4
5
  import type { QbsTableLabels } from '../labels';
@@ -39,7 +40,32 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
39
40
  const toggleId = useId();
40
41
  const [draggedItem, setDraggedItem] = useState<number | null>(null);
41
42
  const popupRef = useRef<HTMLDivElement | null>(null);
43
+ const settingsBtnRef = useRef<HTMLButtonElement | null>(null);
42
44
  const [dragOverPosition, setDragOverPosition] = useState<number | null>();
45
+ const [position, setPosition] = useState({ top: 0, left: 0 });
46
+
47
+ const updatePopupPosition = useCallback(() => {
48
+ if (!settingsBtnRef.current) return;
49
+ const rect = settingsBtnRef.current.getBoundingClientRect();
50
+ const viewportPadding = 8;
51
+ const popupWidth = popupRef.current?.offsetWidth || 360;
52
+ const popupHeight = popupRef.current?.offsetHeight || 320;
53
+
54
+ let left = rtl ? rect.left : rect.right - popupWidth;
55
+ if (left + popupWidth > window.innerWidth - viewportPadding) {
56
+ left = Math.max(viewportPadding, window.innerWidth - popupWidth - viewportPadding);
57
+ }
58
+ if (left < viewportPadding) {
59
+ left = viewportPadding;
60
+ }
61
+
62
+ let top = rect.bottom + 4;
63
+ if (top + popupHeight > window.innerHeight - viewportPadding) {
64
+ top = Math.max(viewportPadding, rect.top - popupHeight - 4);
65
+ }
66
+
67
+ setPosition({ top, left });
68
+ }, [rtl]);
43
69
 
44
70
  useEffect(() => {
45
71
  const handleCloseOthers = (event: Event) => {
@@ -89,7 +115,10 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
89
115
  const handleClickOutside = useCallback(
90
116
  (event: MouseEvent) => {
91
117
  const target = event.target as Node;
92
- if (popupRef.current?.contains(target)) {
118
+ if (
119
+ popupRef.current?.contains(target) ||
120
+ settingsBtnRef.current?.contains(target)
121
+ ) {
93
122
  return;
94
123
  }
95
124
  setIsOpen(false);
@@ -99,9 +128,18 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
99
128
 
100
129
  useEffect(() => {
101
130
  if (!isOpen) return;
131
+ updatePopupPosition();
132
+ const frame = requestAnimationFrame(() => updatePopupPosition());
102
133
  document.addEventListener('mousedown', handleClickOutside);
103
- return () => document.removeEventListener('mousedown', handleClickOutside);
104
- }, [handleClickOutside, isOpen]);
134
+ window.addEventListener('resize', updatePopupPosition);
135
+ window.addEventListener('scroll', updatePopupPosition, true);
136
+ return () => {
137
+ cancelAnimationFrame(frame);
138
+ document.removeEventListener('mousedown', handleClickOutside);
139
+ window.removeEventListener('resize', updatePopupPosition);
140
+ window.removeEventListener('scroll', updatePopupPosition, true);
141
+ };
142
+ }, [handleClickOutside, isOpen, updatePopupPosition]);
105
143
 
106
144
  const renderFixedColumn = (column: QbsColumnProps, index: number) => (
107
145
  <div
@@ -199,30 +237,22 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
199
237
  handleColumnToggle?.(columns);
200
238
  };
201
239
 
202
- return (
203
- <div className="qbs-table-settings-wrapper">
204
- <button
205
- type="button"
206
- onClick={event => {
207
- event.stopPropagation();
208
- if (isOpen) {
209
- setIsOpen(false);
210
- return;
211
- }
212
- closeOtherColumnToggles(toggleId);
213
- setIsOpen(true);
214
- }}
215
- >
216
- <SettingsIcon />
217
- </button>
218
- {isOpen && (
219
- <div
220
- className={`qbs-table-column-popup${rtl ? ' qbs-table-column-popup--rtl' : ''}`}
221
- style={{ maxHeight: tableHeight - 40 }}
222
- ref={popupRef}
223
- dir={rtl ? 'rtl' : 'ltr'}
224
- >
225
- <div className="qbs-table-popup-container">
240
+ const portalTarget = document.getElementById('portal-root') ?? document.body;
241
+
242
+ const popupContent = (
243
+ <div
244
+ className={`qbs-table-column-popup${rtl ? ' qbs-table-column-popup--rtl' : ''}`}
245
+ style={{
246
+ position: 'fixed',
247
+ top: position.top,
248
+ left: position.left,
249
+ maxHeight: Math.min(tableHeight - 40, window.innerHeight - position.top - 16),
250
+ zIndex: 10060,
251
+ }}
252
+ ref={popupRef}
253
+ dir={rtl ? 'rtl' : 'ltr'}
254
+ >
255
+ <div className="qbs-table-popup-container">
226
256
  <div className="qbs-table-popup-item">
227
257
  <div className="qbs-table-popup-label">{labels.fixedColumns}</div>
228
258
  <div className="qbs-table-columns-container">
@@ -277,8 +307,28 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
277
307
  </div>
278
308
  </>
279
309
  )}
280
- </div>
281
- )}
310
+ </div>
311
+ );
312
+
313
+ return (
314
+ <div className="qbs-table-settings-wrapper">
315
+ <button
316
+ type="button"
317
+ ref={settingsBtnRef}
318
+ onClick={event => {
319
+ event.stopPropagation();
320
+ if (isOpen) {
321
+ setIsOpen(false);
322
+ return;
323
+ }
324
+ closeOtherColumnToggles(toggleId);
325
+ updatePopupPosition();
326
+ setIsOpen(true);
327
+ }}
328
+ >
329
+ <SettingsIcon />
330
+ </button>
331
+ {isOpen && portalTarget && ReactDOM.createPortal(popupContent, portalTarget)}
282
332
  </div>
283
333
  );
284
334
  };