funda-ui 4.7.711 → 4.7.730
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/DragDropList/index.d.ts +1 -0
- package/DragDropList/index.js +143 -52
- package/DynamicFields/index.d.ts +1 -0
- package/DynamicFields/index.js +108 -8
- package/EventCalendarTimeline/index.css +12 -1
- package/EventCalendarTimeline/index.d.ts +1 -0
- package/EventCalendarTimeline/index.js +99 -6
- package/MultipleSelect/index.js +162 -71
- package/Table/index.css +5 -1
- package/Table/index.js +410 -90
- package/Utils/useBoundedDrag.d.ts +1 -0
- package/Utils/useBoundedDrag.js +124 -39
- package/lib/cjs/DragDropList/index.d.ts +1 -0
- package/lib/cjs/DragDropList/index.js +143 -52
- package/lib/cjs/DynamicFields/index.d.ts +1 -0
- package/lib/cjs/DynamicFields/index.js +108 -8
- package/lib/cjs/EventCalendarTimeline/index.d.ts +1 -0
- package/lib/cjs/EventCalendarTimeline/index.js +99 -6
- package/lib/cjs/MultipleSelect/index.js +162 -71
- package/lib/cjs/Table/index.js +410 -90
- package/lib/cjs/Utils/useBoundedDrag.d.ts +1 -0
- package/lib/cjs/Utils/useBoundedDrag.js +124 -39
- package/lib/css/EventCalendarTimeline/index.css +12 -1
- package/lib/css/Table/index.css +5 -1
- package/lib/esm/DragDropList/index.tsx +23 -16
- package/lib/esm/DynamicFields/index.tsx +107 -8
- package/lib/esm/EventCalendarTimeline/index.scss +15 -1
- package/lib/esm/EventCalendarTimeline/index.tsx +130 -11
- package/lib/esm/ModalDialog/index.tsx +0 -1
- package/lib/esm/Table/Table.tsx +9 -7
- package/lib/esm/Table/TableRow.tsx +9 -3
- package/lib/esm/Table/index.scss +8 -2
- package/lib/esm/Table/utils/DragHandleSprite.tsx +6 -2
- package/lib/esm/Table/utils/func.ts +12 -1
- package/lib/esm/Table/utils/hooks/useTableDraggable.tsx +401 -93
- package/lib/esm/Utils/hooks/useBoundedDrag.tsx +142 -39
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
|
14
14
|
import getOs from 'funda-utils//dist/cjs/os';
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
export interface EventsValueConfig {
|
|
18
19
|
id: string | number;
|
|
19
20
|
date: string,
|
|
@@ -79,7 +80,7 @@ export type EventCalendarTimelineProps = {
|
|
|
79
80
|
onChangeWeek?: (startDate: string, endDate: string) => void;
|
|
80
81
|
onListRenderComplete?: () => void;
|
|
81
82
|
onChangeAppearanceMode?: (mode: string) => void;
|
|
82
|
-
|
|
83
|
+
enableHeaderResize?: boolean;
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
// modal dialog
|
|
@@ -169,6 +170,7 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
169
170
|
onChangeWeek,
|
|
170
171
|
onListRenderComplete,
|
|
171
172
|
onChangeAppearanceMode,
|
|
173
|
+
enableHeaderResize,
|
|
172
174
|
|
|
173
175
|
//
|
|
174
176
|
modalMaskOpacity,
|
|
@@ -273,11 +275,17 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
273
275
|
const AUTO_SCROLL = autoScroll || false;
|
|
274
276
|
const HEADER_SHOW_WEEK = headerShowWeek || false;
|
|
275
277
|
const BODY_DRAG = draggable || false;
|
|
278
|
+
const ENABLE_HEADER_RESIZE = enableHeaderResize || false;
|
|
276
279
|
const tableGridRef = useRef<any>(null);
|
|
277
280
|
const tableGridHeaderRef = useRef<any>(null);
|
|
278
281
|
const scrollHeaderRef = useRef(null);
|
|
279
282
|
const scrollBodyRef = useRef(null);
|
|
280
283
|
const scrollListRef = useRef(null);
|
|
284
|
+
|
|
285
|
+
// header resize drag
|
|
286
|
+
const isResizingRef = useRef<boolean>(false);
|
|
287
|
+
const resizeStartXRef = useRef<number>(0);
|
|
288
|
+
const resizeStartWidthRef = useRef<number>(0);
|
|
281
289
|
|
|
282
290
|
// Temporary date
|
|
283
291
|
const [tempDate, setTempDate] = useState<string>('');
|
|
@@ -2121,7 +2129,6 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2121
2129
|
|
|
2122
2130
|
}
|
|
2123
2131
|
|
|
2124
|
-
|
|
2125
2132
|
function tableGridReset() {
|
|
2126
2133
|
if (tableGridRef.current === null) return;
|
|
2127
2134
|
|
|
@@ -2153,13 +2160,7 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2153
2160
|
|
|
2154
2161
|
}
|
|
2155
2162
|
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
// ================================================================
|
|
2160
|
-
//
|
|
2161
|
-
// ================================================================
|
|
2162
|
-
//if user change the selectedYear, then udate the years array that is displayed on year tab view
|
|
2163
|
+
// if user change the selectedYear, then udate the years array that is displayed on year tab view
|
|
2163
2164
|
useEffect(() => {
|
|
2164
2165
|
const years: number[] = [];
|
|
2165
2166
|
for (let y = selectedYear - 10; y < selectedYear + 10; y++) {
|
|
@@ -2230,6 +2231,102 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2230
2231
|
}
|
|
2231
2232
|
|
|
2232
2233
|
}, []);
|
|
2234
|
+
|
|
2235
|
+
|
|
2236
|
+
// ================================================================
|
|
2237
|
+
// Handle header resize drag
|
|
2238
|
+
// ================================================================
|
|
2239
|
+
const handleHeaderResizeMove = useCallback((e: MouseEvent | TouchEvent) => {
|
|
2240
|
+
if (!isResizingRef.current || !tableGridRef.current) return;
|
|
2241
|
+
|
|
2242
|
+
const tableGridEl: any = tableGridRef.current;
|
|
2243
|
+
// Find the header title element that should have the CSS variable
|
|
2244
|
+
const headerTitleEl = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle') as HTMLElement;
|
|
2245
|
+
if (!headerTitleEl) return;
|
|
2246
|
+
|
|
2247
|
+
// Get clientX from either MouseEvent or TouchEvent
|
|
2248
|
+
const clientX = 'touches' in e ? e.touches[0]?.clientX : e.clientX;
|
|
2249
|
+
if (clientX === undefined) return;
|
|
2250
|
+
|
|
2251
|
+
const deltaX = clientX - resizeStartXRef.current;
|
|
2252
|
+
const newWidth = Math.max(100, resizeStartWidthRef.current + deltaX); // Minimum width 100px
|
|
2253
|
+
|
|
2254
|
+
// Update CSS variable on the header title element
|
|
2255
|
+
headerTitleEl.style.setProperty('--custom-event-tl-table-header-w', `${newWidth}px`);
|
|
2256
|
+
}, []);
|
|
2257
|
+
|
|
2258
|
+
const handleHeaderResizeEnd = useCallback(() => {
|
|
2259
|
+
if (!isResizingRef.current) return;
|
|
2260
|
+
|
|
2261
|
+
isResizingRef.current = false;
|
|
2262
|
+
document.removeEventListener('mousemove', handleHeaderResizeMove);
|
|
2263
|
+
document.removeEventListener('mouseup', handleHeaderResizeEnd);
|
|
2264
|
+
document.removeEventListener('touchmove', handleHeaderResizeMove);
|
|
2265
|
+
document.removeEventListener('touchend', handleHeaderResizeEnd);
|
|
2266
|
+
|
|
2267
|
+
// Recalculate table grid after resize
|
|
2268
|
+
if (tableGridRef.current) {
|
|
2269
|
+
tableGridInit();
|
|
2270
|
+
}
|
|
2271
|
+
}, [handleHeaderResizeMove]);
|
|
2272
|
+
|
|
2273
|
+
const handleHeaderResizeStart = useCallback((e: React.MouseEvent) => {
|
|
2274
|
+
if (!ENABLE_HEADER_RESIZE || !tableGridRef.current) return;
|
|
2275
|
+
|
|
2276
|
+
e.preventDefault();
|
|
2277
|
+
e.stopPropagation();
|
|
2278
|
+
|
|
2279
|
+
isResizingRef.current = true;
|
|
2280
|
+
resizeStartXRef.current = e.clientX;
|
|
2281
|
+
|
|
2282
|
+
const tableGridEl: any = tableGridRef.current;
|
|
2283
|
+
const headerTitleEl = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle') as HTMLElement;
|
|
2284
|
+
if (headerTitleEl) {
|
|
2285
|
+
resizeStartWidthRef.current = headerTitleEl.clientWidth;
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
document.addEventListener('mousemove', handleHeaderResizeMove);
|
|
2289
|
+
document.addEventListener('mouseup', handleHeaderResizeEnd);
|
|
2290
|
+
}, [ENABLE_HEADER_RESIZE, handleHeaderResizeMove, handleHeaderResizeEnd]);
|
|
2291
|
+
|
|
2292
|
+
const handleHeaderResizeTouchStart = useCallback((e: React.TouchEvent) => {
|
|
2293
|
+
if (!ENABLE_HEADER_RESIZE || !tableGridRef.current) return;
|
|
2294
|
+
|
|
2295
|
+
e.preventDefault();
|
|
2296
|
+
e.stopPropagation();
|
|
2297
|
+
|
|
2298
|
+
isResizingRef.current = true;
|
|
2299
|
+
const touch = e.touches[0];
|
|
2300
|
+
if (touch) {
|
|
2301
|
+
resizeStartXRef.current = touch.clientX;
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
const tableGridEl: any = tableGridRef.current;
|
|
2305
|
+
const headerTitleEl = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle') as HTMLElement;
|
|
2306
|
+
if (headerTitleEl) {
|
|
2307
|
+
resizeStartWidthRef.current = headerTitleEl.clientWidth;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
document.addEventListener('touchmove', handleHeaderResizeMove, { passive: false });
|
|
2311
|
+
document.addEventListener('touchend', handleHeaderResizeEnd);
|
|
2312
|
+
}, [ENABLE_HEADER_RESIZE, handleHeaderResizeMove, handleHeaderResizeEnd]);
|
|
2313
|
+
|
|
2314
|
+
|
|
2315
|
+
|
|
2316
|
+
// Cleanup on unmount
|
|
2317
|
+
useEffect(() => {
|
|
2318
|
+
return () => {
|
|
2319
|
+
document.removeEventListener('mousemove', handleHeaderResizeMove);
|
|
2320
|
+
document.removeEventListener('mouseup', handleHeaderResizeEnd);
|
|
2321
|
+
document.removeEventListener('touchmove', handleHeaderResizeMove);
|
|
2322
|
+
document.removeEventListener('touchend', handleHeaderResizeEnd);
|
|
2323
|
+
};
|
|
2324
|
+
}, [handleHeaderResizeMove, handleHeaderResizeEnd]);
|
|
2325
|
+
|
|
2326
|
+
|
|
2327
|
+
|
|
2328
|
+
|
|
2329
|
+
|
|
2233
2330
|
return (
|
|
2234
2331
|
<>
|
|
2235
2332
|
|
|
@@ -2417,6 +2514,9 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2417
2514
|
<thead role="presentation">
|
|
2418
2515
|
<tr role="row">
|
|
2419
2516
|
<th role="columnheader">
|
|
2517
|
+
{/**
|
|
2518
|
+
* The width of the left column header is set using ".custom-event-tl-table__cell-cushion-headertitle".
|
|
2519
|
+
*/}
|
|
2420
2520
|
<div className="custom-event-tl-table__cell-cushion custom-event-tl-table__cell-cushion-headertitle">
|
|
2421
2521
|
{tableListSectionTitle || ''}
|
|
2422
2522
|
</div>
|
|
@@ -2431,7 +2531,18 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2431
2531
|
|
|
2432
2532
|
|
|
2433
2533
|
</th>
|
|
2434
|
-
<th
|
|
2534
|
+
<th
|
|
2535
|
+
role="presentation"
|
|
2536
|
+
className={combinedCls(
|
|
2537
|
+
'custom-event-tl-table__timeline-divider',
|
|
2538
|
+
ENABLE_HEADER_RESIZE ? 'custom-event-tl-table__timeline-divider--resizable' : ''
|
|
2539
|
+
)}
|
|
2540
|
+
onMouseDown={ENABLE_HEADER_RESIZE ? handleHeaderResizeStart : undefined}
|
|
2541
|
+
onTouchStart={ENABLE_HEADER_RESIZE ? handleHeaderResizeTouchStart : undefined}
|
|
2542
|
+
style={ENABLE_HEADER_RESIZE ? { cursor: 'col-resize', userSelect: 'none' } : undefined}
|
|
2543
|
+
>
|
|
2544
|
+
<div></div>
|
|
2545
|
+
</th>
|
|
2435
2546
|
<th role="presentation">
|
|
2436
2547
|
<div
|
|
2437
2548
|
ref={scrollHeaderRef}
|
|
@@ -2507,12 +2618,20 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2507
2618
|
|
|
2508
2619
|
|
|
2509
2620
|
</td>
|
|
2621
|
+
|
|
2622
|
+
{/**
|
|
2623
|
+
* The dividing line between the left title column and the right content
|
|
2624
|
+
*/}
|
|
2510
2625
|
<td
|
|
2511
2626
|
role="presentation"
|
|
2512
2627
|
className={combinedCls(
|
|
2513
2628
|
'custom-event-tl-table__timeline-divider',
|
|
2514
|
-
tableListDividerClassName
|
|
2629
|
+
tableListDividerClassName,
|
|
2630
|
+
ENABLE_HEADER_RESIZE ? 'custom-event-tl-table__timeline-divider--resizable' : ''
|
|
2515
2631
|
)}
|
|
2632
|
+
onMouseDown={ENABLE_HEADER_RESIZE ? handleHeaderResizeStart : undefined}
|
|
2633
|
+
onTouchStart={ENABLE_HEADER_RESIZE ? handleHeaderResizeTouchStart : undefined}
|
|
2634
|
+
style={ENABLE_HEADER_RESIZE ? { cursor: 'col-resize', userSelect: 'none' } : undefined}
|
|
2516
2635
|
>
|
|
2517
2636
|
<div></div>
|
|
2518
2637
|
</td>
|
package/lib/esm/Table/Table.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import useComId from 'funda-utils/dist/cjs/useComId';
|
|
|
5
5
|
import { clsWrite, combinedCls } from 'funda-utils/dist/cjs/cls';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
import { TableProvider } from './TableContext';
|
|
9
10
|
import useTableResponsive from './utils/hooks/useTableResponsive';
|
|
10
11
|
import useTableDraggable from './utils/hooks/useTableDraggable';
|
|
@@ -148,10 +149,10 @@ const Table = forwardRef<HTMLDivElement, TableProps>((
|
|
|
148
149
|
|
|
149
150
|
// initialize drag & drop data
|
|
150
151
|
const {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
isDragging,
|
|
153
|
+
dragHandlers,
|
|
154
|
+
handleTbodyEnter,
|
|
155
|
+
handleTbodyLeave
|
|
155
156
|
} = useTableDraggable({
|
|
156
157
|
enabled: rowDraggable && rootRef.current,
|
|
157
158
|
data: data,
|
|
@@ -268,9 +269,10 @@ const Table = forwardRef<HTMLDivElement, TableProps>((
|
|
|
268
269
|
|
|
269
270
|
// drag & drop
|
|
270
271
|
rowDraggable,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
isRowDragging: isDragging,
|
|
273
|
+
handleDragStart: dragHandlers.handleDragStart,
|
|
274
|
+
handleDragEnd: dragHandlers.handleDragEnd,
|
|
275
|
+
handledragOver: dragHandlers.handleDragOver,
|
|
274
276
|
handleTbodyEnter,
|
|
275
277
|
|
|
276
278
|
|
|
@@ -44,9 +44,15 @@ const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>((
|
|
|
44
44
|
// selection
|
|
45
45
|
// ================================================================
|
|
46
46
|
const _res = convertMapToArr(selectedItems);
|
|
47
|
+
// Performance optimization: stringify itemData only once instead of N times
|
|
48
|
+
const itemDataStr = itemData ? JSON.stringify(itemData) : '';
|
|
47
49
|
const filteredSelectedItems = _res.map((v: any) => Number(v)).map((rowNum: number) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
const originItem = originData?.[rowNum];
|
|
51
|
+
// Fast path: reference equality
|
|
52
|
+
if (itemData === originItem) return originItem;
|
|
53
|
+
// Fallback: JSON comparison (itemDataStr is cached)
|
|
54
|
+
if (itemDataStr && itemDataStr === JSON.stringify(originItem)) {
|
|
55
|
+
return originItem;
|
|
50
56
|
}
|
|
51
57
|
}).filter(Boolean);
|
|
52
58
|
const selectedClassName = activeClassName || 'active';
|
|
@@ -64,7 +70,7 @@ const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>((
|
|
|
64
70
|
onDragEnd={rowDraggable ? handleDragEnd : () => void(0)}
|
|
65
71
|
data-row-data={`${itemData && typeof itemData === 'object' ? JSON.stringify(itemData) : itemData}`}
|
|
66
72
|
|
|
67
|
-
className={`row-obj ${className || ''} ${active ? selectedClassName : ''} ${itemData && originData ? (filteredData.every((item: any) => filterFieldsData.some((s: string) => !item[s]?.toLowerCase().includes(itemData[s]?.toLowerCase())) ) ? 'd-none' : '') : ''} ${itemData && originData
|
|
73
|
+
className={`row-obj ${className || ''} ${active ? selectedClassName : ''} ${itemData && originData ? (filteredData.every((item: any) => filterFieldsData.some((s: string) => !item[s]?.toLowerCase().includes(itemData[s]?.toLowerCase())) ) ? 'd-none' : '') : ''} ${itemData && originData && filteredSelectedItems.length > 0 ? selectedClassName : ''}`}
|
|
68
74
|
>
|
|
69
75
|
{children}
|
|
70
76
|
</tr>
|
package/lib/esm/Table/index.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
1
3
|
/* ======================================================
|
|
2
4
|
<!-- Table (Synthetic) -->
|
|
3
5
|
/* ====================================================== */
|
|
@@ -7,7 +9,7 @@
|
|
|
7
9
|
--syntable-row-active-bg: #f0f8ff;
|
|
8
10
|
--syntable-scrollbar-color: rgba(0, 0, 0, 0.2);
|
|
9
11
|
--syntable-scrollbar-track: rgba(0, 0, 0, 0);
|
|
10
|
-
--syntable-scrollbar-h:
|
|
12
|
+
--syntable-scrollbar-h: 10px;
|
|
11
13
|
--syntable-scrollbar-w: 10px;
|
|
12
14
|
--syntable-padding-x: 1rem;
|
|
13
15
|
--syntable-padding-y: 0.5rem;
|
|
@@ -165,11 +167,13 @@
|
|
|
165
167
|
|
|
166
168
|
.row-obj-clonelast {
|
|
167
169
|
height: 0 !important;
|
|
168
|
-
|
|
170
|
+
border-color: transparent !important;
|
|
171
|
+
padding: 0 !important;
|
|
169
172
|
|
|
170
173
|
td {
|
|
171
174
|
border: none;
|
|
172
175
|
box-shadow: none;
|
|
176
|
+
padding: 0 !important;
|
|
173
177
|
}
|
|
174
178
|
}
|
|
175
179
|
|
|
@@ -190,11 +194,13 @@
|
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
/* placeholder */
|
|
197
|
+
.row-obj-lastplaceholder,
|
|
193
198
|
.row-placeholder {
|
|
194
199
|
border: 2px dotted #b5ba91;
|
|
195
200
|
background-color: #e4e9c3;
|
|
196
201
|
}
|
|
197
202
|
|
|
203
|
+
|
|
198
204
|
/* trigger */
|
|
199
205
|
.drag-trigger {
|
|
200
206
|
display: inline-block;
|
|
@@ -15,7 +15,8 @@ const DragHandleSprite = forwardRef((props: DragHandleSpriteProps, externalRef:
|
|
|
15
15
|
|
|
16
16
|
const {
|
|
17
17
|
rowDraggable,
|
|
18
|
-
handleTbodyEnter
|
|
18
|
+
handleTbodyEnter,
|
|
19
|
+
handleTbodyLeave
|
|
19
20
|
} = useContext(TableContext);
|
|
20
21
|
|
|
21
22
|
return (
|
|
@@ -23,7 +24,10 @@ const DragHandleSprite = forwardRef((props: DragHandleSpriteProps, externalRef:
|
|
|
23
24
|
{rowDraggable ? <span
|
|
24
25
|
ref={externalRef}
|
|
25
26
|
className={className || 'drag-trigger'}
|
|
26
|
-
|
|
27
|
+
// Only when mousedown happens on this handle will we allow row dragging.
|
|
28
|
+
onMouseDown={handleTbodyEnter}
|
|
29
|
+
onMouseUp={handleTbodyLeave}
|
|
30
|
+
onMouseLeave={handleTbodyLeave}
|
|
27
31
|
>
|
|
28
32
|
{icon || <svg width="1em" height="1em" viewBox="0 0 24 24" fill="none">
|
|
29
33
|
<g>
|
|
@@ -63,6 +63,14 @@ export function initOrderProps(rootElem: any) {
|
|
|
63
63
|
|
|
64
64
|
export function initRowColProps(rootElem: any) {
|
|
65
65
|
if (rootElem === null) return;
|
|
66
|
+
|
|
67
|
+
// !!! Important, performance optimization for large data renderings
|
|
68
|
+
// With this protection, it is only performed once
|
|
69
|
+
if (typeof rootElem.dataset.rowColPropsInit !== 'undefined') return;
|
|
70
|
+
rootElem.dataset.rowColPropsInit = '1';
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
//
|
|
66
74
|
const _allRows = allRows(rootElem);
|
|
67
75
|
const _allHeadRows = allHeadRows(rootElem);
|
|
68
76
|
|
|
@@ -167,7 +175,10 @@ export function cellMark(row: number | string | undefined, col: number | string
|
|
|
167
175
|
|
|
168
176
|
export function removeCellFocusClassName(root: any) {
|
|
169
177
|
if (root) {
|
|
170
|
-
|
|
178
|
+
// !!! Important, performance optimization for large data renderings
|
|
179
|
+
// Only query elements with cell-focus classes
|
|
180
|
+
const focusedCells = root.querySelectorAll('td.cell-focus, th.cell-focus');
|
|
181
|
+
focusedCells.forEach((el: HTMLElement) => {
|
|
171
182
|
el.classList.remove('cell-focus');
|
|
172
183
|
});
|
|
173
184
|
}
|