@teselagen/ui 0.0.9 → 0.0.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.
Files changed (126) hide show
  1. package/README.md +7 -0
  2. package/cypress.config.ts +6 -0
  3. package/index.html +12 -0
  4. package/package.json +2 -2
  5. package/project.json +74 -0
  6. package/src/AdvancedOptions.js +33 -0
  7. package/src/AdvancedOptions.spec.js +24 -0
  8. package/src/AssignDefaultsModeContext.js +21 -0
  9. package/src/AsyncValidateFieldSpinner/index.js +12 -0
  10. package/src/BlueprintError/index.js +14 -0
  11. package/src/BounceLoader/index.js +16 -0
  12. package/src/BounceLoader/style.css +45 -0
  13. package/src/CollapsibleCard/index.js +92 -0
  14. package/src/CollapsibleCard/style.css +21 -0
  15. package/src/DNALoader/index.js +20 -0
  16. package/src/DNALoader/style.css +251 -0
  17. package/src/DataTable/CellDragHandle.js +130 -0
  18. package/src/DataTable/DisabledLoadingComponent.js +15 -0
  19. package/src/DataTable/DisplayOptions.js +218 -0
  20. package/src/DataTable/FilterAndSortMenu.js +397 -0
  21. package/src/DataTable/PagingTool.js +232 -0
  22. package/src/DataTable/SearchBar.js +57 -0
  23. package/src/DataTable/SortableColumns.js +53 -0
  24. package/src/DataTable/TableFormTrackerContext.js +10 -0
  25. package/src/DataTable/dataTableEnhancer.js +291 -0
  26. package/src/DataTable/defaultFormatters.js +32 -0
  27. package/src/DataTable/defaultProps.js +45 -0
  28. package/src/DataTable/defaultValidators.js +40 -0
  29. package/src/DataTable/editCellHelper.js +44 -0
  30. package/src/DataTable/getCellVal.js +20 -0
  31. package/src/DataTable/getVals.js +8 -0
  32. package/src/DataTable/index.js +3537 -0
  33. package/src/DataTable/isTruthy.js +12 -0
  34. package/src/DataTable/isValueEmpty.js +3 -0
  35. package/src/DataTable/style.css +600 -0
  36. package/src/DataTable/utils/computePresets.js +42 -0
  37. package/src/DataTable/utils/convertSchema.js +69 -0
  38. package/src/DataTable/utils/getIdOrCodeOrIndex.js +9 -0
  39. package/src/DataTable/utils/getTableConfigFromStorage.js +5 -0
  40. package/src/DataTable/utils/queryParams.js +1032 -0
  41. package/src/DataTable/utils/rowClick.js +156 -0
  42. package/src/DataTable/utils/selection.js +8 -0
  43. package/src/DataTable/utils/withSelectedEntities.js +65 -0
  44. package/src/DataTable/utils/withTableParams.js +328 -0
  45. package/src/DataTable/validateTableWideErrors.js +135 -0
  46. package/src/DataTable/viewColumn.js +37 -0
  47. package/src/DialogFooter/index.js +79 -0
  48. package/src/DialogFooter/style.css +9 -0
  49. package/src/DropdownButton.js +36 -0
  50. package/src/FillWindow.css +6 -0
  51. package/src/FillWindow.js +69 -0
  52. package/src/FormComponents/Uploader.js +1197 -0
  53. package/src/FormComponents/getNewName.js +31 -0
  54. package/src/FormComponents/index.js +1384 -0
  55. package/src/FormComponents/itemUpload.js +84 -0
  56. package/src/FormComponents/sortify.js +73 -0
  57. package/src/FormComponents/style.css +247 -0
  58. package/src/FormComponents/tryToMatchSchemas.js +222 -0
  59. package/src/FormComponents/utils.js +6 -0
  60. package/src/HotkeysDialog/index.js +79 -0
  61. package/src/HotkeysDialog/style.css +54 -0
  62. package/src/InfoHelper/index.js +83 -0
  63. package/src/InfoHelper/style.css +7 -0
  64. package/src/IntentText/index.js +18 -0
  65. package/src/Loading/index.js +74 -0
  66. package/src/Loading/style.css +4 -0
  67. package/src/MatchHeaders.js +223 -0
  68. package/src/MenuBar/index.js +416 -0
  69. package/src/MenuBar/style.css +45 -0
  70. package/src/PromptUnsavedChanges/index.js +40 -0
  71. package/src/ResizableDraggableDialog/index.js +138 -0
  72. package/src/ResizableDraggableDialog/style.css +42 -0
  73. package/src/ScrollToTop/index.js +72 -0
  74. package/src/SimpleStepViz.js +26 -0
  75. package/src/TgSelect/index.js +465 -0
  76. package/src/TgSelect/style.css +34 -0
  77. package/src/TgSuggest/index.js +121 -0
  78. package/src/Timeline/TimelineEvent.js +31 -0
  79. package/src/Timeline/index.js +22 -0
  80. package/src/Timeline/style.css +29 -0
  81. package/src/UploadCsvWizard.css +4 -0
  82. package/src/UploadCsvWizard.js +731 -0
  83. package/src/autoTooltip.js +89 -0
  84. package/src/constants.js +1 -0
  85. package/src/customIcons.js +361 -0
  86. package/src/enhancers/withDialog/index.js +196 -0
  87. package/src/enhancers/withDialog/tg_modalState.js +46 -0
  88. package/src/enhancers/withField.js +20 -0
  89. package/src/enhancers/withFields.js +11 -0
  90. package/src/enhancers/withLocalStorage.js +11 -0
  91. package/src/index.js +76 -0
  92. package/src/rerenderOnWindowResize.js +27 -0
  93. package/src/showAppSpinner.js +12 -0
  94. package/src/showConfirmationDialog/index.js +116 -0
  95. package/src/showDialogOnDocBody.js +37 -0
  96. package/src/style.css +214 -0
  97. package/src/toastr.js +92 -0
  98. package/src/typeToCommonType.js +6 -0
  99. package/src/useDialog.js +64 -0
  100. package/src/utils/S3Download.js +14 -0
  101. package/src/utils/adHoc.js +10 -0
  102. package/src/utils/basicHandleActionsWithFullState.js +14 -0
  103. package/src/utils/combineReducersWithFullState.js +14 -0
  104. package/src/utils/commandControls.js +83 -0
  105. package/src/utils/commandUtils.js +112 -0
  106. package/src/utils/determineBlackOrWhiteTextColor.js +4 -0
  107. package/src/utils/getDayjsFormatter.js +35 -0
  108. package/src/utils/getTextFromEl.js +28 -0
  109. package/src/utils/handlerHelpers.js +30 -0
  110. package/src/utils/hotkeyUtils.js +129 -0
  111. package/src/utils/menuUtils.js +402 -0
  112. package/src/utils/popoverOverflowModifiers.js +11 -0
  113. package/src/utils/pureNoFunc.js +31 -0
  114. package/src/utils/renderOnDoc.js +29 -0
  115. package/src/utils/showProgressToast.js +22 -0
  116. package/src/utils/tagUtils.js +45 -0
  117. package/src/utils/tgFormValues.js +32 -0
  118. package/src/utils/withSelectTableRecords.js +38 -0
  119. package/src/utils/withStore.js +10 -0
  120. package/src/wrapDialog.js +112 -0
  121. package/tsconfig.json +4 -0
  122. package/vite.config.ts +7 -0
  123. package/index.js +0 -80652
  124. package/index.mjs +0 -80636
  125. package/index.umd.js +0 -80649
  126. package/style.css +0 -10421
