qbs-react-grid 2.2.4 → 2.2.6
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/css/qbs-react-grid.css +1 -1
- package/dist/css/qbs-react-grid.min.css +1 -1
- package/dist/css/qbs-react-grid.min.css.map +1 -1
- package/es/Cell.js +1 -2
- package/es/Pagination.d.ts +0 -3
- package/es/Pagination.js +3 -8
- package/es/Table.d.ts +0 -3
- package/es/Table.js +12 -18
- package/es/index.d.ts +1 -1
- package/es/less/pagination.less +9 -9
- package/es/less/qbs-table.less +73 -205
- package/es/qbsTable/CustomTableCell.js +15 -11
- package/es/qbsTable/QbsTable.js +48 -124
- package/es/qbsTable/TableCardList.js +41 -52
- package/es/qbsTable/Toolbar.js +13 -62
- package/es/qbsTable/commontypes.d.ts +3 -30
- package/es/qbsTable/utilities/CardComponent.d.ts +0 -2
- package/es/qbsTable/utilities/CardComponent.js +3 -7
- package/es/qbsTable/utilities/CardMenuDropdown.d.ts +0 -2
- package/es/qbsTable/utilities/CardMenuDropdown.js +7 -7
- package/es/qbsTable/utilities/ColumShowHide.d.ts +0 -4
- package/es/qbsTable/utilities/ColumShowHide.js +6 -9
- package/es/qbsTable/utilities/SearchInput.d.ts +0 -1
- package/es/qbsTable/utilities/SearchInput.js +1 -3
- package/es/qbsTable/utilities/ToolTip.d.ts +1 -8
- package/es/qbsTable/utilities/ToolTip.js +31 -107
- package/es/qbsTable/utilities/VerticalDropDownMenu.d.ts +7 -9
- package/es/qbsTable/utilities/VerticalDropDownMenu.js +71 -63
- package/es/qbsTable/utilities/empty.js +1 -1
- package/es/qbsTable/utilities/icons.d.ts +0 -3
- package/es/qbsTable/utilities/icons.js +1 -65
- package/es/qbsTable/utilities/tablecalc.d.ts +1 -1
- package/es/qbsTable/utilities/tablecalc.js +2 -7
- package/es/utils/useCellDescriptor.js +1 -0
- package/es/utils/useScrollListener.d.ts +0 -1
- package/es/utils/useScrollListener.js +3 -5
- package/lib/Cell.js +1 -2
- package/lib/Pagination.d.ts +0 -3
- package/lib/Pagination.js +3 -8
- package/lib/Table.d.ts +0 -3
- package/lib/Table.js +12 -18
- package/lib/index.d.ts +1 -1
- package/lib/less/pagination.less +9 -9
- package/lib/less/qbs-table.less +73 -205
- package/lib/qbsTable/CustomTableCell.js +15 -11
- package/lib/qbsTable/QbsTable.js +48 -124
- package/lib/qbsTable/TableCardList.js +41 -52
- package/lib/qbsTable/Toolbar.js +12 -61
- package/lib/qbsTable/commontypes.d.ts +3 -30
- package/lib/qbsTable/utilities/CardComponent.d.ts +0 -2
- package/lib/qbsTable/utilities/CardComponent.js +3 -7
- package/lib/qbsTable/utilities/CardMenuDropdown.d.ts +0 -2
- package/lib/qbsTable/utilities/CardMenuDropdown.js +5 -6
- package/lib/qbsTable/utilities/ColumShowHide.d.ts +0 -4
- package/lib/qbsTable/utilities/ColumShowHide.js +6 -9
- package/lib/qbsTable/utilities/SearchInput.d.ts +0 -1
- package/lib/qbsTable/utilities/SearchInput.js +1 -3
- package/lib/qbsTable/utilities/ToolTip.d.ts +1 -8
- package/lib/qbsTable/utilities/ToolTip.js +30 -107
- package/lib/qbsTable/utilities/VerticalDropDownMenu.d.ts +7 -9
- package/lib/qbsTable/utilities/VerticalDropDownMenu.js +71 -63
- package/lib/qbsTable/utilities/empty.js +1 -1
- package/lib/qbsTable/utilities/icons.d.ts +0 -3
- package/lib/qbsTable/utilities/icons.js +3 -70
- package/lib/qbsTable/utilities/tablecalc.d.ts +1 -1
- package/lib/qbsTable/utilities/tablecalc.js +2 -7
- package/lib/utils/useCellDescriptor.js +1 -0
- package/lib/utils/useScrollListener.d.ts +0 -1
- package/lib/utils/useScrollListener.js +3 -5
- package/package.json +10 -2
- package/src/Cell.tsx +1 -3
- package/src/HeaderCell.tsx +1 -0
- package/src/Pagination.tsx +3 -10
- package/src/Table.tsx +10 -23
- package/src/customSelect.tsx +88 -88
- package/src/index.ts +1 -1
- package/src/less/pagination.less +9 -9
- package/src/less/qbs-table.less +73 -205
- package/src/qbsTable/CustomTableCell.tsx +23 -27
- package/src/qbsTable/QbsTable.tsx +26 -100
- package/src/qbsTable/TableCardList.tsx +20 -34
- package/src/qbsTable/Toolbar.tsx +11 -53
- package/src/qbsTable/commontypes.ts +2 -32
- package/src/qbsTable/utilities/CardComponent.tsx +2 -7
- package/src/qbsTable/utilities/CardMenuDropdown.tsx +6 -11
- package/src/qbsTable/utilities/ColumShowHide.tsx +6 -33
- package/src/qbsTable/utilities/SearchInput.tsx +1 -3
- package/src/qbsTable/utilities/ToolTip.tsx +27 -138
- package/src/qbsTable/utilities/VerticalDropDownMenu.tsx +89 -74
- package/src/qbsTable/utilities/empty.tsx +2 -2
- package/src/qbsTable/utilities/icons.tsx +1 -78
- package/src/qbsTable/utilities/tablecalc.ts +2 -8
- package/src/utils/useCellDescriptor.ts +1 -0
- package/src/utils/useScrollListener.ts +3 -13
- package/src/utils/useTableRows.ts +1 -1
- package/es/qbsTable/labels.d.ts +0 -48
- package/es/qbsTable/labels.js +0 -34
- package/lib/qbsTable/labels.d.ts +0 -48
- package/lib/qbsTable/labels.js +0 -42
- package/src/qbsTable/labels.ts +0 -58
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { QbsColumnProps } from '../commontypes';
|
|
4
|
-
import { mergeLabels, type QbsTableLabels } from '../labels';
|
|
5
4
|
import CardMenuDropdown from './CardMenuDropdown';
|
|
6
5
|
import { handleCellFormat } from './handleFormatCell';
|
|
7
6
|
import { ArrowUpIcon } from './icons';
|
|
@@ -18,7 +17,6 @@ type Props = {
|
|
|
18
17
|
handleMenuActions?: () => void;
|
|
19
18
|
cardColumLimit?: number;
|
|
20
19
|
childDetailHeading?: string;
|
|
21
|
-
labels?: QbsTableLabels;
|
|
22
20
|
};
|
|
23
21
|
|
|
24
22
|
const CardComponent: React.FC<Props> = ({
|
|
@@ -29,10 +27,8 @@ const CardComponent: React.FC<Props> = ({
|
|
|
29
27
|
index,
|
|
30
28
|
cardColumLimit = 5,
|
|
31
29
|
handleMenuActions,
|
|
32
|
-
childDetailHeading = ''
|
|
33
|
-
labels: labelsProp
|
|
30
|
+
childDetailHeading = ''
|
|
34
31
|
}) => {
|
|
35
|
-
const labels = mergeLabels(labelsProp);
|
|
36
32
|
const [viewMore, setViewMore] = useState(false);
|
|
37
33
|
const initialDisplayCount = cardColumLimit;
|
|
38
34
|
|
|
@@ -106,14 +102,13 @@ const CardComponent: React.FC<Props> = ({
|
|
|
106
102
|
iconName="more"
|
|
107
103
|
rowIndex={index}
|
|
108
104
|
handleMenuActions={handleMenuActions}
|
|
109
|
-
labels={labels}
|
|
110
105
|
/>
|
|
111
106
|
</div>
|
|
112
107
|
|
|
113
108
|
{columns.length > initialDisplayCount && (
|
|
114
109
|
<TooltipComponent
|
|
115
110
|
tableBodyRef={useCardRef}
|
|
116
|
-
title={viewMore ?
|
|
111
|
+
title={viewMore ? ' View Less' : 'View More'}
|
|
117
112
|
enabled={false}
|
|
118
113
|
>
|
|
119
114
|
<button
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
2
4
|
import { ActionProps } from '../commontypes';
|
|
3
|
-
import { mergeLabels, type QbsTableLabels } from '../labels';
|
|
4
5
|
import { ThreeDotIcon } from './icons';
|
|
5
6
|
import TooltipComponent from './ToolTip';
|
|
6
7
|
|
|
@@ -12,16 +13,9 @@ type Props = {
|
|
|
12
13
|
dataTheme?: string;
|
|
13
14
|
tableBodyRef: React.RefObject<HTMLDivElement>;
|
|
14
15
|
rowIndex?: number;
|
|
15
|
-
labels?: QbsTableLabels;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
const CardMenuDropdown: React.FC<Props> = ({
|
|
19
|
-
actionDropDown,
|
|
20
|
-
handleMenuActions,
|
|
21
|
-
rowData,
|
|
22
|
-
labels: labelsProp
|
|
23
|
-
}) => {
|
|
24
|
-
const labels = mergeLabels(labelsProp);
|
|
18
|
+
const CardMenuDropdown: React.FC<Props> = ({ actionDropDown, handleMenuActions, rowData }) => {
|
|
25
19
|
const [openMenu, setOpenMenu] = useState(false);
|
|
26
20
|
const [menuPositionStyles, setMenuPositionStyles] = useState<{
|
|
27
21
|
top?: string;
|
|
@@ -52,6 +46,7 @@ const CardMenuDropdown: React.FC<Props> = ({
|
|
|
52
46
|
const dropdownHeight = 200; // Adjust this if your dropdown height varies
|
|
53
47
|
const spaceBelow = window.innerHeight - buttonRect.bottom;
|
|
54
48
|
const spaceAbove = buttonRect.top;
|
|
49
|
+
console.log(spaceAbove, spaceBelow, dropdownHeight);
|
|
55
50
|
if (spaceBelow < dropdownHeight && spaceAbove > spaceBelow) {
|
|
56
51
|
setMenuPositionStyles({
|
|
57
52
|
bottom: '30px',
|
|
@@ -81,7 +76,7 @@ const CardMenuDropdown: React.FC<Props> = ({
|
|
|
81
76
|
return (
|
|
82
77
|
<div className="dropdown text-black dark:text-white dark:bg-[#424242] bg-white" ref={menuRef}>
|
|
83
78
|
<button className="dropdown-toggle" onClick={toggleMenu} ref={menuButtonRef}>
|
|
84
|
-
<TooltipComponent title=
|
|
79
|
+
<TooltipComponent title="Actions" enabled={false} ref={menuButtonRef}>
|
|
85
80
|
<ThreeDotIcon />
|
|
86
81
|
</TooltipComponent>
|
|
87
82
|
</button>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { QbsColumnProps } from '../commontypes';
|
|
4
|
-
import { mergeLabels, type QbsTableLabels } from '../labels';
|
|
5
4
|
import { SettingsIcon } from './icons';
|
|
6
5
|
|
|
7
6
|
interface ColumnToggleProps {
|
|
@@ -13,9 +12,6 @@ interface ColumnToggleProps {
|
|
|
13
12
|
handleColumnToggle?: (columns: QbsColumnProps[]) => void;
|
|
14
13
|
handleResetColumns?: () => void;
|
|
15
14
|
tableHeight?: number;
|
|
16
|
-
viewMode?: string;
|
|
17
|
-
setViewMode?: (value: string) => void;
|
|
18
|
-
labels?: QbsTableLabels;
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
const ColumnToggle: React.FC<ColumnToggleProps> = ({
|
|
@@ -26,10 +22,8 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
|
|
|
26
22
|
setIsOpen,
|
|
27
23
|
handleResetColumns,
|
|
28
24
|
handleColumnToggle,
|
|
29
|
-
tableHeight = 450
|
|
30
|
-
labels: labelsProp
|
|
25
|
+
tableHeight = 450
|
|
31
26
|
}) => {
|
|
32
|
-
const labels = mergeLabels(labelsProp);
|
|
33
27
|
const [draggedItem, setDraggedItem] = useState<number | null>(null);
|
|
34
28
|
const popupRef = useRef<HTMLDivElement | null>(null);
|
|
35
29
|
const [dragOverPosition, setDragOverPosition] = useState<number | null>();
|
|
@@ -189,7 +183,7 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
|
|
|
189
183
|
>
|
|
190
184
|
<div className="qbs-table-popup-container">
|
|
191
185
|
<div className="qbs-table-popup-item">
|
|
192
|
-
<div className="qbs-table-popup-label">
|
|
186
|
+
<div className="qbs-table-popup-label">FIXED COLUMNS</div>
|
|
193
187
|
<div className="qbs-table-columns-container">
|
|
194
188
|
<div className="qbs-table-column">
|
|
195
189
|
{columns.map((column, index) =>
|
|
@@ -200,7 +194,7 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
|
|
|
200
194
|
</div>
|
|
201
195
|
<div className="qbs-table-divider"></div>
|
|
202
196
|
<div className="qbs-table-popup-item">
|
|
203
|
-
<div className="qbs-table-popup-label">
|
|
197
|
+
<div className="qbs-table-popup-label">VISIBLE COLUMNS</div>
|
|
204
198
|
<div className="qbs-table-columns-container">
|
|
205
199
|
<div className="qbs-table-column">
|
|
206
200
|
{columns.map((column, index) =>
|
|
@@ -213,7 +207,7 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
|
|
|
213
207
|
<>
|
|
214
208
|
<div className="qbs-table-divider"></div>
|
|
215
209
|
<div className="qbs-table-popup-item">
|
|
216
|
-
<div className="qbs-table-popup-label">
|
|
210
|
+
<div className="qbs-table-popup-label">AVAILABLE COLUMNS</div>
|
|
217
211
|
<div className="qbs-table-columns-container">
|
|
218
212
|
<div className="qbs-table-column">
|
|
219
213
|
{columns.map((column, index) =>
|
|
@@ -237,35 +231,14 @@ const ColumnToggle: React.FC<ColumnToggleProps> = ({
|
|
|
237
231
|
href="#"
|
|
238
232
|
onClick={() => handleResetColumns?.()}
|
|
239
233
|
>
|
|
240
|
-
|
|
234
|
+
Reset to default
|
|
241
235
|
</a>
|
|
242
236
|
<a className="qbs-table-reset-link" href="#" onClick={() => handleColToggle()}>
|
|
243
|
-
|
|
237
|
+
Save
|
|
244
238
|
</a>
|
|
245
239
|
</div>
|
|
246
240
|
</>
|
|
247
241
|
)}
|
|
248
|
-
{/* <div className="qbs-table-popup-item">
|
|
249
|
-
<label className="flex items-center gap-2">
|
|
250
|
-
<input
|
|
251
|
-
type="radio"
|
|
252
|
-
value="compact"
|
|
253
|
-
checked={viewMode === 'compact'}
|
|
254
|
-
onChange={() => setViewMode?.('compact')}
|
|
255
|
-
/>
|
|
256
|
-
Compact View
|
|
257
|
-
</label>
|
|
258
|
-
|
|
259
|
-
<label className="flex items-center gap-2">
|
|
260
|
-
<input
|
|
261
|
-
type="radio"
|
|
262
|
-
value="expanded"
|
|
263
|
-
checked={viewMode === 'expanded'}
|
|
264
|
-
onChange={() => setViewMode?.('expanded')}
|
|
265
|
-
/>
|
|
266
|
-
Default View
|
|
267
|
-
</label>
|
|
268
|
-
</div> */}
|
|
269
242
|
</div>
|
|
270
243
|
</div>
|
|
271
244
|
)}
|
|
@@ -2,14 +2,12 @@ import React, { memo, useCallback } from 'react';
|
|
|
2
2
|
|
|
3
3
|
export interface SearchProps {
|
|
4
4
|
placeholder: string;
|
|
5
|
-
searchAriaLabel?: string;
|
|
6
5
|
handleChange: (value: string) => void;
|
|
7
6
|
searchValue: string | undefined;
|
|
8
7
|
handleSearch: (value?: string) => void;
|
|
9
8
|
}
|
|
10
9
|
const SearchInput: React.FC<SearchProps> = ({
|
|
11
10
|
placeholder,
|
|
12
|
-
searchAriaLabel = 'Search',
|
|
13
11
|
handleChange,
|
|
14
12
|
searchValue,
|
|
15
13
|
handleSearch
|
|
@@ -39,7 +37,7 @@ const SearchInput: React.FC<SearchProps> = ({
|
|
|
39
37
|
placeholder={placeholder}
|
|
40
38
|
value={searchValue ?? ''}
|
|
41
39
|
onChange={handleInputChange}
|
|
42
|
-
aria-label=
|
|
40
|
+
aria-label="Search"
|
|
43
41
|
/>
|
|
44
42
|
<button
|
|
45
43
|
className="search-button absolute left-1 bottom-1.5 bg-white text-grey-dark"
|
|
@@ -1,149 +1,38 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}) => {
|
|
21
|
-
const [visible, setVisible] = useState(false);
|
|
22
|
-
const [positioned, setPositioned] = useState(false);
|
|
23
|
-
const [placement, setPlacement] = useState<'up' | 'down'>('down');
|
|
24
|
-
const [coords, setCoords] = useState({ top: 0, left: 0 });
|
|
25
|
-
const [arrowOffset, setArrowOffset] = useState(0);
|
|
26
|
-
const triggerRef = useRef<HTMLSpanElement>(null);
|
|
27
|
-
const tooltipRef = useRef<HTMLSpanElement>(null);
|
|
28
|
-
|
|
29
|
-
const updatePosition = useCallback(() => {
|
|
30
|
-
const trigger = triggerRef.current;
|
|
31
|
-
const tooltip = tooltipRef.current;
|
|
32
|
-
if (!trigger || !tooltip) {
|
|
33
|
-
return;
|
|
1
|
+
import React, { useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
const TooltipComponent: React.FC<any> = ({ title, children, tableBodyRef }) => {
|
|
4
|
+
const [dropdownPosition, setDropdownPosition] = useState('bottom-position');
|
|
5
|
+
const dropRef = useRef(null);
|
|
6
|
+
const menuButtonRef = useRef<HTMLElement>(null);
|
|
7
|
+
const adjustDropdownPosition = () => {
|
|
8
|
+
if (menuButtonRef.current && tableBodyRef?.current) {
|
|
9
|
+
const inputBoxRect = menuButtonRef.current?.getBoundingClientRect();
|
|
10
|
+
const tableRect = tableBodyRef.current.getBoundingClientRect();
|
|
11
|
+
// Calculate positions relative to the table
|
|
12
|
+
const spaceAbove = inputBoxRect.top - tableRect.top;
|
|
13
|
+
const spaceBelow = tableRect.bottom - inputBoxRect.bottom;
|
|
14
|
+
|
|
15
|
+
if (spaceAbove > spaceBelow) {
|
|
16
|
+
setDropdownPosition('top-position');
|
|
17
|
+
} else {
|
|
18
|
+
setDropdownPosition('bottom-position');
|
|
19
|
+
}
|
|
34
20
|
}
|
|
35
|
-
|
|
36
|
-
const triggerRect = trigger.getBoundingClientRect();
|
|
37
|
-
const tooltipRect = tooltip.getBoundingClientRect();
|
|
38
|
-
const boundaryRect =
|
|
39
|
-
tableBodyRef?.current?.getBoundingClientRect() ??
|
|
40
|
-
trigger.closest('.qbs-table')?.getBoundingClientRect();
|
|
41
|
-
|
|
42
|
-
const spaceAbove = boundaryRect
|
|
43
|
-
? triggerRect.top - boundaryRect.top
|
|
44
|
-
: triggerRect.top;
|
|
45
|
-
const spaceBelow = boundaryRect
|
|
46
|
-
? boundaryRect.bottom - triggerRect.bottom
|
|
47
|
-
: window.innerHeight - triggerRect.bottom;
|
|
48
|
-
|
|
49
|
-
const nextPlacement =
|
|
50
|
-
spaceBelow >= tooltipRect.height + TOOLTIP_GAP || spaceBelow >= spaceAbove ? 'down' : 'up';
|
|
51
|
-
|
|
52
|
-
const triggerCenter = triggerRect.left + triggerRect.width / 2;
|
|
53
|
-
let left = triggerCenter - tooltipRect.width / 2;
|
|
54
|
-
|
|
55
|
-
if (left < VIEWPORT_PADDING) {
|
|
56
|
-
left = VIEWPORT_PADDING;
|
|
57
|
-
} else if (left + tooltipRect.width > window.innerWidth - VIEWPORT_PADDING) {
|
|
58
|
-
left = window.innerWidth - VIEWPORT_PADDING - tooltipRect.width;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const top =
|
|
62
|
-
nextPlacement === 'down'
|
|
63
|
-
? triggerRect.bottom + TOOLTIP_GAP
|
|
64
|
-
: triggerRect.top - tooltipRect.height - TOOLTIP_GAP;
|
|
65
|
-
|
|
66
|
-
setPlacement(nextPlacement);
|
|
67
|
-
setCoords({ top, left });
|
|
68
|
-
setArrowOffset(triggerCenter - left);
|
|
69
|
-
setPositioned(true);
|
|
70
|
-
}, [tableBodyRef]);
|
|
71
|
-
|
|
72
|
-
const showTooltip = () => {
|
|
73
|
-
setPositioned(false);
|
|
74
|
-
setVisible(true);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const hideTooltip = () => {
|
|
78
|
-
setVisible(false);
|
|
79
|
-
setPositioned(false);
|
|
80
21
|
};
|
|
81
22
|
|
|
82
|
-
useLayoutEffect(() => {
|
|
83
|
-
if (!visible) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
updatePosition();
|
|
88
|
-
const frame = window.requestAnimationFrame(updatePosition);
|
|
89
|
-
return () => window.cancelAnimationFrame(frame);
|
|
90
|
-
}, [visible, title, updatePosition]);
|
|
91
|
-
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
if (!visible) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const handleReposition = () => updatePosition();
|
|
98
|
-
window.addEventListener('resize', handleReposition);
|
|
99
|
-
window.addEventListener('scroll', handleReposition, true);
|
|
100
|
-
return () => {
|
|
101
|
-
window.removeEventListener('resize', handleReposition);
|
|
102
|
-
window.removeEventListener('scroll', handleReposition, true);
|
|
103
|
-
};
|
|
104
|
-
}, [visible, updatePosition]);
|
|
105
|
-
|
|
106
|
-
if (!title || enabled === false) {
|
|
107
|
-
return <>{children}</>;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const portalRoot = typeof document !== 'undefined' ? document.body : null;
|
|
111
|
-
|
|
112
23
|
return (
|
|
113
|
-
|
|
24
|
+
<div className={`qbs-table-tooltip ${dropdownPosition == 'bottom-position' ? 'down' : 'up'} `}>
|
|
114
25
|
<span
|
|
115
|
-
ref={
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
onMouseEnter={showTooltip}
|
|
119
|
-
onMouseLeave={hideTooltip}
|
|
120
|
-
onFocus={showTooltip}
|
|
121
|
-
onBlur={hideTooltip}
|
|
26
|
+
ref={menuButtonRef}
|
|
27
|
+
style={{ display: 'flex' }}
|
|
28
|
+
onMouseEnter={() => adjustDropdownPosition()}
|
|
122
29
|
>
|
|
123
30
|
{children}
|
|
124
31
|
</span>
|
|
125
|
-
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
ref={tooltipRef}
|
|
130
|
-
role="tooltip"
|
|
131
|
-
className={`qbs-table-tooltip-floating tooltiptext qbs-table-tooltip-floating--${placement} ${
|
|
132
|
-
positioned ? 'is-positioned' : ''
|
|
133
|
-
}`}
|
|
134
|
-
style={
|
|
135
|
-
{
|
|
136
|
-
top: coords.top,
|
|
137
|
-
left: coords.left,
|
|
138
|
-
'--tooltip-arrow-offset': `${arrowOffset}px`,
|
|
139
|
-
} as React.CSSProperties
|
|
140
|
-
}
|
|
141
|
-
>
|
|
142
|
-
{title}
|
|
143
|
-
</span>,
|
|
144
|
-
portalRoot,
|
|
145
|
-
)}
|
|
146
|
-
</>
|
|
32
|
+
<span ref={dropRef} className={'tooltiptext'}>
|
|
33
|
+
{title}
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
147
36
|
);
|
|
148
37
|
};
|
|
149
38
|
|
|
@@ -1,75 +1,119 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import ReactDOM from 'react-dom';
|
|
3
3
|
|
|
4
|
-
import { ActionProps } from '../commontypes';
|
|
5
4
|
import { ThreeDotIcon } from './icons';
|
|
6
5
|
import TooltipComponent from './ToolTip';
|
|
6
|
+
import type { ActionProps } from '../commontypes';
|
|
7
7
|
|
|
8
|
-
type
|
|
9
|
-
actionDropDown
|
|
10
|
-
handleMenuActions?: (
|
|
11
|
-
rowData
|
|
12
|
-
|
|
13
|
-
tableBodyRef: React.RefObject<HTMLDivElement | null>;
|
|
8
|
+
type VerticalMenuDropdownProps = {
|
|
9
|
+
actionDropDown?: readonly ActionProps[];
|
|
10
|
+
handleMenuActions?: (actions: ActionProps, rowData: any) => void;
|
|
11
|
+
rowData: any;
|
|
12
|
+
tableBodyRef?: React.RefObject<HTMLDivElement>;
|
|
14
13
|
rowIndex?: number;
|
|
15
|
-
wheelWrapperRef?: React.RefObject<HTMLDivElement>;
|
|
16
14
|
};
|
|
17
15
|
|
|
18
|
-
const VerticalMenuDropdown: React.FC<
|
|
16
|
+
const VerticalMenuDropdown: React.FC<VerticalMenuDropdownProps> = ({
|
|
19
17
|
actionDropDown,
|
|
20
18
|
handleMenuActions,
|
|
21
19
|
rowData,
|
|
22
20
|
tableBodyRef,
|
|
23
|
-
rowIndex
|
|
21
|
+
rowIndex,
|
|
24
22
|
}) => {
|
|
25
23
|
const [openMenu, setOpenMenu] = useState(false);
|
|
26
24
|
const [position, setPosition] = useState({ top: 0, left: 0 });
|
|
27
|
-
const menuButtonRef = useRef<HTMLButtonElement
|
|
28
|
-
const menuRef = useRef<HTMLDivElement
|
|
25
|
+
const menuButtonRef = useRef<HTMLButtonElement>(null);
|
|
26
|
+
const menuRef = useRef<HTMLDivElement>(null);
|
|
27
|
+
|
|
28
|
+
const updateMenuPosition = () => {
|
|
29
|
+
if (!menuButtonRef.current) return;
|
|
30
|
+
|
|
31
|
+
const rect = menuButtonRef.current.getBoundingClientRect();
|
|
32
|
+
const viewportPadding = 8;
|
|
33
|
+
const menuGap = 4;
|
|
34
|
+
const visibleItems =
|
|
35
|
+
actionDropDown?.filter(
|
|
36
|
+
item =>
|
|
37
|
+
!item.hidden && !(item.hide?.call(item, rowData, rowIndex) ?? false),
|
|
38
|
+
) ?? [];
|
|
39
|
+
const menuWidth =
|
|
40
|
+
menuRef.current && menuRef.current.offsetWidth > 0
|
|
41
|
+
? menuRef.current.offsetWidth
|
|
42
|
+
: Math.max(120, visibleItems.length * 48);
|
|
43
|
+
const menuHeight = visibleItems.length * 40;
|
|
44
|
+
const spaceBelow = window.innerHeight - rect.bottom;
|
|
45
|
+
const openBelow = spaceBelow >= menuHeight + menuGap;
|
|
46
|
+
|
|
47
|
+
let left = rect.left;
|
|
48
|
+
if (left + menuWidth > window.innerWidth - viewportPadding) {
|
|
49
|
+
left = Math.max(viewportPadding, rect.right - menuWidth);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setPosition({
|
|
53
|
+
top: openBelow ? rect.bottom + menuGap : rect.top - menuHeight - menuGap,
|
|
54
|
+
left,
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!openMenu) return;
|
|
60
|
+
updateMenuPosition();
|
|
61
|
+
const frame = requestAnimationFrame(() => updateMenuPosition());
|
|
62
|
+
const resizeObserver =
|
|
63
|
+
menuRef.current && typeof ResizeObserver !== 'undefined'
|
|
64
|
+
? new ResizeObserver(() => updateMenuPosition())
|
|
65
|
+
: null;
|
|
66
|
+
if (resizeObserver && menuRef.current) {
|
|
67
|
+
resizeObserver.observe(menuRef.current);
|
|
68
|
+
}
|
|
69
|
+
return () => {
|
|
70
|
+
cancelAnimationFrame(frame);
|
|
71
|
+
resizeObserver?.disconnect();
|
|
72
|
+
};
|
|
73
|
+
}, [openMenu]);
|
|
29
74
|
|
|
30
75
|
useEffect(() => {
|
|
76
|
+
if (!openMenu) return;
|
|
77
|
+
|
|
31
78
|
const handleClickOutside = (event: MouseEvent) => {
|
|
32
|
-
|
|
33
|
-
|
|
79
|
+
const target = event.target as Node;
|
|
80
|
+
if (
|
|
81
|
+
menuRef.current?.contains(target) ||
|
|
82
|
+
menuButtonRef.current?.contains(target)
|
|
83
|
+
) {
|
|
84
|
+
return;
|
|
34
85
|
}
|
|
35
|
-
};
|
|
36
|
-
const handleScroll = () => {
|
|
37
86
|
setOpenMenu(false);
|
|
38
87
|
};
|
|
88
|
+
const handleScroll = () => setOpenMenu(false);
|
|
39
89
|
|
|
40
90
|
document.addEventListener('click', handleClickOutside);
|
|
41
91
|
window.addEventListener('scroll', handleScroll, true);
|
|
42
|
-
// Use capture phase to catch all scrolls
|
|
43
92
|
|
|
44
93
|
return () => {
|
|
45
94
|
document.removeEventListener('click', handleClickOutside);
|
|
46
95
|
window.removeEventListener('scroll', handleScroll, true);
|
|
47
96
|
};
|
|
48
|
-
}, []);
|
|
49
|
-
useEffect(() => {
|
|
50
|
-
const handleStyleChange = () => {
|
|
51
|
-
setOpenMenu(false); // Close the dropdown
|
|
52
|
-
};
|
|
97
|
+
}, [openMenu]);
|
|
53
98
|
|
|
99
|
+
useEffect(() => {
|
|
54
100
|
const scrollbarHandle = document.querySelector('.rs-table-scrollbar-handle');
|
|
55
101
|
if (!scrollbarHandle) return;
|
|
56
102
|
|
|
57
103
|
const observer = new MutationObserver(mutations => {
|
|
58
104
|
for (const mutation of mutations) {
|
|
59
105
|
if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
|
|
60
|
-
|
|
106
|
+
setOpenMenu(false);
|
|
61
107
|
}
|
|
62
108
|
}
|
|
63
109
|
});
|
|
64
110
|
|
|
65
111
|
observer.observe(scrollbarHandle, {
|
|
66
112
|
attributes: true,
|
|
67
|
-
attributeFilter: ['style']
|
|
113
|
+
attributeFilter: ['style'],
|
|
68
114
|
});
|
|
69
115
|
|
|
70
|
-
return () =>
|
|
71
|
-
observer.disconnect();
|
|
72
|
-
};
|
|
116
|
+
return () => observer.disconnect();
|
|
73
117
|
}, [openMenu]);
|
|
74
118
|
|
|
75
119
|
const handleMenuItemClick = (slug: ActionProps) => {
|
|
@@ -78,63 +122,29 @@ const VerticalMenuDropdown: React.FC<Props> = ({
|
|
|
78
122
|
setOpenMenu(false);
|
|
79
123
|
};
|
|
80
124
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const toggleMenu = () => {
|
|
88
|
-
if (!openMenu && menuButtonRef.current) {
|
|
89
|
-
const rect = menuButtonRef.current.getBoundingClientRect();
|
|
90
|
-
const viewportPadding = 8;
|
|
91
|
-
const menuGap = 4;
|
|
92
|
-
const dropdownWidth = 200;
|
|
93
|
-
const visibleItems =
|
|
94
|
-
actionDropDown?.filter(item => !item.hidden && !item?.hide?.(rowData, rowIndex)) ?? [];
|
|
95
|
-
const menuHeight = visibleItems.length * 40;
|
|
96
|
-
|
|
97
|
-
const spaceBelow = window.innerHeight - rect.bottom;
|
|
98
|
-
const openBelow = spaceBelow >= menuHeight + menuGap;
|
|
125
|
+
const visibleCount =
|
|
126
|
+
actionDropDown?.filter(
|
|
127
|
+
item => !item.hidden && !(item.hide?.call(item, rowData, rowIndex) ?? false),
|
|
128
|
+
).length ?? 0;
|
|
99
129
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (left < viewportPadding) {
|
|
104
|
-
left = rect.left;
|
|
105
|
-
}
|
|
106
|
-
if (left + dropdownWidth > window.innerWidth - viewportPadding) {
|
|
107
|
-
left = Math.max(viewportPadding, rect.left - dropdownWidth);
|
|
108
|
-
}
|
|
109
|
-
if (left + dropdownWidth > window.innerWidth - viewportPadding) {
|
|
110
|
-
left = window.innerWidth - viewportPadding - dropdownWidth;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
setPosition({
|
|
114
|
-
top: openBelow ? rect.bottom + menuGap : rect.top - menuHeight - menuGap,
|
|
115
|
-
left,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
setTimeout(() => {
|
|
119
|
-
setOpenMenu(prev => !prev);
|
|
120
|
-
}, 200);
|
|
121
|
-
};
|
|
130
|
+
const portalTarget =
|
|
131
|
+
document.getElementById('portal-root') ?? document.body;
|
|
122
132
|
|
|
123
|
-
const portalTarget = document.getElementById('portal-root');
|
|
124
133
|
const dropdownContent = (
|
|
125
134
|
<div
|
|
126
135
|
className="absolute z-[60] min-w-48 rounded-md vertical-menu-dropdown-content"
|
|
127
136
|
ref={menuRef}
|
|
128
137
|
style={{
|
|
129
|
-
width: 200,
|
|
130
138
|
top: position.top,
|
|
131
139
|
left: position.left,
|
|
132
140
|
position: 'fixed',
|
|
141
|
+
minWidth: 120,
|
|
142
|
+
width: 'max-content',
|
|
133
143
|
}}
|
|
134
144
|
>
|
|
135
145
|
<div className="py-1">
|
|
136
146
|
{actionDropDown?.map(item =>
|
|
137
|
-
!item
|
|
147
|
+
!item.hidden && !(item.hide?.call(item, rowData, rowIndex) ?? false) ? (
|
|
138
148
|
<div
|
|
139
149
|
key={item.title}
|
|
140
150
|
className="vertical-menu-item px-4 py-2 text-sm text-base-black hover:bg-gray-light-1 cursor-pointer flex items-center gap-2 transition-colors"
|
|
@@ -146,12 +156,12 @@ const VerticalMenuDropdown: React.FC<Props> = ({
|
|
|
146
156
|
>
|
|
147
157
|
<TooltipComponent title={item.toolTip} tableBodyRef={tableBodyRef}>
|
|
148
158
|
<div className="vertical-menu-icon-title flex items-center gap-2">
|
|
149
|
-
{item
|
|
159
|
+
{item.icon && <span className="vertical-menu-icon">{item.icon}</span>}
|
|
150
160
|
<span className="vertical-menu-title">{item.title}</span>
|
|
151
161
|
</div>
|
|
152
162
|
</TooltipComponent>
|
|
153
163
|
</div>
|
|
154
|
-
) : null
|
|
164
|
+
) : null,
|
|
155
165
|
)}
|
|
156
166
|
</div>
|
|
157
167
|
</div>
|
|
@@ -160,10 +170,15 @@ const VerticalMenuDropdown: React.FC<Props> = ({
|
|
|
160
170
|
return (
|
|
161
171
|
<>
|
|
162
172
|
<div className="inline-block vertical-menu-dropdown-wrapper">
|
|
163
|
-
{
|
|
173
|
+
{visibleCount > 0 && (
|
|
164
174
|
<button
|
|
175
|
+
type="button"
|
|
165
176
|
className="vertical-menu-trigger-button p-2 rounded text-base-gray hover:bg-gray-light-1 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
|
|
166
|
-
onClick={
|
|
177
|
+
onClick={event => {
|
|
178
|
+
event.stopPropagation();
|
|
179
|
+
if (!openMenu) updateMenuPosition();
|
|
180
|
+
setOpenMenu(prev => !prev);
|
|
181
|
+
}}
|
|
167
182
|
ref={menuButtonRef}
|
|
168
183
|
>
|
|
169
184
|
<ThreeDotIcon />
|
|
@@ -18,7 +18,7 @@ const NoData: React.FC<props> = ({ title, subtitle }) => {
|
|
|
18
18
|
}}
|
|
19
19
|
>
|
|
20
20
|
<div style={{ width: 145, marginBottom: 20 }} className="nodata-img">
|
|
21
|
-
|
|
21
|
+
<svg
|
|
22
22
|
xmlns="http://www.w3.org/2000/svg"
|
|
23
23
|
width="148"
|
|
24
24
|
height="132"
|
|
@@ -71,7 +71,7 @@ const NoData: React.FC<props> = ({ title, subtitle }) => {
|
|
|
71
71
|
fill="#797979"
|
|
72
72
|
d="M47.365 57.417a.926.926 0 00.926-.927v-1.777a.926.926 0 10-1.852 0v1.777c0 .512.415.927.926.927zM104.183 57.417a.926.926 0 00.926-.927v-1.777a.926.926 0 00-1.852 0v1.777c0 .512.414.927.926.927zM47.365 52.974a.926.926 0 00.926-.927V50.27a.926.926 0 00-1.852 0v1.777c0 .512.415.927.926.927zM104.183 52.974a.926.926 0 00.926-.927V50.27a.926.926 0 00-1.852 0v1.777c0 .512.414.927.926.927zM47.365 44.088a.926.926 0 00.926-.927v-1.777a.926.926 0 10-1.852 0v1.777c0 .512.415.927.926.927zM104.183 44.088a.926.926 0 00.926-.927v-1.777a.926.926 0 00-1.852 0v1.777c0 .512.414.927.926.927zM47.365 39.645a.926.926 0 00.926-.927v-1.777a.926.926 0 10-1.852 0v1.777c0 .512.415.927.926.927zM104.183 39.645a.926.926 0 00.926-.927v-1.777a.926.926 0 00-1.852 0v1.777c0 .512.414.927.926.927zM47.365 35.202a.926.926 0 00.926-.927v-1.777a.926.926 0 10-1.852 0v1.777c0 .512.415.927.926.927zM104.183 35.202a.926.926 0 00.926-.927v-1.777a.926.926 0 00-1.852 0v1.777c0 .512.414.927.926.927zM47.365 30.758a.926.926 0 00.926-.926v-.888c0-.248.02-.49.057-.726a.926.926 0 00-1.83-.288c-.052.33-.08.67-.08 1.014v.888c0 .512.416.926.927.926zM104.183 30.758a.926.926 0 00.926-.926v-.888c0-.345-.027-.683-.079-1.014a.926.926 0 10-1.83.288c.037.236.057.478.057.726v.888c0 .512.414.926.926.926zM47.881 26.426a.926.926 0 001.294-.204c.286-.394.633-.74 1.026-1.026a.926.926 0 00-1.09-1.498c-.55.4-1.034.884-1.434 1.434a.926.926 0 00.204 1.294zM103.667 26.426a.926.926 0 00.204-1.294 6.509 6.509 0 00-1.434-1.434.926.926 0 00-1.09 1.498c.393.286.74.632 1.026 1.026a.926.926 0 001.294.204zM51.138 23.597c.08.506.554.851 1.059.772a4.67 4.67 0 01.726-.057h.914a.926.926 0 000-1.852h-.914c-.344 0-.683.026-1.014.078a.926.926 0 00-.77 1.06zM100.41 23.597a.927.927 0 00-.771-1.059 6.522 6.522 0 00-1.014-.078h-.914a.926.926 0 100 1.852h.914c.248 0 .49.02.726.057a.926.926 0 001.059-.772zM55.653 23.386c0 .511.415.926.926.926h1.828a.926.926 0 000-1.852H56.58a.926.926 0 00-.926.926zM60.223 23.386c0 .511.415.926.926.926h1.828a.926.926 0 000-1.852H61.15a.926.926 0 00-.926.926zM64.793 23.386c0 .511.415.926.926.926h1.829a.926.926 0 000-1.852h-1.829a.926.926 0 00-.926.926zM69.364 23.386c0 .511.414.926.926.926h1.828a.926.926 0 000-1.852H70.29a.926.926 0 00-.927.926zM73.934 23.386c0 .511.414.926.926.926h1.828a.926.926 0 000-1.852H74.86a.926.926 0 00-.926.926zM78.504 23.386c0 .511.415.926.926.926h1.828a.926.926 0 000-1.852H79.43a.926.926 0 00-.926.926zM83.074 23.386c0 .511.415.926.927.926h1.828a.926.926 0 000-1.852H84a.926.926 0 00-.927.926zM87.644 23.386c0 .511.415.926.927.926h1.828a.926.926 0 000-1.852H88.57a.926.926 0 00-.927.926zM92.215 23.386c0 .511.414.926.926.926h1.828a.926.926 0 000-1.852h-1.828a.926.926 0 00-.926.926zM72.178 36.453a1.39 1.39 0 10-1.965 1.965l3.797 3.797-3.797 3.798a1.39 1.39 0 001.965 1.965l3.797-3.798 3.798 3.798a1.39 1.39 0 001.965-1.965l-3.798-3.798 3.798-3.797a1.39 1.39 0 10-1.965-1.965l-3.798 3.797-3.797-3.797z"
|
|
73
73
|
></path>
|
|
74
|
-
</svg>{' '}
|
|
74
|
+
</svg> {' '}
|
|
75
75
|
</div>
|
|
76
76
|
<p className="text-center text-common font-bold text-blackAlt nodata-title">{title}</p>
|
|
77
77
|
<span className="text-xxs font-medium text-grey-medium nodata-sub-title">{subtitle}</span>
|