@aglyn/shared-ui-jsx 1.0.0-beta.199 → 1.0.0-beta.201
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/package.json +5 -5
- package/src/lib/components/list-filter-chips.component.d.ts +2 -2
- package/src/lib/components/list-filter-chips.component.js +6 -28
- package/src/lib/components/list-filter-chips.component.js.map +1 -1
- package/src/lib/components/list-filter-toolbar.component.d.ts +56 -0
- package/src/lib/components/list-filter-toolbar.component.js +280 -0
- package/src/lib/components/list-filter-toolbar.component.js.map +1 -0
- package/src/lib/components/list-query-notices.component.d.ts +18 -0
- package/src/lib/components/list-query-notices.component.js +11 -0
- package/src/lib/components/list-query-notices.component.js.map +1 -1
- package/src/lib/components/list-table.component.d.ts +16 -0
- package/src/lib/components/list-table.component.js +70 -8
- package/src/lib/components/list-table.component.js.map +1 -1
- package/src/lib/const/list-filter-sentence.d.ts +40 -0
- package/src/lib/const/list-filter-sentence.js +123 -0
- package/src/lib/const/list-filter-sentence.js.map +1 -0
- package/src/lib/const/list-filter.d.ts +8 -47
- package/src/lib/const/list-filter.js +2 -128
- package/src/lib/const/list-filter.js.map +1 -1
- package/src/lib/const/list-grid-filter.d.ts +39 -28
- package/src/lib/const/list-grid-filter.js +59 -71
- package/src/lib/const/list-grid-filter.js.map +1 -1
- package/src/lib/const/list-query-plan.d.ts +5 -0
- package/src/lib/const/list-query-plan.js.map +1 -1
- package/src/lib/hooks/use-list-grid-filter.d.ts +7 -11
- package/src/lib/hooks/use-list-grid-filter.js +11 -12
- package/src/lib/hooks/use-list-grid-filter.js.map +1 -1
- package/src/lib/hooks/use-list-rows-filter.d.ts +0 -78
- package/src/lib/hooks/use-list-rows-filter.js +0 -86
- package/src/lib/hooks/use-list-rows-filter.js.map +0 -1
- package/src/lib/hooks/use-paged-rows-filter.d.ts +0 -80
- package/src/lib/hooks/use-paged-rows-filter.js +0 -129
- package/src/lib/hooks/use-paged-rows-filter.js.map +0 -1
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2026 Aglyn LLC
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/ 'use client';
|
|
17
|
-
import { useCallback, useMemo } from "react";
|
|
18
|
-
import { filterListRows, listFilterGridColumns } from "../const/list-grid-filter.js";
|
|
19
|
-
import { useListGridFilter } from "./use-list-grid-filter.js";
|
|
20
|
-
const NO_OPTIONS = {};
|
|
21
|
-
const NO_HEADERS = {};
|
|
22
|
-
/**
|
|
23
|
-
* The grid's Filters panel and quick search for a list that HOLDS its rows
|
|
24
|
-
* (AGL-3317) — every row it read, or the window its query capped — and so
|
|
25
|
-
* answers both over that whole set rather than the page on screen.
|
|
26
|
-
*
|
|
27
|
-
* It is `useListGridFilter` with the rest of the recipe every such list
|
|
28
|
-
* repeated: the rows matched through `filterListRows`, the columns typed
|
|
29
|
-
* through `listFilterGridColumns`, and the props the grid and the chips
|
|
30
|
-
* take. A list whose query can serve a clause names it in `served`, puts it
|
|
31
|
-
* on the query, and the rows here are not matched against it again.
|
|
32
|
-
* @deprecated AGL-3321: matches over rows a list has loaded. Serve every clause and search
|
|
33
|
-
* word on the query instead — `planListQuery` (`@aglyn/shared-ui-jsx/const/list-query-plan`, with `nameSearchNormalizers`)
|
|
34
|
-
* through `useListQuery` or `applyListQuery`. Removed once no list calls it.
|
|
35
|
-
*/ export function useListRowsFilter(options) {
|
|
36
|
-
const { rows, fields, options: choices = NO_OPTIONS, headers = NO_HEADERS, search, served } = options;
|
|
37
|
-
const selectFields = useMemo(()=>Object.keys(choices), [
|
|
38
|
-
choices
|
|
39
|
-
]);
|
|
40
|
-
const gridFilter = useListGridFilter({
|
|
41
|
-
clauses: options.clauses,
|
|
42
|
-
onChange: options.onChange,
|
|
43
|
-
selectFields
|
|
44
|
-
});
|
|
45
|
-
const searchKey = gridFilter.searchWords.join(' ');
|
|
46
|
-
const matched = useMemo(()=>filterListRows(rows, fields, gridFilter.clauses, {
|
|
47
|
-
paths: search,
|
|
48
|
-
words: gridFilter.searchWords
|
|
49
|
-
}, served), // `searchKey` stands for the words, which are a new array each render.
|
|
50
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
51
|
-
[
|
|
52
|
-
rows,
|
|
53
|
-
fields,
|
|
54
|
-
gridFilter.clauses,
|
|
55
|
-
searchKey,
|
|
56
|
-
search,
|
|
57
|
-
served
|
|
58
|
-
]);
|
|
59
|
-
const filterColumns = useCallback((columns)=>listFilterGridColumns(columns, fields, choices, headers), [
|
|
60
|
-
fields,
|
|
61
|
-
choices,
|
|
62
|
-
headers
|
|
63
|
-
]);
|
|
64
|
-
return {
|
|
65
|
-
rows: matched,
|
|
66
|
-
filtering: gridFilter.clauses.length > 0 || gridFilter.searchWords.length > 0,
|
|
67
|
-
gridFilter,
|
|
68
|
-
gridProps: {
|
|
69
|
-
filterMode: 'server',
|
|
70
|
-
filterModel: gridFilter.filterModel,
|
|
71
|
-
onFilterModelChange: gridFilter.onFilterModelChange,
|
|
72
|
-
quickFilter: true
|
|
73
|
-
},
|
|
74
|
-
chipsProps: {
|
|
75
|
-
fields,
|
|
76
|
-
headers,
|
|
77
|
-
clauses: gridFilter.clauses,
|
|
78
|
-
onChange: gridFilter.setClauses,
|
|
79
|
-
options: choices
|
|
80
|
-
},
|
|
81
|
-
filterColumns
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
export default useListRowsFilter;
|
|
85
|
-
|
|
86
|
-
//# sourceMappingURL=use-list-rows-filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/hooks/use-list-rows-filter.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport type { GridColDef, GridFilterModel } from '@mui/x-data-grid'\nimport { useCallback, useMemo } from 'react'\nimport type { ListFilterField } from '../const/list-filter'\nimport {\n filterListRows,\n type ListFilterClause,\n type ListFilterOption,\n listFilterGridColumns,\n} from '../const/list-grid-filter'\nimport { type ListGridFilter, useListGridFilter } from './use-list-grid-filter'\n\nexport interface ListRowsFilterOptions<Row extends object> {\n /** Every row the list read — the whole set, or the window its query capped. */\n rows: readonly Row[]\n /** What the panel offers, in the `ListFilterField` grammar. */\n fields: readonly ListFilterField[]\n /** Choices per picked field; each field named here is shown as a select. */\n options?: Readonly<Record<string, readonly ListFilterOption[]>>\n /** How a field reads on a chip and as a hidden column's header. */\n headers?: Readonly<Record<string, string>>\n /** The row paths the quick search reads. */\n search: readonly string[]\n /** A clause the list's query already served, not matched again. */\n served?: (clause: ListFilterClause) => boolean\n /** A saved view's clauses, when the list keeps them; held here otherwise. */\n clauses?: readonly ListFilterClause[]\n onChange?: (clauses: ListFilterClause[]) => void\n}\n\n/** What a list that holds its rows hands its grid and its chips. */\nexport interface ListRowsFilter<Row> {\n /** The rows that answer every clause and the search. */\n rows: Row[]\n /** Whether anything narrows the list — a clause or a search word. */\n filtering: boolean\n gridFilter: ListGridFilter\n /** Spread onto `ListTable`: the controlled panel, answered by the list. */\n gridProps: {\n filterMode: 'server'\n filterModel: GridFilterModel\n onFilterModelChange: (model: GridFilterModel) => void\n quickFilter: true\n }\n /** Spread onto `ListFilterChips`. */\n chipsProps: {\n fields: readonly ListFilterField[]\n headers: Readonly<Record<string, string>>\n clauses: readonly ListFilterClause[]\n onChange: (clauses: ListFilterClause[]) => void\n options: Readonly<Record<string, readonly ListFilterOption[]>>\n }\n /** The list's columns, typed for the panel (`listFilterGridColumns`). */\n filterColumns: (columns: readonly GridColDef[]) => GridColDef[]\n}\n\nconst NO_OPTIONS: Readonly<Record<string, readonly ListFilterOption[]>> = {}\nconst NO_HEADERS: Readonly<Record<string, string>> = {}\n\n/**\n * The grid's Filters panel and quick search for a list that HOLDS its rows\n * (AGL-3317) — every row it read, or the window its query capped — and so\n * answers both over that whole set rather than the page on screen.\n *\n * It is `useListGridFilter` with the rest of the recipe every such list\n * repeated: the rows matched through `filterListRows`, the columns typed\n * through `listFilterGridColumns`, and the props the grid and the chips\n * take. A list whose query can serve a clause names it in `served`, puts it\n * on the query, and the rows here are not matched against it again.\n * @deprecated AGL-3321: matches over rows a list has loaded. Serve every clause and search\n * word on the query instead — `planListQuery` (`@aglyn/shared-ui-jsx/const/list-query-plan`, with `nameSearchNormalizers`)\n * through `useListQuery` or `applyListQuery`. Removed once no list calls it.\n*/\nexport function useListRowsFilter<Row extends object>(\n options: ListRowsFilterOptions<Row>,\n): ListRowsFilter<Row> {\n const {\n rows,\n fields,\n options: choices = NO_OPTIONS,\n headers = NO_HEADERS,\n search,\n served,\n } = options\n const selectFields = useMemo(() => Object.keys(choices), [choices])\n const gridFilter = useListGridFilter({\n clauses: options.clauses,\n onChange: options.onChange,\n selectFields,\n })\n const searchKey = gridFilter.searchWords.join(' ')\n const matched = useMemo(\n () =>\n filterListRows(\n rows,\n fields,\n gridFilter.clauses,\n { paths: search, words: gridFilter.searchWords },\n served,\n ),\n // `searchKey` stands for the words, which are a new array each render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [rows, fields, gridFilter.clauses, searchKey, search, served],\n )\n const filterColumns = useCallback(\n (columns: readonly GridColDef[]) =>\n listFilterGridColumns(columns, fields, choices, headers),\n [fields, choices, headers],\n )\n return {\n rows: matched,\n filtering: gridFilter.clauses.length > 0 || gridFilter.searchWords.length > 0,\n gridFilter,\n gridProps: {\n filterMode: 'server',\n filterModel: gridFilter.filterModel,\n onFilterModelChange: gridFilter.onFilterModelChange,\n quickFilter: true,\n },\n chipsProps: {\n fields,\n headers,\n clauses: gridFilter.clauses,\n onChange: gridFilter.setClauses,\n options: choices,\n },\n filterColumns,\n }\n}\n\nexport default useListRowsFilter\n"],"names":["useCallback","useMemo","filterListRows","listFilterGridColumns","useListGridFilter","NO_OPTIONS","NO_HEADERS","useListRowsFilter","options","rows","fields","choices","headers","search","served","selectFields","Object","keys","gridFilter","clauses","onChange","searchKey","searchWords","join","matched","paths","words","filterColumns","columns","filtering","length","gridProps","filterMode","filterModel","onFilterModelChange","quickFilter","chipsProps","setClauses"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;AAGA,SAASA,WAAW,EAAEC,OAAO,QAAQ,QAAO;AAE5C,SACEC,cAAc,EAGdC,qBAAqB,QAChB,+BAA2B;AAClC,SAA8BC,iBAAiB,QAAQ,4BAAwB;AA8C/E,MAAMC,aAAoE,CAAC;AAC3E,MAAMC,aAA+C,CAAC;AAEtD;;;;;;;;;;;;;AAaA,GACA,OAAO,SAASC,kBACdC,OAAmC;IAEnC,MAAM,EACJC,IAAI,EACJC,MAAM,EACNF,SAASG,UAAUN,UAAU,EAC7BO,UAAUN,UAAU,EACpBO,MAAM,EACNC,MAAM,EACP,GAAGN;IACJ,MAAMO,eAAed,QAAQ,IAAMe,OAAOC,IAAI,CAACN,UAAU;QAACA;KAAQ;IAClE,MAAMO,aAAad,kBAAkB;QACnCe,SAASX,QAAQW,OAAO;QACxBC,UAAUZ,QAAQY,QAAQ;QAC1BL;IACF;IACA,MAAMM,YAAYH,WAAWI,WAAW,CAACC,IAAI,CAAC;IAC9C,MAAMC,UAAUvB,QACd,IACEC,eACEO,MACAC,QACAQ,WAAWC,OAAO,EAClB;YAAEM,OAAOZ;YAAQa,OAAOR,WAAWI,WAAW;QAAC,GAC/CR,SAEJ,uEAAuE;IACvE,uDAAuD;IACvD;QAACL;QAAMC;QAAQQ,WAAWC,OAAO;QAAEE;QAAWR;QAAQC;KAAO;IAE/D,MAAMa,gBAAgB3B,YACpB,CAAC4B,UACCzB,sBAAsByB,SAASlB,QAAQC,SAASC,UAClD;QAACF;QAAQC;QAASC;KAAQ;IAE5B,OAAO;QACLH,MAAMe;QACNK,WAAWX,WAAWC,OAAO,CAACW,MAAM,GAAG,KAAKZ,WAAWI,WAAW,CAACQ,MAAM,GAAG;QAC5EZ;QACAa,WAAW;YACTC,YAAY;YACZC,aAAaf,WAAWe,WAAW;YACnCC,qBAAqBhB,WAAWgB,mBAAmB;YACnDC,aAAa;QACf;QACAC,YAAY;YACV1B;YACAE;YACAO,SAASD,WAAWC,OAAO;YAC3BC,UAAUF,WAAWmB,UAAU;YAC/B7B,SAASG;QACX;QACAgB;IACF;AACF;AAEA,eAAepB,kBAAiB"}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2026 Aglyn LLC
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
import { type ListRowsFilter, type ListRowsFilterOptions } from './use-list-rows-filter';
|
|
18
|
-
/** How many rows a paged list reads while it is filtered — see below. */
|
|
19
|
-
export declare const PAGED_FILTER_WINDOW = 100;
|
|
20
|
-
/**
|
|
21
|
-
* A paged window over a live list — the shape `usePagedCollection` returns:
|
|
22
|
-
* every row from the first page to the one being read (plus, possibly, one
|
|
23
|
-
* probe row past it), the page, and whether more exist.
|
|
24
|
-
*/
|
|
25
|
-
export interface PagedRowsWindow<Row> {
|
|
26
|
-
/** Every row read so far, page 0 to the current page; may hold a probe row. */
|
|
27
|
-
data?: readonly Row[] | null;
|
|
28
|
-
/** The current page's rows, when nothing narrows the list. */
|
|
29
|
-
rows: readonly Row[];
|
|
30
|
-
hasMore: boolean;
|
|
31
|
-
page: number;
|
|
32
|
-
setPage: (page: number) => void;
|
|
33
|
-
pageSize: number;
|
|
34
|
-
setPageSize: (pageSize: number) => void;
|
|
35
|
-
}
|
|
36
|
-
/** What the list's grid, chips and footer take while it is paged. */
|
|
37
|
-
export interface PagedRowsFilter<Row> extends Omit<ListRowsFilter<Row>, 'rows'> {
|
|
38
|
-
/** The rows the grid shows: the page, or the page of the matches. */
|
|
39
|
-
rows: Row[];
|
|
40
|
-
/** How many rows the window read — what a filter has looked through. */
|
|
41
|
-
read: number;
|
|
42
|
-
/** Spread onto `ListPagination`. */
|
|
43
|
-
pagination: {
|
|
44
|
-
page: number;
|
|
45
|
-
pageSize: number;
|
|
46
|
-
rowCount: number;
|
|
47
|
-
hasMore: boolean;
|
|
48
|
-
onPageChange: (page: number) => void;
|
|
49
|
-
onPageSizeChange: (pageSize: number) => void;
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* The grid's Filters panel and quick search over a PAGED live list
|
|
54
|
-
* (AGL-3317), one that reads a window growing a page at a time rather than
|
|
55
|
-
* every row.
|
|
56
|
-
*
|
|
57
|
-
* Unfiltered it is the pager it wraps: the grid shows the page, and the
|
|
58
|
-
* footer turns it. While a clause or a search word is in force the list
|
|
59
|
-
* matches over EVERYTHING the window has read — every page up to the
|
|
60
|
-
* current one, not the page on screen — and pages the matches instead;
|
|
61
|
-
* turning past the last match widens the window by one more page, so a
|
|
62
|
-
* filter reaches further the further the reader goes. `read` says how far
|
|
63
|
-
* it has looked, for the list to say so while more exist.
|
|
64
|
-
*
|
|
65
|
-
* ## The first filter widens the window once
|
|
66
|
-
*
|
|
67
|
-
* A window of one ten-row page is too little to filter: a search would look
|
|
68
|
-
* through ten rows and call the rest "no match". So the first clause or word
|
|
69
|
-
* widens the window to `filterWindow` rows (default
|
|
70
|
-
* {@link PAGED_FILTER_WINDOW}) — one listener that much wider, for as long as
|
|
71
|
-
* the list is narrowed — and clearing the last one puts the reader back on
|
|
72
|
-
* the page they left.
|
|
73
|
-
* @deprecated AGL-3321: matches over rows a list has loaded. Serve every clause and search
|
|
74
|
-
* word on the query instead — `planListQuery` (`@aglyn/shared-ui-jsx/const/list-query-plan`, with `nameSearchNormalizers`)
|
|
75
|
-
* through `useListQuery` or `applyListQuery`. Removed once no list calls it.
|
|
76
|
-
*/
|
|
77
|
-
export declare function usePagedRowsFilter<Row extends object>(paged: PagedRowsWindow<Row>, options: Omit<ListRowsFilterOptions<Row>, 'rows'> & {
|
|
78
|
-
filterWindow?: number;
|
|
79
|
-
}): PagedRowsFilter<Row>;
|
|
80
|
-
export default usePagedRowsFilter;
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2026 Aglyn LLC
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/ 'use client';
|
|
17
|
-
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
-
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
19
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
20
|
-
import { useListRowsFilter } from "./use-list-rows-filter.js";
|
|
21
|
-
/** How many rows a paged list reads while it is filtered — see below. */ export const PAGED_FILTER_WINDOW = 100;
|
|
22
|
-
/**
|
|
23
|
-
* The grid's Filters panel and quick search over a PAGED live list
|
|
24
|
-
* (AGL-3317), one that reads a window growing a page at a time rather than
|
|
25
|
-
* every row.
|
|
26
|
-
*
|
|
27
|
-
* Unfiltered it is the pager it wraps: the grid shows the page, and the
|
|
28
|
-
* footer turns it. While a clause or a search word is in force the list
|
|
29
|
-
* matches over EVERYTHING the window has read — every page up to the
|
|
30
|
-
* current one, not the page on screen — and pages the matches instead;
|
|
31
|
-
* turning past the last match widens the window by one more page, so a
|
|
32
|
-
* filter reaches further the further the reader goes. `read` says how far
|
|
33
|
-
* it has looked, for the list to say so while more exist.
|
|
34
|
-
*
|
|
35
|
-
* ## The first filter widens the window once
|
|
36
|
-
*
|
|
37
|
-
* A window of one ten-row page is too little to filter: a search would look
|
|
38
|
-
* through ten rows and call the rest "no match". So the first clause or word
|
|
39
|
-
* widens the window to `filterWindow` rows (default
|
|
40
|
-
* {@link PAGED_FILTER_WINDOW}) — one listener that much wider, for as long as
|
|
41
|
-
* the list is narrowed — and clearing the last one puts the reader back on
|
|
42
|
-
* the page they left.
|
|
43
|
-
* @deprecated AGL-3321: matches over rows a list has loaded. Serve every clause and search
|
|
44
|
-
* word on the query instead — `planListQuery` (`@aglyn/shared-ui-jsx/const/list-query-plan`, with `nameSearchNormalizers`)
|
|
45
|
-
* through `useListQuery` or `applyListQuery`. Removed once no list calls it.
|
|
46
|
-
*/ export function usePagedRowsFilter(paged, options) {
|
|
47
|
-
const { pageSize } = paged;
|
|
48
|
-
const { filterWindow = PAGED_FILTER_WINDOW } = options, filterOptions = _object_without_properties_loose(options, [
|
|
49
|
-
"filterWindow"
|
|
50
|
-
]);
|
|
51
|
-
const windowRows = useMemo(()=>{
|
|
52
|
-
var _paged_data;
|
|
53
|
-
return ((_paged_data = paged.data) != null ? _paged_data : paged.rows).slice(0, pageSize * (paged.page + 1));
|
|
54
|
-
}, [
|
|
55
|
-
paged.data,
|
|
56
|
-
paged.rows,
|
|
57
|
-
pageSize,
|
|
58
|
-
paged.page
|
|
59
|
-
]);
|
|
60
|
-
const filter = useListRowsFilter(_extends({}, filterOptions, {
|
|
61
|
-
rows: windowRows
|
|
62
|
-
}));
|
|
63
|
-
const [matchPage, setMatchPage] = useState(0);
|
|
64
|
-
const searchKey = filter.gridFilter.searchWords.join(' ');
|
|
65
|
-
// A narrowed list starts again at its first page.
|
|
66
|
-
useEffect(()=>setMatchPage(0), [
|
|
67
|
-
filter.gridFilter.clauses,
|
|
68
|
-
searchKey
|
|
69
|
-
]);
|
|
70
|
-
/** The page the reader was on before the list was narrowed. */ const before = useRef(null);
|
|
71
|
-
const { filtering } = filter;
|
|
72
|
-
useEffect(()=>{
|
|
73
|
-
if (filtering && before.current === null) {
|
|
74
|
-
before.current = paged.page;
|
|
75
|
-
const widened = Math.max(0, Math.ceil(filterWindow / pageSize) - 1);
|
|
76
|
-
if (widened > paged.page) paged.setPage(widened);
|
|
77
|
-
} else if (!filtering && before.current !== null) {
|
|
78
|
-
paged.setPage(before.current);
|
|
79
|
-
before.current = null;
|
|
80
|
-
}
|
|
81
|
-
// Only the transition into and out of a filter moves the window.
|
|
82
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
83
|
-
}, [
|
|
84
|
-
filtering
|
|
85
|
-
]);
|
|
86
|
-
if (!filter.filtering) {
|
|
87
|
-
return _extends({}, filter, {
|
|
88
|
-
rows: [
|
|
89
|
-
...paged.rows
|
|
90
|
-
],
|
|
91
|
-
read: windowRows.length,
|
|
92
|
-
pagination: {
|
|
93
|
-
page: paged.page,
|
|
94
|
-
pageSize,
|
|
95
|
-
rowCount: paged.rows.length,
|
|
96
|
-
hasMore: paged.hasMore,
|
|
97
|
-
onPageChange: paged.setPage,
|
|
98
|
-
onPageSizeChange: paged.setPageSize
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
const matches = filter.rows;
|
|
103
|
-
const shown = matches.slice(matchPage * pageSize, (matchPage + 1) * pageSize);
|
|
104
|
-
const lastMatchPage = Math.max(0, Math.ceil(matches.length / pageSize) - 1);
|
|
105
|
-
return _extends({}, filter, {
|
|
106
|
-
rows: shown,
|
|
107
|
-
read: windowRows.length,
|
|
108
|
-
pagination: {
|
|
109
|
-
page: matchPage,
|
|
110
|
-
pageSize,
|
|
111
|
-
rowCount: shown.length,
|
|
112
|
-
hasMore: paged.hasMore || matchPage < lastMatchPage,
|
|
113
|
-
onPageChange: (next)=>{
|
|
114
|
-
// Past the matches read so far, the window reads another page first.
|
|
115
|
-
if ((next + 1) * pageSize > matches.length && paged.hasMore) {
|
|
116
|
-
paged.setPage(paged.page + 1);
|
|
117
|
-
}
|
|
118
|
-
setMatchPage(next);
|
|
119
|
-
},
|
|
120
|
-
onPageSizeChange: (next)=>{
|
|
121
|
-
paged.setPageSize(next);
|
|
122
|
-
setMatchPage(0);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
export default usePagedRowsFilter;
|
|
128
|
-
|
|
129
|
-
//# sourceMappingURL=use-paged-rows-filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/hooks/use-paged-rows-filter.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport {\n type ListRowsFilter,\n type ListRowsFilterOptions,\n useListRowsFilter,\n} from './use-list-rows-filter'\n\n/** How many rows a paged list reads while it is filtered — see below. */\nexport const PAGED_FILTER_WINDOW = 100\n\n/**\n * A paged window over a live list — the shape `usePagedCollection` returns:\n * every row from the first page to the one being read (plus, possibly, one\n * probe row past it), the page, and whether more exist.\n */\nexport interface PagedRowsWindow<Row> {\n /** Every row read so far, page 0 to the current page; may hold a probe row. */\n data?: readonly Row[] | null\n /** The current page's rows, when nothing narrows the list. */\n rows: readonly Row[]\n hasMore: boolean\n page: number\n setPage: (page: number) => void\n pageSize: number\n setPageSize: (pageSize: number) => void\n}\n\n/** What the list's grid, chips and footer take while it is paged. */\nexport interface PagedRowsFilter<Row> extends Omit<ListRowsFilter<Row>, 'rows'> {\n /** The rows the grid shows: the page, or the page of the matches. */\n rows: Row[]\n /** How many rows the window read — what a filter has looked through. */\n read: number\n /** Spread onto `ListPagination`. */\n pagination: {\n page: number\n pageSize: number\n rowCount: number\n hasMore: boolean\n onPageChange: (page: number) => void\n onPageSizeChange: (pageSize: number) => void\n }\n}\n\n/**\n * The grid's Filters panel and quick search over a PAGED live list\n * (AGL-3317), one that reads a window growing a page at a time rather than\n * every row.\n *\n * Unfiltered it is the pager it wraps: the grid shows the page, and the\n * footer turns it. While a clause or a search word is in force the list\n * matches over EVERYTHING the window has read — every page up to the\n * current one, not the page on screen — and pages the matches instead;\n * turning past the last match widens the window by one more page, so a\n * filter reaches further the further the reader goes. `read` says how far\n * it has looked, for the list to say so while more exist.\n *\n * ## The first filter widens the window once\n *\n * A window of one ten-row page is too little to filter: a search would look\n * through ten rows and call the rest \"no match\". So the first clause or word\n * widens the window to `filterWindow` rows (default\n * {@link PAGED_FILTER_WINDOW}) — one listener that much wider, for as long as\n * the list is narrowed — and clearing the last one puts the reader back on\n * the page they left.\n * @deprecated AGL-3321: matches over rows a list has loaded. Serve every clause and search\n * word on the query instead — `planListQuery` (`@aglyn/shared-ui-jsx/const/list-query-plan`, with `nameSearchNormalizers`)\n * through `useListQuery` or `applyListQuery`. Removed once no list calls it.\n*/\nexport function usePagedRowsFilter<Row extends object>(\n paged: PagedRowsWindow<Row>,\n options: Omit<ListRowsFilterOptions<Row>, 'rows'> & { filterWindow?: number },\n): PagedRowsFilter<Row> {\n const { pageSize } = paged\n const { filterWindow = PAGED_FILTER_WINDOW, ...filterOptions } = options\n const windowRows = useMemo(\n () => (paged.data ?? paged.rows).slice(0, pageSize * (paged.page + 1)),\n [paged.data, paged.rows, pageSize, paged.page],\n )\n const filter = useListRowsFilter({ ...filterOptions, rows: windowRows })\n const [matchPage, setMatchPage] = useState(0)\n const searchKey = filter.gridFilter.searchWords.join(' ')\n // A narrowed list starts again at its first page.\n useEffect(() => setMatchPage(0), [filter.gridFilter.clauses, searchKey])\n\n /** The page the reader was on before the list was narrowed. */\n const before = useRef<number | null>(null)\n const { filtering } = filter\n useEffect(() => {\n if (filtering && before.current === null) {\n before.current = paged.page\n const widened = Math.max(0, Math.ceil(filterWindow / pageSize) - 1)\n if (widened > paged.page) paged.setPage(widened)\n } else if (!filtering && before.current !== null) {\n paged.setPage(before.current)\n before.current = null\n }\n // Only the transition into and out of a filter moves the window.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [filtering])\n\n if (!filter.filtering) {\n return {\n ...filter,\n rows: [...paged.rows],\n read: windowRows.length,\n pagination: {\n page: paged.page,\n pageSize,\n rowCount: paged.rows.length,\n hasMore: paged.hasMore,\n onPageChange: paged.setPage,\n onPageSizeChange: paged.setPageSize,\n },\n }\n }\n const matches = filter.rows\n const shown = matches.slice(matchPage * pageSize, (matchPage + 1) * pageSize)\n const lastMatchPage = Math.max(0, Math.ceil(matches.length / pageSize) - 1)\n return {\n ...filter,\n rows: shown,\n read: windowRows.length,\n pagination: {\n page: matchPage,\n pageSize,\n rowCount: shown.length,\n hasMore: paged.hasMore || matchPage < lastMatchPage,\n onPageChange: (next) => {\n // Past the matches read so far, the window reads another page first.\n if ((next + 1) * pageSize > matches.length && paged.hasMore) {\n paged.setPage(paged.page + 1)\n }\n setMatchPage(next)\n },\n onPageSizeChange: (next) => {\n paged.setPageSize(next)\n setMatchPage(0)\n },\n },\n }\n}\n\nexport default usePagedRowsFilter\n"],"names":["useEffect","useMemo","useRef","useState","useListRowsFilter","PAGED_FILTER_WINDOW","usePagedRowsFilter","paged","options","pageSize","filterWindow","filterOptions","windowRows","data","rows","slice","page","filter","matchPage","setMatchPage","searchKey","gridFilter","searchWords","join","clauses","before","filtering","current","widened","Math","max","ceil","setPage","read","length","pagination","rowCount","hasMore","onPageChange","onPageSizeChange","setPageSize","matches","shown","lastMatchPage","next"],"mappings":"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"}
|