@vuu-ui/vuu-ui-controls 4.0.0-alpha.3 → 4.0.0-alpha.30

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 (63) hide show
  1. package/package.json +17 -15
  2. package/src/drag-drop/Draggable.css.js +2 -2
  3. package/src/drag-drop/useDragDrop.js +7 -1
  4. package/src/expando-input/ExpandoInput.css.js +1 -1
  5. package/src/hover-overlay/HoverOverlay.css.js +8 -0
  6. package/src/hover-overlay/HoverOverlay.js +87 -38
  7. package/src/icon-button/ToggleIconButton.css.js +1 -1
  8. package/src/index.js +1 -2
  9. package/src/instrument-picker/TablePicker.css.js +1 -0
  10. package/src/item-picker/ItemPicker.css.js +1 -1
  11. package/src/item-picker/useItemPicker.js +5 -1
  12. package/src/price-ticker/PriceTicker.css.js +4 -4
  13. package/src/prompt/Prompt.css.js +1 -0
  14. package/src/split-pane/SplitPane.css.js +82 -0
  15. package/src/split-pane/SplitPane.js +60 -0
  16. package/src/split-pane/Splitter.js +82 -0
  17. package/src/split-pane/index.js +1 -0
  18. package/src/split-pane/useSplitPane.js +101 -0
  19. package/src/table-search/SearchCell.css.js +4 -2
  20. package/src/table-search/SearchCell.js +3 -2
  21. package/src/table-search/TableSearch.css.js +4 -0
  22. package/src/table-search/TableSearch.js +3 -1
  23. package/src/table-search/useTableSearch.js +14 -6
  24. package/src/tabstrip/Tab.css.js +3 -3
  25. package/src/tabstrip/Tabstrip.css.js +2 -2
  26. package/src/time-input/MaskedInput.js +176 -156
  27. package/src/time-input/TimeInput.css.js +41 -18
  28. package/src/time-input/TimeInput.js +25 -14
  29. package/src/time-input/useTimeInput.js +57 -47
  30. package/src/toolbar/Toolbar.css.js +1 -1
  31. package/src/vuu-date-picker/VuuDatePicker.js +46 -52
  32. package/src/vuu-time-picker/VuuTimePicker.js +6 -5
  33. package/types/context-panel-provider/ContextPanelProvider.d.ts +1 -1
  34. package/types/drag-drop/DragDropProvider.d.ts +1 -1
  35. package/types/hover-overlay/HoverOverlay.d.ts +7 -1
  36. package/types/icon-button/Icon.d.ts +1 -1
  37. package/types/icon-button/ToggleIconButton.d.ts +1 -1
  38. package/types/index.d.ts +5 -5
  39. package/types/instrument-picker/SearchCell.d.ts +1 -1
  40. package/types/instrument-picker/TablePicker.d.ts +1 -1
  41. package/types/item-picker/useItemPicker.d.ts +2 -2
  42. package/types/modal-provider/ModalProvider.d.ts +1 -1
  43. package/types/price-ticker/PriceTicker.d.ts +1 -1
  44. package/types/prompt/Prompt.d.ts +3 -3
  45. package/types/sortable-list/SortableList.d.ts +2 -2
  46. package/types/split-button/useSplitButton.d.ts +12 -12
  47. package/types/split-pane/SplitPane.d.ts +44 -0
  48. package/types/split-pane/Splitter.d.ts +10 -0
  49. package/types/split-pane/index.d.ts +2 -0
  50. package/types/split-pane/useSplitPane.d.ts +18 -0
  51. package/types/table-search/SearchCell.d.ts +1 -1
  52. package/types/table-search/TableSearch.d.ts +2 -1
  53. package/types/table-search/useTableSearch.d.ts +2 -2
  54. package/types/tabstrip/TabMenu.d.ts +1 -1
  55. package/types/tabstrip/Tabstrip.d.ts +1 -2
  56. package/types/time-input/MaskedInput.d.ts +60 -10
  57. package/types/time-input/TimeInput.d.ts +4 -3
  58. package/types/time-input/useTimeInput.d.ts +24 -5
  59. package/types/toolbar/Toolbar.d.ts +1 -2
  60. package/types/vuu-date-picker/VuuDatePicker.d.ts +19 -3
  61. package/types/vuu-time-picker/VuuTimePicker.d.ts +8 -6
  62. package/types/vuu-typeahead-input/VuuTypeaheadInput.d.ts +1 -1
  63. package/src/modal-provider/ModalProvider.js +0 -147
package/package.json CHANGED
@@ -1,30 +1,30 @@
1
1
  {
2
- "version": "4.0.0-alpha.3",
2
+ "version": "4.0.0-alpha.30",
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.3",
15
- "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.3",
16
- "@vuu-ui/vuu-table-types": "4.0.0-alpha.3"
13
+ "@vuu-ui/vuu-data-types": "4.0.0-alpha.30",
14
+ "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.30",
15
+ "@vuu-ui/vuu-table-types": "4.0.0-alpha.30"
17
16
  },
