@absreim/react-bootstrap-data-grid 1.0.0 → 1.1.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.
@@ -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,63 @@
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
+ return (<tr>
39
+ <td>
40
+ <input type="checkbox" checked={enabled} name="enabled" onChange={handleEnabledChange}/>
41
+ </td>
42
+ <td>{columnLabel}</td>
43
+ <td>{filterState.type === "date" ? "Date" : "Datetime"}</td>
44
+ <td>
45
+ <select disabled={!enabled} className="form-select" value={scheme} onChange={handleOpChange}>
46
+ {dateFilterSchemes.map(function (scheme) { return (<option key={scheme} value={scheme}>
47
+ {dateFilterSchemeNames[scheme]}
48
+ </option>); })}
49
+ </select>
50
+ </td>
51
+ <td>
52
+ {scheme !== "endAt" && (<>
53
+ {scheme === "between" && (<label htmlFor={startDateInputId}>Start Date</label>)}
54
+ <input id={startDateInputId} className="form-control" type={inputType} required={enabled} disabled={!enabled} value={startDate} onChange={handleStartValueChange} aria-label="Start Date"/>
55
+ </>)}
56
+ {scheme !== "startFrom" && (<>
57
+ {scheme === "between" && (<label htmlFor={endDateInputId}>End Date</label>)}
58
+ <input className="form-control" type={inputType} required={enabled} disabled={!enabled} value={endDate} onChange={handleEndValueChange} aria-label="End Date"/>
59
+ </>)}
60
+ </td>
61
+ </tr>);
62
+ };
63
+ 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,47 @@
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
+ // TODO: Input labelling for accessibility
29
+ return (<tr>
30
+ <td>
31
+ <input type="checkbox" checked={enabled} name="enabled" onChange={handleEnabledChange}/>
32
+ </td>
33
+ <td>{columnLabel}</td>
34
+ <td>Number</td>
35
+ <td>
36
+ <select disabled={!enabled} className="form-select" value={scheme} onChange={handleOpChange}>
37
+ {numberFilterSchemes.map(function (scheme) { return (<option key={scheme} value={scheme}>
38
+ {numberFilterSchemeNames[scheme]}
39
+ </option>); })}
40
+ </select>
41
+ </td>
42
+ <td>
43
+ <input className="form-control" type="number" required={enabled} disabled={!enabled} value={inputValue} onChange={handleNumInputValueChange}/>
44
+ </td>
45
+ </tr>);
46
+ };
47
+ 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,47 @@
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
+ // TODO: Input labelling for accessibility
29
+ return (<tr>
30
+ <td>
31
+ <input type="checkbox" checked={enabled} name="enabled" onChange={handleEnabledChange}/>
32
+ </td>
33
+ <td>{columnLabel}</td>
34
+ <td>String</td>
35
+ <td>
36
+ <select disabled={!enabled} className="form-select" value={scheme} onChange={handleOpChange}>
37
+ {stringFilterSchemes.map(function (scheme) { return (<option key={scheme} value={scheme}>
38
+ {stringFilterSchemeNames[scheme]}
39
+ </option>); })}
40
+ </select>
41
+ </td>
42
+ <td>
43
+ <input className="form-control" required={enabled} disabled={!enabled} value={searchString} onChange={handleSearchStringChange}/>
44
+ </td>
45
+ </tr>);
46
+ };
47
+ 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,4 @@
1
+ import { TableFilterState } from "../types";
2
+ import { FilterFormState } from "./types";
3
+ declare const useFormStateFromTableFilterState: (tableFilterState: TableFilterState) => FilterFormState;
4
+ export default useFormStateFromTableFilterState;
@@ -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,8 +1,12 @@
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
+ import useFilter from "./hooks/useFilter";
7
+ import ToggleButton from "./ToggleButton";
8
+ import FilterOptionsTable from "./FilterOptionsTable/FilterOptionsTable";
9
+ import useFilterStateFromEditable from "./hooks/useFilterStateFromEditable";
6
10
  var getTypeComparator = function (typeStr) {
7
11
  if (typeStr === "date" || typeStr === "datetime") {
8
12
  return function (a, b) { return a.valueOf() - b.valueOf(); };
@@ -24,10 +28,13 @@ var getRowComparator = function (comparator, fieldName) {
24
28
  return function (rowA, rowB) { return comparator(rowA[fieldName], rowB[fieldName]); };
25
29
  };
26
30
  var Grid = function (_a) {
27
- var rows = _a.rows, cols = _a.cols, pagination = _a.pagination, sortModel = _a.sortModel;
31
+ var rows = _a.rows, cols = _a.cols, pagination = _a.pagination, sortModel = _a.sortModel, filterModel = _a.filterModel;
32
+ var editableFilterState = (filterModel === null || filterModel === void 0 ? void 0 : filterModel.tableFilterState) || null;
33
+ var filterState = useFilterStateFromEditable(cols, editableFilterState);
34
+ var filteredRows = useFilter(rows, editableFilterState);
28
35
  var sortedRows = useMemo(function () {
29
36
  if (!sortModel || !sortModel.sortColDef) {
30
- return rows;
37
+ return filteredRows;
31
38
  }
32
39
  var sortFieldName = sortModel.sortColDef.name;
33
40
  var sortOrder = sortModel.sortColDef.order;
@@ -47,8 +54,8 @@ var Grid = function (_a) {
47
54
  };
48
55
  rowComparator = getRowComparator(descComparator, sortFieldName);
49
56
  }
50
- return rows.slice().sort(rowComparator);
51
- }, [rows, cols, sortModel]);
57
+ return filteredRows.slice().sort(rowComparator);
58
+ }, [filteredRows, cols, sortModel]);
52
59
  var currentPageRows = useMemo(function () {
53
60
  if (pagination === undefined) {
54
61
  return sortedRows;
@@ -107,6 +114,7 @@ var Grid = function (_a) {
107
114
  return displayRow;
108
115
  });
109
116
  }, [currentPageRows, cols]);
