@vuu-ui/vuu-utils 2.1.19-beta.1 → 2.1.19-beta.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 (82) hide show
  1. package/package.json +8 -9
  2. package/src/Clock.js +43 -0
  3. package/src/PageVisibilityObserver.js +42 -0
  4. package/src/ScaledDecimal.js +32 -0
  5. package/src/ShellContext.js +5 -0
  6. package/src/ThemeProvider.js +56 -0
  7. package/src/array-utils.js +51 -0
  8. package/src/box-utils.js +51 -0
  9. package/src/broadcast-channel.js +0 -0
  10. package/src/column-utils.js +790 -0
  11. package/src/common-types.js +11 -0
  12. package/src/component-registry.js +83 -0
  13. package/src/context-definitions/DataContext.js +15 -0
  14. package/src/context-definitions/DataProvider.js +13 -0
  15. package/src/context-definitions/DataSourceProvider.js +18 -0
  16. package/src/context-definitions/WorkspaceContext.js +14 -0
  17. package/src/cookie-utils.js +15 -0
  18. package/src/css-utils.js +5 -0
  19. package/src/data-editing/DataEditingProvider.js +13 -0
  20. package/src/data-editing/EditButtons.js +32 -0
  21. package/src/data-editing/EditModeProvider.js +18 -0
  22. package/src/data-editing/EditSession.js +149 -0
  23. package/src/data-editing/edit-utils.js +37 -0
  24. package/src/data-editing/useEditableTable.js +76 -0
  25. package/src/data-utils.js +55 -0
  26. package/src/datasource/BaseDataSource.js +233 -0
  27. package/src/datasource/datasource-action-utils.js +6 -0
  28. package/src/datasource/datasource-filter-utils.js +27 -0
  29. package/src/datasource/datasource-utils.js +148 -0
  30. package/src/date/date-utils.js +80 -0
  31. package/src/date/dateTimePattern.js +17 -0
  32. package/src/date/formatter.js +101 -0
  33. package/src/date/index.js +4 -0
  34. package/src/date/types.js +27 -0
  35. package/src/debug-utils.js +25 -0
  36. package/src/event-emitter.js +78 -0
  37. package/src/feature-utils.js +86 -0
  38. package/src/filters/filter-utils.js +136 -0
  39. package/src/filters/filterAsQuery.js +70 -0
  40. package/src/filters/index.js +2 -0
  41. package/src/form-utils.js +69 -0
  42. package/src/formatting-utils.js +42 -0
  43. package/src/getUniqueId.js +2 -0
  44. package/src/group-utils.js +16 -0
  45. package/src/html-utils.js +108 -0
  46. package/src/index.js +77 -0
  47. package/src/input-utils.js +3 -0
  48. package/src/invariant.js +9 -0
  49. package/src/itemToString.js +9 -0
  50. package/src/json-types.js +0 -0
  51. package/src/json-utils.js +108 -0
  52. package/src/keyboard-utils.js +14 -0
  53. package/src/keyset.js +57 -0
  54. package/src/layout-types.js +0 -0
  55. package/src/list-utils.js +5 -0
  56. package/src/local-storage-utils.js +23 -0
  57. package/src/logging-utils.js +52 -0
  58. package/src/module-utils.js +2 -0
  59. package/src/nanoid/index.js +13 -0
  60. package/src/perf-utils.js +28 -0
  61. package/src/promise-utils.js +26 -0
  62. package/src/protocol-message-utils.js +68 -0
  63. package/src/range-utils.js +109 -0
  64. package/src/react-utils.js +64 -0
  65. package/src/round-decimal.js +83 -0
  66. package/src/row-utils.js +43 -0
  67. package/src/selection-utils.js +25 -0
  68. package/src/shell-layout-types.js +9 -0
  69. package/src/sort-utils.js +75 -0
  70. package/src/table-schema-utils.js +11 -0
  71. package/src/text-utils.js +13 -0
  72. package/src/theme-utils.js +21 -0
  73. package/src/tree-types.js +0 -0
  74. package/src/tree-utils.js +96 -0
  75. package/src/ts-utils.js +6 -0
  76. package/src/typeahead-utils.js +4 -0
  77. package/src/url-utils.js +12 -0
  78. package/src/useId.js +6 -0
  79. package/src/useLayoutEffectSkipFirst.js +9 -0
  80. package/src/useResizeObserver.js +122 -0
  81. package/src/useStateRef.js +21 -0
  82. package/src/user-types.js +0 -0
