@bit.rhplus/ag-grid 0.0.39 → 0.0.41

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.
@@ -31,6 +31,7 @@ const BulkEditButton = ({
31
31
  onCancel,
32
32
  }) => {
33
33
  const [popoverVisible, setPopoverVisible] = useState(false);
34
+ const [popoverPosition, setPopoverPosition] = useState(null);
34
35
  const buttonRef = useRef(null);
35
36
  const popoverRef = useRef(null);
36
37
 
@@ -39,6 +40,41 @@ const BulkEditButton = ({
39
40
  setPopoverVisible(editPopover.visible);
40
41
  }, [editPopover.visible]);
41
42
 
43
+ // Viewport-aware positioning pro popover
44
+ useEffect(() => {
45
+ if (popoverVisible && popoverRef.current && position) {
46
+ requestAnimationFrame(() => {
47
+ const popoverRect = popoverRef.current.getBoundingClientRect();
48
+ const viewportWidth = window.innerWidth;
49
+ const viewportHeight = window.innerHeight;
50
+ const MARGIN = 10;
51
+
52
+ let top = position.y + 35;
53
+ let left = position.x;
54
+
55
+ if (left + popoverRect.width > viewportWidth - MARGIN) {
56
+ left = viewportWidth - popoverRect.width - MARGIN;
57
+ }
58
+
59
+ if (left < MARGIN) {
60
+ left = MARGIN;
61
+ }
62
+
63
+ if (top + popoverRect.height > viewportHeight - MARGIN) {
64
+ top = position.y - popoverRect.height - 5;
65
+ }
66
+
67
+ if (top < MARGIN) {
68
+ top = MARGIN;
69
+ }
70
+
71
+ setPopoverPosition({ top, left });
72
+ });
73
+ } else {
74
+ setPopoverPosition(null);
75
+ }
76
+ }, [popoverVisible, position]);
77
+
42
78
  if (!visible) return null;
43
79
 
44
80
  const colDef = column?.getColDef();
@@ -122,10 +158,12 @@ const BulkEditButton = ({
122
158
  ref={popoverRef}
123
159
  style={{
124
160
  position: 'fixed',
125
- top: (position?.y || 0) + 35, // Pod buttonem
126
- left: position?.x || 0,
161
+ top: popoverPosition?.top ?? (position?.y || 0) + 35,
162
+ left: popoverPosition?.left ?? (position?.x || 0),
127
163
  zIndex: 10000,
128
164
  pointerEvents: 'auto',
165
+ opacity: popoverPosition ? 1 : 0,
166
+ transition: 'opacity 0.1s ease-in-out',
129
167
  }}
130
168
  >
131
169
  <BulkEditPopover
@@ -0,0 +1,295 @@
1
+ /* eslint-disable */
2
+ import React, { useState, useCallback, useMemo } from 'react';
3
+ import { Calendar, Button, Space, Tooltip } from 'antd';
4
+ import dayjs from 'dayjs';
5
+ import 'dayjs/locale/cs';
6
+ import styled from 'styled-components';
7
+ import Holidays from 'date-holidays';
8
+
9
+ dayjs.locale('cs');
10
+
11
+ const CalendarContainer = styled.div`
12
+ display: flex;
13
+ gap: 8px;
14
+ margin-bottom: 12px;
15
+ width: 900px;
16
+ justify-content: space-between;
17
+
18
+ .ant-picker-calendar {
19
+ max-width: 260px;
20
+ flex: 1;
21
+ }
22
+
23
+ .ant-picker-calendar-header {
24
+ padding: 8px 12px;
25
+ }
26
+
27
+ .ant-picker-cell-selected .ant-picker-cell-inner {
28
+ background: transparent !important;
29
+ color: inherit !important;
30
+ font-weight: normal !important;
31
+ }
32
+
33
+ .ant-picker-cell-disabled {
34
+ pointer-events: none;
35
+ }
36
+
37
+ .ant-picker-cell-disabled .ant-picker-cell-inner {
38
+ color: rgba(0, 0, 0, 0.25) !important;
39
+ background: transparent !important;
40
+ }
41
+
42
+ .ant-picker-cell:not(.ant-picker-cell-in-view) .ant-picker-cell-inner {
43
+ color: rgba(0, 0, 0, 0.25) !important;
44
+ background: transparent !important;
45
+ }
46
+ `;
47
+
48
+ const BulkEditDatePicker = ({
49
+ value,
50
+ onChange,
51
+ onSubmit,
52
+ onCancel,
53
+ loading,
54
+ format = 'DD.MM.YYYY',
55
+ showTime = false,
56
+ }) => {
57
+ const today = dayjs();
58
+ const [selectedDate, setSelectedDate] = useState(value ? dayjs(value) : null);
59
+ const [baseMonth, setBaseMonth] = useState(today);
60
+
61
+ const month1 = baseMonth;
62
+ const month2 = baseMonth.add(1, 'month');
63
+ const month3 = baseMonth.add(2, 'month');
64
+
65
+ const hd = useMemo(() => new Holidays('CZ'), []);
66
+
67
+ const handleDateSelect = (date) => {
68
+ setSelectedDate(date);
69
+ if (showTime) {
70
+ onChange(date.toISOString());
71
+ } else {
72
+ onChange(date.format('YYYY-MM-DD'));
73
+ }
74
+ };
75
+
76
+ const getHoliday = useCallback((date) => {
77
+ const holidays = hd.isHoliday(date.toDate());
78
+ return holidays && holidays.length > 0 ? holidays[0].name : null;
79
+ }, [hd]);
80
+
81
+ const getVisibleHolidays = useCallback(() => {
82
+ const holidays = [];
83
+ const months = [month1, month2, month3];
84
+
85
+ months.forEach(month => {
86
+ const startOfMonth = month.startOf('month');
87
+ const endOfMonth = month.endOf('month');
88
+ let current = startOfMonth;
89
+
90
+ while (current.isBefore(endOfMonth) || current.isSame(endOfMonth, 'day')) {
91
+ const holidayName = getHoliday(current);
92
+ if (holidayName) {
93
+ holidays.push({
94
+ date: current.format('DD.MM.YYYY'),
95
+ name: holidayName,
96
+ });
97
+ }
98
+ current = current.add(1, 'day');
99
+ }
100
+ });
101
+
102
+ return holidays;
103
+ }, [month1, month2, month3, getHoliday]);
104
+
105
+ const visibleHolidays = useMemo(() => getVisibleHolidays(), [getVisibleHolidays]);
106
+
107
+ const createCellRender = useCallback((monthValue) => {
108
+ return (current, info) => {
109
+ const isSelected = selectedDate &&
110
+ current.date() === selectedDate.date() &&
111
+ current.month() === selectedDate.month() &&
112
+ current.year() === selectedDate.year();
113
+ const isToday = current.isSame(today, 'day');
114
+ const holidayName = getHoliday(current);
115
+
116
+ if (isSelected) {
117
+ return (
118
+ <div className="ant-picker-cell-inner" style={{
119
+ background: '#1890ff',
120
+ color: 'white',
121
+ fontWeight: 600,
122
+ }}>
123
+ {current.date()}
124
+ </div>
125
+ );
126
+ }
127
+
128
+ if (holidayName) {
129
+ return (
130
+ <div className="ant-picker-cell-inner" style={{
131
+ background: '#fff1f0',
132
+ color: '#cf1322',
133
+ fontWeight: 600,
134
+ }}>
135
+ {current.date()}
136
+ </div>
137
+ );
138
+ }
139
+
140
+ if (isToday) {
141
+ return (
142
+ <div className="ant-picker-cell-inner" style={{
143
+ background: '#e6f7ff',
144
+ color: '#1890ff',
145
+ fontWeight: 600,
146
+ border: '1px solid #1890ff',
147
+ }}>
148
+ {current.date()}
149
+ </div>
150
+ );
151
+ }
152
+
153
+ return (
154
+ <div className="ant-picker-cell-inner">
155
+ {current.date()}
156
+ </div>
157
+ );
158
+ };
159
+ }, [selectedDate, today, getHoliday]);
160
+
161
+ return (
162
+ <>
163
+ <CalendarContainer onClick={(e) => e.stopPropagation()}>
164
+ <Calendar
165
+ fullscreen={false}
166
+ value={month1}
167
+ onSelect={handleDateSelect}
168
+ fullCellRender={createCellRender(month1)}
169
+ headerRender={({ value: currentValue }) => (
170
+ <div style={{
171
+ padding: '8px 12px',
172
+ fontWeight: 500,
173
+ textAlign: 'center',
174
+ display: 'flex',
175
+ alignItems: 'center',
176
+ justifyContent: 'space-between'
177
+ }}>
178
+ <span
179
+ style={{ cursor: 'pointer', padding: '0 4px' }}
180
+ onClick={() => setBaseMonth(baseMonth.subtract(1, 'month'))}
181
+ >
182
+
183
+ </span>
184
+ <span>{currentValue.format('MMMM YYYY')}</span>
185
+ <span
186
+ style={{ cursor: 'pointer', padding: '0 4px' }}
187
+ onClick={() => setBaseMonth(baseMonth.add(1, 'month'))}
188
+ >
189
+
190
+ </span>
191
+ </div>
192
+ )}
193
+ />
194
+ <Calendar
195
+ fullscreen={false}
196
+ value={month2}
197
+ onSelect={handleDateSelect}
198
+ fullCellRender={createCellRender(month2)}
199
+ headerRender={({ value: currentValue }) => (
200
+ <div style={{
201
+ padding: '8px 12px',
202
+ fontWeight: 500,
203
+ textAlign: 'center',
204
+ display: 'flex',
205
+ alignItems: 'center',
206
+ justifyContent: 'space-between'
207
+ }}>
208
+ <span
209
+ style={{ cursor: 'pointer', padding: '0 4px' }}
210
+ onClick={() => setBaseMonth(baseMonth.subtract(1, 'month'))}
211
+ >
212
+
213
+ </span>
214
+ <span>{currentValue.format('MMMM YYYY')}</span>
215
+ <span
216
+ style={{ cursor: 'pointer', padding: '0 4px' }}
217
+ onClick={() => setBaseMonth(baseMonth.add(1, 'month'))}
218
+ >
219
+
220
+ </span>
221
+ </div>
222
+ )}
223
+ />
224
+ <Calendar
225
+ fullscreen={false}
226
+ value={month3}
227
+ onSelect={handleDateSelect}
228
+ fullCellRender={createCellRender(month3)}
229
+ headerRender={({ value: currentValue }) => (
230
+ <div style={{
231
+ padding: '8px 12px',
232
+ fontWeight: 500,
233
+ textAlign: 'center',
234
+ display: 'flex',
235
+ alignItems: 'center',
236
+ justifyContent: 'space-between'
237
+ }}>
238
+ <span
239
+ style={{ cursor: 'pointer', padding: '0 4px' }}
240
+ onClick={() => setBaseMonth(baseMonth.subtract(1, 'month'))}
241
+ >
242
+
243
+ </span>
244
+ <span>{currentValue.format('MMMM YYYY')}</span>
245
+ <span
246
+ style={{ cursor: 'pointer', padding: '0 4px' }}
247
+ onClick={() => setBaseMonth(baseMonth.add(1, 'month'))}
248
+ >
249
+
250
+ </span>
251
+ </div>
252
+ )}
253
+ />
254
+ </CalendarContainer>
255
+
256
+ {visibleHolidays.length > 0 && (
257
+ <div style={{ marginBottom: '12px', fontSize: '11px', color: '#666' }}>
258
+ {visibleHolidays.map((holiday, index) => {
259
+ const isSelectedHoliday = selectedDate && holiday.date === selectedDate.format('DD.MM.YYYY');
260
+ return (
261
+ <div
262
+ key={index}
263
+ style={{
264
+ marginBottom: '2px',
265
+ background: isSelectedHoliday ? '#e6f7ff' : 'transparent',
266
+ padding: isSelectedHoliday ? '2px 4px' : '0',
267
+ borderRadius: '2px',
268
+ fontWeight: isSelectedHoliday ? 600 : 'normal',
269
+ }}
270
+ >
271
+ <span style={{ color: '#cf1322', fontWeight: 500 }}>{holiday.date}</span> - {holiday.name}
272
+ </div>
273
+ );
274
+ })}
275
+ </div>
276
+ )}
277
+
278
+ <Space style={{ width: '100%', justifyContent: 'flex-end' }}>
279
+ <Button size="small" onClick={onCancel} disabled={loading}>
280
+ Zrušit
281
+ </Button>
282
+ <Button
283
+ type="primary"
284
+ size="small"
285
+ onClick={() => onSubmit(value)}
286
+ loading={loading}
287
+ >
288
+ Použít
289
+ </Button>
290
+ </Space>
291
+ </>
292
+ );
293
+ };
294
+
295
+ export default BulkEditDatePicker;
@@ -163,7 +163,7 @@ const BulkEditPopover = ({
163
163
  padding: '12px',
164
164
  boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
165
165
  minWidth: '280px',
166
- maxWidth: '320px',
166
+ maxWidth: '1050px',
167
167
  }}
168
168
  >
169
169
  <div style={{ marginBottom: '8px' }}>
@@ -218,7 +218,7 @@ const BulkEditPopover = ({
218
218
  padding: '12px',
219
219
  boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
220
220
  minWidth: '280px',
221
- maxWidth: '320px',
221
+ maxWidth: '1050px',
222
222
  }}
223
223
  >
224
224
  <div style={{ marginBottom: '8px' }}>
package/BulkEdit/index.js CHANGED
@@ -3,6 +3,7 @@ export { useBulkCellEdit } from './useBulkCellEdit';
3
3
  export { default as BulkEditButton } from './BulkEditButton';
4
4
  export { default as BulkEditPopover } from './BulkEditPopover';
5
5
  export { default as BulkEditSelect } from './BulkEditSelect';
6
+ export { default as BulkEditDatePicker } from './BulkEditDatePicker';
6
7
 
7
8
  export * from './utils';
8
9