@onehat/ui 0.3.241 → 0.3.242

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.3.241",
3
+ "version": "0.3.242",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -173,134 +173,197 @@ function Form(props) {
173
173
  context: { isPhantom },
174
174
  }),
175
175
  buildFromColumnsConfig = () => {
176
- // For InlineEditor
176
+ // Only used in InlineEditor
177
177
  // Build the fields that match the current columnsConfig in the grid
178
178
  const
179
- model = Repository.getSchema().model,
180
179
  elements = [],
181
- columnProps = {
180
+ columnProps = { // props applied to every column
182
181
  justifyContent: 'center',
183
182
  alignItems: 'center',
184
183
  borderRightWidth: 1,
185
184
  borderRightColor: 'trueGray.200',
186
185
  px: 1,
186
+ minWidth: styles.INLINE_EDITOR_MIN_WIDTH,
187
187
  };
188
-
189
- if (editorType === EDITOR_TYPE__INLINE) {
190
- columnProps.minWidth = styles.INLINE_EDITOR_MIN_WIDTH;
191
- }
192
-
193
188
  _.each(columnsConfig, (config, ix) => {
194
189
  let {
195
190
  fieldName,
191
+ isEditable = false,
192
+ editor = null,
196
193
  editField,
197
- isEditable,
198
- editor,
199
194
  renderer,
200
195
  w,
201
196
  flex,
197
+ onChange: onEditorChange,
202
198
  useSelectorId = false,
203
- } = config;
204
-
205
- if (!isEditable) {
206
- let renderedValue = renderer ? renderer(record) : record[fieldName];
207
- if (_.isBoolean(renderedValue)) {
208
- renderedValue = renderedValue.toString();
199
+ getDynamicProps,
200
+ getIsRequired,
201
+ ...propsToPass
202
+ } = config,
203
+ type,
204
+ editorTypeProps = {},
205
+ viewerTypeProps = {};
206
+
207
+ if (editField) {
208
+ // Sometimes, columns will be configured to display one field
209
+ // and edit a different field
210
+ fieldName = editField;
211
+ }
212
+ const propertyDef = fieldName && Repository?.getSchema().getPropertyDefinition(fieldName);
213
+ if (propertyDef?.isEditingDisabled && checkIsEditingDisabled) {
214
+ isEditable = false;
215
+ }
216
+ if (!_.isNil(editor)) {
217
+ // if editor is defined on column, use it
218
+ if (_.isString(editor)) {
219
+ type = editor;
220
+ } else if (_.isPlainObject(editor)) {
221
+ const {
222
+ type: t,
223
+ ...p
224
+ } = editor;
225
+ type = t;
226
+ editorTypeProps = p;
209
227
  }
210
- renderedValue += "\n(not editable)";
211
- elements.push(<Box key={ix} w={w} flex={flex} {...columnProps}>
212
- <Text numberOfLines={1} ellipsizeMode="head">{renderedValue}</Text>
213
- </Box>);
214
228
  } else {
215
- const fieldToEdit = editField || fieldName;
216
- elements.push(<Controller
217
- key={'controller-' + ix}
218
- name={fieldToEdit}
219
- // rules={rules}
220
- control={control}
221
- render={(args) => {
222
- const {
223
- field,
224
- fieldState,
225
- // formState,
226
- } = args,
227
- {
228
- onChange,
229
- onBlur,
230
- name,
231
- value,
232
- // ref,
233
- } = field,
234
- {
235
- isTouched,
236
- isDirty,
237
- error,
238
- } = fieldState;
239
- let editorProps = {};
240
- if (!editor) {
241
- const propertyDef = fieldToEdit && Repository?.getSchema().getPropertyDefinition(fieldToEdit);
242
- editor = propertyDef?.editorType;
243
- if (_.isPlainObject(editor)) {
244
- const {
245
- type,
246
- onChange: onEditorChange,
247
- ...p
248
- } = editor;
249
- editorProps = p;
250
- editor = type;
251
- }
252
- }
253
- if (!editor) {
254
- editor = 'Text';
255
- }
256
- if (!editor.match(/Toggle/)) {
257
- editorProps.h = '40px'; // Toggle height gets applied incorrectly; just skip it
258
- }
229
+ // editor is not defined, fall back to property definition
230
+ if (isEditable) {
231
+ const
232
+ {
233
+ type: t,
234
+ ...p
235
+ } = propertyDef?.editorType;
236
+ type = t;
237
+ editorTypeProps = p;
238
+ } else if (propertyDef?.viewerType) {
239
+ const
240
+ {
241
+ type: t,
242
+ ...p
243
+ } = propertyDef?.viewerType;
244
+ type = t;
245
+ viewerTypeProps = p;
246
+ } else {
247
+ type = 'Text';
248
+ }
249
+ }
250
+ const isCombo = type?.match && type.match(/Combo/);
251
+ if (config.hasOwnProperty('autoLoad')) {
252
+ editorTypeProps.autoLoad = config.autoLoad;
253
+ } else {
254
+ if (isCombo && Repository?.isRemote && !Repository?.isLoaded) {
255
+ editorTypeProps.autoLoad = true;
256
+ }
257
+ }
258
+ if (isCombo) {
259
+ // editorTypeProps.showEyeButton = true;
260
+ if (_.isNil(propsToPass.showXButton)) {
261
+ editorTypeProps.showXButton = true;
262
+ }
263
+ }
264
+ const Element = getComponentFromType(type);
259
265
 
260
- const Element = getComponentFromType(editor);
266
+ if (isEditorViewOnly || !isEditable) {
267
+ let value = null;
268
+ if (renderer) {
269
+ value = renderer(record);
270
+ } else {
271
+ if (record?.properties && record.properties[fieldName]) {
272
+ value = record.properties[fieldName].displayValue;
273
+ }
274
+ if (_.isNil(value) && record && record[fieldName]) {
275
+ value = record[fieldName];
276
+ }
277
+ if (_.isNil(value) && startingValues && startingValues[fieldName]) {
278
+ value = startingValues[fieldName];
279
+ }
280
+ }
261
281
 
262
- if (useSelectorId) {
263
- editorProps.selectorId = selectorId;
264
- editorProps.selectorSelected = editorProps;
265
- }
266
-
267
- let element = <Element
268
- name={name}
269
- value={value}
270
- onChangeValue={(newValue) => {
271
- if (newValue === undefined) {
272
- newValue = null; // React Hook Form doesn't respond well when setting value to undefined
273
- }
274
- onChange(newValue);
275
- if (typeof onEditorChange !== 'undefined' && onEditorChange) {
276
- onEditorChange(newValue, formSetValue, formGetValues, formState);
277
- }
278
- }}
279
- onBlur={onBlur}
280
- flex={1}
281
- parent={self}
282
- reference={fieldToEdit}
283
- {...editorProps}
284
- />;
282
+ let element = <Element
283
+ value={value}
284
+ parent={self}
285
+ reference={fieldName}
286
+ {...propsToPass}
287
+ {...viewerTypeProps}
288
+ />;
289
+ elements.push(<Box key={ix} w={w} flex={flex} {...columnProps}>{element}</Box>);
290
+ return;
291
+ }
292
+
293
+ elements.push(<Controller
294
+ key={'controller-' + ix}
295
+ name={fieldName}
296
+ // rules={rules}
297
+ control={control}
298
+ render={(args) => {
299
+ const {
300
+ field,
301
+ fieldState,
302
+ // formState,
303
+ } = args,
304
+ {
305
+ onChange,
306
+ onBlur,
307
+ name,
308
+ value,
309
+ // ref,
310
+ } = field,
311
+ {
312
+ isTouched,
313
+ isDirty,
314
+ error,
315
+ } = fieldState;
316
+
317
+ if (isValidElement(Element)) {
318
+ throw new Error('Should not yet be valid React element. Did you use <Element> instead of () => <Element> when defining it?')
319
+ }
285
320
 
286
- if (editor.match(/Tag/)) {
287
- columnProps.overflow = 'auto';
321
+ if (useSelectorId) { // This causes the whole form to use selectorId
322
+ editorTypeProps.selectorId = selectorId;
323
+ }
324
+ if (propsToPass.selectorId || editorTypeProps.selectorId) { // editorTypeProps.selectorId causes just this one field to use selectorId
325
+ if (_.isNil(propsToPass.selectorSelected)) {
326
+ editorTypeProps.selectorSelected = record;
288
327
  }
289
- // element = <Tooltip key={ix} label={header} placement="bottom">
290
- // {element}
291
- // </Tooltip>;
292
- // if (error) {
293
- // element = <Column pt={1} flex={1}>
294
- // {element}
295
- // <Text color="#f00">{error.message}</Text>
296
- // </Column>;
297
- // }
328
+ }
329
+ let dynamicProps = {};
330
+ if (getDynamicProps) {
331
+ dynamicProps = getDynamicProps({ fieldState, formSetValue, formGetValues, formState });
332
+ }
298
333
 
299
- const dirtyIcon = isDirty && !disableDirtyIcon ? <Icon as={Pencil} size="2xs" color="trueGray.300" position="absolute" top="2px" left="2px" /> : null;
300
- return <Row key={ix} bg={error ? '#fdd' : '#fff'} w={w} flex={flex} {...columnProps}>{dirtyIcon}{element}</Row>;
301
- }}
302
- />);
303
- }
334
+ if (type.match(/Tag/)) {
335
+ editorTypeProps.overflow = 'auto';
336
+ }
337
+ if (!type.match(/Toggle/)) {
338
+ editorTypeProps.h = '40px';
339
+ }
340
+
341
+ let element = <Element
342
+ name={name}
343
+ value={value}
344
+ onChangeValue={(newValue) => {
345
+ if (newValue === undefined) {
346
+ newValue = null; // React Hook Form doesn't respond well when setting value to undefined
347
+ }
348
+ onChange(newValue);
349
+ if (onEditorChange) {
350
+ onEditorChange(newValue, formSetValue, formGetValues, formState, trigger);
351
+ }
352
+ }}
353
+ onBlur={onBlur}
354
+ flex={1}
355
+ parent={self}
356
+ reference={name}
357
+ {...propsToPass}
358
+ {...editorTypeProps}
359
+ {...dynamicProps}
360
+ />;
361
+
362
+ const dirtyIcon = isDirty && !disableDirtyIcon ? <Icon as={Pencil} size="2xs" color="trueGray.300" position="absolute" top="2px" left="2px" /> : null;
363
+ return <Row key={ix} bg={error ? '#fdd' : '#fff'} w={w} flex={flex} {...columnProps}>{dirtyIcon}{element}</Row>;
364
+ }}
365
+ />);
366
+
304
367
  });
305
368
  return <Row>{elements}</Row>;
306
369
  },
@@ -328,7 +391,8 @@ function Form(props) {
328
391
  getIsRequired,
329
392
  ...propsToPass
330
393
  } = item,
331
- editorTypeProps = {};
394
+ editorTypeProps = {},
395
+ viewerTypeProps = {};
332
396
 
333
397
  if (isHidden) {
334
398
  return null;
@@ -359,6 +423,7 @@ function Form(props) {
359
423
  ...p
360
424
  } = propertyDef?.viewerType;
361
425
  type = t;
426
+ viewerTypeProps = p;
362
427
  } else {
363
428
  type = 'Text';
364
429
  }
@@ -378,9 +443,9 @@ function Form(props) {
378
443
  }
379
444
  }
380
445
  const Element = getComponentFromType(type);
381
- let children;
382
446
 
383
447
  if (inArray(type, ['Column', 'Row', 'FieldSet'])) {
448
+ let children;
384
449
  if (_.isEmpty(items)) {
385
450
  return null;
386
451
  }
@@ -432,6 +497,7 @@ function Form(props) {
432
497
  parent={self}
433
498
  reference={name}
434
499
  {...propsToPass}
500
+ {...viewerTypeProps}
435
501
  />;
436
502
  if (!disableLabels && label) {
437
503
  const labelProps = {};
@@ -492,6 +558,7 @@ function Form(props) {
492
558
  isDirty,
493
559
  error,
494
560
  } = fieldState;
561
+
495
562
  if (isValidElement(Element)) {
496
563
  throw new Error('Should not yet be valid React element. Did you use <Element> instead of () => <Element> when defining it?')
497
564
  }
@@ -887,6 +887,7 @@ function GridComponent(props) {
887
887
 
888
888
  if (self) {
889
889
  self.ref = containerRef;
890
+ self.gridRef = gridRef;
890
891
  }
891
892
 
892
893
  isAddingRef.current = isAdding;
@@ -62,13 +62,6 @@ export default function withInlineEditor(WrappedComponent, skipWrappers = false)
62
62
  onChangeColumnsConfig = (columnsConfig) => {
63
63
  setLocalColumnsConfig(columnsConfig);
64
64
  },
65
- onRowClick = (item, rowIndex, e) => {
66
- // move the editor up to the appropriate row
67
- const currentRow = e.currentTarget;
68
- moveEditor(currentRow);
69
-
70
- setCurrentRow(currentRow);
71
- },
72
65
  onScreenResize = () => {
73
66
  // TODO: Attach a div with zIndex 0 to body to monitor resize events. THis is handler
74
67
 
@@ -83,12 +76,28 @@ export default function withInlineEditor(WrappedComponent, skipWrappers = false)
83
76
  delta = editorBounds.top - rowBounds.top;
84
77
 
85
78
  editorStyle.top = (-1 * delta) + 'px';
79
+ },
80
+ onEditorShown = () => {
81
+ // determine which row to move the editor to
82
+ const
83
+ data = self.gridRef.current.props.data, // This is okay, because (for now) the inlineEditor is only for use with grids
84
+ ix = data.indexOf(selection[0]),
85
+ gridRowsContainer = self.gridRef.current._listRef._scrollRef.childNodes[0],
86
+ currentRow = gridRowsContainer.childNodes[ix];
87
+
88
+ // TODO: verify it works if not using a Repository
89
+
90
+ moveEditor(currentRow);
91
+ setCurrentRow(currentRow);
86
92
  };
87
93
 
88
94
  useEffect(() => {
89
95
  if (maskRef.current) {
90
96
  maskRef.current.focus();
91
97
  }
98
+ if (isEditorShown) {
99
+ onEditorShown();
100
+ }
92
101
  }, [isEditorShown]);
93
102
 
94
103
  if (isEditorShown && selection.length < 1) {