@evoke-platform/ui-components 1.1.0-testing.0 → 1.1.0-testing.10

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 (32) hide show
  1. package/dist/published/components/core/DateTimePicker/DateTimePicker.js +7 -1
  2. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.d.ts +4 -5
  3. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +103 -31
  4. package/dist/published/components/custom/CriteriaBuilder/PropertyTree.js +4 -10
  5. package/dist/published/components/custom/CriteriaBuilder/ValueEditor.js +39 -14
  6. package/dist/published/components/custom/Form/Common/Form.d.ts +7 -1
  7. package/dist/published/components/custom/Form/Common/Form.js +112 -94
  8. package/dist/published/components/custom/Form/Common/FormComponentWrapper.d.ts +5 -0
  9. package/dist/published/components/custom/Form/Common/FormComponentWrapper.js +15 -4
  10. package/dist/published/components/custom/Form/FormComponents/FormFieldComponent.d.ts +1 -0
  11. package/dist/published/components/custom/Form/FormComponents/FormFieldComponent.js +1 -1
  12. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectPropertyInput.js +7 -3
  13. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableField.js +6 -2
  14. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableFieldInput.js +1 -0
  15. package/dist/published/components/custom/Form/index.d.ts +2 -1
  16. package/dist/published/components/custom/Form/utils.js +21 -4
  17. package/dist/published/components/custom/FormField/FormField.d.ts +2 -0
  18. package/dist/published/components/custom/FormField/FormField.js +3 -1
  19. package/dist/published/components/custom/FormField/Select/Select.js +28 -4
  20. package/dist/published/components/custom/FormField/Select/Select.test.js +41 -0
  21. package/dist/published/components/custom/OverflowTextField/OverflowTextField.d.ts +4 -0
  22. package/dist/published/components/custom/OverflowTextField/OverflowTextField.js +13 -0
  23. package/dist/published/components/custom/OverflowTextField/index.d.ts +2 -0
  24. package/dist/published/components/custom/OverflowTextField/index.js +2 -0
  25. package/dist/published/components/custom/index.d.ts +3 -2
  26. package/dist/published/components/custom/index.js +2 -2
  27. package/dist/published/index.d.ts +6 -3
  28. package/dist/published/index.js +4 -2
  29. package/dist/published/stories/FormField.stories.js +2 -0
  30. package/dist/published/stories/OverflowTextField.stories.d.ts +5 -0
  31. package/dist/published/stories/OverflowTextField.stories.js +28 -0
  32. package/package.json +2 -8
@@ -24,6 +24,12 @@ const DateTimePicker = (props) => {
24
24
  handleChange(newValue, keyboardInputValue);
25
25
  };
26
26
  return (React.createElement(UIThemeProvider, null,
27
- React.createElement(MUIDateTimePicker, { value: value, onChange: onChange, renderInput: (params) => React.createElement(TextField, { ...params }), ...rest })));
27
+ React.createElement(MUIDateTimePicker, { value: value, onChange: onChange, renderInput: (params) => React.createElement(TextField, { ...params }), PaperProps: {
28
+ sx: {
29
+ '&.MuiPickersPopper-paper': {
30
+ borderRadius: '12px',
31
+ },
32
+ },
33
+ }, ...rest })));
28
34
  };
29
35
  export default DateTimePicker;
@@ -1,4 +1,4 @@
1
- import { ElementType } from 'react';
1
+ /// <reference types="react" />
2
2
  import 'react-querybuilder/dist/query-builder.css';
3
3
  import { EvokeObject } from '../../../types';
4
4
  import { ObjectProperty, Operator, PresetValue, TreeViewObject } from './types';
