@teselagen/ui 0.7.36 → 0.8.2

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 (167) hide show
  1. package/DataTable/EditabelCell.d.ts +7 -0
  2. package/DataTable/defaultProps.d.ts +43 -0
  3. package/DataTable/utils/computePresets.d.ts +1 -0
  4. package/DataTable/utils/useDeepEqualMemo.d.ts +1 -0
  5. package/DataTable/utils/useTableParams.d.ts +49 -0
  6. package/index.cjs.js +30 -9
  7. package/index.es.js +30 -9
  8. package/package.json +1 -1
  9. package/src/AdvancedOptions.spec.js +26 -0
  10. package/src/AsyncValidateFieldSpinner/index.js +12 -0
  11. package/src/BlueprintError/index.js +14 -0
  12. package/src/BounceLoader/index.js +16 -0
  13. package/src/BounceLoader/style.css +45 -0
  14. package/src/CollapsibleCard/index.js +68 -0
  15. package/src/CollapsibleCard/style.css +23 -0
  16. package/src/DNALoader/index.js +20 -0
  17. package/src/DNALoader/style.css +251 -0
  18. package/src/DataTable/Columns.jsx +945 -0
  19. package/src/DataTable/EditabelCell.jsx +44 -0
  20. package/src/DataTable/EditableCell.js +44 -0
  21. package/src/DataTable/RenderCell.js +191 -0
  22. package/{RenderCell.js → src/DataTable/RenderCell.jsx} +1 -1
  23. package/src/DataTable/defaultProps.js +45 -0
  24. package/src/DataTable/index.js +3244 -0
  25. package/src/DataTable/style.css +608 -0
  26. package/src/DataTable/utils/computePresets.js +42 -0
  27. package/src/DataTable/utils/index.js +55 -0
  28. package/src/DataTable/utils/useDeepEqualMemo.js +10 -0
  29. package/src/DataTable/utils/useTableParams.js +361 -0
  30. package/src/DialogFooter/index.js +86 -0
  31. package/src/DialogFooter/style.css +9 -0
  32. package/src/FormComponents/index.js +1266 -0
  33. package/src/FormComponents/style.css +275 -0
  34. package/src/FormComponents/utils.js +6 -0
  35. package/src/HotkeysDialog/index.js +79 -0
  36. package/src/HotkeysDialog/style.css +54 -0
  37. package/src/InfoHelper/index.js +78 -0
  38. package/src/InfoHelper/style.css +7 -0
  39. package/src/IntentText/index.js +18 -0
  40. package/src/Loading/index.js +70 -0
  41. package/src/Loading/style.css +4 -0
  42. package/src/MenuBar/index.js +423 -0
  43. package/src/MenuBar/style.css +45 -0
  44. package/src/PromptUnsavedChanges/index.js +38 -0
  45. package/src/ResizableDraggableDialog/index.js +141 -0
  46. package/src/ResizableDraggableDialog/style.css +42 -0
  47. package/src/ScrollToTop/index.js +72 -0
  48. package/src/TagSelect/index.js +69 -0
  49. package/src/TagSelect/style.css +13 -0
  50. package/src/TgHtmlSelect/index.js +20 -0
  51. package/src/TgSelect/index.js +537 -0
  52. package/src/TgSelect/style.css +61 -0
  53. package/src/TgSuggest/index.js +124 -0
  54. package/src/Timeline/index.js +15 -0
  55. package/src/Timeline/style.css +29 -0
  56. package/src/enhancers/withDialog/index.js +196 -0
  57. package/src/index.js +87 -0
  58. package/src/showConfirmationDialog/index.js +148 -0
  59. package/src/style.css +265 -0
  60. package/{isBeingCalledExcessively.js → src/utils/isBeingCalledExcessively.js} +0 -2
  61. package/style.css +10508 -0
  62. /package/{AdvancedOptions.js → src/AdvancedOptions.js} +0 -0
  63. /package/{AssignDefaultsModeContext.js → src/AssignDefaultsModeContext.js} +0 -0
  64. /package/{CellDragHandle.js → src/DataTable/CellDragHandle.js} +0 -0
  65. /package/{ColumnFilterMenu.js → src/DataTable/ColumnFilterMenu.js} +0 -0
  66. /package/{Columns.js → src/DataTable/Columns.js} +0 -0
  67. /package/{DisabledLoadingComponent.js → src/DataTable/DisabledLoadingComponent.js} +0 -0
  68. /package/{DisplayOptions.js → src/DataTable/DisplayOptions.js} +0 -0
  69. /package/{DropdownCell.js → src/DataTable/DropdownCell.js} +0 -0
  70. /package/{EditableCell.js → src/DataTable/EditabelCell.js} +0 -0
  71. /package/{FilterAndSortMenu.js → src/DataTable/FilterAndSortMenu.js} +0 -0
  72. /package/{PagingTool.js → src/DataTable/PagingTool.js} +0 -0
  73. /package/{SearchBar.js → src/DataTable/SearchBar.js} +0 -0
  74. /package/{SortableColumns.js → src/DataTable/SortableColumns.js} +0 -0
  75. /package/{TableFormTrackerContext.js → src/DataTable/TableFormTrackerContext.js} +0 -0
  76. /package/{ThComponent.js → src/DataTable/ThComponent.js} +0 -0
  77. /package/{dataTableEnhancer.js → src/DataTable/dataTableEnhancer.js} +0 -0
  78. /package/{defaultFormatters.js → src/DataTable/defaultFormatters.js} +0 -0
  79. /package/{defaultValidators.js → src/DataTable/defaultValidators.js} +0 -0
  80. /package/{editCellHelper.js → src/DataTable/editCellHelper.js} +0 -0
  81. /package/{getCellVal.js → src/DataTable/getCellVal.js} +0 -0
  82. /package/{getVals.js → src/DataTable/getVals.js} +0 -0
  83. /package/{isTruthy.js → src/DataTable/isTruthy.js} +0 -0
  84. /package/{isValueEmpty.js → src/DataTable/isValueEmpty.js} +0 -0
  85. /package/{convertSchema.js → src/DataTable/utils/convertSchema.js} +0 -0
  86. /package/{formatPasteData.js → src/DataTable/utils/formatPasteData.js} +0 -0
  87. /package/{getAllRows.js → src/DataTable/utils/getAllRows.js} +0 -0
  88. /package/{getCellCopyText.js → src/DataTable/utils/getCellCopyText.js} +0 -0
  89. /package/{getCellInfo.js → src/DataTable/utils/getCellInfo.js} +0 -0
  90. /package/{getFieldPathToField.js → src/DataTable/utils/getFieldPathToField.js} +0 -0
  91. /package/{getIdOrCodeOrIndex.js → src/DataTable/utils/getIdOrCodeOrIndex.js} +0 -0
  92. /package/{getLastSelectedEntity.js → src/DataTable/utils/getLastSelectedEntity.js} +0 -0
  93. /package/{getNewEntToSelect.js → src/DataTable/utils/getNewEntToSelect.js} +0 -0
  94. /package/{getRowCopyText.js → src/DataTable/utils/getRowCopyText.js} +0 -0
  95. /package/{getTableConfigFromStorage.js → src/DataTable/utils/getTableConfigFromStorage.js} +0 -0
  96. /package/{handleCopyColumn.js → src/DataTable/utils/handleCopyColumn.js} +0 -0
  97. /package/{handleCopyHelper.js → src/DataTable/utils/handleCopyHelper.js} +0 -0
  98. /package/{handleCopyRows.js → src/DataTable/utils/handleCopyRows.js} +0 -0
  99. /package/{handleCopyTable.js → src/DataTable/utils/handleCopyTable.js} +0 -0
  100. /package/{isBottomRightCornerOfRectangle.js → src/DataTable/utils/isBottomRightCornerOfRectangle.js} +0 -0
  101. /package/{isEntityClean.js → src/DataTable/utils/isEntityClean.js} +0 -0
  102. /package/{primarySelectedValue.js → src/DataTable/utils/primarySelectedValue.js} +0 -0
  103. /package/{queryParams.js → src/DataTable/utils/queryParams.js} +0 -0
  104. /package/{removeCleanRows.js → src/DataTable/utils/removeCleanRows.js} +0 -0
  105. /package/{rowClick.js → src/DataTable/utils/rowClick.js} +0 -0
  106. /package/{selection.js → src/DataTable/utils/selection.js} +0 -0
  107. /package/{useTableEntities.js → src/DataTable/utils/useTableEntities.js} +0 -0
  108. /package/{utils.js → src/DataTable/utils/utils.js} +0 -0
  109. /package/{withSelectedEntities.js → src/DataTable/utils/withSelectedEntities.js} +0 -0
  110. /package/{withTableParams.js → src/DataTable/utils/withTableParams.js} +0 -0
  111. /package/{validateTableWideErrors.js → src/DataTable/validateTableWideErrors.js} +0 -0
  112. /package/{viewColumn.js → src/DataTable/viewColumn.js} +0 -0
  113. /package/{DropdownButton.js → src/DropdownButton.js} +0 -0
  114. /package/{FillWindow.css → src/FillWindow.css} +0 -0
  115. /package/{FillWindow.js → src/FillWindow.js} +0 -0
  116. /package/{FormSeparator.js → src/FormComponents/FormSeparator.js} +0 -0
  117. /package/{LoadingDots.js → src/FormComponents/LoadingDots.js} +0 -0
  118. /package/{Uploader.js → src/FormComponents/Uploader.js} +0 -0
  119. /package/{getNewName.js → src/FormComponents/getNewName.js} +0 -0
  120. /package/{itemUpload.js → src/FormComponents/itemUpload.js} +0 -0
  121. /package/{sortify.js → src/FormComponents/sortify.js} +0 -0
  122. /package/{tryToMatchSchemas.js → src/FormComponents/tryToMatchSchemas.js} +0 -0
  123. /package/{MatchHeaders.js → src/MatchHeaders.js} +0 -0
  124. /package/{SimpleStepViz.js → src/SimpleStepViz.js} +0 -0
  125. /package/{Tag.js → src/Tag.js} +0 -0
  126. /package/{TimelineEvent.js → src/Timeline/TimelineEvent.js} +0 -0
  127. /package/{UploadCsvWizard.css → src/UploadCsvWizard.css} +0 -0
  128. /package/{UploadCsvWizard.js → src/UploadCsvWizard.js} +0 -0
  129. /package/{autoTooltip.js → src/autoTooltip.js} +0 -0
  130. /package/{constants.js → src/constants.js} +0 -0
  131. /package/{customIcons.js → src/customIcons.js} +0 -0
  132. /package/{tg_modalState.js → src/enhancers/withDialog/tg_modalState.js} +0 -0
  133. /package/{withField.js → src/enhancers/withField.js} +0 -0
  134. /package/{withFields.js → src/enhancers/withFields.js} +0 -0
  135. /package/{withLocalStorage.js → src/enhancers/withLocalStorage.js} +0 -0
  136. /package/{rerenderOnWindowResize.js → src/rerenderOnWindowResize.js} +0 -0
  137. /package/{showAppSpinner.js → src/showAppSpinner.js} +0 -0
  138. /package/{showDialogOnDocBody.js → src/showDialogOnDocBody.js} +0 -0
  139. /package/{throwFormError.js → src/throwFormError.js} +0 -0
  140. /package/{toastr.js → src/toastr.js} +0 -0
  141. /package/{typeToCommonType.js → src/typeToCommonType.js} +0 -0
  142. /package/{useDialog.js → src/useDialog.js} +0 -0
  143. /package/{adHoc.js → src/utils/adHoc.js} +0 -0
  144. /package/{basicHandleActionsWithFullState.js → src/utils/basicHandleActionsWithFullState.js} +0 -0
  145. /package/{browserUtils.js → src/utils/browserUtils.js} +0 -0
  146. /package/{combineReducersWithFullState.js → src/utils/combineReducersWithFullState.js} +0 -0
  147. /package/{commandControls.js → src/utils/commandControls.js} +0 -0
  148. /package/{commandUtils.js → src/utils/commandUtils.js} +0 -0
  149. /package/{determineBlackOrWhiteTextColor.js → src/utils/determineBlackOrWhiteTextColor.js} +0 -0
  150. /package/{getDayjsFormatter.js → src/utils/getDayjsFormatter.js} +0 -0
  151. /package/{getTextFromEl.js → src/utils/getTextFromEl.js} +0 -0
  152. /package/{handlerHelpers.js → src/utils/handlerHelpers.js} +0 -0
  153. /package/{index.js → src/utils/hooks/index.js} +0 -0
  154. /package/{useDeepEqualMemo.js → src/utils/hooks/useDeepEqualMemo.js} +0 -0
  155. /package/{useStableReference.js → src/utils/hooks/useStableReference.js} +0 -0
  156. /package/{hotkeyUtils.js → src/utils/hotkeyUtils.js} +0 -0
  157. /package/{menuUtils.js → src/utils/menuUtils.js} +0 -0
  158. /package/{popoverOverflowModifiers.js → src/utils/popoverOverflowModifiers.js} +0 -0
  159. /package/{pureNoFunc.js → src/utils/pureNoFunc.js} +0 -0
  160. /package/{renderOnDoc.js → src/utils/renderOnDoc.js} +0 -0
  161. /package/{showProgressToast.js → src/utils/showProgressToast.js} +0 -0
  162. /package/{tagUtils.js → src/utils/tagUtils.js} +0 -0
  163. /package/{tgFormValues.js → src/utils/tgFormValues.js} +0 -0
  164. /package/{useTraceUpdate.js → src/utils/useTraceUpdate.js} +0 -0
  165. /package/{withSelectTableRecords.js → src/utils/withSelectTableRecords.js} +0 -0
  166. /package/{withStore.js → src/utils/withStore.js} +0 -0
  167. /package/{wrapDialog.js → src/wrapDialog.js} +0 -0
