@vuu-ui/vuu-ui-controls 4.0.0-alpha.3 → 4.0.0-alpha.31
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 +17 -15
- package/src/drag-drop/Draggable.css.js +2 -2
- package/src/drag-drop/useDragDrop.js +7 -1
- package/src/expando-input/ExpandoInput.css.js +1 -1
- package/src/hover-overlay/HoverOverlay.css.js +8 -0
- package/src/hover-overlay/HoverOverlay.js +87 -38
- package/src/icon-button/ToggleIconButton.css.js +1 -1
- package/src/index.js +1 -2
- package/src/instrument-picker/TablePicker.css.js +1 -0
- package/src/item-picker/ItemPicker.css.js +1 -1
- package/src/item-picker/useItemPicker.js +5 -1
- package/src/price-ticker/PriceTicker.css.js +4 -4
- package/src/prompt/Prompt.css.js +1 -0
- package/src/split-pane/SplitPane.css.js +82 -0
- package/src/split-pane/SplitPane.js +60 -0
- package/src/split-pane/Splitter.js +82 -0
- package/src/split-pane/index.js +1 -0
- package/src/split-pane/useSplitPane.js +101 -0
- package/src/table-search/SearchCell.css.js +4 -2
- package/src/table-search/SearchCell.js +3 -2
- package/src/table-search/TableSearch.css.js +4 -0
- package/src/table-search/TableSearch.js +3 -1
- package/src/table-search/useTableSearch.js +14 -6
- package/src/tabstrip/Tab.css.js +3 -3
- package/src/tabstrip/Tabstrip.css.js +2 -2
- package/src/time-input/MaskedInput.js +176 -156
- package/src/time-input/TimeInput.css.js +41 -18
- package/src/time-input/TimeInput.js +25 -14
- package/src/time-input/useTimeInput.js +57 -47
- package/src/toolbar/Toolbar.css.js +1 -1
- package/src/vuu-date-picker/VuuDatePicker.js +46 -52
- package/src/vuu-time-picker/VuuTimePicker.js +6 -5
- package/types/context-panel-provider/ContextPanelProvider.d.ts +1 -1
- package/types/drag-drop/DragDropProvider.d.ts +1 -1
- package/types/hover-overlay/HoverOverlay.d.ts +7 -1
- package/types/icon-button/Icon.d.ts +1 -1
- package/types/icon-button/ToggleIconButton.d.ts +1 -1
- package/types/index.d.ts +5 -5
- package/types/instrument-picker/SearchCell.d.ts +1 -1
- package/types/instrument-picker/TablePicker.d.ts +1 -1
- package/types/item-picker/useItemPicker.d.ts +2 -2
- package/types/modal-provider/ModalProvider.d.ts +1 -1
- package/types/price-ticker/PriceTicker.d.ts +1 -1
- package/types/prompt/Prompt.d.ts +3 -3
- package/types/sortable-list/SortableList.d.ts +2 -2
- package/types/split-button/useSplitButton.d.ts +12 -12
- package/types/split-pane/SplitPane.d.ts +44 -0
- package/types/split-pane/Splitter.d.ts +10 -0
- package/types/split-pane/index.d.ts +2 -0
- package/types/split-pane/useSplitPane.d.ts +18 -0
- package/types/table-search/SearchCell.d.ts +1 -1
- package/types/table-search/TableSearch.d.ts +2 -1
- package/types/table-search/useTableSearch.d.ts +2 -2
- package/types/tabstrip/TabMenu.d.ts +1 -1
- package/types/tabstrip/Tabstrip.d.ts +1 -2
- package/types/time-input/MaskedInput.d.ts +60 -10
- package/types/time-input/TimeInput.d.ts +4 -3
- package/types/time-input/useTimeInput.d.ts +24 -5
- package/types/toolbar/Toolbar.d.ts +1 -2
- package/types/vuu-date-picker/VuuDatePicker.d.ts +19 -3
- package/types/vuu-time-picker/VuuTimePicker.d.ts +8 -6
- package/types/vuu-typeahead-input/VuuTypeaheadInput.d.ts +1 -1
- package/src/modal-provider/ModalProvider.js +0 -147
package/package.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0-alpha.
|
|
2
|
+
"version": "4.0.0-alpha.31",
|
|
3
3
|
"description": "VUU UI Controls",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"author": "heswell",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
-
"type": "module",
|
|
8
7
|
"scripts": {
|
|
9
8
|
"build:dev": "node ../../scripts/run-build.mjs",
|
|
10
9
|
"build": "node ../../scripts/run-build-rslib.ts",
|
|
11
10
|
"type-defs": "node ../../scripts/build-type-defs.mjs"
|
|
12
11
|
},
|
|
13
12
|
"devDependencies": {
|
|
14
|
-
"@vuu-ui/vuu-data-types": "4.0.0-alpha.
|
|
15
|
-
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.
|
|
16
|
-
"@vuu-ui/vuu-table-types": "4.0.0-alpha.
|
|
13
|
+
"@vuu-ui/vuu-data-types": "4.0.0-alpha.31",
|
|
14
|
+
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.31",
|
|
15
|
+
"@vuu-ui/vuu-table-types": "4.0.0-alpha.31"
|
|
17
16
|
},
|
|
18
17
|
"dependencies": {
|
|
19
|
-
"@vuu-ui/vuu-context-menu": "4.0.0-alpha.
|
|
20
|
-
"@vuu-ui/vuu-data-react": "4.0.0-alpha.
|
|
21
|
-
"@vuu-ui/vuu-
|
|
22
|
-
"@vuu-ui/vuu-
|
|
23
|
-
"@vuu-ui/vuu-
|
|
24
|
-
"@
|
|
25
|
-
"@salt-ds/
|
|
26
|
-
"@salt-ds/
|
|
27
|
-
"@salt-ds/
|
|
18
|
+
"@vuu-ui/vuu-context-menu": "4.0.0-alpha.31",
|
|
19
|
+
"@vuu-ui/vuu-data-react": "4.0.0-alpha.31",
|
|
20
|
+
"@vuu-ui/vuu-layout": "4.0.0-alpha.31",
|
|
21
|
+
"@vuu-ui/vuu-popups": "4.0.0-alpha.31",
|
|
22
|
+
"@vuu-ui/vuu-table": "4.0.0-alpha.31",
|
|
23
|
+
"@vuu-ui/vuu-utils": "4.0.0-alpha.31",
|
|
24
|
+
"@salt-ds/core": "1.72.0",
|
|
25
|
+
"@salt-ds/icons": "1.18.3",
|
|
26
|
+
"@salt-ds/styles": "0.4.1",
|
|
27
|
+
"@salt-ds/window": "0.1.2",
|
|
28
28
|
"tabbable": "^6.0.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"react-dom": "^19.2.3"
|
|
36
36
|
},
|
|
37
37
|
"sideEffects": false,
|
|
38
|
+
"type": "module",
|
|
38
39
|
"files": [
|
|
39
40
|
"README.md",
|
|
40
41
|
"src",
|
|
@@ -42,8 +43,9 @@
|
|
|
42
43
|
],
|
|
43
44
|
"exports": {
|
|
44
45
|
".": {
|
|
46
|
+
"types": "./types/index.d.ts",
|
|
45
47
|
"import": "./src/index.js",
|
|
46
|
-
"
|
|
48
|
+
"default": "./src/index.js"
|
|
47
49
|
}
|
|
48
50
|
},
|
|
49
51
|
"module": "./src/index.js",
|
|
@@ -26,14 +26,14 @@ const css = `
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
.vuuDraggable-dropIndicator {
|
|
29
|
-
background-color: var(--salt-
|
|
29
|
+
background-color: var(--salt-sentiment-accent-background);
|
|
30
30
|
width: 100%;
|
|
31
31
|
height: 2px;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.vuuDraggable-dropIndicator:before {
|
|
35
35
|
content: "";
|
|
36
|
-
background-color: var(--salt-
|
|
36
|
+
background-color: var(--salt-sentiment-accent-background);
|
|
37
37
|
border-radius: 3px;
|
|
38
38
|
width: 6px;
|
|
39
39
|
height: 6px;
|
|
@@ -292,6 +292,7 @@ const useDragDrop = ({ allowDragDrop, containerRef, draggableClassName, getDragP
|
|
|
292
292
|
scrollableContainerRef.current = scrollableContainer;
|
|
293
293
|
const containerRect = scrollableContainer.getBoundingClientRect();
|
|
294
294
|
const draggableRect = dragElement.getBoundingClientRect();
|
|
295
|
+
const dragElementStyle = getComputedStyle(dragElement);
|
|
295
296
|
const dragDropState = dragDropStateRef.current = new DragDropState(mousePosition, dragElement);
|
|
296
297
|
setDragBoundaries(containerRect, draggableRect);
|
|
297
298
|
beginDrag(dragElement);
|
|
@@ -303,7 +304,12 @@ const useDragDrop = ({ allowDragDrop, containerRef, draggableClassName, getDragP
|
|
|
303
304
|
onDropped: terminateDrag,
|
|
304
305
|
onTransitionEnd: terminateDrag,
|
|
305
306
|
ref: dragDropState.setDraggable,
|
|
306
|
-
style:
|
|
307
|
+
style: {
|
|
308
|
+
...constrainRect(draggableRect, containerRect),
|
|
309
|
+
backgroundColor: dragElementStyle.backgroundColor,
|
|
310
|
+
color: dragElementStyle.color,
|
|
311
|
+
font: dragElementStyle.font
|
|
312
|
+
},
|
|
307
313
|
wrapperClassName: draggableClassName
|
|
308
314
|
}),
|
|
309
315
|
draggedItemIndex: parseInt(index)
|
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Overlay, OverlayPanel, OverlayPanelContent, OverlayTrigger } from "@salt-ds/core";
|
|
3
|
+
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
4
|
+
import { useWindow } from "@salt-ds/window";
|
|
5
|
+
import { containsPoint } from "@vuu-ui/vuu-utils";
|
|
3
6
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
-
|
|
7
|
+
import HoverOverlay from "./HoverOverlay.css";
|
|
8
|
+
const classBase = "vuuHoverOverlay";
|
|
9
|
+
const OPEN_DELAY = 400;
|
|
10
|
+
const CLOSE_DELAY = 300;
|
|
11
|
+
const HoverOverlay_HoverOverlay = ({ children, open: openProp = false, onOpenChange, openOn = "hover", placement = "right", trigger })=>{
|
|
12
|
+
const targetWindow = useWindow();
|
|
13
|
+
useComponentCssInjection({
|
|
14
|
+
testId: "vuu-hover-overlay",
|
|
15
|
+
css: HoverOverlay,
|
|
16
|
+
window: targetWindow
|
|
17
|
+
});
|
|
5
18
|
const [open, _setOpen] = useState(openProp);
|
|
6
19
|
const isOpen = useRef(false);
|
|
7
20
|
const showHandle = useRef(void 0);
|
|
8
21
|
const hideHandle = useRef(void 0);
|
|
22
|
+
const triggerRef = useRef(null);
|
|
23
|
+
const panelRef = useRef(null);
|
|
24
|
+
const clearShowTimer = useCallback(()=>{
|
|
25
|
+
if (showHandle.current) {
|
|
26
|
+
clearTimeout(showHandle.current);
|
|
27
|
+
showHandle.current = void 0;
|
|
28
|
+
}
|
|
29
|
+
}, []);
|
|
30
|
+
const clearHideTimer = useCallback(()=>{
|
|
31
|
+
if (hideHandle.current) {
|
|
32
|
+
clearTimeout(hideHandle.current);
|
|
33
|
+
hideHandle.current = void 0;
|
|
34
|
+
}
|
|
35
|
+
}, []);
|
|
9
36
|
const setOpen = useCallback((open)=>{
|
|
10
37
|
if (open !== isOpen.current) {
|
|
11
38
|
isOpen.current = open;
|
|
@@ -15,78 +42,100 @@ const HoverOverlay = ({ children, open: openProp = false, onOpenChange, placemen
|
|
|
15
42
|
}, [
|
|
16
43
|
onOpenChange
|
|
17
44
|
]);
|
|
45
|
+
const startHideTimer = useCallback(()=>{
|
|
46
|
+
if (void 0 === hideHandle.current) hideHandle.current = setTimeout(()=>{
|
|
47
|
+
hideHandle.current = void 0;
|
|
48
|
+
setOpen(false);
|
|
49
|
+
}, CLOSE_DELAY);
|
|
50
|
+
}, [
|
|
51
|
+
setOpen
|
|
52
|
+
]);
|
|
18
53
|
useEffect(()=>{
|
|
19
54
|
if (openProp !== isOpen.current) setOpen(openProp);
|
|
20
55
|
}, [
|
|
21
56
|
openProp,
|
|
22
57
|
setOpen
|
|
23
58
|
]);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
59
|
+
useEffect(()=>()=>{
|
|
60
|
+
clearShowTimer();
|
|
61
|
+
clearHideTimer();
|
|
62
|
+
}, [
|
|
63
|
+
clearHideTimer,
|
|
64
|
+
clearShowTimer
|
|
65
|
+
]);
|
|
66
|
+
useEffect(()=>{
|
|
67
|
+
if (open && "hover" === openOn) {
|
|
68
|
+
const doc = triggerRef.current?.ownerDocument ?? document;
|
|
69
|
+
const handlePointerMove = ({ clientX, clientY })=>{
|
|
70
|
+
if (containsPoint(triggerRef.current, clientX, clientY) || containsPoint(panelRef.current, clientX, clientY)) clearHideTimer();
|
|
71
|
+
else startHideTimer();
|
|
72
|
+
};
|
|
73
|
+
doc.addEventListener("pointermove", handlePointerMove);
|
|
74
|
+
doc.documentElement.addEventListener("mouseleave", startHideTimer);
|
|
75
|
+
return ()=>{
|
|
76
|
+
doc.removeEventListener("pointermove", handlePointerMove);
|
|
77
|
+
doc.documentElement.removeEventListener("mouseleave", startHideTimer);
|
|
78
|
+
clearHideTimer();
|
|
79
|
+
};
|
|
28
80
|
}
|
|
29
|
-
}, []);
|
|
30
|
-
const handleOverlayMouseLeave = useCallback(()=>{
|
|
31
|
-
hideHandle.current = setTimeout(()=>{
|
|
32
|
-
setOpen(false);
|
|
33
|
-
hideHandle.current = void 0;
|
|
34
|
-
}, 300);
|
|
35
81
|
}, [
|
|
36
|
-
|
|
82
|
+
clearHideTimer,
|
|
83
|
+
open,
|
|
84
|
+
openOn,
|
|
85
|
+
startHideTimer
|
|
37
86
|
]);
|
|
38
87
|
const handleMouseEnter = useCallback(()=>{
|
|
39
|
-
showHandle.current = setTimeout(()=>{
|
|
40
|
-
setOpen(true);
|
|
88
|
+
if (!isOpen.current && void 0 === showHandle.current) showHandle.current = setTimeout(()=>{
|
|
41
89
|
showHandle.current = void 0;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
clearTimeout(hideHandle.current);
|
|
45
|
-
hideHandle.current = void 0;
|
|
46
|
-
}
|
|
90
|
+
setOpen(true);
|
|
91
|
+
}, OPEN_DELAY);
|
|
47
92
|
}, [
|
|
48
93
|
setOpen
|
|
49
94
|
]);
|
|
50
95
|
const handleMouseLeave = useCallback(()=>{
|
|
51
|
-
|
|
52
|
-
clearTimeout(showHandle.current);
|
|
53
|
-
showHandle.current = void 0;
|
|
54
|
-
} else if (isOpen.current) hideHandle.current = setTimeout(()=>{
|
|
55
|
-
setOpen(false);
|
|
56
|
-
hideHandle.current = void 0;
|
|
57
|
-
}, 300);
|
|
96
|
+
clearShowTimer();
|
|
58
97
|
}, [
|
|
59
|
-
|
|
98
|
+
clearShowTimer
|
|
60
99
|
]);
|
|
61
100
|
const handleClick = useCallback(()=>{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
101
|
+
clearShowTimer();
|
|
102
|
+
}, [
|
|
103
|
+
clearShowTimer
|
|
104
|
+
]);
|
|
105
|
+
const handleOpenChange = useCallback((open)=>{
|
|
106
|
+
clearShowTimer();
|
|
107
|
+
clearHideTimer();
|
|
108
|
+
setOpen(open);
|
|
66
109
|
}, [
|
|
110
|
+
clearHideTimer,
|
|
111
|
+
clearShowTimer,
|
|
67
112
|
setOpen
|
|
68
113
|
]);
|
|
114
|
+
const triggerProps = "hover" === openOn ? {
|
|
115
|
+
onClick: handleClick,
|
|
116
|
+
onMouseEnter: handleMouseEnter,
|
|
117
|
+
onMouseLeave: handleMouseLeave
|
|
118
|
+
} : void 0;
|
|
69
119
|
return /*#__PURE__*/ jsxs(Overlay, {
|
|
70
120
|
placement: placement,
|
|
71
|
-
onOpenChange:
|
|
121
|
+
onOpenChange: handleOpenChange,
|
|
72
122
|
open: open,
|
|
73
123
|
children: [
|
|
74
124
|
/*#__PURE__*/ jsx(OverlayTrigger, {
|
|
75
125
|
children: /*#__PURE__*/ jsx("div", {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
onMouseLeave: handleMouseLeave,
|
|
126
|
+
...triggerProps,
|
|
127
|
+
ref: triggerRef,
|
|
79
128
|
children: trigger
|
|
80
129
|
})
|
|
81
130
|
}),
|
|
82
131
|
/*#__PURE__*/ jsx(OverlayPanel, {
|
|
132
|
+
className: `${classBase}-panel`,
|
|
133
|
+
ref: panelRef,
|
|
83
134
|
children: /*#__PURE__*/ jsx(OverlayPanelContent, {
|
|
84
|
-
onMouseEnter: handleOverlayMouseEnter,
|
|
85
|
-
onMouseLeave: handleOverlayMouseLeave,
|
|
86
135
|
children: children
|
|
87
136
|
})
|
|
88
137
|
})
|
|
89
138
|
]
|
|
90
139
|
});
|
|
91
140
|
};
|
|
92
|
-
export { HoverOverlay };
|
|
141
|
+
export { HoverOverlay_HoverOverlay as HoverOverlay };
|
package/src/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from "./measured-container/index.js";
|
|
|
14
14
|
export * from "./overflow-container/index.js";
|
|
15
15
|
export * from "./price-ticker/index.js";
|
|
16
16
|
export * from "./split-button/index.js";
|
|
17
|
+
export * from "./split-pane/index.js";
|
|
17
18
|
export * from "./table-search/index.js";
|
|
18
19
|
export * from "./tabs-next/index.js";
|
|
19
20
|
export * from "./tabstrip/index.js";
|
|
@@ -25,8 +26,6 @@ export * from "./vuu-typeahead-input/index.js";
|
|
|
25
26
|
export { ContextPanelProvider, useContextPanel, useHideContextPanel } from "./context-panel-provider/ContextPanelProvider.js";
|
|
26
27
|
export { HoverOverlay } from "./hover-overlay/HoverOverlay.js";
|
|
27
28
|
export { ItemPicker } from "./item-picker/ItemPicker.js";
|
|
28
|
-
export { SelectedItemsChangeHandler as SelectedItemChangeHandler } from "./item-picker/useItemPicker.js";
|
|
29
|
-
export { ModalProvider, useModal } from "./modal-provider/ModalProvider.js";
|
|
30
29
|
export { Prompt } from "./prompt/Prompt.js";
|
|
31
30
|
export { SortableList, SortableOption } from "./sortable-list/SortableList.js";
|
|
32
31
|
export { TimeInput } from "./time-input/TimeInput.js";
|
|
@@ -17,7 +17,11 @@ const itemName = (target)=>{
|
|
|
17
17
|
if (name) return name;
|
|
18
18
|
throw Error("[useItemPicker] item name could not be identified, data-name attribute not found");
|
|
19
19
|
};
|
|
20
|
-
const byItemName = (
|
|
20
|
+
const byItemName = (item1, item2)=>{
|
|
21
|
+
const n1 = item1.label ? item1.label : item1.name;
|
|
22
|
+
const n2 = item2.label ? item2.label : item2.name;
|
|
23
|
+
return n1 > n2 ? 1 : n2 > n1 ? -1 : 0;
|
|
24
|
+
};
|
|
21
25
|
const useItemPicker = ({ allItems, selectedItems, maxSelections, onSelectedItemsChange })=>{
|
|
22
26
|
if (maxSelections && selectedItems.length > maxSelections) throw Error(`[useItemPicker] max selections ${maxSelections} exceeded by selected items (that has count ${selectedItems.length})`);
|
|
23
27
|
const [searchPattern, setSearchPattern] = useState("");
|
|
@@ -15,15 +15,15 @@ const css = `
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.vuuPriceTicker.up1, .vuuPriceTicker.up2 {
|
|
18
|
-
--vuu-icon-color: var(--
|
|
19
|
-
color: var(--
|
|
18
|
+
--vuu-icon-color: var(--salt-color-green-500);
|
|
19
|
+
color: var(--salt-color-green-500);
|
|
20
20
|
animation-duration: 30s;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
.vuuPriceTicker.down1, .vuuPriceTicker.down2 {
|
|
24
24
|
--vuu-icon-transform: rotate(180deg);
|
|
25
|
-
--vuu-icon-color: var(--
|
|
26
|
-
color: var(--
|
|
25
|
+
--vuu-icon-color: var(--salt-color-red-500);
|
|
26
|
+
color: var(--salt-color-red-500);
|
|
27
27
|
animation-duration: 30s;
|
|
28
28
|
}
|
|
29
29
|
|
package/src/prompt/Prompt.css.js
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const css = `
|
|
2
|
+
.vuuSplitPane {
|
|
3
|
+
--vuuSplitPane-align: stretch;
|
|
4
|
+
--vuuSplitPane-direction: row;
|
|
5
|
+
--vuuSplitPane-gap: 0;
|
|
6
|
+
--vuuSplitPane-justify: flex-start;
|
|
7
|
+
--vuuSplitPane-margin: 0;
|
|
8
|
+
--vuuSplitPane-padding: 0;
|
|
9
|
+
--vuuSplitPane-splitterSize: 3px;
|
|
10
|
+
--vuuSplitPane-splitter-background: var(--salt-separable-secondary-borderColor);
|
|
11
|
+
--vuuSplitPane-splitter-background-active: var(--salt-separable-primary-borderColor);
|
|
12
|
+
--vuuSplitPane-splitter-grabZone: 4px;
|
|
13
|
+
align-items: var(--vuuSplitPane-align);
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
flex-direction: var(--vuuSplitPane-direction);
|
|
16
|
+
gap: var(--vuuSplitPane-gap);
|
|
17
|
+
justify-content: var(--vuuSplitPane-justify);
|
|
18
|
+
margin: var(--vuuSplitPane-margin);
|
|
19
|
+
min-width: 0;
|
|
20
|
+
min-height: 0;
|
|
21
|
+
padding: var(--vuuSplitPane-padding);
|
|
22
|
+
flex-wrap: nowrap;
|
|
23
|
+
display: flex;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:where(.vuuSplitPane) > :where(:not(.vuuSplitPane-splitter)) {
|
|
28
|
+
box-sizing: border-box;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:where(.vuuSplitPane-row) > :where(:not(.vuuSplitPane-splitter)) {
|
|
32
|
+
min-width: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:where(.vuuSplitPane-column) > :where(:not(.vuuSplitPane-splitter)) {
|
|
36
|
+
min-height: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.vuuSplitPane-splitter {
|
|
40
|
+
background-color: var(--vuuSplitPane-splitter-background);
|
|
41
|
+
flex: 0 0 var(--vuuSplitPane-splitterSize);
|
|
42
|
+
touch-action: none;
|
|
43
|
+
z-index: 1;
|
|
44
|
+
outline: none;
|
|
45
|
+
position: relative;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.vuuSplitPane-splitter:before {
|
|
49
|
+
content: "";
|
|
50
|
+
position: absolute;
|
|
51
|
+
inset: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.vuuSplitPane-row > .vuuSplitPane-splitter {
|
|
55
|
+
cursor: ew-resize;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.vuuSplitPane-row > .vuuSplitPane-splitter:before {
|
|
59
|
+
left: calc(-1 * var(--vuuSplitPane-splitter-grabZone));
|
|
60
|
+
right: calc(-1 * var(--vuuSplitPane-splitter-grabZone));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.vuuSplitPane-column > .vuuSplitPane-splitter {
|
|
64
|
+
cursor: ns-resize;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.vuuSplitPane-column > .vuuSplitPane-splitter:before {
|
|
68
|
+
bottom: calc(-1 * var(--vuuSplitPane-splitter-grabZone));
|
|
69
|
+
top: calc(-1 * var(--vuuSplitPane-splitter-grabZone));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.vuuSplitPane-splitter:hover, .vuuSplitPane-splitter-active {
|
|
73
|
+
--vuuSplitPane-splitter-background: var(--vuuSplitPane-splitter-background-active);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.vuuSplitPane-splitter:focus-visible {
|
|
77
|
+
outline: var(--salt-focused-outline);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
`;
|
|
82
|
+
export default css;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveResponsiveValue, useBreakpoint, useForkRef } from "@salt-ds/core";
|
|
3
|
+
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
4
|
+
import { useWindow } from "@salt-ds/window";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import { Children, forwardRef } from "react";
|
|
7
|
+
import { Splitter } from "./Splitter.js";
|
|
8
|
+
import { useSplitPane } from "./useSplitPane.js";
|
|
9
|
+
import SplitPane_0 from "./SplitPane.css";
|
|
10
|
+
const classBase = "vuuSplitPane";
|
|
11
|
+
const parseSpacing = (value)=>"number" == typeof value ? `calc(var(--salt-spacing-100) * ${value})` : value;
|
|
12
|
+
const parseAlignment = (value)=>"start" === value || "end" === value ? `flex-${value}` : value;
|
|
13
|
+
const SplitPane_SplitPane = /*#__PURE__*/ forwardRef(function({ align, children, className, direction = "row", gap = 0, justify, margin = 0, onSplitterMoved, padding = 0, splitterSize, style, ...htmlAttributes }, forwardedRef) {
|
|
14
|
+
const targetWindow = useWindow();
|
|
15
|
+
useComponentCssInjection({
|
|
16
|
+
testId: "vuu-split-pane",
|
|
17
|
+
css: SplitPane_0,
|
|
18
|
+
window: targetWindow
|
|
19
|
+
});
|
|
20
|
+
const { matchedBreakpoints } = useBreakpoint();
|
|
21
|
+
const flexDirection = resolveResponsiveValue(direction, matchedBreakpoints) ?? "row";
|
|
22
|
+
const flexGap = resolveResponsiveValue(gap, matchedBreakpoints);
|
|
23
|
+
const flexMargin = resolveResponsiveValue(margin, matchedBreakpoints);
|
|
24
|
+
const flexPadding = resolveResponsiveValue(padding, matchedBreakpoints);
|
|
25
|
+
const panes = Children.toArray(children);
|
|
26
|
+
if (panes.length > 2) throw Error(`[SplitPane] supports a maximum of two children, ${panes.length} were provided`);
|
|
27
|
+
const { beginResize, endResize, resize, rootRef, splitterPosition } = useSplitPane({
|
|
28
|
+
direction: flexDirection,
|
|
29
|
+
onSplitterMoved,
|
|
30
|
+
paneCount: panes.length
|
|
31
|
+
});
|
|
32
|
+
const splitPaneStyle = {
|
|
33
|
+
...style,
|
|
34
|
+
"--vuuSplitPane-align": parseAlignment(align),
|
|
35
|
+
"--vuuSplitPane-direction": flexDirection,
|
|
36
|
+
"--vuuSplitPane-gap": parseSpacing(flexGap),
|
|
37
|
+
"--vuuSplitPane-justify": parseAlignment(justify),
|
|
38
|
+
"--vuuSplitPane-margin": parseSpacing(flexMargin),
|
|
39
|
+
"--vuuSplitPane-padding": parseSpacing(flexPadding),
|
|
40
|
+
"--vuuSplitPane-splitterSize": void 0 === splitterSize ? void 0 : `${splitterSize}px`
|
|
41
|
+
};
|
|
42
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
43
|
+
...htmlAttributes,
|
|
44
|
+
className: clsx(classBase, `${classBase}-${flexDirection}`, className),
|
|
45
|
+
ref: useForkRef(rootRef, forwardedRef),
|
|
46
|
+
style: splitPaneStyle,
|
|
47
|
+
children: [
|
|
48
|
+
panes[0],
|
|
49
|
+
2 === panes.length ? /*#__PURE__*/ jsx(Splitter, {
|
|
50
|
+
direction: flexDirection,
|
|
51
|
+
onResize: resize,
|
|
52
|
+
onResizeEnd: endResize,
|
|
53
|
+
onResizeStart: beginResize,
|
|
54
|
+
position: splitterPosition
|
|
55
|
+
}) : null,
|
|
56
|
+
panes[1]
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
export { SplitPane_SplitPane as SplitPane };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import { useCallback, useRef, useState } from "react";
|
|
4
|
+
const classBase = "vuuSplitPane-splitter";
|
|
5
|
+
const KEYBOARD_STEP = 1;
|
|
6
|
+
const KEYBOARD_STEP_LARGE = 10;
|
|
7
|
+
const Splitter = ({ className, direction, onResize, onResizeEnd, onResizeStart, position, ...htmlAttributes })=>{
|
|
8
|
+
const startPosRef = useRef(void 0);
|
|
9
|
+
const [active, setActive] = useState(false);
|
|
10
|
+
const isColumn = "column" === direction;
|
|
11
|
+
const getPointerPos = useCallback((e)=>isColumn ? e.clientY : e.clientX, [
|
|
12
|
+
isColumn
|
|
13
|
+
]);
|
|
14
|
+
const handlePointerDown = useCallback((e)=>{
|
|
15
|
+
if (0 === e.button && onResizeStart()) {
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
e.currentTarget.focus();
|
|
18
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
19
|
+
startPosRef.current = getPointerPos(e);
|
|
20
|
+
setActive(true);
|
|
21
|
+
}
|
|
22
|
+
}, [
|
|
23
|
+
getPointerPos,
|
|
24
|
+
onResizeStart
|
|
25
|
+
]);
|
|
26
|
+
const handlePointerMove = useCallback((e)=>{
|
|
27
|
+
if (void 0 !== startPosRef.current) onResize(getPointerPos(e) - startPosRef.current);
|
|
28
|
+
}, [
|
|
29
|
+
getPointerPos,
|
|
30
|
+
onResize
|
|
31
|
+
]);
|
|
32
|
+
const handlePointerEnd = useCallback(()=>{
|
|
33
|
+
if (void 0 !== startPosRef.current) {
|
|
34
|
+
startPosRef.current = void 0;
|
|
35
|
+
setActive(false);
|
|
36
|
+
onResizeEnd();
|
|
37
|
+
}
|
|
38
|
+
}, [
|
|
39
|
+
onResizeEnd
|
|
40
|
+
]);
|
|
41
|
+
const handleKeyDown = useCallback((e)=>{
|
|
42
|
+
const step = e.shiftKey ? KEYBOARD_STEP_LARGE : KEYBOARD_STEP;
|
|
43
|
+
const [decrementKey, incrementKey] = isColumn ? [
|
|
44
|
+
"ArrowUp",
|
|
45
|
+
"ArrowDown"
|
|
46
|
+
] : [
|
|
47
|
+
"ArrowLeft",
|
|
48
|
+
"ArrowRight"
|
|
49
|
+
];
|
|
50
|
+
const distance = e.key === decrementKey ? -step : e.key === incrementKey ? step : "Home" === e.key ? -1 / 0 : "End" === e.key ? 1 / 0 : void 0;
|
|
51
|
+
if (void 0 !== distance && onResizeStart()) {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
onResize(distance);
|
|
54
|
+
onResizeEnd();
|
|
55
|
+
}
|
|
56
|
+
}, [
|
|
57
|
+
isColumn,
|
|
58
|
+
onResize,
|
|
59
|
+
onResizeEnd,
|
|
60
|
+
onResizeStart
|
|
61
|
+
]);
|
|
62
|
+
return /*#__PURE__*/ jsx("div", {
|
|
63
|
+
"aria-label": "Resize",
|
|
64
|
+
...htmlAttributes,
|
|
65
|
+
"aria-orientation": isColumn ? "horizontal" : "vertical",
|
|
66
|
+
"aria-valuemax": 100,
|
|
67
|
+
"aria-valuemin": 0,
|
|
68
|
+
"aria-valuenow": position,
|
|
69
|
+
className: clsx(classBase, className, {
|
|
70
|
+
[`${classBase}-active`]: active
|
|
71
|
+
}),
|
|
72
|
+
onKeyDown: handleKeyDown,
|
|
73
|
+
onLostPointerCapture: handlePointerEnd,
|
|
74
|
+
onPointerCancel: handlePointerEnd,
|
|
75
|
+
onPointerDown: handlePointerDown,
|
|
76
|
+
onPointerMove: handlePointerMove,
|
|
77
|
+
onPointerUp: handlePointerEnd,
|
|
78
|
+
role: "separator",
|
|
79
|
+
tabIndex: 0
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
export { Splitter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./SplitPane.js";
|