@@ -10,10 +10,9 @@ export type CriteriaInputProps = {
10
10
  originalCriteria?: Record<string, unknown>;
11
11
  enablePresetValues?: boolean;
12
12
  presetValues?: PresetValue[];
13
- dynamicContentInput?: {
14
- component: ElementType;
15
- previousSteps: unknown[];
16
- trigger?: Record<string, unknown>;
13
+ customValueEditor?: {
14
+ component: (props: ValueEditorProps) => JSX.Element;
15
+ props?: Record<string, unknown>;
17
16
  };
18
17
  operators?: Operator[];
19
18
  disabledCriteria?: {
@@ -3,12 +3,13 @@ import { Typography } from '@mui/material';
3
3
  import { QueryBuilderMaterial } from '@react-querybuilder/material';
4
4
  import { isArray, isEmpty, startCase } from 'lodash';
5
5
  import React, { useEffect, useMemo, useState } from 'react';
6
- import { QueryBuilder, RuleGroupBodyComponents, RuleGroupHeaderComponents, TestID, defaultRuleProcessorMongoDB, formatQuery, useRuleGroup, } from 'react-querybuilder';
6
+ import { QueryBuilder, RuleGroupBodyComponents, RuleGroupHeaderComponents, TestID, add, defaultRuleProcessorMongoDB, formatQuery, useRuleGroup, } from 'react-querybuilder';
7
7
  import 'react-querybuilder/dist/query-builder.css';
8
8
  import escape from 'string-escape-regex';
9
9
  import { TrashCan } from '../../../icons/custom';
10
- import { Autocomplete, Button, IconButton, TextField } from '../../core';
10
+ import { Autocomplete, Button, IconButton } from '../../core';
11
11
  import { Box } from '../../layout';
12
+ import { OverflowTextField } from '../OverflowTextField';
12
13
  import { difference } from '../util';
13
14
  import PropertyTree from './PropertyTree';
14
15
  import { parseMongoDB, traversePropertyPath } from './utils';
@@ -28,6 +29,13 @@ const ALL_OPERATORS = [
28
29
  { name: 'in', label: 'In' },
29
30
  { name: 'notIn', label: 'Not in' },
30
31
  ];
32
+ const styles = {
33
+ buttons: {
34
+ padding: '6px 16px',
35
+ fontSize: '0.875rem',
36
+ boxShadow: 'none',
37
+ },
38
+ };
31
39
  const CustomRuleGroup = (props) => {
32
40
  const rg = { ...props, ...useRuleGroup(props) };
33
41
  const [addRule, addGroup, cloneGroup, toggleLockGroup, removeGroup] = [
@@ -73,11 +81,8 @@ const customButton = (props) => {
73
81
  case 'Add rule':
74
82
  buttonLabel = 'Add Condition';
75
83
  break;
76
- case 'Remove group':
77
- buttonLabel = 'Clear All';
78
- break;
79
84
  }
80
- return (React.createElement(React.Fragment, null, (path.length < nestedConditionLimit || title === 'Add rule') && (React.createElement(Button, { onClick: handleOnClick, startIcon: React.createElement(AddRounded, null), sx: {
85
+ return (React.createElement(React.Fragment, null, !!path.length && (path.length < nestedConditionLimit || title === 'Add rule') && (React.createElement(Button, { onClick: handleOnClick, startIcon: React.createElement(AddRounded, null), sx: {
81
86
  padding: '6px 16px',
82
87
  fontSize: '0.875rem',
83
88
  marginRight: path.length === 0 ? '.5rem' : '0px',
@@ -193,7 +198,7 @@ const customSelector = (props) => {
193
198
  };
194
199
  return (React.createElement(React.Fragment, null, isTreeViewEnabled ? (React.createElement(PropertyTree, { value: val ?? value, rootObject: object, fetchObject: fetchObject, handleTreePropertySelect: handleTreePropertySelect })) : (React.createElement(Autocomplete, { options: opts, value: val ?? null, getOptionLabel: (option) => {
195
200
  if (typeof option === 'string') {
196
- return opts.find((o) => option === o.name)?.label || '';
201
+ return opts.find((o) => option === o.name)?.label || option;
197
202
  }
198
203
  return option.label;
199
204
  }, isOptionEqualToValue: (option, value) => {
@@ -207,7 +212,10 @@ const customSelector = (props) => {
207
212
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
208
213
  onChange: (event, newValue) => {
209
214
  handleOnChange(newValue?.value.name);
210
- }, renderInput: (params) => React.createElement(TextField, { ...params, placeholder: placeholder, size: "small" }), sx: { width: width, background: '#fff' }, disableClearable: true, readOnly: readOnly }))));
215
+ }, renderInput: (params) => (React.createElement(OverflowTextField, { value: opts.find((o) => value === o.name)?.label || '', ...params, placeholder: placeholder, size: "small", inputProps: {
216
+ ...params.inputProps,
217
+ 'aria-label': placeholder,
218
+ } })), sx: { width: width, background: readOnly ? '#f4f6f8' : '#fff' }, disableClearable: true, readOnly: readOnly }))));
211
219
  };
212
220
  const customCombinator = (props) => {
213
221
  const { value, handleOnChange, context, level, path } = props;
@@ -272,7 +280,7 @@ export const valueEditor = (props) => {
272
280
  return ValueEditor(props);
273
281
  };
274
282
  const CriteriaBuilder = (props) => {
275
- const { properties, criteria, setCriteria, originalCriteria, enablePresetValues, presetValues, operators, dynamicContentInput, disabled, disabledCriteria, hideBorder, presetGroupLabel, treeViewOpts, disableRegexEscapeChars, } = props;
283
+ const { properties, criteria, setCriteria, originalCriteria, enablePresetValues, presetValues, operators, disabled, disabledCriteria, hideBorder, presetGroupLabel, customValueEditor, treeViewOpts, disableRegexEscapeChars, } = props;
276
284
  const [query, setQuery] = useState(undefined);
277
285
  const [propertyTreeMap, setPropertyTreeMap] = useState();
278
286
  useEffect(() => {
@@ -282,33 +290,41 @@ const CriteriaBuilder = (props) => {
282
290
  !isEmpty(treeViewOpts) && updatePropertyTreeMap(updatedQuery);
283
291
  setQuery({
284
292
  ...updatedQuery,
285
- rules: processRules(updatedQuery.rules),
293
+ rules: processRules(updatedQuery.rules, true),
286
294
  });
287
295
  }
288
296
  else {
289
297
  setQuery({ combinator: 'and', rules: [] });
290
298
  }
291
299
  }, [originalCriteria]);
292
- function processRules(rules) {
300
+ const processRules = (rules, isSavedValue) => {
293
301
  return rules.map((rule) => {
294
302
  if ('rules' in rule) {
295
303
  return {
296
304
  ...rule,
297
- rules: processRules(rule.rules),
305
+ rules: processRules(rule.rules, isSavedValue),
298
306
  };
299
307
  }
300
308
  else {
301
309
  const propertyType = properties.find((property) => property.id === rule.field)?.type;
310
+ let adjustedValue = rule.value;
311
+ if ((propertyType === 'array' ||
312
+ ((propertyType === 'string' || propertyType === 'richText') &&
313
+ (rule.operator === 'in' || rule.operator === 'notIn'))) &&
314
+ isSavedValue) {
315
+ adjustedValue = rule.value?.split(',');
316
+ }
317
+ else if ((rule.operator === 'null' || rule.operator === 'notNull') && rule.value) {
318
+ adjustedValue = null;
319
+ }
302
320
  return {
303
321
  ...rule,
304
- value: propertyType === 'array' ||
305
- (propertyType === 'string' && (rule.operator === 'in' || rule.operator === 'notIn'))
306
- ? rule.value?.split(',')
307
- : rule.value,
322
+ operator: propertyType === 'array' && rule.operator === '=' ? 'in' : rule.operator,
323
+ value: adjustedValue,
308
324
  };
309
325
  }
310
326
  });
311
- }
327
+ };
312
328
  // this retrieves the properties from a treeview for each property in the query
313
329
  // they are then used in the custom query builder components to determine the input type etc
314
330
  const updatePropertyTreeMap = (q) => {
@@ -334,9 +350,31 @@ const CriteriaBuilder = (props) => {
334
350
  setPropertyTreeMap(tempPropertyMap);
335
351
  });
336
352
  };
353
+ const handleClearAll = () => {
354
+ handleQueryChange({ combinator: 'and', rules: [] });
355
+ };
356
+ const handleAddRule = () => {
357
+ if (query) {
358
+ const newQuery = add(query, { field: '', operator: '', value: '' }, []);
359
+ setQuery(newQuery);
360
+ }
361
+ };
362
+ const handleAddGroup = () => {
363
+ if (query) {
364
+ const newQuery = add(query, {
365
+ combinator: 'and',
366
+ rules: [{ field: '', operator: '', value: '' }],
367
+ }, []);
368
+ setQuery(newQuery);
369
+ }
370
+ };
337
371
  const handleQueryChange = (q) => {
338
- setQuery(q);
339
- const newCriteria = JSON.parse(formatQuery(q, {
372
+ const processedQuery = {
373
+ ...q,
374
+ rules: processRules(q.rules, false),
375
+ };
376
+ setQuery(processedQuery);
377
+ const newCriteria = JSON.parse(formatQuery(processedQuery, {
340
378
  format: 'mongodb',
341
379
  ruleProcessor: (rule, options) => {
342
380
  let newRule = rule;
@@ -352,16 +390,12 @@ const CriteriaBuilder = (props) => {
352
390
  return defaultRuleProcessorMongoDB(newRule, options);
353
391
  },
354
392
  }));
355
- //when q has no rules, it formats and parses to { $and: [{ $expr: true }] }
356
- const allRulesDeleted = isEmpty(difference(newCriteria, { $and: [{ $expr: true }] }));
357
- // since the Add Condition / Add Group buttons add rules with all the fields empty,
358
- // we need to check if the first rule was added because q will still parse to { $and: [{ $expr: true }] }
359
- const firstRuleAdded = isEmpty(criteria) && q.rules.length > 0;
360
- if (allRulesDeleted && !firstRuleAdded) {
361
- setCriteria(undefined);
393
+ if (!isEmpty(difference(newCriteria, { $and: [{ $expr: true }] }))) {
394
+ setCriteria(newCriteria);
362
395
  }
363
396
  else {
364
- setCriteria(newCriteria);
397
+ if (q.rules.length === 0)
398
+ setCriteria(undefined);
365
399
  }
366
400
  };
367
401
  const fields = useMemo(() => {
@@ -424,7 +458,9 @@ const CriteriaBuilder = (props) => {
424
458
  '.ruleGroup .ruleGroup': { borderStyle: 'solid' },
425
459
  } },
426
460
  React.createElement(QueryBuilderMaterial, null,
427
- React.createElement(QueryBuilder, { query: !criteria && !originalCriteria ? { combinator: 'and', rules: [] } : query, fields: fields, onQueryChange: (q) => {
461
+ React.createElement(QueryBuilder, { query: !criteria && !originalCriteria && query.rules.length === 0
462
+ ? { combinator: 'and', rules: [] }
463
+ : query, fields: fields, onQueryChange: (q) => {
428
464
  handleQueryChange(q);
429
465
  }, onAddRule: (rule) => {
430
466
  // overrides new rule and sets up an empty rule with all three fields empty
@@ -461,9 +497,9 @@ const CriteriaBuilder = (props) => {
461
497
  ruleGroup: CustomRuleGroup,
462
498
  removeGroupAction: customDelete,
463
499
  removeRuleAction: customDelete,
464
- valueEditor: valueEditor,
500
+ valueEditor: customValueEditor ? customValueEditor.component : valueEditor,
465
501
  }, context: {
466
- dynamicContentInput,
502
+ ...(customValueEditor?.props ?? {}),
467
503
  presetValues,
468
504
  enablePresetValues,
469
505
  presetGroupLabel,
@@ -483,7 +519,43 @@ const CriteriaBuilder = (props) => {
483
519
  ruleGroup: 'container',
484
520
  }, operators: operators
485
521
  ? ALL_OPERATORS.filter((o) => operators.includes(o.name))
486
- : ALL_OPERATORS }))));
522
+ : ALL_OPERATORS })),
523
+ React.createElement(Box, { sx: {
524
+ display: 'flex',
525
+ justifyContent: 'space-between',
526
+ alignItems: 'center',
527
+ marginBottom: '10px',
528
+ maxWidth: '71vw',
529
+ } },
530
+ React.createElement(Box, null,
531
+ React.createElement(Button, { sx: {
532
+ backgroundColor: 'rgba(0, 117, 167, 0.08)',
533
+ color: '#0075A7',
534
+ marginLeft: '10px',
535
+ '&:hover': {
536
+ backgroundColor: 'rgba(0, 117, 167, 0.08)',
537
+ },
538
+ ...styles.buttons,
539
+ }, startIcon: React.createElement(AddRounded, null), onClick: handleAddRule }, "Add Condition"),
540
+ React.createElement(Button, { sx: {
541
+ backgroundColor: '#f6f7f8',
542
+ color: '#000',
543
+ marginLeft: '8px',
544
+ '&:hover': {
545
+ backgroundColor: '#f6f7f8',
546
+ },
547
+ ...styles.buttons,
548
+ }, startIcon: React.createElement(AddRounded, null), onClick: handleAddGroup, title: "Add a rule at the bottom of the group" }, "Add Condition Group")),
549
+ React.createElement(Button, { variant: 'text', sx: {
550
+ justifyContent: 'flex-end',
551
+ color: '#000',
552
+ fontWeight: 500,
553
+ paddingLeft: '0px',
554
+ '&:hover': {
555
+ backgroundColor: 'transparent',
556
+ },
557
+ ...styles.buttons,
558
+ }, onClick: handleClearAll, title: "Clear all conditions", disabled: isEmpty(query.rules) }, "Clear all"))));
487
559
  }
488
560
  return React.createElement(React.Fragment, null);
489
561
  };
@@ -1,6 +1,7 @@
1
1
  import { ChevronRight, ExpandMore } from '@mui/icons-material';
2
2
  import React, { useEffect, useState } from 'react';
3
- import { Autocomplete, MenuItem, TextField, Tooltip, TreeView } from '../../core';
3
+ import { Autocomplete, MenuItem, TreeView } from '../../core';
4
+ import { OverflowTextField } from '../OverflowTextField';
4
5
  import PropertyTreeItem from './PropertyTreeItem';
5
6
  import { fetchDisplayNamePath, findPropertyById, setIdPaths, truncateNamePath, updateTreeNode } from './utils';
6
7
  const PropertyTree = ({ fetchObject, handleTreePropertySelect, rootObject, value }) => {
@@ -126,15 +127,8 @@ const PropertyTree = ({ fetchObject, handleTreePropertySelect, rootObject, value
126
127
  : objectPropertyNamePathMap[option.value] ?? '';
127
128
  return truncateNamePath(namePath, NAME_PATH_LIMIT);
128
129
  }, renderInput: (params) => {
129
- let isTruncated = false;
130
- const fullDisplayValue = value && objectPropertyNamePathMap[value];
131
- let displayValue = fullDisplayValue;
132
- if (!!displayValue && displayValue.length > NAME_PATH_LIMIT) {
133
- isTruncated = true;
134
- displayValue = truncateNamePath(displayValue, NAME_PATH_LIMIT);
135
- }
136
- return (React.createElement(Tooltip, { title: isTruncated ? fullDisplayValue : '', arrow: true },
137
- React.createElement(TextField, { ...params, "aria-label": fullDisplayValue, value: displayValue, size: "small", placeholder: "Select a property", variant: "outlined" })));
130
+ const fullDisplayName = value && objectPropertyNamePathMap[value];
131
+ return (React.createElement(OverflowTextField, { ...params, "aria-label": fullDisplayName, value: fullDisplayName, size: "small", placeholder: "Select a property", variant: "outlined" }));
138
132
  }, isOptionEqualToValue: (option, val) => {
139
133
  if (typeof val === 'string') {
140
134
  return option.value === val;
@@ -1,9 +1,9 @@
1
1
  import { Instant, LocalDate, LocalDateTime, LocalTime, ZoneId } from '@js-joda/core';
2
2
  import { ClearRounded } from '@mui/icons-material';
3
3
  import { Box, darken, lighten, styled } from '@mui/material';
4
- import { DateTimePicker, TimePicker } from '@mui/x-date-pickers';
5
- import React, { useRef, useState } from 'react';
6
- import { Autocomplete, Chip, DatePicker, LocalizationProvider, Menu, MenuItem, TextField, Typography, } from '../../core';
4
+ import { TimePicker } from '@mui/x-date-pickers';
5
+ import React, { useEffect, useRef, useState } from 'react';
6
+ import { Autocomplete, Chip, DatePicker, DateTimePicker, LocalizationProvider, Menu, MenuItem, TextField, Typography, } from '../../core';
7
7
  import { NumericFormat } from '../FormField/InputFieldComponent';
8
8
  const GroupHeader = styled('div')(({ theme }) => ({
9
9
  position: 'sticky',
@@ -18,7 +18,7 @@ const GroupHeader = styled('div')(({ theme }) => ({
18
18
  }));
19
19
  const GroupItems = styled('ul')({ padding: 0 });
20
20
  const ValueEditor = (props) => {
21
- const { handleOnChange, value, operator, context, level, rule } = props;
21
+ const { handleOnChange, value, operator, context, level, rule, fieldData } = props;
22
22
  let inputType = props.inputType;
23
23
  let values = props.values;
24
24
  const property = context.propertyTreeMap?.[rule.field];
@@ -47,6 +47,20 @@ const ValueEditor = (props) => {
47
47
  readOnly =
48
48
  Object.entries(context.disabledCriteria.criteria).some(([key, value]) => key === rule.field && value === rule.value && rule.operator === '=') && level === context.disabledCriteria.level;
49
49
  }
50
+ const styles = {
51
+ input: {
52
+ width: '33%',
53
+ background: readOnly ? '#f4f6f8' : '#fff',
54
+ },
55
+ };
56
+ useEffect(() => {
57
+ if (!['in', 'notIn'].includes(operator) && Array.isArray(value)) {
58
+ handleOnChange('');
59
+ }
60
+ else if (['in', 'notIn'].includes(operator) && !Array.isArray(value)) {
61
+ handleOnChange([]);
62
+ }
63
+ }, [operator]);
50
64
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
65
  const onClick = (e) => {
52
66
  // if property is date and date picker is open, don't open preset values
@@ -85,11 +99,11 @@ const ValueEditor = (props) => {
85
99
  if (inputType === 'date') {
86
100
  // date editor
87
101
  return (React.createElement(LocalizationProvider, null,
88
- React.createElement(DatePicker, { inputRef: inputRef, disabled: disabled, value: disabled ? null : value, onChange: handleOnChange, onClose: onClose, renderInput: (params) => (React.createElement(TextField, { ...params, onClick: onClick, placeholder: "Value", size: "small", sx: { width: '33%', background: '#fff' } })), readOnly: readOnly })));
102
+ React.createElement(DatePicker, { inputRef: inputRef, disabled: disabled, value: disabled ? null : value, onChange: handleOnChange, onClose: onClose, renderInput: (params) => (React.createElement(TextField, { ...params, onClick: onClick, placeholder: "Value", size: "small", sx: styles.input })), readOnly: readOnly })));
89
103
  }
90
104
  else if (inputType === 'time') {
91
105
  return (React.createElement(LocalizationProvider, null,
92
- React.createElement(TimePicker, { inputRef: inputRef, disabled: disabled, value: disabled || !value ? null : value, onChange: handleOnChange, renderInput: (params) => (React.createElement(TextField, { ...params, onClick: onClick, placeholder: "Value", size: "small", sx: { width: '33%', background: '#fff' } })), readOnly: readOnly })));
106
+ React.createElement(TimePicker, { inputRef: inputRef, disabled: disabled, value: disabled || !value ? null : value, onChange: handleOnChange, renderInput: (params) => (React.createElement(TextField, { ...params, onClick: onClick, placeholder: "Value", size: "small", sx: styles.input })), readOnly: readOnly })));
93
107
  }
94
108
  else if (inputType === 'date-time') {
95
109
  const dateTimeValue = parseISOStringToLocalDateTime(value);
@@ -110,7 +124,7 @@ const ValueEditor = (props) => {
110
124
  handleOnChange(new Date(localDateTime.toString()).toISOString());
111
125
  }, onClose: onClose, PopperProps: {
112
126
  anchorEl,
113
- }, renderInput: (params) => (React.createElement(Box, { sx: { width: '33%', background: '#fff' }, ref: setAnchorEl },
127
+ }, renderInput: (params) => (React.createElement(Box, { sx: styles.input, ref: setAnchorEl },
114
128
  React.createElement(TextField, { ...params, disabled: disabled, onClick: onClick, placeholder: "Value", size: "small", inputRef: inputRef }))), readOnly: readOnly })));
115
129
  }
116
130
  else if (inputType === 'number' || inputType === 'integer') {
@@ -125,7 +139,7 @@ const ValueEditor = (props) => {
125
139
  handleOnChange(uniqueSelections.length ? uniqueSelections : '');
126
140
  },
127
141
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
- isOptionEqualToValue: (option, value) => option === value, renderInput: (params) => (React.createElement(TextField, { label: params.label, ...params, size: "small", sx: { backgroundColor: '#fff' } })), groupBy: (option) => isPresetValue(option.value?.name) ? context.presetGroupLabel || 'Preset Values' : 'Options', renderGroup: groupRenderGroup, sx: { width: '33%', background: '#fff' }, readOnly: readOnly }));
142
+ isOptionEqualToValue: (option, value) => option === value, renderInput: (params) => (React.createElement(TextField, { label: params.label, ...params, size: "small" })), groupBy: (option) => isPresetValue(option.value?.name) ? context.presetGroupLabel || 'Preset Values' : 'Options', renderGroup: groupRenderGroup, sx: styles.input, readOnly: readOnly }));
129
143
  }
130
144
  else {
131
145
  return (React.createElement(TextField, { inputRef: inputRef, value: ['null', 'notNull'].includes(operator) ? '' : value, disabled: ['null', 'notNull'].includes(operator), onChange: (e) => {
@@ -137,7 +151,7 @@ const ValueEditor = (props) => {
137
151
  }
138
152
  }, ...(inputType === 'number'
139
153
  ? { InputProps: { inputComponent: NumericFormat } }
140
- : { type: 'number' }), placeholder: "Value", size: "small", onClick: onClick, sx: { width: '33%', background: '#fff' }, readOnly: readOnly }));
154
+ : { type: 'number' }), placeholder: "Value", size: "small", onClick: onClick, sx: styles.input, readOnly: readOnly }));
141
155
  }
142
156
  }
143
157
  else {
@@ -147,7 +161,7 @@ const ValueEditor = (props) => {
147
161
  ...(presetValues?.sort((a, b) => a.label.localeCompare(b.label)) ?? []),
148
162
  ];
149
163
  if (isMultiple || values?.length) {
150
- return (React.createElement(Autocomplete, { freeSolo: inputType !== 'array' && inputType !== 'select', multiple: isMultiple, options: options, value: isMultiple ? (Array.isArray(value) ? value : []) : value,
164
+ return (React.createElement(Autocomplete, { freeSolo: inputType !== 'array' && fieldData.valueEditorType !== 'select', multiple: isMultiple, options: options, value: isMultiple ? (Array.isArray(value) ? value : []) : Array.isArray(value) ? '' : value,
151
165
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
152
166
  onChange: (event, newValue) => {
153
167
  let value;
@@ -161,14 +175,25 @@ const ValueEditor = (props) => {
161
175
  }
162
176
  handleOnChange(value);
163
177
  }, onBlur: () => {
164
- if (inputValue && (operator === 'in' || operator === 'notIn')) {
178
+ if (inputValue &&
179
+ (options.some((option) => option.name === inputValue) || !options.length) &&
180
+ (operator === 'in' || operator === 'notIn')) {
181
+ const newValues = Array.isArray(value) ? [...value, inputValue] : [inputValue];
182
+ handleOnChange(Array.from(new Set(newValues)));
183
+ setInputValue('');
184
+ }
185
+ }, onKeyDown: (event) => {
186
+ if (event.key === 'Enter' &&
187
+ inputValue &&
188
+ (options.some((option) => option.name === inputValue) || !options.length) &&
189
+ (operator === 'in' || operator === 'notIn')) {
165
190
  const newValues = Array.isArray(value) ? [...value, inputValue] : [inputValue];
166
191
  handleOnChange(Array.from(new Set(newValues)));
167
192
  setInputValue('');
168
193
  }
169
194
  }, onInputChange: (event, newInputValue) => {
170
195
  setInputValue(newInputValue);
171
- }, inputValue: inputValue, renderInput: (params) => (React.createElement(TextField, { inputRef: inputRef, label: params?.label, ...params, size: "small", sx: { backgroundColor: '#fff' } })),
196
+ }, inputValue: inputValue, renderInput: (params) => (React.createElement(TextField, { inputRef: inputRef, label: params?.label, ...params, size: "small" })),
172
197
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
173
198
  getOptionLabel: (option) => {
174
199
  if (typeof option === 'string') {
@@ -185,10 +210,10 @@ const ValueEditor = (props) => {
185
210
  else {
186
211
  return option?.label === value?.label;
187
212
  }
188
- }, groupBy: (option) => isPresetValue(option.value?.name) ? context.presetGroupLabel || 'Preset Values' : 'Options', renderGroup: groupRenderGroup, sortBy: "NONE", sx: { width: '33%' }, readOnly: readOnly }));
213
+ }, groupBy: (option) => isPresetValue(option.value?.name) ? context.presetGroupLabel || 'Preset Values' : 'Options', renderGroup: groupRenderGroup, sortBy: "NONE", sx: styles.input, readOnly: readOnly }));
189
214
  }
190
215
  else {
191
- return (React.createElement(TextField, { inputRef: inputRef, value: ['null', 'notNull'].includes(operator) ? '' : value, disabled: ['null', 'notNull'].includes(operator), onChange: (e) => handleOnChange(e.target.value), onClick: onClick, placeholder: "Value", size: "small", sx: { width: '33%', background: '#fff' }, readOnly: readOnly }));
216
+ return (React.createElement(TextField, { inputRef: inputRef, value: ['null', 'notNull'].includes(operator) ? '' : value, disabled: ['null', 'notNull'].includes(operator), onChange: (e) => handleOnChange(e.target.value), onClick: onClick, placeholder: "Value", size: "small", sx: styles.input, readOnly: readOnly }));
192
217
  }
193
218
  }
194
219
  };
@@ -1,6 +1,6 @@
1
- /// <reference types="react" />
2
1
  import { ApiServices, Obj, ObjectInstance, UserAccount } from '@evoke-platform/context';
3
2
  import { ReactComponent } from '@formio/react';
3
+ import React from 'react';
4
4
  import '../../../../styles/form-component.css';
5
5
  import { Document, ObjectPropertyInputProps } from '../types';
6
6
  type OnSaveResponse = {
@@ -34,6 +34,12 @@ export type FormProps = {
34
34
  queryAddresses?: unknown;
35
35
  fieldHeight?: 'small' | 'medium';
36
36
  richTextEditor?: typeof ReactComponent;
37
+ hideButtons?: boolean;
38
+ formRef?: React.MutableRefObject<FormRef | undefined>;
39
+ };
40
+ export type FormRef = {
41
+ submit: (submission: Record<string, unknown>, type: 'submit' | 'draft', setError: (error?: Record<string, unknown>) => void, setSubmitting?: (value: boolean) => void) => void;
42
+ data?: Record<string, unknown>;
37
43
  };
38
44
  export declare function Form(props: FormProps): JSX.Element;
39
45
  export default Form;