@@ -0,0 +1,423 @@
1
+ import React from "react";
2
+ import {
3
+ pickBy,
4
+ isNumber,
5
+ startsWith,
6
+ flatMap,
7
+ take,
8
+ flatten,
9
+ noop
10
+ } from "lodash-es";
11
+ import { Suggest } from "@blueprintjs/select";
12
+ import "./style.css";
13
+ import { Popover, Position, Menu, Button } from "@blueprintjs/core";
14
+ import { some } from "lodash-es";
15
+ import {
16
+ createDynamicMenu,
17
+ DynamicMenuItem,
18
+ getStringFromReactComponent,
19
+ doesSearchValMatchText
20
+ } from "../utils/menuUtils";
21
+ import { comboToLabel, withHotkeys } from "../utils/hotkeyUtils";
22
+
23
+ class MenuBar extends React.Component {
24
+ constructor(props) {
25
+ super(props);
26
+ const combo =
27
+ (this.props && this.props.menuSearchHotkey) || menuSearchHotkey;
28
+ this.hotkeyEnabler = withHotkeys({
29
+ searchHotkey: {
30
+ allowInInput: true,
31
+ global: true,
32
+ combo,
33
+ label: "Search the menu",
34
+ preventDefault: true,
35
+ stopPropagation: true,
36
+ onKeyDown: this.toggleFocusSearchMenu
37
+ }
38
+ });
39
+ }
40
+ static defaultProps = {
41
+ className: "",
42
+ style: {}
43
+ };
44
+
45
+ state = {
46
+ isOpen: false,
47
+ openIndex: null,
48
+ helpItemQueryStringTracker: "" //we use this to track the search value and to not do all the item rendering logic until someone is actually searching
49
+ };
50
+
51
+ handleInteraction = index => newOpenState => {
52
+ if (!newOpenState && index !== this.state.openIndex) {
53
+ return; //return early because the "close" is being fired by another popover
54
+ }
55
+ this.setState({
56
+ isOpen: newOpenState,
57
+ openIndex: newOpenState ? index : null
58
+ });
59
+ };
60
+ handleMouseOver = index => () => {
61
+ const { isOpen } = this.state;
62
+ if (isOpen) {
63
+ this.setState({
64
+ openIndex: index
65
+ });
66
+ }
67
+ };
68
+
69
+ getAllMenuItems = () => {
70
+ const { menu, enhancers, context } = this.props;
71
+ return getAllMenuTextsAndHandlers(menu, enhancers, context);
72
+ };
73
+ addHelpItemIfNecessary = (menu, i) => {
74
+ return menu.map((item, innerIndex) => {
75
+ const { isMenuSearch, inputProps, ...rest } = item;
76
+ if (isMenuSearch) {
77
+ const isTopLevelSearch = !isNumber(i);
78
+ this.isTopLevelSearch = isTopLevelSearch;
79
+ this.menuSearchIndex = isTopLevelSearch ? innerIndex : i;
80
+
81
+ return {
82
+ shouldDismissPopover: false,
83
+ text: (
84
+ <Suggest
85
+ closeOnSelect={false}
86
+ items={
87
+ this.state.helpItemQueryStringTracker
88
+ ? this.getAllMenuItems()
89
+ : []
90
+ }
91
+ itemListPredicate={filterMenuItems}
92
+ itemDisabled={i => i.disabled}
93
+ popoverProps={{
94
+ minimal: true,
95
+ popoverClassName: "tg-menu-search-suggestions"
96
+ }}
97
+ onQueryChange={val => {
98
+ this.setState({ helpItemQueryStringTracker: val });
99
+ }}
100
+ className="tg-menu-bar-help-search"
101
+ resetOnSelect={false}
102
+ resetOnClose={true}
103
+ inputProps={{
104
+ inputRef: n => {
105
+ if (n) {
106
+ this.searchInput = n;
107
+ n.setAttribute &&
108
+ n.setAttribute(
109
+ "size",
110
+ n.getAttribute("placeholder").length
111
+ );
112
+ }
113
+ },
114
+ autoFocus: !isTopLevelSearch,
115
+ placeholder: `Search the menus (${comboToLabel(
116
+ this.props.menuSearchHotkey || menuSearchHotkey,
117
+ false
118
+ ).replace(/\s/g, "")})`,
119
+ ...inputProps
120
+ }}
121
+ initialContent={null}
122
+ onItemSelect={this.handleItemClickOrSelect()}
123
+ inputValueRenderer={i => i.text}
124
+ noResults={<div>No Results...</div>}
125
+ itemRenderer={this.helpItemRenderer}
126
+ {...rest}
127
+ />
128
+ )
129
+ };
130
+ } else {
131
+ return item;
132
+ }
133
+ });
134
+ };
135
+
136
+ helpItemRenderer = (i, b) => {
137
+ // if (i.submenu.length === 3) debugger;
138
+ return (
139
+ <DynamicMenuItem
140
+ key={b.index}
141
+ {...{
142
+ doNotEnhanceTopLevelItem: true,
143
+ enhancers: this.props.enhancers,
144
+ def: {
145
+ ...i,
146
+ text: i.isSimpleText ? i.justText || i.text : i.text,
147
+ label: i.path.length && (
148
+ <span style={{ fontSize: 8 }}>
149
+ {flatMap(i.path, (el, i2) => {
150
+ if (i2 === 0) return el;
151
+ return [" > ", el];
152
+ })}
153
+ </span>
154
+ ),
155
+ onClick: this.handleItemClickOrSelect(i),
156
+ active: b.modifiers.active
157
+ // shouldDismissPopover: true,
158
+ }
159
+ }}
160
+ />
161
+ );
162
+ };
163
+ // itemRenderer = (i, b) => {
164
+ // return (
165
+ // <MenuItem
166
+ // key={b.index}
167
+ // {...{
168
+ // // ...i,
169
+ // icon: i.icon,
170
+ // text: i.isSimpleText ? i.justText || i.text : i.text,
171
+ // label: i.path.length && (
172
+ // <span style={{ fontSize: 8 }}>
173
+ // {flatMap(i.path, (el, i2) => {
174
+ // if (i2 === 0) return el;
175
+ // return [" > ", el];
176
+ // })}
177
+ // </span>
178
+ // ),
179
+ // onClick: this.handleItemClickOrSelect(i),
180
+ // active: b.modifiers.active
181
+ // // shouldDismissPopover: true,
182
+ // }}
183
+ // />
184
+ // );
185
+ // };
186
+
187
+ handleItemClickOrSelect = __i => _i => {
188
+ const i = __i || _i;
189
+ if (!i.onClick) return;
190
+ !i.disabled && i.onClick();
191
+ if (i.shouldDismissPopover !== false) {
192
+ this.setState({ isOpen: false });
193
+ } else {
194
+ if (_i && _i.stopPropagation) {
195
+ _i.stopPropagation();
196
+ _i.preventDefault();
197
+ }
198
+ }
199
+ };
200
+ toggleFocusSearchMenu = () => {
201
+ if (!isNumber(this.menuSearchIndex)) return;
202
+ //toggle off
203
+ if (this.searchInput && document.activeElement === this.searchInput) {
204
+ this.searchInput.blur();
205
+ this.setState({
206
+ isOpen: false,
207
+ openIndex: this.menuSearchIndex
208
+ });
209
+ } else {
210
+ //toggle on
211
+ if (this.isTopLevelSearch) {
212
+ this.searchInput && this.searchInput.focus();
213
+ } else {
214
+ this.setState({
215
+ isOpen: true,
216
+ openIndex: this.menuSearchIndex
217
+ });
218
+ }
219
+ }
220
+ };
221
+
222
+ render() {
223
+ const { className, style, menu, enhancers, extraContent } = this.props;
224
+ const { isOpen, openIndex } = this.state;
225
+ return (
226
+ <div className={"tg-menu-bar " + className} style={style}>
227
+ <this.hotkeyEnabler></this.hotkeyEnabler>
228
+ {menu.map((topLevelItem, i) => {
229
+ const dataKeys = pickBy(topLevelItem, function (value, key) {
230
+ return startsWith(key, "data-");
231
+ });
232
+
233
+ // Support enhancers for top level items too
234
+ topLevelItem = enhancers.reduce((v, f) => f(v), topLevelItem);
235
+
236
+ if (topLevelItem.hidden) {
237
+ return null;
238
+ }
239
+
240
+ const button = (
241
+ <Button
242
+ {...dataKeys} //spread all data-* attributes
243
+ key={i}
244
+ elementRef={n => {
245
+ if (!n) return;
246
+ this.n = n;
247
+ }}
248
+ minimal
249
+ className="tg-menu-bar-item"
250
+ onClick={topLevelItem.onClick}
251
+ disabled={topLevelItem.disabled}
252
+ onMouseOver={
253
+ topLevelItem.submenu ? this.handleMouseOver(i) : noop
254
+ }
255
+ >
256
+ {topLevelItem.text}
257
+ </Button>
258
+ );
259
+ const vh = Math.max(
260
+ document.documentElement.clientHeight || 0,
261
+ window.innerHeight || 0
262
+ );
263
+ const maxHeight =
264
+ vh - ((this.n && this.n.getBoundingClientRect().y + 70) || 70);
265
+
266
+ return !topLevelItem.submenu ? (
267
+ button
268
+ ) : (
269
+ <Popover
270
+ autoFocus={false}
271
+ key={i}
272
+ minimal
273
+ canEscapeKeyClose
274
+ onClosed={() => {
275
+ this.setState({ helpItemQueryStringTracker: "" });
276
+ this.props.onMenuClose && this.props.onMenuClose();
277
+ }}
278
+ portalClassName="tg-menu-bar-popover"
279
+ position={Position.BOTTOM_LEFT}
280
+ isOpen={isOpen && i === openIndex}
281
+ onInteraction={this.handleInteraction(i)}
282
+ content={
283
+ <Menu
284
+ style={
285
+ some(topLevelItem.submenu, n => n.isMenuSearch) //tnrbp4upgrade - I added this logic to prevent the Search Suggest component popover from covering the suggest. Remove this once we're on bp4 (shouldn't be necessary according to https://github.com/palantir/blueprint/issues/4552)
286
+ ? {}
287
+ : { maxHeight, overflow: "auto" }
288
+ }
289
+ >
290
+ {createDynamicMenu(
291
+ this.addHelpItemIfNecessary(topLevelItem.submenu, i),
292
+ enhancers
293
+ )}
294
+ </Menu>
295
+ }
296
+ transitionDuration={0}
297
+ style={{
298
+ transition: "none"
299
+ }}
300
+ inline
301
+ >
302
+ {button}
303
+ </Popover>
304
+ );
305
+ })}
306
+ {extraContent}
307
+ </div>
308
+ );
309
+ }
310
+ }
311
+
312
+ const isDivider = item => item.divider !== undefined;
313
+
314
+ function getAllMenuTextsAndHandlers(menu, enhancers, context, path = []) {
315
+ if (!menu) return [];
316
+ return flatMap(menu, item => {
317
+ const enhancedItem = [...enhancers].reduce((v, f) => f(v, context), item);
318
+ if (isDivider(enhancedItem)) {
319
+ return [];
320
+ }
321
+ if (enhancedItem && enhancedItem.hidden) return [];
322
+ return [
323
+ {
324
+ ...enhancedItem,
325
+ path
326
+ },
327
+ ...getAllMenuTextsAndHandlers(enhancedItem.submenu, enhancers, context, [
328
+ ...path,
329
+ enhancedItem.text
330
+ ])
331
+ ];
332
+ });
333
+ }
334
+
335
+ const filterMenuItems = (searchVal, items) => {
336
+ const newItems = flatMap(items, item => {
337
+ const {
338
+ text,
339
+ onClick,
340
+ hidden,
341
+ hideFromMenuSearch,
342
+ hiddenButSearchableText,
343
+ showInSearchMenu,
344
+ component
345
+ } = item;
346
+
347
+ if (
348
+ !showInSearchMenu &&
349
+ !component &&
350
+ (!text || !onClick || !searchVal || hideFromMenuSearch || hidden)
351
+ ) {
352
+ return [];
353
+ }
354
+ //fix this to use some smart regex
355
+ let justText = text;
356
+ let isSimpleText = true;
357
+ if (!text.toLowerCase) {
358
+ if (text.props) {
359
+ isSimpleText = false;
360
+ justText = getStringFromReactComponent(text);
361
+ } else {
362
+ return [];
363
+ }
364
+ }
365
+
366
+ if (
367
+ doesSearchValMatchText(
368
+ searchVal,
369
+ hiddenButSearchableText
370
+ ? `${justText} ${hiddenButSearchableText}`
371
+ : justText
372
+ )
373
+ ) {
374
+ return {
375
+ ...item,
376
+ justText,
377
+ isSimpleText
378
+ };
379
+ } else {
380
+ return [];
381
+ }
382
+ }).sort((a, b) => a.justText.length - b.justText.length);
383
+
384
+ return take(newItems, 10).map(i => ({
385
+ ...i,
386
+ justText: highlight(searchVal, i.justText)
387
+ }));
388
+ };
389
+
390
+ const menuSearchHotkey = "meta+/";
391
+
392
+ function highlight(query, text, opts) {
393
+ opts = opts || { tag: <strong /> };
394
+
395
+ if (query.length === 0) {
396
+ return text;
397
+ }
398
+
399
+ const offset = text.toLowerCase().indexOf(query[0].toLowerCase());
400
+ if (offset === -1) return text;
401
+
402
+ let last = 0;
403
+ for (let i = 1; i < query.length; i++) {
404
+ if (text[offset + i] !== query[i]) {
405
+ break;
406
+ }
407
+
408
+ last = i;
409
+ }
410
+
411
+ const before = text.slice(0, offset);
412
+ const match = <strong>{text.slice(offset, offset + last + 1)}</strong>;
413
+
414
+ const after = highlight(
415
+ query.slice(last + 1),
416
+ text.slice(offset + last + 1),
417
+ opts
418
+ );
419
+
420
+ return flatten([before, match, after]);
421
+ }
422
+
423
+ export default MenuBar;
@@ -0,0 +1,45 @@
1
+ .tg-menu-bar {
2
+ /* background: white; */
3
+ color: inherit;
4
+ text-decoration: none;
5
+ z-index: 19;
6
+ display: flex;
7
+ justify-content: flex-start;
8
+ align-items: center;
9
+ height: 34px;
10
+ width: 100%;
11
+ padding-left: 15px;
12
+ }
13
+
14
+ .tg-menu-bar-item {
15
+ margin: 2px;
16
+ }
17
+
18
+ .tg-menu-bar .bp3-popover {
19
+ margin-top: -1px !important;
20
+ }
21
+
22
+ .tg-menu-bar-popover .bp3-popover .bp3-popover-arrow {
23
+ display: none;
24
+ }
25
+
26
+ /* removing the display inline styling because they broke menu positioning: https://github.com/TeselaGen/lims/issues/2563 */
27
+ /* .tg-menu-bar-popover .bp3-popover-wrapper {
28
+ display: inline;
29
+ }
30
+ .tg-menu-search-suggestions .bp3-popover-wrapper {
31
+ display: inline;
32
+ } */
33
+ /* add a fix here that applies the above logic to only the first child of the menu */
34
+ .tg-menu-search-suggestions .bp3-menu > .bp3-popover-wrapper {
35
+ display: inline;
36
+ }
37
+
38
+ li.bp3-menu-divider + li.bp3-menu-divider,
39
+ li.bp3-menu-divider:first-child,
40
+ li.bp3-menu-divider:last-child {
41
+ display: none;
42
+ }
43
+ .tg_search_highlight {
44
+ font-weight: bold;
45
+ }
@@ -0,0 +1,38 @@
1
+ /* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
2
+
3
+ import React, { useEffect } from "react";
4
+ import { Prompt } from "react-router-dom";
5
+
6
+ export const defaultMessagge =
7
+ "Are you sure you want to leave? There are unsaved changes.";
8
+
9
+ const warnBeforeLeave = e => {
10
+ // if we are in a cypress test run then we don't want to block navigation
11
+ if (window.Cypress) {
12
+ return null;
13
+ }
14
+
15
+ // Maintains older browser compatibility. In newer versions a generic string is returned
16
+ (e || window.event).returnValue = defaultMessagge; //Gecko + IE
17
+ return defaultMessagge; //Webkit, Safari, Chrome
18
+ };
19
+
20
+ export function PromptUnsavedChanges({
21
+ message = defaultMessagge,
22
+ when = false
23
+ }) {
24
+ useEffect(() => {
25
+ if (when) {
26
+ window.addEventListener("beforeunload", warnBeforeLeave);
27
+ }
28
+ return () => window.removeEventListener("beforeunload", warnBeforeLeave);
29
+ });
30
+
31
+ if (window.Cypress) {
32
+ return null;
33
+ }
34
+
35
+ return <Prompt when={when} message={message} />;
36
+ }
37
+
38
+ export default PromptUnsavedChanges;
@@ -0,0 +1,141 @@
1
+ import React from "react";
2
+ import { Dialog, Classes } from "@blueprintjs/core";
3
+ import { Rnd } from "react-rnd";
4
+ import { debounce } from "lodash-es";
5
+ import "./style.css";
6
+
7
+ const defaultDialogWidth = 400;
8
+ const defaultDialogHeight = 100;
9
+ export default class ResizableDraggableDialog extends React.Component {
10
+ componentDidMount() {
11
+ window.addEventListener("resize", this.onWindowResize);
12
+ this.setDefaults();
13
+ setTimeout(() => {
14
+ this.setDefaults();
15
+ try {
16
+ const el = this.containerEl.querySelector(".bp3-dialog-body");
17
+ this.resizeObs = new ResizeObserver(
18
+ debounce(() => {
19
+ this.setDefaults({ doNotSetXOrWidth: true });
20
+ })
21
+ );
22
+ this.resizeObs.observe(el);
23
+ } catch (e) {
24
+ console.warn(
25
+ `1214124599 Error setting up resize observer on dialog :`,
26
+ e
27
+ );
28
+ }
29
+ }, 0);
30
+ }
31
+ state = {
32
+ x: 0,
33
+ y: 0,
34
+ width: defaultDialogWidth,
35
+ height: defaultDialogHeight
36
+ };
37
+
38
+ setDefaults = ({ doNotSetXOrWidth } = {}) => {
39
+ const { width, height } = this.props;
40
+ const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();
41
+
42
+ let heightToUse;
43
+ if (height) {
44
+ heightToUse = height;
45
+ } else {
46
+ heightToUse = (document.querySelector(".bp3-dialog-body") || {})
47
+ .scrollHeight;
48
+ if (heightToUse) {
49
+ heightToUse = heightToUse + 60;
50
+ } else {
51
+ heightToUse = defaultDialogHeight;
52
+ }
53
+ }
54
+ let widthToUse;
55
+ if (width) {
56
+ widthToUse = width;
57
+ } else {
58
+ widthToUse = defaultDialogWidth;
59
+ }
60
+
61
+ this.setState({
62
+ ...(doNotSetXOrWidth
63
+ ? {}
64
+ : {
65
+ x: Math.round(Math.max((windowWidth - widthToUse) / 2, 0)),
66
+ width: Math.min(widthToUse, windowWidth)
67
+ }),
68
+ y: Math.round(Math.max((windowHeight - heightToUse) / 2, 0)),
69
+ height: Math.min(Math.max(defaultDialogHeight, heightToUse), windowHeight)
70
+ });
71
+ };
72
+ onWindowResize = () => {
73
+ this.setDefaults();
74
+ };
75
+ componentWillUnmount() {
76
+ this.resizeObs && this.resizeObs.disconnect();
77
+ window.removeEventListener("resize", this.onWindowResize);
78
+ }
79
+
80
+ getWindowWidthAndHeight = () => {
81
+ const w = window,
82
+ d = document,
83
+ e = d.documentElement,
84
+ g = d.getElementsByTagName("body")[0],
85
+ windowWidth = w.innerWidth || e.clientWidth || g.clientWidth,
86
+ windowHeight = w.innerHeight || e.clientHeight || g.clientHeight;
87
+ return {
88
+ windowWidth,
89
+ windowHeight: windowHeight - 20 //add a small correction here
90
+ };
91
+ };
92
+
93
+ render() {
94
+ const { width, height, RndProps, ...rest } = this.props;
95
+ const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();
96
+ return (
97
+ <div
98
+ ref={el => {
99
+ if (el) this.containerEl = el;
100
+ }}
101
+ className="tg-bp3-dialog-resizable-draggable"
102
+ style={{ top: 0, left: 0, position: "fixed" }}
103
+ >
104
+ <Rnd
105
+ cancel=".bp3-dialog-close-button"
106
+ enableResizing={{
107
+ bottomLeft: true,
108
+ bottomRight: true,
109
+ topLeft: true,
110
+ topRight: true
111
+ }}
112
+ maxHeight={windowHeight}
113
+ maxWidth={windowWidth}
114
+ bounds="window"
115
+ size={{ width: this.state.width, height: this.state.height }}
116
+ position={{ x: this.state.x, y: this.state.y }}
117
+ onDragStop={(e, d) => {
118
+ this.setState({ x: d.x, y: d.y });
119
+ }}
120
+ onResizeStop={(e, direction, ref, delta, position) => {
121
+ this.setState({
122
+ width: ref.style.width,
123
+ height: ref.style.height,
124
+ ...position
125
+ });
126
+ }}
127
+ dragHandleClassName={Classes.DIALOG_HEADER}
128
+ {...RndProps}
129
+ >
130
+ <Dialog
131
+ enforceFocus={false}
132
+ hasBackdrop={false}
133
+ usePortal={false}
134
+ canEscapeKeyClose={true}
135
+ {...rest}
136
+ />
137
+ </Rnd>
138
+ </div>
139
+ );
140
+ }
141
+ }
@@ -0,0 +1,42 @@
1
+ .tg-bp3-dialog-resizable-draggable {
2
+ z-index: 40000; /* necessary for open-vector-editor */
3
+ }
4
+ .tg-bp3-dialog-resizable-draggable
5
+ .bp3-overlay.bp3-overlay-scroll-container.bp3-overlay-inline {
6
+ position: static;
7
+ height: 100%;
8
+ width: 100%;
9
+ }
10
+
11
+ .tg-bp3-dialog-resizable-draggable .bp3-overlay-inline .bp3-overlay-content,
12
+ .tg-bp3-dialog-resizable-draggable
13
+ .bp3-overlay-scroll-container
14
+ .bp3-overlay-content {
15
+ position: static;
16
+ width: 100%;
17
+ height: 100%;
18
+ }
19
+ .tg-bp3-dialog-resizable-draggable .bp3-dialog-container .bp3-dialog {
20
+ position: absolute;
21
+ top: 0;
22
+ width: 100%;
23
+ /* height: 100%; */
24
+ max-height: 100%;
25
+ /* height: -webkit-fill-available; */
26
+ margin: 0 !important;
27
+ }
28
+ .tg-bp3-dialog-resizable-draggable .bp3-dialog-header {
29
+ cursor: move;
30
+ }
31
+ .tg-bp3-dialog-resizable-draggable .bp3-dialog-body {
32
+ height: 100%;
33
+ width: 100%;
34
+ width: stretch;
35
+ overflow: auto;
36
+ margin: 0px;
37
+ padding: 20px;
38
+ padding-bottom: 0px;
39
+ }
40
+ .tg-bp3-dialog-resizable-draggable .bp3-overlay-backdrop {
41
+ display: none;
42
+ }