@vuu-ui/vuu-ui-controls 4.0.0-alpha.2 → 4.0.0-alpha.21
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 +15 -14
- package/src/drag-drop/Draggable.css.js +2 -2
- package/src/expando-input/ExpandoInput.css.js +1 -1
- package/src/icon-button/ToggleIconButton.css.js +1 -1
- package/src/index.js +1 -1
- package/src/item-picker/ItemPicker.css.js +1 -5
- package/src/item-picker/ItemPicker.js +69 -60
- package/src/item-picker/useItemPicker.js +2 -5
- package/src/price-ticker/PriceTicker.css.js +4 -4
- 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/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 +1 -1
- package/types/icon-button/Icon.d.ts +1 -1
- package/types/icon-button/ToggleIconButton.d.ts +1 -1
- package/types/index.d.ts +4 -4
- package/types/instrument-picker/SearchCell.d.ts +1 -1
- package/types/instrument-picker/TablePicker.d.ts +1 -1
- package/types/item-picker/ItemPicker.d.ts +25 -7
- package/types/item-picker/useItemPicker.d.ts +3 -6
- package/types/modal-provider/ModalProvider.d.ts +1 -1
- package/types/price-ticker/PriceTicker.d.ts +1 -1
- package/types/prompt/Prompt.d.ts +1 -1
- 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 +1 -1
- 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,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0-alpha.
|
|
2
|
+
"version": "4.0.0-alpha.21",
|
|
3
3
|
"description": "VUU UI Controls",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"author": "heswell",
|
|
@@ -11,20 +11,20 @@
|
|
|
11
11
|
"type-defs": "node ../../scripts/build-type-defs.mjs"
|
|
12
12
|
},
|
|
13
13
|
"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.
|
|
14
|
+
"@vuu-ui/vuu-data-types": "4.0.0-alpha.21",
|
|
15
|
+
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.21",
|
|
16
|
+
"@vuu-ui/vuu-table-types": "4.0.0-alpha.21"
|
|
17
17
|
},
|
|
18
18
|
"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-popups": "4.0.0-alpha.
|
|
22
|
-
"@vuu-ui/vuu-table": "4.0.0-alpha.
|
|
23
|
-
"@vuu-ui/vuu-utils": "4.0.0-alpha.
|
|
24
|
-
"@salt-ds/core": "1.
|
|
25
|
-
"@salt-ds/icons": "1.
|
|
26
|
-
"@salt-ds/styles": "0.
|
|
27
|
-
"@salt-ds/window": "0.1.
|
|
19
|
+
"@vuu-ui/vuu-context-menu": "4.0.0-alpha.21",
|
|
20
|
+
"@vuu-ui/vuu-data-react": "4.0.0-alpha.21",
|
|
21
|
+
"@vuu-ui/vuu-popups": "4.0.0-alpha.21",
|
|
22
|
+
"@vuu-ui/vuu-table": "4.0.0-alpha.21",
|
|
23
|
+
"@vuu-ui/vuu-utils": "4.0.0-alpha.21",
|
|
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": {
|
|
@@ -42,8 +42,9 @@
|
|
|
42
42
|
],
|
|
43
43
|
"exports": {
|
|
44
44
|
".": {
|
|
45
|
+
"types": "./types/index.d.ts",
|
|
45
46
|
"import": "./src/index.js",
|
|
46
|
-
"
|
|
47
|
+
"default": "./src/index.js"
|
|
47
48
|
}
|
|
48
49
|
},
|
|
49
50
|
"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;
|
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,7 +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 { ModalProvider, useModal } from "./modal-provider/ModalProvider.js";
|
|
29
29
|
export { Prompt } from "./prompt/Prompt.js";
|
|
30
30
|
export { SortableList, SortableOption } from "./sortable-list/SortableList.js";
|
|
31
31
|
export { TimeInput } from "./time-input/TimeInput.js";
|
|
@@ -11,10 +11,6 @@ const css = `
|
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
container-type: inline-size;
|
|
13
13
|
|
|
14
|
-
&.vuuItemPicker-withCalculated {
|
|
15
|
-
--label-margin-left: 8px;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
& .saltListBox {
|
|
19
15
|
background-color: inherit;
|
|
20
16
|
}
|
|
@@ -39,7 +35,7 @@ const css = `
|
|
|
39
35
|
}
|
|
40
36
|
|
|
41
37
|
& .vuuHighlight {
|
|
42
|
-
color: var(--
|
|
38
|
+
color: var(--salt-color-blue-400);
|
|
43
39
|
text-decoration: underline;
|
|
44
40
|
}
|
|
45
41
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Input, ListBox, Option } from "@salt-ds/core";
|
|
3
3
|
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
4
4
|
import { useWindow } from "@salt-ds/window";
|
|
5
5
|
import { applyHighlighting } from "@vuu-ui/vuu-table";
|
|
@@ -32,7 +32,7 @@ const useSorting = (id, index)=>{
|
|
|
32
32
|
ref
|
|
33
33
|
};
|
|
34
34
|
};
|
|
35
|
-
const
|
|
35
|
+
const DefaultSelectedListItem = ({ className: classNameProp, index, item, onRemove, searchPattern = "", ...optionProps })=>{
|
|
36
36
|
const { handleRef, ref } = useSorting(item.name, index);
|
|
37
37
|
const value = getItemLabel(item);
|
|
38
38
|
const valueWithHighlighting = applyHighlighting(value, searchPattern);
|
|
@@ -73,7 +73,7 @@ const SelectedListItem = ({ className: classNameProp, index, item, onRemove, sea
|
|
|
73
73
|
]
|
|
74
74
|
});
|
|
75
75
|
};
|
|
76
|
-
const
|
|
76
|
+
const DefaultAvailableListItem = ({ className: classNameProp, index, item, onAdd, searchPattern = "", disabled, ...optionProps })=>{
|
|
77
77
|
const value = getItemLabel(item);
|
|
78
78
|
const valueWithHighlighting = applyHighlighting(value, searchPattern);
|
|
79
79
|
return /*#__PURE__*/ jsxs(Option, {
|
|
@@ -98,7 +98,14 @@ const AvailableListItem = ({ className: classNameProp, index, item, onAdd, searc
|
|
|
98
98
|
]
|
|
99
99
|
});
|
|
100
100
|
};
|
|
101
|
-
const
|
|
101
|
+
const getOptionName = (option)=>{
|
|
102
|
+
if (option) {
|
|
103
|
+
const { name } = option.dataset;
|
|
104
|
+
if (name) return name;
|
|
105
|
+
}
|
|
106
|
+
throw Error("[ItemPicker] list option has no data-name");
|
|
107
|
+
};
|
|
108
|
+
const ItemPicker_ItemPicker = /*#__PURE__*/ forwardRef(function({ AvailableListItem = DefaultAvailableListItem, SelectedListItem = DefaultSelectedListItem, className, itemTypeName = 'Item', searchForm = true, allItems, layout = 'v-selected-available', selectedItems, maxSelections, onSelectedItemsChange, onSelectionChange, selected = NO_SELECTION, ...htmlAttributes }, forwardedRef) {
|
|
102
109
|
const targetWindow = useWindow();
|
|
103
110
|
useComponentCssInjection({
|
|
104
111
|
testId: "vuu-item-picker",
|
|
@@ -117,13 +124,6 @@ const ItemPicker_ItemPicker = /*#__PURE__*/ forwardRef(function({ className, ite
|
|
|
117
124
|
maxSelections
|
|
118
125
|
});
|
|
119
126
|
const listRef = useRef(null);
|
|
120
|
-
const getOptionName = (option)=>{
|
|
121
|
-
if (option) {
|
|
122
|
-
const { name } = option.dataset;
|
|
123
|
-
if (name) return name;
|
|
124
|
-
}
|
|
125
|
-
throw Error("[ItemPicker] list option has no data-name");
|
|
126
|
-
};
|
|
127
127
|
const handleDragEnd = useCallback(()=>{
|
|
128
128
|
setTimeout(()=>{
|
|
129
129
|
const listItems = listRef.current?.querySelectorAll(".saltOption");
|
|
@@ -133,13 +133,56 @@ const ItemPicker_ItemPicker = /*#__PURE__*/ forwardRef(function({ className, ite
|
|
|
133
133
|
}
|
|
134
134
|
}, 300);
|
|
135
135
|
}, [
|
|
136
|
-
|
|
137
|
-
selectedItemsFiltered
|
|
136
|
+
onReorderSelectedItems
|
|
138
137
|
]);
|
|
139
138
|
const searchPlaceholderText = `Find ${singularForm(itemTypeName)}`;
|
|
140
139
|
const maxSelectionsSubHeading = maxSelections ? `(${maxSelections} max)` : "";
|
|
141
140
|
const selectedItemsHeading = `${selectedItemsCount} ${1 === selectedItemsCount ? singularForm(itemTypeName) : pluralForm(itemTypeName)} in view ${maxSelectionsSubHeading}`;
|
|
142
141
|
const availableItemsHeading = `${availableItemsCount} available ${1 === availableItemsCount ? singularForm(itemTypeName) : pluralForm(itemTypeName)}`;
|
|
142
|
+
const selectedList = /*#__PURE__*/ jsxs(Fragment, {
|
|
143
|
+
children: [
|
|
144
|
+
/*#__PURE__*/ jsx("div", {
|
|
145
|
+
className: `${classBase}-sectionHeader`,
|
|
146
|
+
children: selectedItemsHeading
|
|
147
|
+
}),
|
|
148
|
+
/*#__PURE__*/ jsx(DragDropProvider, {
|
|
149
|
+
onDragEnd: handleDragEnd,
|
|
150
|
+
children: /*#__PURE__*/ jsx(ListBox, {
|
|
151
|
+
className: `${classBase}-selectedList`,
|
|
152
|
+
onSelectionChange: onSelectionChange,
|
|
153
|
+
ref: listRef,
|
|
154
|
+
selected: selected,
|
|
155
|
+
children: selectedItemsFiltered.map((item, index)=>/*#__PURE__*/ jsx(SelectedListItem, {
|
|
156
|
+
item: item,
|
|
157
|
+
index: index,
|
|
158
|
+
onRemove: onRemoveItemFromSelectedList,
|
|
159
|
+
searchPattern: searchText.toLowerCase(),
|
|
160
|
+
value: item
|
|
161
|
+
}, item.name))
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
]
|
|
165
|
+
});
|
|
166
|
+
const availableList = /*#__PURE__*/ jsxs(Fragment, {
|
|
167
|
+
children: [
|
|
168
|
+
/*#__PURE__*/ jsx("div", {
|
|
169
|
+
className: clsx(`${classBase}-sectionHeader`, `${classBase}-availableHeader`),
|
|
170
|
+
children: availableItemsHeading
|
|
171
|
+
}),
|
|
172
|
+
/*#__PURE__*/ jsx(ListBox, {
|
|
173
|
+
className: `${classBase}-availableList`,
|
|
174
|
+
selected: NO_SELECTION,
|
|
175
|
+
children: availableItemsFiltered.map((item, index)=>/*#__PURE__*/ jsx(AvailableListItem, {
|
|
176
|
+
item: item,
|
|
177
|
+
index: index,
|
|
178
|
+
onAdd: onAddItemToSelectedList,
|
|
179
|
+
searchPattern: searchText.toLowerCase(),
|
|
180
|
+
value: item,
|
|
181
|
+
disabled: selectedItemsCount === maxSelections
|
|
182
|
+
}, item.name))
|
|
183
|
+
})
|
|
184
|
+
]
|
|
185
|
+
});
|
|
143
186
|
return /*#__PURE__*/ jsxs("div", {
|
|
144
187
|
...htmlAttributes,
|
|
145
188
|
className: clsx(classBase, className),
|
|
@@ -166,54 +209,20 @@ const ItemPicker_ItemPicker = /*#__PURE__*/ forwardRef(function({ className, ite
|
|
|
166
209
|
onChange: onChangeSearchInput
|
|
167
210
|
})
|
|
168
211
|
}),
|
|
169
|
-
/*#__PURE__*/
|
|
212
|
+
/*#__PURE__*/ jsx("div", {
|
|
170
213
|
className: `${classBase}-scrollContainer vuuScrollable`,
|
|
171
|
-
children:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
ref: listRef,
|
|
182
|
-
selected: selected,
|
|
183
|
-
children: selectedItemsFiltered.map((item, index)=>/*#__PURE__*/ jsx(SelectedListItem, {
|
|
184
|
-
item: item,
|
|
185
|
-
index: index,
|
|
186
|
-
onRemove: onRemoveItemFromSelectedList,
|
|
187
|
-
searchPattern: searchText.toLowerCase(),
|
|
188
|
-
value: item
|
|
189
|
-
}, item.name))
|
|
190
|
-
})
|
|
191
|
-
}),
|
|
192
|
-
/*#__PURE__*/ jsx("div", {
|
|
193
|
-
className: clsx(`${classBase}-sectionHeader`, `${classBase}-availableHeader`),
|
|
194
|
-
children: availableItemsHeading
|
|
195
|
-
}),
|
|
196
|
-
/*#__PURE__*/ jsx(ListBox, {
|
|
197
|
-
className: `${classBase}-availableList`,
|
|
198
|
-
selected: NO_SELECTION,
|
|
199
|
-
children: availableItemsFiltered.map((item, index)=>/*#__PURE__*/ jsx(AvailableListItem, {
|
|
200
|
-
item: item,
|
|
201
|
-
index: index,
|
|
202
|
-
onAdd: onAddItemToSelectedList,
|
|
203
|
-
searchPattern: searchText.toLowerCase(),
|
|
204
|
-
value: item,
|
|
205
|
-
disabled: selectedItemsCount === maxSelections
|
|
206
|
-
}, item.name))
|
|
207
|
-
})
|
|
208
|
-
]
|
|
209
|
-
}),
|
|
210
|
-
createCustomItemProps ? /*#__PURE__*/ jsx("div", {
|
|
211
|
-
className: `${classBase}-item-buttons`,
|
|
212
|
-
children: /*#__PURE__*/ jsx(Button, {
|
|
213
|
-
onClick: createCustomItemProps.onClickCreateCustomItem,
|
|
214
|
-
children: createCustomItemProps.buttonLabel
|
|
214
|
+
children: 'v-selected-available' === layout ? /*#__PURE__*/ jsxs(Fragment, {
|
|
215
|
+
children: [
|
|
216
|
+
selectedList,
|
|
217
|
+
availableList
|
|
218
|
+
]
|
|
219
|
+
}) : /*#__PURE__*/ jsxs(Fragment, {
|
|
220
|
+
children: [
|
|
221
|
+
availableList,
|
|
222
|
+
selectedList
|
|
223
|
+
]
|
|
215
224
|
})
|
|
216
|
-
})
|
|
225
|
+
})
|
|
217
226
|
]
|
|
218
227
|
});
|
|
219
228
|
});
|
|
@@ -55,10 +55,7 @@ const useItemPicker = ({ allItems, selectedItems, maxSelections, onSelectedItems
|
|
|
55
55
|
selectedItems,
|
|
56
56
|
onSelectedItemsChange
|
|
57
57
|
]);
|
|
58
|
-
const getSelectedItemsFiltered =
|
|
59
|
-
selectedItems,
|
|
60
|
-
searchPattern
|
|
61
|
-
]);
|
|
58
|
+
const getSelectedItemsFiltered = (latestSelectedItems, latestSearchPattern)=>filterItems(latestSelectedItems, latestSearchPattern);
|
|
62
59
|
const getAvailableItemsFiltered = useMemo(()=>filterItems(allItems, searchPattern).filter(({ name })=>-1 === selectedItems.findIndex((item)=>item.name === name)).toSorted(byItemName), [
|
|
63
60
|
allItems,
|
|
64
61
|
selectedItems,
|
|
@@ -71,7 +68,7 @@ const useItemPicker = ({ allItems, selectedItems, maxSelections, onSelectedItems
|
|
|
71
68
|
return {
|
|
72
69
|
selectedItemsCount: selectedItems.length,
|
|
73
70
|
availableItemsCount: getAvailableItemsCount,
|
|
74
|
-
selectedItemsFiltered: getSelectedItemsFiltered,
|
|
71
|
+
selectedItemsFiltered: getSelectedItemsFiltered(selectedItems, searchPattern),
|
|
75
72
|
availableItemsFiltered: getAvailableItemsFiltered,
|
|
76
73
|
searchText: searchPattern,
|
|
77
74
|
onChangeSearchInput: handleChangeSearchInput,
|
|
@@ -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
|
|
|
@@ -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";
|