@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,416 @@
1
+ import React from "react";
2
+ import { pickBy, isNumber, startsWith, flatMap, take, flatten, noop } from "lodash";
3
+ import { Suggest } from "@blueprintjs/select";
4
+ import "./style.css";
5
+ import { Popover, Position, Menu, Button } from "@blueprintjs/core";
6
+ import { some } from "lodash";
7
+ import {
8
+ createDynamicMenu,
9
+ DynamicMenuItem,
10
+ getStringFromReactComponent,
11
+ doesSearchValMatchText
12
+ } from "../utils/menuUtils";
13
+ import { comboToLabel, withHotkeys } from "../utils/hotkeyUtils";
14
+
15
+ class MenuBar extends React.Component {
16
+ constructor(props) {
17
+ super(props);
18
+ const combo =
19
+ (this.props && this.props.menuSearchHotkey) || menuSearchHotkey;
20
+ this.hotkeyEnabler = withHotkeys({
21
+ searchHotkey: {
22
+ allowInInput: true,
23
+ global: true,
24
+ combo,
25
+ label: "Search the menu",
26
+ preventDefault: true,
27
+ stopPropagation: true,
28
+ onKeyDown: this.toggleFocusSearchMenu
29
+ }
30
+ });
31
+ }
32
+ static defaultProps = {
33
+ className: "",
34
+ style: {}
35
+ };
36
+
37
+ state = {
38
+ isOpen: false,
39
+ openIndex: null,
40
+ helpItemQueryStringTracker: "" //we use this to track the search value and to not do all the item rendering logic until someone is actually searching
41
+ };
42
+
43
+ handleInteraction = index => newOpenState => {
44
+ if (!newOpenState && index !== this.state.openIndex) {
45
+ return; //return early because the "close" is being fired by another popover
46
+ }
47
+ this.setState({
48
+ isOpen: newOpenState,
49
+ openIndex: newOpenState ? index : null
50
+ });
51
+ };
52
+ handleMouseOver = index => () => {
53
+ const { isOpen } = this.state;
54
+ if (isOpen) {
55
+ this.setState({
56
+ openIndex: index
57
+ });
58
+ }
59
+ };
60
+
61
+ getAllMenuItems = () => {
62
+ const { menu, enhancers, context } = this.props;
63
+ return getAllMenuTextsAndHandlers(menu, enhancers, context);
64
+ };
65
+ addHelpItemIfNecessary = (menu, i) => {
66
+ return menu.map((item, innerIndex) => {
67
+ const { isMenuSearch, inputProps, ...rest } = item;
68
+ if (isMenuSearch) {
69
+ const isTopLevelSearch = !isNumber(i);
70
+ this.isTopLevelSearch = isTopLevelSearch;
71
+ this.menuSearchIndex = isTopLevelSearch ? innerIndex : i;
72
+
73
+ return {
74
+ shouldDismissPopover: false,
75
+ text: (
76
+ <Suggest
77
+ closeOnSelect={false}
78
+ items={
79
+ this.state.helpItemQueryStringTracker
80
+ ? this.getAllMenuItems()
81
+ : []
82
+ }
83
+ itemListPredicate={filterMenuItems}
84
+ itemDisabled={i => i.disabled}
85
+ popoverProps={{
86
+ minimal: true,
87
+ popoverClassName: "tg-menu-search-suggestions"
88
+ }}
89
+ onQueryChange={val => {
90
+ this.setState({ helpItemQueryStringTracker: val });
91
+ }}
92
+ className="tg-menu-bar-help-search"
93
+ resetOnSelect={false}
94
+ resetOnClose={true}
95
+ inputProps={{
96
+ inputRef: n => {
97
+ if (n) {
98
+ this.searchInput = n;
99
+ n.setAttribute &&
100
+ n.setAttribute(
101
+ "size",
102
+ n.getAttribute("placeholder").length
103
+ );
104
+ }
105
+ },
106
+ autoFocus: !isTopLevelSearch,
107
+ placeholder: `Search the menus (${comboToLabel(
108
+ this.props.menuSearchHotkey || menuSearchHotkey,
109
+ false
110
+ ).replace(/\s/g, "")})`,
111
+ ...inputProps
112
+ }}
113
+ initialContent={null}
114
+ onItemSelect={this.handleItemClickOrSelect()}
115
+ inputValueRenderer={i => i.text}
116
+ noResults={<div>No Results...</div>}
117
+ itemRenderer={this.helpItemRenderer}
118
+ {...rest}
119
+ />
120
+ )
121
+ };
122
+ } else {
123
+ return item;
124
+ }
125
+ });
126
+ };
127
+
128
+ helpItemRenderer = (i, b) => {
129
+ // if (i.submenu.length === 3) debugger;
130
+ return (
131
+ <DynamicMenuItem
132
+ key={b.index}
133
+ {...{
134
+ doNotEnhanceTopLevelItem: true,
135
+ enhancers: this.props.enhancers,
136
+ def: {
137
+ ...i,
138
+ text: i.isSimpleText ? i.justText || i.text : i.text,
139
+ label: i.path.length && (
140
+ <span style={{ fontSize: 8 }}>
141
+ {flatMap(i.path, (el, i2) => {
142
+ if (i2 === 0) return el;
143
+ return [" > ", el];
144
+ })}
145
+ </span>
146
+ ),
147
+ onClick: this.handleItemClickOrSelect(i),
148
+ active: b.modifiers.active
149
+ // shouldDismissPopover: true,
150
+ }
151
+ }}
152
+ />
153
+ );
154
+ };
155
+ // itemRenderer = (i, b) => {
156
+ // return (
157
+ // <MenuItem
158
+ // key={b.index}
159
+ // {...{
160
+ // // ...i,
161
+ // icon: i.icon,
162
+ // text: i.isSimpleText ? i.justText || i.text : i.text,
163
+ // label: i.path.length && (
164
+ // <span style={{ fontSize: 8 }}>
165
+ // {flatMap(i.path, (el, i2) => {
166
+ // if (i2 === 0) return el;
167
+ // return [" > ", el];
168
+ // })}
169
+ // </span>
170
+ // ),
171
+ // onClick: this.handleItemClickOrSelect(i),
172
+ // active: b.modifiers.active
173
+ // // shouldDismissPopover: true,
174
+ // }}
175
+ // />
176
+ // );
177
+ // };
178
+
179
+ handleItemClickOrSelect = __i => _i => {
180
+ const i = __i || _i;
181
+ if (!i.onClick) return;
182
+ !i.disabled && i.onClick();
183
+ if (i.shouldDismissPopover !== false) {
184
+ this.setState({ isOpen: false });
185
+ } else {
186
+ if (_i && _i.stopPropagation) {
187
+ _i.stopPropagation();
188
+ _i.preventDefault();
189
+ }
190
+ }
191
+ };
192
+ toggleFocusSearchMenu = () => {
193
+ if (!isNumber(this.menuSearchIndex)) return;
194
+ //toggle off
195
+ if (this.searchInput && document.activeElement === this.searchInput) {
196
+ this.searchInput.blur();
197
+ this.setState({
198
+ isOpen: false,
199
+ openIndex: this.menuSearchIndex
200
+ });
201
+ } else {
202
+ //toggle on
203
+ if (this.isTopLevelSearch) {
204
+ this.searchInput && this.searchInput.focus();
205
+ } else {
206
+ this.setState({
207
+ isOpen: true,
208
+ openIndex: this.menuSearchIndex
209
+ });
210
+ }
211
+ }
212
+ };
213
+
214
+ render() {
215
+ const { className, style, menu, enhancers, extraContent } = this.props;
216
+ const { isOpen, openIndex } = this.state;
217
+ return (
218
+ <div className={"tg-menu-bar " + className} style={style}>
219
+ <this.hotkeyEnabler></this.hotkeyEnabler>
220
+ {menu.map((topLevelItem, i) => {
221
+ const dataKeys = pickBy(topLevelItem, function(value, key) {
222
+ return startsWith(key, "data-");
223
+ });
224
+
225
+ // Support enhancers for top level items too
226
+ topLevelItem = enhancers.reduce((v, f) => f(v), topLevelItem);
227
+
228
+ if (topLevelItem.hidden) {
229
+ return null;
230
+ }
231
+
232
+ const button = (
233
+ <Button
234
+ {...dataKeys} //spread all data-* attributes
235
+ key={i}
236
+ elementRef={n => {
237
+ if (!n) return;
238
+ this.n = n;
239
+ }}
240
+ minimal
241
+ className="tg-menu-bar-item"
242
+ onClick={topLevelItem.onClick}
243
+ disabled={topLevelItem.disabled}
244
+ onMouseOver={
245
+ topLevelItem.submenu ? this.handleMouseOver(i) : noop
246
+ }
247
+ >
248
+ {topLevelItem.text}
249
+ </Button>
250
+ );
251
+ const vh = Math.max(
252
+ document.documentElement.clientHeight || 0,
253
+ window.innerHeight || 0
254
+ );
255
+ const maxHeight =
256
+ vh - ((this.n && this.n.getBoundingClientRect().y + 70) || 70);
257
+
258
+ return !topLevelItem.submenu ? (
259
+ button
260
+ ) : (
261
+ <Popover
262
+ autoFocus={false}
263
+ key={i}
264
+ minimal
265
+ canEscapeKeyClose
266
+ onClosed={() => {
267
+ this.setState({ helpItemQueryStringTracker: "" });
268
+ this.props.onMenuClose && this.props.onMenuClose();
269
+ }}
270
+ portalClassName="tg-menu-bar-popover"
271
+ position={Position.BOTTOM_LEFT}
272
+ isOpen={isOpen && i === openIndex}
273
+ onInteraction={this.handleInteraction(i)}
274
+ content={
275
+ <Menu
276
+ style={
277
+ 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)
278
+ ? {}
279
+ : { maxHeight, overflow: "auto" }
280
+ }
281
+ >
282
+ {createDynamicMenu(
283
+ this.addHelpItemIfNecessary(topLevelItem.submenu, i),
284
+ enhancers
285
+ )}
286
+ </Menu>
287
+ }
288
+ transitionDuration={0}
289
+ style={{
290
+ transition: "none"
291
+ }}
292
+ inline
293
+ >
294
+ {button}
295
+ </Popover>
296
+ );
297
+ })}
298
+ {extraContent}
299
+ </div>
300
+ );
301
+ }
302
+ }
303
+
304
+
305
+ const isDivider = item => item.divider !== undefined;
306
+
307
+ function getAllMenuTextsAndHandlers(menu, enhancers, context, path = []) {
308
+ if (!menu) return [];
309
+ return flatMap(menu, item => {
310
+ const enhancedItem = [...enhancers].reduce((v, f) => f(v, context), item);
311
+ if (isDivider(enhancedItem)) {
312
+ return [];
313
+ }
314
+ if (enhancedItem && enhancedItem.hidden) return [];
315
+ return [
316
+ {
317
+ ...enhancedItem,
318
+ path
319
+ },
320
+ ...getAllMenuTextsAndHandlers(enhancedItem.submenu, enhancers, context, [
321
+ ...path,
322
+ enhancedItem.text
323
+ ])
324
+ ];
325
+ });
326
+ }
327
+
328
+ const filterMenuItems = (searchVal, items) => {
329
+ const newItems = flatMap(items, item => {
330
+ const {
331
+ text,
332
+ onClick,
333
+ hidden,
334
+ hideFromMenuSearch,
335
+ hiddenButSearchableText,
336
+ showInSearchMenu,
337
+ component
338
+ } = item;
339
+
340
+ if (
341
+ !showInSearchMenu &&
342
+ !component &&
343
+ (!text || !onClick || !searchVal || hideFromMenuSearch || hidden)
344
+ ) {
345
+ return [];
346
+ }
347
+ //fix this to use some smart regex
348
+ let justText = text;
349
+ let isSimpleText = true;
350
+ if (!text.toLowerCase) {
351
+ if (text.props) {
352
+ isSimpleText = false;
353
+ justText = getStringFromReactComponent(text);
354
+ } else {
355
+ return [];
356
+ }
357
+ }
358
+
359
+ if (
360
+ doesSearchValMatchText(
361
+ searchVal,
362
+ hiddenButSearchableText
363
+ ? `${justText} ${hiddenButSearchableText}`
364
+ : justText
365
+ )
366
+ ) {
367
+ return {
368
+ ...item,
369
+ justText,
370
+ isSimpleText
371
+ };
372
+ } else {
373
+ return [];
374
+ }
375
+ }).sort((a, b) => a.justText.length - b.justText.length);
376
+
377
+ return take(newItems, 10).map(i => ({
378
+ ...i,
379
+ justText: highlight(searchVal, i.justText)
380
+ }));
381
+ };
382
+
383
+ const menuSearchHotkey = "meta+/";
384
+
385
+ function highlight(query, text, opts) {
386
+ opts = opts || { tag: <strong /> };
387
+
388
+ if (query.length === 0) {
389
+ return text;
390
+ }
391
+
392
+ const offset = text.toLowerCase().indexOf(query[0].toLowerCase());
393
+ if (offset === -1) return text;
394
+
395
+ let last = 0;
396
+ for (let i = 1; i < query.length; i++) {
397
+ if (text[offset + i] !== query[i]) {
398
+ break;
399
+ }
400
+
401
+ last = i;
402
+ }
403
+
404
+ const before = text.slice(0, offset);
405
+ const match = <strong>{text.slice(offset, offset + last + 1)}</strong>;
406
+
407
+ const after = highlight(
408
+ query.slice(last + 1),
409
+ text.slice(offset + last + 1),
410
+ opts
411
+ );
412
+
413
+ return flatten([before, match, after]);
414
+ }
415
+
416
+ 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,40 @@
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 (
36
+ <Prompt when={when} message={message} />
37
+ );
38
+ }
39
+
40
+ export default PromptUnsavedChanges;
@@ -0,0 +1,138 @@
1
+ import React from "react";
2
+ import { Dialog, Classes } from "@blueprintjs/core";
3
+ import { Rnd } from "react-rnd";
4
+ import "./style.css";
5
+
6
+ const defaultDialogWidth = 400;
7
+ const defaultDialogHeight = 100;
8
+ export default class ResizableDraggableDialog extends React.Component {
9
+ componentDidMount() {
10
+ window.addEventListener("resize", this.onWindowResize);
11
+ this.setDefaults();
12
+ setTimeout(() => {
13
+ this.setDefaults();
14
+ try {
15
+ const el = this.containerEl.querySelector(".bp3-dialog-body");
16
+ this.resizeObs = new ResizeObserver(() => {
17
+ this.setDefaults({ doNotSetXOrWidth: true });
18
+ });
19
+ this.resizeObs.observe(el);
20
+ } catch (e) {
21
+ console.warn(
22
+ `1214124599 Error setting up resize observer on dialog :`,
23
+ e
24
+ );
25
+ }
26
+ }, 0);
27
+ }
28
+ state = {
29
+ x: 0,
30
+ y: 0,
31
+ width: defaultDialogWidth,
32
+ height: defaultDialogHeight
33
+ };
34
+
35
+ setDefaults = ({ doNotSetXOrWidth } = {}) => {
36
+ const { width, height } = this.props;
37
+ const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();
38
+
39
+ let heightToUse;
40
+ if (height) {
41
+ heightToUse = height;
42
+ } else {
43
+ heightToUse = (document.querySelector(".bp3-dialog-body") || {})
44
+ .scrollHeight;
45
+ if (heightToUse) {
46
+ heightToUse = heightToUse + 60;
47
+ } else {
48
+ heightToUse = defaultDialogHeight;
49
+ }
50
+ }
51
+ let widthToUse;
52
+ if (width) {
53
+ widthToUse = width;
54
+ } else {
55
+ widthToUse = defaultDialogWidth;
56
+ }
57
+
58
+ this.setState({
59
+ ...(doNotSetXOrWidth
60
+ ? {}
61
+ : {
62
+ x: Math.round(Math.max((windowWidth - widthToUse) / 2, 0)),
63
+ width: Math.min(widthToUse, windowWidth)
64
+ }),
65
+ y: Math.round(Math.max((windowHeight - heightToUse) / 2, 0)),
66
+ height: Math.min(Math.max(defaultDialogHeight, heightToUse), windowHeight)
67
+ });
68
+ };
69
+ onWindowResize = () => {
70
+ this.setDefaults();
71
+ };
72
+ componentWillUnmount() {
73
+ this.resizeObs && this.resizeObs.disconnect();
74
+ window.removeEventListener("resize", this.onWindowResize);
75
+ }
76
+
77
+ getWindowWidthAndHeight = () => {
78
+ const w = window,
79
+ d = document,
80
+ e = d.documentElement,
81
+ g = d.getElementsByTagName("body")[0],
82
+ windowWidth = w.innerWidth || e.clientWidth || g.clientWidth,
83
+ windowHeight = w.innerHeight || e.clientHeight || g.clientHeight;
84
+ return {
85
+ windowWidth,
86
+ windowHeight: windowHeight - 20 //add a small correction here
87
+ };
88
+ };
89
+
90
+ render() {
91
+ const { width, height, RndProps, ...rest } = this.props;
92
+ const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();
93
+ return (
94
+ <div
95
+ ref={el => {
96
+ if (el) this.containerEl = el;
97
+ }}
98
+ className="tg-bp3-dialog-resizable-draggable"
99
+ style={{ top: 0, left: 0, position: "fixed" }}
100
+ >
101
+ <Rnd
102
+ cancel=".bp3-dialog-close-button"
103
+ enableResizing={{
104
+ bottomLeft: true,
105
+ bottomRight: true,
106
+ topLeft: true,
107
+ topRight: true
108
+ }}
109
+ maxHeight={windowHeight}
110
+ maxWidth={windowWidth}
111
+ bounds="window"
112
+ size={{ width: this.state.width, height: this.state.height }}
113
+ position={{ x: this.state.x, y: this.state.y }}
114
+ onDragStop={(e, d) => {
115
+ this.setState({ x: d.x, y: d.y });
116
+ }}
117
+ onResizeStop={(e, direction, ref, delta, position) => {
118
+ this.setState({
119
+ width: ref.style.width,
120
+ height: ref.style.height,
121
+ ...position
122
+ });
123
+ }}
124
+ dragHandleClassName={Classes.DIALOG_HEADER}
125
+ {...RndProps}
126
+ >
127
+ <Dialog
128
+ enforceFocus={false}
129
+ hasBackdrop={false}
130
+ usePortal={false}
131
+ canEscapeKeyClose={true}
132
+ {...rest}
133
+ />
134
+ </Rnd>
135
+ </div>
136
+ );
137
+ }
138
+ }
@@ -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
+ }