@bit.rhplus/ui.grid 0.0.94 → 0.0.95
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/ColumnBuilder.jsx
CHANGED
|
@@ -12,139 +12,6 @@ import { CircleHelp, Check, X } from 'lucide-react';
|
|
|
12
12
|
// Globální cache pro názvy zemí (sdílená napříč všemi instancemi ColumnBuilder)
|
|
13
13
|
const COUNTRY_NAMES_CACHE = {};
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Custom React hook pro zpracování interakcí s link buňkou v AG Grid.
|
|
17
|
-
* Obsluhuje hover efekty, kliky a přepínání overview módu.
|
|
18
|
-
* @param {Object} params - AG Grid parametry buňky
|
|
19
|
-
* @param {Function} onClick - Callback funkce při kliku na link
|
|
20
|
-
* @param {Object|Function} linkStyle - CSS styl pro link nebo funkce vracející styl
|
|
21
|
-
* @param {Object|Function} hoverStyle - CSS styl pro hover stav nebo funkce vracející styl
|
|
22
|
-
* @param {boolean} overviewToggle - Příznak zda aktivovat overview toggle funkčnost
|
|
23
|
-
* @returns {Object} Objekt s handlry a styly pro link buňku
|
|
24
|
-
*/
|
|
25
|
-
const useLinkCellRenderer = (
|
|
26
|
-
params,
|
|
27
|
-
onClick,
|
|
28
|
-
linkStyle,
|
|
29
|
-
hoverStyle,
|
|
30
|
-
overviewToggle
|
|
31
|
-
) => {
|
|
32
|
-
const [isHovered, setIsHovered] = React.useState(false);
|
|
33
|
-
|
|
34
|
-
const handleMouseEnter = React.useCallback(() => {
|
|
35
|
-
setIsHovered(true);
|
|
36
|
-
}, []);
|
|
37
|
-
|
|
38
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
39
|
-
setIsHovered(false);
|
|
40
|
-
}, []);
|
|
41
|
-
|
|
42
|
-
const handleClick = React.useCallback(
|
|
43
|
-
(event) => {
|
|
44
|
-
event.stopPropagation();
|
|
45
|
-
|
|
46
|
-
if (overviewToggle && params.api) {
|
|
47
|
-
params.api.dispatchEvent({
|
|
48
|
-
type: 'overviewToggle',
|
|
49
|
-
data: params.data,
|
|
50
|
-
params,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (onClick) {
|
|
55
|
-
onClick(params);
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
[onClick, overviewToggle, params]
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
// Přesunuto do useMemo, aby se vytvořilo pouze jednou
|
|
62
|
-
const defaultLinkStyle = React.useMemo(
|
|
63
|
-
() => ({
|
|
64
|
-
color: '#1a73e8',
|
|
65
|
-
textDecoration: 'none',
|
|
66
|
-
cursor: 'pointer',
|
|
67
|
-
}),
|
|
68
|
-
[]
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
// Přesunuto do useMemo, aby se vytvořilo pouze jednou
|
|
72
|
-
const defaultHoverStyle = React.useMemo(
|
|
73
|
-
() => ({
|
|
74
|
-
textDecoration: 'underline',
|
|
75
|
-
}),
|
|
76
|
-
[]
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
const computedLinkStyle = React.useMemo(
|
|
80
|
-
() => ({
|
|
81
|
-
...defaultLinkStyle,
|
|
82
|
-
...(typeof linkStyle === 'function'
|
|
83
|
-
? linkStyle(params)
|
|
84
|
-
: linkStyle || {}),
|
|
85
|
-
}),
|
|
86
|
-
[linkStyle, params, defaultLinkStyle]
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
const computedHoverStyle = React.useMemo(
|
|
90
|
-
() => ({
|
|
91
|
-
...defaultLinkStyle,
|
|
92
|
-
...computedLinkStyle,
|
|
93
|
-
...defaultHoverStyle,
|
|
94
|
-
...(typeof hoverStyle === 'function'
|
|
95
|
-
? hoverStyle(params)
|
|
96
|
-
: hoverStyle || {}),
|
|
97
|
-
}),
|
|
98
|
-
[computedLinkStyle, hoverStyle, params, defaultLinkStyle, defaultHoverStyle]
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
isHovered,
|
|
103
|
-
handleMouseEnter,
|
|
104
|
-
handleMouseLeave,
|
|
105
|
-
handleClick,
|
|
106
|
-
computedLinkStyle,
|
|
107
|
-
computedHoverStyle,
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Custom React hook pro zpracování interakcí s object buňkou v AG Grid.
|
|
113
|
-
* Poskytuje funkcionalitu pro editovatelné objekty s hover efekty a edit tlačítkem.
|
|
114
|
-
* @param {Object} params - AG Grid parametry buňky
|
|
115
|
-
* @param {boolean} editable - Příznak zda je buňka editovatelná
|
|
116
|
-
* @param {Function} onEditClick - Callback funkce při kliku na edit tlačítko
|
|
117
|
-
* @returns {Object} Objekt s handlry pro object buňku
|
|
118
|
-
*/
|
|
119
|
-
const useObjectCellRenderer = (params, editable, onEditClick) => {
|
|
120
|
-
const [isHovered, setIsHovered] = React.useState(false);
|
|
121
|
-
|
|
122
|
-
const handleMouseEnter = React.useCallback(() => {
|
|
123
|
-
setIsHovered(true);
|
|
124
|
-
}, []);
|
|
125
|
-
|
|
126
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
127
|
-
setIsHovered(false);
|
|
128
|
-
}, []);
|
|
129
|
-
|
|
130
|
-
const handleEditClick = React.useCallback(
|
|
131
|
-
(event) => {
|
|
132
|
-
event.stopPropagation();
|
|
133
|
-
if (onEditClick) {
|
|
134
|
-
onEditClick(params);
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
[onEditClick, params]
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
isHovered,
|
|
142
|
-
handleMouseEnter,
|
|
143
|
-
handleMouseLeave,
|
|
144
|
-
handleEditClick,
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
|
|
148
15
|
/**
|
|
149
16
|
* Custom React hook pro detekci hover stavu řádku v AG Grid.
|
|
150
17
|
* Používá MutationObserver pro sledování CSS tříd řádků a detekci hover stavu.
|
|
@@ -453,73 +320,55 @@ class ColumnBuilder {
|
|
|
453
320
|
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
454
321
|
* @returns {ColumnBuilder} Instance pro chaining
|
|
455
322
|
*/
|
|
323
|
+
/**
|
|
324
|
+
* Přidá sloupec s odkazem (link) - Používá extrahovaný LinkRenderer.
|
|
325
|
+
* Optimalizovaná implementace s extrahovaným rendererem pro lepší výkon.
|
|
326
|
+
* @param {Object} config - Konfigurace link sloupce
|
|
327
|
+
* @param {string} [config.cellAlign='left'] - Horizontální zarovnání obsahu ('left', 'center', 'right')
|
|
328
|
+
* @param {Function} [config.onClick] - Callback funkce při kliku na link
|
|
329
|
+
* @param {Object|Function} [config.linkStyle] - CSS styl pro link nebo funkce vracející styl
|
|
330
|
+
* @param {Object|Function} [config.hoverStyle] - CSS styl pro hover stav nebo funkce vracející styl
|
|
331
|
+
* @param {boolean} [config.overviewToggle=false] - Příznak zda aktivovat overview toggle funkčnost
|
|
332
|
+
* @param {boolean} [config.editable=false] - Editovatelnost buňky
|
|
333
|
+
* @param {Function} [config.visibleGetter] - Funkce určující viditelnost linku
|
|
334
|
+
* @param {boolean} [config.showOnGroup=false] - Zobrazit link i v group řádcích
|
|
335
|
+
* @param {Object} config.restProps - Další AG-Grid colDef parametry
|
|
336
|
+
* @returns {ColumnBuilder} Instance pro fluent API
|
|
337
|
+
*/
|
|
456
338
|
addLinkColumn({
|
|
339
|
+
cellAlign = 'left',
|
|
457
340
|
onClick,
|
|
458
341
|
linkStyle,
|
|
459
342
|
hoverStyle,
|
|
460
|
-
cellAlign = 'left',
|
|
461
|
-
editable,
|
|
462
343
|
overviewToggle = false,
|
|
344
|
+
editable = false,
|
|
345
|
+
visibleGetter,
|
|
346
|
+
showOnGroup = false,
|
|
347
|
+
contentTooltip,
|
|
348
|
+
tooltipField,
|
|
349
|
+
tooltipInteraction,
|
|
350
|
+
tooltipShowDelay,
|
|
463
351
|
color,
|
|
464
352
|
bgColor,
|
|
465
353
|
colorField,
|
|
466
354
|
bgColorField,
|
|
467
355
|
...restProps
|
|
468
356
|
}) {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
handleMouseEnter,
|
|
474
|
-
handleMouseLeave,
|
|
475
|
-
handleClick,
|
|
476
|
-
computedLinkStyle,
|
|
477
|
-
computedHoverStyle,
|
|
478
|
-
} = useLinkCellRenderer(
|
|
479
|
-
params,
|
|
357
|
+
this.#addPreparedColumn({
|
|
358
|
+
cellAlign,
|
|
359
|
+
cellRenderer: 'linkRenderer',
|
|
360
|
+
cellRendererParams: {
|
|
480
361
|
onClick,
|
|
481
362
|
linkStyle,
|
|
482
363
|
hoverStyle,
|
|
483
|
-
overviewToggle
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
height: '100%',
|
|
492
|
-
display: 'flex',
|
|
493
|
-
alignItems: 'center',
|
|
494
|
-
}}
|
|
495
|
-
>
|
|
496
|
-
<span
|
|
497
|
-
onClick={handleClick}
|
|
498
|
-
onMouseEnter={handleMouseEnter}
|
|
499
|
-
onMouseLeave={handleMouseLeave}
|
|
500
|
-
style={isHovered ? computedHoverStyle : computedLinkStyle}
|
|
501
|
-
role="button"
|
|
502
|
-
tabIndex={0}
|
|
503
|
-
onKeyPress={(event) => {
|
|
504
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
505
|
-
handleClick(event);
|
|
506
|
-
}
|
|
507
|
-
}}
|
|
508
|
-
>
|
|
509
|
-
{params.value}
|
|
510
|
-
</span>
|
|
511
|
-
</div>
|
|
512
|
-
);
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
// Používáme funkci, která vrátí React komponentu
|
|
516
|
-
const cellRenderer = (params) => {
|
|
517
|
-
return <LinkCellRenderer {...params} />;
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
this.#addPreparedColumn({
|
|
521
|
-
cellAlign,
|
|
522
|
-
cellRenderer,
|
|
364
|
+
overviewToggle,
|
|
365
|
+
visibleGetter,
|
|
366
|
+
showOnGroup,
|
|
367
|
+
},
|
|
368
|
+
contentTooltip,
|
|
369
|
+
tooltipField,
|
|
370
|
+
tooltipInteraction,
|
|
371
|
+
tooltipShowDelay,
|
|
523
372
|
editable: this.#resolveEditable(editable),
|
|
524
373
|
overviewToggle,
|
|
525
374
|
color,
|
|
@@ -585,73 +434,47 @@ class ColumnBuilder {
|
|
|
585
434
|
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
586
435
|
* @returns {ColumnBuilder} Instance pro chaining
|
|
587
436
|
*/
|
|
437
|
+
/**
|
|
438
|
+
* Přidá sloupec pro zobrazení objektů - Používá extrahovaný ObjectRenderer.
|
|
439
|
+
* Optimalizovaná implementace s extrahovaným rendererem pro lepší výkon.
|
|
440
|
+
* @param {Object} config - Konfigurace object sloupce
|
|
441
|
+
* @param {boolean} [config.editable=false] - Příznak zda je buňka editovatelná s edit tlačítkem
|
|
442
|
+
* @param {Function} [config.onEditClick] - Callback funkce při kliku na edit tlačítko
|
|
443
|
+
* @param {Function} [config.visibleGetter] - Funkce určující viditelnost objektu
|
|
444
|
+
* @param {boolean} [config.showOnGroup=false] - Zobrazit objekt i v group řádcích
|
|
445
|
+
* @param {string|Function} [config.displayField] - Název pole nebo funkce pro získání zobrazované hodnoty
|
|
446
|
+
* @param {Object} config.restProps - Další AG-Grid colDef parametry
|
|
447
|
+
* @returns {ColumnBuilder} Instance pro fluent API
|
|
448
|
+
*/
|
|
588
449
|
addObjectColumn({
|
|
450
|
+
editable = false,
|
|
451
|
+
onEditClick,
|
|
452
|
+
visibleGetter,
|
|
453
|
+
showOnGroup = false,
|
|
454
|
+
displayField,
|
|
589
455
|
contentTooltip,
|
|
590
456
|
tooltipField,
|
|
591
457
|
tooltipInteraction,
|
|
592
|
-
tooltipShowDelay
|
|
593
|
-
editable,
|
|
594
|
-
onEditClick,
|
|
458
|
+
tooltipShowDelay,
|
|
595
459
|
color,
|
|
596
460
|
bgColor,
|
|
597
461
|
colorField,
|
|
598
462
|
bgColorField,
|
|
599
463
|
...restProps
|
|
600
464
|
}) {
|
|
601
|
-
// Vytvořím komponentu pro cell renderer, která používá hook
|
|
602
|
-
const ObjectCellRenderer = React.memo((params) => {
|
|
603
|
-
const { isHovered, handleMouseEnter, handleMouseLeave, handleEditClick } =
|
|
604
|
-
useObjectCellRenderer(params, editable, onEditClick);
|
|
605
|
-
|
|
606
|
-
return (
|
|
607
|
-
<div
|
|
608
|
-
className="object-cell-container"
|
|
609
|
-
style={{
|
|
610
|
-
position: 'relative',
|
|
611
|
-
width: '100%',
|
|
612
|
-
height: '100%',
|
|
613
|
-
display: 'flex',
|
|
614
|
-
alignItems: 'center',
|
|
615
|
-
}}
|
|
616
|
-
onMouseEnter={handleMouseEnter}
|
|
617
|
-
onMouseLeave={handleMouseLeave}
|
|
618
|
-
>
|
|
619
|
-
<div style={{ flexGrow: 1 }}>{params.value}</div>
|
|
620
|
-
{isHovered && editable && (
|
|
621
|
-
<button
|
|
622
|
-
className="edit-object-button"
|
|
623
|
-
style={{
|
|
624
|
-
position: 'absolute',
|
|
625
|
-
right: '4px',
|
|
626
|
-
background: 'transparent',
|
|
627
|
-
border: 'none',
|
|
628
|
-
cursor: 'pointer',
|
|
629
|
-
padding: '4px',
|
|
630
|
-
display: 'flex',
|
|
631
|
-
alignItems: 'center',
|
|
632
|
-
justifyContent: 'center',
|
|
633
|
-
}}
|
|
634
|
-
onClick={handleEditClick}
|
|
635
|
-
title="Upravit"
|
|
636
|
-
>
|
|
637
|
-
<span style={{ fontSize: '16px' }}>⋮</span>
|
|
638
|
-
</button>
|
|
639
|
-
)}
|
|
640
|
-
</div>
|
|
641
|
-
);
|
|
642
|
-
});
|
|
643
|
-
|
|
644
|
-
// Používáme funkci, která vrátí React komponentu
|
|
645
|
-
const cellRenderer = (params) => {
|
|
646
|
-
return <ObjectCellRenderer {...params} />;
|
|
647
|
-
};
|
|
648
|
-
|
|
649
465
|
this.#addPreparedColumn({
|
|
466
|
+
cellRenderer: 'objectRenderer',
|
|
467
|
+
cellRendererParams: {
|
|
468
|
+
editable,
|
|
469
|
+
onEditClick,
|
|
470
|
+
visibleGetter,
|
|
471
|
+
showOnGroup,
|
|
472
|
+
displayField,
|
|
473
|
+
},
|
|
650
474
|
contentTooltip,
|
|
651
475
|
tooltipField,
|
|
652
476
|
tooltipInteraction,
|
|
653
477
|
tooltipShowDelay,
|
|
654
|
-
cellRenderer,
|
|
655
478
|
editable: this.#resolveEditable(editable),
|
|
656
479
|
color,
|
|
657
480
|
bgColor,
|
|
@@ -886,22 +709,70 @@ class ColumnBuilder {
|
|
|
886
709
|
bgColorField,
|
|
887
710
|
...restProps
|
|
888
711
|
}) {
|
|
712
|
+
// Memoizovaná CountryFlag sub-komponenta s lazy loading a error handling
|
|
713
|
+
const CountryFlag = React.memo(({ code, size }) => {
|
|
714
|
+
const [hasError, setHasError] = React.useState(false);
|
|
715
|
+
|
|
716
|
+
const flagUrl = React.useMemo(() => {
|
|
717
|
+
if (!code) return null;
|
|
718
|
+
return `https://flagcdn.com/w40/${code.toLowerCase()}.png`;
|
|
719
|
+
}, [code]);
|
|
720
|
+
|
|
721
|
+
const handleError = React.useCallback(() => {
|
|
722
|
+
setHasError(true);
|
|
723
|
+
}, []);
|
|
724
|
+
|
|
725
|
+
React.useEffect(() => {
|
|
726
|
+
setHasError(false);
|
|
727
|
+
}, [flagUrl]);
|
|
728
|
+
|
|
729
|
+
const flagStyle = React.useMemo(() => ({
|
|
730
|
+
width: `${size}px`,
|
|
731
|
+
height: `${size}px`,
|
|
732
|
+
borderRadius: '50%',
|
|
733
|
+
objectFit: 'cover',
|
|
734
|
+
flexShrink: 0,
|
|
735
|
+
}), [size]);
|
|
736
|
+
|
|
737
|
+
if (hasError || !flagUrl) return null;
|
|
738
|
+
|
|
739
|
+
return (
|
|
740
|
+
<img
|
|
741
|
+
src={flagUrl}
|
|
742
|
+
alt={`${code} flag`}
|
|
743
|
+
style={flagStyle}
|
|
744
|
+
loading="lazy"
|
|
745
|
+
onError={handleError}
|
|
746
|
+
/>
|
|
747
|
+
);
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
CountryFlag.displayName = 'CountryFlag';
|
|
751
|
+
|
|
889
752
|
const CountryCellRenderer = React.memo((params) => {
|
|
890
753
|
const [countryName, setCountryName] = React.useState(null);
|
|
891
754
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
892
755
|
|
|
893
756
|
// Získání kódu země
|
|
894
|
-
const code =
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
757
|
+
const code = React.useMemo(() => {
|
|
758
|
+
return countryCodeField
|
|
759
|
+
? getValueByPath(params.data, countryCodeField)
|
|
760
|
+
: (typeof countryCode === 'function' ? countryCode(params) : countryCode);
|
|
761
|
+
}, [params.data, params.value]);
|
|
762
|
+
|
|
763
|
+
const upperCode = React.useMemo(() =>
|
|
764
|
+
code ? code.toUpperCase() : null,
|
|
765
|
+
[code]
|
|
766
|
+
);
|
|
899
767
|
|
|
900
|
-
const
|
|
901
|
-
|
|
768
|
+
const cacheKey = React.useMemo(() =>
|
|
769
|
+
upperCode ? `${upperCode}_${language}` : null,
|
|
770
|
+
[upperCode, language]
|
|
771
|
+
);
|
|
902
772
|
|
|
903
773
|
// Načtení názvu země z REST Countries API
|
|
904
774
|
React.useEffect(() => {
|
|
775
|
+
if (!upperCode || !cacheKey) return;
|
|
905
776
|
if (displayType !== 'name') return;
|
|
906
777
|
if (getCountryName) return;
|
|
907
778
|
|
|
@@ -912,16 +783,16 @@ class ColumnBuilder {
|
|
|
912
783
|
}
|
|
913
784
|
|
|
914
785
|
setIsLoading(true);
|
|
915
|
-
|
|
916
|
-
// REST Countries API
|
|
786
|
+
|
|
787
|
+
// REST Countries API
|
|
917
788
|
fetch(`https://restcountries.com/v3.1/alpha/${upperCode}`)
|
|
918
789
|
.then(response => response.json())
|
|
919
790
|
.then(data => {
|
|
920
791
|
if (data && data[0]) {
|
|
921
792
|
// Získání překladu podle jazyka
|
|
922
793
|
const translations = data[0].translations;
|
|
923
|
-
let name = data[0].name.common;
|
|
924
|
-
|
|
794
|
+
let name = data[0].name.common;
|
|
795
|
+
|
|
925
796
|
if (language === 'cs' && translations?.ces) {
|
|
926
797
|
name = translations.ces.common;
|
|
927
798
|
} else if (language === 'cze' && translations?.cze) {
|
|
@@ -929,79 +800,78 @@ class ColumnBuilder {
|
|
|
929
800
|
} else if (translations && translations[language]) {
|
|
930
801
|
name = translations[language].common;
|
|
931
802
|
}
|
|
932
|
-
|
|
933
|
-
|
|
803
|
+
|
|
934
804
|
// Uložení do cache
|
|
935
805
|
COUNTRY_NAMES_CACHE[cacheKey] = name;
|
|
936
806
|
setCountryName(name);
|
|
937
807
|
}
|
|
938
808
|
})
|
|
939
|
-
.catch((
|
|
940
|
-
console.error('Error fetching country:', error);
|
|
809
|
+
.catch(() => {
|
|
941
810
|
// V případě chyby použijeme kód země
|
|
942
811
|
setCountryName(upperCode);
|
|
943
812
|
})
|
|
944
813
|
.finally(() => {
|
|
945
814
|
setIsLoading(false);
|
|
946
815
|
});
|
|
947
|
-
}, [upperCode, cacheKey, displayType, getCountryName
|
|
948
|
-
|
|
949
|
-
// Získání názvu země
|
|
950
|
-
let displayText = upperCode;
|
|
951
|
-
if (displayType === 'name') {
|
|
952
|
-
if (getCountryName) {
|
|
953
|
-
displayText = getCountryName(code, params);
|
|
954
|
-
} else if (countryName) {
|
|
955
|
-
displayText = countryName;
|
|
956
|
-
} else if (isLoading) {
|
|
957
|
-
displayText = '...';
|
|
958
|
-
} else if (params.value) {
|
|
959
|
-
displayText = params.value;
|
|
960
|
-
}
|
|
961
|
-
}
|
|
816
|
+
}, [upperCode, cacheKey, displayType, getCountryName]);
|
|
962
817
|
|
|
963
|
-
//
|
|
964
|
-
const
|
|
818
|
+
// Memoizovaný displayText
|
|
819
|
+
const displayText = React.useMemo(() => {
|
|
820
|
+
if (!upperCode) return '';
|
|
965
821
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
822
|
+
if (displayType === 'name') {
|
|
823
|
+
if (getCountryName) {
|
|
824
|
+
return getCountryName(code, params);
|
|
825
|
+
}
|
|
826
|
+
if (countryName) {
|
|
827
|
+
return countryName;
|
|
828
|
+
}
|
|
829
|
+
if (isLoading) {
|
|
830
|
+
return '...';
|
|
831
|
+
}
|
|
832
|
+
if (params.value) {
|
|
833
|
+
return params.value;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
973
836
|
|
|
974
|
-
|
|
837
|
+
return upperCode;
|
|
838
|
+
}, [upperCode, displayType, getCountryName, code, params, countryName, isLoading]);
|
|
839
|
+
|
|
840
|
+
// Memoizovaný containerStyle
|
|
841
|
+
const containerStyle = React.useMemo(() => ({
|
|
975
842
|
display: 'flex',
|
|
976
843
|
alignItems: 'center',
|
|
977
|
-
justifyContent:
|
|
844
|
+
justifyContent:
|
|
845
|
+
cellAlign === 'center' ? 'center' :
|
|
846
|
+
cellAlign === 'right' ? 'flex-end' :
|
|
847
|
+
'flex-start',
|
|
978
848
|
width: '100%',
|
|
979
849
|
height: '100%',
|
|
980
850
|
gap: `${textGap}px`,
|
|
981
851
|
flexDirection: flagPosition === 'right' ? 'row-reverse' : 'row',
|
|
982
|
-
};
|
|
852
|
+
}), [cellAlign, textGap, flagPosition]);
|
|
853
|
+
|
|
854
|
+
if (!code) return null;
|
|
983
855
|
|
|
984
856
|
return (
|
|
985
857
|
<div style={containerStyle}>
|
|
986
|
-
<
|
|
987
|
-
src={flagUrl}
|
|
988
|
-
alt={`${upperCode} flag`}
|
|
989
|
-
style={flagStyle}
|
|
990
|
-
onError={(e) => {
|
|
991
|
-
e.target.style.display = 'none';
|
|
992
|
-
}}
|
|
993
|
-
/>
|
|
858
|
+
<CountryFlag code={upperCode} size={flagSize} />
|
|
994
859
|
<span>{displayText}</span>
|
|
995
860
|
</div>
|
|
996
861
|
);
|
|
997
862
|
});
|
|
998
863
|
|
|
864
|
+
CountryCellRenderer.displayName = 'CountryCellRenderer';
|
|
865
|
+
|
|
999
866
|
const cellRenderer = (params) => {
|
|
1000
867
|
return <CountryCellRenderer {...params} />;
|
|
1001
868
|
};
|
|
1002
869
|
|
|
1003
870
|
this.#addPreparedColumn({
|
|
1004
871
|
cellRenderer,
|
|
872
|
+
cellRendererParams: {
|
|
873
|
+
deferRender: true, // AG-Grid deferred rendering pro optimalizaci výkonu při scrollování
|
|
874
|
+
},
|
|
1005
875
|
color,
|
|
1006
876
|
bgColor,
|
|
1007
877
|
colorField,
|
|
@@ -1051,58 +921,76 @@ class ColumnBuilder {
|
|
|
1051
921
|
bgColorField,
|
|
1052
922
|
...restProps
|
|
1053
923
|
}) {
|
|
1054
|
-
//
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
924
|
+
// Konstanty mimo komponentu pro lepší výkon
|
|
925
|
+
const ICON_STYLE = {
|
|
926
|
+
display: 'inline-block',
|
|
927
|
+
height: '100%',
|
|
928
|
+
};
|
|
1059
929
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
930
|
+
// Memoizovaná Icon sub-komponenta
|
|
931
|
+
const Icon = React.memo(({ innerValue, size, colorTrue, colorFalse, visibleTrue, visibleFalse, defaultIcon, defaultIconColor }) => {
|
|
932
|
+
if (innerValue === undefined || innerValue === null) {
|
|
933
|
+
if (defaultIcon) {
|
|
934
|
+
return <CircleHelp size={size} color={defaultIconColor} style={ICON_STYLE} />;
|
|
1064
935
|
}
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
1065
938
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}
|
|
939
|
+
if ((!visibleFalse && !innerValue) || (!visibleTrue && innerValue)) {
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
1070
942
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
943
|
+
if (innerValue) {
|
|
944
|
+
return <Check size={size} color={colorTrue} style={ICON_STYLE} />;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
return <X size={size} color={colorFalse} style={ICON_STYLE} />;
|
|
948
|
+
});
|
|
1075
949
|
|
|
1076
|
-
|
|
950
|
+
Icon.displayName = 'BooleanIcon';
|
|
951
|
+
|
|
952
|
+
// Create a React component for boolean cell renderer
|
|
953
|
+
const BooleanCellRenderer = React.memo((params) => {
|
|
954
|
+
const { data, value } = params;
|
|
955
|
+
|
|
956
|
+
const visibleResult = React.useMemo(() =>
|
|
957
|
+
visibleGetter ? visibleGetter(data) : true,
|
|
958
|
+
[data]
|
|
959
|
+
);
|
|
960
|
+
|
|
961
|
+
const showCondition = React.useMemo(() => {
|
|
1077
962
|
const newItem = (data && data._rh_plus_ag_grid_new_item) || false;
|
|
1078
963
|
return !newItem && (showOnGroup || !!data) && visibleResult;
|
|
1079
|
-
};
|
|
964
|
+
}, [data, visibleResult]);
|
|
1080
965
|
|
|
1081
|
-
|
|
966
|
+
const containerStyle = React.useMemo(() => ({
|
|
967
|
+
width: '100%',
|
|
968
|
+
display: 'flex',
|
|
969
|
+
justifyContent: cellAlign ?? 'center',
|
|
970
|
+
alignItems: 'center',
|
|
971
|
+
height: '100%',
|
|
972
|
+
}), [cellAlign]);
|
|
973
|
+
|
|
974
|
+
if (!showCondition) return null;
|
|
1082
975
|
|
|
1083
976
|
return (
|
|
1084
|
-
<span
|
|
1085
|
-
style={{
|
|
1086
|
-
width: '100%',
|
|
1087
|
-
display: 'flex',
|
|
1088
|
-
justifyContent: cellAlign,
|
|
1089
|
-
alignItems: 'center',
|
|
1090
|
-
height: '100%',
|
|
1091
|
-
}}
|
|
1092
|
-
>
|
|
977
|
+
<span style={containerStyle}>
|
|
1093
978
|
<Icon
|
|
1094
|
-
style={{
|
|
1095
|
-
display: 'inline-block',
|
|
1096
|
-
height: '100%',
|
|
1097
|
-
}}
|
|
1098
979
|
innerValue={value}
|
|
980
|
+
size={size}
|
|
981
|
+
colorTrue={colorTrue}
|
|
982
|
+
colorFalse={colorFalse}
|
|
1099
983
|
visibleTrue={visibleTrue}
|
|
1100
984
|
visibleFalse={visibleFalse}
|
|
985
|
+
defaultIcon={defaultIcon}
|
|
986
|
+
defaultIconColor={defaultIconColor}
|
|
1101
987
|
/>
|
|
1102
988
|
</span>
|
|
1103
989
|
);
|
|
1104
990
|
});
|
|
1105
991
|
|
|
992
|
+
BooleanCellRenderer.displayName = 'BooleanCellRenderer';
|
|
993
|
+
|
|
1106
994
|
// Use the function that returns React component
|
|
1107
995
|
const cellRenderer = (params) => {
|
|
1108
996
|
return <BooleanCellRenderer {...params} />;
|
|
@@ -1110,6 +998,9 @@ class ColumnBuilder {
|
|
|
1110
998
|
|
|
1111
999
|
this.#addPreparedColumn({
|
|
1112
1000
|
cellRenderer,
|
|
1001
|
+
cellRendererParams: {
|
|
1002
|
+
deferRender: true, // AG-Grid deferred rendering pro optimalizaci výkonu při scrollování
|
|
1003
|
+
},
|
|
1113
1004
|
editable: this.#resolveEditable(editable),
|
|
1114
1005
|
color,
|
|
1115
1006
|
bgColor,
|
|
@@ -1530,6 +1421,9 @@ class ColumnBuilder {
|
|
|
1530
1421
|
filter: false,
|
|
1531
1422
|
resizable: false,
|
|
1532
1423
|
cellRenderer: ActionDropdownRenderer,
|
|
1424
|
+
cellRendererParams: {
|
|
1425
|
+
deferRender: true, // AG-Grid deferred rendering pro optimalizaci výkonu při scrollování
|
|
1426
|
+
},
|
|
1533
1427
|
cellClass: 'action-button-cell-observer',
|
|
1534
1428
|
...restProps,
|
|
1535
1429
|
});
|