@teselagen/ui 0.7.33-beta.6 → 0.7.33

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 (114) hide show
  1. package/AdvancedOptions.js +33 -0
  2. package/AssignDefaultsModeContext.js +22 -0
  3. package/CellDragHandle.js +132 -0
  4. package/ColumnFilterMenu.js +62 -0
  5. package/Columns.js +979 -0
  6. package/DataTable/utils/queryParams.d.ts +14 -7
  7. package/DisabledLoadingComponent.js +15 -0
  8. package/DisplayOptions.js +199 -0
  9. package/DropdownButton.js +36 -0
  10. package/DropdownCell.js +61 -0
  11. package/EditableCell.js +44 -0
  12. package/FillWindow.css +6 -0
  13. package/FillWindow.js +69 -0
  14. package/FilterAndSortMenu.js +391 -0
  15. package/FormSeparator.js +9 -0
  16. package/LoadingDots.js +14 -0
  17. package/MatchHeaders.js +234 -0
  18. package/PagingTool.js +225 -0
  19. package/RenderCell.js +191 -0
  20. package/SearchBar.js +69 -0
  21. package/SimpleStepViz.js +22 -0
  22. package/SortableColumns.js +100 -0
  23. package/TableFormTrackerContext.js +10 -0
  24. package/Tag.js +112 -0
  25. package/ThComponent.js +44 -0
  26. package/TimelineEvent.js +31 -0
  27. package/UploadCsvWizard.css +4 -0
  28. package/UploadCsvWizard.js +719 -0
  29. package/Uploader.js +1278 -0
  30. package/adHoc.js +10 -0
  31. package/autoTooltip.js +201 -0
  32. package/basicHandleActionsWithFullState.js +14 -0
  33. package/browserUtils.js +3 -0
  34. package/combineReducersWithFullState.js +14 -0
  35. package/commandControls.js +82 -0
  36. package/commandUtils.js +112 -0
  37. package/constants.js +1 -0
  38. package/convertSchema.js +69 -0
  39. package/customIcons.js +361 -0
  40. package/dataTableEnhancer.js +41 -0
  41. package/defaultFormatters.js +32 -0
  42. package/defaultValidators.js +40 -0
  43. package/determineBlackOrWhiteTextColor.js +4 -0
  44. package/editCellHelper.js +44 -0
  45. package/formatPasteData.js +16 -0
  46. package/getAllRows.js +11 -0
  47. package/getCellCopyText.js +7 -0
  48. package/getCellInfo.js +36 -0
  49. package/getCellVal.js +20 -0
  50. package/getDayjsFormatter.js +35 -0
  51. package/getFieldPathToField.js +7 -0
  52. package/getIdOrCodeOrIndex.js +9 -0
  53. package/getLastSelectedEntity.js +11 -0
  54. package/getNewEntToSelect.js +25 -0
  55. package/getNewName.js +31 -0
  56. package/getRowCopyText.js +28 -0
  57. package/getTableConfigFromStorage.js +5 -0
  58. package/getTextFromEl.js +28 -0
  59. package/getVals.js +8 -0
  60. package/handleCopyColumn.js +21 -0
  61. package/handleCopyHelper.js +15 -0
  62. package/handleCopyRows.js +23 -0
  63. package/handleCopyTable.js +16 -0
  64. package/handlerHelpers.js +24 -0
  65. package/hotkeyUtils.js +131 -0
  66. package/index.cjs.js +972 -837
  67. package/index.d.ts +0 -1
  68. package/index.es.js +972 -837
  69. package/index.js +196 -0
  70. package/isBeingCalledExcessively.js +31 -0
  71. package/isBottomRightCornerOfRectangle.js +20 -0
  72. package/isEntityClean.js +15 -0
  73. package/isTruthy.js +12 -0
  74. package/isValueEmpty.js +3 -0
  75. package/itemUpload.js +84 -0
  76. package/menuUtils.js +433 -0
  77. package/package.json +1 -2
  78. package/popoverOverflowModifiers.js +11 -0
  79. package/primarySelectedValue.js +1 -0
  80. package/pureNoFunc.js +31 -0
  81. package/queryParams.js +1058 -0
  82. package/removeCleanRows.js +22 -0
  83. package/renderOnDoc.js +32 -0
  84. package/rerenderOnWindowResize.js +26 -0
  85. package/rowClick.js +181 -0
  86. package/selection.js +8 -0
  87. package/showAppSpinner.js +12 -0
  88. package/showDialogOnDocBody.js +33 -0
  89. package/showProgressToast.js +22 -0
  90. package/sortify.js +73 -0
  91. package/style.css +29 -0
  92. package/tagUtils.js +45 -0
  93. package/tgFormValues.js +35 -0
  94. package/tg_modalState.js +47 -0
  95. package/throwFormError.js +16 -0
  96. package/toastr.js +148 -0
  97. package/tryToMatchSchemas.js +264 -0
  98. package/typeToCommonType.js +6 -0
  99. package/useDeepEqualMemo.js +15 -0
  100. package/useDialog.js +63 -0
  101. package/useStableReference.js +9 -0
  102. package/useTableEntities.js +38 -0
  103. package/useTraceUpdate.js +19 -0
  104. package/utils.js +37 -0
  105. package/validateTableWideErrors.js +160 -0
  106. package/viewColumn.js +97 -0
  107. package/withField.js +20 -0
  108. package/withFields.js +11 -0
  109. package/withLocalStorage.js +11 -0
  110. package/withSelectTableRecords.js +43 -0
  111. package/withSelectedEntities.js +65 -0
  112. package/withStore.js +10 -0
  113. package/withTableParams.js +301 -0
  114. package/wrapDialog.js +116 -0
