@bit.rhplus/ag-grid 0.0.114 → 0.0.116

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.
Files changed (163) hide show
  1. package/AgGridOnRowDataChanged.js +3 -8
  2. package/CheckBoxRenderer.jsx +1 -0
  3. package/Components/ExtendButton.jsx +1 -0
  4. package/Editors/ModuleLookupEditor.jsx +65 -0
  5. package/Editors/index.jsx +1 -0
  6. package/Renderers/CheckboxRenderer.jsx +1 -0
  7. package/Renderers/CountrySelectRenderer.jsx +1 -0
  8. package/Renderers/ModuleLookupRenderer.jsx +40 -0
  9. package/Renderers/SelectCellRenderer.jsx +1 -0
  10. package/Renderers/index.jsx +1 -0
  11. package/dist/AgGridAddNewItem.d.ts +1 -0
  12. package/dist/AgGridAddNewItem.js +6 -0
  13. package/dist/AgGridAddNewItem.js.map +1 -0
  14. package/dist/AgGridColumn.d.ts +3 -0
  15. package/dist/AgGridColumn.js +357 -0
  16. package/dist/AgGridColumn.js.map +1 -0
  17. package/dist/AgGridColumnFilter.d.ts +4 -0
  18. package/dist/AgGridColumnFilter.js +19 -0
  19. package/dist/AgGridColumnFilter.js.map +1 -0
  20. package/dist/AgGridOnGridReady.d.ts +1 -0
  21. package/dist/AgGridOnGridReady.js +6 -0
  22. package/dist/AgGridOnGridReady.js.map +1 -0
  23. package/dist/AgGridOnRowDataChanged.d.ts +1 -0
  24. package/dist/AgGridOnRowDataChanged.js +4 -0
  25. package/dist/AgGridOnRowDataChanged.js.map +1 -0
  26. package/dist/AgGridOnRowDataUpdated.d.ts +1 -0
  27. package/dist/AgGridOnRowDataUpdated.js +27 -0
  28. package/dist/AgGridOnRowDataUpdated.js.map +1 -0
  29. package/dist/AgGridPostSort.d.ts +1 -0
  30. package/dist/AgGridPostSort.js +32 -0
  31. package/dist/AgGridPostSort.js.map +1 -0
  32. package/dist/AggregationNotification.d.ts +1 -0
  33. package/dist/AggregationNotification.js +121 -0
  34. package/dist/AggregationNotification.js.map +1 -0
  35. package/dist/AggregationStatusBar.d.ts +3 -0
  36. package/dist/AggregationStatusBar.js +122 -0
  37. package/dist/AggregationStatusBar.js.map +1 -0
  38. package/dist/Aggregations.d.ts +2 -0
  39. package/dist/Aggregations.js +313 -0
  40. package/dist/Aggregations.js.map +1 -0
  41. package/dist/BulkEdit/BulkEditButton.d.ts +14 -0
  42. package/dist/BulkEdit/BulkEditButton.js +140 -0
  43. package/dist/BulkEdit/BulkEditButton.js.map +1 -0
  44. package/dist/BulkEdit/BulkEditDatePicker.d.ts +11 -0
  45. package/dist/BulkEdit/BulkEditDatePicker.js +160 -0
  46. package/dist/BulkEdit/BulkEditDatePicker.js.map +1 -0
  47. package/dist/BulkEdit/BulkEditInput.d.ts +14 -0
  48. package/dist/BulkEdit/BulkEditInput.js +34 -0
  49. package/dist/BulkEdit/BulkEditInput.js.map +1 -0
  50. package/dist/BulkEdit/BulkEditModule.d.ts +11 -0
  51. package/dist/BulkEdit/BulkEditModule.js +34 -0
  52. package/dist/BulkEdit/BulkEditModule.js.map +1 -0
  53. package/dist/BulkEdit/BulkEditPopover.d.ts +14 -0
  54. package/dist/BulkEdit/BulkEditPopover.js +125 -0
  55. package/dist/BulkEdit/BulkEditPopover.js.map +1 -0
  56. package/dist/BulkEdit/BulkEditSelect.d.ts +18 -0
  57. package/dist/BulkEdit/BulkEditSelect.js +56 -0
  58. package/dist/BulkEdit/BulkEditSelect.js.map +1 -0
  59. package/dist/BulkEdit/BulkEditTagsSelect.d.ts +15 -0
  60. package/dist/BulkEdit/BulkEditTagsSelect.js +45 -0
  61. package/dist/BulkEdit/BulkEditTagsSelect.js.map +1 -0
  62. package/dist/BulkEdit/index.d.ts +1 -0
  63. package/dist/BulkEdit/index.js +11 -0
  64. package/dist/BulkEdit/index.js.map +1 -0
  65. package/dist/BulkEdit/useBulkCellEdit.d.ts +1 -0
  66. package/dist/BulkEdit/useBulkCellEdit.js +397 -0
  67. package/dist/BulkEdit/useBulkCellEdit.js.map +1 -0
  68. package/dist/BulkEdit/utils.d.ts +7 -0
  69. package/dist/BulkEdit/utils.js +568 -0
  70. package/dist/BulkEdit/utils.js.map +1 -0
  71. package/dist/CheckBoxRenderer.d.ts +6 -0
  72. package/dist/CheckBoxRenderer.js +19 -0
  73. package/dist/CheckBoxRenderer.js.map +1 -0
  74. package/dist/Components/ExtendButton.css +6 -0
  75. package/dist/Components/ExtendButton.d.ts +2 -0
  76. package/dist/Components/ExtendButton.js +13 -0
  77. package/dist/Components/ExtendButton.js.map +1 -0
  78. package/dist/CountryCellRenderer.d.ts +1 -0
  79. package/dist/CountryCellRenderer.js +12 -0
  80. package/dist/CountryCellRenderer.js.map +1 -0
  81. package/dist/Editors/DatePickerEditor.d.ts +9 -0
  82. package/dist/Editors/DatePickerEditor.js +55 -0
  83. package/dist/Editors/DatePickerEditor.js.map +1 -0
  84. package/dist/Editors/ModuleLookupEditor.d.ts +8 -0
  85. package/dist/Editors/ModuleLookupEditor.js +43 -0
  86. package/dist/Editors/ModuleLookupEditor.js.map +1 -0
  87. package/dist/Editors/index.d.ts +1 -0
  88. package/dist/Editors/index.js +3 -0
  89. package/dist/Editors/index.js.map +1 -0
  90. package/dist/Functions/index.d.ts +2 -0
  91. package/dist/Functions/index.js +27 -0
  92. package/dist/Functions/index.js.map +1 -0
  93. package/dist/HeaderTemplates/CommonHeaderTemplate.d.ts +1 -0
  94. package/dist/HeaderTemplates/CommonHeaderTemplate.js +15 -0
  95. package/dist/HeaderTemplates/CommonHeaderTemplate.js.map +1 -0
  96. package/dist/HyperModuleEditor.d.ts +1 -0
  97. package/dist/HyperModuleEditor.js +119 -0
  98. package/dist/HyperModuleEditor.js.map +1 -0
  99. package/dist/HyperModuleRenderer.d.ts +1 -0
  100. package/dist/HyperModuleRenderer.js +138 -0
  101. package/dist/HyperModuleRenderer.js.map +1 -0
  102. package/dist/NotificationOptions.d.ts +10 -0
  103. package/dist/NotificationOptions.js +80 -0
  104. package/dist/NotificationOptions.js.map +1 -0
  105. package/dist/OnCellDoubleClicked.d.ts +1 -0
  106. package/dist/OnCellDoubleClicked.js +6 -0
  107. package/dist/OnCellDoubleClicked.js.map +1 -0
  108. package/dist/OnCellEditingStarted.d.ts +1 -0
  109. package/dist/OnCellEditingStarted.js +7 -0
  110. package/dist/OnCellEditingStarted.js.map +1 -0
  111. package/dist/OnCellValueChanged.d.ts +1 -0
  112. package/dist/OnCellValueChanged.js +10 -0
  113. package/dist/OnCellValueChanged.js.map +1 -0
  114. package/dist/Renderers/BooleanRenderer.d.ts +3 -0
  115. package/dist/Renderers/BooleanRenderer.js +55 -0
  116. package/dist/Renderers/BooleanRenderer.js.map +1 -0
  117. package/dist/Renderers/ButtonRenderer.d.ts +3 -0
  118. package/dist/Renderers/ButtonRenderer.js +66 -0
  119. package/dist/Renderers/ButtonRenderer.js.map +1 -0
  120. package/dist/Renderers/CheckboxRenderer.d.ts +7 -0
  121. package/dist/Renderers/CheckboxRenderer.js +37 -0
  122. package/dist/Renderers/CheckboxRenderer.js.map +1 -0
  123. package/dist/Renderers/CountrySelectRenderer.d.ts +7 -0
  124. package/dist/Renderers/CountrySelectRenderer.js +56 -0
  125. package/dist/Renderers/CountrySelectRenderer.js.map +1 -0
  126. package/dist/Renderers/IconRenderer.d.ts +3 -0
  127. package/dist/Renderers/IconRenderer.js +187 -0
  128. package/dist/Renderers/IconRenderer.js.map +1 -0
  129. package/dist/Renderers/ImageRenderer.d.ts +3 -0
  130. package/dist/Renderers/ImageRenderer.js +58 -0
  131. package/dist/Renderers/ImageRenderer.js.map +1 -0
  132. package/dist/Renderers/LinkRenderer.d.ts +3 -0
  133. package/dist/Renderers/LinkRenderer.js +76 -0
  134. package/dist/Renderers/LinkRenderer.js.map +1 -0
  135. package/dist/Renderers/ModuleLookupRenderer.d.ts +3 -0
  136. package/dist/Renderers/ModuleLookupRenderer.js +28 -0
  137. package/dist/Renderers/ModuleLookupRenderer.js.map +1 -0
  138. package/dist/Renderers/ObjectRenderer.d.ts +3 -0
  139. package/dist/Renderers/ObjectRenderer.js +96 -0
  140. package/dist/Renderers/ObjectRenderer.js.map +1 -0
  141. package/dist/Renderers/SelectCellRenderer.d.ts +4 -0
  142. package/dist/Renderers/SelectCellRenderer.js +19 -0
  143. package/dist/Renderers/SelectCellRenderer.js.map +1 -0
  144. package/dist/Renderers/SelectRenderer.d.ts +3 -0
  145. package/dist/Renderers/SelectRenderer.js +56 -0
  146. package/dist/Renderers/SelectRenderer.js.map +1 -0
  147. package/dist/Renderers/StateRenderer.d.ts +3 -0
  148. package/dist/Renderers/StateRenderer.js +137 -0
  149. package/dist/Renderers/StateRenderer.js.map +1 -0
  150. package/dist/Renderers/index.d.ts +1 -0
  151. package/dist/Renderers/index.js +3 -0
  152. package/dist/Renderers/index.js.map +1 -0
  153. package/dist/index.d.ts +3 -0
  154. package/dist/index.js +868 -0
  155. package/dist/index.js.map +1 -0
  156. package/dist/preview-1773828129212.js +7 -0
  157. package/dist/util.d.ts +15 -0
  158. package/dist/util.js +108 -0
  159. package/dist/util.js.map +1 -0
  160. package/package.json +5 -5
  161. package/types/asset.d.ts +43 -0
  162. package/types/env.d.ts +15 -0
  163. package/types/style.d.ts +42 -0
