@vuu-ui/vuu-table 0.8.94 → 0.8.96
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/cjs/Row.css.js +1 -1
- package/cjs/Row.js +1 -1
- package/cjs/Row.js.map +1 -1
- package/cjs/Table.css.js +1 -1
- package/cjs/Table.js +113 -31
- package/cjs/Table.js.map +1 -1
- package/cjs/cell-block/CellBlock.css.js +6 -0
- package/cjs/cell-block/CellBlock.css.js.map +1 -0
- package/cjs/cell-block/CellBlock.js +41 -0
- package/cjs/cell-block/CellBlock.js.map +1 -0
- package/cjs/cell-block/cellblock-utils.js +140 -0
- package/cjs/cell-block/cellblock-utils.js.map +1 -0
- package/cjs/cell-block/useCellBlockSelection.js +232 -0
- package/cjs/cell-block/useCellBlockSelection.js.map +1 -0
- package/cjs/index.js +5 -0
- package/cjs/index.js.map +1 -1
- package/cjs/moving-window.js +21 -9
- package/cjs/moving-window.js.map +1 -1
- package/cjs/pagination/PaginationControl.css.js +6 -0
- package/cjs/pagination/PaginationControl.css.js.map +1 -0
- package/cjs/pagination/PaginationControl.js +38 -0
- package/cjs/pagination/PaginationControl.js.map +1 -0
- package/cjs/pagination/usePagination.js +38 -0
- package/cjs/pagination/usePagination.js.map +1 -0
- package/cjs/table-dom-utils.js +67 -10
- package/cjs/table-dom-utils.js.map +1 -1
- package/cjs/table-header/useTableHeader.js +1 -1
- package/cjs/table-header/useTableHeader.js.map +1 -1
- package/cjs/useCellFocus.js +56 -0
- package/cjs/useCellFocus.js.map +1 -0
- package/cjs/useControlledTableNavigation.js +3 -1
- package/cjs/useControlledTableNavigation.js.map +1 -1
- package/cjs/useDataSource.js +13 -0
- package/cjs/useDataSource.js.map +1 -1
- package/cjs/useKeyboardNavigation.js +8 -82
- package/cjs/useKeyboardNavigation.js.map +1 -1
- package/cjs/useMeasuredHeight.js +5 -5
- package/cjs/useMeasuredHeight.js.map +1 -1
- package/cjs/useTable.js +63 -16
- package/cjs/useTable.js.map +1 -1
- package/cjs/useTableContextMenu.js +2 -1
- package/cjs/useTableContextMenu.js.map +1 -1
- package/cjs/useTableScroll.js.map +1 -1
- package/cjs/useTableViewport.js +31 -13
- package/cjs/useTableViewport.js.map +1 -1
- package/esm/Row.css.js +1 -1
- package/esm/Row.js +1 -1
- package/esm/Row.js.map +1 -1
- package/esm/Table.css.js +1 -1
- package/esm/Table.js +115 -33
- package/esm/Table.js.map +1 -1
- package/esm/cell-block/CellBlock.css.js +4 -0
- package/esm/cell-block/CellBlock.css.js.map +1 -0
- package/esm/cell-block/CellBlock.js +39 -0
- package/esm/cell-block/CellBlock.js.map +1 -0
- package/esm/cell-block/cellblock-utils.js +131 -0
- package/esm/cell-block/cellblock-utils.js.map +1 -0
- package/esm/cell-block/useCellBlockSelection.js +230 -0
- package/esm/cell-block/useCellBlockSelection.js.map +1 -0
- package/esm/index.js +2 -1
- package/esm/index.js.map +1 -1
- package/esm/moving-window.js +21 -9
- package/esm/moving-window.js.map +1 -1
- package/esm/pagination/PaginationControl.css.js +4 -0
- package/esm/pagination/PaginationControl.css.js.map +1 -0
- package/esm/pagination/PaginationControl.js +36 -0
- package/esm/pagination/PaginationControl.js.map +1 -0
- package/esm/pagination/usePagination.js +36 -0
- package/esm/pagination/usePagination.js.map +1 -0
- package/esm/table-dom-utils.js +64 -10
- package/esm/table-dom-utils.js.map +1 -1
- package/esm/table-header/useTableHeader.js +1 -1
- package/esm/table-header/useTableHeader.js.map +1 -1
- package/esm/useCellFocus.js +54 -0
- package/esm/useCellFocus.js.map +1 -0
- package/esm/useControlledTableNavigation.js +3 -2
- package/esm/useControlledTableNavigation.js.map +1 -1
- package/esm/useDataSource.js +13 -0
- package/esm/useDataSource.js.map +1 -1
- package/esm/useKeyboardNavigation.js +8 -82
- package/esm/useKeyboardNavigation.js.map +1 -1
- package/esm/useMeasuredHeight.js +5 -5
- package/esm/useMeasuredHeight.js.map +1 -1
- package/esm/useTable.js +63 -16
- package/esm/useTable.js.map +1 -1
- package/esm/useTableContextMenu.js +2 -1
- package/esm/useTableContextMenu.js.map +1 -1
- package/esm/useTableScroll.js.map +1 -1
- package/esm/useTableViewport.js +31 -13
- package/esm/useTableViewport.js.map +1 -1
- package/package.json +9 -9
- package/types/Table.d.ts +40 -0
- package/types/cell-block/CellBlock.d.ts +6 -0
- package/types/cell-block/cellblock-utils.d.ts +37 -0
- package/types/cell-block/useCellBlockSelection.d.ts +16 -0
- package/types/index.d.ts +1 -0
- package/types/moving-window.d.ts +3 -1
- package/types/pagination/PaginationControl.d.ts +6 -0
- package/types/pagination/index.d.ts +1 -0
- package/types/pagination/usePagination.d.ts +9 -0
- package/types/table-dom-utils.d.ts +6 -1
- package/types/useCellFocus.d.ts +13 -0
- package/types/useControlledTableNavigation.d.ts +1 -0
- package/types/useKeyboardNavigation.d.ts +5 -5
- package/types/useMeasuredHeight.d.ts +2 -2
- package/types/useTable.d.ts +13 -11
- package/types/useTableScroll.d.ts +1 -0
- package/types/useTableViewport.d.ts +3 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
const getPageCount = (dataSource) => {
|
|
6
|
+
const { range, size } = dataSource;
|
|
7
|
+
const pageSize = range.to - range.from;
|
|
8
|
+
if (pageSize > 0) {
|
|
9
|
+
return Math.ceil(size / pageSize);
|
|
10
|
+
} else {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const usePagination = ({ dataSource }) => {
|
|
15
|
+
const [pageCount, setPageCount] = react.useState(getPageCount(dataSource));
|
|
16
|
+
react.useMemo(() => {
|
|
17
|
+
dataSource.on("page-count", (n) => setPageCount(n));
|
|
18
|
+
}, [dataSource]);
|
|
19
|
+
const handlePageChange = react.useCallback(
|
|
20
|
+
(_evt, page) => {
|
|
21
|
+
const { range } = dataSource;
|
|
22
|
+
const pageSize = range.to - range.from;
|
|
23
|
+
const firstRow = pageSize * (page - 1);
|
|
24
|
+
console.log(
|
|
25
|
+
`set range ${JSON.stringify({ from: firstRow, to: firstRow + pageSize })}`
|
|
26
|
+
);
|
|
27
|
+
dataSource.range = { from: firstRow, to: firstRow + pageSize };
|
|
28
|
+
},
|
|
29
|
+
[dataSource]
|
|
30
|
+
);
|
|
31
|
+
return {
|
|
32
|
+
onPageChange: handlePageChange,
|
|
33
|
+
pageCount
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
exports.usePagination = usePagination;
|
|
38
|
+
//# sourceMappingURL=usePagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePagination.js","sources":["../../src/pagination/usePagination.ts"],"sourcesContent":["import { SyntheticEvent, useCallback, useMemo, useState } from \"react\";\nimport { DataSource } from \"@vuu-ui/vuu-data-types\";\n\nexport interface PaginationHookProps {\n dataSource: DataSource;\n}\n\nconst getPageCount = (dataSource: DataSource) => {\n const { range, size } = dataSource;\n const pageSize = range.to - range.from;\n if (pageSize > 0) {\n return Math.ceil(size / pageSize);\n } else {\n return 0;\n }\n};\n\nexport const usePagination = ({ dataSource }: PaginationHookProps) => {\n const [pageCount, setPageCount] = useState<number>(getPageCount(dataSource));\n\n useMemo(() => {\n dataSource.on(\"page-count\", (n: number) => setPageCount(n));\n }, [dataSource]);\n\n const handlePageChange = useCallback(\n (_evt: SyntheticEvent, page: number) => {\n const { range } = dataSource;\n const pageSize = range.to - range.from;\n const firstRow = pageSize * (page - 1);\n console.log(\n `set range ${JSON.stringify({ from: firstRow, to: firstRow + pageSize })}`,\n );\n dataSource.range = { from: firstRow, to: firstRow + pageSize };\n },\n [dataSource],\n );\n\n return {\n onPageChange: handlePageChange,\n pageCount,\n };\n};\n"],"names":["useState","useMemo","useCallback"],"mappings":";;;;AAOA,MAAM,YAAA,GAAe,CAAC,UAA2B,KAAA;AAC/C,EAAM,MAAA,EAAE,KAAO,EAAA,IAAA,EAAS,GAAA,UAAA,CAAA;AACxB,EAAM,MAAA,QAAA,GAAW,KAAM,CAAA,EAAA,GAAK,KAAM,CAAA,IAAA,CAAA;AAClC,EAAA,IAAI,WAAW,CAAG,EAAA;AAChB,IAAO,OAAA,IAAA,CAAK,IAAK,CAAA,IAAA,GAAO,QAAQ,CAAA,CAAA;AAAA,GAC3B,MAAA;AACL,IAAO,OAAA,CAAA,CAAA;AAAA,GACT;AACF,CAAA,CAAA;AAEO,MAAM,aAAgB,GAAA,CAAC,EAAE,UAAA,EAAsC,KAAA;AACpE,EAAA,MAAM,CAAC,SAAW,EAAA,YAAY,IAAIA,cAAiB,CAAA,YAAA,CAAa,UAAU,CAAC,CAAA,CAAA;AAE3E,EAAAC,aAAA,CAAQ,MAAM;AACZ,IAAA,UAAA,CAAW,GAAG,YAAc,EAAA,CAAC,CAAc,KAAA,YAAA,CAAa,CAAC,CAAC,CAAA,CAAA;AAAA,GAC5D,EAAG,CAAC,UAAU,CAAC,CAAA,CAAA;AAEf,EAAA,MAAM,gBAAmB,GAAAC,iBAAA;AAAA,IACvB,CAAC,MAAsB,IAAiB,KAAA;AACtC,MAAM,MAAA,EAAE,OAAU,GAAA,UAAA,CAAA;AAClB,MAAM,MAAA,QAAA,GAAW,KAAM,CAAA,EAAA,GAAK,KAAM,CAAA,IAAA,CAAA;AAClC,MAAM,MAAA,QAAA,GAAW,YAAY,IAAO,GAAA,CAAA,CAAA,CAAA;AACpC,MAAQ,OAAA,CAAA,GAAA;AAAA,QACN,CAAA,UAAA,EAAa,IAAK,CAAA,SAAA,CAAU,EAAE,IAAA,EAAM,UAAU,EAAI,EAAA,QAAA,GAAW,QAAS,EAAC,CAAC,CAAA,CAAA;AAAA,OAC1E,CAAA;AACA,MAAA,UAAA,CAAW,QAAQ,EAAE,IAAA,EAAM,QAAU,EAAA,EAAA,EAAI,WAAW,QAAS,EAAA,CAAA;AAAA,KAC/D;AAAA,IACA,CAAC,UAAU,CAAA;AAAA,GACb,CAAA;AAEA,EAAO,OAAA;AAAA,IACL,YAAc,EAAA,gBAAA;AAAA,IACd,SAAA;AAAA,GACF,CAAA;AACF;;;;"}
|
package/cjs/table-dom-utils.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const NULL_CELL_POS = [-1, -1];
|
|
4
|
+
const headerCellQuery = (colIdx) => `.vuuTable-col-headers .vuuTableHeaderCell[aria-colindex='${colIdx + 1}']`;
|
|
5
|
+
const dataCellQuery = (rowIdx, colIdx) => `.vuuTable-body > [aria-rowindex='${rowIdx + 1}'] > [aria-colindex='${colIdx + 1}']`;
|
|
5
6
|
const getTableCell = (containerRef, [rowIdx, colIdx]) => {
|
|
6
7
|
const cssQuery = rowIdx === -1 ? headerCellQuery(colIdx) : dataCellQuery(rowIdx, colIdx);
|
|
7
8
|
const cell = containerRef.current?.querySelector(
|
|
@@ -22,17 +23,70 @@ const cellDropdownShowing = (cell) => {
|
|
|
22
23
|
return false;
|
|
23
24
|
};
|
|
24
25
|
const cellIsTextInput = (cell) => cell.querySelector(".vuuTableInputCell") !== null;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const getIndexFromRowElement = (rowElement) => {
|
|
27
|
+
const rowIndex = rowElement?.ariaRowIndex;
|
|
28
|
+
if (rowIndex != null) {
|
|
29
|
+
const index = parseInt(rowIndex) - 1;
|
|
30
|
+
if (!isNaN(index)) {
|
|
31
|
+
return index;
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
return -1;
|
|
33
|
-
}
|
|
35
|
+
};
|
|
36
|
+
const getIndexFromCellElement = (cellElement) => {
|
|
37
|
+
const colIndex = cellElement?.ariaColIndex;
|
|
38
|
+
if (colIndex != null) {
|
|
39
|
+
const index = parseInt(colIndex) - 1;
|
|
40
|
+
if (!isNaN(index)) {
|
|
41
|
+
return index;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return -1;
|
|
45
|
+
};
|
|
46
|
+
const getTableCellPos = (tableCell) => {
|
|
47
|
+
const colIdx = getIndexFromCellElement(tableCell);
|
|
48
|
+
if (tableCell.role === "columnHeader") {
|
|
49
|
+
return [-1, colIdx];
|
|
50
|
+
} else {
|
|
51
|
+
const focusedRow = tableCell.closest("[role='row']");
|
|
52
|
+
if (focusedRow) {
|
|
53
|
+
return [getIndexFromRowElement(focusedRow), colIdx];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return NULL_CELL_POS;
|
|
57
|
+
};
|
|
34
58
|
const closestRow = (el) => el.closest('[role="row"]');
|
|
35
|
-
const closestRowIndex = (el) =>
|
|
59
|
+
const closestRowIndex = (el) => getIndexFromRowElement(closestRow(el));
|
|
60
|
+
function getNextCellPos(key, [rowIdx, colIdx], columnCount, rowCount) {
|
|
61
|
+
if (key === "ArrowUp") {
|
|
62
|
+
if (rowIdx > -1) {
|
|
63
|
+
return [rowIdx - 1, colIdx];
|
|
64
|
+
} else {
|
|
65
|
+
return [rowIdx, colIdx];
|
|
66
|
+
}
|
|
67
|
+
} else if (key === "ArrowDown") {
|
|
68
|
+
if (rowIdx === -1) {
|
|
69
|
+
return [0, colIdx];
|
|
70
|
+
} else if (rowIdx === rowCount - 1) {
|
|
71
|
+
return [rowIdx, colIdx];
|
|
72
|
+
} else {
|
|
73
|
+
return [rowIdx + 1, colIdx];
|
|
74
|
+
}
|
|
75
|
+
} else if (key === "ArrowRight") {
|
|
76
|
+
if (colIdx < columnCount - 1) {
|
|
77
|
+
return [rowIdx, colIdx + 1];
|
|
78
|
+
} else {
|
|
79
|
+
return [rowIdx, colIdx];
|
|
80
|
+
}
|
|
81
|
+
} else if (key === "ArrowLeft") {
|
|
82
|
+
if (colIdx > 0) {
|
|
83
|
+
return [rowIdx, colIdx - 1];
|
|
84
|
+
} else {
|
|
85
|
+
return [rowIdx, colIdx];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return [rowIdx, colIdx];
|
|
89
|
+
}
|
|
36
90
|
const NO_SCROLL_NECESSARY = [void 0, void 0];
|
|
37
91
|
const howFarIsRowOutsideViewport = (rowEl, totalHeaderHeight, contentContainer = rowEl.closest(".vuuTable-contentContainer")) => {
|
|
38
92
|
if (contentContainer) {
|
|
@@ -60,8 +114,11 @@ exports.cellIsEditable = cellIsEditable;
|
|
|
60
114
|
exports.cellIsTextInput = cellIsTextInput;
|
|
61
115
|
exports.closestRowIndex = closestRowIndex;
|
|
62
116
|
exports.dataCellQuery = dataCellQuery;
|
|
63
|
-
exports.
|
|
117
|
+
exports.getIndexFromCellElement = getIndexFromCellElement;
|
|
118
|
+
exports.getIndexFromRowElement = getIndexFromRowElement;
|
|
119
|
+
exports.getNextCellPos = getNextCellPos;
|
|
64
120
|
exports.getTableCell = getTableCell;
|
|
121
|
+
exports.getTableCellPos = getTableCellPos;
|
|
65
122
|
exports.headerCellQuery = headerCellQuery;
|
|
66
123
|
exports.howFarIsRowOutsideViewport = howFarIsRowOutsideViewport;
|
|
67
124
|
//# sourceMappingURL=table-dom-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-dom-utils.js","sources":["../src/table-dom-utils.ts"],"sourcesContent":["import { RefObject } from \"react\";\nimport { ScrollDirection } from \"./useTableScroll\";\n\n/**\n * [rowIndex, colIndex\n */\nexport type CellPos = [number, number];\n\nexport const headerCellQuery = (colIdx: number) =>\n `.vuuTable-col-headers .vuuTableHeaderCell
|
|
1
|
+
{"version":3,"file":"table-dom-utils.js","sources":["../src/table-dom-utils.ts"],"sourcesContent":["import { RefObject } from \"react\";\nimport { ScrollDirection } from \"./useTableScroll\";\nimport type { ArrowKey, PageKey } from \"@vuu-ui/vuu-utils\";\n\nconst NULL_CELL_POS: CellPos = [-1, -1];\n\n/**\n * [rowIndex, colIndex\n */\nexport type CellPos = [number, number];\n\nexport type NavigationKey = PageKey | ArrowKey;\n\nexport const headerCellQuery = (colIdx: number) =>\n `.vuuTable-col-headers .vuuTableHeaderCell[aria-colindex='${colIdx + 1}']`;\n\nexport const dataCellQuery = (rowIdx: number, colIdx: number) =>\n `.vuuTable-body > [aria-rowindex='${rowIdx + 1}'] > [aria-colindex='${colIdx + 1}']`;\n\nexport const getTableCell = (\n containerRef: RefObject<HTMLElement>,\n [rowIdx, colIdx]: CellPos,\n) => {\n const cssQuery =\n rowIdx === -1 ? headerCellQuery(colIdx) : dataCellQuery(rowIdx, colIdx);\n const cell = containerRef.current?.querySelector(\n cssQuery,\n ) as HTMLTableCellElement;\n\n if (cellIsEditable(cell)) {\n // Dropdown gets focus, Input does not\n const focusableContent = cell.querySelector(\"button\") as HTMLElement;\n return focusableContent || cell;\n } else {\n return cell;\n }\n};\n\nexport const cellIsEditable = (cell: HTMLDivElement | null) =>\n cell?.classList.contains(\"vuuTableCell-editable\");\n\nexport const cellDropdownShowing = (cell: HTMLDivElement | null) => {\n if (cellIsEditable(cell)) {\n return cell?.querySelector('.saltDropdown[aria-expanded=\"true\"]') !== null;\n }\n return false;\n};\n\nexport const cellIsTextInput = (cell: HTMLElement) =>\n cell.querySelector(\".vuuTableInputCell\") !== null;\n\nexport const getIndexFromRowElement = (rowElement: HTMLElement | null) => {\n const rowIndex = rowElement?.ariaRowIndex;\n if (rowIndex != null) {\n const index = parseInt(rowIndex) - 1;\n if (!isNaN(index)) {\n return index;\n }\n }\n return -1;\n};\n\nexport const getIndexFromCellElement = (cellElement: HTMLElement | null) => {\n const colIndex = cellElement?.ariaColIndex;\n if (colIndex != null) {\n const index = parseInt(colIndex) - 1;\n if (!isNaN(index)) {\n return index;\n }\n }\n return -1;\n};\n\nexport const getTableCellPos = (tableCell: HTMLDivElement): CellPos => {\n const colIdx = getIndexFromCellElement(tableCell);\n if (tableCell.role === \"columnHeader\") {\n return [-1, colIdx];\n } else {\n const focusedRow = tableCell.closest(\"[role='row']\") as HTMLElement;\n if (focusedRow) {\n return [getIndexFromRowElement(focusedRow), colIdx];\n }\n }\n return NULL_CELL_POS;\n};\n\nconst closestRow = (el: HTMLElement) =>\n el.closest('[role=\"row\"]') as HTMLElement;\n\nexport const closestRowIndex = (el: HTMLElement) =>\n getIndexFromRowElement(closestRow(el));\n\nexport function getNextCellPos(\n key: ArrowKey,\n [rowIdx, colIdx]: CellPos,\n columnCount: number,\n rowCount: number,\n): CellPos {\n if (key === \"ArrowUp\") {\n if (rowIdx > -1) {\n return [rowIdx - 1, colIdx];\n } else {\n return [rowIdx, colIdx];\n }\n } else if (key === \"ArrowDown\") {\n if (rowIdx === -1) {\n return [0, colIdx];\n } else if (rowIdx === rowCount - 1) {\n return [rowIdx, colIdx];\n } else {\n return [rowIdx + 1, colIdx];\n }\n } else if (key === \"ArrowRight\") {\n if (colIdx < columnCount - 1) {\n return [rowIdx, colIdx + 1];\n } else {\n return [rowIdx, colIdx];\n }\n } else if (key === \"ArrowLeft\") {\n if (colIdx > 0) {\n return [rowIdx, colIdx - 1];\n } else {\n return [rowIdx, colIdx];\n }\n }\n return [rowIdx, colIdx];\n}\n\nconst NO_SCROLL_NECESSARY = [undefined, undefined] as const;\n\nexport const howFarIsRowOutsideViewport = (\n rowEl: HTMLElement,\n totalHeaderHeight: number,\n contentContainer = rowEl.closest(\".vuuTable-contentContainer\"),\n): readonly [ScrollDirection | undefined, number | undefined] => {\n //TODO lots of scope for optimisation here\n if (contentContainer) {\n // TODO take totalHeaderHeight into consideration\n const viewport = contentContainer?.getBoundingClientRect();\n const upperBoundary = viewport.top + totalHeaderHeight;\n const row = rowEl.getBoundingClientRect();\n if (row) {\n if (row.bottom > viewport.bottom) {\n return [\"down\", row.bottom - viewport.bottom];\n } else if (row.top < upperBoundary) {\n return [\"up\", row.top - upperBoundary];\n } else {\n return NO_SCROLL_NECESSARY;\n }\n } else {\n throw Error(\"Whats going on, row not found\");\n }\n } else {\n throw Error(\"Whats going on, scrollbar container not found\");\n }\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ const useTableHeader = ({
|
|
|
16
16
|
}) => {
|
|
17
17
|
const containerRef = react.useRef(null);
|
|
18
18
|
const scrollingContainerRef = react.useRef(null);
|
|
19
|
-
const { rowRef } = useMeasuredHeight.useMeasuredHeight({
|
|
19
|
+
const { measuredRef: rowRef } = useMeasuredHeight.useMeasuredHeight({
|
|
20
20
|
onHeightMeasured
|
|
21
21
|
});
|
|
22
22
|
const setContainerRef = react.useCallback((el) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTableHeader.js","sources":["../../src/table-header/useTableHeader.ts"],"sourcesContent":["import { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport {\n DropOptions,\n useDragDrop as useDragDrop,\n} from \"@vuu-ui/vuu-ui-controls\";\nimport {\n moveColumnTo,\n queryClosest,\n visibleColumnAtIndex,\n} from \"@vuu-ui/vuu-utils\";\nimport { RefCallback, useCallback, useRef } from \"react\";\nimport { TableHeaderProps } from \"./TableHeader\";\nimport { useMeasuredHeight } from \"../useMeasuredHeight\";\nimport { useForkRef } from \"@salt-ds/core\";\n\nexport interface TableHeaderHookProps\n extends Pick<\n TableHeaderProps,\n | \"allowDragColumnHeader\"\n | \"columns\"\n | \"onMoveColumn\"\n | \"onSortColumn\"\n | \"tableConfig\"\n > {\n label?: string;\n onHeightMeasured: (height: number) => void;\n onMoveColumn: (columns: ColumnDescriptor[]) => void;\n onSortColumn: (column: ColumnDescriptor, addToExistingSort: boolean) => void;\n}\n\nexport const useTableHeader = ({\n allowDragColumnHeader,\n columns,\n onHeightMeasured,\n onMoveColumn,\n onSortColumn,\n tableConfig,\n}: TableHeaderHookProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const scrollingContainerRef = useRef<HTMLDivElement | null>(null);\n const { rowRef } = useMeasuredHeight({\n onHeightMeasured,\n });\n\n const setContainerRef = useCallback<RefCallback<HTMLDivElement>>((el) => {\n containerRef.current = el;\n if (el) {\n scrollingContainerRef.current = el.closest(\".vuuTable-contentContainer\");\n } else {\n scrollingContainerRef.current = null;\n }\n }, []);\n\n const handleDropColumnHeader = useCallback(\n ({ fromIndex: moveFrom, toIndex: moveTo }: DropOptions) => {\n const column = columns[moveFrom];\n // columns are what get rendered, so these are the columns that\n // the drop operation relates to. We must translate these into\n // columns within the table config. Grouping complicates this\n // as the group columns are not present in columns but ARE in\n // config.columns\n const orderedColumns = moveColumnTo(columns, column, moveTo);\n\n const ofColumn =\n ({ name }: ColumnDescriptor) =>\n (col: ColumnDescriptor) =>\n col.name === name;\n\n const targetIndex = orderedColumns.findIndex(ofColumn(column));\n const nextColumn = orderedColumns[targetIndex + 1];\n const insertPos = nextColumn\n ? tableConfig.columns.findIndex(ofColumn(nextColumn))\n : -1;\n\n if (moveTo > moveFrom && insertPos !== -1) {\n onMoveColumn(moveColumnTo(tableConfig.columns, column, insertPos - 1));\n } else {\n onMoveColumn(moveColumnTo(tableConfig.columns, column, insertPos));\n }\n },\n [columns, onMoveColumn, tableConfig.columns],\n );\n\n const handleColumnHeaderClick = useCallback(\n (evt: React.MouseEvent | React.KeyboardEvent) => {\n const headerCell = queryClosest(evt.target, \".vuuTableHeaderCell\");\n const colIdx = parseInt(headerCell?.dataset.index ?? \"-1\");\n const column = visibleColumnAtIndex(columns, colIdx);\n const isAdditive = evt.shiftKey;\n column && onSortColumn(column, isAdditive);\n },\n [columns, onSortColumn],\n );\n\n // Drag Drop column headers\n const {\n onMouseDown: columnHeaderDragMouseDown,\n draggable: draggableColumn,\n ...dragDropHook\n } = useDragDrop({\n allowDragDrop: allowDragColumnHeader,\n containerRef,\n draggableClassName: `vuuTable`,\n itemQuery: \".vuuTableHeaderCell\",\n onDrop: handleDropColumnHeader,\n orientation: \"horizontal\",\n scrollingContainerRef,\n });\n\n return {\n draggableColumn,\n draggedColumnIndex: dragDropHook.draggedItemIndex,\n onClick: handleColumnHeaderClick,\n onMouseDown: columnHeaderDragMouseDown,\n setContainerRef: useForkRef(setContainerRef, rowRef),\n };\n};\n"],"names":["useRef","useMeasuredHeight","useCallback","moveColumnTo","queryClosest","visibleColumnAtIndex","useDragDrop","useForkRef"],"mappings":";;;;;;;;AA8BO,MAAM,iBAAiB,CAAC;AAAA,EAC7B,qBAAA;AAAA,EACA,OAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AACF,CAA4B,KAAA;AAC1B,EAAM,MAAA,YAAA,GAAeA,aAA8B,IAAI,CAAA,CAAA;AACvD,EAAM,MAAA,qBAAA,GAAwBA,aAA8B,IAAI,CAAA,CAAA;AAChE,
|
|
1
|
+
{"version":3,"file":"useTableHeader.js","sources":["../../src/table-header/useTableHeader.ts"],"sourcesContent":["import { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport {\n DropOptions,\n useDragDrop as useDragDrop,\n} from \"@vuu-ui/vuu-ui-controls\";\nimport {\n moveColumnTo,\n queryClosest,\n visibleColumnAtIndex,\n} from \"@vuu-ui/vuu-utils\";\nimport { RefCallback, useCallback, useRef } from \"react\";\nimport { TableHeaderProps } from \"./TableHeader\";\nimport { useMeasuredHeight } from \"../useMeasuredHeight\";\nimport { useForkRef } from \"@salt-ds/core\";\n\nexport interface TableHeaderHookProps\n extends Pick<\n TableHeaderProps,\n | \"allowDragColumnHeader\"\n | \"columns\"\n | \"onMoveColumn\"\n | \"onSortColumn\"\n | \"tableConfig\"\n > {\n label?: string;\n onHeightMeasured: (height: number) => void;\n onMoveColumn: (columns: ColumnDescriptor[]) => void;\n onSortColumn: (column: ColumnDescriptor, addToExistingSort: boolean) => void;\n}\n\nexport const useTableHeader = ({\n allowDragColumnHeader,\n columns,\n onHeightMeasured,\n onMoveColumn,\n onSortColumn,\n tableConfig,\n}: TableHeaderHookProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const scrollingContainerRef = useRef<HTMLDivElement | null>(null);\n const { measuredRef: rowRef } = useMeasuredHeight({\n onHeightMeasured,\n });\n\n const setContainerRef = useCallback<RefCallback<HTMLDivElement>>((el) => {\n containerRef.current = el;\n if (el) {\n scrollingContainerRef.current = el.closest(\".vuuTable-contentContainer\");\n } else {\n scrollingContainerRef.current = null;\n }\n }, []);\n\n const handleDropColumnHeader = useCallback(\n ({ fromIndex: moveFrom, toIndex: moveTo }: DropOptions) => {\n const column = columns[moveFrom];\n // columns are what get rendered, so these are the columns that\n // the drop operation relates to. We must translate these into\n // columns within the table config. Grouping complicates this\n // as the group columns are not present in columns but ARE in\n // config.columns\n const orderedColumns = moveColumnTo(columns, column, moveTo);\n\n const ofColumn =\n ({ name }: ColumnDescriptor) =>\n (col: ColumnDescriptor) =>\n col.name === name;\n\n const targetIndex = orderedColumns.findIndex(ofColumn(column));\n const nextColumn = orderedColumns[targetIndex + 1];\n const insertPos = nextColumn\n ? tableConfig.columns.findIndex(ofColumn(nextColumn))\n : -1;\n\n if (moveTo > moveFrom && insertPos !== -1) {\n onMoveColumn(moveColumnTo(tableConfig.columns, column, insertPos - 1));\n } else {\n onMoveColumn(moveColumnTo(tableConfig.columns, column, insertPos));\n }\n },\n [columns, onMoveColumn, tableConfig.columns],\n );\n\n const handleColumnHeaderClick = useCallback(\n (evt: React.MouseEvent | React.KeyboardEvent) => {\n const headerCell = queryClosest(evt.target, \".vuuTableHeaderCell\");\n const colIdx = parseInt(headerCell?.dataset.index ?? \"-1\");\n const column = visibleColumnAtIndex(columns, colIdx);\n const isAdditive = evt.shiftKey;\n column && onSortColumn(column, isAdditive);\n },\n [columns, onSortColumn],\n );\n\n // Drag Drop column headers\n const {\n onMouseDown: columnHeaderDragMouseDown,\n draggable: draggableColumn,\n ...dragDropHook\n } = useDragDrop({\n allowDragDrop: allowDragColumnHeader,\n containerRef,\n draggableClassName: `vuuTable`,\n itemQuery: \".vuuTableHeaderCell\",\n onDrop: handleDropColumnHeader,\n orientation: \"horizontal\",\n scrollingContainerRef,\n });\n\n return {\n draggableColumn,\n draggedColumnIndex: dragDropHook.draggedItemIndex,\n onClick: handleColumnHeaderClick,\n onMouseDown: columnHeaderDragMouseDown,\n setContainerRef: useForkRef(setContainerRef, rowRef),\n };\n};\n"],"names":["useRef","useMeasuredHeight","useCallback","moveColumnTo","queryClosest","visibleColumnAtIndex","useDragDrop","useForkRef"],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var tableDomUtils = require('./table-dom-utils.js');
|
|
5
|
+
var vuuUtils = require('@vuu-ui/vuu-utils');
|
|
6
|
+
|
|
7
|
+
const useCellFocus = ({
|
|
8
|
+
containerRef,
|
|
9
|
+
disableFocus = false,
|
|
10
|
+
requestScroll
|
|
11
|
+
}) => {
|
|
12
|
+
const focusableCell = react.useRef();
|
|
13
|
+
const focusCell = react.useCallback(
|
|
14
|
+
(cellPos) => {
|
|
15
|
+
if (containerRef.current) {
|
|
16
|
+
const activeCell = tableDomUtils.getTableCell(containerRef, cellPos);
|
|
17
|
+
if (activeCell) {
|
|
18
|
+
if (activeCell !== focusableCell.current) {
|
|
19
|
+
focusableCell.current?.removeAttribute("tabindex");
|
|
20
|
+
focusableCell.current = activeCell;
|
|
21
|
+
activeCell.setAttribute("tabindex", "0");
|
|
22
|
+
}
|
|
23
|
+
requestScroll?.({ type: "scroll-row", rowIndex: cellPos[0] });
|
|
24
|
+
activeCell.focus({ preventScroll: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
// TODO we recreate this function whenever viewportRange changes, which will
|
|
29
|
+
// be often whilst scrolling - store range in a a ref ?
|
|
30
|
+
[containerRef, requestScroll]
|
|
31
|
+
);
|
|
32
|
+
const tableBodyRef = react.useCallback(
|
|
33
|
+
(el) => {
|
|
34
|
+
if (el) {
|
|
35
|
+
const table = vuuUtils.queryClosest(el, ".vuuTable");
|
|
36
|
+
if (table) {
|
|
37
|
+
if (focusableCell.current === void 0 && !disableFocus) {
|
|
38
|
+
const cell = table.querySelector(tableDomUtils.headerCellQuery(0)) || table.querySelector(tableDomUtils.dataCellQuery(0, 0));
|
|
39
|
+
if (cell) {
|
|
40
|
+
cell.setAttribute("tabindex", "0");
|
|
41
|
+
focusableCell.current = cell;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
[disableFocus]
|
|
48
|
+
);
|
|
49
|
+
return {
|
|
50
|
+
focusCell,
|
|
51
|
+
tableBodyRef
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
exports.useCellFocus = useCellFocus;
|
|
56
|
+
//# sourceMappingURL=useCellFocus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCellFocus.js","sources":["../src/useCellFocus.ts"],"sourcesContent":["import { RefCallback, RefObject, useCallback, useRef } from \"react\";\nimport {\n CellPos,\n dataCellQuery,\n getTableCell,\n headerCellQuery,\n} from \"./table-dom-utils\";\nimport { ScrollRequestHandler } from \"./useTableScroll\";\nimport { queryClosest } from \"@vuu-ui/vuu-utils\";\n\nexport interface CellFocusHookProps {\n containerRef: RefObject<HTMLElement>;\n disableFocus?: boolean;\n requestScroll?: ScrollRequestHandler;\n}\n\nexport type FocusCell = (cellPos: CellPos) => void;\n\nexport const useCellFocus = ({\n containerRef,\n disableFocus = false,\n requestScroll,\n}: CellFocusHookProps) => {\n const focusableCell = useRef<HTMLElement>();\n\n const focusCell = useCallback<FocusCell>(\n (cellPos) => {\n if (containerRef.current) {\n const activeCell = getTableCell(containerRef, cellPos);\n if (activeCell) {\n if (activeCell !== focusableCell.current) {\n focusableCell.current?.removeAttribute(\"tabindex\");\n focusableCell.current = activeCell;\n activeCell.setAttribute(\"tabindex\", \"0\");\n }\n // TODO needs to be scroll cell\n requestScroll?.({ type: \"scroll-row\", rowIndex: cellPos[0] });\n activeCell.focus({ preventScroll: true });\n }\n }\n },\n // TODO we recreate this function whenever viewportRange changes, which will\n // be often whilst scrolling - store range in a a ref ?\n [containerRef, requestScroll],\n );\n\n const tableBodyRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n if (el) {\n const table = queryClosest<HTMLDivElement>(el, \".vuuTable\");\n if (table) {\n if (focusableCell.current === undefined && !disableFocus) {\n const cell =\n table.querySelector<HTMLDivElement>(headerCellQuery(0)) ||\n table.querySelector<HTMLDivElement>(dataCellQuery(0, 0));\n if (cell) {\n cell.setAttribute(\"tabindex\", \"0\");\n focusableCell.current = cell;\n }\n }\n }\n }\n },\n [disableFocus],\n );\n\n return {\n focusCell,\n tableBodyRef,\n };\n};\n"],"names":["useRef","useCallback","getTableCell","queryClosest","headerCellQuery","dataCellQuery"],"mappings":";;;;;;AAkBO,MAAM,eAAe,CAAC;AAAA,EAC3B,YAAA;AAAA,EACA,YAAe,GAAA,KAAA;AAAA,EACf,aAAA;AACF,CAA0B,KAAA;AACxB,EAAA,MAAM,gBAAgBA,YAAoB,EAAA,CAAA;AAE1C,EAAA,MAAM,SAAY,GAAAC,iBAAA;AAAA,IAChB,CAAC,OAAY,KAAA;AACX,MAAA,IAAI,aAAa,OAAS,EAAA;AACxB,QAAM,MAAA,UAAA,GAAaC,0BAAa,CAAA,YAAA,EAAc,OAAO,CAAA,CAAA;AACrD,QAAA,IAAI,UAAY,EAAA;AACd,UAAI,IAAA,UAAA,KAAe,cAAc,OAAS,EAAA;AACxC,YAAc,aAAA,CAAA,OAAA,EAAS,gBAAgB,UAAU,CAAA,CAAA;AACjD,YAAA,aAAA,CAAc,OAAU,GAAA,UAAA,CAAA;AACxB,YAAW,UAAA,CAAA,YAAA,CAAa,YAAY,GAAG,CAAA,CAAA;AAAA,WACzC;AAEA,UAAA,aAAA,GAAgB,EAAE,IAAM,EAAA,YAAA,EAAc,UAAU,OAAQ,CAAA,CAAC,GAAG,CAAA,CAAA;AAC5D,UAAA,UAAA,CAAW,KAAM,CAAA,EAAE,aAAe,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,SAC1C;AAAA,OACF;AAAA,KACF;AAAA;AAAA;AAAA,IAGA,CAAC,cAAc,aAAa,CAAA;AAAA,GAC9B,CAAA;AAEA,EAAA,MAAM,YAAe,GAAAD,iBAAA;AAAA,IACnB,CAAC,EAAO,KAAA;AACN,MAAA,IAAI,EAAI,EAAA;AACN,QAAM,MAAA,KAAA,GAAQE,qBAA6B,CAAA,EAAA,EAAI,WAAW,CAAA,CAAA;AAC1D,QAAA,IAAI,KAAO,EAAA;AACT,UAAA,IAAI,aAAc,CAAA,OAAA,KAAY,KAAa,CAAA,IAAA,CAAC,YAAc,EAAA;AACxD,YAAA,MAAM,IACJ,GAAA,KAAA,CAAM,aAA8B,CAAAC,6BAAA,CAAgB,CAAC,CAAC,CACtD,IAAA,KAAA,CAAM,aAA8B,CAAAC,2BAAA,CAAc,CAAG,EAAA,CAAC,CAAC,CAAA,CAAA;AACzD,YAAA,IAAI,IAAM,EAAA;AACR,cAAK,IAAA,CAAA,YAAA,CAAa,YAAY,GAAG,CAAA,CAAA;AACjC,cAAA,aAAA,CAAc,OAAU,GAAA,IAAA,CAAA;AAAA,aAC1B;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,YAAY,CAAA;AAAA,GACf,CAAA;AAEA,EAAO,OAAA;AAAA,IACL,SAAA;AAAA,IACA,YAAA;AAAA,GACF,CAAA;AACF;;;;"}
|
|
@@ -4,6 +4,7 @@ var vuuUiControls = require('@vuu-ui/vuu-ui-controls');
|
|
|
4
4
|
var vuuUtils = require('@vuu-ui/vuu-utils');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
|
|
7
|
+
const isRowSelectionKey = (key) => key === "Enter" || key === " ";
|
|
7
8
|
const useControlledTableNavigation = (initialValue, rowCount) => {
|
|
8
9
|
const tableRef = react.useRef(null);
|
|
9
10
|
const [highlightedIndexRef, setHighlightedIndex] = vuuUiControls.useStateRef(initialValue);
|
|
@@ -13,7 +14,7 @@ const useControlledTableNavigation = (initialValue, rowCount) => {
|
|
|
13
14
|
setHighlightedIndex((index = -1) => Math.min(rowCount - 1, index + 1));
|
|
14
15
|
} else if (e.key === "ArrowUp") {
|
|
15
16
|
setHighlightedIndex((index = -1) => Math.max(0, index - 1));
|
|
16
|
-
} else if (e.key
|
|
17
|
+
} else if (isRowSelectionKey(e.key)) {
|
|
17
18
|
const { current: rowIdx } = highlightedIndexRef;
|
|
18
19
|
if (typeof rowIdx === "number") {
|
|
19
20
|
const rowEl = tableRef.current?.querySelector(
|
|
@@ -41,5 +42,6 @@ const useControlledTableNavigation = (initialValue, rowCount) => {
|
|
|
41
42
|
};
|
|
42
43
|
};
|
|
43
44
|
|
|
45
|
+
exports.isRowSelectionKey = isRowSelectionKey;
|
|
44
46
|
exports.useControlledTableNavigation = useControlledTableNavigation;
|
|
45
47
|
//# sourceMappingURL=useControlledTableNavigation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useControlledTableNavigation.js","sources":["../src/useControlledTableNavigation.ts"],"sourcesContent":["import { useStateRef } from \"@vuu-ui/vuu-ui-controls\";\nimport { dispatchMouseEvent } from \"@vuu-ui/vuu-utils\";\nimport { KeyboardEventHandler, useCallback, useRef } from \"react\";\n\nexport const useControlledTableNavigation = (\n initialValue: number,\n rowCount: number,\n) => {\n const tableRef = useRef<HTMLDivElement>(null);\n\n const [highlightedIndexRef, setHighlightedIndex] = useStateRef<\n number | undefined\n >(initialValue);\n\n const handleKeyDown = useCallback<KeyboardEventHandler>(\n (e) => {\n if (e.key === \"ArrowDown\") {\n setHighlightedIndex((index = -1) => Math.min(rowCount - 1, index + 1));\n } else if (e.key === \"ArrowUp\") {\n setHighlightedIndex((index = -1) => Math.max(0, index - 1));\n } else if (e.key
|
|
1
|
+
{"version":3,"file":"useControlledTableNavigation.js","sources":["../src/useControlledTableNavigation.ts"],"sourcesContent":["import { useStateRef } from \"@vuu-ui/vuu-ui-controls\";\nimport { dispatchMouseEvent } from \"@vuu-ui/vuu-utils\";\nimport { KeyboardEventHandler, useCallback, useRef } from \"react\";\n\nexport const isRowSelectionKey = (key: string) =>\n key === \"Enter\" || key === \" \";\n\nexport const useControlledTableNavigation = (\n initialValue: number,\n rowCount: number,\n) => {\n const tableRef = useRef<HTMLDivElement>(null);\n\n const [highlightedIndexRef, setHighlightedIndex] = useStateRef<\n number | undefined\n >(initialValue);\n\n const handleKeyDown = useCallback<KeyboardEventHandler>(\n (e) => {\n if (e.key === \"ArrowDown\") {\n setHighlightedIndex((index = -1) => Math.min(rowCount - 1, index + 1));\n } else if (e.key === \"ArrowUp\") {\n setHighlightedIndex((index = -1) => Math.max(0, index - 1));\n } else if (isRowSelectionKey(e.key)) {\n const { current: rowIdx } = highlightedIndexRef;\n // induce an onSelect event by 'clicking' the row\n if (typeof rowIdx === \"number\") {\n const rowEl = tableRef.current?.querySelector(\n `[aria-rowindex=\"${rowIdx + 1}\"]`,\n ) as HTMLElement;\n if (rowEl) {\n dispatchMouseEvent(rowEl, \"click\");\n }\n }\n }\n },\n [highlightedIndexRef, rowCount, setHighlightedIndex],\n );\n\n const handleHighlight = useCallback(\n (idx: number) => {\n setHighlightedIndex(idx);\n },\n [setHighlightedIndex],\n );\n\n return {\n highlightedIndexRef,\n onHighlight: handleHighlight,\n onKeyDown: handleKeyDown,\n tableRef,\n };\n};\n"],"names":["useRef","useStateRef","useCallback","dispatchMouseEvent"],"mappings":";;;;;;AAIO,MAAM,iBAAoB,GAAA,CAAC,GAChC,KAAA,GAAA,KAAQ,WAAW,GAAQ,KAAA,IAAA;AAEhB,MAAA,4BAAA,GAA+B,CAC1C,YAAA,EACA,QACG,KAAA;AACH,EAAM,MAAA,QAAA,GAAWA,aAAuB,IAAI,CAAA,CAAA;AAE5C,EAAA,MAAM,CAAC,mBAAA,EAAqB,mBAAmB,CAAA,GAAIC,0BAEjD,YAAY,CAAA,CAAA;AAEd,EAAA,MAAM,aAAgB,GAAAC,iBAAA;AAAA,IACpB,CAAC,CAAM,KAAA;AACL,MAAI,IAAA,CAAA,CAAE,QAAQ,WAAa,EAAA;AACzB,QAAoB,mBAAA,CAAA,CAAC,QAAQ,CAAO,CAAA,KAAA,IAAA,CAAK,IAAI,QAAW,GAAA,CAAA,EAAG,KAAQ,GAAA,CAAC,CAAC,CAAA,CAAA;AAAA,OACvE,MAAA,IAAW,CAAE,CAAA,GAAA,KAAQ,SAAW,EAAA;AAC9B,QAAoB,mBAAA,CAAA,CAAC,QAAQ,CAAO,CAAA,KAAA,IAAA,CAAK,IAAI,CAAG,EAAA,KAAA,GAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,OACjD,MAAA,IAAA,iBAAA,CAAkB,CAAE,CAAA,GAAG,CAAG,EAAA;AACnC,QAAM,MAAA,EAAE,OAAS,EAAA,MAAA,EAAW,GAAA,mBAAA,CAAA;AAE5B,QAAI,IAAA,OAAO,WAAW,QAAU,EAAA;AAC9B,UAAM,MAAA,KAAA,GAAQ,SAAS,OAAS,EAAA,aAAA;AAAA,YAC9B,CAAA,gBAAA,EAAmB,SAAS,CAAC,CAAA,EAAA,CAAA;AAAA,WAC/B,CAAA;AACA,UAAA,IAAI,KAAO,EAAA;AACT,YAAAC,2BAAA,CAAmB,OAAO,OAAO,CAAA,CAAA;AAAA,WACnC;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,mBAAqB,EAAA,QAAA,EAAU,mBAAmB,CAAA;AAAA,GACrD,CAAA;AAEA,EAAA,MAAM,eAAkB,GAAAD,iBAAA;AAAA,IACtB,CAAC,GAAgB,KAAA;AACf,MAAA,mBAAA,CAAoB,GAAG,CAAA,CAAA;AAAA,KACzB;AAAA,IACA,CAAC,mBAAmB,CAAA;AAAA,GACtB,CAAA;AAEA,EAAO,OAAA;AAAA,IACL,mBAAA;AAAA,IACA,WAAa,EAAA,eAAA;AAAA,IACb,SAAW,EAAA,aAAA;AAAA,IACX,QAAA;AAAA,GACF,CAAA;AACF;;;;;"}
|
package/cjs/useDataSource.js
CHANGED
|
@@ -20,6 +20,14 @@ const useDataSource = ({
|
|
|
20
20
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21
21
|
[]
|
|
22
22
|
);
|
|
23
|
+
react.useMemo(() => {
|
|
24
|
+
dataSource.on("resumed", () => {
|
|
25
|
+
const { range } = dataSource;
|
|
26
|
+
if (range.to !== 0) {
|
|
27
|
+
dataWindow.setRange(dataSource.range);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}, [dataSource, dataWindow]);
|
|
23
31
|
const setData = react.useCallback(
|
|
24
32
|
(updates) => {
|
|
25
33
|
for (const row of updates) {
|
|
@@ -46,6 +54,11 @@ const useDataSource = ({
|
|
|
46
54
|
}
|
|
47
55
|
}
|
|
48
56
|
if (message.rows) {
|
|
57
|
+
if (message.range) {
|
|
58
|
+
if (message.range.to !== dataWindow.range.to) {
|
|
59
|
+
dataWindow.setRange(message.range);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
49
62
|
setData(message.rows);
|
|
50
63
|
} else if (message.size === 0) {
|
|
51
64
|
setData([]);
|
package/cjs/useDataSource.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataSource.js","sources":["../src/useDataSource.ts"],"sourcesContent":["import {\n DataSource,\n DataSourceRow,\n DataSourceSubscribedMessage,\n SubscribeCallback,\n} from \"@vuu-ui/vuu-data-types\";\nimport { VuuRange } from \"@vuu-ui/vuu-protocol-types\";\nimport { getFullRange, NULL_RANGE, rangesAreSame } from \"@vuu-ui/vuu-utils\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { MovingWindow } from \"./moving-window\";\n\nexport interface DataSourceHookProps {\n dataSource: DataSource;\n onSizeChange: (size: number) => void;\n onSubscribed: (subscription: DataSourceSubscribedMessage) => void;\n renderBufferSize?: number;\n}\n\nexport const useDataSource = ({\n dataSource,\n onSizeChange,\n onSubscribed,\n renderBufferSize = 0,\n}: DataSourceHookProps) => {\n const [, forceUpdate] = useState<unknown>(null);\n const data = useRef<DataSourceRow[]>([]);\n const isMounted = useRef(true);\n const hasUpdated = useRef(false);\n const rangeRef = useRef<VuuRange>(NULL_RANGE);\n\n const dataWindow = useMemo(\n () => new MovingWindow(getFullRange(NULL_RANGE, renderBufferSize)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n\n const setData = useCallback(\n (updates: DataSourceRow[]) => {\n for (const row of updates) {\n dataWindow.add(row);\n }\n data.current = dataWindow.data;\n if (isMounted.current) {\n // TODO do we ever need to worry about missing updates here ?\n forceUpdate({});\n }\n },\n [dataWindow],\n );\n\n const datasourceMessageHandler: SubscribeCallback = useCallback(\n (message) => {\n if (message.type === \"subscribed\") {\n onSubscribed?.(message);\n } else if (message.type === \"viewport-update\") {\n if (typeof message.size === \"number\") {\n onSizeChange?.(message.size);\n const size = dataWindow.data.length;\n dataWindow.setRowCount(message.size);\n if (dataWindow.data.length < size) {\n forceUpdate({});\n }\n }\n if (message.rows) {\n setData(message.rows);\n } else if (message.size === 0) {\n setData([]);\n } else if (typeof message.size === \"number\") {\n data.current = dataWindow.data;\n hasUpdated.current = true;\n }\n } else if (message.type === \"viewport-clear\") {\n onSizeChange?.(0);\n dataWindow.setRowCount(0);\n setData([]);\n forceUpdate({});\n } else {\n console.log(`useDataSource unexpected message ${message.type}`);\n }\n },\n [dataWindow, onSizeChange, onSubscribed, setData],\n );\n\n const getSelectedRows = useCallback(() => {\n return dataWindow.getSelectedRows();\n }, [dataWindow]);\n\n useEffect(() => {\n isMounted.current = true;\n if (dataSource.status !== \"initialising\") {\n dataSource.resume?.(datasourceMessageHandler);\n }\n return () => {\n isMounted.current = false;\n dataSource.suspend?.();\n };\n }, [dataSource, datasourceMessageHandler]);\n\n useEffect(() => {\n if (dataSource.status === \"disabled\") {\n dataSource.enable?.(datasourceMessageHandler);\n }\n }, [dataSource, datasourceMessageHandler, renderBufferSize]);\n\n const setRange = useCallback(\n (range: VuuRange) => {\n if (!rangesAreSame(range, rangeRef.current)) {\n const fullRange = getFullRange(range, renderBufferSize);\n dataWindow.setRange(fullRange);\n\n if (dataSource.status !== \"subscribed\") {\n dataSource?.subscribe({ range: fullRange }, datasourceMessageHandler);\n } else {\n dataSource.range = rangeRef.current = fullRange;\n }\n // emit a range event omitting the renderBufferSize\n // This isn't great, we're using the dataSource as a conduit to emit a\n // message that has nothing to do with the dataSource itself. Client\n // is the DataSourceState component.\n // WHY CANT THIS BE DONE WITHIN
|
|
1
|
+
{"version":3,"file":"useDataSource.js","sources":["../src/useDataSource.ts"],"sourcesContent":["import {\n DataSource,\n DataSourceRow,\n DataSourceSubscribedMessage,\n SubscribeCallback,\n} from \"@vuu-ui/vuu-data-types\";\nimport { VuuRange } from \"@vuu-ui/vuu-protocol-types\";\nimport { getFullRange, NULL_RANGE, rangesAreSame } from \"@vuu-ui/vuu-utils\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { MovingWindow } from \"./moving-window\";\n\nexport interface DataSourceHookProps {\n dataSource: DataSource;\n onSizeChange: (size: number) => void;\n onSubscribed: (subscription: DataSourceSubscribedMessage) => void;\n renderBufferSize?: number;\n}\n\nexport const useDataSource = ({\n dataSource,\n onSizeChange,\n onSubscribed,\n renderBufferSize = 0,\n}: DataSourceHookProps) => {\n const [, forceUpdate] = useState<unknown>(null);\n const data = useRef<DataSourceRow[]>([]);\n const isMounted = useRef(true);\n const hasUpdated = useRef(false);\n const rangeRef = useRef<VuuRange>(NULL_RANGE);\n\n const dataWindow = useMemo(\n () => new MovingWindow(getFullRange(NULL_RANGE, renderBufferSize)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n );\n\n useMemo(() => {\n dataSource.on(\"resumed\", () => {\n // When we resume a dataSource (after switching tabs etc)\n // client will receive rows. We may not have received any\n // setRange calls at this point so dataWindow range will\n //not yet be set. If the dataWindow range is already set,\n // this is a no-op.\n const { range } = dataSource;\n if (range.to !== 0) {\n dataWindow.setRange(dataSource.range);\n }\n });\n }, [dataSource, dataWindow]);\n\n const setData = useCallback(\n (updates: DataSourceRow[]) => {\n for (const row of updates) {\n dataWindow.add(row);\n }\n data.current = dataWindow.data;\n if (isMounted.current) {\n // TODO do we ever need to worry about missing updates here ?\n forceUpdate({});\n }\n },\n [dataWindow],\n );\n\n const datasourceMessageHandler: SubscribeCallback = useCallback(\n (message) => {\n if (message.type === \"subscribed\") {\n onSubscribed?.(message);\n } else if (message.type === \"viewport-update\") {\n if (typeof message.size === \"number\") {\n onSizeChange?.(message.size);\n const size = dataWindow.data.length;\n dataWindow.setRowCount(message.size);\n if (dataWindow.data.length < size) {\n forceUpdate({});\n }\n }\n if (message.rows) {\n if (message.range) {\n if (message.range.to !== dataWindow.range.to) {\n dataWindow.setRange(message.range);\n }\n }\n setData(message.rows);\n } else if (message.size === 0) {\n setData([]);\n } else if (typeof message.size === \"number\") {\n data.current = dataWindow.data;\n hasUpdated.current = true;\n }\n } else if (message.type === \"viewport-clear\") {\n onSizeChange?.(0);\n dataWindow.setRowCount(0);\n setData([]);\n forceUpdate({});\n } else {\n console.log(`useDataSource unexpected message ${message.type}`);\n }\n },\n [dataWindow, onSizeChange, onSubscribed, setData],\n );\n\n const getSelectedRows = useCallback(() => {\n return dataWindow.getSelectedRows();\n }, [dataWindow]);\n\n useEffect(() => {\n isMounted.current = true;\n if (dataSource.status !== \"initialising\") {\n dataSource.resume?.(datasourceMessageHandler);\n }\n return () => {\n isMounted.current = false;\n dataSource.suspend?.();\n };\n }, [dataSource, datasourceMessageHandler]);\n\n useEffect(() => {\n if (dataSource.status === \"disabled\") {\n dataSource.enable?.(datasourceMessageHandler);\n }\n }, [dataSource, datasourceMessageHandler, renderBufferSize]);\n\n const setRange = useCallback(\n (range: VuuRange) => {\n if (!rangesAreSame(range, rangeRef.current)) {\n const fullRange = getFullRange(range, renderBufferSize);\n dataWindow.setRange(fullRange);\n\n if (dataSource.status !== \"subscribed\") {\n dataSource?.subscribe({ range: fullRange }, datasourceMessageHandler);\n } else {\n dataSource.range = rangeRef.current = fullRange;\n }\n // emit a range event omitting the renderBufferSize\n // This isn't great, we're using the dataSource as a conduit to emit a\n // message that has nothing to do with the dataSource itself. Client\n // is the DataSourceState component.\n // WHY CANT THIS BE DONE WITHIN DataSource ?\n dataSource.emit(\"range\", range);\n }\n },\n [dataSource, dataWindow, datasourceMessageHandler, renderBufferSize],\n );\n\n return {\n data: data.current,\n dataRef: data,\n getSelectedRows,\n range: rangeRef.current,\n setRange,\n };\n};\n"],"names":["useState","useRef","NULL_RANGE","useMemo","MovingWindow","getFullRange","useCallback","useEffect","rangesAreSame"],"mappings":"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"}
|
|
@@ -28,43 +28,12 @@ const isNavigationKey = (key, navigationStyle) => {
|
|
|
28
28
|
};
|
|
29
29
|
const PageKeys = ["Home", "End", "PageUp", "PageDown"];
|
|
30
30
|
const isPagingKey = (key) => PageKeys.includes(key);
|
|
31
|
-
const NULL_CELL_POS = [-1, -1];
|
|
32
|
-
function nextCellPos(key, [rowIdx, colIdx], columnCount, rowCount) {
|
|
33
|
-
if (key === "ArrowUp") {
|
|
34
|
-
if (rowIdx > -1) {
|
|
35
|
-
return [rowIdx - 1, colIdx];
|
|
36
|
-
} else {
|
|
37
|
-
return [rowIdx, colIdx];
|
|
38
|
-
}
|
|
39
|
-
} else if (key === "ArrowDown") {
|
|
40
|
-
if (rowIdx === -1) {
|
|
41
|
-
return [0, colIdx];
|
|
42
|
-
} else if (rowIdx === rowCount - 1) {
|
|
43
|
-
return [rowIdx, colIdx];
|
|
44
|
-
} else {
|
|
45
|
-
return [rowIdx + 1, colIdx];
|
|
46
|
-
}
|
|
47
|
-
} else if (key === "ArrowRight") {
|
|
48
|
-
if (colIdx < columnCount) {
|
|
49
|
-
return [rowIdx, colIdx + 1];
|
|
50
|
-
} else {
|
|
51
|
-
return [rowIdx, colIdx];
|
|
52
|
-
}
|
|
53
|
-
} else if (key === "ArrowLeft") {
|
|
54
|
-
if (colIdx > 1) {
|
|
55
|
-
return [rowIdx, colIdx - 1];
|
|
56
|
-
} else {
|
|
57
|
-
return [rowIdx, colIdx];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return [rowIdx, colIdx];
|
|
61
|
-
}
|
|
62
31
|
const useKeyboardNavigation = ({
|
|
63
32
|
columnCount = 0,
|
|
64
33
|
containerRef,
|
|
65
|
-
disableFocus = false,
|
|
66
34
|
defaultHighlightedIndex,
|
|
67
35
|
disableHighlightOnFocus,
|
|
36
|
+
focusCell,
|
|
68
37
|
highlightedIndex: highlightedIndexProp,
|
|
69
38
|
navigationStyle,
|
|
70
39
|
requestScroll,
|
|
@@ -73,7 +42,6 @@ const useKeyboardNavigation = ({
|
|
|
73
42
|
viewportRowCount
|
|
74
43
|
}) => {
|
|
75
44
|
const focusedCellPos = react.useRef([-1, -1]);
|
|
76
|
-
const focusableCell = react.useRef();
|
|
77
45
|
const activeCellPos = react.useRef([-1, 0]);
|
|
78
46
|
const highlightedIndexRef = react.useRef();
|
|
79
47
|
const [highlightedIndex, setHighlightedIdx] = core.useControlled({
|
|
@@ -92,39 +60,6 @@ const useKeyboardNavigation = ({
|
|
|
92
60
|
const getFocusedCell = (element) => element?.closest(
|
|
93
61
|
"[role='columnHeader'],[role='cell']"
|
|
94
62
|
);
|
|
95
|
-
const getTableCellPos = (tableCell) => {
|
|
96
|
-
if (tableCell.role === "columnHeader") {
|
|
97
|
-
const colIdx = parseInt(tableCell.dataset.idx ?? "-1", 10);
|
|
98
|
-
return [-1, colIdx];
|
|
99
|
-
} else {
|
|
100
|
-
const focusedRow = tableCell.closest("[role='row']");
|
|
101
|
-
if (focusedRow) {
|
|
102
|
-
const rowIdx = vuuUtils.getIndexFromRowElement(focusedRow);
|
|
103
|
-
const colIdx = Array.from(focusedRow.childNodes).indexOf(tableCell);
|
|
104
|
-
return [rowIdx, colIdx];
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return NULL_CELL_POS;
|
|
108
|
-
};
|
|
109
|
-
const focusCell = react.useCallback(
|
|
110
|
-
(cellPos) => {
|
|
111
|
-
if (containerRef.current) {
|
|
112
|
-
const activeCell = tableDomUtils.getTableCell(containerRef, cellPos);
|
|
113
|
-
if (activeCell) {
|
|
114
|
-
if (activeCell !== focusableCell.current) {
|
|
115
|
-
focusableCell.current?.removeAttribute("tabindex");
|
|
116
|
-
focusableCell.current = activeCell;
|
|
117
|
-
activeCell.setAttribute("tabindex", "0");
|
|
118
|
-
}
|
|
119
|
-
requestScroll?.({ type: "scroll-row", rowIndex: cellPos[0] });
|
|
120
|
-
activeCell.focus({ preventScroll: true });
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
// TODO we recreate this function whenever viewportRange changes, which will
|
|
125
|
-
// be often whilst scrolling - store range in a a ref ?
|
|
126
|
-
[containerRef, requestScroll]
|
|
127
|
-
);
|
|
128
63
|
const setActiveCell = react.useCallback(
|
|
129
64
|
(rowIdx, colIdx, fromKeyboard = false) => {
|
|
130
65
|
const pos = [rowIdx, colIdx];
|
|
@@ -184,7 +119,7 @@ const useKeyboardNavigation = ({
|
|
|
184
119
|
if (containerRef.current?.contains(document.activeElement)) {
|
|
185
120
|
const focusedCell = getFocusedCell(document.activeElement);
|
|
186
121
|
if (focusedCell) {
|
|
187
|
-
focusedCellPos.current = getTableCellPos(focusedCell);
|
|
122
|
+
focusedCellPos.current = tableDomUtils.getTableCellPos(focusedCell);
|
|
188
123
|
if (navigationStyle === "row") {
|
|
189
124
|
setHighlightedIdx(focusedCellPos.current[0]);
|
|
190
125
|
}
|
|
@@ -199,7 +134,7 @@ const useKeyboardNavigation = ({
|
|
|
199
134
|
]);
|
|
200
135
|
const navigateChildItems = react.useCallback(
|
|
201
136
|
async (key) => {
|
|
202
|
-
const [nextRowIdx, nextColIdx] = isPagingKey(key) ? await nextPageItemIdx(key, activeCellPos.current) :
|
|
137
|
+
const [nextRowIdx, nextColIdx] = isPagingKey(key) ? await nextPageItemIdx(key, activeCellPos.current) : tableDomUtils.getNextCellPos(key, activeCellPos.current, columnCount, rowCount);
|
|
203
138
|
const [rowIdx, colIdx] = activeCellPos.current;
|
|
204
139
|
if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {
|
|
205
140
|
setActiveCell(nextRowIdx, nextColIdx, true);
|
|
@@ -216,7 +151,7 @@ const useKeyboardNavigation = ({
|
|
|
216
151
|
const moveHighlightedRow = react.useCallback(
|
|
217
152
|
async (key) => {
|
|
218
153
|
const { current: highlighted } = highlightedIndexRef;
|
|
219
|
-
const [nextRowIdx] = isPagingKey(key) ? await nextPageItemIdx(key, [highlighted ?? -1, 0]) :
|
|
154
|
+
const [nextRowIdx] = isPagingKey(key) ? await nextPageItemIdx(key, [highlighted ?? -1, 0]) : tableDomUtils.getNextCellPos(key, [highlighted ?? -1, 0], columnCount, rowCount);
|
|
220
155
|
if (nextRowIdx !== highlighted) {
|
|
221
156
|
setHighlightedIndex(nextRowIdx);
|
|
222
157
|
scrollRowIntoViewIfNecessary(nextRowIdx);
|
|
@@ -232,7 +167,9 @@ const useKeyboardNavigation = ({
|
|
|
232
167
|
);
|
|
233
168
|
react.useEffect(() => {
|
|
234
169
|
if (highlightedIndexProp !== void 0 && highlightedIndexProp !== -1) {
|
|
235
|
-
|
|
170
|
+
requestAnimationFrame(() => {
|
|
171
|
+
scrollRowIntoViewIfNecessary(highlightedIndexProp);
|
|
172
|
+
});
|
|
236
173
|
}
|
|
237
174
|
}, [highlightedIndexProp, scrollRowIntoViewIfNecessary]);
|
|
238
175
|
const handleKeyDown = react.useCallback(
|
|
@@ -259,7 +196,7 @@ const useKeyboardNavigation = ({
|
|
|
259
196
|
const target = evt.target;
|
|
260
197
|
const focusedCell = getFocusedCell(target);
|
|
261
198
|
if (focusedCell) {
|
|
262
|
-
const [rowIdx, colIdx] = getTableCellPos(focusedCell);
|
|
199
|
+
const [rowIdx, colIdx] = tableDomUtils.getTableCellPos(focusedCell);
|
|
263
200
|
setActiveCell(rowIdx, colIdx);
|
|
264
201
|
}
|
|
265
202
|
},
|
|
@@ -280,17 +217,6 @@ const useKeyboardNavigation = ({
|
|
|
280
217
|
const navigate = react.useCallback(() => {
|
|
281
218
|
navigateChildItems("ArrowDown");
|
|
282
219
|
}, [navigateChildItems]);
|
|
283
|
-
const fullyRendered = containerRef.current?.firstChild != null;
|
|
284
|
-
react.useEffect(() => {
|
|
285
|
-
if (fullyRendered && focusableCell.current === void 0 && !disableFocus) {
|
|
286
|
-
const { current: container } = containerRef;
|
|
287
|
-
const cell = container?.querySelector(tableDomUtils.headerCellQuery(0)) || container?.querySelector(tableDomUtils.dataCellQuery(0, 0));
|
|
288
|
-
if (cell) {
|
|
289
|
-
cell.setAttribute("tabindex", "0");
|
|
290
|
-
focusableCell.current = cell;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}, [containerRef, disableFocus, fullyRendered]);
|
|
294
220
|
return {
|
|
295
221
|
highlightedIndexRef,
|
|
296
222
|
navigate,
|