@bit.rhplus/ag-grid 0.0.37 → 0.0.38

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 (36) hide show
  1. package/Aggregations.js +26 -3
  2. package/BulkEdit/BulkEditButton.jsx +149 -0
  3. package/BulkEdit/BulkEditPopover.jsx +301 -0
  4. package/BulkEdit/BulkEditSelect.jsx +80 -0
  5. package/BulkEdit/index.js +5 -0
  6. package/BulkEdit/useBulkCellEdit.js +328 -0
  7. package/BulkEdit/utils.js +532 -0
  8. package/Renderers/StateRenderer.jsx +17 -11
  9. package/dist/Aggregations.d.ts +1 -1
  10. package/dist/Aggregations.js +19 -2
  11. package/dist/Aggregations.js.map +1 -1
  12. package/dist/BulkEdit/BulkEditButton.d.ts +27 -0
  13. package/dist/BulkEdit/BulkEditButton.js +82 -0
  14. package/dist/BulkEdit/BulkEditButton.js.map +1 -0
  15. package/dist/BulkEdit/BulkEditPopover.d.ts +27 -0
  16. package/dist/BulkEdit/BulkEditPopover.js +122 -0
  17. package/dist/BulkEdit/BulkEditPopover.js.map +1 -0
  18. package/dist/BulkEdit/BulkEditSelect.d.ts +14 -0
  19. package/dist/BulkEdit/BulkEditSelect.js +31 -0
  20. package/dist/BulkEdit/BulkEditSelect.js.map +1 -0
  21. package/dist/BulkEdit/index.d.ts +4 -0
  22. package/dist/BulkEdit/index.js +6 -0
  23. package/dist/BulkEdit/index.js.map +1 -0
  24. package/dist/BulkEdit/useBulkCellEdit.d.ts +1 -0
  25. package/dist/BulkEdit/useBulkCellEdit.js +262 -0
  26. package/dist/BulkEdit/useBulkCellEdit.js.map +1 -0
  27. package/dist/BulkEdit/utils.d.ts +7 -0
  28. package/dist/BulkEdit/utils.js +472 -0
  29. package/dist/BulkEdit/utils.js.map +1 -0
  30. package/dist/Renderers/StateRenderer.js +16 -11
  31. package/dist/Renderers/StateRenderer.js.map +1 -1
  32. package/dist/index.js +63 -25
  33. package/dist/index.js.map +1 -1
  34. package/index.jsx +103 -24
  35. package/package.json +5 -4
  36. /package/dist/{preview-1760103803977.js → preview-1760387336452.js} +0 -0
