@omegagrid/grid-core 0.11.33 → 0.11.34
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/dist/model/dateFilter.d.ts +28 -0
- package/dist/model/dateFilter.d.ts.map +1 -0
- package/dist/model/dateFilter.js +221 -0
- package/dist/model/dateFilter.js.map +1 -0
- package/dist/model/filterModel.d.ts +1 -4
- package/dist/model/filterModel.d.ts.map +1 -1
- package/dist/model/filterModel.js +9 -57
- package/dist/model/filterModel.js.map +1 -1
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/index.js +1 -0
- package/dist/model/index.js.map +1 -1
- package/dist/types.d.ts +17 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DateFilterGroups, DateFilterType } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* The time a value of a date column compares by: a Date, a serial date (the value of a date cell) or a text (an ISO
|
|
4
|
+
* date, a typed time); a time (type tm) by its time of day on the day of the serial date 0. Null for no value or a
|
|
5
|
+
* text that is none.
|
|
6
|
+
*/
|
|
7
|
+
export declare const toDateFilterTime: (v: unknown, type: DateFilterType) => number | null;
|
|
8
|
+
/**
|
|
9
|
+
* Parses a date filter expression into a disjunction of conjunctions of bounds (OR groups, each an AND-combined
|
|
10
|
+
* list of `>=` and `<` bounds, see {@link DateFilterGroups}). A literal means the interval it names, to the precision
|
|
11
|
+
* it is written in: a day (`6.11.2026`), a month (`11.2026`, `2026-11`), a year (`2026`), a day with a time of day
|
|
12
|
+
* (`6.11.2026 14:00`, a minute; `6.11.2026 14:00:30`, a second), a time of day alone for a time column (`9:05`).
|
|
13
|
+
*
|
|
14
|
+
* Supported syntax:
|
|
15
|
+
* - a bare literal, matched as the whole interval: `6.11.2026` is the whole day
|
|
16
|
+
* - operators `>`, `>=`, `<`, `<=`, `=`/`==`, `!=`/`<>` followed by a literal: `> 6.11.2026` starts the day after,
|
|
17
|
+
* `<= 6.11.2026` reaches to the end of the day
|
|
18
|
+
* - a range `a..b`, from the start of `a` to the end of `b`: `6.11.2026..20.11.2026`, `9:00..17:00`
|
|
19
|
+
* - `and` / `or` connectors (case-insensitive); without one, two bare literals are an OR (a list of days), a
|
|
20
|
+
* comparison narrows (AND)
|
|
21
|
+
*
|
|
22
|
+
* The dates are read in the format of the current locale, an ISO date in any. A literal that is no date or time, or
|
|
23
|
+
* not one of the column type (a day in a time column), makes its unit match nothing. Null when the expression holds
|
|
24
|
+
* no unit at all: the text is no date expression.
|
|
25
|
+
*/
|
|
26
|
+
export declare const parseDateExpression: (input: string, type: DateFilterType) => DateFilterGroups | null;
|
|
27
|
+
export declare const createDateMatcher: <TItem>(groups: DateFilterGroups, property: keyof TItem, type: DateFilterType) => (item: TItem) => boolean;
|
|
28
|
+
//# sourceMappingURL=dateFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateFilter.d.ts","sourceRoot":"","sources":["../../src/model/dateFilter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,gBAAgB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,OAAO,EAAE,MAAM,cAAc,KAAG,MAAM,GAAG,IAQ5E,CAAC;AAgIF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,EAAE,MAAM,cAAc,KAAG,gBAAgB,GAAC,IAoD1F,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,KAAK,EAAE,QAAQ,gBAAgB,EAAE,UAAU,MAAM,KAAK,EAAE,MAAM,cAAc,MAGrG,MAAM,KAAK,YAKnB,CAAC"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { dates, utils } from "@omegagrid/core";
|
|
2
|
+
import { getLocale } from "@omegagrid/localize";
|
|
3
|
+
import { addDays, addMilliseconds, addMinutes, addMonths, addSeconds, addYears } from "date-fns";
|
|
4
|
+
/**
|
|
5
|
+
* The time a value of a date column compares by: a Date, a serial date (the value of a date cell) or a text (an ISO
|
|
6
|
+
* date, a typed time); a time (type tm) by its time of day on the day of the serial date 0. Null for no value or a
|
|
7
|
+
* text that is none.
|
|
8
|
+
*/
|
|
9
|
+
export const toDateFilterTime = (v, type) => {
|
|
10
|
+
if (v == null || v === '')
|
|
11
|
+
return null;
|
|
12
|
+
let date;
|
|
13
|
+
if (v instanceof Date)
|
|
14
|
+
date = v;
|
|
15
|
+
else if (utils.isNumber(v))
|
|
16
|
+
date = dates.serialDateToDateTime(v);
|
|
17
|
+
else
|
|
18
|
+
date = type === 'tm' ? dates.parseTime(String(v), getLocale()) : dates.parseDateTime(String(v), getLocale());
|
|
19
|
+
if (!date || Number.isNaN(date.getTime()))
|
|
20
|
+
return null;
|
|
21
|
+
return type === 'tm' ? dates.timeOfDay(date).getTime() : date.getTime();
|
|
22
|
+
};
|
|
23
|
+
// a date: two or three numbers with a dot, slash or dash between them ('6.11.2026', '6. 11. 2026', '11/6/2026',
|
|
24
|
+
// '2026-11-06', '11.2026', '2026-11'); the parts are read by their format later
|
|
25
|
+
const DATE_TOKEN = '\\d{1,4}\\s*[./-]\\s*\\d{1,4}(?:\\s*[./-]\\s*\\d{1,4})?';
|
|
26
|
+
// a time of day: hours and minutes, optional seconds with an optional fraction
|
|
27
|
+
const TIME_TOKEN = '\\d{1,2}:\\d{1,2}(?::\\d{1,2}(?:[.,]\\d+)?)?';
|
|
28
|
+
const tokenize = (input) => {
|
|
29
|
+
// the 'T' of an ISO date and time ('2026-11-06T14:00') separates them the way a space does
|
|
30
|
+
input = input.replace(/(\d)T(\d)/g, '$1 $2');
|
|
31
|
+
const re = new RegExp(`(\\.\\.)` + // 1 range
|
|
32
|
+
`|(>=|<=|<>|!=|==|=|>|<)` + // 2 comparison operator
|
|
33
|
+
`|\\b(and|or)\\b` + // 3 connector
|
|
34
|
+
`|(${DATE_TOKEN})` + // 4 date
|
|
35
|
+
`|(${TIME_TOKEN})` + // 5 time
|
|
36
|
+
`|(?<!\\d|\\d[.:/-])(\\d{4})(?!\\d|[.:/-]\\d)`, // 6 year (not a part of a date; '2026..2027' are two years)
|
|
37
|
+
'gi');
|
|
38
|
+
const tokens = [];
|
|
39
|
+
let m;
|
|
40
|
+
while ((m = re.exec(input)) !== null) {
|
|
41
|
+
if (m[1] != null)
|
|
42
|
+
tokens.push({ kind: 'range' });
|
|
43
|
+
else if (m[2] != null) {
|
|
44
|
+
const op = m[2] === '==' ? '=' : m[2] === '<>' ? '!=' : m[2];
|
|
45
|
+
tokens.push({ kind: 'op', op: op });
|
|
46
|
+
}
|
|
47
|
+
else if (m[3] != null)
|
|
48
|
+
tokens.push({ kind: 'connector', connector: m[3].toLowerCase() });
|
|
49
|
+
else if (m[4] != null)
|
|
50
|
+
tokens.push({ kind: 'literal', literal: { date: m[4] } });
|
|
51
|
+
else if (m[5] != null) {
|
|
52
|
+
// a time right after a date belongs to it ('6.11.2026 14:00')
|
|
53
|
+
const last = tokens[tokens.length - 1];
|
|
54
|
+
if (last?.kind === 'literal' && last.literal.date && !last.literal.time)
|
|
55
|
+
last.literal.time = m[5];
|
|
56
|
+
else
|
|
57
|
+
tokens.push({ kind: 'literal', literal: { time: m[5] } });
|
|
58
|
+
}
|
|
59
|
+
else if (m[6] != null)
|
|
60
|
+
tokens.push({ kind: 'literal', literal: { year: m[6] } });
|
|
61
|
+
}
|
|
62
|
+
return tokens;
|
|
63
|
+
};
|
|
64
|
+
const MONTH_FIRST = /^(\d{1,2})\s*[./]\s*(\d{4})$/; // '11.2026', '11/2026'
|
|
65
|
+
const YEAR_FIRST = /^(\d{4})\s*[-/.]\s*(\d{1,2})$/; // '2026-11', '2026/11'
|
|
66
|
+
const monthInterval = (year, month) => {
|
|
67
|
+
if (month < 1 || month > 12)
|
|
68
|
+
return null;
|
|
69
|
+
const start = new Date(year, month - 1, 1);
|
|
70
|
+
return { start, end: addMonths(start, 1) };
|
|
71
|
+
};
|
|
72
|
+
// the interval of a time of day by the precision it is written in: a minute, a second or a millisecond
|
|
73
|
+
const timePrecisionEnd = (start, time) => {
|
|
74
|
+
const parts = time.split(':');
|
|
75
|
+
if (parts.length < 3)
|
|
76
|
+
return addMinutes(start, 1);
|
|
77
|
+
return /[.,]/.test(parts[2]) ? addMilliseconds(start, 1) : addSeconds(start, 1);
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The interval a literal names for a column type: a year, a month, a day, or a time of day to the precision it is
|
|
81
|
+
* written in. A time of day on its own counts for a time column only, a day or a longer span for a date column only.
|
|
82
|
+
* Null when the literal is no date or time, or not one of the type.
|
|
83
|
+
*/
|
|
84
|
+
const literalInterval = (literal, type) => {
|
|
85
|
+
const locale = getLocale();
|
|
86
|
+
if (type === 'tm') {
|
|
87
|
+
// a time of day, also the time of day of a date and time
|
|
88
|
+
const text = literal.time ? (literal.date ? `${literal.date} ${literal.time}` : literal.time) : null;
|
|
89
|
+
if (!text)
|
|
90
|
+
return null;
|
|
91
|
+
const start = dates.parseTime(text, locale);
|
|
92
|
+
return start ? { start, end: timePrecisionEnd(start, literal.time) } : null;
|
|
93
|
+
}
|
|
94
|
+
if (literal.year) {
|
|
95
|
+
const start = new Date(Number(literal.year), 0, 1);
|
|
96
|
+
return { start, end: addYears(start, 1) };
|
|
97
|
+
}
|
|
98
|
+
if (!literal.date)
|
|
99
|
+
return null;
|
|
100
|
+
const monthFirst = MONTH_FIRST.exec(literal.date);
|
|
101
|
+
if (monthFirst)
|
|
102
|
+
return monthInterval(Number(monthFirst[2]), Number(monthFirst[1]));
|
|
103
|
+
const yearFirst = YEAR_FIRST.exec(literal.date);
|
|
104
|
+
if (yearFirst)
|
|
105
|
+
return monthInterval(Number(yearFirst[1]), Number(yearFirst[2]));
|
|
106
|
+
const start = dates.parseDateTime(literal.time ? `${literal.date} ${literal.time}` : literal.date, locale);
|
|
107
|
+
if (!start)
|
|
108
|
+
return null;
|
|
109
|
+
return { start, end: literal.time ? timePrecisionEnd(start, literal.time) : addDays(start, 1) };
|
|
110
|
+
};
|
|
111
|
+
const NOTHING = [];
|
|
112
|
+
// a literal means the interval it names: '= day' is the whole day, '> day' starts the day after
|
|
113
|
+
const compareUnit = (op, interval) => {
|
|
114
|
+
const exact = op.op === '=';
|
|
115
|
+
if (!interval)
|
|
116
|
+
return { groups: NOTHING, exact };
|
|
117
|
+
const { start, end } = interval;
|
|
118
|
+
switch (op.op) {
|
|
119
|
+
case '=': return { groups: [[{ op: '>=', value: start }, { op: '<', value: end }]], exact };
|
|
120
|
+
case '!=': return { groups: [[{ op: '<', value: start }], [{ op: '>=', value: end }]], exact };
|
|
121
|
+
case '>': return { groups: [[{ op: '>=', value: end }]], exact };
|
|
122
|
+
case '>=': return { groups: [[{ op: '>=', value: start }]], exact };
|
|
123
|
+
case '<': return { groups: [[{ op: '<', value: start }]], exact };
|
|
124
|
+
case '<=': return { groups: [[{ op: '<', value: end }]], exact };
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const rangeUnit = (from, to) => {
|
|
128
|
+
if (!from || !to)
|
|
129
|
+
return { groups: NOTHING, exact: false };
|
|
130
|
+
return { groups: [[{ op: '>=', value: from.start }, { op: '<', value: to.end }]], exact: false };
|
|
131
|
+
};
|
|
132
|
+
// the AND of two expressions in their OR groups: every group of one with every group of the other
|
|
133
|
+
const andGroups = (a, b) => {
|
|
134
|
+
const result = [];
|
|
135
|
+
a.forEach(ga => b.forEach(gb => result.push([...ga, ...gb])));
|
|
136
|
+
return result;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Parses a date filter expression into a disjunction of conjunctions of bounds (OR groups, each an AND-combined
|
|
140
|
+
* list of `>=` and `<` bounds, see {@link DateFilterGroups}). A literal means the interval it names, to the precision
|
|
141
|
+
* it is written in: a day (`6.11.2026`), a month (`11.2026`, `2026-11`), a year (`2026`), a day with a time of day
|
|
142
|
+
* (`6.11.2026 14:00`, a minute; `6.11.2026 14:00:30`, a second), a time of day alone for a time column (`9:05`).
|
|
143
|
+
*
|
|
144
|
+
* Supported syntax:
|
|
145
|
+
* - a bare literal, matched as the whole interval: `6.11.2026` is the whole day
|
|
146
|
+
* - operators `>`, `>=`, `<`, `<=`, `=`/`==`, `!=`/`<>` followed by a literal: `> 6.11.2026` starts the day after,
|
|
147
|
+
* `<= 6.11.2026` reaches to the end of the day
|
|
148
|
+
* - a range `a..b`, from the start of `a` to the end of `b`: `6.11.2026..20.11.2026`, `9:00..17:00`
|
|
149
|
+
* - `and` / `or` connectors (case-insensitive); without one, two bare literals are an OR (a list of days), a
|
|
150
|
+
* comparison narrows (AND)
|
|
151
|
+
*
|
|
152
|
+
* The dates are read in the format of the current locale, an ISO date in any. A literal that is no date or time, or
|
|
153
|
+
* not one of the column type (a day in a time column), makes its unit match nothing. Null when the expression holds
|
|
154
|
+
* no unit at all: the text is no date expression.
|
|
155
|
+
*/
|
|
156
|
+
export const parseDateExpression = (input, type) => {
|
|
157
|
+
const tokens = tokenize(input ?? '');
|
|
158
|
+
const units = [];
|
|
159
|
+
let pending = null;
|
|
160
|
+
const interval = (i) => {
|
|
161
|
+
const t = tokens[i];
|
|
162
|
+
return t?.kind === 'literal' ? literalInterval(t.literal, type) : null;
|
|
163
|
+
};
|
|
164
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
165
|
+
const t = tokens[i];
|
|
166
|
+
if (t.kind === 'connector') {
|
|
167
|
+
pending = t.connector;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
let unit = null;
|
|
171
|
+
if (t.kind === 'op') {
|
|
172
|
+
if (tokens[i + 1]?.kind !== 'literal')
|
|
173
|
+
continue; // an operator without a value is skipped
|
|
174
|
+
unit = compareUnit(t, interval(i + 1));
|
|
175
|
+
i += 1;
|
|
176
|
+
}
|
|
177
|
+
else if (t.kind === 'literal') {
|
|
178
|
+
if (tokens[i + 1]?.kind === 'range') {
|
|
179
|
+
unit = rangeUnit(interval(i), tokens[i + 2]?.kind === 'literal' ? interval(i + 2) : null);
|
|
180
|
+
i += 2;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
unit = compareUnit({ kind: 'op', op: '=' }, interval(i));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
continue; // a stray range operator
|
|
188
|
+
}
|
|
189
|
+
units.push({ unit, connector: pending });
|
|
190
|
+
pending = null;
|
|
191
|
+
}
|
|
192
|
+
if (units.length === 0)
|
|
193
|
+
return null;
|
|
194
|
+
// an explicit connector, otherwise OR between two bare literals (a list of days) and AND elsewhere
|
|
195
|
+
const groups = [];
|
|
196
|
+
let current = units[0].unit.groups;
|
|
197
|
+
for (let i = 1; i < units.length; i++) {
|
|
198
|
+
const { unit, connector } = units[i];
|
|
199
|
+
const implicit = units[i - 1].unit.exact && unit.exact ? 'or' : 'and';
|
|
200
|
+
if ((connector ?? implicit) === 'or') {
|
|
201
|
+
groups.push(...current);
|
|
202
|
+
current = unit.groups;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
current = andGroups(current, unit.groups);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
groups.push(...current);
|
|
209
|
+
return groups;
|
|
210
|
+
};
|
|
211
|
+
export const createDateMatcher = (groups, property, type) => {
|
|
212
|
+
// the bounds compare by their times: a time of day lies on the day of the serial date 0 the way the values do
|
|
213
|
+
const bounds = groups.map(group => group.map(b => ({ op: b.op, time: b.value.getTime() })));
|
|
214
|
+
return (item) => {
|
|
215
|
+
const v = toDateFilterTime(item[property], type);
|
|
216
|
+
if (v === null)
|
|
217
|
+
return false;
|
|
218
|
+
return bounds.some(group => group.every(b => b.op === '>=' ? v >= b.time : v < b.time));
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=dateFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateFilter.js","sourceRoot":"","sources":["../../src/model/dateFilter.ts"],"names":[],"mappings":"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","sourcesContent":["import { dates, utils } from \"@omegagrid/core\";\nimport { getLocale } from \"@omegagrid/localize\";\nimport { addDays, addMilliseconds, addMinutes, addMonths, addSeconds, addYears } from \"date-fns\";\nimport { DateFilterBound, DateFilterGroups, DateFilterType } from \"../types\";\n\n/**\n * The time a value of a date column compares by: a Date, a serial date (the value of a date cell) or a text (an ISO\n * date, a typed time); a time (type tm) by its time of day on the day of the serial date 0. Null for no value or a\n * text that is none.\n */\nexport const toDateFilterTime = (v: unknown, type: DateFilterType): number | null => {\n\tif (v == null || v === '') return null;\n\tlet date: Date|null;\n\tif (v instanceof Date) date = v;\n\telse if (utils.isNumber(v)) date = dates.serialDateToDateTime(v as number);\n\telse date = type === 'tm' ? dates.parseTime(String(v), getLocale()) : dates.parseDateTime(String(v), getLocale());\n\tif (!date || Number.isNaN(date.getTime())) return null;\n\treturn type === 'tm' ? dates.timeOfDay(date).getTime() : date.getTime();\n};\n\n/** The interval a date literal names: from its start to its end, the end excluded */\ntype Interval = { start: Date, end: Date };\n\ntype Literal = { date?: string, time?: string, year?: string };\n\ntype Token =\n\t| { kind: 'range' }\n\t| { kind: 'op', op: '=' | '!=' | '<' | '<=' | '>' | '>=' }\n\t| { kind: 'connector', connector: 'and' | 'or' }\n\t| { kind: 'literal', literal: Literal };\n\n// a date: two or three numbers with a dot, slash or dash between them ('6.11.2026', '6. 11. 2026', '11/6/2026',\n// '2026-11-06', '11.2026', '2026-11'); the parts are read by their format later\nconst DATE_TOKEN = '\\\\d{1,4}\\\\s*[./-]\\\\s*\\\\d{1,4}(?:\\\\s*[./-]\\\\s*\\\\d{1,4})?';\n// a time of day: hours and minutes, optional seconds with an optional fraction\nconst TIME_TOKEN = '\\\\d{1,2}:\\\\d{1,2}(?::\\\\d{1,2}(?:[.,]\\\\d+)?)?';\n\nconst tokenize = (input: string): Token[] => {\n\t// the 'T' of an ISO date and time ('2026-11-06T14:00') separates them the way a space does\n\tinput = input.replace(/(\\d)T(\\d)/g, '$1 $2');\n\tconst re = new RegExp(\n\t\t`(\\\\.\\\\.)` + // 1 range\n\t\t`|(>=|<=|<>|!=|==|=|>|<)` + // 2 comparison operator\n\t\t`|\\\\b(and|or)\\\\b` + // 3 connector\n\t\t`|(${DATE_TOKEN})` + // 4 date\n\t\t`|(${TIME_TOKEN})` + // 5 time\n\t\t`|(?<!\\\\d|\\\\d[.:/-])(\\\\d{4})(?!\\\\d|[.:/-]\\\\d)`, // 6 year (not a part of a date; '2026..2027' are two years)\n\t\t'gi'\n\t);\n\tconst tokens: Token[] = [];\n\tlet m: RegExpExecArray | null;\n\twhile ((m = re.exec(input)) !== null) {\n\t\tif (m[1] != null) tokens.push({ kind: 'range' });\n\t\telse if (m[2] != null) {\n\t\t\tconst op = m[2] === '==' ? '=' : m[2] === '<>' ? '!=' : m[2];\n\t\t\ttokens.push({ kind: 'op', op: op as '=' | '!=' | '<' | '<=' | '>' | '>=' });\n\t\t}\n\t\telse if (m[3] != null) tokens.push({ kind: 'connector', connector: m[3].toLowerCase() as 'and' | 'or' });\n\t\telse if (m[4] != null) tokens.push({ kind: 'literal', literal: { date: m[4] } });\n\t\telse if (m[5] != null) {\n\t\t\t// a time right after a date belongs to it ('6.11.2026 14:00')\n\t\t\tconst last = tokens[tokens.length - 1];\n\t\t\tif (last?.kind === 'literal' && last.literal.date && !last.literal.time) last.literal.time = m[5];\n\t\t\telse tokens.push({ kind: 'literal', literal: { time: m[5] } });\n\t\t}\n\t\telse if (m[6] != null) tokens.push({ kind: 'literal', literal: { year: m[6] } });\n\t}\n\treturn tokens;\n};\n\nconst MONTH_FIRST = /^(\\d{1,2})\\s*[./]\\s*(\\d{4})$/; // '11.2026', '11/2026'\nconst YEAR_FIRST = /^(\\d{4})\\s*[-/.]\\s*(\\d{1,2})$/; // '2026-11', '2026/11'\n\nconst monthInterval = (year: number, month: number): Interval|null => {\n\tif (month < 1 || month > 12) return null;\n\tconst start = new Date(year, month - 1, 1);\n\treturn { start, end: addMonths(start, 1) };\n};\n\n// the interval of a time of day by the precision it is written in: a minute, a second or a millisecond\nconst timePrecisionEnd = (start: Date, time: string) => {\n\tconst parts = time.split(':');\n\tif (parts.length < 3) return addMinutes(start, 1);\n\treturn /[.,]/.test(parts[2]) ? addMilliseconds(start, 1) : addSeconds(start, 1);\n};\n\n/**\n * The interval a literal names for a column type: a year, a month, a day, or a time of day to the precision it is\n * written in. A time of day on its own counts for a time column only, a day or a longer span for a date column only.\n * Null when the literal is no date or time, or not one of the type.\n */\nconst literalInterval = (literal: Literal, type: DateFilterType): Interval|null => {\n\tconst locale = getLocale();\n\tif (type === 'tm') {\n\t\t// a time of day, also the time of day of a date and time\n\t\tconst text = literal.time ? (literal.date ? `${literal.date} ${literal.time}` : literal.time) : null;\n\t\tif (!text) return null;\n\t\tconst start = dates.parseTime(text, locale);\n\t\treturn start ? { start, end: timePrecisionEnd(start, literal.time) } : null;\n\t}\n\tif (literal.year) {\n\t\tconst start = new Date(Number(literal.year), 0, 1);\n\t\treturn { start, end: addYears(start, 1) };\n\t}\n\tif (!literal.date) return null;\n\tconst monthFirst = MONTH_FIRST.exec(literal.date);\n\tif (monthFirst) return monthInterval(Number(monthFirst[2]), Number(monthFirst[1]));\n\tconst yearFirst = YEAR_FIRST.exec(literal.date);\n\tif (yearFirst) return monthInterval(Number(yearFirst[1]), Number(yearFirst[2]));\n\tconst start = dates.parseDateTime(literal.time ? `${literal.date} ${literal.time}` : literal.date, locale);\n\tif (!start) return null;\n\treturn { start, end: literal.time ? timePrecisionEnd(start, literal.time) : addDays(start, 1) };\n};\n\n/** A unit of the expression: a comparison or a range, as OR groups of its bounds; no group matches nothing */\ntype Unit = { groups: DateFilterGroups, exact: boolean };\n\nconst NOTHING: DateFilterGroups = [];\n\n// a literal means the interval it names: '= day' is the whole day, '> day' starts the day after\nconst compareUnit = (op: Token & { kind: 'op' }, interval: Interval|null): Unit => {\n\tconst exact = op.op === '=';\n\tif (!interval) return { groups: NOTHING, exact };\n\tconst { start, end } = interval;\n\tswitch (op.op) {\n\t\tcase '=': return { groups: [[{ op: '>=', value: start }, { op: '<', value: end }]], exact };\n\t\tcase '!=': return { groups: [[{ op: '<', value: start }], [{ op: '>=', value: end }]], exact };\n\t\tcase '>': return { groups: [[{ op: '>=', value: end }]], exact };\n\t\tcase '>=': return { groups: [[{ op: '>=', value: start }]], exact };\n\t\tcase '<': return { groups: [[{ op: '<', value: start }]], exact };\n\t\tcase '<=': return { groups: [[{ op: '<', value: end }]], exact };\n\t}\n};\n\nconst rangeUnit = (from: Interval|null, to: Interval|null): Unit => {\n\tif (!from || !to) return { groups: NOTHING, exact: false };\n\treturn { groups: [[{ op: '>=', value: from.start }, { op: '<', value: to.end }]], exact: false };\n};\n\n// the AND of two expressions in their OR groups: every group of one with every group of the other\nconst andGroups = (a: DateFilterGroups, b: DateFilterGroups): DateFilterGroups => {\n\tconst result: DateFilterBound[][] = [];\n\ta.forEach(ga => b.forEach(gb => result.push([...ga, ...gb])));\n\treturn result;\n};\n\n/**\n * Parses a date filter expression into a disjunction of conjunctions of bounds (OR groups, each an AND-combined\n * list of `>=` and `<` bounds, see {@link DateFilterGroups}). A literal means the interval it names, to the precision\n * it is written in: a day (`6.11.2026`), a month (`11.2026`, `2026-11`), a year (`2026`), a day with a time of day\n * (`6.11.2026 14:00`, a minute; `6.11.2026 14:00:30`, a second), a time of day alone for a time column (`9:05`).\n *\n * Supported syntax:\n * - a bare literal, matched as the whole interval: `6.11.2026` is the whole day\n * - operators `>`, `>=`, `<`, `<=`, `=`/`==`, `!=`/`<>` followed by a literal: `> 6.11.2026` starts the day after,\n * `<= 6.11.2026` reaches to the end of the day\n * - a range `a..b`, from the start of `a` to the end of `b`: `6.11.2026..20.11.2026`, `9:00..17:00`\n * - `and` / `or` connectors (case-insensitive); without one, two bare literals are an OR (a list of days), a\n * comparison narrows (AND)\n *\n * The dates are read in the format of the current locale, an ISO date in any. A literal that is no date or time, or\n * not one of the column type (a day in a time column), makes its unit match nothing. Null when the expression holds\n * no unit at all: the text is no date expression.\n */\nexport const parseDateExpression = (input: string, type: DateFilterType): DateFilterGroups|null => {\n\tconst tokens = tokenize(input ?? '');\n\tconst units: { unit: Unit, connector: 'and' | 'or' | null }[] = [];\n\tlet pending: 'and' | 'or' | null = null;\n\n\tconst interval = (i: number) => {\n\t\tconst t = tokens[i];\n\t\treturn t?.kind === 'literal' ? literalInterval(t.literal, type) : null;\n\t};\n\n\tfor (let i = 0; i < tokens.length; i++) {\n\t\tconst t = tokens[i];\n\t\tif (t.kind === 'connector') {\n\t\t\tpending = t.connector;\n\t\t\tcontinue;\n\t\t}\n\t\tlet unit: Unit|null = null;\n\t\tif (t.kind === 'op') {\n\t\t\tif (tokens[i + 1]?.kind !== 'literal') continue; // an operator without a value is skipped\n\t\t\tunit = compareUnit(t, interval(i + 1));\n\t\t\ti += 1;\n\t\t} else if (t.kind === 'literal') {\n\t\t\tif (tokens[i + 1]?.kind === 'range') {\n\t\t\t\tunit = rangeUnit(interval(i), tokens[i + 2]?.kind === 'literal' ? interval(i + 2) : null);\n\t\t\t\ti += 2;\n\t\t\t} else {\n\t\t\t\tunit = compareUnit({ kind: 'op', op: '=' }, interval(i));\n\t\t\t}\n\t\t} else {\n\t\t\tcontinue; // a stray range operator\n\t\t}\n\t\tunits.push({ unit, connector: pending });\n\t\tpending = null;\n\t}\n\n\tif (units.length === 0) return null;\n\n\t// an explicit connector, otherwise OR between two bare literals (a list of days) and AND elsewhere\n\tconst groups: DateFilterGroups = [];\n\tlet current: DateFilterGroups = units[0].unit.groups;\n\tfor (let i = 1; i < units.length; i++) {\n\t\tconst { unit, connector } = units[i];\n\t\tconst implicit = units[i - 1].unit.exact && unit.exact ? 'or' : 'and';\n\t\tif ((connector ?? implicit) === 'or') {\n\t\t\tgroups.push(...current);\n\t\t\tcurrent = unit.groups;\n\t\t} else {\n\t\t\tcurrent = andGroups(current, unit.groups);\n\t\t}\n\t}\n\tgroups.push(...current);\n\treturn groups;\n};\n\nexport const createDateMatcher = <TItem>(groups: DateFilterGroups, property: keyof TItem, type: DateFilterType) => {\n\t// the bounds compare by their times: a time of day lies on the day of the serial date 0 the way the values do\n\tconst bounds = groups.map(group => group.map(b => ({ op: b.op, time: b.value.getTime() })));\n\treturn (item: TItem) => {\n\t\tconst v = toDateFilterTime(item[property], type);\n\t\tif (v === null) return false;\n\t\treturn bounds.some(group => group.every(b => b.op === '>=' ? v >= b.time : v < b.time));\n\t};\n};\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { KeyValue } from "@omegagrid/core";
|
|
2
2
|
import { CellModel } from "./cellModel";
|
|
3
3
|
import { GridModel } from "./gridModel";
|
|
4
|
-
import { CellType,
|
|
4
|
+
import { CellType, FilterValue, NumericFilterGroups } from "../types";
|
|
5
5
|
export type FilterMatcher = (cell: CellModel) => boolean;
|
|
6
6
|
export type FilterSettings = {
|
|
7
7
|
c: number;
|
|
@@ -11,9 +11,6 @@ export declare const createTextMatcher: <TItem>(term: string, property: keyof TI
|
|
|
11
11
|
export declare const createBoolMatcher: <TItem>(term: boolean, property: keyof TItem) => (item: TItem) => boolean;
|
|
12
12
|
export declare const createMultiMatcher: <TItem>(term: KeyValue[], property: keyof TItem) => (item: TItem) => boolean;
|
|
13
13
|
export declare const createMultiMultiMatcher: <TItem>(_term: KeyValue[], _property: keyof TItem) => (_item: TItem) => boolean;
|
|
14
|
-
export declare const isFilterRange: (term: FilterValue) => term is FilterRange;
|
|
15
|
-
export declare const isFilterRangeEmpty: (term: FilterRange) => boolean;
|
|
16
|
-
export declare const createRangeMatcher: <TItem>(term: FilterRange, property: keyof TItem, type: "d" | "dt" | "tm") => (item: TItem) => boolean;
|
|
17
14
|
/** True when the whole (trimmed) input is a single bare number, e.g. `42`, `-3.5`, `1,5`. */
|
|
18
15
|
export declare const isSingleNumber: (input: string) => boolean;
|
|
19
16
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterModel.d.ts","sourceRoot":"","sources":["../../src/model/filterModel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"filterModel.d.ts","sourceRoot":"","sources":["../../src/model/filterModel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAoB,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAuB,mBAAmB,EAAyB,MAAM,UAAU,CAAC;AAElH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC;AAEzD,MAAM,MAAM,cAAc,GAAG;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,WAAW,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,KAAK,EAAE,MAAM,MAAM,EAAE,UAAU,MAAM,KAAK,MAEnE,MAAM,KAAK,YAInB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,KAAK,EAAE,MAAM,OAAO,EAAE,UAAU,MAAM,KAAK,MACpE,MAAM,KAAK,YACnB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,KAAK,EAAE,MAAM,QAAQ,EAAE,EAAE,UAAU,MAAM,KAAK,MAExE,MAAM,KAAK,YAGnB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,KAAK,EAAE,OAAO,QAAQ,EAAE,EAAE,WAAW,MAAM,KAAK,MAC/E,OAAO,KAAK,YACpB,CAAC;AAMF,6FAA6F;AAC7F,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,YAAoD,CAAC;AAEjG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,KAAG,mBA8CtD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,KAAK,EAAE,QAAQ,mBAAmB,EAAE,UAAU,MAAM,KAAK,MAWrF,MAAM,KAAK,YASnB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,QAAQ,EAAE,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,iCAsB7F,CAAA;AAED,qBAAa,WAAY,SAAQ,KAAK;;CAIrC;AAED,qBAAa,WAAY,SAAQ,WAAW;aAkB1B,KAAK,EAAE,SAAS;IAhB1B,MAAM,UAAS;IAEtB,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAAwB;IACzC,IAAI,QAAQ,IACI,cAAc,EAAE,GAAC,IAAI,CADG;IACxC,IAAI,QAAQ,CAAC,CAAC,EAAE,cAAc,EAAE,GAAC,IAAI,EAQpC;gBAGgB,KAAK,EAAE,SAAS,EAChC,QAAQ,GAAE,cAAc,EAAE,GAAC,IAAW;IAMvC;;;OAGG;IACH,GAAG,CAAC,CAAC,EAAE,MAAM;IAIb;;;;OAIG;IACH,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,MAAM,UAAQ;IAUlD,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,aAAa,UAAO;IA6BnD,WAAW,CAAC,aAAa,UAAO;IAoDhC,WAAW,CAAC,aAAa,UAAO;IAOhC,OAAO,CAAC,YAAY;CAKpB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { log, tree, utils } from "@omegagrid/core";
|
|
2
|
+
import { createDateMatcher, parseDateExpression } from "./dateFilter";
|
|
3
3
|
export const createTextMatcher = (term, property) => {
|
|
4
4
|
const regex = new RegExp(`${utils.escapeRegExp(utils.removeAccents(term))}`, 'ig');
|
|
5
5
|
return (item) => {
|
|
@@ -19,50 +19,6 @@ export const createMultiMatcher = (term, property) => {
|
|
|
19
19
|
export const createMultiMultiMatcher = (_term, _property) => {
|
|
20
20
|
return (_item) => false;
|
|
21
21
|
};
|
|
22
|
-
export const isFilterRange = (term) => !!term && typeof term === 'object' && !Array.isArray(term) && term.kind === 'range';
|
|
23
|
-
export const isFilterRangeEmpty = (term) => (term.from == null || term.from === '') && (term.to == null || term.to === '');
|
|
24
|
-
/**
|
|
25
|
-
* The time a bound or a value of a range filter compares by: a Date, a serial date (the value of a date cell) or a text
|
|
26
|
-
* (an ISO date, a time typed into the popup); a time (type tm) by its time of day on the day of the serial date 0.
|
|
27
|
-
* Null for no value or a text that is none.
|
|
28
|
-
*/
|
|
29
|
-
const toRangeTime = (v, type) => {
|
|
30
|
-
if (v == null || v === '')
|
|
31
|
-
return null;
|
|
32
|
-
let date;
|
|
33
|
-
if (v instanceof Date)
|
|
34
|
-
date = v;
|
|
35
|
-
else if (utils.isNumber(v))
|
|
36
|
-
date = dates.serialDateToDateTime(v);
|
|
37
|
-
else
|
|
38
|
-
date = type === 'tm' ? dates.parseTime(String(v), getLocale()) : dates.parseDateTime(String(v), getLocale());
|
|
39
|
-
if (!date || Number.isNaN(date.getTime()))
|
|
40
|
-
return null;
|
|
41
|
-
return type === 'tm' ? dates.timeOfDay(date).getTime() : date.getTime();
|
|
42
|
-
};
|
|
43
|
-
const hasBound = (bound) => bound != null && bound !== '';
|
|
44
|
-
export const createRangeMatcher = (term, property, type) => {
|
|
45
|
-
const from = toRangeTime(term.from, type);
|
|
46
|
-
let to = toRangeTime(term.to, type);
|
|
47
|
-
// a bound in no form of the type ('abc' as a time) matches nothing rather than everything
|
|
48
|
-
const invalidBound = (hasBound(term.from) && from === null) || (hasBound(term.to) && to === null);
|
|
49
|
-
// a day picked as the upper bound of a date type reaches to the end of that day
|
|
50
|
-
// TODO: remove dt, when time picker is implemented
|
|
51
|
-
if (to !== null && (type === 'd' || type === 'dt'))
|
|
52
|
-
to += 24 * 60 * 60 * 1000 - 1;
|
|
53
|
-
return (item) => {
|
|
54
|
-
if (invalidBound)
|
|
55
|
-
return false;
|
|
56
|
-
const v = toRangeTime(item[property], type);
|
|
57
|
-
if (v === null)
|
|
58
|
-
return false;
|
|
59
|
-
if (from !== null && v < from)
|
|
60
|
-
return false;
|
|
61
|
-
if (to !== null && v > to)
|
|
62
|
-
return false;
|
|
63
|
-
return true;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
22
|
// number token: optional sign, digits, optional decimal part using '.' or ',' as separator
|
|
67
23
|
const NUM_TOKEN = '[-+]?\\d+(?:[.,]\\d+)?';
|
|
68
24
|
const toClauseNumber = (t) => Number(t.replace(',', '.'));
|
|
@@ -162,9 +118,12 @@ export const createNumericMatcher = (groups, property) => {
|
|
|
162
118
|
};
|
|
163
119
|
export const createCellMatcher = (type, term, property) => {
|
|
164
120
|
property = property ?? 'value';
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
121
|
+
if (type === 'd' || type === 'dt' || type === 'tm') {
|
|
122
|
+
// a date expression ('6.11.2026', '6.11.2026..20.11.2026', '> 11.2026'), a text that is none searches the shown text
|
|
123
|
+
const groups = parseDateExpression((term?.toString()) ?? '', type);
|
|
124
|
+
if (groups)
|
|
125
|
+
return createDateMatcher(groups, property, type);
|
|
126
|
+
return createTextMatcher((term?.toString()), 'formattedValue');
|
|
168
127
|
}
|
|
169
128
|
if (type === 'n') {
|
|
170
129
|
const str = (term?.toString()) ?? '';
|
|
@@ -184,12 +143,6 @@ export const createCellMatcher = (type, term, property) => {
|
|
|
184
143
|
return createTextMatcher((term?.toString()), 'formattedValue');
|
|
185
144
|
else if (type === 'm' && Array.isArray(term))
|
|
186
145
|
return createMultiMultiMatcher(term, property);
|
|
187
|
-
else if (type === 'd')
|
|
188
|
-
return createTextMatcher((term?.toString()), 'formattedValue');
|
|
189
|
-
else if (type === 'dt')
|
|
190
|
-
return createTextMatcher((term?.toString()), 'formattedValue');
|
|
191
|
-
else if (type === 'tm')
|
|
192
|
-
return createTextMatcher((term?.toString()), 'formattedValue');
|
|
193
146
|
// text search in the value must not see the quote prefix, a custom property is kept as is
|
|
194
147
|
return createTextMatcher((term?.toString()), property === 'value' ? 'plainValue' : property);
|
|
195
148
|
};
|
|
@@ -242,8 +195,7 @@ export class FilterModel extends EventTarget {
|
|
|
242
195
|
}
|
|
243
196
|
filter(filter, dispatchEvent = true) {
|
|
244
197
|
const filterSetting = this.get(filter.c);
|
|
245
|
-
const empty = filter.term === null || filter.term === ''
|
|
246
|
-
|| (isFilterRange(filter.term) && isFilterRangeEmpty(filter.term));
|
|
198
|
+
const empty = filter.term === null || filter.term === '';
|
|
247
199
|
if (filterSetting && empty) {
|
|
248
200
|
// remove; splice shifts the following slots, so the map must be rebuilt
|
|
249
201
|
this.settings.splice(this.colMap.get(filter.c), 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterModel.js","sourceRoot":"","sources":["../../src/model/filterModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyValue, dates, log, tree, utils } from \"@omegagrid/core\";\nimport { getLocale } from \"@omegagrid/localize\";\nimport { CellModel } from \"./cellModel\";\nimport { GridModel } from \"./gridModel\";\nimport { RowModel } from \"./rowModel\";\nimport { FilterOptions } from \"./options\";\nimport { CellType, FilterRange, FilterValue, NumericFilterClause, NumericFilterGroups, NumericFilterOperator } from \"../types\";\n\nexport type FilterMatcher = (cell: CellModel) => boolean;\n\nexport type FilterSettings = {\n\tc: number;\n\tterm: FilterValue;\n};\n\nexport const createTextMatcher = <TItem>(term: string, property: keyof TItem) => {\n\tconst regex = new RegExp(`${utils.escapeRegExp(utils.removeAccents(term))}`, 'ig');\n\treturn (item: TItem) => {\n\t\tregex.lastIndex = 0;\n\t\treturn regex.test(utils.removeAccents((item[property] ?? \"\").toString()));\n\t}\n};\n\nexport const createBoolMatcher = <TItem>(term: boolean, property: keyof TItem) => {\n\treturn (item: TItem) => !!item[property] === term;\n};\n\nexport const createMultiMatcher = <TItem>(term: KeyValue[], property: keyof TItem) => {\n\tconst keys = term.map(t => t.key?.toString());\n\treturn (item: TItem) => {\n\t\treturn item[property] == null ? false : keys.includes(item[property].toString());\n\t};\n};\n\nexport const createMultiMultiMatcher = <TItem>(_term: KeyValue[], _property: keyof TItem) => {\n\treturn (_item: TItem) => false;\n};\n\nexport const isFilterRange = (term: FilterValue): term is FilterRange =>\n\t!!term && typeof term === 'object' && !Array.isArray(term) && (term as FilterRange).kind === 'range';\n\nexport const isFilterRangeEmpty = (term: FilterRange) =>\n\t(term.from == null || term.from === '') && (term.to == null || term.to === '');\n\n/**\n * The time a bound or a value of a range filter compares by: a Date, a serial date (the value of a date cell) or a text\n * (an ISO date, a time typed into the popup); a time (type tm) by its time of day on the day of the serial date 0.\n * Null for no value or a text that is none.\n */\nconst toRangeTime = (v: unknown, type: 'd'|'dt'|'tm'): number | null => {\n\tif (v == null || v === '') return null;\n\tlet date: Date|null;\n\tif (v instanceof Date) date = v;\n\telse if (utils.isNumber(v)) date = dates.serialDateToDateTime(v as number);\n\telse date = type === 'tm' ? dates.parseTime(String(v), getLocale()) : dates.parseDateTime(String(v), getLocale());\n\tif (!date || Number.isNaN(date.getTime())) return null;\n\treturn type === 'tm' ? dates.timeOfDay(date).getTime() : date.getTime();\n};\n\nconst hasBound = (bound: unknown) => bound != null && bound !== '';\n\nexport const createRangeMatcher = <TItem>(term: FilterRange, property: keyof TItem, type: 'd'|'dt'|'tm') => {\n\tconst from = toRangeTime(term.from, type);\n\tlet to = toRangeTime(term.to, type);\n\t// a bound in no form of the type ('abc' as a time) matches nothing rather than everything\n\tconst invalidBound = (hasBound(term.from) && from === null) || (hasBound(term.to) && to === null);\n\t// a day picked as the upper bound of a date type reaches to the end of that day\n\t// TODO: remove dt, when time picker is implemented\n\tif (to !== null && (type === 'd' || type === 'dt')) to += 24 * 60 * 60 * 1000 - 1;\n\n\treturn (item: TItem) => {\n\t\tif (invalidBound) return false;\n\t\tconst v = toRangeTime(item[property], type);\n\t\tif (v === null) return false;\n\t\tif (from !== null && v < from) return false;\n\t\tif (to !== null && v > to) return false;\n\t\treturn true;\n\t};\n};\n\n// number token: optional sign, digits, optional decimal part using '.' or ',' as separator\nconst NUM_TOKEN = '[-+]?\\\\d+(?:[.,]\\\\d+)?';\nconst toClauseNumber = (t: string) => Number(t.replace(',', '.'));\n\n/** True when the whole (trimmed) input is a single bare number, e.g. `42`, `-3.5`, `1,5`. */\nexport const isSingleNumber = (input: string) => new RegExp(`^${NUM_TOKEN}$`).test(input.trim());\n\n/**\n * Parse a numeric filter expression into a disjunction of conjunctions\n * (OR groups, each an AND-combined list of clauses).\n *\n * Supported syntax:\n * - operators `>`, `>=`, `<`, `<=`, `=`/`==`, `!=`/`<>` followed by a number (e.g. `> 100`, `=42`, `!=5`)\n * - a bare number, treated as an exact match `= n` (e.g. `42`)\n * - a range `a..b`, expanded to `>= a` and `<= b` (e.g. `10..20`)\n * - `and` / `or` connectors (case-insensitive), e.g. `<10 or >20`, `>10 and <20`.\n *\n * Combining rules: an explicit `or` starts a new OR group, an explicit `and` keeps\n * clauses in the same AND group. When no connector is given between two clauses the\n * implicit connector is OR if both are exact (`=`) clauses — a value list such as\n * `1 2 3` — and AND otherwise (comparisons narrow, e.g. `>10 <20`).\n *\n * Note: a lone bare number is parsed here as `= n`; callers that want the\n * \"contains\" text-search behaviour for a single number must check {@link isSingleNumber}.\n *\n * Decimal separator may be `.` or `,`. Tokens that cannot be parsed are ignored.\n */\nexport const parseNumericExpression = (input: string): NumericFilterGroups => {\n\tconst groups: NumericFilterClause[][] = [];\n\tif (!input) return groups;\n\n\tlet current: NumericFilterClause[] = [];\n\tlet pending: 'and' | 'or' | null = null; // explicit connector awaiting the next clause\n\tlet lastOp: NumericFilterOperator | null = null;\n\n\tconst flush = () => { if (current.length > 0) { groups.push(current); current = []; } };\n\n\t// add one AND-unit (a single clause, or the two bounds of a range), honouring the\n\t// pending explicit connector or the implicit default (OR between two `=`, else AND)\n\tconst addUnit = (clauses: NumericFilterClause[]) => {\n\t\tconst first = groups.length === 0 && current.length === 0;\n\t\tif (!first) {\n\t\t\tconst connector = pending ?? ((lastOp === '=' && clauses[0].op === '=') ? 'or' : 'and');\n\t\t\tif (connector === 'or') flush();\n\t\t}\n\t\tcurrent.push(...clauses);\n\t\tpending = null;\n\t\tlastOp = clauses[clauses.length - 1].op;\n\t};\n\n\tconst tokenRe = new RegExp(\n\t\t`(${NUM_TOKEN})\\\\s*\\\\.\\\\.\\\\s*(${NUM_TOKEN})` + // 1,2 range a..b\n\t\t`|(>=|<=|<>|!=|==|=|>|<)\\\\s*(${NUM_TOKEN})` + // 3,4 comparison clause\n\t\t`|\\\\b(and|or)\\\\b` + // 5 connector\n\t\t`|(${NUM_TOKEN})`, // 6 bare number (exact match)\n\t\t'gi'\n\t);\n\n\tlet m: RegExpExecArray | null;\n\twhile ((m = tokenRe.exec(input)) !== null) {\n\t\tif (m[1] != null) {\n\t\t\taddUnit([{ op: '>=', value: toClauseNumber(m[1]) }, { op: '<=', value: toClauseNumber(m[2]) }]);\n\t\t} else if (m[3] != null) {\n\t\t\tconst op: NumericFilterOperator = m[3] === '==' ? '=' : m[3] === '<>' ? '!=' : m[3] as NumericFilterOperator;\n\t\t\taddUnit([{ op, value: toClauseNumber(m[4]) }]);\n\t\t} else if (m[5] != null) {\n\t\t\tpending = m[5].toLowerCase() === 'or' ? 'or' : 'and';\n\t\t} else if (m[6] != null) {\n\t\t\taddUnit([{ op: '=', value: toClauseNumber(m[6]) }]);\n\t\t}\n\t}\n\tflush();\n\treturn groups;\n};\n\nexport const createNumericMatcher = <TItem>(groups: NumericFilterGroups, property: keyof TItem) => {\n\tconst test = (v: number, c: NumericFilterClause) => {\n\t\tswitch (c.op) {\n\t\t\tcase '>': return v > c.value;\n\t\t\tcase '>=': return v >= c.value;\n\t\t\tcase '<': return v < c.value;\n\t\t\tcase '<=': return v <= c.value;\n\t\t\tcase '=': return v === c.value;\n\t\t\tcase '!=': return v !== c.value;\n\t\t}\n\t};\n\treturn (item: TItem) => {\n\t\tif (groups.length === 0) return true;\n\t\tconst raw = item[property];\n\t\tif (raw == null || raw === '') return false;\n\t\tconst v = typeof raw === 'number' ? raw : Number(raw);\n\t\tif (Number.isNaN(v)) return false;\n\t\t// value matches if it satisfies every clause of at least one OR group\n\t\treturn groups.some(group => group.every(c => test(v, c)));\n\t};\n};\n\nexport const createCellMatcher = (type: CellType, term: FilterValue, property: keyof CellModel) => {\n\tproperty = property ?? 'value';\n\t// range terms come only from the date/datetime/time range popup\n\tif ((type === 'd' || type === 'dt' || type === 'tm') && isFilterRange(term)) {\n\t\treturn createRangeMatcher<CellModel>(term, property, type);\n\t}\n\tif (type === 'n') {\n\t\tconst str = (term?.toString()) ?? '';\n\t\t// a lone bare number -> plain \"contains\" text search; anything else -> numeric expression\n\t\tif (isSingleNumber(str)) return createTextMatcher<CellModel>(str.trim(), 'formattedValue');\n\t\tconst groups = parseNumericExpression(str);\n\t\tif (groups.length > 0) return createNumericMatcher<CellModel>(groups, property);\n\t\treturn createTextMatcher<CellModel>(str, 'formattedValue');\n\t}\n\tif (type === 'b') return createBoolMatcher<CellModel>(term as boolean, property);\n\telse if (type === 's' && Array.isArray(term)) return createMultiMatcher<CellModel>((term as KeyValue[]), 'value');\n\telse if (type === 's') return createTextMatcher<CellModel>((term?.toString()), 'formattedValue');\n\telse if (type === 'm' && Array.isArray(term)) return createMultiMultiMatcher<CellModel>((term as KeyValue[]), property);\n\telse if (type === 'd') return createTextMatcher<CellModel>((term?.toString()) as string, 'formattedValue');\n\telse if (type === 'dt') return createTextMatcher<CellModel>((term?.toString()) as string, 'formattedValue');\n\telse if (type === 'tm') return createTextMatcher<CellModel>((term?.toString()) as string, 'formattedValue');\n\t// text search in the value must not see the quote prefix, a custom property is kept as is\n\treturn createTextMatcher<CellModel>((term?.toString()) as string, property === 'value' ? 'plainValue' : property);\n}\n\nexport class FilterEvent extends Event {\n\tconstructor() {\n\t\tsuper('filter', {bubbles: false, cancelable: true, composed: true});\n\t}\n}\n\nexport class FilterModel extends EventTarget {\n\t\n\tpublic custom = false;\n\n\tprivate colMap = new Map<number, number>();\n\tprivate _settings: FilterSettings[] = [];\n\tget settings() { return this._settings }\n\tset settings(v: FilterSettings[]|null) {\n\t\tthis._settings = v || [];\n\t\tthis.colMap.clear();\n\t\tif (this.settings.length > 0) {\n\t\t\tthis.settings.forEach((s, i) => this.colMap.set(s.c, i));\n\t\t\tthis.applyFilter();\n\t\t\tlog.getLogger().info(`filtering applied: ${JSON.stringify(this.settings)}`);\n\t\t}\n\t}\n\n\tconstructor(\n\t\tpublic readonly model: GridModel,\n\t\tsettings: FilterSettings[]|null = null\n\t) {\n\t\tsuper();\n\t\tthis.settings = settings;\n\t}\n\n\t/**\n\t * Get filtering settings for specified column\n\t * @param c column index\n\t */\n\tget(c: number) {\n\t\treturn this.colMap.has(c) ? this.settings[this.colMap.get(c)] : null;\n\t}\n\n\t/**\n\t * Restore settings captured from a previous model instance (grid refresh recreates the model).\n\t * With `custom` (the server filters) the rows came filtered by these settings already: they all count as\n\t * matched, whatever the settings the new model applied to itself in its constructor (the default ones).\n\t */\n\trestore(settings: FilterSettings[], custom = false) {\n\t\tthis.custom = custom;\n\t\t// drop settings for columns that no longer exist in the refreshed model\n\t\tthis._settings = (settings || []).filter(s => this.model.columns[s.c]);\n\t\tthis.colMap.clear();\n\t\tthis._settings.forEach((s, i) => this.colMap.set(s.c, i));\n\t\tif (custom) this.matchAllRows();\n\t\telse if (this._settings.length > 0) this.applyFilter(false);\n\t}\n\n\tfilter(filter: FilterSettings, dispatchEvent = true) {\n\t\tconst filterSetting = this.get(filter.c);\n\t\tconst empty = filter.term === null || filter.term === ''\n\t\t\t|| (isFilterRange(filter.term) && isFilterRangeEmpty(filter.term));\n\n\t\tif (filterSetting && empty) {\n\t\t\t// remove; splice shifts the following slots, so the map must be rebuilt\n\t\t\tthis.settings.splice(this.colMap.get(filter.c), 1);\n\t\t\tthis.colMap.clear();\n\t\t\tthis.settings.forEach((s, i) => this.colMap.set(s.c, i));\n\t\t} else if (filterSetting) {\n\t\t\t// update\n\t\t\tfilterSetting.term = filter.term;\n\t\t} else if (!empty) {\n\t\t\t// add\n\t\t\tthis.colMap.set(filter.c, this.settings.length);\n\t\t\tthis.settings.push(filter);\n\t\t}\n\n\t\tif (!this.custom) {\n\t\t\tif (this.settings.length > 0) {\n\t\t\t\tthis.applyFilter(false);\n\t\t\t} else {\n\t\t\t\tthis.resetFilter(false);\n\t\t\t}\n\t\t}\n\n\t\tif (dispatchEvent) this.dispatchEvent(new FilterEvent())\n\t}\n\n\tapplyFilter(dispatchEvent = true) {\n\t\tconst cellMatchers: {c: number, matcher: FilterMatcher}[] = [];\n\t\tthis.settings.forEach((s) => {\n\t\t\tconst column = this.model.columns[s.c];\n\t\t\tcellMatchers.push({c: s.c, matcher: createCellMatcher(column.type, s.term, column.filter?.property)});\n\t\t});\n\n\t\tconst count = cellMatchers.length;\n\t\tconst rowMatcher = (row: RowModel) => {\n\t\t\tif (!row.filterable) return true;\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tif (!cellMatchers[i].matcher(row.cell(cellMatchers[i].c))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t};\n\n\t\tconst includeParents = (this.model.options.filters as FilterOptions)?.includeParents ?? true;\n\t\tconst includeChildren = (this.model.options.filters as FilterOptions)?.includeChildren ?? true;\n\n\t\tconst visitedRows = new Set<number>();\n\t\tthis.model.rows.forEach(row => {\n\t\t\tconst visited = visitedRows.has(row.index);\n\n\t\t\tif (rowMatcher(row)) {\n\t\t\t\trow.filterState = tree.FilterState.Matched;\n\t\t\t\tif (includeParents) {\n\t\t\t\t\trow.walkUp((parent: RowModel) => {\n\t\t\t\t\t\tif (visitedRows.has(parent.index) && parent.filterState > 0) return false;\n\t\t\t\t\t\tparent.filterState = tree.FilterState.ChildMatched;\n\t\t\t\t\t\tvisitedRows.add(parent.index);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (includeChildren) {\n\t\t\t\t\trow.walk((child: RowModel) => {\n\t\t\t\t\t\tif (visitedRows.has(child.index) && child.filterState > 0) return false;\n\t\t\t\t\t\tchild.filterState = tree.FilterState.ParentMatched;\n\t\t\t\t\t\tvisitedRows.add(child.index);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (!visited) {\n\t\t\t\trow.filterState = tree.FilterState.Filtered;\n\t\t\t}\n\n\t\t\tvisitedRows.add(row.index);\n\t\t});\n\n\t\tthis.model.indexRows();\n\t\tif (dispatchEvent) this.dispatchEvent(new FilterEvent())\n\t}\n\n\tresetFilter(dispatchEvent = true) {\n\t\tthis.settings = [];\n\t\tthis.colMap.clear();\n\t\tthis.matchAllRows();\n\t\tif (dispatchEvent) this.dispatchEvent(new FilterEvent())\n\t}\n\n\tprivate matchAllRows() {\n\t\tthis.model.rows.forEach(row => row.filterState = tree.FilterState.Matched);\n\t\tthis.model.indexRows();\n\t}\n\n}"]}
|
|
1
|
+
{"version":3,"file":"filterModel.js","sourceRoot":"","sources":["../../src/model/filterModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyValue, log, tree, utils } from \"@omegagrid/core\";\nimport { CellModel } from \"./cellModel\";\nimport { GridModel } from \"./gridModel\";\nimport { RowModel } from \"./rowModel\";\nimport { FilterOptions } from \"./options\";\nimport { createDateMatcher, parseDateExpression } from \"./dateFilter\";\nimport { CellType, FilterValue, NumericFilterClause, NumericFilterGroups, NumericFilterOperator } from \"../types\";\n\nexport type FilterMatcher = (cell: CellModel) => boolean;\n\nexport type FilterSettings = {\n\tc: number;\n\tterm: FilterValue;\n};\n\nexport const createTextMatcher = <TItem>(term: string, property: keyof TItem) => {\n\tconst regex = new RegExp(`${utils.escapeRegExp(utils.removeAccents(term))}`, 'ig');\n\treturn (item: TItem) => {\n\t\tregex.lastIndex = 0;\n\t\treturn regex.test(utils.removeAccents((item[property] ?? \"\").toString()));\n\t}\n};\n\nexport const createBoolMatcher = <TItem>(term: boolean, property: keyof TItem) => {\n\treturn (item: TItem) => !!item[property] === term;\n};\n\nexport const createMultiMatcher = <TItem>(term: KeyValue[], property: keyof TItem) => {\n\tconst keys = term.map(t => t.key?.toString());\n\treturn (item: TItem) => {\n\t\treturn item[property] == null ? false : keys.includes(item[property].toString());\n\t};\n};\n\nexport const createMultiMultiMatcher = <TItem>(_term: KeyValue[], _property: keyof TItem) => {\n\treturn (_item: TItem) => false;\n};\n\n// number token: optional sign, digits, optional decimal part using '.' or ',' as separator\nconst NUM_TOKEN = '[-+]?\\\\d+(?:[.,]\\\\d+)?';\nconst toClauseNumber = (t: string) => Number(t.replace(',', '.'));\n\n/** True when the whole (trimmed) input is a single bare number, e.g. `42`, `-3.5`, `1,5`. */\nexport const isSingleNumber = (input: string) => new RegExp(`^${NUM_TOKEN}$`).test(input.trim());\n\n/**\n * Parse a numeric filter expression into a disjunction of conjunctions\n * (OR groups, each an AND-combined list of clauses).\n *\n * Supported syntax:\n * - operators `>`, `>=`, `<`, `<=`, `=`/`==`, `!=`/`<>` followed by a number (e.g. `> 100`, `=42`, `!=5`)\n * - a bare number, treated as an exact match `= n` (e.g. `42`)\n * - a range `a..b`, expanded to `>= a` and `<= b` (e.g. `10..20`)\n * - `and` / `or` connectors (case-insensitive), e.g. `<10 or >20`, `>10 and <20`.\n *\n * Combining rules: an explicit `or` starts a new OR group, an explicit `and` keeps\n * clauses in the same AND group. When no connector is given between two clauses the\n * implicit connector is OR if both are exact (`=`) clauses — a value list such as\n * `1 2 3` — and AND otherwise (comparisons narrow, e.g. `>10 <20`).\n *\n * Note: a lone bare number is parsed here as `= n`; callers that want the\n * \"contains\" text-search behaviour for a single number must check {@link isSingleNumber}.\n *\n * Decimal separator may be `.` or `,`. Tokens that cannot be parsed are ignored.\n */\nexport const parseNumericExpression = (input: string): NumericFilterGroups => {\n\tconst groups: NumericFilterClause[][] = [];\n\tif (!input) return groups;\n\n\tlet current: NumericFilterClause[] = [];\n\tlet pending: 'and' | 'or' | null = null; // explicit connector awaiting the next clause\n\tlet lastOp: NumericFilterOperator | null = null;\n\n\tconst flush = () => { if (current.length > 0) { groups.push(current); current = []; } };\n\n\t// add one AND-unit (a single clause, or the two bounds of a range), honouring the\n\t// pending explicit connector or the implicit default (OR between two `=`, else AND)\n\tconst addUnit = (clauses: NumericFilterClause[]) => {\n\t\tconst first = groups.length === 0 && current.length === 0;\n\t\tif (!first) {\n\t\t\tconst connector = pending ?? ((lastOp === '=' && clauses[0].op === '=') ? 'or' : 'and');\n\t\t\tif (connector === 'or') flush();\n\t\t}\n\t\tcurrent.push(...clauses);\n\t\tpending = null;\n\t\tlastOp = clauses[clauses.length - 1].op;\n\t};\n\n\tconst tokenRe = new RegExp(\n\t\t`(${NUM_TOKEN})\\\\s*\\\\.\\\\.\\\\s*(${NUM_TOKEN})` + // 1,2 range a..b\n\t\t`|(>=|<=|<>|!=|==|=|>|<)\\\\s*(${NUM_TOKEN})` + // 3,4 comparison clause\n\t\t`|\\\\b(and|or)\\\\b` + // 5 connector\n\t\t`|(${NUM_TOKEN})`, // 6 bare number (exact match)\n\t\t'gi'\n\t);\n\n\tlet m: RegExpExecArray | null;\n\twhile ((m = tokenRe.exec(input)) !== null) {\n\t\tif (m[1] != null) {\n\t\t\taddUnit([{ op: '>=', value: toClauseNumber(m[1]) }, { op: '<=', value: toClauseNumber(m[2]) }]);\n\t\t} else if (m[3] != null) {\n\t\t\tconst op: NumericFilterOperator = m[3] === '==' ? '=' : m[3] === '<>' ? '!=' : m[3] as NumericFilterOperator;\n\t\t\taddUnit([{ op, value: toClauseNumber(m[4]) }]);\n\t\t} else if (m[5] != null) {\n\t\t\tpending = m[5].toLowerCase() === 'or' ? 'or' : 'and';\n\t\t} else if (m[6] != null) {\n\t\t\taddUnit([{ op: '=', value: toClauseNumber(m[6]) }]);\n\t\t}\n\t}\n\tflush();\n\treturn groups;\n};\n\nexport const createNumericMatcher = <TItem>(groups: NumericFilterGroups, property: keyof TItem) => {\n\tconst test = (v: number, c: NumericFilterClause) => {\n\t\tswitch (c.op) {\n\t\t\tcase '>': return v > c.value;\n\t\t\tcase '>=': return v >= c.value;\n\t\t\tcase '<': return v < c.value;\n\t\t\tcase '<=': return v <= c.value;\n\t\t\tcase '=': return v === c.value;\n\t\t\tcase '!=': return v !== c.value;\n\t\t}\n\t};\n\treturn (item: TItem) => {\n\t\tif (groups.length === 0) return true;\n\t\tconst raw = item[property];\n\t\tif (raw == null || raw === '') return false;\n\t\tconst v = typeof raw === 'number' ? raw : Number(raw);\n\t\tif (Number.isNaN(v)) return false;\n\t\t// value matches if it satisfies every clause of at least one OR group\n\t\treturn groups.some(group => group.every(c => test(v, c)));\n\t};\n};\n\nexport const createCellMatcher = (type: CellType, term: FilterValue, property: keyof CellModel) => {\n\tproperty = property ?? 'value';\n\tif (type === 'd' || type === 'dt' || type === 'tm') {\n\t\t// a date expression ('6.11.2026', '6.11.2026..20.11.2026', '> 11.2026'), a text that is none searches the shown text\n\t\tconst groups = parseDateExpression((term?.toString()) ?? '', type);\n\t\tif (groups) return createDateMatcher<CellModel>(groups, property, type);\n\t\treturn createTextMatcher<CellModel>((term?.toString()) as string, 'formattedValue');\n\t}\n\tif (type === 'n') {\n\t\tconst str = (term?.toString()) ?? '';\n\t\t// a lone bare number -> plain \"contains\" text search; anything else -> numeric expression\n\t\tif (isSingleNumber(str)) return createTextMatcher<CellModel>(str.trim(), 'formattedValue');\n\t\tconst groups = parseNumericExpression(str);\n\t\tif (groups.length > 0) return createNumericMatcher<CellModel>(groups, property);\n\t\treturn createTextMatcher<CellModel>(str, 'formattedValue');\n\t}\n\tif (type === 'b') return createBoolMatcher<CellModel>(term as boolean, property);\n\telse if (type === 's' && Array.isArray(term)) return createMultiMatcher<CellModel>((term as KeyValue[]), 'value');\n\telse if (type === 's') return createTextMatcher<CellModel>((term?.toString()), 'formattedValue');\n\telse if (type === 'm' && Array.isArray(term)) return createMultiMultiMatcher<CellModel>((term as KeyValue[]), property);\n\t// text search in the value must not see the quote prefix, a custom property is kept as is\n\treturn createTextMatcher<CellModel>((term?.toString()) as string, property === 'value' ? 'plainValue' : property);\n}\n\nexport class FilterEvent extends Event {\n\tconstructor() {\n\t\tsuper('filter', {bubbles: false, cancelable: true, composed: true});\n\t}\n}\n\nexport class FilterModel extends EventTarget {\n\t\n\tpublic custom = false;\n\n\tprivate colMap = new Map<number, number>();\n\tprivate _settings: FilterSettings[] = [];\n\tget settings() { return this._settings }\n\tset settings(v: FilterSettings[]|null) {\n\t\tthis._settings = v || [];\n\t\tthis.colMap.clear();\n\t\tif (this.settings.length > 0) {\n\t\t\tthis.settings.forEach((s, i) => this.colMap.set(s.c, i));\n\t\t\tthis.applyFilter();\n\t\t\tlog.getLogger().info(`filtering applied: ${JSON.stringify(this.settings)}`);\n\t\t}\n\t}\n\n\tconstructor(\n\t\tpublic readonly model: GridModel,\n\t\tsettings: FilterSettings[]|null = null\n\t) {\n\t\tsuper();\n\t\tthis.settings = settings;\n\t}\n\n\t/**\n\t * Get filtering settings for specified column\n\t * @param c column index\n\t */\n\tget(c: number) {\n\t\treturn this.colMap.has(c) ? this.settings[this.colMap.get(c)] : null;\n\t}\n\n\t/**\n\t * Restore settings captured from a previous model instance (grid refresh recreates the model).\n\t * With `custom` (the server filters) the rows came filtered by these settings already: they all count as\n\t * matched, whatever the settings the new model applied to itself in its constructor (the default ones).\n\t */\n\trestore(settings: FilterSettings[], custom = false) {\n\t\tthis.custom = custom;\n\t\t// drop settings for columns that no longer exist in the refreshed model\n\t\tthis._settings = (settings || []).filter(s => this.model.columns[s.c]);\n\t\tthis.colMap.clear();\n\t\tthis._settings.forEach((s, i) => this.colMap.set(s.c, i));\n\t\tif (custom) this.matchAllRows();\n\t\telse if (this._settings.length > 0) this.applyFilter(false);\n\t}\n\n\tfilter(filter: FilterSettings, dispatchEvent = true) {\n\t\tconst filterSetting = this.get(filter.c);\n\t\tconst empty = filter.term === null || filter.term === '';\n\n\t\tif (filterSetting && empty) {\n\t\t\t// remove; splice shifts the following slots, so the map must be rebuilt\n\t\t\tthis.settings.splice(this.colMap.get(filter.c), 1);\n\t\t\tthis.colMap.clear();\n\t\t\tthis.settings.forEach((s, i) => this.colMap.set(s.c, i));\n\t\t} else if (filterSetting) {\n\t\t\t// update\n\t\t\tfilterSetting.term = filter.term;\n\t\t} else if (!empty) {\n\t\t\t// add\n\t\t\tthis.colMap.set(filter.c, this.settings.length);\n\t\t\tthis.settings.push(filter);\n\t\t}\n\n\t\tif (!this.custom) {\n\t\t\tif (this.settings.length > 0) {\n\t\t\t\tthis.applyFilter(false);\n\t\t\t} else {\n\t\t\t\tthis.resetFilter(false);\n\t\t\t}\n\t\t}\n\n\t\tif (dispatchEvent) this.dispatchEvent(new FilterEvent())\n\t}\n\n\tapplyFilter(dispatchEvent = true) {\n\t\tconst cellMatchers: {c: number, matcher: FilterMatcher}[] = [];\n\t\tthis.settings.forEach((s) => {\n\t\t\tconst column = this.model.columns[s.c];\n\t\t\tcellMatchers.push({c: s.c, matcher: createCellMatcher(column.type, s.term, column.filter?.property)});\n\t\t});\n\n\t\tconst count = cellMatchers.length;\n\t\tconst rowMatcher = (row: RowModel) => {\n\t\t\tif (!row.filterable) return true;\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tif (!cellMatchers[i].matcher(row.cell(cellMatchers[i].c))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t};\n\n\t\tconst includeParents = (this.model.options.filters as FilterOptions)?.includeParents ?? true;\n\t\tconst includeChildren = (this.model.options.filters as FilterOptions)?.includeChildren ?? true;\n\n\t\tconst visitedRows = new Set<number>();\n\t\tthis.model.rows.forEach(row => {\n\t\t\tconst visited = visitedRows.has(row.index);\n\n\t\t\tif (rowMatcher(row)) {\n\t\t\t\trow.filterState = tree.FilterState.Matched;\n\t\t\t\tif (includeParents) {\n\t\t\t\t\trow.walkUp((parent: RowModel) => {\n\t\t\t\t\t\tif (visitedRows.has(parent.index) && parent.filterState > 0) return false;\n\t\t\t\t\t\tparent.filterState = tree.FilterState.ChildMatched;\n\t\t\t\t\t\tvisitedRows.add(parent.index);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (includeChildren) {\n\t\t\t\t\trow.walk((child: RowModel) => {\n\t\t\t\t\t\tif (visitedRows.has(child.index) && child.filterState > 0) return false;\n\t\t\t\t\t\tchild.filterState = tree.FilterState.ParentMatched;\n\t\t\t\t\t\tvisitedRows.add(child.index);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (!visited) {\n\t\t\t\trow.filterState = tree.FilterState.Filtered;\n\t\t\t}\n\n\t\t\tvisitedRows.add(row.index);\n\t\t});\n\n\t\tthis.model.indexRows();\n\t\tif (dispatchEvent) this.dispatchEvent(new FilterEvent())\n\t}\n\n\tresetFilter(dispatchEvent = true) {\n\t\tthis.settings = [];\n\t\tthis.colMap.clear();\n\t\tthis.matchAllRows();\n\t\tif (dispatchEvent) this.dispatchEvent(new FilterEvent())\n\t}\n\n\tprivate matchAllRows() {\n\t\tthis.model.rows.forEach(row => row.filterState = tree.FilterState.Matched);\n\t\tthis.model.indexRows();\n\t}\n\n}"]}
|
package/dist/model/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './conditionalFormats';
|
|
|
7
7
|
export * from './cssStyle';
|
|
8
8
|
export * from './dependencies';
|
|
9
9
|
export * from './elementModel';
|
|
10
|
+
export * from './dateFilter';
|
|
10
11
|
export * from './filterModel';
|
|
11
12
|
export * from './gridModel';
|
|
12
13
|
export * from './groupModel';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
|
package/dist/model/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './conditionalFormats';
|
|
|
7
7
|
export * from './cssStyle';
|
|
8
8
|
export * from './dependencies';
|
|
9
9
|
export * from './elementModel';
|
|
10
|
+
export * from './dateFilter';
|
|
10
11
|
export * from './filterModel';
|
|
11
12
|
export * from './gridModel';
|
|
12
13
|
export * from './groupModel';
|
package/dist/model/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC","sourcesContent":["export * from './cellModel';\nexport * from './columnModel';\nexport * from './sortingModel';\nexport * from './commentModel';\nexport * from './calculationModel';\nexport * from './conditionalFormats';\nexport * from './cssStyle';\nexport * from './dependencies';\nexport * from './elementModel';\nexport * from './filterModel';\nexport * from './gridModel';\nexport * from './groupModel';\nexport * from './history';\nexport * from './iterableRange';\nexport * from './options';\nexport * from './rowModel';\nexport * from './namingModel';\nexport * from './selectionModel';\nexport * from './style';\nexport * from './tableTheme';\nexport * from './validations';\nexport * from './merges';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC","sourcesContent":["export * from './cellModel';\nexport * from './columnModel';\nexport * from './sortingModel';\nexport * from './commentModel';\nexport * from './calculationModel';\nexport * from './conditionalFormats';\nexport * from './cssStyle';\nexport * from './dependencies';\nexport * from './elementModel';\nexport * from './dateFilter';\nexport * from './filterModel';\nexport * from './gridModel';\nexport * from './groupModel';\nexport * from './history';\nexport * from './iterableRange';\nexport * from './options';\nexport * from './rowModel';\nexport * from './namingModel';\nexport * from './selectionModel';\nexport * from './style';\nexport * from './tableTheme';\nexport * from './validations';\nexport * from './merges';\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -11,17 +11,7 @@ export type BaseGroupModelSource = {
|
|
|
11
11
|
};
|
|
12
12
|
export type EditType = 'value' | 'style' | 'insert_row' | 'insert_column' | 'delete_row' | 'delete_column' | 'move_row' | 'move_column' | 'autofill';
|
|
13
13
|
export type CellValueType = unknown;
|
|
14
|
-
|
|
15
|
-
* Filter term produced by the date/datetime/time range filter popup (`og-filter-range`).
|
|
16
|
-
* Numeric columns do NOT use this — they filter via a text expression (see
|
|
17
|
-
* {@link NumericFilterGroups} and `parseNumericExpression`).
|
|
18
|
-
*/
|
|
19
|
-
export type FilterRange = {
|
|
20
|
-
kind: 'range';
|
|
21
|
-
from?: number | string | Date | null;
|
|
22
|
-
to?: number | string | Date | null;
|
|
23
|
-
};
|
|
24
|
-
export type FilterValue = string | number | boolean | KeyValue[] | FilterRange;
|
|
14
|
+
export type FilterValue = string | number | boolean | KeyValue[];
|
|
25
15
|
/** Comparison operators usable in a numeric text filter expression (e.g. `> 100`). */
|
|
26
16
|
export type NumericFilterOperator = '=' | '!=' | '<' | '<=' | '>' | '>=';
|
|
27
17
|
export type NumericFilterClause = {
|
|
@@ -34,6 +24,22 @@ export type NumericFilterClause = {
|
|
|
34
24
|
* satisfies every clause of at least one group.
|
|
35
25
|
*/
|
|
36
26
|
export type NumericFilterGroups = NumericFilterClause[][];
|
|
27
|
+
/** The date column types: a date, a date and time, a time of day */
|
|
28
|
+
export type DateFilterType = 'd' | 'dt' | 'tm';
|
|
29
|
+
/**
|
|
30
|
+
* A bound of a date filter expression: the value is at or after a time (`>=`) or before it (`<`). A time of day
|
|
31
|
+
* (type tm) lies on the day of the serial date 0, the end of a day is the start of the next one.
|
|
32
|
+
*/
|
|
33
|
+
export type DateFilterBound = {
|
|
34
|
+
op: '>=' | '<';
|
|
35
|
+
value: Date;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Parsed date expression (see `parseDateExpression`) as a disjunction of conjunctions: the outer array holds OR
|
|
39
|
+
* groups, each inner array holds bounds combined with AND. A value matches if it satisfies every bound of at
|
|
40
|
+
* least one group; no group matches nothing.
|
|
41
|
+
*/
|
|
42
|
+
export type DateFilterGroups = DateFilterBound[][];
|
|
37
43
|
/**
|
|
38
44
|
* Actions = 'a',
|
|
39
45
|
* Html = 'h'
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACjH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1G,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,KAAK,cAAc,CAAC;AAChF,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,KAAK,cAAc,CAAC;AAE7G,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,KAAK,MAAM,CAAC;AAE9D,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;AAE9D,MAAM,MAAM,oBAAoB,GAAG;IAClC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAA;CAErB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAC,OAAO,GAAC,YAAY,GAAC,eAAe,GAAC,YAAY,GAAC,eAAe,GAAC,UAAU,GAAC,aAAa,GAAC,UAAU,CAAC;AACrI,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;AACpC
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ColorTypes, Direction, Size, Location, UIValueType, Matrix, KeyValue, MenuItem } from \"@omegagrid/core\";\nimport { CSSStyle, CellModel, GridSource, Style, CommentItem, TableTheme, EditingOptions } from \"./model\";\nimport { CellRange } from \"./common\";\n\nexport type Renderer = (div: HTMLDivElement, cell: CellModel) => HTMLDivElement;\nexport type CommentRenderer = (div: HTMLDivElement, comment: CommentItem, cell: CellModel) => HTMLDivElement;\n\nexport type Comparer = (a: CellModel, b: CellModel) => number;\n\nexport type FormulaFunction = (...args: unknown[]) => unknown;\n\nexport type BaseGroupModelSource = {\n\tmodels: GridSource[],\n\tthemes?: TableTheme[]\n\t//layout: TabSplitContainerModel\n}\n\nexport type EditType = 'value'|'style'|'insert_row'|'insert_column'|'delete_row'|'delete_column'|'move_row'|'move_column'|'autofill';\nexport type CellValueType = unknown; //number|string|boolean|object|null;\
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ColorTypes, Direction, Size, Location, UIValueType, Matrix, KeyValue, MenuItem } from \"@omegagrid/core\";\nimport { CSSStyle, CellModel, GridSource, Style, CommentItem, TableTheme, EditingOptions } from \"./model\";\nimport { CellRange } from \"./common\";\n\nexport type Renderer = (div: HTMLDivElement, cell: CellModel) => HTMLDivElement;\nexport type CommentRenderer = (div: HTMLDivElement, comment: CommentItem, cell: CellModel) => HTMLDivElement;\n\nexport type Comparer = (a: CellModel, b: CellModel) => number;\n\nexport type FormulaFunction = (...args: unknown[]) => unknown;\n\nexport type BaseGroupModelSource = {\n\tmodels: GridSource[],\n\tthemes?: TableTheme[]\n\t//layout: TabSplitContainerModel\n}\n\nexport type EditType = 'value'|'style'|'insert_row'|'insert_column'|'delete_row'|'delete_column'|'move_row'|'move_column'|'autofill';\nexport type CellValueType = unknown; //number|string|boolean|object|null;\nexport type FilterValue = string|number|boolean|KeyValue[];\n\n/** Comparison operators usable in a numeric text filter expression (e.g. `> 100`). */\nexport type NumericFilterOperator = '=' | '!=' | '<' | '<=' | '>' | '>=';\nexport type NumericFilterClause = { op: NumericFilterOperator, value: number };\n/**\n * Parsed numeric expression as a disjunction of conjunctions: the outer array holds\n * OR groups, each inner array holds clauses combined with AND. A value matches if it\n * satisfies every clause of at least one group.\n */\nexport type NumericFilterGroups = NumericFilterClause[][];\n\n/** The date column types: a date, a date and time, a time of day */\nexport type DateFilterType = 'd' | 'dt' | 'tm';\n/**\n * A bound of a date filter expression: the value is at or after a time (`>=`) or before it (`<`). A time of day\n * (type tm) lies on the day of the serial date 0, the end of a day is the start of the next one.\n */\nexport type DateFilterBound = { op: '>=' | '<', value: Date };\n/**\n * Parsed date expression (see `parseDateExpression`) as a disjunction of conjunctions: the outer array holds OR\n * groups, each inner array holds bounds combined with AND. A value matches if it satisfies every bound of at\n * least one group; no group matches nothing.\n */\nexport type DateFilterGroups = DateFilterBound[][];\n\n/**\n * Actions = 'a',\n * Html = 'h'\n */\nexport type AditionalUIValueType = 'a'|'h';\n\nexport type CellType = UIValueType | AditionalUIValueType;\n\nexport type StyleSource = number|string|Style|CSSStyle;\n\nexport type CellAction = {\n\taction: string,\n\ticon?: string,\n\ttext?: string,\n\ttitle?: string,\n\tcolor?: ColorTypes,\n\ttype?: 'button'|'menu',\n\titems?: MenuItem[]\n}\n\nexport type CellValidationSource = {\n\t/** Allow invalid cell values */\n\tallowInvalid?: boolean,\n\n\t/** Validation pattern */\n\tpattern?: string|RegExp,\n\n\t/** Validation function */\n\tvalidate?: (cell: CellModel, value: unknown) => boolean,\n}\n\nexport type CellValidation = Omit<CellValidationSource, 'pattern'> & {\n\t/** Validation pattern */\n\tpattern?: RegExp,\n}\n\nexport type ShiftOptions = {\n\t/** Index of the first shifted row/column */\n\tindex: number;\n\t/** Number of rows/columns to shift */\n\toffset: number;\n\t/** Shift direction up/down for rows, left/right for columns */\n\tdirection: Direction;\n\t/** Name of the sheet where the shift occured */\n\tsheet?: string;\n\t/** Force shift on all references */\n\tallSheets?: boolean;\n\t/** Maximum affected index */\n\tmaxIndex?: number;\n\t/** Shift anchored coords */\n\tignoreAnchors?: boolean;\n}\n\nexport type FormulaFuncParamDescription = {\n\tname: string,\n\ttype: string,\n\tdescription: string,\n\toptional: boolean,\n\tdefault?: string\n}\n\nexport type FormulaFuncDescription = {\n\tname: string,\n\tparams: FormulaFuncParamDescription[],\n\treturns: string,\n\tdescription: string,\n\tlinks: string[]\n}\n\nexport type FormulaFuncGroupDescription = {\n\tname: string,\n\tfunctions: FormulaFuncDescription[]\n}\n\nexport type TabOptions = {\n\tcolor?: string,\n\thidden?: boolean,\n}\n\nexport type ObjectModel = {\n\tlocation: Location;\n\tsize: Size;\n\tzIndex?: number;\n}\n\nexport type SpillOptions = {\n\tcell: CellModel; \n\tvalues: Matrix;\n\tpropertyCell?: CellModel;\n\tdisplayValues?: Matrix<string>;\n}\n\nexport type SpillResult = {\n\tcells: CellModel[];\n\toldValues: CellValueType[];\n\trange: CellRange;\n}\n\nexport type AutofitOptions = {\n\t// visibleOnly?: boolean;\n\t/** column autofit measures the header labels too (default true) */\n\tincludeHeaders?: boolean;\n}\n\nexport type CellSerializationOptions = {\n\tdisplayValue?: boolean;\n}\n\nexport type EditorFactory<T extends HTMLElement = HTMLElement> = (cell: CellModel, options?: EditingOptions) => T;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omegagrid/grid-core",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.34",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"description": "Grid model, no ui components",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"generate-functions-docs": "node ./scripts/generate-functions-docs.cjs"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@omegagrid/core": "^0.11.
|
|
32
|
-
"@omegagrid/localize": "^0.11.
|
|
31
|
+
"@omegagrid/core": "^0.11.34",
|
|
32
|
+
"@omegagrid/localize": "^0.11.34",
|
|
33
33
|
"@stdlib/stats": "^0.0.13",
|
|
34
34
|
"color": "^4.2.3",
|
|
35
35
|
"date-fns": "^3.2.0",
|