@aglyn/shared-ui-jsx 1.0.0-beta.197 → 1.0.0-beta.199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
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 ListFilterField, type ListFilterRequest } from './list-filter';
18
+ /**
19
+ * How the written search fields were normalized, so a typed value becomes the
20
+ * key the query can match: the lower-cased key (`equals`, `startsWith`), the
21
+ * one word-prefix token (`contains`, search), and the reversed key
22
+ * (`endsWith`). `maxPrefix` is the longest token a writer stores.
23
+ */
24
+ export interface ListQueryNormalizers {
25
+ key(value: string): string;
26
+ token(value: string): string;
27
+ reversed(value: string): string;
28
+ maxPrefix: number;
29
+ }
30
+ /** A predicate on the query, SDK-free. `path` `__name__` is the document id. */
31
+ export type ListQueryOp = '==' | '!=' | '<' | '<=' | '>' | '>=' | 'in' | 'array-contains' | 'array-contains-any';
32
+ export type ListQueryValue = string | number | boolean | null | Date | readonly (string | number)[];
33
+ export interface ListQueryFilter {
34
+ path: string;
35
+ op: ListQueryOp;
36
+ value: ListQueryValue;
37
+ }
38
+ export interface ListQuerySort {
39
+ path: string;
40
+ direction: 'asc' | 'desc';
41
+ /** The grid column this order sorts, when the list lets the grid sort by it. */
42
+ column?: string;
43
+ }
44
+ /** The document id, as a path. */
45
+ export declare const LIST_QUERY_ID_PATH = "__name__";
46
+ /** Firestore's cap on disjunctions — `in` values times `array-contains-any` values. */
47
+ export declare const LIST_QUERY_DISJUNCTIONS = 30;
48
+ export interface ListQueryDeclaration {
49
+ /** Every field the Filters panel may name. */
50
+ fields: readonly ListFilterField[];
51
+ /**
52
+ * The orders the list offers, its default FIRST. The query takes no other:
53
+ * each is a composite the index file carries for every filterable field.
54
+ */
55
+ sorts: readonly ListQuerySort[];
56
+ /**
57
+ * The quick search: the token array every write stamps (see
58
+ * `nameSearchTokens`), queried with `array-contains` on one typed word.
59
+ * Absent, the list offers no search box.
60
+ */
61
+ search?: {
62
+ tokensPath: string;
63
+ /**
64
+ * Under a scope clause the search cannot be a SECOND array clause, so a
65
+ * scoped list writes `<scopeToken><join><prefix>` tokens and the query
66
+ * asks `array-contains-any` over the scope's tokens joined to the word —
67
+ * one array clause that answers both.
68
+ */
69
+ scoped?: {
70
+ tokensPath: string;
71
+ join: string;
72
+ };
73
+ };
74
+ /**
75
+ * Keys a presence-map field (`keysOf`) is filtered by, for the index
76
+ * enumeration: `sources.form`, `sources.order`, …
77
+ */
78
+ keys?: Readonly<Record<string, readonly string[]>>;
79
+ }
80
+ /** What the list asks this time. */
81
+ export interface ListQueryRequest {
82
+ clauses: readonly ListFilterRequest[];
83
+ /** The quick search's words. */
84
+ search?: readonly string[];
85
+ /** The order asked for; a sort the declaration does not offer is ignored. */
86
+ sort?: ListQuerySort | null;
87
+ /**
88
+ * Predicates the list always applies — its scope — which count against
89
+ * the same limits. An `array-contains-any` scope is what a scoped search
90
+ * folds into (`declaration.search.scoped`).
91
+ */
92
+ base?: readonly ListQueryFilter[];
93
+ }
94
+ export interface ListQueryRefusal {
95
+ /** The clause refused, or `search`. */
96
+ clause: ListFilterRequest | 'search';
97
+ reason: string;
98
+ }
99
+ export interface ListQueryPlan {
100
+ /** Every predicate, base included, in the order the SDK should add them. */
101
+ filters: ListQueryFilter[];
102
+ /** The one order: the range field's when there is one, else the sort. */
103
+ orderBy: ListQuerySort;
104
+ /** The clauses on the query. */
105
+ served: ListFilterRequest[];
106
+ /** The search word on the query, or null. */
107
+ searched: string | null;
108
+ /** What was asked and could not be put on the query, with why. */
109
+ refused: ListQueryRefusal[];
110
+ /** Said to the reader about what WAS served — e.g. one search word of two. */
111
+ notices: string[];
112
+ }
113
+ /**
114
+ * Every clause and the search, as ONE query — or as much of it as one query
115
+ * can hold, with the rest refused by name.
116
+ *
117
+ * Order of claim: the base (the list's scope) first, then the search, then
118
+ * the clauses in the order they were added. A clause that would be a second
119
+ * array clause, a second inequality field or push the disjunctions past
120
+ * thirty is refused, and the list shows the refusal beside its chip; the
121
+ * clauses before it stand. The search is claimed before the clauses because
122
+ * it is the thing a reader typed last and looks at.
123
+ */
124
+ export declare function planListQuery(declaration: ListQueryDeclaration, request: ListQueryRequest, names: ListQueryNormalizers): ListQueryPlan;
125
+ /** A composite the plan's shapes need, in the index file's own terms. */
126
+ export interface ListQueryIndex {
127
+ fields: Array<{
128
+ fieldPath: string;
129
+ order?: 'ASCENDING' | 'DESCENDING';
130
+ arrayConfig?: 'CONTAINS';
131
+ }>;
132
+ }
133
+ /**
134
+ * Every composite a declaration's queries can need, under index merging:
135
+ * one `(predicate field, order)` index per equality or array field and per
136
+ * order the list can take — its sorts, and the order each range imposes.
137
+ *
138
+ * `base` names the scope predicates the list always applies (their paths
139
+ * and whether they are array clauses), which need their own index per order
140
+ * like any other equality. Pinned by each list's spec against
141
+ * `cloud/firebase-firestore.indexes.json`.
142
+ */
143
+ export declare function listQueryIndexes(declaration: ListQueryDeclaration, base?: readonly {
144
+ path: string;
145
+ array?: boolean;
146
+ }[]): ListQueryIndex[];
147
+ /** An index entry as `cloud/firebase-firestore.indexes.json` stores it. */
148
+ interface IndexFileEntry {
149
+ collectionGroup: string;
150
+ queryScope: string;
151
+ fields: Array<{
152
+ fieldPath: string;
153
+ order?: string;
154
+ arrayConfig?: string;
155
+ }>;
156
+ }
157
+ /**
158
+ * The composites a declaration needs that an index file does not hold — what
159
+ * a list's spec asserts is empty, so a declared filter cannot ship without
160
+ * the index that serves it.
161
+ */
162
+ export declare function missingListQueryIndexes(file: {
163
+ indexes: readonly IndexFileEntry[];
164
+ }, collectionGroup: string, needed: readonly ListQueryIndex[], queryScope?: 'COLLECTION' | 'COLLECTION_GROUP'): ListQueryIndex[];
165
+ export {};