@absreim/react-bootstrap-data-grid 1.0.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FilterOptionsTable/DateFilterRow.d.ts +10 -0
- package/FilterOptionsTable/DateFilterRow.jsx +67 -0
- package/FilterOptionsTable/FilterOptionsTable.d.ts +8 -0
- package/FilterOptionsTable/FilterOptionsTable.jsx +118 -0
- package/FilterOptionsTable/NumberFilterRow.d.ts +9 -0
- package/FilterOptionsTable/NumberFilterRow.jsx +49 -0
- package/FilterOptionsTable/StringFilterRow.d.ts +9 -0
- package/FilterOptionsTable/StringFilterRow.jsx +49 -0
- package/FilterOptionsTable/types.d.ts +13 -0
- package/FilterOptionsTable/types.js +1 -0
- package/FilterOptionsTable/useFormStateFromTableFilterState.d.ts +4 -0
- package/FilterOptionsTable/useFormStateFromTableFilterState.js +72 -0
- package/Grid.d.ts +2 -1
- package/Grid.jsx +27 -99
- package/ToggleButton.d.ts +8 -0
- package/ToggleButton.jsx +13 -0
- package/hooks/useAugmentedRows.d.ts +3 -0
- package/hooks/useAugmentedRows.js +12 -0
- package/hooks/useDisplayRows.d.ts +3 -0
- package/hooks/useDisplayRows.js +52 -0
- package/hooks/useEditableFromFilterState.d.ts +3 -0
- package/hooks/useEditableFromFilterState.js +14 -0
- package/hooks/useFilter.d.ts +3 -0
- package/hooks/useFilter.js +84 -0
- package/hooks/useFilterStateFromEditable.d.ts +3 -0
- package/hooks/useFilterStateFromEditable.js +18 -0
- package/hooks/useSortedRows.d.ts +3 -0
- package/hooks/useSortedRows.js +48 -0
- package/models/descriptions.d.ts +2 -0
- package/models/descriptions.js +6 -0
- package/package.json +3 -2
- package/types.d.ts +62 -0
- package/types.js +30 -1
- package/util/datetime.d.ts +3 -0
- package/util/datetime.js +9 -0
- package/component.d.ts +0 -8
- package/component.jsx +0 -72
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { DateFormFilterState } from "./types";
|
|
3
|
+
interface DateFilterRowProps {
|
|
4
|
+
includeTime: boolean;
|
|
5
|
+
columnLabel: string;
|
|
6
|
+
filterState: DateFormFilterState;
|
|
7
|
+
setFilterState: (filterState: DateFormFilterState) => void;
|
|
8
|
+
}
|
|
9
|
+
declare const DateFilterRow: FC<DateFilterRowProps>;
|
|
10
|
+
export default DateFilterRow;
|
|
@@ -0,0 +1,67 @@
|
|
|
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 { useMemo } from "react";
|
|
13
|
+
import { dateFilterSchemeNames, dateFilterSchemes, } from "../types";
|
|
14
|
+
import { nanoid } from "nanoid/non-secure";
|
|
15
|
+
var DateFilterRow = function (_a) {
|
|
16
|
+
var includeTime = _a.includeTime, columnLabel = _a.columnLabel, filterState = _a.filterState, setFilterState = _a.setFilterState;
|
|
17
|
+
var handleOpChange = function (_a) {
|
|
18
|
+
var target = _a.target;
|
|
19
|
+
setFilterState(__assign(__assign({}, filterState), { scheme: target.value }));
|
|
20
|
+
};
|
|
21
|
+
var handleEnabledChange = function (_a) {
|
|
22
|
+
var target = _a.target;
|
|
23
|
+
setFilterState(__assign(__assign({}, filterState), { enabled: target.checked }));
|
|
24
|
+
};
|
|
25
|
+
var handleStartValueChange = function (_a) {
|
|
26
|
+
var target = _a.target;
|
|
27
|
+
setFilterState(__assign(__assign({}, filterState), { startDate: target.value }));
|
|
28
|
+
};
|
|
29
|
+
var handleEndValueChange = function (_a) {
|
|
30
|
+
var target = _a.target;
|
|
31
|
+
setFilterState(__assign(__assign({}, filterState), { endDate: target.value }));
|
|
32
|
+
};
|
|
33
|
+
var enabled = filterState.enabled, scheme = filterState.scheme, startDate = filterState.startDate, endDate = filterState.endDate;
|
|
34
|
+
var inputType = includeTime ? "datetime-local" : "date";
|
|
35
|
+
var inputId = useMemo(function () { return nanoid(); }, []);
|
|
36
|
+
var startDateInputId = "$startDate-".concat(inputId);
|
|
37
|
+
var endDateInputId = "$endDate-".concat(inputId);
|
|
38
|
+
var checkboxLabel = "".concat(columnLabel, " Column Filter Toggle");
|
|
39
|
+
var opSelectLabel = "".concat(columnLabel, " Column Filter Operator Selection");
|
|
40
|
+
var startDateInputLabel = "".concat(columnLabel, " Column Filter Start Date");
|
|
41
|
+
var endDateInputLabel = "".concat(columnLabel, " Column Filter End Date");
|
|
42
|
+
return (<tr>
|
|
43
|
+
<td>
|
|
44
|
+
<input name={checkboxLabel} aria-label={checkboxLabel} type="checkbox" checked={enabled} onChange={handleEnabledChange}/>
|
|
45
|
+
</td>
|
|
46
|
+
<td>{columnLabel}</td>
|
|
47
|
+
<td>{filterState.type === "date" ? "Date" : "Datetime"}</td>
|
|
48
|
+
<td>
|
|
49
|
+
<select name={opSelectLabel} aria-label={opSelectLabel} disabled={!enabled} className="form-select" value={scheme} onChange={handleOpChange}>
|
|
50
|
+
{dateFilterSchemes.map(function (scheme) { return (<option key={scheme} value={scheme}>
|
|
51
|
+
{dateFilterSchemeNames[scheme]}
|
|
52
|
+
</option>); })}
|
|
53
|
+
</select>
|
|
54
|
+
</td>
|
|
55
|
+
<td>
|
|
56
|
+
{scheme !== "endAt" && (<>
|
|
57
|
+
{scheme === "between" && (<label htmlFor={startDateInputId}>Start Date</label>)}
|
|
58
|
+
<input id={startDateInputId} className="form-control" type={inputType} required={enabled} disabled={!enabled} value={startDate} onChange={handleStartValueChange} aria-label={startDateInputLabel}/>
|
|
59
|
+
</>)}
|
|
60
|
+
{scheme !== "startFrom" && (<>
|
|
61
|
+
{scheme === "between" && (<label htmlFor={endDateInputId}>End Date</label>)}
|
|
62
|
+
<input id={endDateInputId} className="form-control" type={inputType} required={enabled} disabled={!enabled} value={endDate} onChange={handleEndValueChange} aria-label={endDateInputLabel}/>
|
|
63
|
+
</>)}
|
|
64
|
+
</td>
|
|
65
|
+
</tr>);
|
|
66
|
+
};
|
|
67
|
+
export default DateFilterRow;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { EditableTableFilterState, TableFilterState } from "../types";
|
|
3
|
+
interface FilterOptionsTableProps {
|
|
4
|
+
filterState: TableFilterState;
|
|
5
|
+
setFilterState: (filterState: EditableTableFilterState) => void;
|
|
6
|
+
}
|
|
7
|
+
declare const FilterOptionsTable: FC<FilterOptionsTableProps>;
|
|
8
|
+
export default FilterOptionsTable;
|
|
@@ -0,0 +1,118 @@
|
|
|
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 { useState } from "react";
|
|
13
|
+
import StringFilterRow from "./StringFilterRow";
|
|
14
|
+
import { datetimeInputStrToUtc } from "../util/datetime";
|
|
15
|
+
import NumberFilterRow from "./NumberFilterRow";
|
|
16
|
+
import useFormStateFromTableFilterState from "./useFormStateFromTableFilterState";
|
|
17
|
+
import DateFilterRow from "./DateFilterRow";
|
|
18
|
+
var convertFilterFormStateToEditableState = function (filterFormState) {
|
|
19
|
+
return Object.keys(filterFormState).reduce(function (editableState, colName) {
|
|
20
|
+
var rowFilterFormState = filterFormState[colName];
|
|
21
|
+
switch (rowFilterFormState.type) {
|
|
22
|
+
case "string": {
|
|
23
|
+
editableState[colName] = __assign({}, rowFilterFormState);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case "number": {
|
|
27
|
+
editableState[colName] = {
|
|
28
|
+
type: rowFilterFormState.type,
|
|
29
|
+
enabled: rowFilterFormState.enabled,
|
|
30
|
+
scheme: rowFilterFormState.scheme,
|
|
31
|
+
numValue: rowFilterFormState.inputValue === ""
|
|
32
|
+
? null
|
|
33
|
+
: Number(rowFilterFormState.inputValue),
|
|
34
|
+
};
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
default: {
|
|
38
|
+
// date or datetime
|
|
39
|
+
var partialFilterState = {
|
|
40
|
+
type: rowFilterFormState.type,
|
|
41
|
+
enabled: rowFilterFormState.enabled,
|
|
42
|
+
};
|
|
43
|
+
var strModifierFn_1 = rowFilterFormState.type === "date"
|
|
44
|
+
? function (str) { return str; }
|
|
45
|
+
: datetimeInputStrToUtc;
|
|
46
|
+
var inputStrToDate = function (str) {
|
|
47
|
+
return str === "" ? null : new Date(strModifierFn_1(str));
|
|
48
|
+
};
|
|
49
|
+
switch (rowFilterFormState.scheme) {
|
|
50
|
+
case "startFrom": {
|
|
51
|
+
editableState[colName] = __assign(__assign({}, partialFilterState), { scheme: rowFilterFormState.scheme, startDate: inputStrToDate(rowFilterFormState.startDate) });
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case "endAt": {
|
|
55
|
+
editableState[colName] = __assign(__assign({}, partialFilterState), { scheme: rowFilterFormState.scheme, endDate: inputStrToDate(rowFilterFormState.endDate) });
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
default: {
|
|
59
|
+
editableState[colName] = __assign(__assign({}, partialFilterState), { scheme: rowFilterFormState.scheme, startDate: inputStrToDate(rowFilterFormState.startDate), endDate: inputStrToDate(rowFilterFormState.endDate) });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return editableState;
|
|
65
|
+
}, {});
|
|
66
|
+
};
|
|
67
|
+
var FilterOptionsTable = function (_a) {
|
|
68
|
+
var filterState = _a.filterState, setFilterState = _a.setFilterState;
|
|
69
|
+
var formFilterState = useFormStateFromTableFilterState(filterState);
|
|
70
|
+
var _b = useState(formFilterState), formState = _b[0], setFormState = _b[1];
|
|
71
|
+
var getRows = function () {
|
|
72
|
+
return Object.keys(formState).map(function (colName) {
|
|
73
|
+
function getColStateSetter(colName) {
|
|
74
|
+
return function (rowState) {
|
|
75
|
+
var _a;
|
|
76
|
+
return setFormState(__assign(__assign({}, formState), (_a = {}, _a[colName] = rowState, _a)));
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
var colLabel = filterState[colName].label;
|
|
80
|
+
var colFilterState = formState[colName];
|
|
81
|
+
switch (colFilterState.type) {
|
|
82
|
+
case "string": {
|
|
83
|
+
return (<StringFilterRow key={colName} columnLabel={colLabel} filterState={colFilterState} setFilterState={getColStateSetter(colName)}/>);
|
|
84
|
+
}
|
|
85
|
+
case "number": {
|
|
86
|
+
return (<NumberFilterRow key={colName} columnLabel={colLabel} filterState={colFilterState} setFilterState={getColStateSetter(colName)}/>);
|
|
87
|
+
}
|
|
88
|
+
default: {
|
|
89
|
+
// date or datetime
|
|
90
|
+
return (<DateFilterRow key={colName} includeTime={colFilterState.type === "datetime"} columnLabel={colLabel} filterState={colFilterState} setFilterState={getColStateSetter(colName)}/>);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
var onSubmit = function (event) {
|
|
96
|
+
event.preventDefault();
|
|
97
|
+
var editableTableFilterState = convertFilterFormStateToEditableState(formState);
|
|
98
|
+
setFilterState(editableTableFilterState);
|
|
99
|
+
};
|
|
100
|
+
return (<form onSubmit={onSubmit}>
|
|
101
|
+
<table className="table">
|
|
102
|
+
<thead>
|
|
103
|
+
<tr>
|
|
104
|
+
<th>Enabled</th>
|
|
105
|
+
<th>Column</th>
|
|
106
|
+
<th>Type</th>
|
|
107
|
+
<th>Operator</th>
|
|
108
|
+
<th>Value</th>
|
|
109
|
+
</tr>
|
|
110
|
+
</thead>
|
|
111
|
+
<tbody>{getRows()}</tbody>
|
|
112
|
+
</table>
|
|
113
|
+
<button className="btn btn-secondary" type="submit">
|
|
114
|
+
Submit
|
|
115
|
+
</button>
|
|
116
|
+
</form>);
|
|
117
|
+
};
|
|
118
|
+
export default FilterOptionsTable;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { NumberFormFilterState } from "./types";
|
|
3
|
+
interface NumberFilterRowProps {
|
|
4
|
+
columnLabel: string;
|
|
5
|
+
filterState: NumberFormFilterState;
|
|
6
|
+
setFilterState: (filterState: NumberFormFilterState) => void;
|
|
7
|
+
}
|
|
8
|
+
declare const NumberFilterRow: FC<NumberFilterRowProps>;
|
|
9
|
+
export default NumberFilterRow;
|
|
@@ -0,0 +1,49 @@
|
|
|
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 { numberFilterSchemeNames, numberFilterSchemes, } from "../types";
|
|
13
|
+
var NumberFilterRow = function (_a) {
|
|
14
|
+
var columnLabel = _a.columnLabel, filterState = _a.filterState, setFilterState = _a.setFilterState;
|
|
15
|
+
var handleOpChange = function (_a) {
|
|
16
|
+
var target = _a.target;
|
|
17
|
+
setFilterState(__assign(__assign({}, filterState), { scheme: target.value }));
|
|
18
|
+
};
|
|
19
|
+
var handleEnabledChange = function (_a) {
|
|
20
|
+
var target = _a.target;
|
|
21
|
+
setFilterState(__assign(__assign({}, filterState), { enabled: target.checked }));
|
|
22
|
+
};
|
|
23
|
+
var handleNumInputValueChange = function (_a) {
|
|
24
|
+
var target = _a.target;
|
|
25
|
+
setFilterState(__assign(__assign({}, filterState), { inputValue: target.value }));
|
|
26
|
+
};
|
|
27
|
+
var enabled = filterState.enabled, scheme = filterState.scheme, inputValue = filterState.inputValue;
|
|
28
|
+
var checkboxLabel = "".concat(columnLabel, " Column Filter Toggle");
|
|
29
|
+
var opSelectLabel = "".concat(columnLabel, " Column Filter Operator Selection");
|
|
30
|
+
var valueInputLabel = "".concat(columnLabel, " Column Filter Value");
|
|
31
|
+
return (<tr>
|
|
32
|
+
<td>
|
|
33
|
+
<input name={checkboxLabel} aria-label={checkboxLabel} type="checkbox" checked={enabled} onChange={handleEnabledChange}/>
|
|
34
|
+
</td>
|
|
35
|
+
<td>{columnLabel}</td>
|
|
36
|
+
<td>Number</td>
|
|
37
|
+
<td>
|
|
38
|
+
<select name={opSelectLabel} aria-label={opSelectLabel} disabled={!enabled} className="form-select" value={scheme} onChange={handleOpChange}>
|
|
39
|
+
{numberFilterSchemes.map(function (scheme) { return (<option key={scheme} value={scheme}>
|
|
40
|
+
{numberFilterSchemeNames[scheme]}
|
|
41
|
+
</option>); })}
|
|
42
|
+
</select>
|
|
43
|
+
</td>
|
|
44
|
+
<td>
|
|
45
|
+
<input name={valueInputLabel} aria-label={valueInputLabel} className="form-control" type="number" required={enabled} disabled={!enabled} value={inputValue} onChange={handleNumInputValueChange}/>
|
|
46
|
+
</td>
|
|
47
|
+
</tr>);
|
|
48
|
+
};
|
|
49
|
+
export default NumberFilterRow;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { StringFilterState } from "../types";
|
|
3
|
+
interface StringFilterRowProps {
|
|
4
|
+
columnLabel: string;
|
|
5
|
+
filterState: StringFilterState;
|
|
6
|
+
setFilterState: (filterState: StringFilterState) => void;
|
|
7
|
+
}
|
|
8
|
+
declare const StringFilterRow: FC<StringFilterRowProps>;
|
|
9
|
+
export default StringFilterRow;
|
|
@@ -0,0 +1,49 @@
|
|
|
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 { stringFilterSchemeNames, stringFilterSchemes, } from "../types";
|
|
13
|
+
var StringFilterRow = function (_a) {
|
|
14
|
+
var columnLabel = _a.columnLabel, filterState = _a.filterState, setFilterState = _a.setFilterState;
|
|
15
|
+
var handleOpChange = function (_a) {
|
|
16
|
+
var target = _a.target;
|
|
17
|
+
setFilterState(__assign(__assign({}, filterState), { scheme: target.value }));
|
|
18
|
+
};
|
|
19
|
+
var handleEnabledChange = function (_a) {
|
|
20
|
+
var target = _a.target;
|
|
21
|
+
setFilterState(__assign(__assign({}, filterState), { enabled: target.checked }));
|
|
22
|
+
};
|
|
23
|
+
var handleSearchStringChange = function (_a) {
|
|
24
|
+
var target = _a.target;
|
|
25
|
+
setFilterState(__assign(__assign({}, filterState), { searchString: target.value }));
|
|
26
|
+
};
|
|
27
|
+
var enabled = filterState.enabled, scheme = filterState.scheme, searchString = filterState.searchString;
|
|
28
|
+
var checkboxLabel = "".concat(columnLabel, " Column Filter Toggle");
|
|
29
|
+
var opSelectLabel = "".concat(columnLabel, " Column Filter Operator Selection");
|
|
30
|
+
var valueInputLabel = "".concat(columnLabel, " Column Filter Value");
|
|
31
|
+
return (<tr>
|
|
32
|
+
<td>
|
|
33
|
+
<input name={checkboxLabel} aria-label={checkboxLabel} type="checkbox" checked={enabled} onChange={handleEnabledChange}/>
|
|
34
|
+
</td>
|
|
35
|
+
<td>{columnLabel}</td>
|
|
36
|
+
<td>String</td>
|
|
37
|
+
<td>
|
|
38
|
+
<select name={opSelectLabel} aria-label={opSelectLabel} disabled={!enabled} className="form-select" value={scheme} onChange={handleOpChange}>
|
|
39
|
+
{stringFilterSchemes.map(function (scheme) { return (<option key={scheme} value={scheme}>
|
|
40
|
+
{stringFilterSchemeNames[scheme]}
|
|
41
|
+
</option>); })}
|
|
42
|
+
</select>
|
|
43
|
+
</td>
|
|
44
|
+
<td>
|
|
45
|
+
<input name={valueInputLabel} aria-label={valueInputLabel} className="form-control" required={enabled} disabled={!enabled} value={searchString} onChange={handleSearchStringChange}/>
|
|
46
|
+
</td>
|
|
47
|
+
</tr>);
|
|
48
|
+
};
|
|
49
|
+
export default StringFilterRow;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AbstractDateFilterState, AbstractFilterState, DateFilterScheme, NumberFilterScheme, StringFilterState } from "../types";
|
|
2
|
+
export interface NumberFormFilterState extends AbstractFilterState {
|
|
3
|
+
type: "number";
|
|
4
|
+
scheme: NumberFilterScheme;
|
|
5
|
+
inputValue: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DateFormFilterState extends AbstractDateFilterState {
|
|
8
|
+
scheme: DateFilterScheme;
|
|
9
|
+
startDate: string;
|
|
10
|
+
endDate: string;
|
|
11
|
+
}
|
|
12
|
+
export type FilterFormRowState = StringFilterState | NumberFormFilterState | DateFormFilterState;
|
|
13
|
+
export type FilterFormState = Record<string, FilterFormRowState>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
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 { useMemo } from "react";
|
|
13
|
+
import { dateToDatetimeInputStr, dateToInputStr } from "../util/datetime";
|
|
14
|
+
var useFormStateFromTableFilterState = function (tableFilterState) {
|
|
15
|
+
return useMemo(function () {
|
|
16
|
+
return Object.keys(tableFilterState).reduce(function (filterFormState, colName) {
|
|
17
|
+
var editableState = tableFilterState[colName].editableState;
|
|
18
|
+
switch (editableState.type) {
|
|
19
|
+
case "string": {
|
|
20
|
+
filterFormState[colName] = __assign({}, editableState);
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
case "number": {
|
|
24
|
+
filterFormState[colName] = {
|
|
25
|
+
type: "number",
|
|
26
|
+
scheme: editableState.scheme,
|
|
27
|
+
enabled: editableState.enabled,
|
|
28
|
+
inputValue: editableState.numValue === null
|
|
29
|
+
? ""
|
|
30
|
+
: String(editableState.numValue),
|
|
31
|
+
};
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
default: {
|
|
35
|
+
// date or datetime
|
|
36
|
+
var partialFormState = {
|
|
37
|
+
type: editableState.type,
|
|
38
|
+
enabled: editableState.enabled,
|
|
39
|
+
};
|
|
40
|
+
var dateToStrConverter = editableState.type === "date"
|
|
41
|
+
? dateToInputStr
|
|
42
|
+
: dateToDatetimeInputStr;
|
|
43
|
+
switch (editableState.scheme) {
|
|
44
|
+
case "startFrom": {
|
|
45
|
+
filterFormState[colName] = __assign(__assign({}, partialFormState), { scheme: "startFrom", startDate: editableState.startDate === null
|
|
46
|
+
? ""
|
|
47
|
+
: dateToStrConverter(editableState.startDate), endDate: "" });
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "endAt": {
|
|
51
|
+
filterFormState[colName] = __assign(__assign({}, partialFormState), { scheme: "endAt", startDate: "", endDate: editableState.endDate === null
|
|
52
|
+
? ""
|
|
53
|
+
: dateToStrConverter(editableState.endDate) });
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
default: {
|
|
57
|
+
// between
|
|
58
|
+
filterFormState[colName] = __assign(__assign({}, partialFormState), { scheme: "between", startDate: editableState.startDate === null
|
|
59
|
+
? ""
|
|
60
|
+
: dateToStrConverter(editableState.startDate), endDate: editableState.endDate === null
|
|
61
|
+
? ""
|
|
62
|
+
: dateToStrConverter(editableState.endDate) });
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return filterFormState;
|
|
69
|
+
}, {});
|
|
70
|
+
}, [tableFilterState]);
|
|
71
|
+
};
|
|
72
|
+
export default useFormStateFromTableFilterState;
|
package/Grid.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
|
-
import { ColDef, RowDef, Size, TableSortModel } from "./types";
|
|
2
|
+
import { ColDef, FilterModel, RowDef, Size, TableSortModel } from "./types";
|
|
3
3
|
export interface GridPaginationState {
|
|
4
4
|
pageSizeOptions: number[];
|
|
5
5
|
pageSizeIndex: number;
|
|
@@ -14,6 +14,7 @@ export interface GridProps {
|
|
|
14
14
|
cols: ColDef[];
|
|
15
15
|
pagination?: GridPaginationState;
|
|
16
16
|
sortModel?: TableSortModel;
|
|
17
|
+
filterModel?: FilterModel;
|
|
17
18
|
}
|
|
18
19
|
declare const Grid: FC<GridProps>;
|
|
19
20
|
export default Grid;
|
package/Grid.jsx
CHANGED
|
@@ -1,54 +1,22 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useMemo } from "react";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
3
|
import Pagination from "./Pagination";
|
|
4
4
|
import classNames from "classnames";
|
|
5
5
|
import ColHeaderCell from "./ColHeaderCell";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return function (a, b) {
|
|
14
|
-
if (a < b) {
|
|
15
|
-
return -1;
|
|
16
|
-
}
|
|
17
|
-
if (a > b) {
|
|
18
|
-
return 1;
|
|
19
|
-
}
|
|
20
|
-
return 0;
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
var getRowComparator = function (comparator, fieldName) {
|
|
24
|
-
return function (rowA, rowB) { return comparator(rowA[fieldName], rowB[fieldName]); };
|
|
25
|
-
};
|
|
6
|
+
import useFilter from "./hooks/useFilter";
|
|
7
|
+
import ToggleButton from "./ToggleButton";
|
|
8
|
+
import FilterOptionsTable from "./FilterOptionsTable/FilterOptionsTable";
|
|
9
|
+
import useFilterStateFromEditable from "./hooks/useFilterStateFromEditable";
|
|
10
|
+
import useAugmentedRows from "./hooks/useAugmentedRows";
|
|
11
|
+
import useSortedRows from "./hooks/useSortedRows";
|
|
12
|
+
import useDisplayRows from "./hooks/useDisplayRows";
|
|
26
13
|
var Grid = function (_a) {
|
|
27
|
-
var rows = _a.rows, cols = _a.cols, pagination = _a.pagination, sortModel = _a.sortModel;
|
|
28
|
-
var
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
var sortOrder = sortModel.sortColDef.order;
|
|
34
|
-
var sortColIndex = cols.findIndex(function (_a) {
|
|
35
|
-
var name = _a.name;
|
|
36
|
-
return name === sortFieldName;
|
|
37
|
-
});
|
|
38
|
-
if (sortColIndex < 0) {
|
|
39
|
-
throw new Error("The sortModel for the grid specifies that the data should be sorted based on a column named ".concat(sortFieldName, ", but it was not found among the column definitions."));
|
|
40
|
-
}
|
|
41
|
-
var typeStr = cols[sortColIndex].type;
|
|
42
|
-
var ascComparator = getTypeComparator(typeStr);
|
|
43
|
-
var rowComparator = getRowComparator(ascComparator, sortFieldName);
|
|
44
|
-
if (sortOrder === "desc") {
|
|
45
|
-
var descComparator = function (a, b) {
|
|
46
|
-
return ascComparator(a, b) * -1;
|
|
47
|
-
};
|
|
48
|
-
rowComparator = getRowComparator(descComparator, sortFieldName);
|
|
49
|
-
}
|
|
50
|
-
return rows.slice().sort(rowComparator);
|
|
51
|
-
}, [rows, cols, sortModel]);
|
|
14
|
+
var rows = _a.rows, cols = _a.cols, pagination = _a.pagination, sortModel = _a.sortModel, filterModel = _a.filterModel;
|
|
15
|
+
var editableFilterState = (filterModel === null || filterModel === void 0 ? void 0 : filterModel.tableFilterState) || null;
|
|
16
|
+
var filterState = useFilterStateFromEditable(cols, editableFilterState);
|
|
17
|
+
var augmentedRows = useAugmentedRows(rows);
|
|
18
|
+
var filteredRows = useFilter(augmentedRows, editableFilterState);
|
|
19
|
+
var sortedRows = useSortedRows(filteredRows, cols, sortModel);
|
|
52
20
|
var currentPageRows = useMemo(function () {
|
|
53
21
|
if (pagination === undefined) {
|
|
54
22
|
return sortedRows;
|
|
@@ -59,54 +27,8 @@ var Grid = function (_a) {
|
|
|
59
27
|
var upperIndex = lowerIndex + pageSize;
|
|
60
28
|
return sortedRows.slice(lowerIndex, upperIndex);
|
|
61
29
|
}, [sortedRows, pagination]);
|
|
62
|
-
var displayRows =
|
|
63
|
-
|
|
64
|
-
cols.forEach(function (_a, index) {
|
|
65
|
-
var name = _a.name;
|
|
66
|
-
nameToIndex.set(name, index);
|
|
67
|
-
});
|
|
68
|
-
return currentPageRows.map(function (row, index) {
|
|
69
|
-
cols
|
|
70
|
-
.map(function (_a) {
|
|
71
|
-
var name = _a.name;
|
|
72
|
-
return name;
|
|
73
|
-
})
|
|
74
|
-
.forEach(function (name) {
|
|
75
|
-
if (!(name in row)) {
|
|
76
|
-
throw new Error("Column definition specifies a property named \"".concat(name, "\", but it was not found in the row data object at index ").concat(index, "."));
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
var displayRow = [];
|
|
80
|
-
Object.keys(row).forEach(function (name) {
|
|
81
|
-
if (!nameToIndex.has(name)) {
|
|
82
|
-
console.error("Warning: row data contains a property named \"".concat(name, "\", but it was not found among the column definitions."));
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
var index = nameToIndex.get(name);
|
|
86
|
-
var formatter = cols[index].formatter;
|
|
87
|
-
var typeString = cols[index].type;
|
|
88
|
-
var value = row[name];
|
|
89
|
-
if (formatter) {
|
|
90
|
-
displayRow[index] = formatter(value);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (typeString === "date") {
|
|
94
|
-
displayRow[index] = value.toDateString();
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (typeString === "datetime") {
|
|
98
|
-
displayRow[index] = value.toLocaleString();
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (typeString === "number") {
|
|
102
|
-
displayRow[index] = value.toLocaleString();
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
displayRow[index] = value;
|
|
106
|
-
});
|
|
107
|
-
return displayRow;
|
|
108
|
-
});
|
|
109
|
-
}, [currentPageRows, cols]);
|
|
30
|
+
var displayRows = useDisplayRows(currentPageRows, cols);
|
|
31
|
+
var _b = useState(false), filterOptionsVisible = _b[0], setFilterOptionsVisible = _b[1];
|
|
110
32
|
var handleSetPageNum = function (pageNum) {
|
|
111
33
|
if (pagination === undefined) {
|
|
112
34
|
return;
|
|
@@ -119,12 +41,18 @@ var Grid = function (_a) {
|
|
|
119
41
|
}
|
|
120
42
|
pagination.setPageSizeIndex(Number(event.target.value));
|
|
121
43
|
};
|
|
44
|
+
var handleToggleFilterOptions = function () {
|
|
45
|
+
setFilterOptionsVisible(!filterOptionsVisible);
|
|
46
|
+
};
|
|
122
47
|
// Once this component implements selection state, and if such interactivity is enabled, (conditionally) change the
|
|
123
48
|
// aria role to "grid".
|
|
124
|
-
//
|
|
125
|
-
// sorting or pagination, is implemented.
|
|
49
|
+
// TODO: implement the above described features: conditionally changing aria role to grid
|
|
126
50
|
return (<div>
|
|
127
|
-
<
|
|
51
|
+
{filterState && filterModel && (<div>
|
|
52
|
+
<ToggleButton isActive={filterOptionsVisible} label={"".concat(filterOptionsVisible ? "Hide" : "Show ", " Filter Options")} onClick={handleToggleFilterOptions}/>
|
|
53
|
+
{filterOptionsVisible && (<FilterOptionsTable filterState={filterState} setFilterState={filterModel.setTableFilterState}/>)}
|
|
54
|
+
</div>)}
|
|
55
|
+
<table className="table" aria-rowcount={filteredRows.length + 1}>
|
|
128
56
|
<thead>
|
|
129
57
|
<tr aria-rowindex={1}>
|
|
130
58
|
{cols.map(function (_a, index) {
|
|
@@ -145,8 +73,8 @@ var Grid = function (_a) {
|
|
|
145
73
|
</tr>
|
|
146
74
|
</thead>
|
|
147
75
|
<tbody>
|
|
148
|
-
{displayRows.map(function (row, index) { return (<tr key={
|
|
149
|
-
{row.map(function (value, index) { return (<td key={index} aria-colindex={index + 1}>
|
|
76
|
+
{displayRows.map(function (row, index) { return (<tr key={row.origIndex} aria-rowindex={index + 2}>
|
|
77
|
+
{row.contents.map(function (value, index) { return (<td key={index} aria-colindex={index + 1}>
|
|
150
78
|
{value}
|
|
151
79
|
</td>); })}
|
|
152
80
|
</tr>); })}
|
package/ToggleButton.jsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import classNames from "classnames";
|
|
3
|
+
var ToggleButton = function (_a) {
|
|
4
|
+
var isActive = _a.isActive, label = _a.label, onClick = _a.onClick;
|
|
5
|
+
var baseClasses = ["btn", "btn-primary"];
|
|
6
|
+
var variableClasses = {
|
|
7
|
+
active: isActive,
|
|
8
|
+
};
|
|
9
|
+
return (<button type="button" className={classNames(baseClasses, variableClasses)} aria-pressed={isActive} onClick={onClick}>
|
|
10
|
+
{label}
|
|
11
|
+
</button>);
|
|
12
|
+
};
|
|
13
|
+
export default ToggleButton;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
var useAugmentedRows = function (rows) {
|
|
3
|
+
return useMemo(function () {
|
|
4
|
+
return rows.map(function (row, index) { return ({
|
|
5
|
+
data: row,
|
|
6
|
+
meta: {
|
|
7
|
+
origIndex: index,
|
|
8
|
+
},
|
|
9
|
+
}); });
|
|
10
|
+
}, [rows]);
|
|
11
|
+
};
|
|
12
|
+
export default useAugmentedRows;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
var useDisplayRows = function (currentPageRows, cols) {
|
|
3
|
+
return useMemo(function () {
|
|
4
|
+
var nameToIndex = new Map();
|
|
5
|
+
cols.forEach(function (_a, index) {
|
|
6
|
+
var name = _a.name;
|
|
7
|
+
nameToIndex.set(name, index);
|
|
8
|
+
});
|
|
9
|
+
return currentPageRows.map(function (row, index) {
|
|
10
|
+
cols
|
|
11
|
+
.map(function (_a) {
|
|
12
|
+
var name = _a.name;
|
|
13
|
+
return name;
|
|
14
|
+
})
|
|
15
|
+
.forEach(function (name) {
|
|
16
|
+
if (!(name in row.data)) {
|
|
17
|
+
throw new Error("Column definition specifies a property named \"".concat(name, "\", but it was not found in the row data object at index ").concat(index, "."));
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
var displayRow = [];
|
|
21
|
+
Object.keys(row.data).forEach(function (name) {
|
|
22
|
+
if (!nameToIndex.has(name)) {
|
|
23
|
+
console.error("Warning: row data contains a property named \"".concat(name, "\", but it was not found among the column definitions."));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
var index = nameToIndex.get(name);
|
|
27
|
+
var formatter = cols[index].formatter;
|
|
28
|
+
var typeString = cols[index].type;
|
|
29
|
+
var value = row.data[name];
|
|
30
|
+
if (formatter) {
|
|
31
|
+
displayRow[index] = formatter(value);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (typeString === "date") {
|
|
35
|
+
displayRow[index] = value.toDateString();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (typeString === "datetime") {
|
|
39
|
+
displayRow[index] = value.toLocaleString();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (typeString === "number") {
|
|
43
|
+
displayRow[index] = value.toLocaleString();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
displayRow[index] = value;
|
|
47
|
+
});
|
|
48
|
+
return { contents: displayRow, origIndex: row.meta.origIndex };
|
|
49
|
+
});
|
|
50
|
+
}, [currentPageRows, cols]);
|
|
51
|
+
};
|
|
52
|
+
export default useDisplayRows;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
var useEditableFromFilterState = function (filterState) {
|
|
3
|
+
return useMemo(function () {
|
|
4
|
+
if (filterState === null) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
var editableState = {};
|
|
8
|
+
Object.keys(filterState).forEach(function (columnName) {
|
|
9
|
+
editableState[columnName] = filterState[columnName].editableState;
|
|
10
|
+
});
|
|
11
|
+
return editableState;
|
|
12
|
+
}, [filterState]);
|
|
13
|
+
};
|
|
14
|
+
export default useEditableFromFilterState;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
var useFilter = function (rows, filterState) {
|
|
3
|
+
return useMemo(function () {
|
|
4
|
+
if (filterState === null) {
|
|
5
|
+
return rows;
|
|
6
|
+
}
|
|
7
|
+
return rows.filter(function (row) {
|
|
8
|
+
function checkIfPassesStringFilter(value, state) {
|
|
9
|
+
switch (state.scheme) {
|
|
10
|
+
case "contains": {
|
|
11
|
+
return value.includes(state.searchString);
|
|
12
|
+
}
|
|
13
|
+
case "startsWith": {
|
|
14
|
+
return value.startsWith(state.searchString);
|
|
15
|
+
}
|
|
16
|
+
default: {
|
|
17
|
+
return value.endsWith(state.searchString);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function checkIfPassesNumberFilter(value, state) {
|
|
22
|
+
// Note that a blank string becomes 0. This situation should usually be
|
|
23
|
+
// prevented by form validation.
|
|
24
|
+
var numValue = Number(state.numValue);
|
|
25
|
+
switch (state.scheme) {
|
|
26
|
+
case "equals":
|
|
27
|
+
return value === numValue;
|
|
28
|
+
case "greaterThan":
|
|
29
|
+
return value > numValue;
|
|
30
|
+
case "lessThan":
|
|
31
|
+
return value < numValue;
|
|
32
|
+
case "greaterOrEqual":
|
|
33
|
+
return value >= numValue;
|
|
34
|
+
default:
|
|
35
|
+
return value <= numValue;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function checkIfPassesDateFilter(value, state) {
|
|
39
|
+
switch (state.scheme) {
|
|
40
|
+
case "startFrom":
|
|
41
|
+
return state.startDate === null || value >= state.startDate;
|
|
42
|
+
case "endAt":
|
|
43
|
+
return state.endDate === null || value <= state.endDate;
|
|
44
|
+
case "between":
|
|
45
|
+
return (state.startDate === null ||
|
|
46
|
+
state.endDate === null ||
|
|
47
|
+
(value >= state.startDate && value <= state.endDate));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var columnNames = Object.keys(row.data);
|
|
51
|
+
for (var _i = 0, columnNames_1 = columnNames; _i < columnNames_1.length; _i++) {
|
|
52
|
+
var columnName = columnNames_1[_i];
|
|
53
|
+
if (!(columnName in filterState)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (!filterState[columnName].enabled) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
var columnFilterState = filterState[columnName];
|
|
60
|
+
switch (columnFilterState.type) {
|
|
61
|
+
case "string": {
|
|
62
|
+
if (!checkIfPassesStringFilter(row.data[columnName], columnFilterState)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case "number": {
|
|
68
|
+
if (!checkIfPassesNumberFilter(row.data[columnName], columnFilterState)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
default: {
|
|
74
|
+
if (!checkIfPassesDateFilter(row.data[columnName], columnFilterState)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
82
|
+
}, [rows, filterState]);
|
|
83
|
+
};
|
|
84
|
+
export default useFilter;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
var useFilterStateFromEditable = function (colDefs, editableFilterState) {
|
|
3
|
+
return useMemo(function () {
|
|
4
|
+
if (editableFilterState === null) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
var filterState = {};
|
|
8
|
+
colDefs.forEach(function (_a) {
|
|
9
|
+
var name = _a.name, label = _a.label;
|
|
10
|
+
filterState[name] = {
|
|
11
|
+
editableState: editableFilterState[name],
|
|
12
|
+
label: label,
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
return filterState;
|
|
16
|
+
}, [colDefs, editableFilterState]);
|
|
17
|
+
};
|
|
18
|
+
export default useFilterStateFromEditable;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
var getTypeComparator = function (typeStr) {
|
|
3
|
+
if (typeStr === "date" || typeStr === "datetime") {
|
|
4
|
+
return function (a, b) { return a.valueOf() - b.valueOf(); };
|
|
5
|
+
}
|
|
6
|
+
if (typeStr === "number") {
|
|
7
|
+
return function (a, b) { return a - b; };
|
|
8
|
+
}
|
|
9
|
+
return function (a, b) {
|
|
10
|
+
if (a < b) {
|
|
11
|
+
return -1;
|
|
12
|
+
}
|
|
13
|
+
if (a > b) {
|
|
14
|
+
return 1;
|
|
15
|
+
}
|
|
16
|
+
return 0;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
var getRowComparator = function (comparator, fieldName) {
|
|
20
|
+
return function (rowA, rowB) { return comparator(rowA.data[fieldName], rowB.data[fieldName]); };
|
|
21
|
+
};
|
|
22
|
+
var useSortedRows = function (rows, cols, sortModel) {
|
|
23
|
+
return useMemo(function () {
|
|
24
|
+
if (!sortModel || !sortModel.sortColDef) {
|
|
25
|
+
return rows;
|
|
26
|
+
}
|
|
27
|
+
var sortFieldName = sortModel.sortColDef.name;
|
|
28
|
+
var sortOrder = sortModel.sortColDef.order;
|
|
29
|
+
var sortColIndex = cols.findIndex(function (_a) {
|
|
30
|
+
var name = _a.name;
|
|
31
|
+
return name === sortFieldName;
|
|
32
|
+
});
|
|
33
|
+
if (sortColIndex < 0) {
|
|
34
|
+
throw new Error("The sortModel for the grid specifies that the data should be sorted based on a column named ".concat(sortFieldName, ", but it was not found among the column definitions."));
|
|
35
|
+
}
|
|
36
|
+
var typeStr = cols[sortColIndex].type;
|
|
37
|
+
var ascComparator = getTypeComparator(typeStr);
|
|
38
|
+
var rowComparator = getRowComparator(ascComparator, sortFieldName);
|
|
39
|
+
if (sortOrder === "desc") {
|
|
40
|
+
var descComparator = function (a, b) {
|
|
41
|
+
return ascComparator(a, b) * -1;
|
|
42
|
+
};
|
|
43
|
+
rowComparator = getRowComparator(descComparator, sortFieldName);
|
|
44
|
+
}
|
|
45
|
+
return rows.slice().sort(rowComparator);
|
|
46
|
+
}, [rows, cols, sortModel]);
|
|
47
|
+
};
|
|
48
|
+
export default useSortedRows;
|
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": "1.
|
|
4
|
+
"version": "1.1.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Brook Li",
|
|
7
7
|
"homepage": "https://react-bootstrap-data-grid.vercel.app/",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"grid"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"classnames": "^2.5.1"
|
|
17
|
+
"classnames": "^2.5.1",
|
|
18
|
+
"dayjs": "^1.11.13"
|
|
18
19
|
},
|
|
19
20
|
"peerDependencies": {
|
|
20
21
|
"react": "^19",
|
package/types.d.ts
CHANGED
|
@@ -8,6 +8,17 @@ export interface ColDef {
|
|
|
8
8
|
sortable?: boolean;
|
|
9
9
|
}
|
|
10
10
|
export type RowDef = Record<string, ColDataType>;
|
|
11
|
+
export interface RowMetadata {
|
|
12
|
+
origIndex: number;
|
|
13
|
+
}
|
|
14
|
+
export interface AugRowDef {
|
|
15
|
+
data: RowDef;
|
|
16
|
+
meta: RowMetadata;
|
|
17
|
+
}
|
|
18
|
+
export interface FormattedRow {
|
|
19
|
+
contents: string[];
|
|
20
|
+
origIndex: number;
|
|
21
|
+
}
|
|
11
22
|
export type JustifyContentSetting = "start" | "end" | "center" | "between" | "around" | "evenly";
|
|
12
23
|
export type Size = "small" | "medium" | "large";
|
|
13
24
|
export type SortOrder = "asc" | "desc";
|
|
@@ -23,3 +34,54 @@ export interface TableSortModel {
|
|
|
23
34
|
sortColDef: SortColDef | null;
|
|
24
35
|
setSortColDef: (sortColDef: SortColDef | null) => void;
|
|
25
36
|
}
|
|
37
|
+
export type TableFilterState = Record<string, ColFilterState>;
|
|
38
|
+
export type EditableTableFilterState = Record<string, FilterState>;
|
|
39
|
+
export interface ColFilterState {
|
|
40
|
+
editableState: FilterState;
|
|
41
|
+
label: string;
|
|
42
|
+
}
|
|
43
|
+
export interface AbstractFilterState {
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
}
|
|
46
|
+
export declare const stringFilterSchemes: readonly ["contains", "startsWith", "endsWith"];
|
|
47
|
+
export type StringFilterScheme = (typeof stringFilterSchemes)[number];
|
|
48
|
+
export declare const stringFilterSchemeNames: Record<StringFilterScheme, string>;
|
|
49
|
+
export interface StringFilterState extends AbstractFilterState {
|
|
50
|
+
type: "string";
|
|
51
|
+
scheme: StringFilterScheme;
|
|
52
|
+
searchString: string;
|
|
53
|
+
}
|
|
54
|
+
export declare const numberFilterSchemes: readonly ["equals", "greaterThan", "lessThan", "greaterOrEqual", "lessOrEqual"];
|
|
55
|
+
export type NumberFilterScheme = (typeof numberFilterSchemes)[number];
|
|
56
|
+
export declare const numberFilterSchemeNames: Record<NumberFilterScheme, string>;
|
|
57
|
+
export interface NumberFilterState extends AbstractFilterState {
|
|
58
|
+
type: "number";
|
|
59
|
+
scheme: NumberFilterScheme;
|
|
60
|
+
numValue: number | null;
|
|
61
|
+
}
|
|
62
|
+
export declare const dateFilterSchemes: readonly ["startFrom", "endAt", "between"];
|
|
63
|
+
export type DateFilterScheme = (typeof dateFilterSchemes)[number];
|
|
64
|
+
export declare const dateFilterSchemeNames: Record<DateFilterScheme, string>;
|
|
65
|
+
export interface AbstractDateFilterState extends AbstractFilterState {
|
|
66
|
+
type: "date" | "datetime";
|
|
67
|
+
scheme: DateFilterScheme;
|
|
68
|
+
}
|
|
69
|
+
export interface StartDateFilterState extends AbstractDateFilterState {
|
|
70
|
+
scheme: "startFrom";
|
|
71
|
+
startDate: Date | null;
|
|
72
|
+
}
|
|
73
|
+
export interface EndDateFilterState extends AbstractDateFilterState {
|
|
74
|
+
scheme: "endAt";
|
|
75
|
+
endDate: Date | null;
|
|
76
|
+
}
|
|
77
|
+
export interface BetweenDatesFilterState extends AbstractDateFilterState {
|
|
78
|
+
scheme: "between";
|
|
79
|
+
startDate: Date | null;
|
|
80
|
+
endDate: Date | null;
|
|
81
|
+
}
|
|
82
|
+
export type DateFilterState = StartDateFilterState | EndDateFilterState | BetweenDatesFilterState;
|
|
83
|
+
export type FilterState = StringFilterState | NumberFilterState | DateFilterState;
|
|
84
|
+
export interface FilterModel {
|
|
85
|
+
tableFilterState: EditableTableFilterState;
|
|
86
|
+
setTableFilterState: (state: EditableTableFilterState) => void;
|
|
87
|
+
}
|
package/types.js
CHANGED
|
@@ -1 +1,30 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var stringFilterSchemes = [
|
|
2
|
+
"contains",
|
|
3
|
+
"startsWith",
|
|
4
|
+
"endsWith",
|
|
5
|
+
];
|
|
6
|
+
export var stringFilterSchemeNames = {
|
|
7
|
+
contains: "Contains",
|
|
8
|
+
startsWith: "Starts With",
|
|
9
|
+
endsWith: "Ends With",
|
|
10
|
+
};
|
|
11
|
+
export var numberFilterSchemes = [
|
|
12
|
+
"equals",
|
|
13
|
+
"greaterThan",
|
|
14
|
+
"lessThan",
|
|
15
|
+
"greaterOrEqual",
|
|
16
|
+
"lessOrEqual",
|
|
17
|
+
];
|
|
18
|
+
export var numberFilterSchemeNames = {
|
|
19
|
+
equals: "=",
|
|
20
|
+
greaterThan: ">",
|
|
21
|
+
lessThan: "<",
|
|
22
|
+
greaterOrEqual: ">=",
|
|
23
|
+
lessOrEqual: "<=",
|
|
24
|
+
};
|
|
25
|
+
export var dateFilterSchemes = ["startFrom", "endAt", "between"];
|
|
26
|
+
export var dateFilterSchemeNames = {
|
|
27
|
+
startFrom: "Start Form",
|
|
28
|
+
endAt: "End At",
|
|
29
|
+
between: "Between",
|
|
30
|
+
};
|
package/util/datetime.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
export var dateToInputStr = function (date) { return dayjs(date).format("YYYY-MM-DD"); };
|
|
3
|
+
export var dateToDatetimeInputStr = function (date) {
|
|
4
|
+
return dayjs(date).format("YYYY-MM-DDTHH:mm");
|
|
5
|
+
};
|
|
6
|
+
// All dates and datetimes that the grid displays are in UTC. The datetime
|
|
7
|
+
// string in the value attribute of an input element of type datetime-local
|
|
8
|
+
// is based on the local timezone of the client.
|
|
9
|
+
export var datetimeInputStrToUtc = function (datetimeStr) { return datetimeStr + "Z"; };
|
package/component.d.ts
DELETED
package/component.jsx
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useMemo } from "react";
|
|
3
|
-
var Grid = function (_a) {
|
|
4
|
-
var rows = _a.rows, cols = _a.cols;
|
|
5
|
-
var displayRows = useMemo(function () {
|
|
6
|
-
var nameToIndex = new Map();
|
|
7
|
-
cols.forEach(function (_a, index) {
|
|
8
|
-
var name = _a.name;
|
|
9
|
-
nameToIndex.set(name, index);
|
|
10
|
-
});
|
|
11
|
-
return rows.map(function (row, index) {
|
|
12
|
-
cols
|
|
13
|
-
.map(function (_a) {
|
|
14
|
-
var name = _a.name;
|
|
15
|
-
return name;
|
|
16
|
-
})
|
|
17
|
-
.forEach(function (name) {
|
|
18
|
-
if (!(name in row)) {
|
|
19
|
-
throw new Error("Column definition specifies a property named \"".concat(name, "\",\n but it was no found in the row data object at index ").concat(index));
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
var displayRow = [];
|
|
23
|
-
Object.keys(row).forEach(function (name) {
|
|
24
|
-
if (!nameToIndex.has(name)) {
|
|
25
|
-
throw new Error("Row data contains a property named \"".concat(name, "\",\n but it was not found among the column definitions"));
|
|
26
|
-
}
|
|
27
|
-
var index = nameToIndex.get(name);
|
|
28
|
-
var formatter = cols[index].formatter;
|
|
29
|
-
var typeString = cols[index].type;
|
|
30
|
-
var value = row[name];
|
|
31
|
-
if (formatter) {
|
|
32
|
-
displayRow[index] = formatter(value);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (typeString === "date") {
|
|
36
|
-
displayRow[index] = value.toDateString();
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (typeString === "datetime") {
|
|
40
|
-
displayRow[index] = value.toLocaleString();
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
if (typeString === "number") {
|
|
44
|
-
displayRow[index] = value.toLocaleString();
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
displayRow[index] = value;
|
|
48
|
-
});
|
|
49
|
-
return displayRow;
|
|
50
|
-
});
|
|
51
|
-
}, [rows, cols]);
|
|
52
|
-
// Once this component implements selection state, and if such interactivity is enabled, (conditionally) change the
|
|
53
|
-
// aria role to "grid".
|
|
54
|
-
// Array index is okay for the key for rows until some type of feature involving changing the index of rows, such as
|
|
55
|
-
// sorting or pagination, is implemented.
|
|
56
|
-
return (<table className="table">
|
|
57
|
-
<thead>
|
|
58
|
-
<tr>
|
|
59
|
-
{cols.map(function (_a) {
|
|
60
|
-
var name = _a.name, label = _a.label;
|
|
61
|
-
return (<th key={name}>{label}</th>);
|
|
62
|
-
})}
|
|
63
|
-
</tr>
|
|
64
|
-
</thead>
|
|
65
|
-
<tbody>
|
|
66
|
-
{displayRows.map(function (row, index) { return (<tr key={index}>
|
|
67
|
-
{row.map(function (value, index) { return (<td key={index}>{value}</td>); })}
|
|
68
|
-
</tr>); })}
|
|
69
|
-
</tbody>
|
|
70
|
-
</table>);
|
|
71
|
-
};
|
|
72
|
-
export default Grid;
|