@vuu-ui/vuu-table 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 +12 -13
- package/src/CellFocusState.mjs +25 -0
- package/src/Row.mjs +83 -0
- package/src/Table.css.js +441 -0
- package/src/Table.mjs +297 -0
- package/src/VirtualColSpan.mjs +12 -0
- package/src/applyHighlighting.mjs +28 -0
- package/src/bulk-edit/BulkEditPanel.css.js +27 -0
- package/src/bulk-edit/BulkEditPanel.mjs +77 -0
- package/src/bulk-edit/ColumnCascadingUpdateEditor.css.js +86 -0
- package/src/bulk-edit/ColumnCascadingUpdateEditor.mjs +59 -0
- package/src/bulk-edit/InsertNewRowEditor.css.js +86 -0
- package/src/bulk-edit/InsertNewRowEditor.mjs +59 -0
- package/src/bulk-edit/useBulkEditPanel.mjs +61 -0
- package/src/bulk-edit/useColumnCascadingEditor.mjs +124 -0
- package/src/cell-block/CellBlock.css.js +95 -0
- package/src/cell-block/CellBlock.mjs +32 -0
- package/src/cell-block/cellblock-utils.mjs +114 -0
- package/src/cell-block/useCellBlockSelection.mjs +245 -0
- package/src/cell-renderers/checkbox-cell/CheckboxCell.css.js +16 -0
- package/src/cell-renderers/checkbox-cell/CheckboxCell.mjs +56 -0
- package/src/cell-renderers/checkbox-cell/index.mjs +1 -0
- package/src/cell-renderers/checkbox-row-selector/CheckboxRowSelectorCell.css.js +19 -0
- package/src/cell-renderers/checkbox-row-selector/CheckboxRowSelectorCell.mjs +34 -0
- package/src/cell-renderers/checkbox-row-selector/index.mjs +1 -0
- package/src/cell-renderers/index.mjs +4 -0
- package/src/cell-renderers/input-cell/InputCell.css.js +81 -0
- package/src/cell-renderers/input-cell/InputCell.mjs +73 -0
- package/src/cell-renderers/input-cell/index.mjs +1 -0
- package/src/cell-renderers/input-cell/useInputCell.mjs +199 -0
- package/src/cell-renderers/toggle-cell/ToggleCell.css.js +31 -0
- package/src/cell-renderers/toggle-cell/ToggleCell.mjs +47 -0
- package/src/cell-renderers/toggle-cell/index.mjs +1 -0
- package/src/column-header-pill/ColumnHeaderPill.css.js +34 -0
- package/src/column-header-pill/ColumnHeaderPill.mjs +39 -0
- package/src/column-header-pill/GroupColumnPill.css.js +10 -0
- package/src/column-header-pill/GroupColumnPill.mjs +33 -0
- package/src/column-header-pill/SortIndicator.css.js +15 -0
- package/src/column-header-pill/SortIndicator.mjs +29 -0
- package/src/column-header-pill/index.mjs +3 -0
- package/src/column-resizing/ColumnResizer.css.js +32 -0
- package/src/column-resizing/ColumnResizer.mjs +69 -0
- package/src/column-resizing/index.mjs +2 -0
- package/src/column-resizing/useTableColumnResize.mjs +57 -0
- package/src/data-row/DataRow.mjs +298 -0
- package/src/header-cell/GroupHeaderCell.css.js +91 -0
- package/src/header-cell/GroupHeaderCell.mjs +98 -0
- package/src/header-cell/HeaderCell.css.js +182 -0
- package/src/header-cell/HeaderCell.mjs +126 -0
- package/src/header-cell/index.mjs +2 -0
- package/src/index.mjs +20 -0
- package/src/pagination/PaginationControl.css.js +18 -0
- package/src/pagination/PaginationControl.mjs +34 -0
- package/src/pagination/index.mjs +1 -0
- package/src/pagination/usePagination.mjs +29 -0
- package/src/table-cell/TableCell.css.js +67 -0
- package/src/table-cell/TableCell.mjs +54 -0
- package/src/table-cell/TableGroupCell.css.js +91 -0
- package/src/table-cell/TableGroupCell.mjs +61 -0
- package/src/table-cell/index.mjs +2 -0
- package/src/table-config/useTableConfig.mjs +49 -0
- package/src/table-config.mjs +38 -0
- package/src/table-data-source/DataRowMovingWindow.mjs +66 -0
- package/src/table-data-source/useDataSource.mjs +177 -0
- package/src/table-dom-utils.mjs +162 -0
- package/src/table-header/HeaderProvider.mjs +14 -0
- package/src/table-header/TableHeader.mjs +182 -0
- package/src/table-header/index.mjs +2 -0
- package/src/table-header/useTableHeader.mjs +69 -0
- package/src/useCell.mjs +22 -0
- package/src/useCellEditing.mjs +58 -0
- package/src/useCellFocus.mjs +112 -0
- package/src/useControlledTableNavigation.mjs +34 -0
- package/src/useEditableCell.mjs +18 -0
- package/src/useInitialValue.mjs +6 -0
- package/src/useKeyboardNavigation.mjs +275 -0
- package/src/useMeasuredHeight.mjs +44 -0
- package/src/useResizeObserver.mjs +118 -0
- package/src/useRowClassNameGenerators.mjs +21 -0
- package/src/useSelection.mjs +101 -0
- package/src/useTable.mjs +588 -0
- package/src/useTableContextMenu.mjs +54 -0
- package/src/useTableModel.mjs +344 -0
- package/src/useTableScroll.mjs +382 -0
- package/src/useTableViewport.mjs +120 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Checkbox, useForkRef } from "@salt-ds/core";
|
|
3
|
+
import { ColumnMenu } from "@vuu-ui/vuu-table-extras";
|
|
4
|
+
import { isTypeDescriptor, useSortable } from "@vuu-ui/vuu-utils";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
7
|
+
import { SortIndicator } from "../column-header-pill/index.mjs";
|
|
8
|
+
import { ColumnResizer, useTableColumnResize } from "../column-resizing/index.mjs";
|
|
9
|
+
import { useCell } from "../useCell.mjs";
|
|
10
|
+
const classBase = "vuuTableHeaderCell";
|
|
11
|
+
const doNothing = ()=>({
|
|
12
|
+
ref: {
|
|
13
|
+
current: null
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const HeaderCell = ({ allowDragColumnHeader = true, allowSelectAll, allRowsSelected, className: classNameProp, column, id, index, onCheckBoxColumnHeaderClick, onClick, onResize, showColumnHeaderMenus = true, ...htmlAttributes })=>{
|
|
17
|
+
const dragDropSortHook = allowDragColumnHeader ? useSortable : doNothing;
|
|
18
|
+
const { ref: sortableRef } = dragDropSortHook({
|
|
19
|
+
id,
|
|
20
|
+
index
|
|
21
|
+
});
|
|
22
|
+
const { allowColumnHeaderMenu = true, HeaderCellContentRenderer, HeaderCellLabelRenderer } = column;
|
|
23
|
+
const rootRef = useRef(null);
|
|
24
|
+
const { isResizing, ...resizeProps } = useTableColumnResize({
|
|
25
|
+
column,
|
|
26
|
+
onResize,
|
|
27
|
+
rootRef
|
|
28
|
+
});
|
|
29
|
+
const handleCheckBoxClick = useCallback((e)=>{
|
|
30
|
+
e.stopPropagation();
|
|
31
|
+
onCheckBoxColumnHeaderClick?.();
|
|
32
|
+
}, [
|
|
33
|
+
onCheckBoxColumnHeaderClick
|
|
34
|
+
]);
|
|
35
|
+
const headerItems = useMemo(()=>{
|
|
36
|
+
const renderCheckbox = allowSelectAll && column.isSystemColumn && isTypeDescriptor(column.type) && "checkbox" === column.type.name;
|
|
37
|
+
if (renderCheckbox) return [
|
|
38
|
+
/*#__PURE__*/ jsx(Checkbox, {
|
|
39
|
+
checked: allRowsSelected,
|
|
40
|
+
className: "vuuCheckboxRowSelector",
|
|
41
|
+
onClick: handleCheckBoxClick
|
|
42
|
+
}, "checkbox")
|
|
43
|
+
];
|
|
44
|
+
{
|
|
45
|
+
const sortIndicator = /*#__PURE__*/ jsx(SortIndicator, {
|
|
46
|
+
column: column
|
|
47
|
+
});
|
|
48
|
+
const columnLabel = HeaderCellLabelRenderer ? /*#__PURE__*/ jsx(HeaderCellLabelRenderer, {
|
|
49
|
+
className: `${classBase}-label`,
|
|
50
|
+
column: column
|
|
51
|
+
}) : /*#__PURE__*/ jsx("div", {
|
|
52
|
+
className: `${classBase}-label`,
|
|
53
|
+
children: column.label ?? column.name
|
|
54
|
+
});
|
|
55
|
+
const columnContent = HeaderCellContentRenderer ? [
|
|
56
|
+
/*#__PURE__*/ jsx(HeaderCellContentRenderer, {
|
|
57
|
+
column: column
|
|
58
|
+
}, "content")
|
|
59
|
+
] : [];
|
|
60
|
+
if (!showColumnHeaderMenus || !allowColumnHeaderMenu) return [
|
|
61
|
+
columnLabel,
|
|
62
|
+
sortIndicator,
|
|
63
|
+
columnContent
|
|
64
|
+
];
|
|
65
|
+
{
|
|
66
|
+
const menuPermissions = true === showColumnHeaderMenus ? void 0 : showColumnHeaderMenus;
|
|
67
|
+
const columnMenu = /*#__PURE__*/ jsx(ColumnMenu, {
|
|
68
|
+
column: column,
|
|
69
|
+
menuPermissions: menuPermissions
|
|
70
|
+
});
|
|
71
|
+
return [
|
|
72
|
+
columnLabel,
|
|
73
|
+
columnContent,
|
|
74
|
+
sortIndicator,
|
|
75
|
+
columnMenu
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}, [
|
|
80
|
+
HeaderCellContentRenderer,
|
|
81
|
+
HeaderCellLabelRenderer,
|
|
82
|
+
allRowsSelected,
|
|
83
|
+
allowColumnHeaderMenu,
|
|
84
|
+
allowSelectAll,
|
|
85
|
+
column,
|
|
86
|
+
handleCheckBoxClick,
|
|
87
|
+
showColumnHeaderMenus
|
|
88
|
+
]);
|
|
89
|
+
const handleClick = useCallback((evt)=>{
|
|
90
|
+
isResizing || onClick?.(evt);
|
|
91
|
+
}, [
|
|
92
|
+
isResizing,
|
|
93
|
+
onClick
|
|
94
|
+
]);
|
|
95
|
+
const handleKeyDown = useCallback((evt)=>{
|
|
96
|
+
if ("Enter" === evt.key) onClick?.(evt);
|
|
97
|
+
}, [
|
|
98
|
+
onClick
|
|
99
|
+
]);
|
|
100
|
+
const { className, style } = useCell(column, classBase, true);
|
|
101
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
102
|
+
...htmlAttributes,
|
|
103
|
+
"aria-colindex": column.ariaColIndex,
|
|
104
|
+
"aria-label": `${column.label ?? column.name} column header`,
|
|
105
|
+
className: clsx(className, classNameProp, column.status, {
|
|
106
|
+
[`${classBase}-resizing`]: isResizing,
|
|
107
|
+
[`${classBase}-selected`]: column.selected,
|
|
108
|
+
[`${classBase}-noMenu`]: false === showColumnHeaderMenus
|
|
109
|
+
}),
|
|
110
|
+
"data-column-name": column.name,
|
|
111
|
+
"data-index": index,
|
|
112
|
+
id: id,
|
|
113
|
+
onClick: handleClick,
|
|
114
|
+
onKeyDown: handleKeyDown,
|
|
115
|
+
ref: useForkRef(rootRef, sortableRef),
|
|
116
|
+
role: "columnheader",
|
|
117
|
+
style: style,
|
|
118
|
+
children: [
|
|
119
|
+
...headerItems,
|
|
120
|
+
false !== column.resizeable ? /*#__PURE__*/ jsx(ColumnResizer, {
|
|
121
|
+
...resizeProps
|
|
122
|
+
}) : null
|
|
123
|
+
]
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
export { HeaderCell };
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from "./cell-renderers/index.mjs";
|
|
2
|
+
export * from "./header-cell/index.mjs";
|
|
3
|
+
export * from "./pagination/index.mjs";
|
|
4
|
+
export * from "./Table.mjs";
|
|
5
|
+
export * from "./table-cell/index.mjs";
|
|
6
|
+
export * from "./table-config.mjs";
|
|
7
|
+
export * from "./table-header/index.mjs";
|
|
8
|
+
export * from "./useControlledTableNavigation.mjs";
|
|
9
|
+
export * from "./useEditableCell.mjs";
|
|
10
|
+
export * from "./applyHighlighting.mjs";
|
|
11
|
+
export * from "./useKeyboardNavigation.mjs";
|
|
12
|
+
export * from "./useTableContextMenu.mjs";
|
|
13
|
+
export * from "./useTableModel.mjs";
|
|
14
|
+
export * from "./useTableScroll.mjs";
|
|
15
|
+
export * from "./useTableViewport.mjs";
|
|
16
|
+
export * from "./VirtualColSpan.mjs";
|
|
17
|
+
export { BulkEditPanel } from "./bulk-edit/BulkEditPanel.mjs";
|
|
18
|
+
export { dataRowFactory } from "./data-row/DataRow.mjs";
|
|
19
|
+
export { Row } from "./Row.mjs";
|
|
20
|
+
export { useTableConfig } from "./table-config/useTableConfig.mjs";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const css = `
|
|
2
|
+
.vuuPaginationControl {
|
|
3
|
+
height: var(--vuuPaginationControl-height, auto);
|
|
4
|
+
padding: 0 var(--salt-spacing-100);
|
|
5
|
+
justify-content: flex-end;
|
|
6
|
+
align-items: center;
|
|
7
|
+
display: flex;
|
|
8
|
+
|
|
9
|
+
& .saltButton {
|
|
10
|
+
& .saltIcon {
|
|
11
|
+
display: block !important;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
`;
|
|
18
|
+
export default css;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
3
|
+
import { useWindow } from "@salt-ds/window";
|
|
4
|
+
import { GoToInput, Pagination, Paginator } from "@salt-ds/core";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import { usePagination } from "./usePagination.mjs";
|
|
7
|
+
import PaginationControl_0 from "./PaginationControl.css";
|
|
8
|
+
import { forwardRef } from "react";
|
|
9
|
+
const classBase = "vuuPaginationControl";
|
|
10
|
+
const PaginationControl_PaginationControl = /*#__PURE__*/ forwardRef(function({ className, dataSource, ...htmlAttributes }, forwardedRef) {
|
|
11
|
+
const targetWindow = useWindow();
|
|
12
|
+
useComponentCssInjection({
|
|
13
|
+
testId: "vuu-table",
|
|
14
|
+
css: PaginationControl_0,
|
|
15
|
+
window: targetWindow
|
|
16
|
+
});
|
|
17
|
+
const { onPageChange, pageCount } = usePagination({
|
|
18
|
+
dataSource
|
|
19
|
+
});
|
|
20
|
+
return /*#__PURE__*/ jsx("div", {
|
|
21
|
+
...htmlAttributes,
|
|
22
|
+
className: clsx(classBase, className),
|
|
23
|
+
ref: forwardedRef,
|
|
24
|
+
children: /*#__PURE__*/ jsxs(Pagination, {
|
|
25
|
+
count: pageCount,
|
|
26
|
+
onPageChange: onPageChange,
|
|
27
|
+
children: [
|
|
28
|
+
/*#__PURE__*/ jsx(GoToInput, {}),
|
|
29
|
+
/*#__PURE__*/ jsx(Paginator, {})
|
|
30
|
+
]
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
export { PaginationControl_PaginationControl as PaginationControl };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./PaginationControl.mjs";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
import { Range } from "@vuu-ui/vuu-utils";
|
|
3
|
+
const getPageCount = (dataSource)=>{
|
|
4
|
+
const { range, size } = dataSource;
|
|
5
|
+
const pageSize = range.to - range.from;
|
|
6
|
+
if (pageSize > 0) return Math.ceil(size / pageSize);
|
|
7
|
+
return 0;
|
|
8
|
+
};
|
|
9
|
+
const usePagination = ({ dataSource })=>{
|
|
10
|
+
const [pageCount, setPageCount] = useState(getPageCount(dataSource));
|
|
11
|
+
useMemo(()=>{
|
|
12
|
+
dataSource.on("page-count", (n)=>setPageCount(n));
|
|
13
|
+
}, [
|
|
14
|
+
dataSource
|
|
15
|
+
]);
|
|
16
|
+
const handlePageChange = useCallback((_evt, page)=>{
|
|
17
|
+
const { range } = dataSource;
|
|
18
|
+
const pageSize = range.to - range.from;
|
|
19
|
+
const firstRow = pageSize * (page - 1);
|
|
20
|
+
dataSource.range = Range(firstRow, firstRow + pageSize);
|
|
21
|
+
}, [
|
|
22
|
+
dataSource
|
|
23
|
+
]);
|
|
24
|
+
return {
|
|
25
|
+
onPageChange: handlePageChange,
|
|
26
|
+
pageCount
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export { usePagination };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const css = `
|
|
2
|
+
.vuuTableCell {
|
|
3
|
+
border-right-color: var(--cell-borderColor);
|
|
4
|
+
white-space: nowrap;
|
|
5
|
+
outline-offset: -2px;
|
|
6
|
+
height: 100%;
|
|
7
|
+
padding: var(--vuuTableCell-padding, 0 11px 0 8px);
|
|
8
|
+
text-overflow: ellipsis;
|
|
9
|
+
vertical-align: top;
|
|
10
|
+
border-right-style: solid;
|
|
11
|
+
border-right-width: 1px;
|
|
12
|
+
display: inline-block;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
|
|
15
|
+
&:has(.vuuCheckboxRowSelector) {
|
|
16
|
+
text-overflow: unset;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.vuuTableCell-right {
|
|
21
|
+
text-align: right;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.vuuTableCell-editable {
|
|
25
|
+
padding: var(--vuuTableCell-padding-editable, 0px 1px 0 2px);
|
|
26
|
+
align-items: center;
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.vuuTableCell:focus-visible {
|
|
31
|
+
outline: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.vuuTableCell-editable:focus-within, .vuuTableCell:focus {
|
|
35
|
+
border-bottom: none;
|
|
36
|
+
|
|
37
|
+
& .saltInput-bordered {
|
|
38
|
+
outline: solid var(--salt-editable-borderColor-active) 2px;
|
|
39
|
+
outline-offset: -1px;
|
|
40
|
+
border-color: #0000;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
& .saltInput-bordered.vuuEditing {
|
|
44
|
+
outline: dashed var(--salt-editable-borderColor-active) 2px;
|
|
45
|
+
outline-offset: -1px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
& .vuuTableInputCell-error.saltInput-bordered {
|
|
49
|
+
outline: dashed var(--salt-status-error-borderColor) 2px;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.vuuTableRow-selected .vuuTableCell:not(.vuuTableCell-editable):focus {
|
|
54
|
+
outline: var(--vuuTableCell-outline, solid var(--salt-focused-outlineColor) 2px);
|
|
55
|
+
|
|
56
|
+
&:has(.vuuCheckboxRowSelector) {
|
|
57
|
+
outline: none;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.vuuTableCell.ContextOpen {
|
|
62
|
+
outline: var(--vuuTableCell-outline, solid var(--vuuTableCell-contextOpen-outlineColor, var(--salt-focused-outlineColor)) 2px);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
`;
|
|
67
|
+
export default css;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
3
|
+
import { useWindow } from "@salt-ds/window";
|
|
4
|
+
import { useEditSession } from "@vuu-ui/vuu-utils";
|
|
5
|
+
import { useCallback, useState } from "react";
|
|
6
|
+
import { applyHighlighting } from "../applyHighlighting.mjs";
|
|
7
|
+
import { useCell } from "../useCell.mjs";
|
|
8
|
+
import TableCell from "./TableCell.css";
|
|
9
|
+
const classBase = "vuuTableCell";
|
|
10
|
+
const TableCell_TableCell = ({ column, dataRow, onClick, searchPattern = "" })=>{
|
|
11
|
+
const targetWindow = useWindow();
|
|
12
|
+
useComponentCssInjection({
|
|
13
|
+
testId: "vuu-table-cell",
|
|
14
|
+
css: TableCell,
|
|
15
|
+
window: targetWindow
|
|
16
|
+
});
|
|
17
|
+
const editSession = useEditSession();
|
|
18
|
+
const { className, style } = useCell(column, classBase, false);
|
|
19
|
+
const { ariaColIndex, CellRenderer, name, valueFormatter } = column;
|
|
20
|
+
const [editedDuringCurrentSession, setEditingDuringCurrentSession] = useState(void 0);
|
|
21
|
+
const handleDataItemEdited = useCallback(async (editState, editPhase)=>{
|
|
22
|
+
const { isValid = true, previousValue = "", value } = editState;
|
|
23
|
+
if ("commit" === editPhase && editSession) {
|
|
24
|
+
const { editedDuringCurrentSession, ...response } = await editSession.commit(dataRow.key, name, previousValue, value, isValid);
|
|
25
|
+
setEditingDuringCurrentSession(editedDuringCurrentSession);
|
|
26
|
+
return response;
|
|
27
|
+
}
|
|
28
|
+
}, [
|
|
29
|
+
dataRow.key,
|
|
30
|
+
editSession,
|
|
31
|
+
name
|
|
32
|
+
]);
|
|
33
|
+
const handleClick = useCallback((evt)=>{
|
|
34
|
+
onClick?.(evt, column);
|
|
35
|
+
}, [
|
|
36
|
+
column,
|
|
37
|
+
onClick
|
|
38
|
+
]);
|
|
39
|
+
return /*#__PURE__*/ jsx("div", {
|
|
40
|
+
"aria-colindex": ariaColIndex,
|
|
41
|
+
className: className,
|
|
42
|
+
onClick: onClick ? handleClick : void 0,
|
|
43
|
+
role: "cell",
|
|
44
|
+
style: style,
|
|
45
|
+
children: CellRenderer ? /*#__PURE__*/ jsx(CellRenderer, {
|
|
46
|
+
column: column,
|
|
47
|
+
dataRow: dataRow,
|
|
48
|
+
editedDuringCurrentSession: editedDuringCurrentSession,
|
|
49
|
+
onEdit: handleDataItemEdited,
|
|
50
|
+
searchPattern: searchPattern
|
|
51
|
+
}) : applyHighlighting(valueFormatter(dataRow[column.name]), searchPattern)
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
export { TableCell_TableCell as TableCell };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const css = `
|
|
2
|
+
.vuuTableGroupCell.vuuTableCell {
|
|
3
|
+
--group-cell-spacer-width: 20px;
|
|
4
|
+
border-right-color: var(--vuuTableGroupCell-borderColor, var(--salt-separable-tertiary-borderColor));
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
border-right-style: solid;
|
|
7
|
+
border-right-width: 1px;
|
|
8
|
+
align-items: center;
|
|
9
|
+
line-height: 16px;
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
|
|
12
|
+
& .vuuIcon {
|
|
13
|
+
--vuu-icon-height: 20px;
|
|
14
|
+
--vuu-icon-width: 20px;
|
|
15
|
+
margin-right: var(--salt-spacing-100);
|
|
16
|
+
min-width: 20px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
& .vuuToggleIconButton.saltButton {
|
|
20
|
+
--saltButton-height: 20px;
|
|
21
|
+
--saltButton-width: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
& .vuuTableGroupCell-label {
|
|
25
|
+
text-overflow: ellipsis;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[aria-level="2"] {
|
|
31
|
+
--indent: 1;
|
|
32
|
+
|
|
33
|
+
&:not([aria-expanded]) {
|
|
34
|
+
--indent: 2;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
[aria-level="3"] {
|
|
39
|
+
--indent: 2;
|
|
40
|
+
|
|
41
|
+
&:not([aria-expanded]) {
|
|
42
|
+
--indent: 3;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
[aria-level="4"] {
|
|
47
|
+
--indent: 3;
|
|
48
|
+
|
|
49
|
+
&:not([aria-expanded]) {
|
|
50
|
+
--indent: 4;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
[aria-level="5"] {
|
|
55
|
+
--indent: 4;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[aria-level="6"] {
|
|
59
|
+
--indent: 5;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
[aria-level="7"] {
|
|
63
|
+
--indent: 6;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[aria-level="8"] {
|
|
67
|
+
--indent: 7;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
[aria-level="9"] {
|
|
71
|
+
--indent: 8;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
[aria-level="10"] {
|
|
75
|
+
--indent: 9;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.vuuTableGroupCell-spacer {
|
|
79
|
+
min-width: calc(var(--indent, 0) * var(--group-cell-spacer-width));
|
|
80
|
+
display: inline-block;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.vuuTreeTable {
|
|
84
|
+
& .vuuTableGroupCell.vuuTableCell {
|
|
85
|
+
border-right: none;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
`;
|
|
91
|
+
export default css;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Icon, ToggleIconButton } from "@vuu-ui/vuu-ui-controls";
|
|
3
|
+
import { getGroupIcon, getGroupValue } from "@vuu-ui/vuu-utils";
|
|
4
|
+
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
5
|
+
import { useWindow } from "@salt-ds/window";
|
|
6
|
+
import clsx from "clsx";
|
|
7
|
+
import { useCallback } from "react";
|
|
8
|
+
import { useCell } from "../useCell.mjs";
|
|
9
|
+
import TableCell from "./TableCell.css";
|
|
10
|
+
import TableGroupCell from "./TableGroupCell.css";
|
|
11
|
+
import { applyHighlighting } from "../applyHighlighting.mjs";
|
|
12
|
+
const classBase = "vuuTableGroupCell";
|
|
13
|
+
const TableGroupCell_TableGroupCell = ({ column, dataRow, onClick, searchPattern = "" })=>{
|
|
14
|
+
const targetWindow = useWindow();
|
|
15
|
+
useComponentCssInjection({
|
|
16
|
+
testId: "vuu-table-cell",
|
|
17
|
+
css: TableCell,
|
|
18
|
+
window: targetWindow
|
|
19
|
+
});
|
|
20
|
+
useComponentCssInjection({
|
|
21
|
+
testId: "vuu-table-group-cell",
|
|
22
|
+
css: TableGroupCell,
|
|
23
|
+
window: targetWindow
|
|
24
|
+
});
|
|
25
|
+
const { columns } = column;
|
|
26
|
+
const value = getGroupValue(columns, dataRow);
|
|
27
|
+
const valueWithHighlighting = applyHighlighting(value || "", searchPattern);
|
|
28
|
+
const icon = getGroupIcon(columns, dataRow);
|
|
29
|
+
const { className, style } = useCell(column, classBase);
|
|
30
|
+
const handleClick = useCallback((evt)=>{
|
|
31
|
+
onClick?.(evt, column);
|
|
32
|
+
}, [
|
|
33
|
+
column,
|
|
34
|
+
onClick
|
|
35
|
+
]);
|
|
36
|
+
const { childCount, isExpanded, isLeaf } = dataRow;
|
|
37
|
+
const isLeafNode = isLeaf || 0 == childCount;
|
|
38
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
39
|
+
"aria-colindex": 1,
|
|
40
|
+
className: clsx(className, "vuuTableCell"),
|
|
41
|
+
role: "cell",
|
|
42
|
+
style: style,
|
|
43
|
+
onClick: isLeafNode ? void 0 : handleClick,
|
|
44
|
+
children: [
|
|
45
|
+
/*#__PURE__*/ jsx("span", {
|
|
46
|
+
className: `${classBase}-spacer`
|
|
47
|
+
}),
|
|
48
|
+
isLeafNode ? null : /*#__PURE__*/ jsx(ToggleIconButton, {
|
|
49
|
+
isExpanded: isExpanded
|
|
50
|
+
}),
|
|
51
|
+
icon ? /*#__PURE__*/ jsx(Icon, {
|
|
52
|
+
name: icon
|
|
53
|
+
}) : null,
|
|
54
|
+
/*#__PURE__*/ jsx("span", {
|
|
55
|
+
className: `${classBase}-label`,
|
|
56
|
+
children: valueWithHighlighting
|
|
57
|
+
})
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
export { TableGroupCell_TableGroupCell as TableGroupCell };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ColumnModel } from "@vuu-ui/vuu-table-extras";
|
|
2
|
+
import { useCallback, useMemo, useState } from "react";
|
|
3
|
+
const useTableConfig = ({ availableColumns, config: initialTableConfig, dataSource, onTableConfigChange })=>{
|
|
4
|
+
const [tableConfig, setTableConfig] = useState(initialTableConfig);
|
|
5
|
+
const handleColumnModelChange = useCallback((columns, changeSource, changeDescriptor)=>{
|
|
6
|
+
if ("column-picker" === changeSource || "column-settings" === changeSource) {
|
|
7
|
+
if (changeDescriptor?.type === "calculated-column-added" || changeDescriptor?.type === "column-added") dataSource.columns = dataSource.columns.concat(changeDescriptor.column.name);
|
|
8
|
+
else if (changeDescriptor?.type === "column-removed") dataSource.columns = dataSource.columns.filter((name)=>name !== changeDescriptor.column.name);
|
|
9
|
+
let newConfig;
|
|
10
|
+
setTableConfig((config)=>newConfig = {
|
|
11
|
+
...config,
|
|
12
|
+
columns
|
|
13
|
+
});
|
|
14
|
+
if (changeDescriptor?.type === "column-removed" || changeDescriptor?.type === "column-added" || changeDescriptor?.type === "calculated-column-added") {
|
|
15
|
+
if (newConfig) onTableConfigChange?.(newConfig, changeDescriptor);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}, [
|
|
19
|
+
dataSource,
|
|
20
|
+
onTableConfigChange
|
|
21
|
+
]);
|
|
22
|
+
const columnModel = useMemo(()=>{
|
|
23
|
+
const model = new ColumnModel(availableColumns, tableConfig.columns);
|
|
24
|
+
model.on("change", handleColumnModelChange);
|
|
25
|
+
return model;
|
|
26
|
+
}, [
|
|
27
|
+
availableColumns,
|
|
28
|
+
handleColumnModelChange,
|
|
29
|
+
tableConfig.columns
|
|
30
|
+
]);
|
|
31
|
+
const handleTableConfigChange = useCallback((_config, changeType)=>{
|
|
32
|
+
if ("column-removed" === changeType.type) columnModel.removeItemFromSelectedColumns(changeType.column.name, "table");
|
|
33
|
+
}, [
|
|
34
|
+
columnModel
|
|
35
|
+
]);
|
|
36
|
+
const handleTableDisplayAttributeChange = useCallback((displayAttributes)=>{
|
|
37
|
+
setTableConfig((config)=>({
|
|
38
|
+
...config,
|
|
39
|
+
...displayAttributes
|
|
40
|
+
}));
|
|
41
|
+
}, []);
|
|
42
|
+
return {
|
|
43
|
+
columnModel,
|
|
44
|
+
onTableDisplayAttributeChange: handleTableDisplayAttributeChange,
|
|
45
|
+
onTableConfigChange: handleTableConfigChange,
|
|
46
|
+
tableConfig
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export { useTableConfig };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getRuntimeColumnWidth } from "@vuu-ui/vuu-utils";
|
|
2
|
+
const updateTableConfig = (config, action)=>{
|
|
3
|
+
switch(action.type){
|
|
4
|
+
case "col-size":
|
|
5
|
+
{
|
|
6
|
+
const { columns: runtimeColumns, width } = action;
|
|
7
|
+
const isFit = "fit" === config.columnLayout;
|
|
8
|
+
return {
|
|
9
|
+
...config,
|
|
10
|
+
columnLayout: isFit ? "manual" : config.columnLayout,
|
|
11
|
+
columns: config.columns.map((col)=>{
|
|
12
|
+
if (isFit) return col.name === action.column.name ? {
|
|
13
|
+
...col,
|
|
14
|
+
width
|
|
15
|
+
} : col.width ? col : {
|
|
16
|
+
...col,
|
|
17
|
+
width: getRuntimeColumnWidth(col, runtimeColumns)
|
|
18
|
+
};
|
|
19
|
+
return col.name === action.column.name ? {
|
|
20
|
+
...col,
|
|
21
|
+
width: action.width
|
|
22
|
+
} : col;
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
case "column-prop":
|
|
27
|
+
return {
|
|
28
|
+
...config,
|
|
29
|
+
columns: config.columns.map((col)=>col.name === action.column.name ? {
|
|
30
|
+
...col,
|
|
31
|
+
[action.property]: action.value
|
|
32
|
+
} : col)
|
|
33
|
+
};
|
|
34
|
+
default:
|
|
35
|
+
return config;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export { updateTableConfig };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { WindowRange } from "@vuu-ui/vuu-utils";
|
|
2
|
+
class DataRowMovingWindow {
|
|
3
|
+
data;
|
|
4
|
+
rowCount = 0;
|
|
5
|
+
#range;
|
|
6
|
+
constructor({ from, to }){
|
|
7
|
+
this.#range = new WindowRange(from, to);
|
|
8
|
+
this.data = new Array(Math.max(0, to - from));
|
|
9
|
+
this.rowCount = 0;
|
|
10
|
+
}
|
|
11
|
+
setRowCount = (rowCount)=>{
|
|
12
|
+
if (rowCount < this.data.length) this.data.length = rowCount;
|
|
13
|
+
this.rowCount = rowCount;
|
|
14
|
+
};
|
|
15
|
+
add(data) {
|
|
16
|
+
const { index } = data;
|
|
17
|
+
if (this.isWithinRange(index)) {
|
|
18
|
+
const internalIndex = index - this.#range.from;
|
|
19
|
+
this.data[internalIndex] = data;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
getAtIndex(index) {
|
|
23
|
+
return this.#range.isWithin(index) && null != this.data[index - this.#range.from] ? this.data[index - this.#range.from] : void 0;
|
|
24
|
+
}
|
|
25
|
+
getByKey(key) {
|
|
26
|
+
return this.data.find((row)=>row.key === key);
|
|
27
|
+
}
|
|
28
|
+
isWithinRange(index) {
|
|
29
|
+
return index < this.rowCount && this.#range.isWithin(index);
|
|
30
|
+
}
|
|
31
|
+
setRange({ from, to }) {
|
|
32
|
+
if (from !== this.#range.from || to !== this.#range.to) {
|
|
33
|
+
const [overlapFrom, overlapTo] = this.#range.overlap(from, to);
|
|
34
|
+
const newData = new Array(Math.max(0, to - from));
|
|
35
|
+
for(let i = overlapFrom; i < overlapTo; i++){
|
|
36
|
+
const data = this.getAtIndex(i);
|
|
37
|
+
if (data) {
|
|
38
|
+
const index = i - from;
|
|
39
|
+
newData[index] = data;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
this.data = newData;
|
|
43
|
+
this.#range.from = from;
|
|
44
|
+
this.#range.to = to;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
getSelectedRows() {
|
|
48
|
+
return this.data.filter((dataRow)=>dataRow.isSelected);
|
|
49
|
+
}
|
|
50
|
+
get hasData() {
|
|
51
|
+
return this.data.some((d)=>void 0 !== d);
|
|
52
|
+
}
|
|
53
|
+
get firstRow() {
|
|
54
|
+
for(let i = 0; i < this.data.length; i++)if (this.data[i]) return this.data[i];
|
|
55
|
+
throw Error("[DataRowMovingWinddow] firstRow, no data");
|
|
56
|
+
}
|
|
57
|
+
get range() {
|
|
58
|
+
return this.#range;
|
|
59
|
+
}
|
|
60
|
+
get hasAllRowsWithinRange() {
|
|
61
|
+
const { from, to } = this.#range;
|
|
62
|
+
for(let i = from; i < to; i++)if (void 0 === this.getAtIndex(i)) return false;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export { DataRowMovingWindow };
|