@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.
- package/package.json +8 -9
- package/src/Clock.js +43 -0
- package/src/PageVisibilityObserver.js +42 -0
- package/src/ScaledDecimal.js +32 -0
- package/src/ShellContext.js +5 -0
- package/src/ThemeProvider.js +56 -0
- package/src/array-utils.js +51 -0
- package/src/box-utils.js +51 -0
- package/src/broadcast-channel.js +0 -0
- package/src/column-utils.js +790 -0
- package/src/common-types.js +11 -0
- package/src/component-registry.js +83 -0
- package/src/context-definitions/DataContext.js +15 -0
- package/src/context-definitions/DataProvider.js +13 -0
- package/src/context-definitions/DataSourceProvider.js +18 -0
- package/src/context-definitions/WorkspaceContext.js +14 -0
- package/src/cookie-utils.js +15 -0
- package/src/css-utils.js +5 -0
- package/src/data-editing/DataEditingProvider.js +13 -0
- package/src/data-editing/EditButtons.js +32 -0
- package/src/data-editing/EditModeProvider.js +18 -0
- package/src/data-editing/EditSession.js +149 -0
- package/src/data-editing/edit-utils.js +37 -0
- package/src/data-editing/useEditableTable.js +76 -0
- package/src/data-utils.js +55 -0
- package/src/datasource/BaseDataSource.js +233 -0
- package/src/datasource/datasource-action-utils.js +6 -0
- package/src/datasource/datasource-filter-utils.js +27 -0
- package/src/datasource/datasource-utils.js +148 -0
- package/src/date/date-utils.js +80 -0
- package/src/date/dateTimePattern.js +17 -0
- package/src/date/formatter.js +101 -0
- package/src/date/index.js +4 -0
- package/src/date/types.js +27 -0
- package/src/debug-utils.js +25 -0
- package/src/event-emitter.js +78 -0
- package/src/feature-utils.js +86 -0
- package/src/filters/filter-utils.js +136 -0
- package/src/filters/filterAsQuery.js +70 -0
- package/src/filters/index.js +2 -0
- package/src/form-utils.js +69 -0
- package/src/formatting-utils.js +42 -0
- package/src/getUniqueId.js +2 -0
- package/src/group-utils.js +16 -0
- package/src/html-utils.js +108 -0
- package/src/index.js +77 -0
- package/src/input-utils.js +3 -0
- package/src/invariant.js +9 -0
- package/src/itemToString.js +9 -0
- package/src/json-types.js +0 -0
- package/src/json-utils.js +108 -0
- package/src/keyboard-utils.js +14 -0
- package/src/keyset.js +57 -0
- package/src/layout-types.js +0 -0
- package/src/list-utils.js +5 -0
- package/src/local-storage-utils.js +23 -0
- package/src/logging-utils.js +52 -0
- package/src/module-utils.js +2 -0
- package/src/nanoid/index.js +13 -0
- package/src/perf-utils.js +28 -0
- package/src/promise-utils.js +26 -0
- package/src/protocol-message-utils.js +68 -0
- package/src/range-utils.js +109 -0
- package/src/react-utils.js +64 -0
- package/src/round-decimal.js +83 -0
- package/src/row-utils.js +43 -0
- package/src/selection-utils.js +25 -0
- package/src/shell-layout-types.js +9 -0
- package/src/sort-utils.js +75 -0
- package/src/table-schema-utils.js +11 -0
- package/src/text-utils.js +13 -0
- package/src/theme-utils.js +21 -0
- package/src/tree-types.js +0 -0
- package/src/tree-utils.js +96 -0
- package/src/ts-utils.js +6 -0
- package/src/typeahead-utils.js +4 -0
- package/src/url-utils.js +12 -0
- package/src/useId.js +6 -0
- package/src/useLayoutEffectSkipFirst.js +9 -0
- package/src/useResizeObserver.js +122 -0
- package/src/useStateRef.js +21 -0
- package/src/user-types.js +0 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.1.19-beta.
|
|
2
|
+
"version": "2.1.19-beta.2",
|
|
3
3
|
"author": "heswell",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"types": "types/index.d.ts",
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
"@salt-ds/core": "1.54.1"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@vuu-ui/vuu-data-types": "2.1.19-beta.
|
|
12
|
-
"@vuu-ui/vuu-table-types": "2.1.19-beta.
|
|
13
|
-
"@vuu-ui/vuu-filter-types": "2.1.19-beta.
|
|
14
|
-
"@vuu-ui/vuu-protocol-types": "2.1.19-beta.
|
|
11
|
+
"@vuu-ui/vuu-data-types": "2.1.19-beta.2",
|
|
12
|
+
"@vuu-ui/vuu-table-types": "2.1.19-beta.2",
|
|
13
|
+
"@vuu-ui/vuu-filter-types": "2.1.19-beta.2",
|
|
14
|
+
"@vuu-ui/vuu-protocol-types": "2.1.19-beta.2"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"@internationalized/date": "^3.0.0",
|
|
18
|
-
"@vuu-ui/vuu-filter-parser": "2.1.19-beta.
|
|
18
|
+
"@vuu-ui/vuu-filter-parser": "2.1.19-beta.2",
|
|
19
19
|
"clsx": "^2.0.0",
|
|
20
20
|
"react": "^19.2.3",
|
|
21
21
|
"react-dom": "^19.2.3"
|
|
@@ -23,13 +23,12 @@
|
|
|
23
23
|
"sideEffects": false,
|
|
24
24
|
"files": [
|
|
25
25
|
"README.md",
|
|
26
|
-
"
|
|
27
|
-
"cjs",
|
|
26
|
+
"src",
|
|
28
27
|
"/types"
|
|
29
28
|
],
|
|
30
29
|
"exports": {
|
|
31
30
|
".": {
|
|
32
|
-
"import": "./index.js",
|
|
31
|
+
"import": "./src/index.js",
|
|
33
32
|
"types": "./types/index.d.ts"
|
|
34
33
|
}
|
|
35
34
|
},
|
package/src/Clock.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
class Clock {
|
|
2
|
+
#millisSinceEpoch = 0;
|
|
3
|
+
#showCurrentTime = false;
|
|
4
|
+
constructor(props){
|
|
5
|
+
const today = new Date();
|
|
6
|
+
const offset = today.getTimezoneOffset();
|
|
7
|
+
if (props) {
|
|
8
|
+
const dateProvided = "number" == typeof props.year && "number" == typeof props.month && "number" == typeof props.day;
|
|
9
|
+
const year = props.year ?? today.getFullYear();
|
|
10
|
+
const month = void 0 !== props.month ? props.month - 1 : today.getMonth();
|
|
11
|
+
const day = props.day ?? today.getDay();
|
|
12
|
+
const hours = void 0 !== props.hours ? 0 === offset ? props.hours : props.hours + 1 : dateProvided ? offset ? 1 : 0 : today.getUTCHours();
|
|
13
|
+
const minutes = props.minutes ?? (dateProvided ? 0 : today.getMinutes());
|
|
14
|
+
const seconds = props.seconds ?? (dateProvided ? 0 : today.getSeconds());
|
|
15
|
+
const ms = props.milliseconds ?? (dateProvided ? 0 : today.getMilliseconds());
|
|
16
|
+
const date = new Date(year, month, day, hours, minutes, seconds, ms);
|
|
17
|
+
this.#millisSinceEpoch = date.getTime();
|
|
18
|
+
} else this.#millisSinceEpoch = today.getTime();
|
|
19
|
+
}
|
|
20
|
+
goBack(value, units = "ms") {
|
|
21
|
+
const multiplier = "ms" === units ? 1 : "seconds" === units ? 1000 : 60000;
|
|
22
|
+
this.#millisSinceEpoch -= value * multiplier;
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
advance(value, units = "ms") {
|
|
26
|
+
const multiplier = "ms" === units ? 1 : "seconds" === units ? 1000 : 60000;
|
|
27
|
+
this.#millisSinceEpoch += value * multiplier;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
set showCurrentTime(value) {
|
|
31
|
+
this.#showCurrentTime = value;
|
|
32
|
+
}
|
|
33
|
+
toString() {
|
|
34
|
+
return new Date(this.now).toISOString();
|
|
35
|
+
}
|
|
36
|
+
get now() {
|
|
37
|
+
return this.#showCurrentTime ? new Date().getTime() : this.#millisSinceEpoch;
|
|
38
|
+
}
|
|
39
|
+
get date() {
|
|
40
|
+
return this.#showCurrentTime ? new Date() : new Date(this.#millisSinceEpoch);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export { Clock };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EventEmitter } from "./event-emitter.js";
|
|
2
|
+
const defaultProps = {};
|
|
3
|
+
class PageVisibilityObserver extends EventEmitter {
|
|
4
|
+
#inactiveTimeoutMs;
|
|
5
|
+
#inactivityTimer;
|
|
6
|
+
#hidden;
|
|
7
|
+
visibilityChangeHandler = ()=>{
|
|
8
|
+
this.hidden = document.hidden;
|
|
9
|
+
};
|
|
10
|
+
constructor({ inactiveTimeout = 0, onHidden, onInactiveTimeout, onVisibilityChange, onVisible } = defaultProps){
|
|
11
|
+
super();
|
|
12
|
+
this.#hidden = document.hidden;
|
|
13
|
+
this.#inactiveTimeoutMs = 1000 * inactiveTimeout;
|
|
14
|
+
if (onInactiveTimeout) this.on("inactive-timeout", onInactiveTimeout);
|
|
15
|
+
if (onHidden) this.on("hidden", onHidden);
|
|
16
|
+
if (onVisible) this.on("visible", onVisible);
|
|
17
|
+
if (onVisibilityChange) this.on("visibilityChange", onVisibilityChange);
|
|
18
|
+
document.addEventListener("visibilitychange", this.visibilityChangeHandler);
|
|
19
|
+
}
|
|
20
|
+
clear() {
|
|
21
|
+
document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
|
|
22
|
+
}
|
|
23
|
+
set hidden(hidden) {
|
|
24
|
+
if (hidden !== this.#hidden) {
|
|
25
|
+
this.#hidden = hidden;
|
|
26
|
+
if (document.hidden) {
|
|
27
|
+
this.emit("hidden");
|
|
28
|
+
if (this.#inactiveTimeoutMs) this.#inactivityTimer = setTimeout(()=>{
|
|
29
|
+
this.emit("inactive-timeout");
|
|
30
|
+
}, this.#inactiveTimeoutMs);
|
|
31
|
+
} else {
|
|
32
|
+
this.emit("visible");
|
|
33
|
+
if (this.#inactivityTimer) {
|
|
34
|
+
clearTimeout(this.#inactivityTimer);
|
|
35
|
+
this.#inactivityTimer = void 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
this.emit("visibilityChange", hidden);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export { PageVisibilityObserver };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const scaledDecimals = (fraction, decimals)=>{
|
|
2
|
+
if (fraction.length > decimals) return fraction.slice(0, decimals);
|
|
3
|
+
if (fraction.length === decimals) return fraction;
|
|
4
|
+
return fraction.padEnd(decimals, "0");
|
|
5
|
+
};
|
|
6
|
+
class ScaledDecimal {
|
|
7
|
+
value;
|
|
8
|
+
decimals;
|
|
9
|
+
constructor(value, decimals = 6){
|
|
10
|
+
this.value = value;
|
|
11
|
+
this.decimals = decimals;
|
|
12
|
+
console.log(`create a scaled decimal ${value} (${decimals} decimals)`);
|
|
13
|
+
}
|
|
14
|
+
get asLong() {
|
|
15
|
+
if ("" === this.value) return "";
|
|
16
|
+
{
|
|
17
|
+
const [integral, fraction = "0"] = this.value.split(".");
|
|
18
|
+
return `${integral}${scaledDecimals(fraction, this.decimals)}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
toJSON() {
|
|
22
|
+
return this.value;
|
|
23
|
+
}
|
|
24
|
+
toString() {
|
|
25
|
+
return this.value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const ScaledDecimal2 = (value)=>new ScaledDecimal(value, 2);
|
|
29
|
+
const ScaledDecimal4 = (value)=>new ScaledDecimal(value, 4);
|
|
30
|
+
const ScaledDecimal6 = (value)=>new ScaledDecimal(value, 6);
|
|
31
|
+
const ScaledDecimal8 = (value)=>new ScaledDecimal(value, 8);
|
|
32
|
+
export { ScaledDecimal, ScaledDecimal2, ScaledDecimal4, ScaledDecimal6, ScaledDecimal8 };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cloneElement, createContext, isValidElement, useContext } from "react";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
const DEFAULT_DENSITY = "medium";
|
|
5
|
+
const DEFAULT_THEME = "salt-theme";
|
|
6
|
+
const DEFAULT_THEME_MODE = "light";
|
|
7
|
+
const ThemeContext = /*#__PURE__*/ createContext({
|
|
8
|
+
density: "high",
|
|
9
|
+
theme: "vuu",
|
|
10
|
+
themeMode: "light"
|
|
11
|
+
});
|
|
12
|
+
const DEFAULT_THEME_ATTRIBUTES = [
|
|
13
|
+
"vuu",
|
|
14
|
+
"salt-density-high",
|
|
15
|
+
"light"
|
|
16
|
+
];
|
|
17
|
+
const useThemeAttributes = (themeAttributes)=>{
|
|
18
|
+
const context = useContext(ThemeContext);
|
|
19
|
+
if (themeAttributes) return [
|
|
20
|
+
themeAttributes.themeClass,
|
|
21
|
+
themeAttributes.densityClass,
|
|
22
|
+
themeAttributes.dataMode
|
|
23
|
+
];
|
|
24
|
+
if (context) return [
|
|
25
|
+
`${context.theme}-theme`,
|
|
26
|
+
`salt-density-${context.density}`,
|
|
27
|
+
context.themeMode
|
|
28
|
+
];
|
|
29
|
+
return DEFAULT_THEME_ATTRIBUTES;
|
|
30
|
+
};
|
|
31
|
+
const createThemedChildren = (children, theme, themeMode, density)=>{
|
|
32
|
+
if (/*#__PURE__*/ isValidElement(children)) return /*#__PURE__*/ cloneElement(children, {
|
|
33
|
+
className: clsx(children.props?.className, `${theme}-theme`, `salt-density-${density}`),
|
|
34
|
+
"data-mode": themeMode
|
|
35
|
+
});
|
|
36
|
+
console.warn(`\nThemeProvider can only apply CSS classes for theming to a single nested child element of the ThemeProvider.
|
|
37
|
+
Wrap elements with a single container`);
|
|
38
|
+
return children;
|
|
39
|
+
};
|
|
40
|
+
const ThemeProvider = ({ applyThemeClasses = false, children, theme: themeProp, themeMode: themeModeProp, density: densityProp })=>{
|
|
41
|
+
const { density: inheritedDensity, themeMode: inheritedThemeMode, theme: inheritedTheme } = useContext(ThemeContext);
|
|
42
|
+
const density = densityProp ?? inheritedDensity ?? DEFAULT_DENSITY;
|
|
43
|
+
const themeMode = themeModeProp ?? inheritedThemeMode ?? DEFAULT_THEME_MODE;
|
|
44
|
+
const theme = themeProp ?? inheritedTheme ?? DEFAULT_THEME;
|
|
45
|
+
const themedChildren = applyThemeClasses ? createThemedChildren(children, theme, themeMode, density) : children;
|
|
46
|
+
return /*#__PURE__*/ jsx(ThemeContext.Provider, {
|
|
47
|
+
value: {
|
|
48
|
+
themeMode,
|
|
49
|
+
density,
|
|
50
|
+
theme
|
|
51
|
+
},
|
|
52
|
+
children: themedChildren
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
ThemeProvider.displayName = "ThemeProvider";
|
|
56
|
+
export { DEFAULT_DENSITY, DEFAULT_THEME, DEFAULT_THEME_MODE, ThemeContext, ThemeProvider, useThemeAttributes };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function partition(array, test, pass = [], fail = []) {
|
|
2
|
+
for(let i = 0, len = array.length; i < len; i++)(test(array[i], i) ? pass : fail).push(array[i]);
|
|
3
|
+
return [
|
|
4
|
+
pass,
|
|
5
|
+
fail
|
|
6
|
+
];
|
|
7
|
+
}
|
|
8
|
+
function itemsChanged(currentItems, newItems, identityProperty) {
|
|
9
|
+
if (currentItems.length !== newItems.length) return true;
|
|
10
|
+
if (void 0 === identityProperty) return !currentItems.every((item)=>newItems.includes(item));
|
|
11
|
+
return currentItems.some((currentItem)=>-1 === newItems.findIndex((newItem)=>newItem[identityProperty] === currentItem[identityProperty]));
|
|
12
|
+
}
|
|
13
|
+
function itemsOrOrderChanged(currentItems, newItems, identityProperty) {
|
|
14
|
+
if (currentItems.length !== newItems.length) return true;
|
|
15
|
+
if (void 0 === identityProperty) return currentItems.some((item, index)=>newItems[index] !== item);
|
|
16
|
+
return currentItems.some((currentItem, index)=>newItems[index][identityProperty] !== currentItem[identityProperty]);
|
|
17
|
+
}
|
|
18
|
+
const moveItemDeprecated = (items, item, moveTo)=>{
|
|
19
|
+
const fromIndex = items.indexOf(item);
|
|
20
|
+
if (fromIndex === moveTo) return items;
|
|
21
|
+
const newItems = items.slice();
|
|
22
|
+
if (-1 === fromIndex) throw Error("moveItem, item to be moved not found");
|
|
23
|
+
newItems.splice(fromIndex, 1);
|
|
24
|
+
if (-1 === moveTo) newItems.push(item);
|
|
25
|
+
else {
|
|
26
|
+
const offset = moveTo > fromIndex ? 0 : 0;
|
|
27
|
+
newItems.splice(moveTo + offset, 0, item);
|
|
28
|
+
}
|
|
29
|
+
return newItems;
|
|
30
|
+
};
|
|
31
|
+
const moveItem = (items, fromIndex, toIndex)=>{
|
|
32
|
+
if (fromIndex === toIndex) return items;
|
|
33
|
+
{
|
|
34
|
+
const newItems = items.slice();
|
|
35
|
+
const [item] = newItems.splice(fromIndex, 1);
|
|
36
|
+
if (-1 === toIndex) return newItems.concat(item);
|
|
37
|
+
{
|
|
38
|
+
const offset = toIndex > fromIndex ? 0 : 0;
|
|
39
|
+
newItems.splice(toIndex + offset, 0, item);
|
|
40
|
+
return newItems;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const getAddedItems = (values, newValues)=>{
|
|
45
|
+
const isNew = (v)=>!values?.includes(v);
|
|
46
|
+
if (void 0 === values) return newValues;
|
|
47
|
+
if (newValues.some(isNew)) return newValues.filter(isNew);
|
|
48
|
+
return [];
|
|
49
|
+
};
|
|
50
|
+
const getMissingItems = (sourceItems, items, identity)=>items.filter((i)=>-1 === sourceItems.findIndex((s)=>identity(s) === i));
|
|
51
|
+
export { getAddedItems, getMissingItems, itemsChanged, itemsOrOrderChanged, moveItem, moveItemDeprecated, partition };
|
package/src/box-utils.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function boxContainsPoint(rect, x, y) {
|
|
2
|
+
if (rect) return x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
|
|
3
|
+
}
|
|
4
|
+
function getCenteredBox({ right, left, top, bottom }, pctSize) {
|
|
5
|
+
const pctOffset = (1 - pctSize) / 2;
|
|
6
|
+
const w = (right - left) * pctOffset;
|
|
7
|
+
const h = (bottom - top) * pctOffset;
|
|
8
|
+
return {
|
|
9
|
+
left: left + w,
|
|
10
|
+
top: top + h,
|
|
11
|
+
right: right - w,
|
|
12
|
+
bottom: bottom - h
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function pointPositionWithinRect(x, y, rect, borderZone = 30) {
|
|
16
|
+
const width = rect.right - rect.left;
|
|
17
|
+
const height = rect.bottom - rect.top;
|
|
18
|
+
const posX = x - rect.left;
|
|
19
|
+
const posY = y - rect.top;
|
|
20
|
+
let closeToTheEdge = 0;
|
|
21
|
+
if (posX < borderZone) closeToTheEdge += 8;
|
|
22
|
+
if (posX > width - borderZone) closeToTheEdge += 2;
|
|
23
|
+
if (posY < borderZone) closeToTheEdge += 1;
|
|
24
|
+
if (posY > height - borderZone) closeToTheEdge += 4;
|
|
25
|
+
return {
|
|
26
|
+
pctX: posX / width,
|
|
27
|
+
pctY: posY / height,
|
|
28
|
+
closeToTheEdge
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const isGridLayoutSplitDirection = (position)=>"centre" !== position && "header" !== position;
|
|
32
|
+
function getPositionWithinBox(x, y, rect, pctX, pctY) {
|
|
33
|
+
const centerBox = getCenteredBox(rect, 0.2);
|
|
34
|
+
if (boxContainsPoint(centerBox, x, y)) return "centre";
|
|
35
|
+
{
|
|
36
|
+
const quadrant = `${pctY < 0.5 ? "north" : "south"}${pctX < 0.5 ? "west" : "east"}`;
|
|
37
|
+
switch(quadrant){
|
|
38
|
+
case "northwest":
|
|
39
|
+
return pctX > pctY ? "north" : "west";
|
|
40
|
+
case "northeast":
|
|
41
|
+
return 1 - pctX > pctY ? "north" : "east";
|
|
42
|
+
case "southeast":
|
|
43
|
+
return pctX > pctY ? "east" : "south";
|
|
44
|
+
case "southwest":
|
|
45
|
+
return 1 - pctX > pctY ? "west" : "south";
|
|
46
|
+
default:
|
|
47
|
+
throw Error("getPositionWithinBox failed top compute position");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export { boxContainsPoint, getCenteredBox, getPositionWithinBox, isGridLayoutSplitDirection, pointPositionWithinRect };
|
|
File without changes
|