@@ -0,0 +1,328 @@
1
+ /* eslint-disable */
2
+ import { useState, useCallback, useEffect, useRef } from 'react';
3
+ import {
4
+ validateRangeEditable,
5
+ getLastCellPosition,
6
+ applyBulkChanges,
7
+ applyBulkChangesWithApi,
8
+ } from './utils';
9
+ import useData from '@bit.rhplus/data';
10
+
11
+ /**
12
+ * Hook pro bulk cell edit funkcionalitu v AG Grid
13
+ * @param {Object} gridRef - Reference na AG Grid
14
+ * @param {Object} options - Konfigurace bulk edit
15
+ * @returns {Object} - State a handlery pro bulk edit
16
+ */
17
+ export const useBulkCellEdit = (gridRef, options = {}) => {
18
+ const {
19
+ enabled = false,
20
+ minCells = 2,
21
+ allowMultiColumn = false,
22
+ buttonPosition = 'bottom-right',
23
+ buttonOffset = { x: 5, y: 5 },
24
+ accessToken = null,
25
+ onBulkEditStart,
26
+ onBulkEditComplete,
27
+ } = options;
28
+
29
+ const { fetchDataUIAsync } = useData();
30
+
31
+ const [floatingButton, setFloatingButton] = useState({
32
+ visible: false,
33
+ position: null,
34
+ range: null,
35
+ column: null,
36
+ cellCount: 0,
37
+ });
38
+
39
+ const [editPopover, setEditPopover] = useState({
40
+ visible: false,
41
+ value: '',
42
+ loading: false,
43
+ error: null,
44
+ });
45
+
46
+ const scrollListenerRef = useRef(null);
47
+ const rangeTimeoutRef = useRef(null);
48
+
49
+ /**
50
+ * Handler pro změnu range selection
51
+ */
52
+ const handleRangeChange = useCallback(
53
+ (event) => {
54
+ // Clear předchozí timeout
55
+ if (rangeTimeoutRef.current) {
56
+ clearTimeout(rangeTimeoutRef.current);
57
+ }
58
+
59
+ // 1. Kontrola enableBulkEdit
60
+ if (!enabled) {
61
+ setFloatingButton({ visible: false });
62
+ return;
63
+ }
64
+
65
+ const ranges = event.api.getCellRanges();
66
+
67
+ // 2. Kontrola existence ranges
68
+ if (!ranges || ranges.length === 0) {
69
+ setFloatingButton({ visible: false });
70
+ return;
71
+ }
72
+
73
+ const range = ranges[0];
74
+
75
+ // 3. Kontrola single column (pokud není povoleno multi-column)
76
+ if (!allowMultiColumn && range.columns.length !== 1) {
77
+ setFloatingButton({ visible: false });
78
+ return;
79
+ }
80
+
81
+ // 4. Výpočet počtu buněk
82
+ const cellCount =
83
+ Math.abs(range.endRow.rowIndex - range.startRow.rowIndex) + 1;
84
+
85
+ // 5. Kontrola min počtu buněk
86
+ if (cellCount < minCells) {
87
+ setFloatingButton({ visible: false });
88
+ return;
89
+ }
90
+
91
+ // 6. Kontrola editable sloupce
92
+ if (!validateRangeEditable(range, event.api)) {
93
+ setFloatingButton({ visible: false });
94
+ return;
95
+ }
96
+
97
+ // 7-9. Debounce výpočet pozice a zobrazení buttonu (500ms)
98
+ rangeTimeoutRef.current = setTimeout(() => {
99
+ const cellPosition = getLastCellPosition(range, event.api);
100
+ if (!cellPosition) {
101
+ setFloatingButton({ visible: false });
102
+ return;
103
+ }
104
+
105
+ let buttonX, buttonY;
106
+
107
+ switch (buttonPosition) {
108
+ case 'bottom-right':
109
+ buttonX = cellPosition.right + buttonOffset.x;
110
+ buttonY = cellPosition.bottom + buttonOffset.y;
111
+ break;
112
+ case 'bottom-left':
113
+ buttonX = cellPosition.left - buttonOffset.x;
114
+ buttonY = cellPosition.bottom + buttonOffset.y;
115
+ break;
116
+ case 'top-right':
117
+ buttonX = cellPosition.right + buttonOffset.x;
118
+ buttonY = cellPosition.top - buttonOffset.y;
119
+ break;
120
+ case 'top-left':
121
+ buttonX = cellPosition.left - buttonOffset.x;
122
+ buttonY = cellPosition.top - buttonOffset.y;
123
+ break;
124
+ default:
125
+ buttonX = cellPosition.right + buttonOffset.x;
126
+ buttonY = cellPosition.bottom + buttonOffset.y;
127
+ }
128
+
129
+ setFloatingButton({
130
+ visible: true,
131
+ position: { x: buttonX, y: buttonY },
132
+ range,
133
+ column: range.columns[0],
134
+ cellCount,
135
+ });
136
+ }, 500);
137
+ },
138
+ [enabled, minCells, allowMultiColumn, buttonPosition, buttonOffset]
139
+ );
140
+
141
+ /**
142
+ * Handler pro kliknutí na bulk edit button - otevře popover
143
+ */
144
+ const handleOpenPopover = useCallback(() => {
145
+ if (onBulkEditStart) {
146
+ onBulkEditStart({
147
+ range: floatingButton.range,
148
+ column: floatingButton.column,
149
+ cellCount: floatingButton.cellCount,
150
+ });
151
+ }
152
+
153
+ setEditPopover({
154
+ visible: true,
155
+ value: '',
156
+ loading: false,
157
+ error: null,
158
+ });
159
+ }, [floatingButton, onBulkEditStart]);
160
+
161
+ /**
162
+ * Handler pro submit bulk edit změn
163
+ */
164
+ const handleSubmitEdit = useCallback(
165
+ async (newValue) => {
166
+ if (!gridRef.current || !floatingButton.range) {
167
+ return;
168
+ }
169
+
170
+ setEditPopover((prev) => ({ ...prev, loading: true, error: null }));
171
+
172
+ try {
173
+ const colDef = floatingButton.column?.getColDef();
174
+ const bulkEditApi = colDef?.bulkEditApi;
175
+
176
+ let result;
177
+
178
+ // Pokud je definováno bulkEditApi, použij API volání
179
+ if (bulkEditApi?.endpoint) {
180
+ result = await applyBulkChangesWithApi(
181
+ floatingButton.range,
182
+ newValue,
183
+ gridRef.current.api,
184
+ bulkEditApi,
185
+ accessToken,
186
+ fetchDataUIAsync,
187
+ (result) => {
188
+ if (onBulkEditComplete) {
189
+ onBulkEditComplete({
190
+ ...result,
191
+ range: floatingButton.range,
192
+ column: floatingButton.column,
193
+ newValue,
194
+ });
195
+ }
196
+ }
197
+ );
198
+ } else {
199
+ // Pokud není API, použij lokální změnu
200
+ result = applyBulkChanges(
201
+ floatingButton.range,
202
+ newValue,
203
+ gridRef.current.api,
204
+ (result) => {
205
+ if (onBulkEditComplete) {
206
+ onBulkEditComplete({
207
+ ...result,
208
+ range: floatingButton.range,
209
+ column: floatingButton.column,
210
+ newValue,
211
+ });
212
+ }
213
+ }
214
+ );
215
+ }
216
+
217
+ if (result.success) {
218
+ // Úspěch - zavřít popover a skrýt button
219
+ setEditPopover({
220
+ visible: false,
221
+ value: '',
222
+ loading: false,
223
+ error: null,
224
+ });
225
+ setFloatingButton({ visible: false });
226
+ } else {
227
+ // Chyba - zobrazit error
228
+ setEditPopover((prev) => ({
229
+ ...prev,
230
+ loading: false,
231
+ error: result.error || result.errors?.[0] || 'Chyba při aplikaci změn',
232
+ }));
233
+ }
234
+ } catch (error) {
235
+ setEditPopover((prev) => ({
236
+ ...prev,
237
+ loading: false,
238
+ error: error?.message || 'Neznámá chyba',
239
+ }));
240
+ }
241
+ },
242
+ [gridRef, floatingButton, onBulkEditComplete, accessToken, fetchDataUIAsync]
243
+ );
244
+
245
+ /**
246
+ * Handler pro zrušení bulk edit
247
+ */
248
+ const handleCancelEdit = useCallback(() => {
249
+ setEditPopover({
250
+ visible: false,
251
+ value: '',
252
+ loading: false,
253
+ error: null,
254
+ });
255
+ setFloatingButton({ visible: false });
256
+ }, []);
257
+
258
+ /**
259
+ * Handler pro změnu hodnoty v popover inputu
260
+ */
261
+ const handleValueChange = useCallback((value) => {
262
+ setEditPopover((prev) => ({ ...prev, value, error: null }));
263
+ }, []);
264
+
265
+ /**
266
+ * Scroll listener - skrýt button při scrollování
267
+ */
268
+ useEffect(() => {
269
+ if (!enabled || !gridRef.current) return;
270
+
271
+ const gridElement = gridRef.current.api?.gridBodyCtrl?.eBodyViewport;
272
+ if (!gridElement) return;
273
+
274
+ const handleScroll = () => {
275
+ if (floatingButton.visible) {
276
+ setFloatingButton({ visible: false });
277
+ }
278
+ };
279
+
280
+ scrollListenerRef.current = handleScroll;
281
+ gridElement.addEventListener('scroll', handleScroll);
282
+
283
+ return () => {
284
+ if (gridElement && scrollListenerRef.current) {
285
+ gridElement.removeEventListener('scroll', scrollListenerRef.current);
286
+ }
287
+ };
288
+ }, [enabled, gridRef, floatingButton.visible]);
289
+
290
+ /**
291
+ * Window resize listener - přepočítat pozici
292
+ */
293
+ useEffect(() => {
294
+ if (!enabled || !floatingButton.visible) return;
295
+
296
+ const handleResize = () => {
297
+ // Při resize okna skryjeme button (user musí znovu označit)
298
+ setFloatingButton({ visible: false });
299
+ };
300
+
301
+ window.addEventListener('resize', handleResize);
302
+
303
+ return () => {
304
+ window.removeEventListener('resize', handleResize);
305
+ };
306
+ }, [enabled, floatingButton.visible]);
307
+
308
+ /**
309
+ * Cleanup timeout on unmount
310
+ */
311
+ useEffect(() => {
312
+ return () => {
313
+ if (rangeTimeoutRef.current) {
314
+ clearTimeout(rangeTimeoutRef.current);
315
+ }
316
+ };
317
+ }, []);
318
+
319
+ return {
320
+ floatingButton,
321
+ editPopover,
322
+ handleRangeChange,
323
+ handleOpenPopover,
324
+ handleSubmitEdit,
325
+ handleCancelEdit,
326
+ handleValueChange,
327
+ };
328
+ };