117
+ var _b = useState(false), filterOptionsVisible = _b[0], setFilterOptionsVisible = _b[1];
110
118
  var handleSetPageNum = function (pageNum) {
111
119
  if (pagination === undefined) {
112
120
  return;
@@ -119,11 +127,20 @@ var Grid = function (_a) {
119
127
  }
120
128
  pagination.setPageSizeIndex(Number(event.target.value));
121
129
  };
130
+ var handleToggleFilterOptions = function () {
131
+ setFilterOptionsVisible(!filterOptionsVisible);
132
+ };
122
133
  // Once this component implements selection state, and if such interactivity is enabled, (conditionally) change the
123
134
  // aria role to "grid".
124
135
  // Array index is okay for the key for rows until some type of feature involving changing the index of rows, such as
125
136
  // sorting or pagination, is implemented.
137
+ // TODO: implement the above described features: conditionally changing aria role to grid and a key field other than
138
+ // index
126
139
  return (<div>
140
+ {filterState && filterModel && (<div>
141
+ <ToggleButton isActive={filterOptionsVisible} label={"".concat(filterOptionsVisible ? "Hide" : "Show ", " Filter Options")} onClick={handleToggleFilterOptions}/>
142
+ {filterOptionsVisible && (<FilterOptionsTable filterState={filterState} setFilterState={filterModel.setTableFilterState}/>)}
143
+ </div>)}
127
144
  <table className="table">
128
145
  <thead>
129
146
  <tr aria-rowindex={1}>
@@ -0,0 +1,8 @@
1
+ import { FC } from "react";
2
+ export interface ToggleButtonProps {
3
+ isActive: boolean;
4
+ label: string;
5
+ onClick: () => void;
6
+ }
7
+ declare const ToggleButton: FC<ToggleButtonProps>;
8
+ export default ToggleButton;
@@ -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,3 @@
1
+ import { EditableTableFilterState, TableFilterState } from "../types";
2
+ declare const useEditableFromFilterState: (filterState: TableFilterState | null) => EditableTableFilterState | null;
3
+ export default useEditableFromFilterState;
@@ -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,3 @@
1
+ import { EditableTableFilterState, RowDef } from "../types";
2
+ declare const useFilter: (rows: RowDef[], filterState: EditableTableFilterState | null) => RowDef[];
3
+ export default useFilter;
@@ -0,0 +1,82 @@
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
+ var numValue = Number(state.numValue); // Note that a blank string becomes 0
23
+ switch (state.scheme) {
24
+ case "equals":
25
+ return value === numValue;
26
+ case "greaterThan":
27
+ return value > numValue;
28
+ case "lessThan":
29
+ return value < numValue;
30
+ case "greaterOrEqual":
31
+ return value >= numValue;
32
+ default:
33
+ return value <= numValue;
34
+ }
35
+ }
36
+ function checkIfPassesDateFilter(value, state) {
37
+ switch (state.scheme) {
38
+ case "startFrom":
39
+ return state.startDate === null || value >= state.startDate;
40
+ case "endAt":
41
+ return state.endDate === null || value <= state.endDate;
42
+ case "between":
43
+ return (state.startDate === null ||
44
+ state.endDate === null ||
45
+ (value >= state.startDate && value <= state.endDate));
46
+ }
47
+ }
48
+ var columnNames = Object.keys(row);
49
+ for (var _i = 0, columnNames_1 = columnNames; _i < columnNames_1.length; _i++) {
50
+ var columnName = columnNames_1[_i];
51
+ if (!(columnName in filterState)) {
52
+ continue;
53
+ }
54
+ if (!filterState[columnName].enabled) {
55
+ continue;
56
+ }
57
+ var columnFilterState = filterState[columnName];
58
+ switch (columnFilterState.type) {
59
+ case "string": {
60
+ if (!checkIfPassesStringFilter(row[columnName], columnFilterState)) {
61
+ return false;
62
+ }
63
+ break;
64
+ }
65
+ case "number": {
66
+ if (!checkIfPassesNumberFilter(row[columnName], columnFilterState)) {
67
+ return false;
68
+ }
69
+ break;
70
+ }
71
+ default: {
72
+ if (!checkIfPassesDateFilter(row[columnName], columnFilterState)) {
73
+ return false;
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return true;
79
+ });
80
+ }, [rows, filterState]);
81
+ };
82
+ export default useFilter;
@@ -0,0 +1,3 @@
1
+ import { ColDef, EditableTableFilterState, TableFilterState } from "../types";
2
+ declare const useFilterStateFromEditable: (colDefs: ColDef[], editableFilterState: EditableTableFilterState | null) => TableFilterState | null;
3
+ export default useFilterStateFromEditable;
@@ -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,2 @@
1
+ import { ColDataTypeStrings } from "../types";
2
+ export declare const colTypeDescs: Record<ColDataTypeStrings, string>;
@@ -0,0 +1,6 @@
1
+ export var colTypeDescs = {
2
+ string: "String",
3
+ number: "Number",
4
+ date: "Date",
5
+ datetime: "DateTime",
6
+ };
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.0.0",
4
+ "version": "1.1.0",
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
@@ -23,3 +23,54 @@ export interface TableSortModel {
23
23
  sortColDef: SortColDef | null;
24
24
  setSortColDef: (sortColDef: SortColDef | null) => void;
25
25
  }