@@ -0,0 +1,72 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Button } from "@blueprintjs/core";
3
+ import { Transition } from "react-transition-group";
4
+
5
+ const duration = 300;
6
+
7
+ const defaultStyle = {
8
+ transition: `opacity ${duration}ms ease-in-out`,
9
+ opacity: 0
10
+ };
11
+
12
+ const transitionStyles = {
13
+ entering: { opacity: 1 },
14
+ entered: { opacity: 1 },
15
+ exiting: { opacity: 0 },
16
+ exited: { opacity: 0 }
17
+ };
18
+
19
+ function ScrollToTop({
20
+ showAt = 150,
21
+ scrollContainer = document.scrollingElement
22
+ }) {
23
+ const [shouldShow, setShouldShow] = useState(
24
+ scrollContainer.scrollTop >= showAt
25
+ );
26
+
27
+ useEffect(() => {
28
+ const scrollListener = () => {
29
+ const newShouldShow = scrollContainer.scrollTop >= showAt;
30
+ if (newShouldShow !== shouldShow) setShouldShow(newShouldShow);
31
+ };
32
+ const listenerContainer =
33
+ scrollContainer === document.scrollingElement ? window : scrollContainer;
34
+ listenerContainer.addEventListener("scroll", scrollListener);
35
+ // Specify how to clean up after this effect:
36
+ return function cleanup() {
37
+ listenerContainer.removeEventListener("scroll", scrollListener);
38
+ };
39
+ }, [shouldShow, showAt, scrollContainer]);
40
+
41
+ const scrollToTop = () => {
42
+ const c = scrollContainer.scrollTop;
43
+ if (c > 0) {
44
+ window.requestAnimationFrame(scrollToTop);
45
+ scrollContainer.scrollTo(0, c - c / 8);
46
+ }
47
+ };
48
+
49
+ return (
50
+ <Transition in={shouldShow} timeout={duration}>
51
+ {state =>
52
+ state === "exited" ? null : (
53
+ <div style={{ position: "fixed", bottom: 25, right: 25, zIndex: 10 }}>
54
+ <Button
55
+ style={{
56
+ borderRadius: "50%",
57
+ ...defaultStyle,
58
+ ...transitionStyles[state]
59
+ }}
60
+ intent="primary"
61
+ icon="arrow-up"
62
+ large
63
+ onClick={scrollToTop}
64
+ />
65
+ </div>
66
+ )
67
+ }
68
+ </Transition>
69
+ );
70
+ }
71
+
72
+ export default ScrollToTop;
@@ -0,0 +1,26 @@
1
+ import { Icon } from "@blueprintjs/core";
2
+ import classNames from "classnames";
3
+ import React from "react";
4
+
5
+ export default function SimpleStepViz({ steps, ...rest }) {
6
+ return (
7
+ <div style={{ display: "flex", justifyContent: "center" }}>
8
+ <ul className="bp3-breadcrumbs" {...rest}>
9
+ {steps.map(({ completed, active, text }, i) => {
10
+ return (
11
+ <li key={i}>
12
+ <div
13
+ className={classNames("bp3-breadcrumb", {
14
+ "bp3-breadcrumb-current": active
15
+ })}
16
+ >
17
+ <Icon icon={completed ? "tick-circle" : undefined}></Icon>
18
+ {text}
19
+ </div>
20
+ </li>
21
+ );
22
+ })}
23
+ </ul>
24
+ </div>
25
+ );
26
+ }
@@ -0,0 +1,465 @@
1
+ /* eslint-disable @typescript-eslint/no-empty-function */
2
+ import { MultiSelect, getCreateNewItem } from "@blueprintjs/select";
3
+ import { Keys, Button, MenuItem, Tag } from "@blueprintjs/core";
4
+ import React from "react";
5
+ import { filter, isEqual } from "lodash";
6
+ import classNames from "classnames";
7
+ import "./style.css";
8
+ import { withProps } from "recompose";
9
+ import fuzzysearch from "fuzzysearch";
10
+ import getTextFromEl from "../utils/getTextFromEl";
11
+ import { getTagColorStyle, getTagProps } from "../utils/tagUtils";
12
+ import popoverOverflowModifiers from "../utils/popoverOverflowModifiers";
13
+
14
+ class TgSelect extends React.Component {
15
+ constructor(props) {
16
+ super(props);
17
+ const { autoOpen = false } = this.props;
18
+
19
+ this.state = {
20
+ isOpen: autoOpen,
21
+ activeItem: null,
22
+ query: ""
23
+ };
24
+ }
25
+
26
+ static defaultProps = {
27
+ onChange: () => {},
28
+ options: [],
29
+ unfilteredOptions: [],
30
+ value: undefined
31
+ };
32
+
33
+ itemRenderer = (i, { index, handleClick, modifiers }) => {
34
+ const optionRenderer = this.getOptionRenderer();
35
+ const onClick = i.onClick || handleClick;
36
+ return (
37
+ <div //we specifically don't use a BP MenuItem component here because the menu item is too slow when 100s are loaded and will cause the component to lag
38
+ onClick={modifiers.disabled ? undefined : onClick}
39
+ key={index}
40
+ className={classNames(
41
+ "tg-select-option bp3-menu-item bp3-fill bp3-text-overflow-ellipsis",
42
+ {
43
+ "bp3-active": modifiers.active,
44
+ "bp3-disabled": modifiers.disabled
45
+ }
46
+ )}
47
+ >
48
+ {optionRenderer ? optionRenderer(i, this.props) : i.label}
49
+ </div>
50
+ );
51
+ };
52
+ tagRenderer = i => {
53
+ if (!i || (!this.props.multi && this.state.query)) {
54
+ return null;
55
+ }
56
+ // return i
57
+ return i.label;
58
+ };
59
+
60
+ handleItemSelect = (item, e) => {
61
+ e.stopPropagation();
62
+ const { onChange, value, multi, closeOnSelect, isTagSelect } = this.props;
63
+ this.setState({ activeItem: null });
64
+ if (multi) {
65
+ let valArray = getValueArray(value);
66
+
67
+ if (closeOnSelect || item.closeOnSelect) {
68
+ this.setState({ isOpen: false });
69
+ this.input && this.input.blur();
70
+ }
71
+ if (
72
+ isTagSelect &&
73
+ item.value &&
74
+ item.value.includes &&
75
+ item.value.includes(":")
76
+ ) {
77
+ const topLevelId = item.value.split(":")[0];
78
+ valArray = valArray.filter(val => {
79
+ if (val.value && val.value.includes && val.value.includes(":")) {
80
+ const valId = val.value.split(":")[0];
81
+ if (valId === topLevelId) {
82
+ return false;
83
+ }
84
+ }
85
+ return true;
86
+ });
87
+ }
88
+ return onChange([...valArray, item]);
89
+ } else {
90
+ this.setState({ isOpen: false });
91
+ this.input && this.input.blur();
92
+ return onChange(item);
93
+ }
94
+ };
95
+
96
+ handleTagRemove = (e, tagProps) => {
97
+ const { onChange, value } = this.props;
98
+ const filteredVals = filter(
99
+ value,
100
+ (obj, i) => !isEqual(i, tagProps["data-tag-index"])
101
+ );
102
+ e.stopPropagation();
103
+ onChange(filteredVals);
104
+ this.setState({ isOpen: false });
105
+ this.input.focus();
106
+ };
107
+ handleTagInputRemove = (val, index) => {
108
+ const { onChange, value } = this.props;
109
+ const filteredVals = filter(value, (obj, i) => !isEqual(i, index));
110
+ // e.stopPropagation();
111
+ return onChange(filteredVals);
112
+ };
113
+
114
+ handleClear = e => {
115
+ const { multi, value } = this.props;
116
+
117
+ e.stopPropagation();
118
+ e.preventDefault();
119
+ let newValue = null;
120
+ if (multi) {
121
+ newValue = filter(value, obj => obj.disabled) || [];
122
+ } else if (value && value.disabled) {
123
+ newValue = value;
124
+ }
125
+ const { onChange } = this.props;
126
+ this.setState({ query: "" });
127
+ onChange(newValue);
128
+ this.setState({ isOpen: false });
129
+ this.input.focus();
130
+ };
131
+
132
+ itemListPredicate = (queryString, item) => {
133
+ // this will hide an option if it returns false
134
+ // each item is an individual option item
135
+ const { isSimpleSearch } = this.props;
136
+
137
+ return itemListPredicate(queryString, item, isSimpleSearch);
138
+ };
139
+
140
+ onQueryChange = query => {
141
+ const { onInputChange = () => {} } = this.props;
142
+ this.setState({
143
+ query
144
+ });
145
+ onInputChange(query);
146
+ };
147
+ handleActiveItemChange = (item, isCreateNewItem) => {
148
+ this.setState({
149
+ activeItem:
150
+ item ||
151
+ //if there's no item and we're in creatable mode, auto-select the create-new option
152
+ (isCreateNewItem || this.props.creatable ? getCreateNewItem() : null)
153
+ });
154
+ };
155
+ onInteraction = () => {
156
+ if (this.input != null && this.input !== document.activeElement) {
157
+ // the input is no longer focused so we can close the popover
158
+ this.setState({ isOpen: false, query: "" });
159
+ } else if (!this.props.openOnKeyDown) {
160
+ // open the popover when focusing the tag input
161
+ this.setState({ isOpen: true });
162
+ }
163
+ };
164
+
165
+ queryHasExactOptionMatch = () => {
166
+ //we don't want to show the creatable if the thing being created already exactly matches the label
167
+ return (
168
+ [
169
+ ...(this.props.options || []),
170
+ ...(Array.isArray(this.props.value)
171
+ ? this.props.value
172
+ : [this.props.value])
173
+ ].filter(o => {
174
+ const { label, value } = o || {};
175
+ const lowerQuery = (this.state.query || "").toLowerCase();
176
+ const lowerLabelOrVal =
177
+ label && label.toLowerCase
178
+ ? label.toLowerCase()
179
+ : value && value.toLowerCase && value.toLowerCase();
180
+ const textFromEl = getTextFromEl(label);
181
+
182
+ return lowerQuery === lowerLabelOrVal || lowerQuery === textFromEl;
183
+ }).length > 0
184
+ );
185
+ };
186
+
187
+ getTagProps = label => {
188
+ const { multi, value = [], disabled: _disabled } = this.props;
189
+ const val = Array.isArray(value) ? value : [value];
190
+ const matchingVal = val.find(op => op.label === label);
191
+ const disabled = _disabled || (matchingVal && matchingVal.disabled);
192
+ const className = matchingVal && matchingVal.className;
193
+
194
+ return {
195
+ ...getTagColorStyle(multi && matchingVal && matchingVal.color),
196
+ intent: disabled ? "" : "primary",
197
+ minimal: true,
198
+ className: classNames(className, "tg-select-value", {
199
+ disabled
200
+ }),
201
+ onRemove: multi && !disabled ? this.handleTagRemove : null
202
+ };
203
+ };
204
+
205
+ getOptionRenderer = () => {
206
+ const { isTagSelect, optionRenderer, multi } = this.props;
207
+
208
+ if (isTagSelect && multi) {
209
+ return tagOptionRender;
210
+ }
211
+ return optionRenderer;
212
+ };
213
+
214
+ render() {
215
+ const {
216
+ multi,
217
+ options,
218
+ unfilteredOptions,
219
+ value,
220
+ creatable,
221
+ optionRenderer, //pull this one out here so it doesn't get passsed along
222
+ tagInputProps,
223
+ autoFocus,
224
+ autoOpen,
225
+ noResultsText,
226
+ noResults: _noResults,
227
+ inputProps,
228
+ placeholder,
229
+ isLoading,
230
+ disallowClear,
231
+ onBlur,
232
+ disabled,
233
+ popoverProps,
234
+ additionalRightEl,
235
+ resetOnSelect = true,
236
+ renderCreateNewOption: _renderCreateNewOption = renderCreateNewOption,
237
+ ...rest
238
+ } = this.props;
239
+ let noResults = _noResults;
240
+
241
+ // Null is also a valid value for a React Component, noResultsDefault should only be appplied when noResults is undefined
242
+ if (noResults === undefined) noResults = noResultsDefault;
243
+ const hasValue = Array.isArray(value)
244
+ ? value.length > 0
245
+ : !!value || value === 0;
246
+
247
+ const rightElement = isLoading ? (
248
+ <Button loading minimal />
249
+ ) : (
250
+ <span>
251
+ {additionalRightEl}
252
+ {hasValue && !disallowClear && !disabled && (
253
+ <Button
254
+ className="tg-select-clear-all"
255
+ icon="cross"
256
+ minimal
257
+ onClick={this.handleClear}
258
+ />
259
+ )}
260
+ {noResults !== null && (
261
+ <Button
262
+ onClick={e => {
263
+ if (this.state.isOpen) {
264
+ e.stopPropagation();
265
+
266
+ this.setState({ isOpen: false });
267
+ }
268
+ }}
269
+ disabled={disabled}
270
+ className="tg-select-toggle"
271
+ minimal
272
+ icon={this.state.isOpen ? "caret-up" : "caret-down"}
273
+ />
274
+ )}
275
+ </span>
276
+ );
277
+
278
+ const maybeCreateNewItemFromQuery = creatable ? createNewOption : undefined;
279
+ const maybeCreateNewItemRenderer =
280
+ creatable && !this.queryHasExactOptionMatch()
281
+ ? _renderCreateNewOption
282
+ : null;
283
+ const selectedItems = getValueArray(value).map(value => {
284
+ if (value && value.label) return value; //if the value has a label, just use that
285
+ //if not, look for an existing option to use that value
286
+ // unfilteredOptions will have every option included selected ones
287
+ return unfilteredOptions.find(
288
+ opt => opt && opt.value === ((value && value.value) || value)
289
+ );
290
+ });
291
+ return (
292
+ <MultiSelect
293
+ onActiveItemChange={this.handleActiveItemChange}
294
+ closeOnSelect={!multi}
295
+ resetOnSelect={resetOnSelect}
296
+ items={options || []}
297
+ activeItem={
298
+ this.state.activeItem ||
299
+ (options && options.filter(opt => !selectedItems.includes(opt))[0]) ||
300
+ null //it's important we pass null here instead of undefined if no active item is found
301
+ }
302
+ itemDisabled={itemDisabled}
303
+ query={this.state.query}
304
+ popoverProps={{
305
+ captureDismiss: true,
306
+ minimal: true,
307
+ className: classNames("tg-select", "tg-stop-dialog-form-enter", {
308
+ "tg-single-select": !multi
309
+ }),
310
+ wrapperTagName: "div",
311
+ canEscapeKeyClose: true,
312
+ onInteraction: this.onInteraction,
313
+ isOpen: this.state.isOpen,
314
+ modifiers: popoverOverflowModifiers,
315
+ ...popoverProps
316
+ }}
317
+ onItemSelect={this.handleItemSelect}
318
+ createNewItemFromQuery={maybeCreateNewItemFromQuery}
319
+ createNewItemRenderer={maybeCreateNewItemRenderer}
320
+ noResults={noResultsText || noResults}
321
+ onQueryChange={this.onQueryChange}
322
+ itemRenderer={this.itemRenderer}
323
+ itemListPredicate={this.itemListPredicate}
324
+ {...{
325
+ selectedItems,
326
+ tagRenderer: this.tagRenderer,
327
+ tagInputProps: {
328
+ inputRef: n => {
329
+ if (n) this.input = n;
330
+ },
331
+ placeholder:
332
+ placeholder || (creatable ? "Select/Create..." : "Select..."),
333
+ tagProps: this.getTagProps,
334
+ onRemove: multi ? this.handleTagInputRemove : null,
335
+ rightElement: rightElement,
336
+ disabled: disabled, // tg: adding isLoading will cause the input to be blurred when using generic select asReactSelect (don't do it),
337
+ ...tagInputProps, //spread additional tag input props here
338
+ intent: this.props.intent,
339
+ onKeyDown: e => {
340
+ const { which } = e;
341
+ e.persist();
342
+ if (which === Keys.ENTER) {
343
+ e.preventDefault();
344
+ // e.stopPropagation();
345
+ }
346
+ if (which === Keys.ESCAPE || which === Keys.TAB) {
347
+ // By default the escape key will not trigger a blur on the
348
+ // input element. It must be done explicitly.
349
+ if (this.input != null) {
350
+ this.input.blur();
351
+ }
352
+ this.setState({ isOpen: false });
353
+ e.preventDefault();
354
+ e.stopPropagation(); //this prevents dialog's it is in from closing
355
+ } else if (
356
+ !(
357
+ which === Keys.BACKSPACE ||
358
+ which === Keys.ARROW_LEFT ||
359
+ which === Keys.ARROW_RIGHT
360
+ )
361
+ ) {
362
+ this.setState({ isOpen: true });
363
+ }
364
+ },
365
+ inputProps: {
366
+ autoFocus: autoFocus || autoOpen,
367
+ onBlur,
368
+ ...(tagInputProps && tagInputProps.inputProps)
369
+ }
370
+ }
371
+ }}
372
+ {...rest}
373
+ />
374
+ );
375
+ }
376
+ }
377
+ export default withProps(props => {
378
+ const { multi, value, options } = props;
379
+ let optionsToRet = options;
380
+ // based on incoming value hide those selected options from the option list
381
+ if (multi && value) {
382
+ const valArray = getValueArray(value);
383
+ optionsToRet = options.filter(op => {
384
+ const isOptionSelected = valArray.some(val => {
385
+ if (!val) return false;
386
+ const matching = isEqual(val.value, op.value);
387
+ return matching;
388
+ });
389
+ return !isOptionSelected;
390
+ });
391
+ }
392
+ return {
393
+ // unfilteredOptions is needed for finding selected items
394
+ unfilteredOptions: options,
395
+ options: optionsToRet
396
+ };
397
+ })(TgSelect);
398
+
399
+ const itemDisabled = i => i.disabled;
400
+ const noResultsDefault = <div>No Results...</div>;
401
+
402
+ export const renderCreateNewOption = (query, active, handleClick) => (
403
+ <MenuItem
404
+ icon="add"
405
+ text={`Create "${query}"`}
406
+ active={active}
407
+ onClick={handleClick}
408
+ shouldDismissPopover={false}
409
+ />
410
+ );
411
+
412
+ export function createNewOption(newValString) {
413
+ return {
414
+ userCreated: true,
415
+ label: newValString,
416
+ value: newValString
417
+ };
418
+ }
419
+
420
+ function getValueArray(value) {
421
+ return value || value === 0 ? (Array.isArray(value) ? value : [value]) : [];
422
+ }
423
+
424
+ //we export this here for use in createGenericSelect
425
+ export const itemListPredicate = (_queryString = "", items, isSimpleSearch) => {
426
+ const queryString = _queryString.toLowerCase();
427
+ const toSearchArr = (items || []).map(item => {
428
+ return {
429
+ item,
430
+ text: item.toLowerCase
431
+ ? item.toLowerCase()
432
+ : item.label
433
+ ? item.label.toLowerCase
434
+ ? item.label.toLowerCase()
435
+ : getTextFromEl(item.label).toLowerCase()
436
+ : (item.value && item.value.toLowerCase && item.value.toLowerCase()) ||
437
+ ""
438
+ };
439
+ });
440
+ let toRet = toSearchArr.filter(({ text }) =>
441
+ (isSimpleSearch ? simplesearch : fuzzysearch)(queryString, text)
442
+ );
443
+ toRet = toRet.sort(({ text }, { text: text2 }) => {
444
+ return getSort(text, queryString) - getSort(text2, queryString);
445
+ });
446
+
447
+ toRet = toRet.map(({ item }) => item);
448
+ return toRet;
449
+ };
450
+
451
+ export function simplesearch(needle, haystack) {
452
+ return (haystack || "").indexOf(needle) !== -1;
453
+ }
454
+ function tagOptionRender(vals) {
455
+ if (vals.noTagStyle) return vals.label;
456
+ return <Tag {...getTagProps(vals)}></Tag>;
457
+ }
458
+
459
+ function getSort(text, queryString) {
460
+ let ret;
461
+ if (text === queryString) ret = 0;
462
+ else if (text.includes(queryString)) ret = 0.9;
463
+ else ret = 1;
464
+ return ret;
465
+ }
@@ -0,0 +1,34 @@
1
+ .tg-select {
2
+ width: 100%;
3
+ min-width: 170px;
4
+ }
5
+ .tg-select input {
6
+ font-size: 14px;
7
+ }
8
+ .tg-select-option {
9
+ width: fit-content;
10
+ min-width: 100%;
11
+ }
12
+ /* Fix cutoff placeholder */
13
+ .tg-select .bp3-input-ghost[placeholder] {
14
+ width: 80%;
15
+ text-overflow: ellipsis;
16
+ }
17
+
18
+ .tg-single-select input {
19
+ position: absolute;
20
+ top: 5px;
21
+ }
22
+ .tg-single-select .bp3-tag {
23
+ background-color: initial !important;
24
+ font-size: 14px;
25
+ }
26
+ .tg-single-select .bp3-popover-open .bp3-tag {
27
+ opacity: 0.6;
28
+ }
29
+ .bp3-multi-select-popover .bp3-menu,
30
+ .bp3-select-popover .bp3-menu {
31
+ max-width: 400px;
32
+ max-height: 300px;
33
+ overflow: auto;
34
+ }