18
17
  "dependencies": {
19
- "@vuu-ui/vuu-context-menu": "4.0.0-alpha.3",
20
- "@vuu-ui/vuu-data-react": "4.0.0-alpha.3",
21
- "@vuu-ui/vuu-popups": "4.0.0-alpha.3",
22
- "@vuu-ui/vuu-table": "4.0.0-alpha.3",
23
- "@vuu-ui/vuu-utils": "4.0.0-alpha.3",
24
- "@salt-ds/core": "1.67.0",
25
- "@salt-ds/icons": "1.16.0",
26
- "@salt-ds/styles": "0.2.1",
27
- "@salt-ds/window": "0.1.1",
18
+ "@vuu-ui/vuu-context-menu": "4.0.0-alpha.30",
19
+ "@vuu-ui/vuu-data-react": "4.0.0-alpha.30",
20
+ "@vuu-ui/vuu-layout": "4.0.0-alpha.30",
21
+ "@vuu-ui/vuu-popups": "4.0.0-alpha.30",
22
+ "@vuu-ui/vuu-table": "4.0.0-alpha.30",
23
+ "@vuu-ui/vuu-utils": "4.0.0-alpha.30",
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
- "types": "./types/index.d.ts"
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-palette-accent-background);
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-palette-accent-background);
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: constrainRect(draggableRect, containerRect),
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)
@@ -31,7 +31,7 @@ const css = `
31
31
  }
32
32
 
33
33
  .vuuExpandoInput-error {
34
- border-color: var(--vuu-color-red-50);
34
+ border-color: var(--salt-color-red-500);
35
35
  }
36
36
 
37
37
  .vuuExpandoInput .saltInput {
@@ -0,0 +1,8 @@
1
+ const css = `
2
+ .vuuHoverOverlay-panel {
3
+ --saltOverlay-borderColor: var(--salt-container-primary-borderColor);
4
+ }
5
+
6
+
7
+ `;
8
+ export default css;
@@ -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
- const HoverOverlay = ({ children, open: openProp = false, onOpenChange, placement = "right", trigger })=>{
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
- const handleOverlayMouseEnter = useCallback(()=>{
25
- if (hideHandle.current) {
26
- clearTimeout(hideHandle.current);
27
- hideHandle.current = void 0;
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
- setOpen
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
- }, 400);
43
- if (hideHandle.current) {
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
- if (showHandle.current) {
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
- setOpen
98
+ clearShowTimer
60
99
  ]);
61
100
  const handleClick = useCallback(()=>{
62
- if (showHandle.current) {
63
- clearTimeout(showHandle.current);
64
- showHandle.current = void 0;
65
- } else if (isOpen.current) setOpen(false);
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: onOpenChange,
121
+ onOpenChange: handleOpenChange,
72
122
  open: open,
73
123
  children: [
74
124
  /*#__PURE__*/ jsx(OverlayTrigger, {
75
125
  children: /*#__PURE__*/ jsx("div", {
76
- onClick: handleClick,
77
- onMouseEnter: handleMouseEnter,
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 };
@@ -37,7 +37,7 @@ const css = `
37
37
  .vuuTableGroupCell:hover {
38
38
  & .vuuToggleIconButton {
39
39
  & .vuuIcon:after {
40
- --vuu-icon-color: var(--salt-palette-interact-cta-background-hover);
40
+ --vuu-icon-color: var(--salt-sentiment-accent-background);
41
41
  }
42
42
  }
43
43
  }
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";
@@ -7,6 +7,7 @@ const css = `
7
7
  }
8
8
 
9
9
  .vuuTablePicker-floating-table {
10
+ background: var(--salt-container-primary-background);
10
11
  border: solid 1px var(--salt-container-secondary-borderColor);
11
12
  padding: var(--salt-spacing-100) 0;
12
13
  z-index: var(--salt-zIndex-popout);
@@ -35,7 +35,7 @@ const css = `
35
35
  }
36
36
 
37
37
  & .vuuHighlight {
38
- color: var(--vuu-color-blue-40);
38
+ color: var(--salt-color-blue-400);
39
39
  text-decoration: underline;
40
40
  }
41
41
 
@@ -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 = ({ name: n1 }, { name: n2 })=>n1 > n2 ? 1 : n2 > n1 ? -1 : 0;
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(--vuu-color-green-50);
19
- color: var(--vuu-color-green-50);
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(--vuu-color-red-50);
26
- color: var(--vuu-color-red-50);
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
 
@@ -1,5 +1,6 @@
1
1
  const css = `
2
2
  .vuuPrompt {
3
+ max-width: var(--vuuPrompt-maxWidth);
3
4
  min-height: var(--vuuPrompt-minHeight, 257px);
4
5
  min-width: var(--vuuPrompt-minWidth, 380px);
5
6
 
@@ -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";