@absreim/react-bootstrap-data-grid 2.0.0 → 2.2.0
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/Grid.d.ts +1 -0
- package/Grid.js +51 -19
- package/export/ExportForm.d.ts +9 -0
- package/export/ExportForm.js +97 -0
- package/export/types.d.ts +5 -0
- package/export/types.js +1 -0
- package/export/useExportFn.d.ts +23 -0
- package/export/useExportFn.js +115 -0
- package/filtering/DateFilterRow.js +2 -3
- package/filtering/FilterOptionsTable.d.ts +1 -1
- package/filtering/FilterOptionsTable.js +3 -1
- package/filtering/types.d.ts +7 -1
- package/package.json +3 -2
- package/pagination/Pagination.d.ts +3 -10
- package/pagination/Pagination.js +8 -4
- package/pagination/types.d.ts +17 -7
- package/pipeline/useCurrentPageRows.d.ts +5 -2
- package/pipeline/useCurrentPageRows.js +45 -7
- package/pipeline/useFilterStateStore.d.ts +4 -0
- package/pipeline/useFilterStateStore.js +57 -0
- package/pipeline/useSortedRows.d.ts +7 -2
- package/pipeline/useSortedRows.js +16 -6
- package/selection/types.d.ts +1 -1
- package/sorting/types.d.ts +7 -1
- package/styling/styleModelUnwrappers.js +1 -0
- package/styling/types.d.ts +16 -0
- package/toolbar/Toolbar.d.ts +12 -0
- package/toolbar/Toolbar.js +26 -0
- package/toolbar/ToolbarContainer.d.ts +9 -0
- package/toolbar/ToolbarContainer.js +24 -0
- package/toolbar/types.d.ts +3 -0
- package/toolbar/types.js +1 -0
- package/toolbar/useInterfaces.d.ts +9 -0
- package/toolbar/useInterfaces.js +23 -0
package/Grid.d.ts
CHANGED
package/Grid.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useMemo, useState } from "react";
|
|
3
|
+
import { useId, useMemo, useState } from "react";
|
|
4
4
|
import ColHeaderCell from "./ColHeaderCell";
|
|
5
5
|
import useFilter from "./pipeline/useFilter";
|
|
6
6
|
import ToggleButton from "./ToggleButton";
|
|
@@ -17,18 +17,51 @@ import inputStrsToRowData from "./editing/inputStrsToRowData";
|
|
|
17
17
|
import { unwrapAdditionalComponentsStyleModel, unwrapTableStyleModel, } from "./styling/styleModelUnwrappers";
|
|
18
18
|
import useCurrentPageRows from "./pipeline/useCurrentPageRows";
|
|
19
19
|
import isSubset from "./util/isSubset";
|
|
20
|
+
import useFilterStateStore from "./pipeline/useFilterStateStore";
|
|
21
|
+
import useInterfaces from "./toolbar/useInterfaces";
|
|
22
|
+
import ToolbarContainer from "./toolbar/ToolbarContainer";
|
|
23
|
+
import useExportFn from "./export/useExportFn";
|
|
20
24
|
var Grid = function (_a) {
|
|
21
25
|
var _b;
|
|
22
|
-
var rows = _a.rows, cols = _a.cols, pagination = _a.pagination, sortModel = _a.sortModel, filterModel = _a.filterModel, selectModel = _a.selectModel, editModel = _a.editModel, caption = _a.caption, styleModel = _a.styleModel;
|
|
23
|
-
var
|
|
24
|
-
var
|
|
26
|
+
var rows = _a.rows, cols = _a.cols, pagination = _a.pagination, sortModel = _a.sortModel, filterModel = _a.filterModel, selectModel = _a.selectModel, editModel = _a.editModel, caption = _a.caption, styleModel = _a.styleModel, useToolbar = _a.useToolbar;
|
|
27
|
+
var normalizedTableFilterModel = useFilterStateStore(filterModel, cols);
|
|
28
|
+
var editableFilterState = (normalizedTableFilterModel === null || normalizedTableFilterModel === void 0 ? void 0 : normalizedTableFilterModel.tableFilterState) || null;
|
|
25
29
|
var filteredRows = useFilter(rows, editableFilterState);
|
|
26
|
-
var
|
|
27
|
-
var
|
|
30
|
+
var filterState = useFilterStateFromEditable(cols, editableFilterState);
|
|
31
|
+
var _c = useSortedRows(filteredRows, cols, sortModel), sortedRows = _c.sortedRows, sortingEnabled = _c.sortingEnabled, sortColDef = _c.sortColDef, setSortColDef = _c.setSortColDef;
|
|
32
|
+
var _d = useCurrentPageRows(sortedRows, pagination), paginatedRows = _d.paginatedRows, normalizedModel = _d.normalizedModel;
|
|
28
33
|
var showSelectCol = selectModel && selectModel.mode !== "row";
|
|
29
34
|
var ariaColIndexOffset = showSelectCol ? 1 : 0;
|
|
30
|
-
var displayRows = useDisplayRows(
|
|
31
|
-
var
|
|
35
|
+
var displayRows = useDisplayRows(paginatedRows, cols, ariaColIndexOffset);
|
|
36
|
+
var _e = useState(false), filterOptionsVisible = _e[0], setFilterOptionsVisible = _e[1];
|
|
37
|
+
var exportFnInfo = useExportFn({
|
|
38
|
+
rows: rows,
|
|
39
|
+
cols: cols,
|
|
40
|
+
filteredRows: filterModel && filteredRows,
|
|
41
|
+
currentPageRows: pagination && paginatedRows,
|
|
42
|
+
});
|
|
43
|
+
var toolbarInterfaceParams = useMemo(function () { return ({
|
|
44
|
+
filtering: useToolbar && filterState && filterModel && normalizedTableFilterModel
|
|
45
|
+
? {
|
|
46
|
+
filterState: filterState,
|
|
47
|
+
setFilterState: normalizedTableFilterModel.setTableFilterState,
|
|
48
|
+
caption: filterModel.filterTableCaption,
|
|
49
|
+
styleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.filterInputTableStyleModel,
|
|
50
|
+
}
|
|
51
|
+
: undefined,
|
|
52
|
+
exporting: useToolbar
|
|
53
|
+
? { exportFnInfo: exportFnInfo, styleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.exportFormStyleModel }
|
|
54
|
+
: undefined,
|
|
55
|
+
}); }, [
|
|
56
|
+
exportFnInfo,
|
|
57
|
+
filterModel,
|
|
58
|
+
filterState,
|
|
59
|
+
normalizedTableFilterModel,
|
|
60
|
+
styleModel === null || styleModel === void 0 ? void 0 : styleModel.exportFormStyleModel,
|
|
61
|
+
styleModel === null || styleModel === void 0 ? void 0 : styleModel.filterInputTableStyleModel,
|
|
62
|
+
useToolbar,
|
|
63
|
+
]);
|
|
64
|
+
var toolbarInterfaces = useInterfaces(toolbarInterfaceParams);
|
|
32
65
|
var handleToggleFilterOptions = function () {
|
|
33
66
|
setFilterOptionsVisible(!filterOptionsVisible);
|
|
34
67
|
};
|
|
@@ -79,11 +112,12 @@ var Grid = function (_a) {
|
|
|
79
112
|
selectModel.setSelected(selectModel.selected.filter(function (num) { return num !== index; }));
|
|
80
113
|
}; };
|
|
81
114
|
// used to group radio buttons for selection
|
|
115
|
+
var gridId = useId();
|
|
82
116
|
var getSelectInputModel = function (id, selectModel) {
|
|
83
117
|
if (selectModel.type === "single") {
|
|
84
118
|
return {
|
|
85
119
|
type: "radio",
|
|
86
|
-
name: selectModel.groupName,
|
|
120
|
+
name: selectModel.groupName || gridId,
|
|
87
121
|
};
|
|
88
122
|
}
|
|
89
123
|
return {
|
|
@@ -113,9 +147,9 @@ var Grid = function (_a) {
|
|
|
113
147
|
}
|
|
114
148
|
var getMultiExistingSelection = function (selectionExists, rows) {
|
|
115
149
|
var rowIndices = rows.map(function (_, index) { return index; });
|
|
116
|
-
|
|
117
|
-
// Note that isFullSelection is true if there are no rows at all. In that case, the existing selection value
|
|
150
|
+
// Note that isFullSelection is true if there are no rows at all. In that case, the return value of this function
|
|
118
151
|
// should be "none", not "full".
|
|
152
|
+
var isFullSelection = isSubset(rowIndices, selectModel.selected);
|
|
119
153
|
if (!selectionExists) {
|
|
120
154
|
return "none";
|
|
121
155
|
}
|
|
@@ -157,18 +191,16 @@ var Grid = function (_a) {
|
|
|
157
191
|
var unwrappedAdditionalStyleModel = useMemo(function () {
|
|
158
192
|
return unwrapAdditionalComponentsStyleModel(styleModel === null || styleModel === void 0 ? void 0 : styleModel.additionalComponentsStyleModel);
|
|
159
193
|
}, [styleModel === null || styleModel === void 0 ? void 0 : styleModel.additionalComponentsStyleModel]);
|
|
160
|
-
return (_jsxs("div", { "data-testid": "rbdg-top-level-div", className: classNames(unwrappedAdditionalStyleModel.topLevelDiv), children: [
|
|
194
|
+
return (_jsxs("div", { "data-testid": "rbdg-top-level-div", className: classNames(unwrappedAdditionalStyleModel.topLevelDiv), children: [normalizedTableFilterModel && !useToolbar && (_jsxs("div", { "data-testid": "rbdg-filter-inputs-div", className: classNames(unwrappedAdditionalStyleModel.filterInputsDiv), children: [_jsx(ToggleButton, { isActive: filterOptionsVisible, label: "".concat(filterOptionsVisible ? "Hide" : "Show ", " Filter Options"), onClick: handleToggleFilterOptions, classes: (_b = styleModel === null || styleModel === void 0 ? void 0 : styleModel.additionalComponentsStyleModel) === null || _b === void 0 ? void 0 : _b.filterUiToggleButton }), filterOptionsVisible && (_jsx(FilterOptionsTable, { caption: filterModel.filterTableCaption, filterState: filterState, setFilterState: normalizedTableFilterModel.setTableFilterState, styleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.filterInputTableStyleModel }))] })), useToolbar && (_jsx(ToolbarContainer, { interfaces: toolbarInterfaces, styleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.toolbarStyleModel })), _jsxs("div", { "data-testid": "rbdg-table-and-pagination-div", className: classNames(unwrappedAdditionalStyleModel.tableAndPaginationDiv), children: [_jsxs("table", { className: classNames("table", {
|
|
161
195
|
"table-hover": rowsAreSelectable,
|
|
162
196
|
}, unwrappedTableModel.table), "aria-rowcount": filteredRows.length + 1, children: [caption !== undefined && (_jsx("caption", { className: classNames(unwrappedTableModel.caption), children: caption })), _jsx("thead", { className: classNames(unwrappedTableModel.thead), children: _jsxs("tr", { "aria-rowindex": 1, className: classNames(unwrappedTableModel.theadTr), children: [showSelectCol && (_jsx(SelectAllHeaderCell, { selectionInfo: selectionInfo, onClick: selectAllOnClick, totalRows: rows.length, additionalClasses: unwrappedTableModel.rowSelectColTh })), cols.map(function (_a, index) {
|
|
163
|
-
var _b;
|
|
164
197
|
var name = _a.name, label = _a.label, sortable = _a.sortable;
|
|
165
|
-
var colSortModel =
|
|
198
|
+
var colSortModel = sortingEnabled && sortable
|
|
166
199
|
? {
|
|
167
|
-
sortOrder: (
|
|
168
|
-
? sortModel.sortColDef.order
|
|
169
|
-
: null,
|
|
200
|
+
sortOrder: (sortColDef === null || sortColDef === void 0 ? void 0 : sortColDef.name) === name ? sortColDef.order : null,
|
|
170
201
|
setSortOrder: function (order) {
|
|
171
|
-
|
|
202
|
+
setSortColDef &&
|
|
203
|
+
setSortColDef(order && { name: name, order: order });
|
|
172
204
|
},
|
|
173
205
|
}
|
|
174
206
|
: undefined;
|
|
@@ -183,6 +215,6 @@ var Grid = function (_a) {
|
|
|
183
215
|
}, dataCellInputClasses: function (colIndex) {
|
|
184
216
|
return unwrappedTableModel.tbodyTdInput(row.id, index, colIndex);
|
|
185
217
|
}, editCellClasses: unwrappedTableModel.editColTd(row.id, index), saveButtonClasses: unwrappedTableModel.editSaveButton(row.id, index), deleteButtonClasses: unwrappedTableModel.editDeleteButton(row.id, index), startButtonClasses: unwrappedTableModel.editStartButton(row.id, index), cancelButtonClasses: unwrappedTableModel.editCancelButton(row.id, index), children: showSelectCol && (_jsx("td", { className: classNames(unwrappedTableModel.rowSelectColTd(row.id, index)), "aria-colindex": 1, children: _jsx(SelectionInput, { selected: selectedSet.has(row.id), selectionInputModel: getSelectInputModel(row.id, selectModel), selectCallback: getSelectHandler(row.id), additionalClasses: unwrappedTableModel.rowSelectInput(row.id, index) }) })) }, row.id));
|
|
186
|
-
}) })] }),
|
|
218
|
+
}) })] }), normalizedModel && (_jsx(Pagination, { normalizedModel: normalizedModel, prePagingNumRows: sortedRows.length, containerDivClasses: unwrappedAdditionalStyleModel.paginationUiDiv }))] })] }));
|
|
187
219
|
};
|
|
188
220
|
export default Grid;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ExportFnInfo } from "./useExportFn";
|
|
2
|
+
import { FC } from "react";
|
|
3
|
+
import { ExportFormStyleModel } from "../styling/types";
|
|
4
|
+
export interface ExportFormProps {
|
|
5
|
+
exportFnInfo: ExportFnInfo;
|
|
6
|
+
styleModel?: ExportFormStyleModel;
|
|
7
|
+
}
|
|
8
|
+
declare const ExportForm: FC<ExportFormProps>;
|
|
9
|
+
export default ExportForm;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { useId, useState } from "react";
|
|
14
|
+
import classNames from "classnames";
|
|
15
|
+
var ExportForm = function (_a) {
|
|
16
|
+
var _b = _a.exportFnInfo, exportFn = _b.exportFn, formattersExist = _b.formattersExist, paginationEnabled = _b.paginationEnabled, filteringEnabled = _b.filteringEnabled, rowCounts = _b.rowCounts, styleModel = _a.styleModel;
|
|
17
|
+
var formId = useId();
|
|
18
|
+
var _c = useState({
|
|
19
|
+
stage: "original",
|
|
20
|
+
formatted: false,
|
|
21
|
+
fileType: "json",
|
|
22
|
+
}), formState = _c[0], setFormState = _c[1];
|
|
23
|
+
var getChangeHandler = function (field, value) {
|
|
24
|
+
return function () {
|
|
25
|
+
setFormState(function (prev) {
|
|
26
|
+
var _a;
|
|
27
|
+
return (__assign(__assign({}, prev), (_a = {}, _a[field] = value, _a)));
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
var getRowCountLabel = function (featureType, count) {
|
|
32
|
+
if (count === undefined) {
|
|
33
|
+
return "".concat(featureType, " disabled");
|
|
34
|
+
}
|
|
35
|
+
return "".concat(count, " ").concat(count === 1 ? "row" : "rows");
|
|
36
|
+
};
|
|
37
|
+
var stageOptions = [
|
|
38
|
+
{
|
|
39
|
+
value: "original",
|
|
40
|
+
label: "Original rows (total ".concat(rowCounts.total, " ").concat(rowCounts.total === 1 ? "row" : "rows", ")"),
|
|
41
|
+
disabled: false,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
value: "filtered",
|
|
45
|
+
label: "After filters applied (".concat(getRowCountLabel("filtering", rowCounts.filtered), ")"),
|
|
46
|
+
disabled: !filteringEnabled,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
value: "paged",
|
|
50
|
+
label: "Current page only (".concat(getRowCountLabel("pagination", rowCounts.currentPage), ")"),
|
|
51
|
+
disabled: !paginationEnabled,
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
var formatOptions = [
|
|
55
|
+
{
|
|
56
|
+
formatted: false,
|
|
57
|
+
label: "Use original data",
|
|
58
|
+
disabled: false,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
formatted: true,
|
|
62
|
+
label: "Apply formatters to data".concat(formattersExist ? "" : " (no formatters defined)"),
|
|
63
|
+
disabled: !formattersExist,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
var fileTypeOptions = [
|
|
67
|
+
{
|
|
68
|
+
fileType: "json",
|
|
69
|
+
label: "JSON",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
fileType: "csv",
|
|
73
|
+
label: "CSV",
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
var handleSubmit = function (event) {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
var stage = formState.stage, fileType = formState.fileType, formatted = formState.formatted;
|
|
79
|
+
exportFn(stage, fileType, formatted);
|
|
80
|
+
};
|
|
81
|
+
var legendClasses = classNames((styleModel === null || styleModel === void 0 ? void 0 : styleModel.legend) || []);
|
|
82
|
+
var radioContainerClasses = classNames((styleModel === null || styleModel === void 0 ? void 0 : styleModel.radioContainer) || ["form-check"]);
|
|
83
|
+
var radioInputClasses = classNames((styleModel === null || styleModel === void 0 ? void 0 : styleModel.radioInput) || ["form-check-input"]);
|
|
84
|
+
var radioLabelClasses = classNames((styleModel === null || styleModel === void 0 ? void 0 : styleModel.radioLabel) || ["form-check-label"]);
|
|
85
|
+
var submitButtonClasses = classNames((styleModel === null || styleModel === void 0 ? void 0 : styleModel.submitButton) || ["btn", "btn-secondary"]);
|
|
86
|
+
return (_jsxs("form", { onSubmit: handleSubmit, children: [_jsxs("fieldset", { children: [_jsx("legend", { className: legendClasses, children: "Choose data to export" }), stageOptions.map(function (_a) {
|
|
87
|
+
var value = _a.value, label = _a.label, disabled = _a.disabled;
|
|
88
|
+
return (_jsxs("div", { className: radioContainerClasses, children: [_jsx("input", { className: radioInputClasses, type: "radio", id: "".concat(formId, "-").concat(value), value: value, checked: formState.stage === value, onChange: getChangeHandler("stage", value), disabled: disabled }), _jsx("label", { className: radioLabelClasses, htmlFor: "".concat(formId, "-").concat(value), children: label })] }, value));
|
|
89
|
+
})] }), _jsxs("fieldset", { children: [_jsx("legend", { className: legendClasses, children: "Choose whether to apply formatters" }), formatOptions.map(function (_a) {
|
|
90
|
+
var formatted = _a.formatted, label = _a.label, disabled = _a.disabled;
|
|
91
|
+
return (_jsxs("div", { className: radioContainerClasses, children: [_jsx("input", { className: radioInputClasses, type: "radio", id: "".concat(formId, "-").concat(formatted), value: String(formatted), checked: formState.formatted === formatted, onChange: getChangeHandler("formatted", formatted), disabled: disabled }), _jsx("label", { className: radioLabelClasses, htmlFor: "".concat(formId, "-").concat(formatted), children: label })] }, String(formatted)));
|
|
92
|
+
})] }), _jsxs("fieldset", { children: [_jsx("legend", { className: legendClasses, children: "Choose the file type" }), fileTypeOptions.map(function (_a) {
|
|
93
|
+
var fileType = _a.fileType, label = _a.label;
|
|
94
|
+
return (_jsxs("div", { className: radioContainerClasses, children: [_jsx("input", { className: radioInputClasses, type: "radio", id: "".concat(formId, "-").concat(fileType), value: fileType, checked: formState.fileType === fileType, onChange: getChangeHandler("fileType", fileType) }), _jsx("label", { className: radioLabelClasses, htmlFor: "".concat(formId, "-").concat(fileType), children: label })] }, fileType));
|
|
95
|
+
})] }), _jsx("button", { type: "submit", className: submitButtonClasses, children: "Submit" })] }));
|
|
96
|
+
};
|
|
97
|
+
export default ExportForm;
|
package/export/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ColDef, RowDef } from "../types";
|
|
2
|
+
export interface UseExportFnsParams {
|
|
3
|
+
rows: RowDef[];
|
|
4
|
+
cols: ColDef[];
|
|
5
|
+
filteredRows?: RowDef[];
|
|
6
|
+
currentPageRows?: RowDef[];
|
|
7
|
+
}
|
|
8
|
+
export type Stage = "original" | "filtered" | "paged";
|
|
9
|
+
export type FileType = "csv" | "json";
|
|
10
|
+
export type ExportFn = (stage: Stage, fileType: FileType, formatted: boolean) => void;
|
|
11
|
+
export interface ExportFnInfo {
|
|
12
|
+
exportFn: ExportFn;
|
|
13
|
+
formattersExist: boolean;
|
|
14
|
+
filteringEnabled: boolean;
|
|
15
|
+
paginationEnabled: boolean;
|
|
16
|
+
rowCounts: {
|
|
17
|
+
total: number;
|
|
18
|
+
filtered?: number;
|
|
19
|
+
currentPage?: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
declare const useExportFn: (params: UseExportFnsParams) => ExportFnInfo;
|
|
23
|
+
export default useExportFn;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { dateToDatetimeInputStr, dateToInputStr } from "../util/datetime";
|
|
13
|
+
import Papa from "papaparse";
|
|
14
|
+
import { useCallback, useMemo } from "react";
|
|
15
|
+
var downloadFile = function (data, filename, type) {
|
|
16
|
+
var blob = new Blob([data], { type: type });
|
|
17
|
+
var url = URL.createObjectURL(blob);
|
|
18
|
+
var a = document.createElement("a");
|
|
19
|
+
a.href = url;
|
|
20
|
+
a.download = filename;
|
|
21
|
+
a.click();
|
|
22
|
+
a.remove();
|
|
23
|
+
setTimeout(function () { return URL.revokeObjectURL(url); }, 0);
|
|
24
|
+
};
|
|
25
|
+
var getDefaultFormatter = function (type) {
|
|
26
|
+
switch (type) {
|
|
27
|
+
case "date":
|
|
28
|
+
return dateToInputStr;
|
|
29
|
+
case "datetime":
|
|
30
|
+
return dateToDatetimeInputStr;
|
|
31
|
+
default:
|
|
32
|
+
return function (a) { return a; };
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var applyFormatters = function (rows, cols, defaultOnly) {
|
|
36
|
+
var colToFormatter = cols.reduce(function (map, _a) {
|
|
37
|
+
var name = _a.name, formatter = _a.formatter, type = _a.type;
|
|
38
|
+
var normalizedFormatter = (!defaultOnly && formatter) || getDefaultFormatter(type);
|
|
39
|
+
map.set(name, normalizedFormatter);
|
|
40
|
+
return map;
|
|
41
|
+
}, new Map());
|
|
42
|
+
return rows.map(function (_a) {
|
|
43
|
+
var id = _a.id, data = _a.data;
|
|
44
|
+
return ({
|
|
45
|
+
id: id,
|
|
46
|
+
data: Object.keys(data).reduce(function (newData, name) {
|
|
47
|
+
var formatter = colToFormatter.get(name);
|
|
48
|
+
newData[name] = formatter(data[name]);
|
|
49
|
+
return newData;
|
|
50
|
+
}, {}),
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
var flattenExportRows = function (rows) {
|
|
55
|
+
return rows.map(function (_a) {
|
|
56
|
+
var id = _a.id, data = _a.data;
|
|
57
|
+
return (__assign({ id: id }, data));
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
var exportJson = function (rows, cols, useDefaultFormatters) {
|
|
61
|
+
var formattedRows = applyFormatters(rows, cols, useDefaultFormatters);
|
|
62
|
+
var json = JSON.stringify(formattedRows, null, 2);
|
|
63
|
+
downloadFile(json, "export.json", "application/json");
|
|
64
|
+
};
|
|
65
|
+
var exportCsv = function (rows, cols, useDefaultFormatters) {
|
|
66
|
+
var formattedRows = applyFormatters(rows, cols, useDefaultFormatters);
|
|
67
|
+
var flattenedRows = flattenExportRows(formattedRows);
|
|
68
|
+
var csv = Papa.unparse(flattenedRows, { header: true });
|
|
69
|
+
downloadFile(csv, "export.csv", "text/csv");
|
|
70
|
+
};
|
|
71
|
+
var useExportFn = function (_a) {
|
|
72
|
+
var rows = _a.rows, cols = _a.cols, filteredRows = _a.filteredRows, currentPageRows = _a.currentPageRows;
|
|
73
|
+
var formattersExist = useMemo(function () { return cols.reduce(function (prev, _a) {
|
|
74
|
+
var formatter = _a.formatter;
|
|
75
|
+
return prev || !!formatter;
|
|
76
|
+
}, false); }, [cols]);
|
|
77
|
+
var exportFn = useCallback(function (stage, fileType, formatted) {
|
|
78
|
+
if (stage === "filtered" && !filteredRows) {
|
|
79
|
+
throw Error("Cannot export filtered rows because filtering is not enabled for this grid");
|
|
80
|
+
}
|
|
81
|
+
if (stage === "paged" && !currentPageRows) {
|
|
82
|
+
throw Error("Cannot export current page of rows because paging is not enabled for this grid");
|
|
83
|
+
}
|
|
84
|
+
if (formatted && !formattersExist) {
|
|
85
|
+
throw Error("Cannot export formatted rows because formatters are not defined for this grid");
|
|
86
|
+
}
|
|
87
|
+
var exportRows = (function () {
|
|
88
|
+
switch (stage) {
|
|
89
|
+
case "filtered":
|
|
90
|
+
return filteredRows;
|
|
91
|
+
case "paged":
|
|
92
|
+
return currentPageRows;
|
|
93
|
+
default:
|
|
94
|
+
return rows;
|
|
95
|
+
}
|
|
96
|
+
})();
|
|
97
|
+
if (fileType === "csv") {
|
|
98
|
+
exportCsv(exportRows, cols, !formatted);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
exportJson(exportRows, cols, !formatted);
|
|
102
|
+
}, [cols, currentPageRows, filteredRows, formattersExist, rows]);
|
|
103
|
+
return useMemo(function () { return ({
|
|
104
|
+
exportFn: exportFn,
|
|
105
|
+
formattersExist: formattersExist,
|
|
106
|
+
paginationEnabled: !!currentPageRows,
|
|
107
|
+
filteringEnabled: !!filteredRows,
|
|
108
|
+
rowCounts: {
|
|
109
|
+
total: rows.length,
|
|
110
|
+
filtered: filteredRows === null || filteredRows === void 0 ? void 0 : filteredRows.length,
|
|
111
|
+
currentPage: currentPageRows === null || currentPageRows === void 0 ? void 0 : currentPageRows.length,
|
|
112
|
+
}
|
|
113
|
+
}); }, [currentPageRows, exportFn, filteredRows, formattersExist, rows.length]);
|
|
114
|
+
};
|
|
115
|
+
export default useExportFn;
|
|
@@ -10,9 +10,8 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import {
|
|
13
|
+
import { useId } from "react";
|
|
14
14
|
import { dateFilterSchemeNames, } from "./types";
|
|
15
|
-
import { nanoid } from "nanoid/non-secure";
|
|
16
15
|
import FilterRow from "./FilterRow";
|
|
17
16
|
import classNames from "classnames";
|
|
18
17
|
var DateFilterRow = function (_a) {
|
|
@@ -35,7 +34,7 @@ var DateFilterRow = function (_a) {
|
|
|
35
34
|
};
|
|
36
35
|
var enabled = filterState.enabled, scheme = filterState.scheme, startDate = filterState.startDate, endDate = filterState.endDate;
|
|
37
36
|
var inputType = includeTime ? "datetime-local" : "date";
|
|
38
|
-
var inputId =
|
|
37
|
+
var inputId = useId();
|
|
39
38
|
var startDateInputId = "$startDate-".concat(inputId);
|
|
40
39
|
var endDateInputId = "$endDate-".concat(inputId);
|
|
41
40
|
var startDateInputLabel = "".concat(columnLabel, " Column Filter Start Date");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
2
|
import { EditableTableFilterState, TableFilterState } from "./types";
|
|
3
3
|
import { FilterInputTableStyleModel } from "../styling/types";
|
|
4
|
-
interface FilterOptionsTableProps {
|
|
4
|
+
export interface FilterOptionsTableProps {
|
|
5
5
|
filterState: TableFilterState;
|
|
6
6
|
setFilterState: (filterState: EditableTableFilterState) => void;
|
|
7
7
|
caption?: string;
|
|
@@ -112,7 +112,9 @@ var FilterOptionsTable = function (_a) {
|
|
|
112
112
|
var editableTableFilterState = convertFilterFormStateToEditableState(formState);
|
|
113
113
|
setFilterState(editableTableFilterState);
|
|
114
114
|
};
|
|
115
|
-
// TODO: consider using an accordion to show and hide this component
|
|
115
|
+
// TODO: consider using an accordion to show and hide this component.
|
|
116
|
+
// Will eventually be a moot point due to the toolbar being implemented, but
|
|
117
|
+
// still worth considering for backwards compatibility.
|
|
116
118
|
return (_jsxs("form", { onSubmit: onSubmit, children: [_jsxs("table", { className: classNames.apply(void 0, __spreadArray(["table"], unwrappedStyleModel.table, false)), children: [caption && (_jsx("caption", { className: classNames(unwrappedStyleModel.caption), children: caption })), _jsx("thead", { className: classNames.apply(void 0, unwrappedStyleModel.thead), children: _jsx("tr", { className: classNames.apply(void 0, unwrappedStyleModel.theadTr), children: ["Enabled", "Column", "Type", "Operator", "Value"].map(function (colName, index) { return (_jsx("th", { className: classNames.apply(void 0, unwrappedStyleModel.theadTh(index)), children: colName }, index)); }) }) }), _jsx("tbody", { className: classNames.apply(void 0, unwrappedStyleModel.tbody), children: getRows() })] }), _jsx("button", { className: classNames("btn", { "btn-secondary": unwrappedStyleModel.submitButton.length === 0 }, unwrappedStyleModel.submitButton), type: "submit", children: "Submit" })] }));
|
|
117
119
|
};
|
|
118
120
|
export default FilterOptionsTable;
|
package/filtering/types.d.ts
CHANGED
|
@@ -45,16 +45,22 @@ export interface BetweenDatesFilterState extends AbstractDateFilterState {
|
|
|
45
45
|
}
|
|
46
46
|
export type DateFilterState = StartDateFilterState | EndDateFilterState | BetweenDatesFilterState;
|
|
47
47
|
export type FilterState = StringFilterState | NumberFilterState | DateFilterState;
|
|
48
|
-
export interface
|
|
48
|
+
export interface ControlledFilterModel {
|
|
49
|
+
type?: "controlled";
|
|
49
50
|
tableFilterState: EditableTableFilterState;
|
|
50
51
|
setTableFilterState: (state: EditableTableFilterState) => void;
|
|
51
52
|
filterTableCaption?: string;
|
|
52
53
|
}
|
|
54
|
+
export type UncontrolledFilterModel = Partial<Pick<ControlledFilterModel, "tableFilterState" | "filterTableCaption">> & {
|
|
55
|
+
type: "uncontrolled";
|
|
56
|
+
};
|
|
57
|
+
export type NormalizedTableFilterModel = Pick<ControlledFilterModel, "tableFilterState" | "setTableFilterState">;
|
|
53
58
|
export interface NumberFormFilterState extends AbstractFilterState {
|
|
54
59
|
type: "number";
|
|
55
60
|
scheme: NumberFilterScheme;
|
|
56
61
|
inputValue: string;
|
|
57
62
|
}
|
|
63
|
+
export type FilterModel = ControlledFilterModel | UncontrolledFilterModel;
|
|
58
64
|
export interface DateFormFilterState extends AbstractDateFilterState {
|
|
59
65
|
scheme: DateFilterScheme;
|
|
60
66
|
startDate: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@absreim/react-bootstrap-data-grid",
|
|
3
3
|
"description": "Data grid UI component for use with web apps using React and Bootstrap",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Brook Li",
|
|
7
7
|
"homepage": "https://react-bootstrap-data-grid.vercel.app/",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"classnames": "^2.5.1",
|
|
19
|
-
"dayjs": "^1.11.13"
|
|
19
|
+
"dayjs": "^1.11.13",
|
|
20
|
+
"papaparse": "^5.5.3"
|
|
20
21
|
},
|
|
21
22
|
"peerDependencies": {
|
|
22
23
|
"react": "^19",
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { NormalizedPaginationModel } from "./types";
|
|
3
3
|
export interface PaginationProps {
|
|
4
|
-
|
|
5
|
-
pageSizeOptions: number[];
|
|
6
|
-
pageSizeIndex: number;
|
|
7
|
-
handleSetPageSizeIndex: (index: number) => void;
|
|
8
|
-
handleSetPageNum: (index: number) => void;
|
|
4
|
+
normalizedModel: NormalizedPaginationModel;
|
|
9
5
|
prePagingNumRows: number;
|
|
10
|
-
|
|
11
|
-
currentPage: number;
|
|
12
|
-
pageSelectorAriaLabel?: string;
|
|
13
|
-
pageSelectorJustifyContent?: JustifyContentSetting;
|
|
6
|
+
containerDivClasses: string[];
|
|
14
7
|
}
|
|
15
8
|
declare const Pagination: FC<PaginationProps>;
|
|
16
9
|
export default Pagination;
|
package/pagination/Pagination.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import PageSizeSelector from "./PageSizeSelector";
|
|
3
3
|
import PageSelector from "./PageSelector";
|
|
4
|
+
import classNames from "classnames";
|
|
4
5
|
var Pagination = function (_a) {
|
|
5
|
-
var
|
|
6
|
+
var normalizedModel = _a.normalizedModel, prePagingNumRows = _a.prePagingNumRows, containerDivClasses = _a.containerDivClasses;
|
|
7
|
+
var pageSizeOptions = normalizedModel.pageSizeOptions, pageSizeIndex = normalizedModel.pageSizeIndex, currentPage = normalizedModel.currentPage, setCurrentPage = normalizedModel.setCurrentPage, setPageSizeIndex = normalizedModel.setPageSizeIndex, componentSize = normalizedModel.componentSize, maxPageButtons = normalizedModel.maxPageButtons, pageSelectorAriaLabel = normalizedModel.pageSelectorAriaLabel, pageSelectorJustifyContent = normalizedModel.pageSelectorJustifyContent;
|
|
6
8
|
var numPages = Math.ceil(prePagingNumRows / pageSizeOptions[pageSizeIndex]);
|
|
7
9
|
var pageIndexAwarePageSizeSetter = function (newPageSizeIndex) {
|
|
8
10
|
var newPageSize = pageSizeOptions[newPageSizeIndex];
|
|
9
11
|
var maxPages = Math.ceil(prePagingNumRows / newPageSize);
|
|
10
|
-
|
|
12
|
+
setPageSizeIndex(newPageSizeIndex);
|
|
11
13
|
// The new page size can cause the current page number to be out of bounds.
|
|
12
14
|
// In that case, set the page num to the maximum possible with new page
|
|
13
15
|
// size.
|
|
14
16
|
if (currentPage > maxPages) {
|
|
15
|
-
|
|
17
|
+
setCurrentPage(maxPages);
|
|
16
18
|
}
|
|
17
19
|
};
|
|
18
|
-
return (_jsxs("div", {
|
|
20
|
+
return (_jsxs("div", { "data-testid": "pagination ui container div", className: classNames(containerDivClasses.length > 0
|
|
21
|
+
? containerDivClasses
|
|
22
|
+
: ["d-flex", "justify-content-end", "gap-2", "px-2"]), children: [_jsx(PageSizeSelector, { componentSize: componentSize, pageSizeOptions: pageSizeOptions, pageSizeIndex: pageSizeIndex, handleSetPageSize: pageIndexAwarePageSizeSetter }), _jsx(PageSelector, { numPages: numPages, pageNum: currentPage, numButtons: maxPageButtons, setPageNum: setCurrentPage, size: componentSize, ariaLabel: pageSelectorAriaLabel, alignment: pageSelectorJustifyContent })] }));
|
|
19
23
|
};
|
|
20
24
|
export default Pagination;
|
package/pagination/types.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { JustifyContentSetting, Size } from "../types";
|
|
2
|
-
export interface
|
|
3
|
-
pageSizeOptions
|
|
4
|
-
|
|
5
|
-
setPageSizeIndex: (pageSizeIndex: number) => void;
|
|
6
|
-
currentPage: number;
|
|
7
|
-
setCurrentPage: (pageNum: number) => void;
|
|
8
|
-
maxPageButtons: number;
|
|
2
|
+
export interface PaginationOptions {
|
|
3
|
+
pageSizeOptions?: number[];
|
|
4
|
+
maxPageButtons?: number;
|
|
9
5
|
componentSize?: Size;
|
|
10
6
|
pageSelectorAriaLabel?: string;
|
|
11
7
|
pageSelectorJustifyContent?: JustifyContentSetting;
|
|
12
8
|
}
|
|
9
|
+
export type ControlledPaginationModel = PaginationOptions & {
|
|
10
|
+
type?: "controlled";
|
|
11
|
+
pageSizeIndex: number;
|
|
12
|
+
setPageSizeIndex: (pageSizeIndex: number) => void;
|
|
13
|
+
currentPage: number;
|
|
14
|
+
setCurrentPage: (pageNum: number) => void;
|
|
15
|
+
};
|
|
16
|
+
export type UncontrolledPaginationModel = PaginationOptions & {
|
|
17
|
+
type: "uncontrolled";
|
|
18
|
+
startingPageSizeIndex?: number;
|
|
19
|
+
startingCurrentPage?: number;
|
|
20
|
+
};
|
|
21
|
+
export type GridPaginationState = ControlledPaginationModel | UncontrolledPaginationModel;
|
|
22
|
+
export type NormalizedPaginationModel = Required<Omit<ControlledPaginationModel, "type" | "pageSelectorAriaLabel" | "pageSelectorJustifyContent">> & Pick<ControlledPaginationModel, "pageSelectorAriaLabel" | "pageSelectorJustifyContent">;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { RowDef } from "../types";
|
|
2
|
-
import { GridPaginationState } from "../pagination/types";
|
|
3
|
-
declare const useCurrentPageRows: (sortedRows: RowDef[],
|
|
2
|
+
import { NormalizedPaginationModel, GridPaginationState } from "../pagination/types";
|
|
3
|
+
declare const useCurrentPageRows: (sortedRows: RowDef[], paginationModel: GridPaginationState | undefined) => {
|
|
4
|
+
paginatedRows: RowDef[];
|
|
5
|
+
normalizedModel: NormalizedPaginationModel | null;
|
|
6
|
+
};
|
|
4
7
|
export default useCurrentPageRows;
|
|
@@ -1,14 +1,52 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
2
|
-
var useCurrentPageRows = function (sortedRows,
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
var useCurrentPageRows = function (sortedRows, paginationModel) {
|
|
3
|
+
var componentSize = (paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.componentSize) || "medium";
|
|
4
|
+
var isControlled = (paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.type) !== "uncontrolled";
|
|
5
|
+
var _a = useState(isControlled ? 0 : paginationModel.startingPageSizeIndex || 0), internalPageSizeIndex = _a[0], setInternalPageSizeIndex = _a[1];
|
|
6
|
+
var pageSizeIndex = isControlled
|
|
7
|
+
? (paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.pageSizeIndex) || 0
|
|
8
|
+
: internalPageSizeIndex;
|
|
9
|
+
var setPageSizeIndex = isControlled
|
|
10
|
+
? paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.setPageSizeIndex
|
|
11
|
+
: setInternalPageSizeIndex;
|
|
12
|
+
var _b = useState(isControlled ? 1 : paginationModel.startingCurrentPage || 1), internalPageNum = _b[0], setInternalPageNum = _b[1];
|
|
13
|
+
var currentPage = isControlled
|
|
14
|
+
? (paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.currentPage) || 1
|
|
15
|
+
: internalPageNum;
|
|
16
|
+
var setCurrentPage = isControlled
|
|
17
|
+
? paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.setCurrentPage
|
|
18
|
+
: setInternalPageNum;
|
|
19
|
+
var maxPageButtons = (paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.maxPageButtons) || 5;
|
|
3
20
|
return useMemo(function () {
|
|
4
|
-
if (
|
|
5
|
-
return sortedRows;
|
|
21
|
+
if (paginationModel === undefined) {
|
|
22
|
+
return { paginatedRows: sortedRows, normalizedModel: null };
|
|
6
23
|
}
|
|
7
|
-
var pageSizeOptions =
|
|
24
|
+
var pageSizeOptions = (paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.pageSizeOptions) || [10, 25, 100];
|
|
25
|
+
var normalizedModel = {
|
|
26
|
+
pageSizeIndex: pageSizeIndex,
|
|
27
|
+
setPageSizeIndex: setPageSizeIndex,
|
|
28
|
+
currentPage: currentPage,
|
|
29
|
+
setCurrentPage: setCurrentPage,
|
|
30
|
+
pageSizeOptions: pageSizeOptions,
|
|
31
|
+
maxPageButtons: maxPageButtons,
|
|
32
|
+
componentSize: componentSize,
|
|
33
|
+
pageSelectorAriaLabel: paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.pageSelectorAriaLabel,
|
|
34
|
+
pageSelectorJustifyContent: paginationModel === null || paginationModel === void 0 ? void 0 : paginationModel.pageSelectorJustifyContent,
|
|
35
|
+
};
|
|
8
36
|
var pageSize = pageSizeOptions[pageSizeIndex];
|
|
9
37
|
var lowerIndex = pageSize * (currentPage - 1);
|
|
10
38
|
var upperIndex = lowerIndex + pageSize;
|
|
11
|
-
|
|
12
|
-
|
|
39
|
+
var paginatedRows = sortedRows.slice(lowerIndex, upperIndex);
|
|
40
|
+
return { paginatedRows: paginatedRows, normalizedModel: normalizedModel };
|
|
41
|
+
}, [
|
|
42
|
+
paginationModel,
|
|
43
|
+
pageSizeIndex,
|
|
44
|
+
setPageSizeIndex,
|
|
45
|
+
currentPage,
|
|
46
|
+
setCurrentPage,
|
|
47
|
+
maxPageButtons,
|
|
48
|
+
componentSize,
|
|
49
|
+
sortedRows,
|
|
50
|
+
]);
|
|
13
51
|
};
|
|
14
52
|
export default useCurrentPageRows;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { FilterModel, NormalizedTableFilterModel } from "../filtering/types";
|
|
2
|
+
import { ColDef } from "../types";
|
|
3
|
+
declare const useFilterStateStore: (filterModel: FilterModel | undefined, cols: ColDef[]) => NormalizedTableFilterModel | null;
|
|
4
|
+
export default useFilterStateStore;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
var generateEmptyFilterState = function (cols) {
|
|
3
|
+
var filterState = {};
|
|
4
|
+
cols.forEach(function (_a) {
|
|
5
|
+
var type = _a.type, name = _a.name;
|
|
6
|
+
switch (type) {
|
|
7
|
+
case "string": {
|
|
8
|
+
filterState[name] = {
|
|
9
|
+
type: "string",
|
|
10
|
+
enabled: false,
|
|
11
|
+
scheme: "contains",
|
|
12
|
+
searchString: "",
|
|
13
|
+
};
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
case "number": {
|
|
17
|
+
filterState[name] = {
|
|
18
|
+
type: "number",
|
|
19
|
+
enabled: false,
|
|
20
|
+
scheme: "greaterOrEqual",
|
|
21
|
+
numValue: null,
|
|
22
|
+
};
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
default: {
|
|
26
|
+
filterState[name] = {
|
|
27
|
+
type: type,
|
|
28
|
+
enabled: false,
|
|
29
|
+
scheme: "startFrom",
|
|
30
|
+
startDate: null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return filterState;
|
|
36
|
+
};
|
|
37
|
+
var useFilterStateStore = function (filterModel, cols) {
|
|
38
|
+
// Initial states being from prop values means that should uncontrolled
|
|
39
|
+
// FilterModel starting values change, the changes will not take effect
|
|
40
|
+
// unless the Grid is remounted. The documentation for this and other
|
|
41
|
+
// uncontrolled features should indicate this fact and recommend using
|
|
42
|
+
// controlled modes if this behavior is unacceptable.
|
|
43
|
+
var _a = useState((filterModel === null || filterModel === void 0 ? void 0 : filterModel.tableFilterState) || generateEmptyFilterState(cols)), internalFilterState = _a[0], setInternalFilterState = _a[1];
|
|
44
|
+
if (!filterModel) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return filterModel.type === "uncontrolled"
|
|
48
|
+
? {
|
|
49
|
+
tableFilterState: internalFilterState,
|
|
50
|
+
setTableFilterState: setInternalFilterState,
|
|
51
|
+
}
|
|
52
|
+
: {
|
|
53
|
+
tableFilterState: filterModel.tableFilterState,
|
|
54
|
+
setTableFilterState: filterModel.setTableFilterState,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
export default useFilterStateStore;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { ColDef, RowDef } from "../types";
|
|
2
|
-
import { TableSortModel } from "../sorting/types";
|
|
3
|
-
declare const useSortedRows: (rows: RowDef[], cols: ColDef[], sortModel: TableSortModel | undefined) =>
|
|
2
|
+
import { SortColDef, TableSortModel } from "../sorting/types";
|
|
3
|
+
declare const useSortedRows: (rows: RowDef[], cols: ColDef[], sortModel: TableSortModel | undefined) => {
|
|
4
|
+
sortedRows: RowDef[];
|
|
5
|
+
sortingEnabled: boolean;
|
|
6
|
+
sortColDef: SortColDef | null | undefined;
|
|
7
|
+
setSortColDef: ((sortColDef: SortColDef | null) => void) | undefined;
|
|
8
|
+
};
|
|
4
9
|
export default useSortedRows;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
2
|
var getTypeComparator = function (typeStr) {
|
|
3
3
|
if (typeStr === "date" || typeStr === "datetime") {
|
|
4
4
|
return function (a, b) { return a.valueOf() - b.valueOf(); };
|
|
@@ -20,12 +20,21 @@ var getRowComparator = function (comparator, fieldName) {
|
|
|
20
20
|
return function (rowA, rowB) { return comparator(rowA.data[fieldName], rowB.data[fieldName]); };
|
|
21
21
|
};
|
|
22
22
|
var useSortedRows = function (rows, cols, sortModel) {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
var _a = useState(((sortModel === null || sortModel === void 0 ? void 0 : sortModel.type) === "uncontrolled" && sortModel.initialSortColDef) ||
|
|
24
|
+
null), internalSortColDef = _a[0], setInternalSortColDef = _a[1];
|
|
25
|
+
var sortColDef = (sortModel === null || sortModel === void 0 ? void 0 : sortModel.type) === "uncontrolled"
|
|
26
|
+
? internalSortColDef
|
|
27
|
+
: (sortModel === null || sortModel === void 0 ? void 0 : sortModel.sortColDef) || undefined;
|
|
28
|
+
var setSortColDef = (sortModel === null || sortModel === void 0 ? void 0 : sortModel.type) === "uncontrolled"
|
|
29
|
+
? setInternalSortColDef
|
|
30
|
+
: (sortModel === null || sortModel === void 0 ? void 0 : sortModel.setSortColDef) || undefined;
|
|
31
|
+
var sortingEnabled = !!sortModel;
|
|
32
|
+
var sortedRows = useMemo(function () {
|
|
33
|
+
if (!sortColDef) {
|
|
25
34
|
return rows;
|
|
26
35
|
}
|
|
27
|
-
var sortFieldName =
|
|
28
|
-
var sortOrder =
|
|
36
|
+
var sortFieldName = sortColDef.name;
|
|
37
|
+
var sortOrder = sortColDef.order;
|
|
29
38
|
var sortColIndex = cols.findIndex(function (_a) {
|
|
30
39
|
var name = _a.name;
|
|
31
40
|
return name === sortFieldName;
|
|
@@ -43,6 +52,7 @@ var useSortedRows = function (rows, cols, sortModel) {
|
|
|
43
52
|
rowComparator = getRowComparator(descComparator, sortFieldName);
|
|
44
53
|
}
|
|
45
54
|
return rows.slice().sort(rowComparator);
|
|
46
|
-
}, [
|
|
55
|
+
}, [sortColDef, cols, rows]);
|
|
56
|
+
return { sortedRows: sortedRows, sortingEnabled: sortingEnabled, sortColDef: sortColDef, setSortColDef: setSortColDef };
|
|
47
57
|
};
|
|
48
58
|
export default useSortedRows;
|
package/selection/types.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export interface SingleSelectModel {
|
|
|
12
12
|
type: "single";
|
|
13
13
|
selected: RowId | null;
|
|
14
14
|
setSelected: (selected: RowId | null) => void;
|
|
15
|
-
groupName
|
|
15
|
+
groupName?: string;
|
|
16
16
|
}
|
|
17
17
|
export type SelectModel = SingleSelectModel | MultiSelectModel;
|
|
18
18
|
export type MultiExistingSelection = "full" | "partial" | "none";
|
package/sorting/types.d.ts
CHANGED
|
@@ -7,7 +7,13 @@ export interface ColSortModel {
|
|
|
7
7
|
sortOrder: SortOrder | null;
|
|
8
8
|
setSortOrder: (order: SortOrder | null) => void;
|
|
9
9
|
}
|
|
10
|
-
export interface
|
|
10
|
+
export interface ControlledTableSortModel {
|
|
11
|
+
type?: "controlled";
|
|
11
12
|
sortColDef: SortColDef | null;
|
|
12
13
|
setSortColDef: (sortColDef: SortColDef | null) => void;
|
|
13
14
|
}
|
|
15
|
+
export interface UncontrolledTableSortModel {
|
|
16
|
+
type: "uncontrolled";
|
|
17
|
+
initialSortColDef: SortColDef | null;
|
|
18
|
+
}
|
|
19
|
+
export type TableSortModel = ControlledTableSortModel | UncontrolledTableSortModel;
|
|
@@ -54,4 +54,5 @@ export var unwrapAdditionalComponentsStyleModel = function (styleModel) { return
|
|
|
54
54
|
filterInputsDiv: (styleModel === null || styleModel === void 0 ? void 0 : styleModel.filterInputsDiv) || [],
|
|
55
55
|
tableAndPaginationDiv: (styleModel === null || styleModel === void 0 ? void 0 : styleModel.tableAndPaginationDiv) || [],
|
|
56
56
|
filterUiToggleButton: (styleModel === null || styleModel === void 0 ? void 0 : styleModel.filterUiToggleButton) || [],
|
|
57
|
+
paginationUiDiv: (styleModel === null || styleModel === void 0 ? void 0 : styleModel.paginationUiDiv) || [],
|
|
57
58
|
}); };
|
package/styling/types.d.ts
CHANGED
|
@@ -37,9 +37,25 @@ export interface AdditionalComponentsStyleModel {
|
|
|
37
37
|
filterInputsDiv?: string[];
|
|
38
38
|
tableAndPaginationDiv?: string[];
|
|
39
39
|
filterUiToggleButton?: string[];
|
|
40
|
+
paginationUiDiv?: string[];
|
|
41
|
+
}
|
|
42
|
+
export interface ToolbarStyleModel {
|
|
43
|
+
activeButton?: string[];
|
|
44
|
+
inactiveButton?: string[];
|
|
45
|
+
toolbar?: string[];
|
|
46
|
+
interfaceContainer?: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface ExportFormStyleModel {
|
|
49
|
+
legend?: string[];
|
|
50
|
+
radioContainer?: string[];
|
|
51
|
+
radioInput?: string[];
|
|
52
|
+
radioLabel?: string[];
|
|
53
|
+
submitButton?: string[];
|
|
40
54
|
}
|
|
41
55
|
export interface StyleModel {
|
|
42
56
|
mainTableStyleModel?: TableStyleModel;
|
|
43
57
|
filterInputTableStyleModel?: FilterInputTableStyleModel;
|
|
44
58
|
additionalComponentsStyleModel?: AdditionalComponentsStyleModel;
|
|
59
|
+
toolbarStyleModel?: ToolbarStyleModel;
|
|
60
|
+
exportFormStyleModel?: ExportFormStyleModel;
|
|
45
61
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ToolbarOption } from "./types";
|
|
2
|
+
import { FC } from "react";
|
|
3
|
+
export interface ToolbarProps {
|
|
4
|
+
enabledFeatures: Partial<Record<ToolbarOption, boolean>>;
|
|
5
|
+
option: ToolbarOption | null;
|
|
6
|
+
setOption: (option: ToolbarOption | null) => void;
|
|
7
|
+
toolbarClasses?: string[];
|
|
8
|
+
activeClasses?: string[];
|
|
9
|
+
inactiveClasses?: string[];
|
|
10
|
+
}
|
|
11
|
+
declare const Toolbar: FC<ToolbarProps>;
|
|
12
|
+
export default Toolbar;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import classNames from "classnames";
|
|
3
|
+
var buttonSpecs = {
|
|
4
|
+
filtering: {
|
|
5
|
+
label: "Filtering",
|
|
6
|
+
icon: (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16", children: _jsx("path", { d: "M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5m-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5m-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5" }) })),
|
|
7
|
+
},
|
|
8
|
+
exporting: {
|
|
9
|
+
label: "Export",
|
|
10
|
+
icon: (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16", children: [_jsx("path", { d: "M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5" }), _jsx("path", { d: "M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z" })] })),
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
// TODO: figure out tabindex and accessibility
|
|
14
|
+
var Toolbar = function (_a) {
|
|
15
|
+
var enabledFeatures = _a.enabledFeatures, option = _a.option, setOption = _a.setOption, toolbarClasses = _a.toolbarClasses, activeClasses = _a.activeClasses, inactiveClasses = _a.inactiveClasses;
|
|
16
|
+
return (_jsx("div", { className: classNames(toolbarClasses || ["hstack", "gap-2", "justify-content-start", "px-2"]), role: "toolbar", children: Object.keys(buttonSpecs)
|
|
17
|
+
.filter(function (toolbarOption) { return !!enabledFeatures[toolbarOption]; })
|
|
18
|
+
.map(function (toolbarOption) { return (_jsx("button", { "aria-label": buttonSpecs[toolbarOption].label, "aria-roledescription": "Grouped toggle button to show/hide ".concat(toolbarOption, " UI"), "aria-pressed": option === toolbarOption, className: classNames.apply(void 0, (option === toolbarOption
|
|
19
|
+
? activeClasses || ["btn", "btn-outline-secondary", "active"]
|
|
20
|
+
: inactiveClasses || ["btn", "btn-outline-secondary"])), title: buttonSpecs[toolbarOption].label, onClick: function () {
|
|
21
|
+
setOption(option === toolbarOption
|
|
22
|
+
? null
|
|
23
|
+
: toolbarOption);
|
|
24
|
+
}, children: buttonSpecs[toolbarOption].icon }, toolbarOption)); }) }));
|
|
25
|
+
};
|
|
26
|
+
export default Toolbar;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ToolbarInterfaces } from "./types";
|
|
2
|
+
import { FC } from "react";
|
|
3
|
+
import { ToolbarStyleModel } from "../styling/types";
|
|
4
|
+
interface ToolbarContainerProps {
|
|
5
|
+
interfaces: ToolbarInterfaces;
|
|
6
|
+
styleModel?: ToolbarStyleModel;
|
|
7
|
+
}
|
|
8
|
+
declare const ToolbarContainer: FC<ToolbarContainerProps>;
|
|
9
|
+
export default ToolbarContainer;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import Toolbar from "./Toolbar";
|
|
4
|
+
import classNames from "classnames";
|
|
5
|
+
var ToolbarContainer = function (_a) {
|
|
6
|
+
var interfaces = _a.interfaces, styleModel = _a.styleModel;
|
|
7
|
+
var _b = useState(null), option = _b[0], setOption = _b[1];
|
|
8
|
+
var enabledFeatures = Object.keys(interfaces).reduce(function (prev, toolbarOption) {
|
|
9
|
+
prev[toolbarOption] =
|
|
10
|
+
!!interfaces[toolbarOption];
|
|
11
|
+
return prev;
|
|
12
|
+
}, {});
|
|
13
|
+
// TODO: mention in documentation that Bootstrap 5.3 is required due to the
|
|
14
|
+
// use of the z-index utility
|
|
15
|
+
return (_jsxs("div", { className: "vstack", "data-testid": "toolbar container", children: [_jsx(Toolbar, { enabledFeatures: enabledFeatures, option: option, setOption: setOption, toolbarClasses: styleModel === null || styleModel === void 0 ? void 0 : styleModel.toolbar, activeClasses: styleModel === null || styleModel === void 0 ? void 0 : styleModel.activeButton, inactiveClasses: styleModel === null || styleModel === void 0 ? void 0 : styleModel.inactiveButton }), _jsx("div", { className: "position-relative", children: option !== null && (_jsx("div", { "data-testid": "toolbar feature interface content container", className: classNames((styleModel === null || styleModel === void 0 ? void 0 : styleModel.interfaceContainer) || [
|
|
16
|
+
"position-absolute",
|
|
17
|
+
"z-1",
|
|
18
|
+
"bg-body",
|
|
19
|
+
"border",
|
|
20
|
+
"shadow",
|
|
21
|
+
"p-2",
|
|
22
|
+
]), children: interfaces[option] })) })] }));
|
|
23
|
+
};
|
|
24
|
+
export default ToolbarContainer;
|
package/toolbar/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FilterOptionsTableProps } from "../filtering/FilterOptionsTable";
|
|
2
|
+
import { ToolbarInterfaces } from "./types";
|
|
3
|
+
import { ExportFormProps } from "../export/ExportForm";
|
|
4
|
+
export interface InterfaceParams {
|
|
5
|
+
filtering?: FilterOptionsTableProps;
|
|
6
|
+
exporting?: ExportFormProps;
|
|
7
|
+
}
|
|
8
|
+
declare const useInterfaces: (params: InterfaceParams) => ToolbarInterfaces;
|
|
9
|
+
export default useInterfaces;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import FilterOptionsTable from "../filtering/FilterOptionsTable";
|
|
14
|
+
import { useMemo } from "react";
|
|
15
|
+
import ExportForm from "../export/ExportForm";
|
|
16
|
+
var useInterfaces = function (_a) {
|
|
17
|
+
var filtering = _a.filtering, exporting = _a.exporting;
|
|
18
|
+
return useMemo(function () { return ({
|
|
19
|
+
filtering: filtering ? _jsx(FilterOptionsTable, __assign({}, filtering)) : undefined,
|
|
20
|
+
exporting: exporting ? _jsx(ExportForm, __assign({}, exporting)) : undefined,
|
|
21
|
+
}); }, [exporting, filtering]);
|
|
22
|
+
};
|
|
23
|
+
export default useInterfaces;
|