@@ -0,0 +1,64 @@
1
+ import { Children, isValidElement, useEffect, useMemo, useRef } from "react";
2
+ const EMPTY_ARRAY = [];
3
+ const asReactElements = (children)=>{
4
+ const isArray = Array.isArray(children);
5
+ const count = isArray ? children.length : Children.count(children);
6
+ if (isArray && children.every(isValidElement)) return children;
7
+ if (1 === count && !isArray && isValidElement(children)) return [
8
+ children
9
+ ];
10
+ if (count > 1) return children;
11
+ return EMPTY_ARRAY;
12
+ };
13
+ const useIsMounted = (id = "")=>{
14
+ const isMountedRef = useRef(false);
15
+ useEffect(()=>{
16
+ console.log(`is MOUNTED ${id}`);
17
+ isMountedRef.current = true;
18
+ return ()=>{
19
+ console.log(`is UNMOUNTED ${id}`);
20
+ isMountedRef.current = false;
21
+ };
22
+ }, [
23
+ id
24
+ ]);
25
+ return isMountedRef;
26
+ };
27
+ const isSimpleStateValue = (arg)=>"function" != typeof arg;
28
+ const createSyntheticEvent = (event)=>{
29
+ let isDefaultPrevented = false;
30
+ let isPropagationStopped = false;
31
+ const preventDefault = ()=>{
32
+ isDefaultPrevented = true;
33
+ event.preventDefault();
34
+ };
35
+ const stopPropagation = ()=>{
36
+ isPropagationStopped = true;
37
+ event.stopPropagation();
38
+ };
39
+ return {
40
+ nativeEvent: event,
41
+ currentTarget: event.currentTarget,
42
+ target: event.target,
43
+ bubbles: event.bubbles,
44
+ cancelable: event.cancelable,
45
+ defaultPrevented: event.defaultPrevented,
46
+ eventPhase: event.eventPhase,
47
+ isTrusted: event.isTrusted,
48
+ preventDefault,
49
+ isDefaultPrevented: ()=>isDefaultPrevented,
50
+ stopPropagation,
51
+ isPropagationStopped: ()=>isPropagationStopped,
52
+ persist: ()=>void 0,
53
+ timeStamp: event.timeStamp,
54
+ type: event.type
55
+ };
56
+ };
57
+ const useStableReference = (value)=>{
58
+ const referenceToProp = useRef(value);
59
+ useMemo(()=>referenceToProp.current = value, [
60
+ value
61
+ ]);
62
+ return referenceToProp;
63
+ };
64
+ export { asReactElements, createSyntheticEvent, isSimpleStateValue, useIsMounted, useStableReference };
@@ -0,0 +1,83 @@
1
+ const PUNCTUATION_STR = String.fromCharCode(8200);
2
+ const DIGIT_STR = String.fromCharCode(8199);
3
+ const DECIMALS_AUTO = -1;
4
+ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER.toString();
5
+ const MAX_INTEGER_DIGITS = MAX_SAFE_INTEGER.length;
6
+ const exceedsMaxSafeInteger = (value)=>value.length > MAX_INTEGER_DIGITS || value.length === MAX_INTEGER_DIGITS && value > MAX_SAFE_INTEGER;
7
+ const Space = {
8
+ DIGIT: DIGIT_STR,
9
+ TWO_DIGITS: DIGIT_STR + DIGIT_STR,
10
+ THREE_DIGITS: DIGIT_STR + DIGIT_STR + DIGIT_STR,
11
+ FULL_PADDING: [
12
+ null,
13
+ PUNCTUATION_STR + DIGIT_STR,
14
+ PUNCTUATION_STR + DIGIT_STR + DIGIT_STR,
15
+ PUNCTUATION_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR,
16
+ PUNCTUATION_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR
17
+ ]
18
+ };
19
+ const Zero = {
20
+ DIGIT: "0",
21
+ TWO_DIGITS: "00",
22
+ THREE_DIGITS: "000",
23
+ FULL_PADDING: [
24
+ null,
25
+ "0",
26
+ "00",
27
+ "000",
28
+ "0000"
29
+ ]
30
+ };
31
+ function padLeft(value, maxLength = 6) {
32
+ return (LEADING_FILL + value).slice(-maxLength);
33
+ }
34
+ const LEADING_FILL = DIGIT_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR + DIGIT_STR;
35
+ const Align = {
36
+ Right: "right",
37
+ Center: "center",
38
+ Left: "left"
39
+ };
40
+ function pad(n, dp, Pad) {
41
+ let len = n.length;
42
+ const diff = dp - len;
43
+ if (diff > 0) {
44
+ if (1 === diff) n += Pad.DIGIT;
45
+ else if (2 === diff) n += Pad.TWO_DIGITS;
46
+ else if (3 === diff) n += Pad.THREE_DIGITS;
47
+ } else {
48
+ if (diff < 0) {
49
+ n = n.slice(0, dp);
50
+ len = dp;
51
+ }
52
+ if (Pad === Space && "0" === n.charAt(len - 1)) {
53
+ n = n.replace(/0+$/, "");
54
+ return pad(n, dp, Pad);
55
+ }
56
+ }
57
+ return n;
58
+ }
59
+ function roundDecimal(value, align = Align.Right, decimals = 4, zeroPad, alignOnDecimals, useLocaleString = true, roundingRule = "round") {
60
+ if (void 0 === value || "number" != typeof value || isNaN(value)) return "";
61
+ let integral;
62
+ let fraction;
63
+ let Pad;
64
+ const [part1, part2 = ""] = value.toString().split(".");
65
+ const actualDecimals = part2.length;
66
+ integral = "-0" === part1 ? "-0" : useLocaleString ? parseFloat(part1).toLocaleString() : parseFloat(part1).toString();
67
+ if (align === Align.Left && alignOnDecimals) integral = padLeft(integral);
68
+ fraction = decimals === DECIMALS_AUTO || actualDecimals === decimals ? part2 : actualDecimals > decimals ? "round" === roundingRule ? parseFloat("0." + part2).toFixed(decimals).slice(2) : part2.slice(0, decimals) : (Pad = zeroPad ? Zero : alignOnDecimals && align !== Align.Left ? Space : null) ? 0 === actualDecimals ? Pad.FULL_PADDING[decimals] ?? "" : pad(part2, decimals, Pad) : part2;
69
+ return integral + (fraction ? "." + fraction : "");
70
+ }
71
+ function roundScaledDecimal(value, align = Align.Right, decimals = 4, zeroPad, alignOnDecimals, useLocaleString = true, roundingRule = "round") {
72
+ let integral;
73
+ let fraction;
74
+ let Pad;
75
+ if ("" === value) return "";
76
+ const [part1, part2 = ""] = value.split(".");
77
+ const actualDecimals = part2.length;
78
+ integral = "" === part1 ? "0" : "-0" === part1 ? "-0" : useLocaleString ? exceedsMaxSafeInteger(value) ? BigInt(part1).toLocaleString() : parseFloat(part1).toLocaleString() : part1;
79
+ if (align === Align.Left && alignOnDecimals) integral = padLeft(integral);
80
+ fraction = decimals === DECIMALS_AUTO || actualDecimals === decimals ? part2 : actualDecimals > decimals ? "round" === roundingRule ? parseFloat("0." + part2).toFixed(decimals).slice(2) : part2.slice(0, decimals) : (Pad = zeroPad ? Zero : alignOnDecimals && align !== Align.Left ? Space : null) ? 0 === actualDecimals ? Pad.FULL_PADDING[decimals] ?? "" : pad(part2, decimals, Pad) : part2;
81
+ return integral + (fraction ? "." + fraction : "");
82
+ }
83
+ export { exceedsMaxSafeInteger, roundDecimal, roundScaledDecimal };
@@ -0,0 +1,43 @@
1
+ import { metadataKeys } from "./column-utils.js";
2
+ const { IS_LEAF: IS_LEAF, KEY: KEY, IDX: IDX, SELECTED: SELECTED } = metadataKeys;
3
+ const actualRowPositioning = (rowHeight)=>[
4
+ (dataRow)=>dataRow.index * rowHeight,
5
+ (position)=>Math.floor(position / rowHeight),
6
+ false
7
+ ];
8
+ const virtualRowPositioning = (rowHeight, virtualisedExtent, pctScrollTop)=>[
9
+ (dataRow, offset = 0)=>{
10
+ const rowOffset = pctScrollTop.current * virtualisedExtent;
11
+ return (dataRow.index - offset) * rowHeight - rowOffset;
12
+ },
13
+ (position)=>{
14
+ const rowOffset = pctScrollTop.current * virtualisedExtent;
15
+ return Math.round((position + rowOffset) / rowHeight);
16
+ },
17
+ true
18
+ ];
19
+ const asDataSourceRowObject = (row, columnMap)=>{
20
+ const { [IS_LEAF]: isLeaf, [KEY]: key, [IDX]: index } = row;
21
+ const rowObject = {
22
+ key,
23
+ index,
24
+ isGroupRow: !isLeaf,
25
+ isSelected: 0 !== row[SELECTED],
26
+ data: {}
27
+ };
28
+ for (const [colName, colIdx] of Object.entries(columnMap))rowObject.data[colName] = row[colIdx];
29
+ return rowObject;
30
+ };
31
+ const vuuRowToDataSourceRow = ({ rowIndex, rowKey, sel: isSelected = 0, ts, data }, keys)=>[
32
+ rowIndex,
33
+ keys.keyFor(rowIndex),
34
+ true,
35
+ false,
36
+ 0,
37
+ 0,
38
+ rowKey,
39
+ isSelected,
40
+ ts,
41
+ false
42
+ ].concat(data);
43
+ export { actualRowPositioning, asDataSourceRowObject, virtualRowPositioning, vuuRowToDataSourceRow };
@@ -0,0 +1,25 @@
1
+ const deselectItem = (selectionModel, rowKey, rangeSelect, preserveExistingSelection = false)=>({
2
+ preserveExistingSelection,
3
+ rowKey,
4
+ type: "DESELECT_ROW"
5
+ });
6
+ const selectItem = (selectionModel, rowKey, rangeSelect, preserveExistingSelection = false, activeRowKey)=>{
7
+ const singleSelect = "single" === selectionModel || "single-no-deselect" === selectionModel;
8
+ const actsLikeSingleSelect = singleSelect || void 0 === activeRowKey;
9
+ if ("none" === selectionModel) return;
10
+ if (actsLikeSingleSelect) {
11
+ const preserveSelection = singleSelect ? false : preserveExistingSelection;
12
+ return {
13
+ preserveExistingSelection: preserveSelection,
14
+ rowKey,
15
+ type: "SELECT_ROW"
16
+ };
17
+ }
18
+ if (rangeSelect) return {
19
+ preserveExistingSelection,
20
+ fromRowKey: rowKey,
21
+ toRowKey: activeRowKey,
22
+ type: "SELECT_ROW_RANGE"
23
+ };
24
+ };
25
+ export { deselectItem, selectItem };
@@ -0,0 +1,9 @@
1
+ const VuuShellLocation = {
2
+ ContextPanel: "context-panel",
3
+ MultiWorkspaceContainer: "vuu-multi-workspace-container",
4
+ SidePanel: "vuu-side-panel",
5
+ SideToolbar: "vuu-side-toolbar",
6
+ Workspace: "vuu-workspace",
7
+ WorkspaceContainer: "vuu-workspace-container"
8
+ };
9
+ export { VuuShellLocation };
@@ -0,0 +1,75 @@
1
+ const cycleSortType = (sortType)=>"A" === sortType ? "D" : "D" === sortType ? void 0 : "A";
2
+ const NO_SORT = {
3
+ sortDefs: []
4
+ };
5
+ const toggleOrApplySort = ({ sortDefs }, { name: column }, extendSort = false, sortType)=>{
6
+ if (extendSort) {
7
+ const existingDef = sortDefs.find((sortDef)=>sortDef.column === column);
8
+ if (existingDef) return {
9
+ sortDefs: sortDefs.map((sortDef)=>sortDef.column === column ? {
10
+ column,
11
+ sortType: "A" === sortDef.sortType ? "D" : "A"
12
+ } : sortDef)
13
+ };
14
+ return {
15
+ sortDefs: sortDefs.concat({
16
+ column,
17
+ sortType: sortType ?? "A"
18
+ })
19
+ };
20
+ }
21
+ const newSortType = "string" == typeof sortType ? sortType : 1 === sortDefs.length && sortDefs[0].column === column ? cycleSortType(sortDefs[0].sortType) : "A";
22
+ return newSortType ? {
23
+ sortDefs: [
24
+ {
25
+ column,
26
+ sortType: newSortType
27
+ }
28
+ ]
29
+ } : NO_SORT;
30
+ };
31
+ const setSortColumn = ({ sortDefs }, column, sortType)=>{
32
+ if (void 0 === sortType) {
33
+ const columnSort = sortDefs.find((item)=>item.column === column.name);
34
+ if (columnSort) return {
35
+ sortDefs: [
36
+ {
37
+ column: column.name,
38
+ sortType: "A" === columnSort.sortType ? "D" : "A"
39
+ }
40
+ ]
41
+ };
42
+ }
43
+ return {
44
+ sortDefs: [
45
+ {
46
+ column: column.name,
47
+ sortType: sortType ?? "A"
48
+ }
49
+ ]
50
+ };
51
+ };
52
+ const addSortColumn = ({ sortDefs }, column, sortType = "A")=>{
53
+ const sortEntry = {
54
+ column: column.name,
55
+ sortType
56
+ };
57
+ if (sortDefs.length > 0) return {
58
+ sortDefs: sortDefs.concat(sortEntry)
59
+ };
60
+ return {
61
+ sortDefs: [
62
+ sortEntry
63
+ ]
64
+ };
65
+ };
66
+ const getSortStatus = (columnName, vuuSort)=>{
67
+ if (void 0 === vuuSort || 0 === vuuSort.sortDefs.length) return "no-sort";
68
+ {
69
+ const sortDef = vuuSort.sortDefs.find((sd)=>sd.column === columnName);
70
+ if (!sortDef) return "sort-other-column";
71
+ if (1 === vuuSort.sortDefs.length) return "A" === sortDef.sortType ? "single-sort-asc" : "single-sort-desc";
72
+ return "A" === sortDef.sortType ? "multi-sort-includes-column-asc" : "multi-sort-includes-column-desc";
73
+ }
74
+ };
75
+ export { addSortColumn, getSortStatus, setSortColumn, toggleOrApplySort };
@@ -0,0 +1,11 @@
1
+ const getVuuTable = (schemaTable)=>{
2
+ if (!schemaTable.session) return schemaTable;
3
+ {
4
+ const { module, session } = schemaTable;
5
+ return {
6
+ module,
7
+ table: session
8
+ };
9
+ }
10
+ };
11
+ export { getVuuTable };
@@ -0,0 +1,13 @@
1
+ const lastWord = (text)=>{
2
+ const trimmedText = text.trim();
3
+ const pos = trimmedText.lastIndexOf(" ");
4
+ if (-1 === pos) return trimmedText;
5
+ return trimmedText.slice(pos + 1);
6
+ };
7
+ const capitalize = (text)=>0 === text.length ? "" : text[0].toUpperCase() + text.slice(1);
8
+ const regexp_worfify = /(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])/;
9
+ const wordify = (text)=>{
10
+ const [firstWord, ...rest] = text.split(regexp_worfify);
11
+ return `${capitalize(firstWord)} ${rest.join(" ")}`;
12
+ };
13
+ export { lastWord, wordify };
@@ -0,0 +1,21 @@
1
+ import { useMemo, useState } from "react";
2
+ const checkCssToken = (tokenName)=>new Promise((resolve)=>{
3
+ requestAnimationFrame(()=>{
4
+ const saltSpacing100 = getComputedStyle(document.documentElement).getPropertyValue(tokenName);
5
+ resolve("" !== saltSpacing100);
6
+ });
7
+ });
8
+ const ThemeLoadChecker = ({ children, cssToken = "--salt-spacing-100", theme })=>{
9
+ const [ready, setReady] = useState(false);
10
+ useMemo(async ()=>{
11
+ let ready = await checkCssToken(cssToken);
12
+ while(!ready)ready = await checkCssToken(cssToken);
13
+ setReady(true);
14
+ }, [
15
+ cssToken
16
+ ]);
17
+ if ("no-theme" === theme) return children;
18
+ if (false === ready) return null;
19
+ return children;
20
+ };
21
+ export { ThemeLoadChecker };
File without changes
@@ -0,0 +1,96 @@
1
+ import { metadataKeys } from "./column-utils.js";
2
+ const { COUNT: COUNT, DEPTH: DEPTH, IDX: IDX, KEY: KEY } = metadataKeys;
3
+ const timestamp = 0;
4
+ const isNew = false;
5
+ const treeToDataSourceRows = (treeSourceNodes, iconProvider)=>{
6
+ const columns = [];
7
+ columns.push({
8
+ hidden: true,
9
+ name: "nodeData",
10
+ type: "json"
11
+ }, {
12
+ getIcon: iconProvider?.getIcon,
13
+ name: "Level 1",
14
+ type: "string"
15
+ }, {
16
+ getIcon: iconProvider?.getIcon,
17
+ name: "Level 2",
18
+ type: "string"
19
+ });
20
+ const rows = [];
21
+ addChildValues(rows, treeSourceNodes, columns, iconProvider);
22
+ return [
23
+ columns,
24
+ rows
25
+ ];
26
+ };
27
+ const addChildValues = (rows, treeSourceNodes, cols, iconProvider, index = {
28
+ value: 0
29
+ }, keyBase = "$root", depth = 1)=>{
30
+ let leafCount = 0;
31
+ let rowCount = 0;
32
+ if (depth === cols.length - 1) cols.push({
33
+ getIcon: iconProvider?.getIcon,
34
+ name: `Level ${cols.length}`,
35
+ type: "string"
36
+ });
37
+ for(let i = 0; i < treeSourceNodes.length; i++, index.value += 1){
38
+ const { childNodes, icon, label, nodeData } = treeSourceNodes[i];
39
+ const blanks = Array(depth - 1).fill("");
40
+ const fullKey = `${keyBase}|${label}`;
41
+ const row = [
42
+ index.value,
43
+ index.value,
44
+ false,
45
+ false,
46
+ depth,
47
+ 0,
48
+ fullKey,
49
+ 0,
50
+ timestamp,
51
+ isNew,
52
+ nodeData,
53
+ ...blanks,
54
+ label
55
+ ];
56
+ if (icon) iconProvider?.setIcon(fullKey, icon);
57
+ rows.push(row);
58
+ rowCount += 1;
59
+ if (childNodes && childNodes.length > 0) {
60
+ const [nestedLeafCount, nestedRowCount] = addChildValues(rows, childNodes, cols, iconProvider, {
61
+ value: index.value + 1
62
+ }, fullKey, depth + 1);
63
+ row[COUNT] = nestedLeafCount;
64
+ leafCount += nestedLeafCount;
65
+ rowCount += nestedRowCount;
66
+ index.value += nestedRowCount;
67
+ } else leafCount += 1;
68
+ }
69
+ return [
70
+ leafCount,
71
+ rowCount
72
+ ];
73
+ };
74
+ const lastPathSegment = (path, separator = "/")=>{
75
+ const root = path.endsWith(separator) ? path.slice(0, -1) : path;
76
+ return root.slice(root.lastIndexOf(separator) + 1);
77
+ };
78
+ const dropLastPathSegment = (path, separator = "/")=>path.slice(0, path.lastIndexOf(separator));
79
+ const getParentRow = (rows, row)=>{
80
+ const { [IDX]: idx, [DEPTH]: depth } = row;
81
+ for(let i = idx - 1; i >= 0; i--){
82
+ const nextRow = rows[i];
83
+ if (nextRow[DEPTH] === depth - 1) return nextRow;
84
+ }
85
+ };
86
+ const rowsAreSiblings = (key1, key2)=>dropLastPathSegment(key1, "|") === dropLastPathSegment(key2, "|");
87
+ const missingAncestor = (row, previousRow)=>{
88
+ if (previousRow) {
89
+ const prevKey = previousRow[KEY];
90
+ const key = row[KEY];
91
+ if (key.startsWith(prevKey)) ;
92
+ else if (!rowsAreSiblings(prevKey, key)) return true;
93
+ } else if (row[DEPTH] > 1) return true;
94
+ return false;
95
+ };
96
+ export { dropLastPathSegment, getParentRow, lastPathSegment, missingAncestor, treeToDataSourceRows };
@@ -0,0 +1,6 @@
1
+ function isNotNullOrUndefined(value) {
2
+ return null != value;
3
+ }
4
+ const isObject = (o)=>"object" == typeof o && null !== o;
5
+ const elementImplementsJSONSerialization = (element)=>"function" == typeof element.type.toJSON;
6
+ export { elementImplementsJSONSerialization, isNotNullOrUndefined, isObject };
@@ -0,0 +1,4 @@
1
+ const NO_DATA_MATCH = [
2
+ "No matching data"
3
+ ];
4
+ export { NO_DATA_MATCH };
@@ -0,0 +1,12 @@
1
+ function getUrlParameter(paramName, defaultValue) {
2
+ const url = new URL(document.location.href);
3
+ const parameter = url.searchParams.get(paramName);
4
+ if (parameter) return parameter;
5
+ const hashParams = url.hash;
6
+ const regex = new RegExp(`${paramName}=([a-zA-Z]*)`);
7
+ const result = regex.exec(hashParams);
8
+ if (result) return result[1];
9
+ return defaultValue;
10
+ }
11
+ const hasUrlParameter = (paramName)=>new URL(document.location.href).searchParams.has(paramName);
12
+ export { getUrlParameter, hasUrlParameter };
package/src/useId.js ADDED
@@ -0,0 +1,6 @@
1
+ import { useMemo } from "react";
2
+ let vuuComponentIdCount = 0;
3
+ const useId = (id)=>useMemo(()=>id ?? `vuu-${++vuuComponentIdCount}`, [
4
+ id
5
+ ]);
6
+ export { useId };
@@ -0,0 +1,9 @@
1
+ import { useLayoutEffect, useRef } from "react";
2
+ const useLayoutEffectSkipFirst = (func, deps)=>{
3
+ const goodToGo = useRef(false);
4
+ useLayoutEffect(()=>{
5
+ if (goodToGo.current) func();
6
+ else goodToGo.current = true;
7
+ }, deps);
8
+ };
9
+ export { useLayoutEffectSkipFirst };
@@ -0,0 +1,122 @@
1
+ import { useCallback, useEffect, useRef } from "react";
2
+ const WidthHeight = [
3
+ "height",
4
+ "width"
5
+ ];
6
+ const WidthOnly = [
7
+ "width"
8
+ ];
9
+ const observedMap = new Map();
10
+ const getTargetSize = (element, size, dimension)=>{
11
+ switch(dimension){
12
+ case "height":
13
+ return size.height;
14
+ case "clientHeight":
15
+ return Math.floor(element.clientHeight);
16
+ case "clientWidth":
17
+ return Math.floor(element.clientWidth);
18
+ case "contentHeight":
19
+ return size.contentHeight;
20
+ case "contentWidth":
21
+ return size.contentWidth;
22
+ case "scrollHeight":
23
+ return Math.ceil(Math.floor(element.scrollHeight));
24
+ case "scrollWidth":
25
+ return Math.ceil(Math.floor(element.scrollWidth));
26
+ case "width":
27
+ return size.width;
28
+ default:
29
+ return 0;
30
+ }
31
+ };
32
+ const resizeObserver = new ResizeObserver((entries)=>{
33
+ for (const entry of entries){
34
+ const { target, borderBoxSize, contentBoxSize } = entry;
35
+ const observedTarget = observedMap.get(target);
36
+ if (observedTarget) {
37
+ const [{ blockSize: height, inlineSize: width }] = borderBoxSize;
38
+ const [{ blockSize: contentHeight, inlineSize: contentWidth }] = contentBoxSize;
39
+ const { onResize, measurements } = observedTarget;
40
+ let sizeChanged = false;
41
+ for (const [dimension, size] of Object.entries(measurements)){
42
+ const newSize = getTargetSize(target, {
43
+ height,
44
+ width,
45
+ contentHeight,
46
+ contentWidth
47
+ }, dimension);
48
+ if (newSize !== size) {
49
+ sizeChanged = true;
50
+ measurements[dimension] = newSize;
51
+ }
52
+ }
53
+ if (sizeChanged) onResize && onResize(measurements);
54
+ }
55
+ }
56
+ });
57
+ function useResizeObserver(ref, dimensions, onResize, reportInitialSize = false) {
58
+ const dimensionsRef = useRef(dimensions);
59
+ const measure = useCallback((target)=>{
60
+ const { width, height } = target.getBoundingClientRect();
61
+ const { clientWidth: contentWidth, clientHeight: contentHeight } = target;
62
+ const flooredHeight = Math.floor(height);
63
+ const flooredWidth = Math.floor(width);
64
+ return dimensionsRef.current.reduce((map, dim)=>{
65
+ map[dim] = getTargetSize(target, {
66
+ width: flooredWidth,
67
+ height: flooredHeight,
68
+ contentHeight,
69
+ contentWidth
70
+ }, dim);
71
+ return map;
72
+ }, {});
73
+ }, []);
74
+ useEffect(()=>{
75
+ const target = ref.current;
76
+ async function registerObserver() {
77
+ observedMap.set(target, {
78
+ measurements: {}
79
+ });
80
+ const observedTarget = observedMap.get(target);
81
+ if (observedTarget) {
82
+ const measurements = measure(target);
83
+ observedTarget.measurements = measurements;
84
+ resizeObserver.observe(target);
85
+ if (reportInitialSize) onResize(measurements);
86
+ } else console.log("%cuseResizeObserver an target expected to be under observation wa snot found. This warrants investigation", "font-weight:bold; color:red;");
87
+ }
88
+ if (target) {
89
+ if (observedMap.has(target)) console.log("useResizeObserver attemping to observe same element twice", {
90
+ target
91
+ });
92
+ registerObserver();
93
+ }
94
+ return ()=>{
95
+ if (target && observedMap.has(target)) {
96
+ resizeObserver.unobserve(target);
97
+ observedMap.delete(target);
98
+ }
99
+ };
100
+ }, [
101
+ measure,
102
+ ref
103
+ ]);
104
+ useEffect(()=>{
105
+ const target = ref.current;
106
+ const record = observedMap.get(target);
107
+ if (record) {
108
+ if (dimensionsRef.current !== dimensions) {
109
+ dimensionsRef.current = dimensions;
110
+ const measurements = measure(target);
111
+ record.measurements = measurements;
112
+ }
113
+ record.onResize = onResize;
114
+ }
115
+ }, [
116
+ dimensions,
117
+ measure,
118
+ ref,
119
+ onResize
120
+ ]);
121
+ }
122
+ export { WidthHeight, WidthOnly, useResizeObserver };
@@ -0,0 +1,21 @@
1
+ import { useCallback, useRef, useState } from "react";
2
+ const isSimpleStateValue = (arg)=>"function" != typeof arg;
3
+ const useStateRef = (initialValue)=>{
4
+ const [value, _setValue] = useState(initialValue);
5
+ const ref = useRef(value);
6
+ const setValue = useCallback((arg)=>{
7
+ if (isSimpleStateValue(arg)) {
8
+ ref.current = arg;
9
+ _setValue(arg);
10
+ } else {
11
+ const { current: prev } = ref;
12
+ ref.current = arg(prev);
13
+ _setValue(ref.current);
14
+ }
15
+ }, []);
16
+ return [
17
+ ref,
18
+ setValue
19
+ ];
20
+ };
21
+ export { useStateRef };
File without changes