@visns-studio/visns-components 5.9.1 → 5.9.3
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/package.json
CHANGED
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
87
87
|
},
|
|
88
88
|
"name": "@visns-studio/visns-components",
|
|
89
|
-
"version": "5.9.
|
|
89
|
+
"version": "5.9.3",
|
|
90
90
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
91
91
|
"main": "src/index.js",
|
|
92
92
|
"files": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '../styles/global.css';
|
|
2
2
|
|
|
3
|
-
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
4
4
|
import { useNavigate } from 'react-router-dom';
|
|
5
5
|
import { motion } from 'framer-motion';
|
|
6
6
|
import { toast } from 'react-toastify';
|
|
@@ -86,8 +86,15 @@ function Form({
|
|
|
86
86
|
const [formData, setFormData] = useState({});
|
|
87
87
|
const [inputClass, setInputClass] = useState({});
|
|
88
88
|
const [tableData, setTableData] = useState({ columns: [], dataSource: [] });
|
|
89
|
+
const [tableProps, setTableProps] = useState({});
|
|
89
90
|
const [uploadProgress, setUploadProgress] = useState(0);
|
|
90
91
|
|
|
92
|
+
// Group selection state management
|
|
93
|
+
const [selected, setSelected] = useState({});
|
|
94
|
+
const [collapsedGroups, setCollapsedGroups] = useState({});
|
|
95
|
+
const dataRef = useRef([]);
|
|
96
|
+
const groupClickTimeoutRef = useRef(null);
|
|
97
|
+
|
|
91
98
|
const childDropdownCallback = (data) => {
|
|
92
99
|
let _form = { ...formSettings };
|
|
93
100
|
|
|
@@ -539,6 +546,163 @@ function Form({
|
|
|
539
546
|
.join(' ');
|
|
540
547
|
};
|
|
541
548
|
|
|
549
|
+
// Group selection functions
|
|
550
|
+
const handleGroupSelectionChange = useCallback(
|
|
551
|
+
(groupValue, isChecked) => {
|
|
552
|
+
if (!dataRef.current || !tableProps?.groupBy) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const groupField = tableProps.groupBy[0];
|
|
557
|
+
const groupRows = dataRef.current.filter(
|
|
558
|
+
(row) => row[groupField] === groupValue
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
// Clean the selected state - remove any invalid entries
|
|
562
|
+
const cleanSelected = {};
|
|
563
|
+
Object.keys(selected).forEach((key) => {
|
|
564
|
+
const item = selected[key];
|
|
565
|
+
// Only keep items that have valid IDs and are not group objects
|
|
566
|
+
if (
|
|
567
|
+
key !== 'undefined' &&
|
|
568
|
+
key !== 'null' &&
|
|
569
|
+
item &&
|
|
570
|
+
!item.__group &&
|
|
571
|
+
item.id !== undefined
|
|
572
|
+
) {
|
|
573
|
+
cleanSelected[key] = item;
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
const newSelected = { ...cleanSelected };
|
|
577
|
+
|
|
578
|
+
if (isChecked) {
|
|
579
|
+
// Select all rows in the group
|
|
580
|
+
groupRows.forEach((row) => {
|
|
581
|
+
if (row && row.id !== undefined && row.id !== null) {
|
|
582
|
+
newSelected[row.id] = row;
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
} else {
|
|
586
|
+
// Deselect all rows in the group
|
|
587
|
+
groupRows.forEach((row) => {
|
|
588
|
+
if (row && row.id !== undefined && row.id !== null) {
|
|
589
|
+
delete newSelected[row.id];
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Update the selection state
|
|
595
|
+
setSelected(newSelected);
|
|
596
|
+
},
|
|
597
|
+
[selected, tableProps?.groupBy]
|
|
598
|
+
);
|
|
599
|
+
|
|
600
|
+
const isGroupSelected = useCallback(
|
|
601
|
+
(groupValue) => {
|
|
602
|
+
if (!dataRef.current || !tableProps?.groupBy) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Clean the selected state first
|
|
607
|
+
const cleanSelected = {};
|
|
608
|
+
Object.keys(selected).forEach((key) => {
|
|
609
|
+
const item = selected[key];
|
|
610
|
+
if (
|
|
611
|
+
key !== 'undefined' &&
|
|
612
|
+
key !== 'null' &&
|
|
613
|
+
item &&
|
|
614
|
+
!item.__group &&
|
|
615
|
+
item.id !== undefined
|
|
616
|
+
) {
|
|
617
|
+
cleanSelected[key] = item;
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
const groupField = tableProps.groupBy[0];
|
|
622
|
+
const groupRows = dataRef.current.filter(
|
|
623
|
+
(row) => row[groupField] === groupValue
|
|
624
|
+
);
|
|
625
|
+
|
|
626
|
+
if (groupRows.length === 0) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Filter out rows with invalid IDs and check if all valid rows are selected
|
|
631
|
+
const validRows = groupRows.filter(
|
|
632
|
+
(row) => row && row.id !== undefined && row.id !== null
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
if (validRows.length === 0) {
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return validRows.every((row) => cleanSelected[row.id]);
|
|
640
|
+
},
|
|
641
|
+
[selected, tableProps?.groupBy]
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
// Handle selection changes from ReactDataGrid
|
|
645
|
+
const handleSelectionChange = useCallback(
|
|
646
|
+
(param) => {
|
|
647
|
+
// Handle the selection change based on the parameter type
|
|
648
|
+
if (param.selected === true) {
|
|
649
|
+
// Select all rows - this happens when header checkbox is clicked to select all
|
|
650
|
+
const s = {};
|
|
651
|
+
|
|
652
|
+
// Always prefer dataRef.current as it contains the most reliable data
|
|
653
|
+
// especially when grouping is active
|
|
654
|
+
if (dataRef.current && Array.isArray(dataRef.current)) {
|
|
655
|
+
dataRef.current.forEach((obj) => {
|
|
656
|
+
if (
|
|
657
|
+
obj &&
|
|
658
|
+
obj.id !== undefined &&
|
|
659
|
+
obj.id !== null
|
|
660
|
+
) {
|
|
661
|
+
s[obj.id] = obj;
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
} else if (param.data && Array.isArray(param.data)) {
|
|
665
|
+
// Fallback to param.data if dataRef.current is not available
|
|
666
|
+
param.data.forEach((obj) => {
|
|
667
|
+
if (
|
|
668
|
+
obj &&
|
|
669
|
+
obj.id !== undefined &&
|
|
670
|
+
obj.id !== null
|
|
671
|
+
) {
|
|
672
|
+
s[obj.id] = obj;
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
setSelected(s);
|
|
678
|
+
} else if (param.selected === false) {
|
|
679
|
+
// Deselect all rows
|
|
680
|
+
setSelected({});
|
|
681
|
+
} else if (typeof param.selected === 'object') {
|
|
682
|
+
// Individual row selection/deselection - ReactDataGrid sends the complete new selection state
|
|
683
|
+
// ReactDataGrid sends the complete new selection state, not just the changed row
|
|
684
|
+
// Clean the selection to remove any group objects or invalid entries
|
|
685
|
+
const cleanSelection = {};
|
|
686
|
+
Object.keys(param.selected).forEach((key) => {
|
|
687
|
+
const item = param.selected[key];
|
|
688
|
+
// Only keep items that have valid IDs and are not group objects
|
|
689
|
+
if (
|
|
690
|
+
key !== 'undefined' &&
|
|
691
|
+
key !== 'null' &&
|
|
692
|
+
item &&
|
|
693
|
+
!item.__group &&
|
|
694
|
+
item.id !== undefined
|
|
695
|
+
) {
|
|
696
|
+
cleanSelection[key] = item;
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
setSelected(cleanSelection);
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
[selected]
|
|
704
|
+
);
|
|
705
|
+
|
|
542
706
|
const handleDownload = async (e) => {
|
|
543
707
|
try {
|
|
544
708
|
if (e) {
|
|
@@ -987,6 +1151,10 @@ function Form({
|
|
|
987
1151
|
formSettings?.save?.return?.type === 'table' &&
|
|
988
1152
|
formSettings?.save?.return?.param
|
|
989
1153
|
) {
|
|
1154
|
+
if ( formSettings.save.return.props ) {
|
|
1155
|
+
setTableProps(formSettings.save.return.props);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
990
1158
|
if (
|
|
991
1159
|
res.data[formSettings.save.return.param]
|
|
992
1160
|
?.length > 0
|
|
@@ -1366,6 +1534,13 @@ function Form({
|
|
|
1366
1534
|
fetchData();
|
|
1367
1535
|
}, []);
|
|
1368
1536
|
|
|
1537
|
+
// Update dataRef when tableData changes
|
|
1538
|
+
useEffect(() => {
|
|
1539
|
+
if (tableData.dataSource && Array.isArray(tableData.dataSource)) {
|
|
1540
|
+
dataRef.current = tableData.dataSource;
|
|
1541
|
+
}
|
|
1542
|
+
}, [tableData.dataSource]);
|
|
1543
|
+
|
|
1369
1544
|
useEffect(() => {
|
|
1370
1545
|
formSettings.fields.forEach((field) => {
|
|
1371
1546
|
const showConditions = field.show || [];
|
|
@@ -1541,6 +1716,395 @@ function Form({
|
|
|
1541
1716
|
dataSource={tableData.dataSource}
|
|
1542
1717
|
style={{ minHeight: 550 }}
|
|
1543
1718
|
showActiveRowIndicator={false}
|
|
1719
|
+
selected={selected}
|
|
1720
|
+
onSelectionChange={handleSelectionChange}
|
|
1721
|
+
{...(tableProps && tableProps.groupBy
|
|
1722
|
+
? {
|
|
1723
|
+
defaultGroupBy: tableProps.groupBy,
|
|
1724
|
+
defaultCollapsed: true,
|
|
1725
|
+
collapsedGroups: collapsedGroups,
|
|
1726
|
+
onGroupToggle: (groupData) => {
|
|
1727
|
+
// Handle group expand/collapse events
|
|
1728
|
+
// Update collapsed groups state
|
|
1729
|
+
const groupValue =
|
|
1730
|
+
typeof groupData === 'string'
|
|
1731
|
+
? groupData
|
|
1732
|
+
: groupData?.value ||
|
|
1733
|
+
groupData?.name ||
|
|
1734
|
+
'';
|
|
1735
|
+
|
|
1736
|
+
setCollapsedGroups((prev) => {
|
|
1737
|
+
const newState = { ...prev };
|
|
1738
|
+
if (newState[groupValue]) {
|
|
1739
|
+
delete newState[groupValue];
|
|
1740
|
+
} else {
|
|
1741
|
+
newState[groupValue] = true;
|
|
1742
|
+
}
|
|
1743
|
+
console.log(
|
|
1744
|
+
'Updated collapsed groups:',
|
|
1745
|
+
newState
|
|
1746
|
+
);
|
|
1747
|
+
return newState;
|
|
1748
|
+
});
|
|
1749
|
+
},
|
|
1750
|
+
renderGroupTitle: (groupData) => {
|
|
1751
|
+
const groupValue =
|
|
1752
|
+
typeof groupData === 'string'
|
|
1753
|
+
? groupData
|
|
1754
|
+
: groupData?.value ||
|
|
1755
|
+
groupData?.name ||
|
|
1756
|
+
'';
|
|
1757
|
+
|
|
1758
|
+
// Use ReactDataGrid's built-in toggle functionality
|
|
1759
|
+
const collapsed =
|
|
1760
|
+
collapsedGroups[groupValue] ||
|
|
1761
|
+
false;
|
|
1762
|
+
const toggleGroup = () => {
|
|
1763
|
+
// Update the collapsed state
|
|
1764
|
+
setCollapsedGroups((prev) => {
|
|
1765
|
+
const newState = { ...prev };
|
|
1766
|
+
if (newState[groupValue]) {
|
|
1767
|
+
delete newState[
|
|
1768
|
+
groupValue
|
|
1769
|
+
];
|
|
1770
|
+
} else {
|
|
1771
|
+
newState[
|
|
1772
|
+
groupValue
|
|
1773
|
+
] = true;
|
|
1774
|
+
}
|
|
1775
|
+
return newState;
|
|
1776
|
+
});
|
|
1777
|
+
};
|
|
1778
|
+
const groupCount =
|
|
1779
|
+
typeof groupData === 'object'
|
|
1780
|
+
? groupData?.count || 0
|
|
1781
|
+
: 0;
|
|
1782
|
+
const hasCheckboxColumn =
|
|
1783
|
+
tableData.columns.some(
|
|
1784
|
+
(col) =>
|
|
1785
|
+
col.id ===
|
|
1786
|
+
'__checkbox-column'
|
|
1787
|
+
);
|
|
1788
|
+
|
|
1789
|
+
// Handle group header click for selection
|
|
1790
|
+
const handleGroupHeaderClick = (
|
|
1791
|
+
e
|
|
1792
|
+
) => {
|
|
1793
|
+
// Prevent rapid clicks
|
|
1794
|
+
if (
|
|
1795
|
+
groupClickTimeoutRef.current
|
|
1796
|
+
) {
|
|
1797
|
+
console.log(
|
|
1798
|
+
'🖱️ Ignoring rapid click'
|
|
1799
|
+
);
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
// Don't trigger if clicking on the expand button or checkbox
|
|
1804
|
+
if (
|
|
1805
|
+
e.target.closest(
|
|
1806
|
+
'.group-expand-btn'
|
|
1807
|
+
) ||
|
|
1808
|
+
e.target.closest(
|
|
1809
|
+
'input[type="checkbox"]'
|
|
1810
|
+
)
|
|
1811
|
+
) {
|
|
1812
|
+
console.log(
|
|
1813
|
+
'🖱️ Ignoring click on expand button or checkbox'
|
|
1814
|
+
);
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// Set timeout to prevent rapid clicks
|
|
1819
|
+
groupClickTimeoutRef.current =
|
|
1820
|
+
setTimeout(() => {
|
|
1821
|
+
groupClickTimeoutRef.current =
|
|
1822
|
+
null;
|
|
1823
|
+
}, 300);
|
|
1824
|
+
|
|
1825
|
+
// Toggle selection of all items in this group
|
|
1826
|
+
const isCurrentlySelected =
|
|
1827
|
+
isGroupSelected(groupValue);
|
|
1828
|
+
|
|
1829
|
+
handleGroupSelectionChange(
|
|
1830
|
+
groupValue,
|
|
1831
|
+
!isCurrentlySelected
|
|
1832
|
+
);
|
|
1833
|
+
};
|
|
1834
|
+
|
|
1835
|
+
return (
|
|
1836
|
+
<div
|
|
1837
|
+
className="group-header-clean group-header-fixed-height"
|
|
1838
|
+
onClick={
|
|
1839
|
+
handleGroupHeaderClick
|
|
1840
|
+
}
|
|
1841
|
+
style={{
|
|
1842
|
+
display: 'flex',
|
|
1843
|
+
alignItems: 'center',
|
|
1844
|
+
justifyContent:
|
|
1845
|
+
'space-between',
|
|
1846
|
+
width: '100%',
|
|
1847
|
+
height: '34px', // Compact height
|
|
1848
|
+
padding: '6px 12px', // Reduced padding for compact design
|
|
1849
|
+
background:
|
|
1850
|
+
'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)',
|
|
1851
|
+
borderLeft:
|
|
1852
|
+
'4px solid var(--primary-color, #3b82f6)',
|
|
1853
|
+
position: 'relative',
|
|
1854
|
+
overflow: 'hidden',
|
|
1855
|
+
boxShadow:
|
|
1856
|
+
'0 1px 3px rgba(0,0,0,0.1)',
|
|
1857
|
+
borderRadius:
|
|
1858
|
+
'0 4px 4px 0',
|
|
1859
|
+
cursor: 'pointer',
|
|
1860
|
+
boxSizing: 'border-box',
|
|
1861
|
+
lineHeight: '1.1', // Compact line height
|
|
1862
|
+
flexShrink: 0,
|
|
1863
|
+
transition:
|
|
1864
|
+
'background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease',
|
|
1865
|
+
}}
|
|
1866
|
+
onMouseEnter={(e) => {
|
|
1867
|
+
e.currentTarget.style.background =
|
|
1868
|
+
'linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%)';
|
|
1869
|
+
e.currentTarget.style.boxShadow =
|
|
1870
|
+
'0 2px 8px rgba(0,0,0,0.15)';
|
|
1871
|
+
e.currentTarget.style.transform =
|
|
1872
|
+
'translateY(-1px)';
|
|
1873
|
+
}}
|
|
1874
|
+
onMouseLeave={(e) => {
|
|
1875
|
+
e.currentTarget.style.background =
|
|
1876
|
+
'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)';
|
|
1877
|
+
e.currentTarget.style.boxShadow =
|
|
1878
|
+
'0 1px 3px rgba(0,0,0,0.1)';
|
|
1879
|
+
e.currentTarget.style.transform =
|
|
1880
|
+
'translateY(0)';
|
|
1881
|
+
}}
|
|
1882
|
+
>
|
|
1883
|
+
{/* Left side - Group info and expand/collapse */}
|
|
1884
|
+
<div
|
|
1885
|
+
style={{
|
|
1886
|
+
display: 'flex',
|
|
1887
|
+
alignItems: 'center',
|
|
1888
|
+
flex: 1,
|
|
1889
|
+
zIndex: 2,
|
|
1890
|
+
position: 'relative',
|
|
1891
|
+
}}
|
|
1892
|
+
>
|
|
1893
|
+
<button
|
|
1894
|
+
className="group-expand-btn"
|
|
1895
|
+
onClick={(e) => {
|
|
1896
|
+
e.preventDefault();
|
|
1897
|
+
e.stopPropagation();
|
|
1898
|
+
if (
|
|
1899
|
+
typeof toggleGroup ===
|
|
1900
|
+
'function'
|
|
1901
|
+
) {
|
|
1902
|
+
toggleGroup();
|
|
1903
|
+
} else {
|
|
1904
|
+
console.warn(
|
|
1905
|
+
'toggleGroup is not a function:',
|
|
1906
|
+
toggleGroup
|
|
1907
|
+
);
|
|
1908
|
+
}
|
|
1909
|
+
}}
|
|
1910
|
+
style={{
|
|
1911
|
+
background:
|
|
1912
|
+
'var(--primary-color, #3b82f6)',
|
|
1913
|
+
border: 'none',
|
|
1914
|
+
borderRadius:
|
|
1915
|
+
'3px',
|
|
1916
|
+
color: 'white',
|
|
1917
|
+
width: '20px', // More compact
|
|
1918
|
+
height: '20px', // More compact
|
|
1919
|
+
display: 'flex',
|
|
1920
|
+
alignItems:
|
|
1921
|
+
'center',
|
|
1922
|
+
justifyContent:
|
|
1923
|
+
'center',
|
|
1924
|
+
marginRight:
|
|
1925
|
+
'8px', // Reduced margin
|
|
1926
|
+
cursor: 'pointer',
|
|
1927
|
+
fontSize: '11px', // Smaller font
|
|
1928
|
+
fontWeight:
|
|
1929
|
+
'bold',
|
|
1930
|
+
boxShadow:
|
|
1931
|
+
'0 1px 2px rgba(0,0,0,0.1)',
|
|
1932
|
+
transition:
|
|
1933
|
+
'all 0.15s ease',
|
|
1934
|
+
}}
|
|
1935
|
+
onMouseEnter={(e) => {
|
|
1936
|
+
e.target.style.transform =
|
|
1937
|
+
'scale(1.05)';
|
|
1938
|
+
e.target.style.background =
|
|
1939
|
+
'var(--secondary-color, #2563eb)';
|
|
1940
|
+
}}
|
|
1941
|
+
onMouseLeave={(e) => {
|
|
1942
|
+
e.target.style.transform =
|
|
1943
|
+
'scale(1)';
|
|
1944
|
+
e.target.style.background =
|
|
1945
|
+
'var(--primary-color, #3b82f6)';
|
|
1946
|
+
}}
|
|
1947
|
+
>
|
|
1948
|
+
{collapsed
|
|
1949
|
+
? '+'
|
|
1950
|
+
: '−'}
|
|
1951
|
+
</button>
|
|
1952
|
+
<div
|
|
1953
|
+
style={{
|
|
1954
|
+
display: 'flex',
|
|
1955
|
+
alignItems:
|
|
1956
|
+
'center', // Changed to center for compact layout
|
|
1957
|
+
gap: '8px', // Add gap between elements
|
|
1958
|
+
}}
|
|
1959
|
+
>
|
|
1960
|
+
<strong
|
|
1961
|
+
style={{
|
|
1962
|
+
fontSize:
|
|
1963
|
+
'0.85rem', // Slightly smaller for compact design
|
|
1964
|
+
color: 'var(--secondary-color, #1f2937)',
|
|
1965
|
+
fontWeight:
|
|
1966
|
+
'600',
|
|
1967
|
+
textTransform:
|
|
1968
|
+
'uppercase',
|
|
1969
|
+
letterSpacing:
|
|
1970
|
+
'0.025em',
|
|
1971
|
+
}}
|
|
1972
|
+
>
|
|
1973
|
+
{groupValue}
|
|
1974
|
+
</strong>
|
|
1975
|
+
{groupCount > 0 && (
|
|
1976
|
+
<span
|
|
1977
|
+
style={{
|
|
1978
|
+
color: '#6b7280',
|
|
1979
|
+
fontSize:
|
|
1980
|
+
'0.75rem', // Smaller for compact design
|
|
1981
|
+
fontWeight:
|
|
1982
|
+
'500',
|
|
1983
|
+
}}
|
|
1984
|
+
>
|
|
1985
|
+
({groupCount}{' '}
|
|
1986
|
+
{groupCount ===
|
|
1987
|
+
1
|
|
1988
|
+
? 'item'
|
|
1989
|
+
: 'items'}
|
|
1990
|
+
)
|
|
1991
|
+
</span>
|
|
1992
|
+
)}
|
|
1993
|
+
{/* Click indicator */}
|
|
1994
|
+
<span
|
|
1995
|
+
style={{
|
|
1996
|
+
color: '#9ca3af',
|
|
1997
|
+
fontSize:
|
|
1998
|
+
'0.7rem',
|
|
1999
|
+
fontStyle:
|
|
2000
|
+
'italic',
|
|
2001
|
+
opacity: 0.8,
|
|
2002
|
+
marginLeft:
|
|
2003
|
+
'auto',
|
|
2004
|
+
userSelect:
|
|
2005
|
+
'none',
|
|
2006
|
+
}}
|
|
2007
|
+
>
|
|
2008
|
+
Click to
|
|
2009
|
+
select/unselect
|
|
2010
|
+
all
|
|
2011
|
+
</span>
|
|
2012
|
+
</div>
|
|
2013
|
+
</div>
|
|
2014
|
+
|
|
2015
|
+
{/* Right side - Group selection */}
|
|
2016
|
+
{hasCheckboxColumn && (
|
|
2017
|
+
<div
|
|
2018
|
+
style={{
|
|
2019
|
+
display: 'flex',
|
|
2020
|
+
alignItems:
|
|
2021
|
+
'center',
|
|
2022
|
+
gap: '4px', // Reduced gap for compact design
|
|
2023
|
+
fontSize:
|
|
2024
|
+
'0.75rem', // Smaller font for compact design
|
|
2025
|
+
background:
|
|
2026
|
+
'rgba(255, 255, 255, 0.9)',
|
|
2027
|
+
padding:
|
|
2028
|
+
'3px 8px', // Reduced padding for compact design
|
|
2029
|
+
borderRadius:
|
|
2030
|
+
'12px', // Smaller border radius
|
|
2031
|
+
border: '1px solid rgba(59, 130, 246, 0.3)',
|
|
2032
|
+
zIndex: 2,
|
|
2033
|
+
position:
|
|
2034
|
+
'relative',
|
|
2035
|
+
boxShadow:
|
|
2036
|
+
'0 1px 2px rgba(0,0,0,0.05)',
|
|
2037
|
+
}}
|
|
2038
|
+
>
|
|
2039
|
+
<input
|
|
2040
|
+
type="checkbox"
|
|
2041
|
+
onChange={(e) => {
|
|
2042
|
+
e.stopPropagation();
|
|
2043
|
+
handleGroupSelectionChange(
|
|
2044
|
+
groupValue,
|
|
2045
|
+
e.target
|
|
2046
|
+
.checked
|
|
2047
|
+
);
|
|
2048
|
+
}}
|
|
2049
|
+
checked={isGroupSelected(
|
|
2050
|
+
groupValue
|
|
2051
|
+
)}
|
|
2052
|
+
style={{
|
|
2053
|
+
width: '14px', // Smaller checkbox for compact design
|
|
2054
|
+
height: '14px',
|
|
2055
|
+
cursor: 'pointer',
|
|
2056
|
+
accentColor:
|
|
2057
|
+
'var(--primary-color, #3b82f6)',
|
|
2058
|
+
}}
|
|
2059
|
+
/>
|
|
2060
|
+
<span
|
|
2061
|
+
style={{
|
|
2062
|
+
cursor: 'pointer',
|
|
2063
|
+
userSelect:
|
|
2064
|
+
'none',
|
|
2065
|
+
color: 'var(--secondary-color, #1f2937)',
|
|
2066
|
+
fontWeight:
|
|
2067
|
+
'500',
|
|
2068
|
+
fontSize:
|
|
2069
|
+
'0.7rem', // Smaller font for compact design
|
|
2070
|
+
}}
|
|
2071
|
+
onClick={(e) => {
|
|
2072
|
+
e.stopPropagation();
|
|
2073
|
+
const checkbox =
|
|
2074
|
+
e.target
|
|
2075
|
+
.previousElementSibling;
|
|
2076
|
+
checkbox.checked =
|
|
2077
|
+
!checkbox.checked;
|
|
2078
|
+
handleGroupSelectionChange(
|
|
2079
|
+
groupValue,
|
|
2080
|
+
checkbox.checked
|
|
2081
|
+
);
|
|
2082
|
+
}}
|
|
2083
|
+
>
|
|
2084
|
+
Select All
|
|
2085
|
+
</span>
|
|
2086
|
+
</div>
|
|
2087
|
+
)}
|
|
2088
|
+
|
|
2089
|
+
{/* Background pattern */}
|
|
2090
|
+
<div
|
|
2091
|
+
style={{
|
|
2092
|
+
position: 'absolute',
|
|
2093
|
+
top: 0,
|
|
2094
|
+
left: 0,
|
|
2095
|
+
right: 0,
|
|
2096
|
+
bottom: 0,
|
|
2097
|
+
background:
|
|
2098
|
+
'repeating-linear-gradient(45deg, transparent, transparent 2px, rgba(59, 130, 246, 0.03) 2px, rgba(59, 130, 246, 0.03) 4px)',
|
|
2099
|
+
zIndex: 1,
|
|
2100
|
+
pointerEvents: 'none',
|
|
2101
|
+
}}
|
|
2102
|
+
/>
|
|
2103
|
+
</div>
|
|
2104
|
+
);
|
|
2105
|
+
},
|
|
2106
|
+
}
|
|
2107
|
+
: {})}
|
|
1544
2108
|
/>
|
|
1545
2109
|
</div>
|
|
1546
2110
|
)}
|