react-graph-grid 0.1.9 → 0.1.12

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.
@@ -0,0 +1,376 @@
1
+ /* eslint-disable no-mixed-operators */
2
+ import { useState, useEffect, useRef, useLayoutEffect } from 'react';
3
+ import { BaseComponent } from './Base';
4
+ import { Modal } from './Modal';
5
+ import { Images } from './Themes/Images';
6
+ import { GridFE } from './GridFE';
7
+ export function FieldEdit(props) {
8
+ let fe = null;
9
+
10
+ const [feState, setState] = useState({ fe: fe, ind: 0 });
11
+
12
+ fe = feState.fe;
13
+ if (!fe) {
14
+ if (props.findFieldEdit) {
15
+ fe = props.findFieldEdit();
16
+ }
17
+ fe = fe || new FieldEditClass(props);
18
+ }
19
+
20
+ fe.textareaRef = useRef(null);
21
+
22
+ fe.column = props.column;
23
+
24
+ if (fe.value == null) {
25
+ fe.value = props.value || '';
26
+ fe.text = props.text || '';
27
+ }
28
+
29
+ fe.getFilters = props.getFilters;
30
+
31
+ fe.multi = props.multi;
32
+
33
+ fe.large = props.large;
34
+
35
+ fe.id = props.keyPref || FieldEditClass._seq++;
36
+
37
+ fe.disabled = props.disabled;
38
+
39
+ BaseComponent.theme = BaseComponent.theme || {};
40
+
41
+ fe.buttonClass = props.buttonClass || BaseComponent.theme.filterButtonClass || '';
42
+ fe.inputClass = props.inputClass || BaseComponent.theme.inputClass || '';
43
+ fe.inputClassLG = props.inputClassLG || BaseComponent.theme.inputClassLG || '';
44
+ fe.clearButtonClass = props.clearButtonClass || BaseComponent.theme.clearButtonClass || '';
45
+ fe.selectClass = props.selectClass || BaseComponent.theme.selectClass || '';
46
+ fe.divContainerClass = props.divContainerClass || '';
47
+
48
+ fe.w = props.w;
49
+ fe.maxW = props.maxW;
50
+ fe.h = fe.h || props.h || '1.6em';
51
+ fe.textareaH = props.textareaH || '2.1em';
52
+
53
+ if (props.init) {
54
+ props.init(fe);
55
+ }
56
+
57
+ fe.refreshState = function () {
58
+ setState({ fe: fe, ind: fe.stateind++ });
59
+ }
60
+
61
+ useEffect(() => {
62
+ return () => {
63
+ if (fe._resizeObserver && fe._resizeObservedObj) {
64
+ fe._resizeObserver.unobserve(fe._resizeObservedObj);
65
+ }
66
+ };
67
+ }, [fe])
68
+
69
+ useLayoutEffect(() => {
70
+ if (fe.textareaRef.current && fe._refocus) {
71
+ fe.textareaRef.current.focus();
72
+ if (fe.selectionStart > 0) {
73
+ fe.textareaRef.current.setSelectionRange(fe.selectionStart, fe.selectionStart);
74
+ }
75
+ fe._refocus = false;
76
+ }
77
+
78
+ const handleResize = () => {
79
+ //console.log('Textarea resized. New height:', fe.textareaRef.current.offsetHeight);
80
+ if (fe.textareaRef.current) {
81
+ fe.h = fe.textareaRef.current.offsetHeight;
82
+ }
83
+ };
84
+
85
+ if (fe.textareaRef.current && fe._resizeObserved !== fe.textareaRef.current) {
86
+ fe._resizeObserver = new ResizeObserver(handleResize);
87
+
88
+ if (fe._resizeObservedObj) {
89
+ fe._resizeObserver.unobserve(fe._resizeObservedObj);
90
+ }
91
+
92
+ fe._resizeObservedObj = fe.textareaRef.current;
93
+
94
+ fe._resizeObserver.observe(fe.textareaRef.current);
95
+ }
96
+ });
97
+
98
+ return (fe.render());
99
+ }
100
+
101
+ // ==================================================================================================================================================================
102
+ export class FieldEditClass extends BaseComponent {
103
+
104
+ constructor(props) {
105
+ super(props);
106
+
107
+ const fe = this;
108
+
109
+ fe.stateind = 0;
110
+ fe.id = props.keyPref || FieldEditClass._seq++;
111
+
112
+ fe.onChange = props.onChange || (() => { });
113
+
114
+ fe.selectionStart = 0;
115
+
116
+ // просто разметка 'span 2' etc.
117
+ fe.gridColumn = props.gridColumn;
118
+
119
+ fe._selectedOptions = [];
120
+ }
121
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
122
+ static _seq = 0;
123
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
124
+ render() {
125
+ const fe = this;
126
+
127
+ return (
128
+ <>
129
+ <div
130
+ key={`fieldEditDiv_${fe.id}_${fe.column.id}_`}
131
+ className={fe.divContainerClass ? fe.divContainerClass : fe.large ? 'field-edit' : fe.column.type === 'lookup' && !fe.column.readonly ? 'grid-cell-lookup' : 'grid-cell-edit'}
132
+ style={{
133
+ border: 'none',
134
+ height: !fe.inputClass ? fe.h : '',
135
+ width: '100%',
136
+ display: 'grid',
137
+ gridColumn: fe.gridColumn || '',
138
+ gridTemplateColumns: fe.getDivGridTemplateColumns(),
139
+ maxWidth: fe.maxW ? fe.maxW : '',
140
+ minHeight: fe.large ? '2.5em' : '',
141
+ columnGap: fe.large ? '0.2em' : '',
142
+ alignItems: 'center',
143
+ justifyItems: 'center',
144
+ }}
145
+ >
146
+ {
147
+ fe.renderInput()
148
+ }
149
+ {
150
+ fe.canClear() ?
151
+ <button
152
+ key={`fieldClearButton_${fe.id}_${fe.column.id}_`}
153
+ className={`${fe.large ? 'graph-filter-clear' : 'grid-cell-button'} ${fe.clearButtonClass || ''}`}
154
+ style={{ width: !fe.large ? '1.6em' : '', height: !fe.large ? '1.6em' : '' }}
155
+ onClick={(e) => {
156
+ fe.onClearClick(e);
157
+ }}
158
+ disabled={fe.disabled}
159
+ >
160
+ {!fe.large ? '×' : Images.images.filterClear()}
161
+ </button>
162
+ :
163
+ <></>
164
+ }
165
+ </div >
166
+ {
167
+ fe.lookupIsShowing ?
168
+ <Modal
169
+ title={fe.column.title}
170
+ renderContent={(wnd) => { return fe.renderLookupGrid(wnd); }}
171
+ pos={fe.popupPos}
172
+ onClose={(e) => {
173
+ if (fe.grid) {
174
+ delete fe.grid.value;
175
+ }
176
+ fe.closeLookupField();
177
+ fe.refreshState();
178
+ }}
179
+ >
180
+ </Modal>
181
+ :
182
+ <></>
183
+ }
184
+ </>
185
+ )
186
+ }
187
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
188
+ renderInput() {
189
+ const fe = this;
190
+
191
+ const isLookup = fe.column.type === 'lookup';
192
+ const noClear = !fe.canClear();
193
+
194
+ return (
195
+ <>
196
+ {
197
+ isLookup && !fe.column.readonly ?
198
+ <>
199
+ <input
200
+ key={`fieldLookupTitle_${fe.id}_${fe.column.id}_`}
201
+ style={{
202
+ width: '100%',
203
+ gridColumn: noClear ? 'span 2' : 'span 1',
204
+ overflowX: 'hidden',
205
+ height: !fe.large ? '1.7em' : '2.2em',
206
+ minHeight: !fe.inputClass ? fe.textareaH : fe.h,
207
+ boxSizing: 'border-box',
208
+ }}
209
+ disabled={true}
210
+ className={fe.large ? fe.inputClassLG : fe.inputClass || ''}
211
+ value={fe.value == null || fe.value == '' ? '' : fe.text != null && fe.text !== '' ? fe.text : fe.value}
212
+ >
213
+ </input>
214
+ <button
215
+ key={`fieldLookupButton_${fe.id}_${fe.column.id}_`}
216
+ className={`${fe.large ? 'graph-filter-button' : 'grid-cell-button'} ${fe.clearButtonClass}`}
217
+ style={{ width: !fe.large ? '1.6em' : '', height: !fe.large ? '1.6em' : '' }}
218
+ onClick={(e) => {
219
+ fe.openLookupField(e);
220
+ }}
221
+ disabled={fe.disabled}
222
+ >
223
+ {!fe.large ? '...' : Images.images.filterSelect()}
224
+ </button>
225
+ </>
226
+ :
227
+ <textarea
228
+ key={`fieldTextarea_${fe.id}_${fe.column.id}_`}
229
+ ref={fe.textareaRef}
230
+ className={`${fe.large ? fe.inputClassLG : fe.inputClass}`}
231
+ value={isLookup ? fe.text : fe.value || ''}
232
+ style={{
233
+ width: noClear ? 'calc(100% - 2px)' : '100%',
234
+ height: !fe.large ? fe.h ? fe.h : '1.7em' : '2.2em',
235
+ minHeight: !fe.inputClass ? fe.textareaH : fe.minH,
236
+ padding: '0',
237
+ boxSizing: 'border-box',
238
+ gridColumn: noClear ? 'span 3' : 'span 2',
239
+ resize: 'vertical',
240
+ overflowX: 'hidden',
241
+ }}
242
+ onChange={(e) => {
243
+ e.value = e.text = e.target.value;
244
+ fe.value = fe.text = e.target.value;
245
+ e.fe = fe;
246
+
247
+ fe.selectionStart = e.target.selectionStart;
248
+ fe._refocus = true;
249
+
250
+ fe.onChange(e);
251
+ fe.refreshState();
252
+ }}
253
+ disabled={fe.disabled || fe.column.readonly}
254
+ >
255
+ </textarea>
256
+ }
257
+ </>
258
+ );
259
+ }
260
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
261
+ renderLookupGrid(wnd) {
262
+ const fe = this;
263
+
264
+ return (
265
+ <GridFE
266
+ getRows={fe.column.getRows}
267
+ keyField={fe.column.refKeyField}
268
+ nameField={fe.column.refNameField}
269
+ activeRow={fe.value}
270
+ multi={fe.multi}
271
+ level={fe.level + 1}
272
+ findGrid={() => { return fe.grid; }}
273
+ onSelectValue={(e) => {
274
+ fe._selectedOptions = e.values || [];
275
+
276
+ fe.value = e.value;
277
+ fe.text = e.text;
278
+
279
+ e.fe = fe;
280
+
281
+ fe.closeLookupField();
282
+ fe.onChange(e);
283
+ fe.refreshState();
284
+ }}
285
+ init={(lookupGrid) => {
286
+ if (!lookupGrid.value || fe.value && fe.value !== lookupGrid.value) {
287
+ fe.onLookupGridInit(lookupGrid);
288
+
289
+ delete lookupGrid._selectedRows;
290
+ if (fe.value) {
291
+ lookupGrid._selectedRowsDict = {};
292
+ for (let opt of fe._selectedOptions) {
293
+ let fakeRow = {};
294
+ fakeRow[fe.column.refKeyField] = opt.value;
295
+ fakeRow[fe.column.refNameField] = opt.label;
296
+ lookupGrid._selectedRowsDict[opt.value] = fakeRow;
297
+ }
298
+ }
299
+ }
300
+
301
+ lookupGrid.closeSelfWnd = () => {
302
+ fe.closeLookupField();
303
+ fe.refreshState();
304
+ };
305
+ }}
306
+ onClose={() => {
307
+ fe.closeLookupField();
308
+ }}
309
+ >
310
+ </GridFE>
311
+ );
312
+ }
313
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
314
+ getDivGridTemplateColumns() {
315
+ const fe = this;
316
+ return fe.large ? 'calc(100% - 4.6em) 2.2em 2.2em' : 'calc(100% - 2.8em) 1.4em 1.4em';
317
+ }
318
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
319
+ canClear() {
320
+ const fe = this;
321
+ return !fe.column.required && !fe.column.readonly && (fe.multi || fe.value != null && fe.value !== '');
322
+ }
323
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
324
+ onClearClick(e) {
325
+ const fe = this;
326
+
327
+ e.value = e.text = '';
328
+ fe.value = fe.text = '';
329
+ e.fe = fe;
330
+ fe.onChange(e);
331
+ fe.refreshState();
332
+ }
333
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
334
+ closeLookupField() {
335
+ const fe = this;
336
+ fe.lookupIsShowing = false;
337
+ if (fe.ownerGrid) {
338
+ fe.ownerGrid._clicksDisabled = false;
339
+ }
340
+ }
341
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
342
+ openLookupField(e) {
343
+ const fe = this;
344
+
345
+ const shift = (fe.level + 1) * 20;
346
+
347
+ fe.popupPos = fe.popupPos || { x: 100 + shift, y: 100 + shift, w: 1700, h: 900 };
348
+
349
+ fe.lookupIsShowing = true;
350
+ if (fe.ownerGrid) {
351
+ fe.ownerGrid._clicksDisabled = true;
352
+ }
353
+
354
+ fe.refreshState();
355
+ }
356
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
357
+ onLookupGridInit(grid) {
358
+ const fe = this;
359
+ fe.grid = grid;
360
+ grid.value = fe.value;
361
+ grid.getSelectedRowIndex();
362
+
363
+ if (fe.getFilters) {
364
+ grid.collectFilters = fe.getFilters;
365
+ }
366
+
367
+ if (grid._lookupPrepared) return;
368
+
369
+ grid._lookupPrepared = true;
370
+
371
+ grid.visible = true;
372
+ grid.title = fe.column.title;
373
+ grid.isSelecting = true;
374
+ };
375
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------
376
+ }