@teselagen/ui 0.5.21 → 0.5.23-beta.1

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 (76) hide show
  1. package/DataTable/Columns.d.ts +1 -0
  2. package/DataTable/DisplayOptions.d.ts +14 -14
  3. package/DataTable/EditabelCell.d.ts +3 -5
  4. package/DataTable/FilterAndSortMenu.d.ts +9 -9
  5. package/DataTable/PagingTool.d.ts +25 -2
  6. package/DataTable/SearchBar.d.ts +2 -2
  7. package/DataTable/SortableColumns.d.ts +6 -9
  8. package/DataTable/ThComponent.d.ts +9 -0
  9. package/DataTable/index.d.ts +0 -5
  10. package/DataTable/utils/getIdOrCodeOrIndex.d.ts +1 -2
  11. package/DataTable/utils/handleCopyTable.d.ts +1 -0
  12. package/DataTable/utils/index.d.ts +4 -2
  13. package/DataTable/utils/primarySelectedValue.d.ts +1 -0
  14. package/DataTable/utils/queryParams.d.ts +6 -0
  15. package/DataTable/utils/removeCleanRows.d.ts +1 -1
  16. package/DataTable/utils/rowClick.d.ts +24 -3
  17. package/DataTable/utils/useDeepEqualMemo.d.ts +1 -0
  18. package/DataTable/utils/useTableParams.d.ts +49 -0
  19. package/FormComponents/Uploader.d.ts +34 -1
  20. package/FormComponents/index.d.ts +111 -45
  21. package/MatchHeaders.d.ts +9 -10
  22. package/SimpleStepViz.d.ts +2 -1
  23. package/TgSuggest/index.d.ts +1 -21
  24. package/UploadCsvWizard.d.ts +1 -1
  25. package/index.cjs.js +41038 -45265
  26. package/index.d.ts +3 -2
  27. package/index.es.js +44524 -48751
  28. package/package.json +2 -8
  29. package/src/DataTable/CellDragHandle.js +70 -69
  30. package/src/DataTable/ColumnFilterMenu.js +18 -18
  31. package/src/DataTable/Columns.js +1066 -0
  32. package/src/DataTable/DisplayOptions.js +173 -192
  33. package/src/DataTable/EditabelCell.js +6 -16
  34. package/src/DataTable/FilterAndSortMenu.js +213 -234
  35. package/src/DataTable/PagingTool.js +47 -56
  36. package/src/DataTable/SearchBar.js +3 -3
  37. package/src/DataTable/SortableColumns.js +44 -39
  38. package/src/DataTable/ThComponent.js +44 -0
  39. package/src/DataTable/dataTableEnhancer.js +35 -294
  40. package/src/DataTable/index.js +2933 -3601
  41. package/src/DataTable/utils/getIdOrCodeOrIndex.js +1 -1
  42. package/src/DataTable/utils/handleCopyTable.js +16 -0
  43. package/src/DataTable/utils/index.js +7 -3
  44. package/src/DataTable/utils/primarySelectedValue.js +1 -0
  45. package/src/DataTable/utils/queryParams.js +42 -13
  46. package/src/DataTable/utils/removeCleanRows.js +3 -3
  47. package/src/DataTable/utils/rowClick.js +34 -9
  48. package/src/DataTable/utils/selection.js +1 -1
  49. package/src/DataTable/utils/useDeepEqualMemo.js +10 -0
  50. package/src/DataTable/utils/useTableParams.js +361 -0
  51. package/src/DataTable/utils/withTableParams.js +30 -87
  52. package/src/DataTable/validateTableWideErrors.js +1 -1
  53. package/src/DialogFooter/index.js +3 -3
  54. package/src/FillWindow.js +2 -3
  55. package/src/FormComponents/Uploader.js +825 -784
  56. package/src/FormComponents/index.js +441 -603
  57. package/src/FormComponents/tryToMatchSchemas.js +1 -6
  58. package/src/MatchHeaders.js +27 -22
  59. package/src/SimpleStepViz.js +19 -23
  60. package/src/TgSuggest/index.js +94 -106
  61. package/src/UploadCsvWizard.js +570 -577
  62. package/src/index.js +4 -3
  63. package/src/showDialogOnDocBody.js +5 -9
  64. package/src/useDialog.js +25 -26
  65. package/src/utils/commandControls.js +2 -2
  66. package/src/utils/handlerHelpers.js +19 -25
  67. package/src/utils/popoverOverflowModifiers.js +1 -1
  68. package/src/utils/renderOnDoc.js +8 -5
  69. package/src/utils/tagUtils.js +3 -3
  70. package/src/utils/useTraceUpdate.js +19 -0
  71. package/src/wrapDialog.js +0 -2
  72. package/style.css +251 -251
  73. package/useDialog.d.ts +2 -6
  74. package/utils/renderOnDoc.d.ts +1 -1
  75. package/utils/tagUtils.d.ts +5 -1
  76. package/utils/useTraceUpdate.d.ts +1 -0
@@ -2,9 +2,8 @@ import classNames from "classnames";
2
2
  import { SketchPicker } from "react-color";
3
3
  import { isNumber, noop, kebabCase, isPlainObject, isEqual } from "lodash-es";
4
4
  import mathExpressionEvaluator from "math-expression-evaluator";
5
- import React, { useContext, useState } from "react";
5
+ import React, { useContext, useEffect, useState } from "react";
6
6
  import { Field, change } from "redux-form";
7
-
8
7
  import "./style.css";