package/dist/index.js ADDED
@@ -0,0 +1,868 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable */
3
+ import * as React from 'react';
4
+ import { AgGridReact } from 'ag-grid-react';
5
+ import { AgGridColumns } from './AgGridColumn';
6
+ import { RhPlusOnCellEditingStarted } from './OnCellEditingStarted';
7
+ import { RhPlusOnCellDoubleClicked } from './OnCellDoubleClicked';
8
+ import { RhPlusOnCellValueChanged } from './OnCellValueChanged';
9
+ import { AgGridPostSort } from './AgGridPostSort';
10
+ import { AgGridOnRowDataChanged } from './AgGridOnRowDataChanged';
11
+ import { AgGridOnRowDataUpdated } from './AgGridOnRowDataUpdated';
12
+ import CheckboxRenderer from './Renderers/CheckboxRenderer';
13
+ import BooleanRenderer from './Renderers/BooleanRenderer';
14
+ import { createGridComparison } from '@bit.rhplus/react-memo';
15
+ import IconRenderer from './Renderers/IconRenderer';
16
+ import ImageRenderer from './Renderers/ImageRenderer';
17
+ import StateRenderer from './Renderers/StateRenderer';
18
+ import SelectRenderer from './Renderers/SelectRenderer';
19
+ import ButtonRenderer from './Renderers/ButtonRenderer';
20
+ import CountrySelectRenderer from './Renderers/CountrySelectRenderer';
21
+ import ObjectRenderer from './Renderers/ObjectRenderer';
22
+ import LinkRenderer from './Renderers/LinkRenderer';
23
+ import NotificationOptionsInit from "./NotificationOptions";
24
+ import AggregationStatusBar from "./AggregationStatusBar";
25
+ import { notification, Button } from "antd";
26
+ import { CompressOutlined } from '@ant-design/icons';
27
+ import Aggregations, { hashRanges } from "./Aggregations";
28
+ import { useBulkCellEdit, BulkEditButton } from './BulkEdit';
29
+ import { ModuleRegistry, themeAlpine, themeBalham, themeMaterial, themeQuartz, ClientSideRowModelModule, QuickFilterModule, ValidationModule, CsvExportModule, TooltipModule, } from "ag-grid-community";
30
+ import { ExcelExportModule } from "ag-grid-enterprise";
31
+ // Registrace AG-Grid modulů (nutné pro Quick Filter, export a další funkce)
32
+ ModuleRegistry.registerModules([
33
+ QuickFilterModule,
34
+ ClientSideRowModelModule,
35
+ CsvExportModule,
36
+ ExcelExportModule,
37
+ TooltipModule,
38
+ ...(process.env.NODE_ENV !== "production" ? [ValidationModule] : []),
39
+ ]);
40
+ const themes = [
41
+ { id: "themeQuartz", theme: themeQuartz },
42
+ { id: "themeBalham", theme: themeBalham },
43
+ { id: "themeMaterial", theme: themeMaterial },
44
+ { id: "themeAlpine", theme: themeAlpine },
45
+ ];
46
+ const AgGrid = React.forwardRef((props, ref) => {
47
+ const internalRef = React.useRef();
48
+ const { theme = "themeAlpine", // Default theme
49
+ rowData = [], newRowFlash = true, updatedRowFlash = false, onGridReady,
50
+ // Notification props
51
+ notificationMode = 'full', // 'full' | 'simple' | 'none'
52
+ notificationOptions: { notificationHead = NotificationOptionsInit.head, notificationBody = NotificationOptionsInit.body, style = NotificationOptionsInit.style, placement = NotificationOptionsInit.placement, } = {},
53
+ // Status Bar props (pro simple mode)
54
+ statusBarMetrics = [
55
+ 'count',
56
+ 'sum',
57
+ 'min',
58
+ 'max',
59
+ 'avg',
60
+ 'median',
61
+ 'range',
62
+ 'geometry',
63
+ 'dateRange'
64
+ ], statusBarHeight = 36,
65
+ // Bulk Edit props
66
+ enableBulkEdit = false, bulkEditOptions = {}, bulkEditAccessToken, onBulkEditStart, onBulkEditComplete,
67
+ // SignalR transaction support
68
+ queryKey, // Identifikátor pro SignalR transactions
69
+ // Quick Filter
70
+ quickFilterText = "", // Text pro fulltextové vyhledávání
71
+ } = props;
72
+ // Najít theme objekt podle názvu z props
73
+ const themeObject = React.useMemo(() => {
74
+ const foundTheme = themes.find(t => t.id === theme);
75
+ return foundTheme ? foundTheme.theme : themeQuartz; // Fallback na themeQuartz
76
+ }, [theme]);
77
+ const [, setIsGridReady] = React.useState(false);
78
+ const isSelectingRef = React.useRef(false); // ✅ FIX: Změna ze state na ref pro eliminaci rerenderů
79
+ const aggregationDataRef = React.useRef(null); // // Pro simple mode status bar
80
+ const activeNotificationModeRef = React.useRef(notificationMode); // // Aktivní mód (může být dočasně přepsán uživatelem)
81
+ const previousRowDataRef = React.useRef(rowData);
82
+ // Synchronizovat activeNotificationModeRef s notificationMode prop
83
+ React.useEffect(() => {
84
+ activeNotificationModeRef.current = notificationMode;
85
+ }, [notificationMode]);
86
+ // Bulk Edit hook
87
+ const { floatingButton, editPopover, handleRangeChange, handleOpenPopover, handleSubmitEdit, handleCancelEdit, handleValueChange, } = useBulkCellEdit(internalRef, {
88
+ enabled: enableBulkEdit,
89
+ accessToken: bulkEditAccessToken,
90
+ onBulkEditStart,
91
+ onBulkEditComplete,
92
+ ...bulkEditOptions,
93
+ });
94
+ // ========== PERFORMANCE OPTIMIZATION: Shallow comparison helper ==========
95
+ // Shallow porovnání objektů - 100x rychlejší než JSON.stringify
96
+ const shallowEqual = React.useCallback((obj1, obj2) => {
97
+ if (obj1 === obj2)
98
+ return true;
99
+ if (!obj1 || !obj2)
100
+ return false;
101
+ const keys1 = Object.keys(obj1);
102
+ const keys2 = Object.keys(obj2);
103
+ if (keys1.length !== keys2.length)
104
+ return false;
105
+ for (let key of keys1) {
106
+ if (obj1[key] !== obj2[key])
107
+ return false;
108
+ }
109
+ return true;
110
+ }, []);
111
+ // Memoizované funkce pro detekci změn v rowData
112
+ const findNewRows = React.useCallback((oldData, newData) => {
113
+ const oldIds = new Set(oldData.map((row) => row.id));
114
+ return newData.filter((row) => !oldIds.has(row.id));
115
+ }, []);
116
+ const findUpdatedRows = React.useCallback((oldData, newData) => {
117
+ const oldDataMap = new Map(oldData.map((row) => [row.id, row]));
118
+ return newData.filter((newRow) => {
119
+ const oldRow = oldDataMap.get(newRow.id);
120
+ if (!oldRow)
121
+ return false; // Nový řádek, ne aktualizovaný
122
+ // ✅ OPTIMALIZACE: Shallow comparison místo JSON.stringify (100x rychlejší!)
123
+ return !shallowEqual(oldRow, newRow);
124
+ });
125
+ }, [shallowEqual]);
126
+ React.useImperativeHandle(ref, () => internalRef.current, [internalRef]);
127
+ // Throttle timer pro notifikace - zobrazuje se BĚHEM označování s 100ms throttle
128
+ const notificationThrottleRef = React.useRef(null);
129
+ const notificationLastCallRef = React.useRef(0);
130
+ const lastRangeHashRef = React.useRef(null);
131
+ // ✅ Callback pro přepnutí z full na simple mód
132
+ const handleSwitchToSimple = React.useCallback(() => {
133
+ const gridId = props.gridName || props.id || 'default';
134
+ const key = `aggregation-grid-${gridId}`;
135
+ // Zavřít full notifikaci
136
+ notification.destroy(key);
137
+ // Znovu spočítat a zobrazit simple status bar
138
+ if (internalRef?.current?.api) {
139
+ const ranges = internalRef.current.api.getCellRanges();
140
+ if (ranges && ranges.length > 0 && ranges[0]?.startRow) {
141
+ const messageInfo = Aggregations(internalRef);
142
+ if (messageInfo.count > 1) {
143
+ aggregationDataRef.current = messageInfo;
144
+ }
145
+ }
146
+ }
147
+ activeNotificationModeRef.current = 'simple';
148
+ }, [props, internalRef]);
149
+ // ✅ Helper funkce pro vytvoření custom description s tlačítkem pro přepnutí na simple
150
+ const createNotificationDescription = React.useCallback((messageInfo, showSwitchButton = false) => {
151
+ const bodyContent = notificationBody(messageInfo);
152
+ if (!showSwitchButton) {
153
+ return bodyContent;
154
+ }
155
+ return (_jsxs("div", { children: [bodyContent, _jsx("div", { style: { marginTop: '12px', borderTop: '1px solid #f0f0f0', paddingTop: '8px' }, children: _jsx(Button, { type: "link", size: "small", icon: _jsx(CompressOutlined, {}), onClick: handleSwitchToSimple, style: { padding: 0 }, children: "Zobrazit kompaktn\u00ED re\u017Eim" }) })] }));
156
+ }, [notificationBody, handleSwitchToSimple]);
157
+ // ✅ Callback pro přepnutí z simple na full mód
158
+ const handleSwitchToFull = React.useCallback(() => {
159
+ if (!aggregationDataRef.current)
160
+ return;
161
+ const gridId = props.gridName || props.id || 'default';
162
+ const key = `aggregation-grid-${gridId}`;
163
+ // Zobrazit full notifikaci s aktuálními daty a tlačítkem pro přepnutí
164
+ notification.info({
165
+ key,
166
+ message: notificationHead(aggregationDataRef.current),
167
+ description: createNotificationDescription(aggregationDataRef.current, true),
168
+ duration: 0,
169
+ style,
170
+ placement,
171
+ });
172
+ // Skrýt simple status bar
173
+ aggregationDataRef.current = null;
174
+ activeNotificationModeRef.current = 'full';
175
+ }, [props, notificationHead, createNotificationDescription, style, placement]);
176
+ // ========== PERFORMANCE FIX: Stabilní refs pro updateAggregationNotification ==========
177
+ // ✅ FIX: isSelectingRef je už deklarovaný na řádku 107 jako React.useRef(false)
178
+ const notificationHeadRef = React.useRef(notificationHead);
179
+ const createNotificationDescriptionRef = React.useRef(createNotificationDescription);
180
+ const styleRef = React.useRef(style);
181
+ const placementRef = React.useRef(placement);
182
+ const propsRef = React.useRef(props);
183
+ // ✅ FIX: Odstraněn useEffect pro isSelecting - isSelectingRef je nyní řízený přímo v updatePointerEventsForSelecting
184
+ React.useEffect(() => {
185
+ notificationHeadRef.current = notificationHead;
186
+ }, [notificationHead]);
187
+ React.useEffect(() => {
188
+ createNotificationDescriptionRef.current = createNotificationDescription;
189
+ }, [createNotificationDescription]);
190
+ React.useEffect(() => {
191
+ styleRef.current = style;
192
+ }, [style]);
193
+ React.useEffect(() => {
194
+ placementRef.current = placement;
195
+ }, [placement]);
196
+ React.useEffect(() => {
197
+ propsRef.current = props;
198
+ }, [props]);
199
+ // ✅ OPTIMALIZACE: Helper funkce pro aktualizaci aggregace notifikace s cache check
200
+ // Volá se BĚHEM označování s 100ms throttle pro real-time feedback
201
+ // STABILNÍ callback - používá pouze refs!
202
+ const updateAggregationNotification = React.useCallback((event) => {
203
+ // Pokud je notificationMode 'none', nedělat nic
204
+ if (notificationModeRef.current === 'none') {
205
+ return;
206
+ }
207
+ // Lightweight cache check PŘED voláním Aggregations()
208
+ const ranges = event.api.getCellRanges();
209
+ const currentRangeHash = hashRanges(ranges);
210
+ // Žádné ranges nebo jen jedna buňka - vyčistit vše
211
+ if (!ranges || ranges.length === 0 || !ranges[0]?.startRow) {
212
+ lastRangeHashRef.current = null;
213
+ // V 'full' módu zavřít notifikaci
214
+ if (activeNotificationModeRef.current === 'full') {
215
+ const gridId = propsRef.current.gridName || propsRef.current.id || 'default';
216
+ const key = `aggregation-grid-${gridId}`;
217
+ notification.destroy(key);
218
+ }
219
+ // V 'simple' módu vyčistit aggregationData
220
+ if (activeNotificationModeRef.current === 'simple') {
221
+ aggregationDataRef.current = null;
222
+ }
223
+ return;
224
+ }
225
+ // Cache hit - ranges se nezměnily, skip
226
+ if (currentRangeHash === lastRangeHashRef.current) {
227
+ return;
228
+ }
229
+ // Cache miss - spočítat aggregace
230
+ const messageInfo = Aggregations(internalRef);
231
+ if (messageInfo.count > 1) {
232
+ // Uložit hash pro příští porovnání
233
+ lastRangeHashRef.current = currentRangeHash;
234
+ // Zavolat onAggregationChanged callback pokud existuje
235
+ if (propsRef.current.onAggregationChanged) {
236
+ propsRef.current.onAggregationChanged(messageInfo);
237
+ }
238
+ // Podle aktivního módu zobrazit buď notifikaci nebo aktualizovat status bar
239
+ if (activeNotificationModeRef.current === 'full') {
240
+ // FULL mód - zobrazit plovoucí notifikaci s tlačítkem pro přepnutí na simple
241
+ const gridId = propsRef.current.gridName || propsRef.current.id || 'default';
242
+ const key = `aggregation-grid-${gridId}`;
243
+ const dynamicStyle = {
244
+ ...styleRef.current,
245
+ pointerEvents: isSelectingRef.current ? 'none' : 'auto'
246
+ };
247
+ notification.info({
248
+ key,
249
+ message: notificationHeadRef.current(messageInfo),
250
+ description: createNotificationDescriptionRef.current(messageInfo, true),
251
+ duration: 0,
252
+ style: dynamicStyle,
253
+ placement: placementRef.current,
254
+ });
255
+ }
256
+ else if (activeNotificationModeRef.current === 'simple') {
257
+ // SIMPLE mód - aktualizovat state pro status bar
258
+ aggregationDataRef.current = messageInfo;
259
+ }
260
+ }
261
+ else {
262
+ // Jen jedna buňka - zavřít/vyčistit vše
263
+ lastRangeHashRef.current = null;
264
+ if (activeNotificationModeRef.current === 'full') {
265
+ const gridId = propsRef.current.gridName || propsRef.current.id || 'default';
266
+ const key = `aggregation-grid-${gridId}`;
267
+ notification.destroy(key);
268
+ }
269
+ if (activeNotificationModeRef.current === 'simple') {
270
+ aggregationDataRef.current = null;
271
+ }
272
+ }
273
+ }, [internalRef]); // ✅ Pouze internalRef v dependencies!
274
+ // Helper funkce pro nastavení pointer-events na notifikace
275
+ const setNotificationPointerEvents = React.useCallback((enable) => {
276
+ const notifications = document.querySelectorAll('.ant-notification');
277
+ notifications.forEach((notif) => {
278
+ if (enable) {
279
+ // Obnovit pointer-events na notifikaci
280
+ const original = notif.dataset.originalPointerEvents || 'auto';
281
+ notif.style.pointerEvents = original;
282
+ notif.style.removeProperty('pointer-events');
283
+ delete notif.dataset.originalPointerEvents;
284
+ // Obnovit pointer-events na všechny child elementy
285
+ const allChildren = notif.querySelectorAll('*');
286
+ allChildren.forEach((child) => {
287
+ child.style.removeProperty('pointer-events');
288
+ delete child.dataset.originalPointerEvents;
289
+ });
290
+ }
291
+ else {
292
+ // Zakázat pointer-events na notifikaci
293
+ if (!notif.dataset.originalPointerEvents) {
294
+ notif.dataset.originalPointerEvents = notif.style.pointerEvents || 'auto';
295
+ }
296
+ notif.style.setProperty('pointer-events', 'none', 'important');
297
+ // Zakázat pointer-events na všechny child elementy
298
+ const allChildren = notif.querySelectorAll('*');
299
+ allChildren.forEach((child) => {
300
+ if (!child.dataset.originalPointerEvents) {
301
+ child.dataset.originalPointerEvents = child.style.pointerEvents || '';
302
+ }
303
+ child.style.setProperty('pointer-events', 'none', 'important');
304
+ });
305
+ }
306
+ });
307
+ }, []);
308
+ // ✅ FIX: Helper funkce pro update isSelecting bez state změny (eliminuje rerender)
309
+ const updatePointerEventsForSelecting = React.useCallback((selecting) => {
310
+ isSelectingRef.current = selecting;
311
+ if (selecting) {
312
+ document.body.classList.add('ag-grid-selecting');
313
+ setNotificationPointerEvents(false);
314
+ // KRITICKÉ: Sledovat DOM změny - když se objeví nová notifikace během označování
315
+ const observer = new MutationObserver((mutations) => {
316
+ mutations.forEach((mutation) => {
317
+ mutation.addedNodes.forEach((node) => {
318
+ if (node.nodeType === 1) {
319
+ if (node.classList?.contains('ant-notification') ||
320
+ node.querySelector?.('.ant-notification')) {
321
+ setNotificationPointerEvents(false);
322
+ }
323
+ }
324
+ });
325
+ });
326
+ });
327
+ observer.observe(document.body, {
328
+ childList: true,
329
+ subtree: true
330
+ });
331
+ // Uložit observer do ref pro případný cleanup
332
+ if (!updatePointerEventsForSelecting.observer) {
333
+ updatePointerEventsForSelecting.observer = observer;
334
+ }
335
+ }
336
+ else {
337
+ document.body.classList.remove('ag-grid-selecting');
338
+ // Cleanup observer
339
+ if (updatePointerEventsForSelecting.observer) {
340
+ updatePointerEventsForSelecting.observer.disconnect();
341
+ updatePointerEventsForSelecting.observer = null;
342
+ }
343
+ setTimeout(() => setNotificationPointerEvents(true), 100);
344
+ }
345
+ }, [setNotificationPointerEvents]);
346
+ // Detekce konce označování pomocí mouseup event
347
+ React.useEffect(() => {
348
+ const handleMouseUp = () => {
349
+ // ✅ FIX: Ukončit isSelecting pomocí ref (bez state update → žádný rerender)
350
+ setTimeout(() => {
351
+ updatePointerEventsForSelecting(false);
352
+ // ✅ FIX: Zkontrolovat jestli jsou stále nějaké ranges, pokud ne - vyčistit status bar
353
+ if (internalRef?.current?.api && activeNotificationModeRef.current === 'simple') {
354
+ const ranges = internalRef.current.api.getCellRanges();
355
+ if (!ranges || ranges.length === 0 || !ranges[0]?.startRow) {
356
+ aggregationDataRef.current = null;
357
+ // Reset na původní notificationMode když jsou všechny buňky odznačeny
358
+ activeNotificationModeRef.current = notificationMode;
359
+ }
360
+ }
361
+ }, 50);
362
+ };
363
+ document.addEventListener('mouseup', handleMouseUp);
364
+ document.addEventListener('touchend', handleMouseUp); // Pro touch zařízení
365
+ return () => {
366
+ document.removeEventListener('mouseup', handleMouseUp);
367
+ document.removeEventListener('touchend', handleMouseUp);
368
+ };
369
+ }, [notificationMode, internalRef, updatePointerEventsForSelecting]);
370
+ // Cleanup notifikací a timerů při zničení komponenty
371
+ React.useEffect(() => {
372
+ return () => {
373
+ // Clear throttle timer
374
+ if (notificationThrottleRef.current) {
375
+ clearTimeout(notificationThrottleRef.current);
376
+ }
377
+ if (notificationMode === 'full') {
378
+ const gridId = props.gridName || props.id || 'default';
379
+ const key = `aggregation-grid-${gridId}`;
380
+ notification.destroy(key);
381
+ }
382
+ // Cleanup SignalR transaction callback při unmount
383
+ if (queryKey && window.agGridTransactionCallbacks) {
384
+ delete window.agGridTransactionCallbacks[queryKey];
385
+ }
386
+ };
387
+ }, [notificationMode, props.gridName, props.id, queryKey]);
388
+ React.useEffect(() => {
389
+ // VYPNUTO: Cell flash je globálně vypnutý
390
+ return;
391
+ if (!newRowFlash && !updatedRowFlash)
392
+ return;
393
+ const previousRowData = previousRowDataRef.current;
394
+ const addedRows = newRowFlash ? findNewRows(previousRowData, rowData) : [];
395
+ const updatedRows = updatedRowFlash ? findUpdatedRows(previousRowData, rowData) : [];
396
+ if (addedRows.length > 0 || updatedRows.length > 0) {
397
+ setTimeout(() => {
398
+ try {
399
+ // Bezpečnostní kontrola API dostupnosti
400
+ if (!internalRef.current?.api || internalRef.current.api.isDestroyed?.()) {
401
+ return;
402
+ }
403
+ // Modern AG-Grid (33+): getColumnState() moved to main api
404
+ const columnApi = internalRef.current?.columnApi || internalRef.current?.api;
405
+ if (!columnApi?.getColumnState) {
406
+ return;
407
+ }
408
+ const columnStates = columnApi.getColumnState();
409
+ const allColumns = columnStates
410
+ .filter(colState => colState.colId) // Filtrujeme pouze platné colId
411
+ .map((colState) => colState.colId);
412
+ // Kontrola, že máme platné sloupce
413
+ if (allColumns.length === 0) {
414
+ return;
415
+ }
416
+ // Flash efekt pro nové řádky (používá defaultní zelená barva AG Grid)
417
+ if (addedRows.length > 0) {
418
+ const newRowNodes = [];
419
+ internalRef.current.api.forEachNode((node) => {
420
+ if (addedRows.some((row) => row.id === node.data.id)) {
421
+ newRowNodes.push(node);
422
+ }
423
+ });
424
+ if (newRowNodes.length > 0) {
425
+ internalRef.current.api.flashCells({
426
+ rowNodes: newRowNodes,
427
+ columns: allColumns,
428
+ flashDelay: 0,
429
+ fadeDelay: 1000,
430
+ });
431
+ }
432
+ }
433
+ // Flash efekt pro aktualizované řádky (modrá barva)
434
+ if (updatedRows.length > 0) {
435
+ const updatedRowNodes = [];
436
+ internalRef.current.api.forEachNode((node) => {
437
+ if (updatedRows.some((row) => row.id === node.data.id)) {
438
+ updatedRowNodes.push(node);
439
+ }
440
+ });
441
+ if (updatedRowNodes.length > 0) {
442
+ // Použijeme vlastní CSS animaci pro modrou flash
443
+ updatedRowNodes.forEach(node => {
444
+ const rowElement = node.eGridRow || document.querySelector(`[row-id="${node.data.id}"]`);
445
+ if (rowElement) {
446
+ rowElement.classList.add('ag-row-flash-updated');
447
+ setTimeout(() => {
448
+ rowElement.classList.remove('ag-row-flash-updated');
449
+ }, 1000);
450
+ }
451
+ });
452
+ }
453
+ }
454
+ }
455
+ catch (error) {
456
+ // Ignorujeme chybu a pokračujeme bez crash aplikace
457
+ }
458
+ }, 100); // Zvýšený timeout pro stabilizaci gridu
459
+ }
460
+ previousRowDataRef.current = rowData;
461
+ }, [rowData, newRowFlash, updatedRowFlash]);
462
+ // ========== PERFORMANCE FIX: Stabilní ref pattern pro callbacks ==========
463
+ // Refs pro aktuální hodnoty - zabraňuje re-creation RhPlusRangeSelectionChanged při změně stavu
464
+ const notificationModeRef = React.useRef(notificationMode);
465
+ const enableBulkEditRef = React.useRef(enableBulkEdit);
466
+ const handleRangeChangeRef = React.useRef(handleRangeChange);
467
+ const onRangeSelectionChangedRef = React.useRef(props.onRangeSelectionChanged);
468
+ const updateAggregationNotificationRef = React.useRef(updateAggregationNotification);
469
+ // ✅ FIX #12: Refs pro grid layout handlery (eliminuje rerendery při změně props)
470
+ const onColumnMovedRef = React.useRef(props.onColumnMoved);
471
+ const onDragStoppedRef = React.useRef(props.onDragStopped);
472
+ const onColumnVisibleRef = React.useRef(props.onColumnVisible);
473
+ const onColumnPinnedRef = React.useRef(props.onColumnPinned);
474
+ const onColumnResizedRef = React.useRef(props.onColumnResized);
475
+ // Aktualizovat refs při změně hodnot
476
+ React.useEffect(() => {
477
+ notificationModeRef.current = notificationMode;
478
+ }, [notificationMode]);
479
+ React.useEffect(() => {
480
+ enableBulkEditRef.current = enableBulkEdit;
481
+ }, [enableBulkEdit]);
482
+ React.useEffect(() => {
483
+ handleRangeChangeRef.current = handleRangeChange;
484
+ }, [handleRangeChange]);
485
+ React.useEffect(() => {
486
+ onRangeSelectionChangedRef.current = props.onRangeSelectionChanged;
487
+ }, [props.onRangeSelectionChanged]);
488
+ React.useEffect(() => {
489
+ updateAggregationNotificationRef.current = updateAggregationNotification;
490
+ }, [updateAggregationNotification]);
491
+ // ✅ FIX #12: Aktualizovat grid layout handler refs
492
+ React.useEffect(() => {
493
+ onColumnMovedRef.current = props.onColumnMoved;
494
+ }, [props.onColumnMoved]);
495
+ React.useEffect(() => {
496
+ onDragStoppedRef.current = props.onDragStopped;
497
+ }, [props.onDragStopped]);
498
+ React.useEffect(() => {
499
+ onColumnVisibleRef.current = props.onColumnVisible;
500
+ }, [props.onColumnVisible]);
501
+ React.useEffect(() => {
502
+ onColumnPinnedRef.current = props.onColumnPinned;
503
+ }, [props.onColumnPinned]);
504
+ React.useEffect(() => {
505
+ onColumnResizedRef.current = props.onColumnResized;
506
+ }, [props.onColumnResized]);
507
+ // Stabilní callback s prázdnými dependencies - používá pouze refs
508
+ const RhPlusRangeSelectionChanged = React.useCallback((event) => {
509
+ // ✅ FIX: Detekovat začátek označování pomocí ref (bez state update → žádný rerender)
510
+ updatePointerEventsForSelecting(true);
511
+ // 1. ✅ OPTIMALIZACE: Zobrazení notifikace BĚHEM označování s THROTTLE
512
+ // Simple mode: 300ms throttle (méně častá aktualizace, lepší výkon)
513
+ // Full mode: 100ms throttle (rychlejší feedback, plovoucí notifikace je levná)
514
+ if (notificationModeRef.current !== 'none') {
515
+ const throttleInterval = notificationModeRef.current === 'simple' ? 300 : 100;
516
+ const now = Date.now();
517
+ const timeSinceLastCall = now - notificationLastCallRef.current;
518
+ // První volání NEBO uplynul throttle interval
519
+ if (timeSinceLastCall >= throttleInterval) {
520
+ // Okamžité volání
521
+ notificationLastCallRef.current = now;
522
+ if (internalRef?.current) {
523
+ updateAggregationNotificationRef.current(event);
524
+ }
525
+ }
526
+ else {
527
+ // Naplánovat volání za zbývající čas (trailing edge)
528
+ if (notificationThrottleRef.current) {
529
+ clearTimeout(notificationThrottleRef.current);
530
+ }
531
+ notificationThrottleRef.current = setTimeout(() => {
532
+ notificationLastCallRef.current = Date.now();
533
+ if (internalRef?.current) {
534
+ updateAggregationNotificationRef.current(event);
535
+ }
536
+ }, throttleInterval - timeSinceLastCall);
537
+ }
538
+ }
539
+ // 2. ✅ OPTIMALIZACE: Bulk edit handler BEZ debounce - okamžité zobrazení ikony
540
+ // Lightweight validace v useBulkCellEdit zajistí okamžité zobrazení
541
+ // Těžká validace proběhne s 15ms debounce uvnitř useBulkCellEdit
542
+ if (enableBulkEditRef.current) {
543
+ handleRangeChangeRef.current(event);
544
+ }
545
+ // 3. Custom onRangeSelectionChanged callback - bez debounce
546
+ if (onRangeSelectionChangedRef.current) {
547
+ onRangeSelectionChangedRef.current(event);
548
+ }
549
+ }, [] // ✅ PRÁZDNÉ dependencies - stabilní reference!
550
+ );
551
+ // ✅ FIX #12: Stabilní wrappery pro grid layout handlery (prázdné dependencies)
552
+ const stableOnColumnMoved = React.useCallback((params) => {
553
+ if (onColumnMovedRef.current) {
554
+ onColumnMovedRef.current(params);
555
+ }
556
+ }, []);
557
+ const stableOnDragStopped = React.useCallback((params) => {
558
+ if (onDragStoppedRef.current) {
559
+ onDragStoppedRef.current(params);
560
+ }
561
+ }, []);
562
+ const stableOnColumnVisible = React.useCallback((params) => {
563
+ if (onColumnVisibleRef.current) {
564
+ onColumnVisibleRef.current(params);
565
+ }
566
+ }, []);
567
+ const stableOnColumnPinned = React.useCallback((params) => {
568
+ if (onColumnPinnedRef.current) {
569
+ onColumnPinnedRef.current(params);
570
+ }
571
+ }, []);
572
+ const stableOnColumnResized = React.useCallback((params) => {
573
+ if (onColumnResizedRef.current) {
574
+ onColumnResizedRef.current(params);
575
+ }
576
+ }, []);
577
+ const AgGridOnGridReady = (event, options) => {
578
+ if (onGridReady) {
579
+ onGridReady(event, options);
580
+ }
581
+ // Nejprve nastavíme API reference pro interní použití
582
+ if (internalRef.current) {
583
+ internalRef.current.api = event.api;
584
+ internalRef.current.columnApi = event.columnApi || event.api; // fallback for modern AG-Grid
585
+ }
586
+ // Nastavíme API ready flag pro quick filter useEffect
587
+ setIsApiReady(true);
588
+ // Registruj callback pro AG Grid transactions (SignalR optimalizace)
589
+ // Inicializace globálního registru pro více AG-Grid instancí
590
+ if (!window.agGridTransactionCallbacks) {
591
+ window.agGridTransactionCallbacks = {};
592
+ }
593
+ // Registrace callbacku pro tuto konkrétní AG-Grid instanci (podle queryKey)
594
+ if (event.api && queryKey) {
595
+ window.agGridTransactionCallbacks[queryKey] = (transactionData) => {
596
+ try {
597
+ if (!event.api || event.api.isDestroyed?.())
598
+ return;
599
+ const { operation, records } = transactionData;
600
+ switch (operation) {
601
+ case 'add':
602
+ // Nastavíme flag _rh_plus_ag_grid_signal_new (NE _rh_plus_ag_grid_new_item),
603
+ // aby postSort přesunul řádek na začátek, ale renderery obsah nezahovaly
604
+ const addRecords = records.map(r => ({ ...r, _rh_plus_ag_grid_signal_new: true }));
605
+ event.api.applyTransaction({ add: addRecords, addIndex: 0 });
606
+ // Flash efekt pro nové řádky + po 5s odebrat signal flag a re-sort
607
+ setTimeout(() => {
608
+ records.forEach(record => {
609
+ const rowNode = event.api.getRowNode(record.id);
610
+ if (rowNode) {
611
+ if (rowNode.rowElement) {
612
+ rowNode.rowElement.classList.add('ag-row-flash-created');
613
+ setTimeout(() => {
614
+ rowNode.rowElement.classList.remove('ag-row-flash-created');
615
+ }, 1000);
616
+ }
617
+ // Po 5 sekundách odebrat signal flag a refreshnout sort
618
+ setTimeout(() => {
619
+ if (rowNode.data) {
620
+ delete rowNode.data._rh_plus_ag_grid_signal_new;
621
+ // Refresh sort, aby se řádek zařadil podle aktuálního řazení
622
+ if (event.api && !event.api.isDestroyed?.()) {
623
+ event.api.refreshClientSideRowModel('sort');
624
+ }
625
+ }
626
+ }, 5000);
627
+ }
628
+ });
629
+ }, 100);
630
+ break;
631
+ case 'update':
632
+ event.api.applyTransaction({ update: records });
633
+ // Flash efekt pro aktualizované řádky
634
+ setTimeout(() => {
635
+ records.forEach(record => {
636
+ const rowNode = event.api.getRowNode(record.id);
637
+ if (rowNode && rowNode.rowElement) {
638
+ rowNode.rowElement.classList.add('ag-row-flash-updated');
639
+ setTimeout(() => {
640
+ rowNode.rowElement.classList.remove('ag-row-flash-updated');
641
+ }, 1000);
642
+ }
643
+ });
644
+ }, 100);
645
+ break;
646
+ case 'remove':
647
+ // Flash efekt před smazáním
648
+ records.forEach(record => {
649
+ const rowNode = event.api.getRowNode(record.id);
650
+ if (rowNode && rowNode.rowElement) {
651
+ rowNode.rowElement.classList.add('ag-row-flash-deleted');
652
+ }
653
+ });
654
+ setTimeout(() => {
655
+ event.api.applyTransaction({ remove: records });
656
+ }, 500); // Krátké zpoždění pro zobrazení flash efektu
657
+ break;
658
+ }
659
+ }
660
+ catch (error) {
661
+ // Ignorujeme chyby
662
+ }
663
+ };
664
+ }
665
+ // Pak zavoláme parent onGridReady handler, pokud existuje
666
+ // Toto je kritické pro správné fungování bit/ui/grid a GridLayout
667
+ if (options.onGridReady) {
668
+ try {
669
+ options.onGridReady(event);
670
+ }
671
+ catch (error) {
672
+ // Error handling without console output
673
+ }
674
+ }
675
+ // Nakonec nastavíme grid ready state s timeout
676
+ setTimeout(() => {
677
+ setIsGridReady(true);
678
+ }, 1000);
679
+ };
680
+ const components = React.useMemo(() => {
681
+ return {
682
+ checkboxRenderer: CheckboxRenderer,
683
+ selectRenderer: SelectRenderer,
684
+ countrySelectRenderer: CountrySelectRenderer,
685
+ booleanRenderer: BooleanRenderer,
686
+ buttonRenderer: ButtonRenderer,
687
+ iconRenderer: IconRenderer,
688
+ imageRenderer: ImageRenderer,
689
+ stateRenderer: StateRenderer,
690
+ objectRenderer: ObjectRenderer,
691
+ linkRenderer: LinkRenderer,
692
+ ...props.frameworkComponents,
693
+ };
694
+ }, [props.frameworkComponents]);
695
+ // ========== PERFORMANCE OPTIMIZATION: Memoizované event handlers ==========
696
+ const memoizedOnCellEditingStarted = React.useCallback((event) => RhPlusOnCellEditingStarted(event, props), [props.onCellEditingStarted]);
697
+ const memoizedOnCellDoubleClicked = React.useCallback((event) => RhPlusOnCellDoubleClicked(event, props), [props.onCellDoubleClicked]);
698
+ const memoizedOnCellValueChanged = React.useCallback((event) => RhPlusOnCellValueChanged(event, props), [props.onCellValueChanged]);
699
+ const memoizedPostSort = React.useCallback((event) => AgGridPostSort(event, props), [props.postSort]);
700
+ const memoizedOnGridReady = React.useCallback((event, options) => AgGridOnGridReady(event, props), [onGridReady]);
701
+ const memoizedOnRowDataChanged = React.useCallback((event) => AgGridOnRowDataChanged(event, props), [props.onRowDataChanged]);
702
+ const memoizedOnRowDataUpdated = React.useCallback((event) => AgGridOnRowDataUpdated(event, props), [props.onRowDataUpdated]);
703
+ // Memoizovaný context object
704
+ // ✅ OPTIMALIZACE: Použít pouze relevantní props pro context - neměnit při změně props
705
+ const memoizedContext = React.useMemo(() => ({
706
+ componentParent: props
707
+ }), [props.context, props.gridName, props.id]);
708
+ // Memoizovaný defaultColDef
709
+ const memoizedDefaultColDef = React.useMemo(() => ({
710
+ filter: 'agTextColumnFilter',
711
+ floatingFilter: true,
712
+ filterParams: {
713
+ defaultOption: 'contains',
714
+ },
715
+ ...props.defaultColDef,
716
+ suppressHeaderMenuButton: true,
717
+ suppressHeaderFilterButton: true,
718
+ suppressMenu: true,
719
+ // ✅ FIX AG-Grid v35: Bezpečné zpracování null hodnot v Quick Filter
720
+ // AG-Grid v35 změnil implementaci Quick Filter - nyní volá .toString() na hodnotách buněk bez null check
721
+ // Tento callback zajistí že nikdy nedojde k chybě "Cannot read properties of null (reading 'toString')"
722
+ getQuickFilterText: (params) => {
723
+ const value = params.value;
724
+ // Null/undefined → prázdný string (bez chyby)
725
+ if (value == null)
726
+ return '';
727
+ // Objekty a pole → JSON string
728
+ if (typeof value === 'object') {
729
+ try {
730
+ return JSON.stringify(value);
731
+ }
732
+ catch {
733
+ // Cirkulární reference nebo jiná chyba při serializaci → prázdný string
734
+ return '';
735
+ }
736
+ }
737
+ // Primitivní typy → toString
738
+ return value.toString();
739
+ },
740
+ }), [props.defaultColDef]);
741
+ // ========== PERFORMANCE FIX: Memoizovat columnDefs ==========
742
+ // AgGridColumns vrací nový array při každém volání, i když jsou vstupy stejné
743
+ const memoizedColumnDefs = React.useMemo(() => {
744
+ return AgGridColumns(props.columnDefs, props);
745
+ }, [props.columnDefs, props.getRowId, props.frameworkComponents]);
746
+ // ========== CRITICAL FIX: Stabilní allGridProps objekt pomocí ref ==========
747
+ // Problém: Jakékoli použití useMemo vytváří nový objekt při změně dependencies
748
+ // Řešení: Použít ref pro VŽDY stejný objekt
749
+ // AG-Grid САМО detekuje změny rowData a columnDefs → NENÍ potřeba forceUpdate!
750
+ const allGridPropsRef = React.useRef(null);
751
+ // Inicializace objektu
752
+ if (!allGridPropsRef.current) {
753
+ allGridPropsRef.current = {};
754
+ }
755
+ // ✅ Aktualizovat props v EXISTUJÍCÍM objektu (mutace)
756
+ // AG Grid interně detekuje změny props, nepotřebuje nový objekt
757
+ allGridPropsRef.current.ref = internalRef;
758
+ allGridPropsRef.current.rowData = props.rowData;
759
+ allGridPropsRef.current.getRowId = props.getRowId;
760
+ allGridPropsRef.current.theme = themeObject;
761
+ allGridPropsRef.current.columnDefs = memoizedColumnDefs;
762
+ allGridPropsRef.current.defaultColDef = memoizedDefaultColDef;
763
+ allGridPropsRef.current.onCellEditingStarted = memoizedOnCellEditingStarted;
764
+ allGridPropsRef.current.onCellDoubleClicked = memoizedOnCellDoubleClicked;
765
+ allGridPropsRef.current.onCellValueChanged = memoizedOnCellValueChanged;
766
+ allGridPropsRef.current.postSort = memoizedPostSort;
767
+ allGridPropsRef.current.onGridReady = memoizedOnGridReady;
768
+ allGridPropsRef.current.onRowDataChanged = memoizedOnRowDataChanged;
769
+ allGridPropsRef.current.onRowDataUpdated = memoizedOnRowDataUpdated;
770
+ allGridPropsRef.current.onRangeSelectionChanged = RhPlusRangeSelectionChanged;
771
+ allGridPropsRef.current.context = memoizedContext;
772
+ allGridPropsRef.current.components = components;
773
+ // Další AG Grid props
774
+ allGridPropsRef.current.rowModelType = props.rowModelType;
775
+ allGridPropsRef.current.rowSelection = props.rowSelection;
776
+ allGridPropsRef.current.enableRangeSelection = props.enableRangeSelection;
777
+ allGridPropsRef.current.enableRangeHandle = props.enableRangeHandle;
778
+ allGridPropsRef.current.enableFillHandle = props.enableFillHandle;
779
+ allGridPropsRef.current.suppressRowClickSelection = props.suppressRowClickSelection;
780
+ allGridPropsRef.current.singleClickEdit = props.singleClickEdit;
781
+ allGridPropsRef.current.stopEditingWhenCellsLoseFocus = props.stopEditingWhenCellsLoseFocus;
782
+ allGridPropsRef.current.rowClass = props.rowClass;
783
+ allGridPropsRef.current.rowStyle = props.rowStyle;
784
+ allGridPropsRef.current.getRowClass = props.getRowClass;
785
+ allGridPropsRef.current.getRowStyle = props.getRowStyle;
786
+ allGridPropsRef.current.animateRows = props.animateRows;
787
+ allGridPropsRef.current.suppressCellFocus = props.suppressCellFocus;
788
+ allGridPropsRef.current.suppressMenuHide = props.suppressMenuHide;
789
+ allGridPropsRef.current.enableCellTextSelection = props.enableCellTextSelection;
790
+ allGridPropsRef.current.ensureDomOrder = props.ensureDomOrder;
791
+ allGridPropsRef.current.suppressRowTransform = props.suppressRowTransform;
792
+ allGridPropsRef.current.suppressColumnVirtualisation = props.suppressColumnVirtualisation;
793
+ allGridPropsRef.current.suppressRowVirtualisation = props.suppressRowVirtualisation;
794
+ allGridPropsRef.current.tooltipShowDelay = props.tooltipShowDelay;
795
+ allGridPropsRef.current.tooltipHideDelay = props.tooltipHideDelay;
796
+ allGridPropsRef.current.tooltipMouseTrack = props.tooltipMouseTrack;
797
+ allGridPropsRef.current.gridId = props.gridId;
798
+ allGridPropsRef.current.id = props.id;
799
+ allGridPropsRef.current.gridName = props.gridName;
800
+ allGridPropsRef.current.getContextMenuItems = props.getContextMenuItems;
801
+ allGridPropsRef.current.rowClassRules = props.rowClassRules;
802
+ allGridPropsRef.current.isRowSelectable = props.isRowSelectable;
803
+ // Grid Layout event handlers - stabilní wrappery (eliminuje rerendery)
804
+ // ✅ FIX #12: Používáme stabilní wrappery místo props → eliminuje rerendery při změně props
805
+ allGridPropsRef.current.onColumnMoved = stableOnColumnMoved;
806
+ allGridPropsRef.current.onDragStopped = stableOnDragStopped;
807
+ allGridPropsRef.current.onColumnVisible = stableOnColumnVisible;
808
+ allGridPropsRef.current.onColumnPinned = stableOnColumnPinned;
809
+ allGridPropsRef.current.onColumnResized = stableOnColumnResized;
810
+ // ✅ gridOptions support - spread additional AG-Grid props
811
+ // Přidává POUZE hodnoty které ještě NEJSOU nastaveny výše (nejnižší priorita)
812
+ if (props.gridOptions && typeof props.gridOptions === 'object') {
813
+ for (const key in props.gridOptions) {
814
+ if (props.gridOptions[key] !== undefined && allGridPropsRef.current[key] === undefined) {
815
+ allGridPropsRef.current[key] = props.gridOptions[key];
816
+ }
817
+ }
818
+ }
819
+ // ✅ AG-Grid САМО detekuje změny rowData a columnDefs
820
+ // NENÍ potřeba forceUpdate - AG-Grid reaguje na změny v props automaticky!
821
+ // ✅ Vracíme VŽDY stejný objekt (stabilní reference)
822
+ const allGridProps = allGridPropsRef.current;
823
+ // State pro sledování, kdy je API ready
824
+ const [isApiReady, setIsApiReady] = React.useState(false);
825
+ // Nastavení Quick Filter přes API (podle AG-Grid v33 dokumentace)
826
+ // Tento useEffect se volá při změně quickFilterText NEBO když API je ready
827
+ React.useEffect(() => {
828
+ if (internalRef.current?.api && !internalRef.current.api.isDestroyed?.()) {
829
+ // ✅ FIX AG-Grid v35: Zajistit že quickFilterText není null/undefined
830
+ // AG-Grid v35 interně volá .toString() na této hodnotě bez null checku
831
+ const safeQuickFilterText = quickFilterText ?? '';
832
+ internalRef.current.api.setGridOption("quickFilterText", safeQuickFilterText);
833
+ }
834
+ }, [quickFilterText, isApiReady]);
835
+ // Status bar se zobrazuje pouze v simple mode
836
+ const showStatusBar = notificationMode === 'simple' && aggregationDataRef.current;
837
+ // ✅ FIX: Rezervovat místo pro status bar pouze když má data
838
+ // Grid se dynamicky rozšíří/zmenší podle přítomnosti status baru
839
+ const shouldReserveSpace = showStatusBar;
840
+ const gridContainerStyle = shouldReserveSpace
841
+ ? { height: `calc(100% - ${statusBarHeight}px)`, width: '100%', position: 'relative' }
842
+ : { height: '100%', width: '100%', position: 'relative' };
843
+ return (_jsxs("div", { style: { height: '100%', width: '100%', position: 'relative' }, children: [_jsx("div", { style: gridContainerStyle, children: _jsx(AgGridReact, { ...allGridProps }) }), shouldReserveSpace && (_jsx("div", { style: {
844
+ position: 'absolute',
845
+ bottom: 0,
846
+ left: 0,
847
+ right: 0,
848
+ height: `${statusBarHeight}px`,
849
+ opacity: showStatusBar ? 1 : 0,
850
+ visibility: showStatusBar ? 'visible' : 'hidden',
851
+ pointerEvents: showStatusBar ? 'auto' : 'none',
852
+ zIndex: 10,
853
+ // GPU acceleration pro plynulejší zobrazení
854
+ transform: 'translateZ(0)',
855
+ willChange: 'opacity'
856
+ }, children: _jsx(AggregationStatusBar, { data: aggregationDataRef.current || {}, metrics: statusBarMetrics, height: statusBarHeight, onSwitchToFull: handleSwitchToFull }) })), enableBulkEdit && floatingButton.visible && (_jsx(BulkEditButton, { visible: floatingButton.visible, position: floatingButton.position, range: floatingButton.range, column: floatingButton.column, cellCount: floatingButton.cellCount, rowsContainer: floatingButton.rowsContainer, gridApi: internalRef.current?.api, editPopover: editPopover, onOpenPopover: handleOpenPopover, onValueChange: handleValueChange, onSubmit: handleSubmitEdit, onCancel: handleCancelEdit }))] }));
857
+ });
858
+ // ========== PERFORMANCE OPTIMIZATION: React.memo ==========
859
+ // Refactored: Používá createGridComparison utility místo manuálního deep comparison
860
+ // Eliminováno ~120 řádků duplicitního kódu, zachována stejná funkcionalita
861
+ // Diagnostic mode: zapnutý pouze ve development módu
862
+ export default React.memo(AgGrid, createGridComparison(process.env.NODE_ENV !== 'production' // Diagnostic mode pouze ve development
863
+ ));
864
+ export { useBulkCellEdit, BulkEditButton, BulkEditPopover, BulkEditSelect, BulkEditDatePicker, BulkEditModule, BulkEditInput, BulkEditTagsSelect } from './BulkEdit';
865
+ export { default as CheckboxRenderer } from './Renderers/CheckboxRenderer';
866
+ export * from './Renderers';
867
+ export * from './Editors';
868
+ //# sourceMappingURL=index.js.map