26
+ export type TableFilterState = Record<string, ColFilterState>;
27
+ export type EditableTableFilterState = Record<string, FilterState>;
28
+ export interface ColFilterState {
29
+ editableState: FilterState;
30
+ label: string;
31
+ }
32
+ export interface AbstractFilterState {
33
+ enabled: boolean;
34
+ }
35
+ export declare const stringFilterSchemes: readonly ["contains", "startsWith", "endsWith"];
36
+ export type StringFilterScheme = (typeof stringFilterSchemes)[number];
37
+ export declare const stringFilterSchemeNames: Record<StringFilterScheme, string>;
38
+ export interface StringFilterState extends AbstractFilterState {
39
+ type: "string";
40
+ scheme: StringFilterScheme;
41
+ searchString: string;
42
+ }
43
+ export declare const numberFilterSchemes: readonly ["equals", "greaterThan", "lessThan", "greaterOrEqual", "lessOrEqual"];
44
+ export type NumberFilterScheme = (typeof numberFilterSchemes)[number];
45
+ export declare const numberFilterSchemeNames: Record<NumberFilterScheme, string>;
46
+ export interface NumberFilterState extends AbstractFilterState {
47
+ type: "number";
48
+ scheme: NumberFilterScheme;
49
+ numValue: number | null;
50
+ }
51
+ export declare const dateFilterSchemes: readonly ["startFrom", "endAt", "between"];
52
+ export type DateFilterScheme = (typeof dateFilterSchemes)[number];
53
+ export declare const dateFilterSchemeNames: Record<DateFilterScheme, string>;
54
+ export interface AbstractDateFilterState extends AbstractFilterState {
55
+ type: "date" | "datetime";
56
+ scheme: DateFilterScheme;
57
+ }
58
+ export interface StartDateFilterState extends AbstractDateFilterState {
59
+ scheme: "startFrom";
60
+ startDate: Date | null;
61
+ }
62
+ export interface EndDateFilterState extends AbstractDateFilterState {
63
+ scheme: "endAt";
64
+ endDate: Date | null;
65
+ }
66
+ export interface BetweenDatesFilterState extends AbstractDateFilterState {
67
+ scheme: "between";
68
+ startDate: Date | null;
69
+ endDate: Date | null;
70
+ }
71
+ export type DateFilterState = StartDateFilterState | EndDateFilterState | BetweenDatesFilterState;
72
+ export type FilterState = StringFilterState | NumberFilterState | DateFilterState;
73
+ export interface FilterModel {
74
+ tableFilterState: EditableTableFilterState;
75
+ setTableFilterState: (state: EditableTableFilterState) => void;
76
+ }
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
+ };
@@ -0,0 +1,3 @@
1
+ export declare const dateToInputStr: (date: Date) => string;
2
+ export declare const dateToDatetimeInputStr: (date: Date) => string;
3
+ export declare const datetimeInputStrToUtc: (datetimeStr: string) => string;
@@ -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"; };