package/menuUtils.js ADDED
@@ -0,0 +1,433 @@
1
+ import React from "react";
2
+ import { lifecycle, compose, branch } from "recompose";
3
+ import { withRouter, Link } from "react-router-dom";
4
+ import {
5
+ MenuItem,
6
+ MenuDivider,
7
+ Tooltip,
8
+ KeyCombo,
9
+ ContextMenu,
10
+ Menu,
11
+ Classes,
12
+ Icon
13
+ } from "@blueprintjs/core";
14
+ import {
15
+ startCase,
16
+ omit,
17
+ isNumber,
18
+ flatMap,
19
+ isArray,
20
+ isString,
21
+ noop
22
+ } from "lodash-es";
23
+ import fuzzysearch from "fuzzysearch";
24
+ import classNames from "classnames";
25
+ // https://github.com/palantir/blueprint/issues/2820
26
+ export function MenuItemLink({ text, onClick, icon, navTo, active, disabled }) {
27
+ if (disabled) {
28
+ return (
29
+ <li className={Classes.POPOVER_DISMISS}>
30
+ <MenuItem icon={icon} disabled={true} text={text} />
31
+ </li>
32
+ );
33
+ }
34
+ const handleLinkClick = e => {
35
+ e.target.closest(`.${Classes.POPOVER_DISMISS}`).click();
36
+ };
37
+
38
+ return (
39
+ <li className={Classes.POPOVER_DISMISS} onClick={onClick}>
40
+ <Link
41
+ onClick={handleLinkClick}
42
+ to={navTo}
43
+ className={classNames(Classes.MENU_ITEM, {
44
+ [Classes.ACTIVE]: active,
45
+ [Classes.INTENT_PRIMARY]: active
46
+ })}
47
+ >
48
+ {icon && <Icon icon={icon} />}
49
+ <div className="bp3-text-overflow-ellipsis bp3-fill">{text}</div>
50
+ </Link>
51
+ </li>
52
+ );
53
+ }
54
+
55
+ // Enhanced MenuItem that supports history-based navigation when passed a
56
+ // `navTo` prop
57
+ export const EnhancedMenuItem = compose(
58
+ lifecycle({
59
+ componentDidMount: function () {
60
+ const { didMount = noop, className } = this.props;
61
+ didMount({ className });
62
+ },
63
+ componentWillUnmount: function () {
64
+ const { willUnmount = noop, className } = this.props;
65
+ willUnmount({ className });
66
+ }
67
+ }),
68
+ branch(({ navTo }) => navTo, withRouter)
69
+ )(function ({
70
+ navTo,
71
+ context,
72
+ staticContext,
73
+ didMount,
74
+ willUnmount,
75
+ ...props
76
+ }) {
77
+ let MenuItemComp = MenuItem;
78
+ if (navTo) {
79
+ MenuItemComp = MenuItemLink;
80
+ }
81
+ return (
82
+ <MenuItemComp
83
+ popoverProps={{
84
+ autoFocus: false
85
+ }}
86
+ {...(navTo && { navTo })}
87
+ {...props}
88
+ onClick={
89
+ props.onClick
90
+ ? (...args) => {
91
+ return props.onClick(...args, context);
92
+ }
93
+ : undefined
94
+ }
95
+ />
96
+ );
97
+ });
98
+
99
+ // First Non-Undefined
100
+ function fnu(...args) {
101
+ return args.find(v => v !== undefined);
102
+ }
103
+
104
+ // Sets a tick icon if items has a `checked` prop
105
+ export const tickMenuEnhancer = def => {
106
+ const out = { ...def };
107
+ if (out.checked !== undefined) {
108
+ out.icon = out.checked ? "small-tick" : "blank";
109
+ }
110
+ return out;
111
+ };
112
+
113
+ // Derives various menu item props based on command objects matched via the `cmd`
114
+ // prop. Derived props include `text`, `icon`, `hotkey`, `onClick` and `disabled`.
115
+ export const commandMenuEnhancer =
116
+ (commands, config = {}) =>
117
+ (def, context) => {
118
+ const cmdId = typeof def === "string" ? def : def.cmd;
119
+ let item = typeof def === "string" ? { cmd: def } : { ...def };
120
+
121
+ const useTicks = fnu(item.useTicks, config.useTicks);
122
+ delete item.useTicks;
123
+
124
+ if (cmdId && commands[cmdId] && def.divider === undefined) {
125
+ const command = commands[cmdId];
126
+
127
+ const { isActive, isDisabled, isHidden } = command;
128
+ const toggles = isActive !== undefined;
129
+
130
+ item.hidden = fnu(item.hidden, isHidden);
131
+ item.disabled = fnu(item.disabled, isDisabled);
132
+
133
+ item.key = item.key || cmdId;
134
+ item.submenu = item.submenu || command.submenu;
135
+ item.component = item.component || command.component;
136
+
137
+ if (toggles) {
138
+ if (useTicks) {
139
+ item.text = item.text || command.shortName || command.name;
140
+ item.checked = item.checked || isActive;
141
+ } else {
142
+ item.text =
143
+ item.text ||
144
+ (isActive ? command.name : command.inactiveName || command.name);
145
+ item.icon =
146
+ item.icon ||
147
+ (isActive ? command.icon : command.inactiveIcon || command.icon);
148
+ }
149
+ } else {
150
+ item.text = item.text || command.name;
151
+ item.icon = item.icon || command.icon;
152
+ }
153
+
154
+ item.hotkey = item.hotkey || command.hotkey;
155
+ if (!item.onClick) {
156
+ item.onClick = event =>
157
+ command.execute({
158
+ event,
159
+ context,
160
+ menuItem: item,
161
+ viaMenu: true
162
+ });
163
+ }
164
+ } else if (cmdId && !commands[cmdId]) {
165
+ item.text = item.text || startCase(cmdId);
166
+ item.disabled = true;
167
+ }
168
+
169
+ if (config.omitIcons) {
170
+ item.icon = undefined;
171
+ }
172
+
173
+ if (config.forceIconAlignment !== false) {
174
+ item.icon = item.icon || "blank";
175
+ }
176
+
177
+ if (useTicks) {
178
+ item = tickMenuEnhancer(item);
179
+ }
180
+
181
+ return item;
182
+ };
183
+
184
+ const ident = x => x;
185
+
186
+ const dividerShorthandEnhancer = def =>
187
+ typeof def === "string" && def.startsWith("--")
188
+ ? { divider: def.substr(2) }
189
+ : def;
190
+
191
+ // filter out unwanted attributes here! we won't want these to show up on the dom element or react will give nasty warnings
192
+ const unwantedAttrs = [
193
+ "isSimpleText",
194
+ "justText",
195
+ "submenu",
196
+ "component",
197
+ "hotkey",
198
+ "changingProps",
199
+ "showInSearchMenu",
200
+ "hideFromMenuSearch"
201
+ ];
202
+
203
+ /** A menu item component that adds many features over the standard MenuItem,
204
+ * and allows for dynamic menu structures that are computed efficiently (only
205
+ * visible sections are computed and rendered).
206
+ * TODO: document and add examples
207
+ */
208
+ export const DynamicMenuItem = ({
209
+ def,
210
+ enhancers = [ident],
211
+ context,
212
+ doNotEnhanceTopLevelItem
213
+ }) => {
214
+ // If passed an element instead of a menu item definition, return it.
215
+ // This allows mixing menu item elements and menu item defs, and makes it
216
+ // safe to call menu creation utils with their own output.
217
+ if (React.isValidElement(def)) return def;
218
+
219
+ const item = [
220
+ dividerShorthandEnhancer,
221
+ ...(doNotEnhanceTopLevelItem ? [ident] : enhancers)
222
+ ].reduce((v, f) => f(v, context), def);
223
+ let out;
224
+ if (item.divider !== undefined) {
225
+ out = (
226
+ <MenuDivider
227
+ {...(item.divider
228
+ ? { title: item.divider, className: item.className }
229
+ : {})}
230
+ />
231
+ );
232
+ } else {
233
+ const ItemComponent = item.component || EnhancedMenuItem;
234
+ out = (
235
+ <ItemComponent
236
+ // filter out unwanted attributes here!
237
+ {...omit(item, unwantedAttrs)}
238
+ context={context}
239
+ icon={item.icon || item.iconName}
240
+ labelElement={item.hotkey && <KeyCombo minimal combo={item.hotkey} />}
241
+ text={item.text}
242
+ >
243
+ {item.submenu
244
+ ? item.submenu
245
+ .filter(ident)
246
+ .map((def, index) => (
247
+ <DynamicMenuItem key={index} {...{ def, enhancers, context }} />
248
+ ))
249
+ : undefined}
250
+ </ItemComponent>
251
+ );
252
+ }
253
+ // if (item.disabled && item.disabledTooltip) {
254
+ // item.tooltip = def.disabledTooltip
255
+ // }
256
+ if (item.disabled && typeof item.disabled === "string") {
257
+ item.tooltip = item.disabled;
258
+ }
259
+
260
+ if (item.tooltip) {
261
+ out = <Tooltip content={item.tooltip}>{out}</Tooltip>;
262
+ }
263
+
264
+ return item.hidden ? null : out;
265
+ };
266
+
267
+ // Map the passed item definition(s) to DynamicMenuItem elements
268
+ export const createDynamicMenu = (menuDef, enhancers, context) => {
269
+ if (menuDef instanceof Array) {
270
+ return menuDef.map((def, index) => (
271
+ <DynamicMenuItem key={index} {...{ def, enhancers, context }} />
272
+ ));
273
+ } else {
274
+ return <DynamicMenuItem {...{ def: menuDef, enhancers, context }} />;
275
+ }
276
+ };
277
+
278
+ // Create a "bar" menu, keeping the top level array unchanged, and only
279
+ // map their submenus to DynamicMenuItem elements
280
+ export const createDynamicBarMenu = (topMenuDef, enhancers, context) => {
281
+ return topMenuDef.map(topLevelItem => {
282
+ const def = { ...topLevelItem };
283
+ if (def.submenu) {
284
+ def.submenu = def.submenu.map((subdef, index) => (
285
+ <DynamicMenuItem key={index} def={subdef} {...{ enhancers, context }} />
286
+ ));
287
+ }
288
+ return def;
289
+ });
290
+ };
291
+
292
+ // Shorthand for command-based menus
293
+ export const createCommandMenu = (menuDef, commands, config, context) => {
294
+ return createDynamicMenu(
295
+ menuDef,
296
+ [commandMenuEnhancer(commands, config)],
297
+ context
298
+ );
299
+ };
300
+
301
+ // Shorthand for command-based bar menus
302
+ export const createCommandBarMenu = (menuDef, commands, config, context) => {
303
+ return createDynamicBarMenu(
304
+ menuDef,
305
+ [commandMenuEnhancer(commands, config)],
306
+ context
307
+ );
308
+ };
309
+
310
+ export function showCommandContextMenu(
311
+ menuDef,
312
+ commands,
313
+ config,
314
+ event,
315
+ onClose,
316
+ context
317
+ ) {
318
+ return showContextMenu(
319
+ menuDef,
320
+ [commandMenuEnhancer(commands, config)],
321
+ event,
322
+ onClose,
323
+ context
324
+ );
325
+ }
326
+
327
+ /**
328
+ * TODO: update documentation. This is now an alias of createDynamicMenu
329
+ *
330
+ * Creates the contents of a Blueprint menu based on a given menu structure.
331
+ *
332
+ * The input can be an array of item objects, where each may contain:
333
+ * text: text to show
334
+ * key: React key to use (optional)
335
+ * divider: indicates it's a divider instead of an item. Use an empty string
336
+ * for a normal divider, or some label text for a labeled one
337
+ * icon: name of icon to show (optional)
338
+ * label: right-aligned label, used mostly for shortcuts (optional)
339
+ * hotkey: right-aligned label formatted with <KeyCombo> (optional)
340
+ * tooltip: tooltip text to use (optional)
341
+ * submenu: nested menu structure describing submenu (i.e. array of item objects),
342
+ * or array of MenuItem elements
343
+ * onClick: click handler
344
+ * navTo: a url to navigate to (assumes react-router)
345
+ * href: a url to link to
346
+ * target: link target
347
+ *
348
+ * Since this function is recursive (to handle nested submenus), and React
349
+ * elements passed as input are returned unchanged, it is possible to freely mix
350
+ * item objects and MenuItem elements. That also makes it safe to call the function
351
+ * with its own output.
352
+ *
353
+ * A customize function may also be provided, and allows customization or
354
+ * replacement of the created MenuItems, allowing for custom props or behavior.
355
+ * That function receives the original created element and the item object, and
356
+ * must return an element.
357
+ *
358
+ * Usage example:
359
+ *
360
+ * const menu = createMenu([
361
+ * { text: 'Item One', icon: 'add', onClick: () => console.info('Clicked 1') },
362
+ * { text: 'Item One', onClick: () => console.info('Clicked 2') },
363
+ * { divider: '' },
364
+ * { text: 'Item Three', icon: 'numerical', onClick: () => console.info('Clicked 3') },
365
+ * { divider: '' },
366
+ * { text: 'Submenus', submenu: [
367
+ * { text: 'Sub One' },
368
+ * { text: 'Sub Two' },
369
+ * ]},
370
+ * ]);
371
+ *
372
+ */
373
+ export const createMenu = createDynamicMenu;
374
+
375
+ export function showContextMenu(
376
+ menuDef,
377
+ enhancers,
378
+ event,
379
+ onClose,
380
+ context,
381
+ menuComp = Menu
382
+ ) {
383
+ menuDef = filterMenuForCorrectness(menuDef);
384
+ if (!menuDef) return;
385
+
386
+ const MenuComponent = menuComp;
387
+ event.persist && event.persist();
388
+ // Render a context menu at the passed event's position
389
+ ContextMenu.show(
390
+ <MenuComponent>
391
+ {createDynamicMenu(menuDef, enhancers, context)}
392
+ </MenuComponent>,
393
+ { left: event.clientX, top: event.clientY },
394
+ onClose
395
+ );
396
+ event.stopPropagation && event.stopPropagation();
397
+ event.preventDefault && event.preventDefault();
398
+ }
399
+
400
+ function filterMenuForCorrectness(menuDef) {
401
+ return menuDef && menuDef.length && menuDef.filter(ident);
402
+ }
403
+
404
+ export function getStringFromReactComponent(comp) {
405
+ if (!comp) return "";
406
+ if (isString(comp) || isNumber(comp)) return comp;
407
+ if (comp.props?.text) {
408
+ return getStringFromReactComponent(comp.props.text);
409
+ }
410
+ const { children } = comp.props || {};
411
+ if (!children) return "";
412
+ if (isArray(children))
413
+ return flatMap(children, getStringFromReactComponent).join("");
414
+ if (isString(children)) return children;
415
+
416
+ if (children.props) {
417
+ return getStringFromReactComponent(children.props);
418
+ }
419
+ }
420
+ export function doesSearchValMatchText(searchVal, justText) {
421
+ return fuzzysearch(
422
+ searchVal ? searchVal.toLowerCase() : "",
423
+ justText ? justText.toLowerCase() : ""
424
+ );
425
+ }
426
+
427
+ export const MenuItemWithTooltip = ({ tooltip, ...rest }) => {
428
+ let out = <MenuItem {...rest}></MenuItem>;
429
+ if (tooltip) {
430
+ out = <Tooltip content={tooltip}>{out}</Tooltip>;
431
+ }
432
+ return out;
433
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ui",
3
- "version": "0.7.33-beta.6",
3
+ "version": "0.7.33",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,7 +17,6 @@
17
17
  "@dnd-kit/core": "^6.1.0",
18
18
  "@dnd-kit/modifiers": "^7.0.0",
19
19
  "@dnd-kit/sortable": "^8.0.0",
20
- "@teselagen/react-table": "6.10.16",
21
20
  "classnames": "^2.3.2",
22
21
  "color": "^3.2.1",
23
22
  "copy-to-clipboard": "^3.3.1",
@@ -0,0 +1,11 @@
1
+ // will help tooltip to not get smushed
2
+ const popoverOverflowModifiers = {
3
+ preventOverflow: { boundariesElement: "viewport" },
4
+ hide: {
5
+ enabled: false
6
+ },
7
+ flip: {
8
+ boundariesElement: "viewport"
9
+ }
10
+ };
11
+ export default popoverOverflowModifiers;
@@ -0,0 +1 @@
1
+ export const PRIMARY_SELECTED_VAL = "main_cell";
package/pureNoFunc.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * This HOC compares props to create a pure component that will only update
3
+ * when props are not deep equal. It will compare the string values of functions
4
+ */
5
+ import { shouldUpdate } from "recompose";
6
+ import { isEqualWith, isFunction } from "lodash-es";
7
+
8
+ /**
9
+ * tgreen: This is an awful function which we should come up with a better solution for
10
+ * @param {*} o1
11
+ * @param {*} o2
12
+ */
13
+ const isEq = (o1, o2) => {
14
+ const isEq = isEqualWith(o1, o2, function (val1, val2) {
15
+ if (isFunction(val1) && isFunction(val2)) {
16
+ return val1 === val2 || val1.toString() === val2.toString();
17
+ }
18
+ // tgreen: we were seeing an issue where the isEq would infinite loop on react children
19
+ // components. We decided to just ignore them (assume they are equal)
20
+ if (val1 && val1.constructor && val1.constructor.name === "FiberNode")
21
+ return true;
22
+ });
23
+ return isEq;
24
+ };
25
+
26
+ const pure = BaseComponent => {
27
+ const hoc = shouldUpdate((props, nextProps) => !isEq(props, nextProps));
28
+ return hoc(BaseComponent);
29
+ };
30
+
31
+ export default pure;