9
8
  import {
10
9
  InputGroup,
@@ -22,7 +21,6 @@ import {
22
21
  TextArea,
23
22
  Popover
24
23
  } from "@blueprintjs/core";
25
-
26
24
  import { DateInput, DateRangeInput } from "@blueprintjs/datetime";
27
25
  import useDeepCompareEffect from "use-deep-compare-effect";
28
26
  import { difference } from "lodash-es";
@@ -41,6 +39,7 @@ import popoverOverflowModifiers from "../utils/popoverOverflowModifiers";
41
39
  import Uploader from "./Uploader";
42
40
  import sortify from "./sortify";
43
41
  import { fieldRequired } from "./utils";
42
+ import { useDispatch } from "react-redux";
44
43
 
45
44
  export { fieldRequired };
46
45
 
@@ -57,8 +56,14 @@ function getIntent({
57
56
  }
58
57
  }
59
58
 
60
- function getIntentClass(...args) {
61
- const intent = getIntent(...args);
59
+ function getIntentClass({
60
+ showErrorIfUntouched,
61
+ meta: { touched, error, warning }
62
+ }) {
63
+ const intent = getIntent({
64
+ showErrorIfUntouched,
65
+ meta: { touched, error, warning }
66
+ });
62
67
  if (intent === Intent.DANGER) {
63
68
  return Classes.INTENT_DANGER;
64
69
  } else if (intent === Intent.WARNING) {
@@ -100,8 +105,8 @@ function removeUnwantedProps(props) {
100
105
  return cleanedProps;
101
106
  }
102
107
 
103
- function LabelWithTooltipInfo({ label, tooltipInfo, labelStyle }) {
104
- return tooltipInfo ? (
108
+ const LabelWithTooltipInfo = ({ label, tooltipInfo, labelStyle }) =>
109
+ tooltipInfo ? (
105
110
  <div style={{ display: "flex", alignItems: "center", ...labelStyle }}>
106
111
  {label}{" "}
107
112
  <InfoHelper
@@ -113,253 +118,212 @@ function LabelWithTooltipInfo({ label, tooltipInfo, labelStyle }) {
113
118
  ) : (
114
119
  label || null
115
120
  );
116
- }
117
121
 
118
- class AbstractInput extends React.Component {
119
- componentDidMount() {
120
- const {
121
- defaultValue,
122
- enableReinitialize,
123
- input: { value }
124
- } = this.props;
125
- if (
126
- ((value !== false && !value) || enableReinitialize) &&
127
- defaultValue !== undefined
128
- ) {
129
- this.updateDefaultValue();
122
+ const AbstractInput = ({
123
+ assignDefaultButton,
124
+ asyncValidating,
125
+ className,
126
+ children,
127
+ containerStyle,
128
+ defaultValue,
129
+ disabled,
130
+ fileLimit,
131
+ inlineLabel,
132
+ input: { name },
133
+ intent,
134
+ isLabelTooltip,
135
+ isLoadingDefaultValue,
136
+ isRequired,
137
+ label,
138
+ labelStyle,
139
+ leftEl,
140
+ meta: { form, touched, error, warning },
141
+ noFillField,
142
+ noMarginBottom,
143
+ noOuterLabel,
144
+ onDefaultValChanged,
145
+ onFieldSubmit,
146
+ rightEl,
147
+ secondaryLabel,
148
+ setAssignDefaultsMode,
149
+ showErrorIfUntouched,
150
+ showGenerateDefaultDot,
151
+ startAssigningDefault,
152
+ tooltipError,
153
+ tooltipInfo,
154
+ tooltipProps
155
+ }) => {
156
+ const dispatch = useDispatch();
157
+
158
+ // This only takes care that the default Value is changed when it is changed in the parent component
159
+ useEffect(() => {
160
+ if (defaultValue !== undefined) {
161
+ dispatch(change(form, name, defaultValue));
162
+ onDefaultValChanged && onDefaultValChanged(defaultValue, name, form);
163
+ onFieldSubmit && onFieldSubmit(defaultValue);
130
164
  }
165
+ // eslint-disable-next-line react-hooks/exhaustive-deps
166
+ }, [defaultValue]);
167
+
168
+ // if our custom field level validation is happening then we don't want to show the error visually
169
+ const showError =
170
+ (touched || showErrorIfUntouched) && error && !asyncValidating;
171
+ const showWarning = (touched || showErrorIfUntouched) && warning;
172
+ let componentToWrap =
173
+ isLabelTooltip || tooltipError ? (
174
+ <Tooltip
175
+ disabled={isLabelTooltip ? false : !showError}
176
+ intent={isLabelTooltip ? "none" : error ? "danger" : "warning"}
177
+ content={isLabelTooltip ? label : error || warning}
178
+ position={Position.TOP}
179
+ modifiers={popoverOverflowModifiers}
180
+ {...tooltipProps}
181
+ >
182
+ {children}
183
+ </Tooltip>
184
+ ) : (
185
+ children
186
+ );
187
+ const testClassName = "tg-test-" + kebabCase(name);
188
+ if (noFillField) {
189
+ componentToWrap = <div className="tg-no-fill-field">{componentToWrap}</div>;
131
190
  }
132
191
 
133
- componentDidUpdate(oldProps) {
134
- const {
135
- defaultValue: oldDefaultValue,
136
- defaultValCount: oldDefaultValCount
137
- } = oldProps;
138
- const {
139
- defaultValue,
140
- defaultValCount,
141
- enableReinitialize,
142
- input: { value }
143
- } = this.props;
144
-
145
- if (
146
- ((value !== false && !value) ||
147
- enableReinitialize ||
148
- defaultValCount !== oldDefaultValCount) &&
149
- !isEqual(defaultValue, oldDefaultValue)
150
- ) {
151
- this.updateDefaultValue();
192
+ let helperText;
193
+ if (!tooltipError) {
194
+ if (showError) {
195
+ helperText = error;
196
+ } else if (showWarning) {
197
+ helperText = warning;
152
198
  }
153
199
  }
154
200
 
155
- updateDefaultValue = () => {
156
- const {
157
- defaultValue,
158
- input: { name },
159
- meta: { dispatch, form },
160
- onDefaultValChanged,
161
- onFieldSubmit
162
- } = this.props;
163
- dispatch(change(form, name, defaultValue));
164
- onDefaultValChanged &&
165
- onDefaultValChanged(defaultValue, name, form, this.props);
166
- onFieldSubmit && onFieldSubmit(defaultValue);
167
- };
168
-
169
- render() {
170
- const {
171
- children,
172
- tooltipProps,
173
- tooltipError,
174
- disabled,
175
- intent,
176
- tooltipInfo,
177
- label,
178
- inlineLabel,
179
- isLabelTooltip,
180
- secondaryLabel,
181
- className,
182
- showErrorIfUntouched,
183
- asyncValidating,
184
- meta,
185
- containerStyle,
186
- leftEl,
187
- rightEl,
188
- labelStyle,
189
- noOuterLabel,
190
- fileLimit,
191
- noMarginBottom,
192
- assignDefaultButton,
193
- showGenerateDefaultDot,
194
- setAssignDefaultsMode,
195
- startAssigningDefault,
196
- input,
197
- noFillField,
198
- isRequired,
199
- isLoadingDefaultValue
200
- } = this.props;
201
- const { touched, error, warning } = meta;
202
-
203
- // if our custom field level validation is happening then we don't want to show the error visually
204
- const showError =
205
- (touched || showErrorIfUntouched) && error && !asyncValidating;
206
- const showWarning = (touched || showErrorIfUntouched) && warning;
207
- let componentToWrap =
208
- isLabelTooltip || tooltipError ? (
209
- <Tooltip
210
- disabled={isLabelTooltip ? false : !showError}
211
- intent={isLabelTooltip ? "none" : error ? "danger" : "warning"}
212
- content={isLabelTooltip ? label : error || warning}
213
- position={Position.TOP}
214
- modifiers={popoverOverflowModifiers}
215
- {...tooltipProps}
216
- >
217
- {children}
218
- </Tooltip>
219
- ) : (
220
- children
221
- );
222
- const testClassName = "tg-test-" + kebabCase(input.name);
223
- if (noFillField) {
224
- componentToWrap = (
225
- <div className="tg-no-fill-field">{componentToWrap}</div>
226
- );
227
- }
228
-
229
- let helperText;
230
- if (!tooltipError) {
231
- if (showError) {
232
- helperText = error;
233
- } else if (showWarning) {
234
- helperText = warning;
235
- }
236
- }
237
-
238
- // if in a cypress test show message so that inputs will not be interactable
239
- if (window.Cypress && isLoadingDefaultValue) {
240
- return "Loading default value...";
241
- }
242
-
243
- let labelInfo = secondaryLabel;
244
-
245
- const hasOuterLabel = !noOuterLabel && !isLabelTooltip;
246
- function getFileLimitInfo() {
247
- if (!fileLimit) return "";
248
- return `max ${fileLimit} file${fileLimit === 1 ? "" : "s"}`;
249
- }
201
+ // if in a cypress test show message so that inputs will not be interactable
202
+ if (window.Cypress && isLoadingDefaultValue) {
203
+ return "Loading default value...";
204
+ }
250
205
 
251
- if (isRequired && hasOuterLabel && label && !labelInfo) {
252
- labelInfo = `(required${fileLimit ? `, ${getFileLimitInfo()}` : ""})`;
253
- } else if (!labelInfo && fileLimit) {
254
- labelInfo = `(${getFileLimitInfo()})`;
255
- }
206
+ let labelInfo = secondaryLabel;
256
207
 
257
- return (
258
- <FormGroup
259
- className={classNames(className, testClassName, {
260
- "tg-flex-form-content": leftEl || rightEl,
261
- "tg-tooltipError": tooltipError,
262
- "tg-has-error": showError && error
263
- })}
264
- disabled={disabled}
265
- helperText={helperText}
266
- intent={intent}
267
- label={
268
- hasOuterLabel && (
269
- <LabelWithTooltipInfo
270
- labelStyle={labelStyle}
271
- label={label}
272
- tooltipInfo={tooltipInfo}
273
- />
274
- )
275
- }
276
- inline={inlineLabel}
277
- labelInfo={labelInfo}
278
- style={{
279
- ...(noMarginBottom && { marginBottom: 0 }),
280
- ...containerStyle
281
- }}
282
- >
283
- {showGenerateDefaultDot && (
284
- <div
285
- style={{ zIndex: 10, position: "relative", height: 0, width: 0 }}
286
- >
287
- <div style={{ position: "absolute", left: "0px", top: "0px" }}>
288
- <Tooltip
289
- modifiers={popoverOverflowModifiers}
290
- content="Allows a Default to be Set. Click to Enter Set Default Mode (or press Shift+D when outside the input field)"
291
- >
292
- <div
293
- onClick={() => {
294
- setAssignDefaultsMode(true);
295
- startAssigningDefault();
296
- }}
297
- className="generateDefaultDot"
298
- ></div>
299
- </Tooltip>
300
- </div>
301
- </div>
302
- )}
303
- {assignDefaultButton}
304
- {leftEl} {componentToWrap} {rightEl}
305
- </FormGroup>
306
- );
208
+ const hasOuterLabel = !noOuterLabel && !isLabelTooltip;
209
+ function getFileLimitInfo() {
210
+ if (!fileLimit) return "";
211
+ return `max ${fileLimit} file${fileLimit === 1 ? "" : "s"}`;
307
212
  }
308
- }
309
-
310
- export const renderBlueprintDateInput = props => {
311
- const { input, intent, onFieldSubmit, inputProps, ...rest } = props;
312
- return (
313
- <DateInput
314
- {...getDayjsFormatter("L")}
315
- {...removeUnwantedProps(rest)}
316
- intent={intent}
317
- inputProps={inputProps}
318
- {...input}
319
- value={input.value ? new Date(input.value) : undefined}
320
- onChange={function (selectedDate) {
321
- input.onChange(selectedDate);
322
- onFieldSubmit(selectedDate);
323
- }}
324
- />
325
- );
326
- };
327
213
 
328
- export const renderBlueprintDateRangeInput = props => {
329
- const { input, intent, onFieldSubmit, inputProps, ...rest } = props;
214
+ if (isRequired && hasOuterLabel && label && !labelInfo) {
215
+ labelInfo = `(required${fileLimit ? `, ${getFileLimitInfo()}` : ""})`;
216
+ } else if (!labelInfo && fileLimit) {
217
+ labelInfo = `(${getFileLimitInfo()})`;
218
+ }
330
219
 
331
220
  return (
332
- <DateRangeInput
333
- {...getDayjsFormatter("L")}
334
- {...removeUnwantedProps(rest)}
221
+ <FormGroup
222
+ className={classNames(className, testClassName, {
223
+ "tg-flex-form-content": leftEl || rightEl,
224
+ "tg-tooltipError": tooltipError,
225
+ "tg-has-error": showError && error
226
+ })}
227
+ disabled={disabled}
228
+ helperText={helperText}
335
229
  intent={intent}
336
- inputProps={inputProps}
337
- {...input}
338
- value={
339
- input.value
340
- ? [new Date(input.value[0]), new Date(input.value[1])]
341
- : undefined
230
+ label={
231
+ hasOuterLabel && (
232
+ <LabelWithTooltipInfo
233
+ labelStyle={labelStyle}
234
+ label={label}
235
+ tooltipInfo={tooltipInfo}
236
+ />
237
+ )
342
238
  }
343
- onChange={function (selectedDate) {
344
- input.onChange(selectedDate);
345
- onFieldSubmit(selectedDate);
239
+ inline={inlineLabel}
240
+ labelInfo={labelInfo}
241
+ style={{
242
+ ...(noMarginBottom && { marginBottom: 0 }),
243
+ ...containerStyle
346
244
  }}
347
- />
245
+ >
246
+ {showGenerateDefaultDot && (
247
+ <div style={{ zIndex: 10, position: "relative", height: 0, width: 0 }}>
248
+ <div style={{ position: "absolute", left: "0px", top: "0px" }}>
249
+ <Tooltip
250
+ modifiers={popoverOverflowModifiers}
251
+ content="Allows a Default to be Set. Click to Enter Set Default Mode (or press Shift+D when outside the input field)"
252
+ >
253
+ <div
254
+ onClick={() => {
255
+ setAssignDefaultsMode(true);
256
+ startAssigningDefault();
257
+ }}
258
+ className="generateDefaultDot"
259
+ />
260
+ </Tooltip>
261
+ </div>
262
+ </div>
263
+ )}
264
+ {assignDefaultButton}
265
+ {leftEl} {componentToWrap} {rightEl}
266
+ </FormGroup>
348
267
  );
349
268
  };
350
269
 
351
- export const RenderBlueprintInput = props => {
352
- const {
353
- input,
354
- // meta = {},
355
- intent,
356
- onFieldSubmit,
357
- onKeyDown = noop,
358
- asyncValidating,
359
- rightElement,
360
- clickToEdit,
361
- ...rest
362
- } = props;
270
+ export const renderBlueprintDateInput = ({
271
+ input,
272
+ intent,
273
+ onFieldSubmit,
274
+ inputProps,
275
+ ...rest
276
+ }) => (
277
+ <DateInput
278
+ {...getDayjsFormatter("L")}
279
+ {...removeUnwantedProps(rest)}
280
+ intent={intent}
281
+ inputProps={inputProps}
282
+ {...input}
283
+ value={input.value ? new Date(input.value) : undefined}
284
+ onChange={function (selectedDate) {
285
+ input.onChange(selectedDate);
286
+ onFieldSubmit(selectedDate);
287
+ }}
288
+ />
289
+ );
290
+
291
+ export const renderBlueprintDateRangeInput = ({
292
+ input,
293
+ intent,
294
+ onFieldSubmit,
295
+ inputProps,
296
+ ...rest
297
+ }) => (
298
+ <DateRangeInput
299
+ {...getDayjsFormatter("L")}
300
+ {...removeUnwantedProps(rest)}
301
+ intent={intent}
302
+ inputProps={inputProps}
303
+ {...input}
304
+ value={
305
+ input.value
306
+ ? [new Date(input.value[0]), new Date(input.value[1])]
307
+ : undefined
308
+ }
309
+ onChange={function (selectedDate) {
310
+ input.onChange(selectedDate);
311
+ onFieldSubmit(selectedDate);
312
+ }}
313
+ />
314
+ );
315
+
316
+ export const RenderBlueprintInput = ({
317
+ input,
318
+ // meta = {},
319
+ intent,
320
+ onFieldSubmit,
321
+ onKeyDown = noop,
322
+ asyncValidating,
323
+ rightElement,
324
+ clickToEdit,
325
+ ...rest
326
+ }) => {
363
327
  const [isOpen, setOpen] = useState(false);
364
328
  const [value, setVal] = useState(null);
365
329
  const toSpread = {};
@@ -433,11 +397,7 @@ export const RenderBlueprintInput = props => {
433
397
  {clickToEdit &&
434
398
  (isOpen ? (
435
399
  <>
436
- <Button
437
- icon="small-cross"
438
- onClick={stopEdit}
439
- intent="danger"
440
- ></Button>
400
+ <Button icon="small-cross" onClick={stopEdit} intent="danger" />
441
401
  <Button
442
402
  icon="small-tick"
443
403
  onClick={() => {
@@ -448,7 +408,7 @@ export const RenderBlueprintInput = props => {
448
408
  stopEdit();
449
409
  }}
450
410
  intent="success"
451
- ></Button>{" "}
411
+ />{" "}
452
412
  </>
453
413
  ) : (
454
414
  <Button
@@ -457,30 +417,33 @@ export const RenderBlueprintInput = props => {
457
417
  setOpen(true);
458
418
  }}
459
419
  icon="edit"
460
- ></Button>
420
+ />
461
421
  ))}
462
422
  </div>
463
423
  );
464
424
  return inner;
465
425
  };
466
426
 
467
- export const renderBlueprintCheckbox = props => {
468
- const { input, label, tooltipInfo, beforeOnChange, onFieldSubmit, ...rest } =
469
- props;
470
- return (
471
- <Checkbox
472
- {...removeUnwantedProps(rest)}
473
- {...input}
474
- checked={input.value}
475
- label={<LabelWithTooltipInfo label={label} tooltipInfo={tooltipInfo} />}
476
- onChange={getCheckboxOrSwitchOnChange({
477
- beforeOnChange,
478
- input,
479
- onFieldSubmit
480
- })}
481
- />
482
- );
483
- };
427
+ export const renderBlueprintCheckbox = ({
428
+ input,
429
+ label,
430
+ tooltipInfo,
431
+ beforeOnChange,
432
+ onFieldSubmit,
433
+ ...rest
434
+ }) => (
435
+ <Checkbox
436
+ {...removeUnwantedProps(rest)}
437
+ {...input}
438
+ checked={input.value}
439
+ label={<LabelWithTooltipInfo label={label} tooltipInfo={tooltipInfo} />}
440
+ onChange={getCheckboxOrSwitchOnChange({
441
+ beforeOnChange,
442
+ input,
443
+ onFieldSubmit
444
+ })}
445
+ />
446
+ );
484
447
 
485
448
  const getCheckboxOrSwitchOnChange = ({
486
449
  beforeOnChange,
@@ -498,154 +461,136 @@ const getCheckboxOrSwitchOnChange = ({
498
461
  onFieldSubmit(v);
499
462
  };
500
463
 
501
- export const renderBlueprintSwitch = props => {
502
- const { input, label, tooltipInfo, onFieldSubmit, beforeOnChange, ...rest } =
503
- props;
504
-
505
- return (
506
- <Switch
507
- {...removeUnwantedProps(rest)}
508
- {...input}
509
- checked={input.value}
510
- label={<LabelWithTooltipInfo label={label} tooltipInfo={tooltipInfo} />}
511
- onChange={getCheckboxOrSwitchOnChange({
512
- beforeOnChange,
513
- input,
514
- onFieldSubmit
515
- })}
516
- />
517
- );
518
- };
519
-
520
- export const renderFileUpload = props => {
521
- const { input, onFieldSubmit, ...rest } = props;
522
- return (
523
- <Uploader
524
- fileList={input.value}
525
- onFieldSubmit={onFieldSubmit}
526
- {...rest}
527
- onChange={input.onChange}
528
- />
529
- );
530
- };
464
+ export const renderBlueprintSwitch = ({
465
+ input,
466
+ label,
467
+ tooltipInfo,
468
+ onFieldSubmit,
469
+ beforeOnChange,
470
+ ...rest
471
+ }) => (
472
+ <Switch
473
+ {...removeUnwantedProps(rest)}
474
+ {...input}
475
+ checked={input.value}
476
+ label={<LabelWithTooltipInfo label={label} tooltipInfo={tooltipInfo} />}
477
+ onChange={getCheckboxOrSwitchOnChange({
478
+ beforeOnChange,
479
+ input,
480
+ onFieldSubmit
481
+ })}
482
+ />
483
+ );
484
+
485
+ export const renderFileUpload = ({ input, onFieldSubmit, ...rest }) => (
486
+ <Uploader
487
+ fileList={input.value}
488
+ onFieldSubmit={onFieldSubmit}
489
+ {...rest}
490
+ name={input.name}
491
+ onChange={input.onChange}
492
+ />
493
+ );
494
+
495
+ export const RenderBlueprintTextarea = ({
496
+ input,
497
+ onFieldSubmit,
498
+ onKeyDown,
499
+ intentClass,
500
+ inputClassName,
501
+ clickToEdit,
502
+ disabled,
503
+ ...rest
504
+ }) => {
505
+ const [value, setValue] = useState(null);
506
+ const [isOpen, setIsOpen] = useState(false);
531
507
 
532
- export class renderBlueprintTextarea extends React.Component {
533
- state = {
534
- value: null,
535
- isOpen: false
536
- };
537
- allowEdit = () => {
538
- this.setState({ isOpen: true });
539
- };
540
- stopEdit = () => {
541
- this.setState({ isOpen: false });
542
- this.setState({ value: null });
543
- };
544
- updateVal = e => {
545
- this.setState({ value: e.target.value });
508
+ const stopEdit = () => {
509
+ setIsOpen(false);
510
+ setValue(null);
546
511
  };
547
- handleValSubmit = () => {
548
- this.props.input.onChange(
549
- this.state.value === null ? this.props.input.value : this.state.value
550
- );
551
- this.props.onFieldSubmit(
552
- this.state.value === null ? this.props.input.value : this.state.value,
553
- { cmdEnter: true }
554
- );
555
- this.stopEdit();
512
+
513
+ const handleValSubmit = () => {
514
+ input.onChange(value === null ? input.value : value);
515
+ onFieldSubmit(value === null ? input.value : value, {
516
+ cmdEnter: true
517
+ });
518
+ stopEdit();
556
519
  };
557
- onKeyDown = (...args) => {
520
+
521
+ const handleOnKeyDown = (...args) => {
558
522
  const e = args[0];
559
- (this.props.onKeyDown || noop)(...args);
523
+ (onKeyDown || noop)(...args);
560
524
  if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
561
- this.props.onFieldSubmit(e.target.value, { cmdEnter: true }, e);
562
- this.props.input.onChange(e);
563
- this.stopEdit();
525
+ onFieldSubmit(e.target.value, { cmdEnter: true }, e);
526
+ input.onChange(e);
527
+ stopEdit();
564
528
  }
565
529
  };
566
- render() {
567
- const {
568
- input,
569
- intentClass,
570
- inputClassName,
571
- onFieldSubmit,
572
- clickToEdit,
573
- onKeyDown,
574
- disabled,
575
- ...rest
576
- } = this.props;
577
- if (clickToEdit) {
578
- const isDisabled = clickToEdit && !this.state.isOpen;
579
530
 
580
- return (
581
- <React.Fragment>
582
- <TextArea
583
- {...removeUnwantedProps(rest)}
584
- disabled={rest.disabled || isDisabled}
585
- className={classNames(
586
- intentClass,
587
- inputClassName,
588
- Classes.INPUT,
589
- Classes.FILL
590
- )}
591
- value={this.state.value === null ? input.value : this.state.value}
592
- onChange={this.updateVal}
593
- onKeyDown={this.onKeyDown}
594
- />
595
- {clickToEdit &&
596
- !disabled &&
597
- (this.state.isOpen ? (
598
- //show okay/cancel buttons
599
- <div>
600
- <Button onClick={this.stopEdit} intent="danger">
601
- Cancel
602
- </Button>
603
- <Button onClick={this.handleValSubmit} intent="success">
604
- Ok
605
- </Button>
606
- </div>
607
- ) : (
608
- //show click to edit button
609
- <Button onClick={this.allowEdit}>Edit</Button>
610
- ))}
611
- </React.Fragment>
612
- );
613
- } else {
614
- return (
531
+ if (clickToEdit) {
532
+ const isDisabled = clickToEdit && !isOpen;
533
+ return (
534
+ <>
615
535
  <TextArea
616
536
  {...removeUnwantedProps(rest)}
617
- disabled={disabled}
537
+ disabled={rest.disabled || isDisabled}
618
538
  className={classNames(
619
539
  intentClass,
620
540
  inputClassName,
621
541
  Classes.INPUT,
622
542
  Classes.FILL
623
543
  )}
624
- {...input}
625
- onBlur={function (e, val) {
626
- if (rest.readOnly) return;
627
- input.onBlur(e, val);
628
- onFieldSubmit(e.target ? e.target.value : val, { blur: true }, e);
629
- }}
630
- onKeyDown={(...args) => {
631
- const e = args[0];
632
- (onKeyDown || noop)(...args);
633
- if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
634
- onFieldSubmit(e.target.value, { cmdEnter: true }, e);
635
- }
636
- }}
544
+ value={value === null ? input.value : value}
545
+ onChange={e => setValue(e.target.value)}
546
+ onKeyDown={handleOnKeyDown}
637
547
  />
638
- );
639
- }
548
+ {clickToEdit &&
549
+ !disabled &&
550
+ (isOpen ? (
551
+ //show okay/cancel buttons
552
+ <div>
553
+ <Button onClick={stopEdit} intent="danger">
554
+ Cancel
555
+ </Button>
556
+ <Button onClick={handleValSubmit} intent="success">
557
+ Ok
558
+ </Button>
559
+ </div>
560
+ ) : (
561
+ //show click to edit button
562
+ <Button onClick={() => setIsOpen(true)}>Edit</Button>
563
+ ))}
564
+ </>
565
+ );
566
+ } else {
567
+ return (
568
+ <TextArea
569
+ {...removeUnwantedProps(rest)}
570
+ disabled={disabled}
571
+ className={classNames(
572
+ intentClass,
573
+ inputClassName,
574
+ Classes.INPUT,
575
+ Classes.FILL
576
+ )}
577
+ {...input}
578
+ onBlur={function (e, val) {
579
+ if (rest.readOnly) return;
580
+ input.onBlur(e, val);
581
+ onFieldSubmit(e.target ? e.target.value : val, { blur: true }, e);
582
+ }}
583
+ onKeyDown={(...args) => {
584
+ const e = args[0];
585
+ (onKeyDown || noop)(...args);
586
+ if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
587
+ onFieldSubmit(e.target.value, { cmdEnter: true }, e);
588
+ }
589
+ }}
590
+ />
591
+ );
640
592
  }
641
- }
642
-
643
- // class ClickToEditWrapper extends React.Component {
644
- // state = { isEditing: false };
645
- // render() {
646
- // return <div />;
647
- // }
648
- // }
593
+ };
649
594
 
650
595
  export const renderBlueprintEditableText = props => {
651
596
  const { input, onFieldSubmit, ...rest } = props;
@@ -767,17 +712,15 @@ export const renderSuggest_old = props => {
767
712
  return renderReactSelect({ ...props, asSuggest: true });
768
713
  };
769
714
 
770
- export const renderSuggest = props => {
771
- const {
772
- async,
773
- input: { value, onChange },
774
- hideValue,
775
- intent,
776
- options,
777
- onFieldSubmit,
778
- ...rest
779
- } = props;
780
-
715
+ export const renderSuggest = ({
716
+ async,
717
+ input: { value, onChange },
718
+ hideValue,
719
+ intent,
720
+ options,
721
+ onFieldSubmit,
722
+ ...rest
723
+ }) => {
781
724
  const propsToUse = {
782
725
  ...removeUnwantedProps(rest),
783
726
  intent,
@@ -793,27 +736,25 @@ export const renderSuggest = props => {
793
736
  }
794
737
  }
795
738
  };
796
- return <TgSuggest {...propsToUse}></TgSuggest>;
739
+ return <TgSuggest {...propsToUse} />;
797
740
  };
798
741
 
799
742
  export const BPSelect = ({ value, onChange, ...rest }) => {
800
743
  return renderSelect({ ...rest, input: { onChange, value } });
801
744
  };
802
745
 
803
- export const renderSelect = props => {
804
- // spreading input not working, grab the values needed instead
805
- const {
806
- input: { value, onChange },
807
- hideValue,
808
- className,
809
- placeholder,
810
- onFieldSubmit,
811
- options,
812
- hidePlaceHolder,
813
- minimal,
814
- disabled,
815
- ...rest
816
- } = props;
746
+ export const renderSelect = ({
747
+ input: { value, onChange },
748
+ hideValue,
749
+ className,
750
+ placeholder,
751
+ onFieldSubmit,
752
+ options,
753
+ hidePlaceHolder,
754
+ minimal,
755
+ disabled,
756
+ ...rest
757
+ }) => {
817
758
  return (
818
759
  <div
819
760
  className={
@@ -892,16 +833,15 @@ export const renderSelect = props => {
892
833
  );
893
834
  };
894
835
 
895
- export const renderBlueprintNumericInput = props => {
896
- const {
897
- input,
898
- hideValue,
899
- intent,
900
- inputClassName,
901
- onFieldSubmit,
902
- onAnyNumberChange,
903
- ...rest
904
- } = props;
836
+ export const renderBlueprintNumericInput = ({
837
+ input,
838
+ hideValue,
839
+ intent,
840
+ inputClassName,
841
+ onFieldSubmit,
842
+ onAnyNumberChange,
843
+ ...rest
844
+ }) => {
905
845
  function handleBlurOrButtonClick(stringVal) {
906
846
  if (rest.readOnly) return;
907
847
  try {
@@ -984,173 +924,57 @@ export const renderBlueprintRadioGroup = ({
984
924
  );
985
925
  };
986
926
 
987
- export class RenderReactColorPicker extends React.Component {
988
- handleChange = color => {
989
- const { input, onFieldSubmit } = this.props;
990
-
991
- input.onChange(color.hex);
992
- onFieldSubmit(color.hex);
993
- };
994
-
995
- render() {
996
- const { input, onFieldSubmit, ...rest } = this.props;
997
- return (
998
- <Popover
999
- position="bottom-right"
1000
- minimal
1001
- modifiers={popoverOverflowModifiers}
1002
- content={
1003
- <SketchPicker
1004
- className="tg-color-picker-selector"
1005
- color={input.value}
1006
- onChangeComplete={this.handleChange}
1007
- {...removeUnwantedProps(rest)}
1008
- />
1009
- }
1010
- >
1011
- <div
1012
- style={{
1013
- padding: "7px",
1014
- margin: "1px",
1015
- background: "#fff",
1016
- borderRadius: "1px",
1017
- boxShadow: "0 0 0 1px rgba(0,0,0,.1)",
1018
- display: "inline-block",
1019
- cursor: "pointer"
1020
- }}
1021
- >
1022
- <div
1023
- className="tg-color-picker-selected-color"
1024
- style={{
1025
- width: "36px",
1026
- height: "14px",
1027
- borderRadius: "2px",
1028
- background: `${input.value}`
1029
- }}
1030
- />
1031
- </div>
1032
- </Popover>
1033
- );
1034
- }
1035
- }
1036
-
1037
- // tgreen: This doesn't work because the async validate function will not be automatically rerun onSubmit
1038
- // class AddAsyncValidate extends Component {
1039
- // constructor(props) {
1040
- // super(props);
1041
- // this.state = {
1042
- // asyncValidating: false
1043
- // };
1044
- // this.runAsyncValidationDebounced = debounce(this.runAsyncValidation, 500);
1045
- // }
1046
-
1047
- // componentDidUpdate(oldProps) {
1048
- // const {
1049
- // validateOnChange,
1050
- // input: { name, value },
1051
- // meta: { touched, form, dispatch }
1052
- // } = this.props;
1053
- // const newValue = value;
1054
- // const oldValue = oldProps.input.value;
1055
- // const valueHasChanged = newValue !== oldValue;
1056
- // if (validateOnChange && valueHasChanged) {
1057
- // this.runAsyncValidationDebounced(newValue);
1058
- // }
1059
- // // mark the input as touched after changing value
1060
- // if (valueHasChanged && !touched) {
1061
- // dispatch(touch(form, name));
1062
- // }
1063
- // }
1064
-
1065
- // triggerAsyncValidation(error) {
1066
- // const {
1067
- // input: { name },
1068
- // meta: { dispatch, form },
1069
- // formAsyncErrors
1070
- // } = this.props;
1071
- // // this needs to get a fresh prop for formAsyncErrors otherwise it will get out of sync.
1072
- // // the test will catch this.
1073
- // dispatch(
1074
- // stopAsyncValidation(form, {
1075
- // ...formAsyncErrors,
1076
- // [name]: error
1077
- // })
1078
- // );
1079
- // }
1080
-
1081
- // runAsyncValidation = async val => {
1082
- // const {
1083
- // input: { name },
1084
- // meta: { dispatch, form },
1085
- // asyncValidate
1086
- // } = this.props;
1087
-
1088
- // this.setState({
1089
- // asyncValidating: true
1090
- // });
1091
- // // mark this field as invalid so that the user can not submit this form while async validating
1092
- // this.triggerAsyncValidation("asyncValidating");
1093
- // dispatch(startAsyncValidation(form));
1094
- // const error = await asyncValidate(val);
1095
- // this.triggerAsyncValidation(error);
1096
- // // if there is no error then clear it from redux
1097
- // if (!error) {
1098
- // dispatch(clearAsyncError(form, name));
1099
- // }
1100
-
1101
- // this.setState({
1102
- // asyncValidating: false
1103
- // });
1104
-
1105
- // return error;
1106
- // };
1107
-
1108
- // onBlur = (...args) => {
1109
- // const { input } = this.props;
1110
- // // always run this on input blur so that the user cannot submit a form with a field that has not finished validating
1111
- // this.runAsyncValidation(input.value);
1112
- // input.onBlur(...args);
1113
- // };
1114
-
1115
- // render() {
1116
- // const { asyncValidating } = this.state;
1117
- // const {
1118
- // passedComponent: Component,
1119
- // input,
1120
- // formAsyncErrors, // don't pass through
1121
- // dispatch, // don't pass through
1122
- // ...rest
1123
- // } = this.props;
1124
-
1125
- // return (
1126
- // <Component
1127
- // {...rest}
1128
- // input={{
1129
- // ...input,
1130
- // onBlur: this.onBlur
1131
- // }}
1132
- // asyncValidating={asyncValidating}
1133
- // />
1134
- // );
1135
- // }
1136
- // }
1137
-
1138
- // const WrappedAddAsyncValidate = connect((state, { meta }) => {
1139
- // return {
1140
- // formAsyncErrors: getFormAsyncErrors(meta.form)(state)
1141
- // };
1142
- // })(AddAsyncValidate);
927
+ export const RenderReactColorPicker = ({ input, onFieldSubmit, ...rest }) => (
928
+ <Popover
929
+ position="bottom-right"
930
+ minimal
931
+ modifiers={popoverOverflowModifiers}
932
+ content={
933
+ <SketchPicker
934
+ className="tg-color-picker-selector"
935
+ color={input.value}
936
+ onChangeComplete={color => {
937
+ input.onChange(color.hex);
938
+ onFieldSubmit(color.hex);
939
+ }}
940
+ {...removeUnwantedProps(rest)}
941
+ />
942
+ }
943
+ >
944
+ <div
945
+ style={{
946
+ padding: "7px",
947
+ margin: "1px",
948
+ background: "#fff",
949
+ borderRadius: "1px",
950
+ boxShadow: "0 0 0 1px rgba(0,0,0,.1)",
951
+ display: "inline-block",
952
+ cursor: "pointer"
953
+ }}
954
+ >
955
+ <div
956
+ className="tg-color-picker-selected-color"
957
+ style={{
958
+ width: "36px",
959
+ height: "14px",
960
+ borderRadius: "2px",
961
+ background: `${input.value}`
962
+ }}
963
+ />
964
+ </div>
965
+ </Popover>
966
+ );
1143
967
 
1144
968
  export function generateField(component, opts) {
1145
969
  const compWithDefaultVal = withAbstractWrapper(component, opts);
1146
- return function FieldMaker({
970
+ return ({
1147
971
  name,
1148
972
  isRequired,
1149
973
  onFieldSubmit = noop,
1150
- noRedux,
974
+ noRedux = false,
1151
975
  // asyncValidate,
1152
976
  ...rest
1153
- }) {
977
+ }) => {
1154
978
  const component = compWithDefaultVal;
1155
979
 
1156
980
  const props = {
@@ -1167,6 +991,7 @@ export function generateField(component, opts) {
1167
991
  component,
1168
992
  ...(isRequired && { validate: fieldRequired }),
1169
993
  isRequired,
994
+ noRedux,
1170
995
  ...rest
1171
996
  };
1172
997
 
@@ -1194,9 +1019,15 @@ export const withAbstractWrapper = (ComponentToWrap, opts = {}) => {
1194
1019
  ...rest
1195
1020
  } = props;
1196
1021
 
1022
+ const {
1023
+ showErrorIfUntouched: _showErrorIfUntouched,
1024
+ meta: { touched, error, warning }
1025
+ } = props;
1026
+ const showErrorIfUntouched =
1027
+ opts.showErrorIfUntouched || _showErrorIfUntouched;
1197
1028
  //get is assign defaults mode
1198
1029
  //if assign default value mode then add on to the component
1199
- const [defaultValCount, setDefaultValCount] = React.useState(0);
1030
+ const [defaultValCount, setDefaultValCount] = useState(0);
1200
1031
  const [defaultValueFromBackend, setDefault] = useState();
1201
1032
  const [allowUserOverride, setUserOverride] = useState(true);
1202
1033
  const [isLoadingDefaultValue, setLoadingDefaultValue] = useState(false);
@@ -1305,8 +1136,14 @@ export const withAbstractWrapper = (ComponentToWrap, opts = {}) => {
1305
1136
  defaultValue: defaultValueFromBackend || defaultValueFromProps,
1306
1137
  disabled: props.disabled || allowUserOverride === false,
1307
1138
  readOnly: props.readOnly || isLoadingDefaultValue,
1308
- intent: getIntent(props),
1309
- intentClass: getIntentClass(props)
1139
+ intent: getIntent({
1140
+ showErrorIfUntouched,
1141
+ meta: { touched, error, warning }
1142
+ }),
1143
+ intentClass: getIntentClass({
1144
+ showErrorIfUntouched,
1145
+ meta: { touched, error, warning }
1146
+ })
1310
1147
  };
1311
1148
 
1312
1149
  // don't show intent while async validating
@@ -1330,20 +1167,21 @@ export const withAbstractWrapper = (ComponentToWrap, opts = {}) => {
1330
1167
 
1331
1168
  return (
1332
1169
  <AbstractInput
1333
- {...{
1334
- ...opts,
1335
- defaultValCount,
1336
- isRequired,
1337
- ...defaultProps,
1338
- isLoadingDefaultValue,
1339
- showGenerateDefaultDot:
1340
- !inAssignDefaultsMode &&
1341
- window.__showGenerateDefaultDot &&
1342
- window.__showGenerateDefaultDot() &&
1343
- !!generateDefaultValue,
1344
- setAssignDefaultsMode,
1345
- startAssigningDefault,
1346
- assignDefaultButton: inAssignDefaultsMode && generateDefaultValue && (
1170
+ {...opts}
1171
+ defaultValCount={defaultValCount}
1172
+ isRequired={isRequired}
1173
+ {...defaultProps}
1174
+ isLoadingDefaultValue={isLoadingDefaultValue}
1175
+ showGenerateDefaultDot={
1176
+ !inAssignDefaultsMode &&
1177
+ window.__showGenerateDefaultDot?.() &&
1178
+ !!generateDefaultValue
1179
+ }
1180
+ setAssignDefaultsMode={setAssignDefaultsMode}
1181
+ startAssigningDefault={startAssigningDefault}
1182
+ assignDefaultButton={
1183
+ inAssignDefaultsMode &&
1184
+ generateDefaultValue && (
1347
1185
  <Button
1348
1186
  onClick={startAssigningDefault}
1349
1187
  small
@@ -1352,7 +1190,7 @@ export const withAbstractWrapper = (ComponentToWrap, opts = {}) => {
1352
1190
  Assign Default
1353
1191
  </Button>
1354
1192
  )
1355
- }}
1193
+ }
1356
1194
  >
1357
1195
  <ComponentToWrap {...defaultProps} />
1358
1196
  </AbstractInput>
@@ -1372,7 +1210,7 @@ export const SwitchField = generateField(renderBlueprintSwitch, {
1372
1210
  noOuterLabel: true,
1373
1211
  noFillField: true
1374
1212
  });
1375
- export const TextareaField = generateField(renderBlueprintTextarea);
1213
+ export const TextareaField = generateField(RenderBlueprintTextarea);
1376
1214
  export const SuggestField = generateField(renderSuggest);
1377
1215
  export const EditableTextField = generateField(renderBlueprintEditableText);
1378
1216
  export const NumericInputField = generateField(renderBlueprintNumericInput);