@object-ui/components 17.6.0 → 18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9618 -0
- package/README.md +27 -3
- package/dist/custom/RecordTitleChip.d.ts +4 -3
- package/dist/custom/button-group.d.ts +1 -1
- package/dist/custom/combobox.d.ts +2 -4
- package/dist/custom/dialog-viewport-gutter.d.ts +37 -0
- package/dist/custom/empty-state-link.d.ts +63 -0
- package/dist/custom/empty.d.ts +16 -4
- package/dist/custom/field.d.ts +1 -1
- package/dist/custom/filter-builder.d.ts +225 -77
- package/dist/custom/grouping-editor.d.ts +4 -0
- package/dist/custom/horizontal-overflow.d.ts +18 -0
- package/dist/custom/index.d.ts +4 -1
- package/dist/custom/item.d.ts +1 -1
- package/dist/custom/kbd.d.ts +1 -1
- package/dist/custom/mobile-dialog-content.d.ts +22 -1
- package/dist/custom/navigation-overlay.d.ts +105 -0
- package/dist/custom/refresh-indicator.d.ts +8 -2
- package/dist/custom/sort-builder.d.ts +8 -0
- package/dist/custom/use-horizontal-overflow.d.ts +36 -0
- package/dist/custom/view-states.d.ts +74 -1
- package/dist/hooks/related-count-store.d.ts +81 -28
- package/dist/index.css +345 -361
- package/dist/index.d.ts +11 -3
- package/dist/index.js +8480 -6628
- package/dist/index.umd.cjs +11 -15
- package/dist/lib/close-label.d.ts +1 -2
- package/dist/lib/date-fns-locale.d.ts +41 -0
- package/dist/lib/inline-markdown.d.ts +64 -0
- package/dist/lib/lazy-icon.d.ts +32 -1
- package/dist/lib/lucide-record-icon-names.d.ts +30 -0
- package/dist/lib/utils.d.ts +113 -0
- package/dist/renderers/action/action-bar.d.ts +8 -36
- package/dist/renderers/action/action-button.d.ts +15 -4
- package/dist/renderers/action/action-group.d.ts +5 -4
- package/dist/renderers/action/action-icon.d.ts +12 -2
- package/dist/renderers/action/action-menu.d.ts +5 -2
- package/dist/renderers/action/auto-trigger.d.ts +19 -4
- package/dist/renderers/action/disabled-reason.d.ts +49 -0
- package/dist/renderers/action/resolve-icon.d.ts +27 -2
- package/dist/renderers/action/static-params.d.ts +71 -0
- package/dist/renderers/action/visibility-gate.d.ts +11 -3
- package/dist/renderers/basic/data-list.d.ts +2 -1
- package/dist/renderers/basic/elements.d.ts +2 -0
- package/dist/renderers/basic/html-elements.d.ts +7 -3
- package/dist/renderers/basic/readProps.d.ts +60 -0
- package/dist/renderers/basic/record-picker.d.ts +3 -2
- package/dist/renderers/complex/data-table.d.ts +31 -14
- package/dist/renderers/complex/dataTableBindDiagnostic.d.ts +187 -0
- package/dist/renderers/layout/box.d.ts +8 -0
- package/dist/renderers/layout/containers.d.ts +28 -23
- package/dist/renderers/layout/page-block-grid.d.ts +29 -0
- package/dist/renderers/layout/page-block-span.d.ts +50 -0
- package/dist/renderers/layout/page-description-context.d.ts +14 -0
- package/dist/renderers/layout/page-print.d.ts +14 -0
- package/dist/renderers/layout/page-region-posture.d.ts +82 -0
- package/dist/renderers/layout/react-page.d.ts +4 -0
- package/dist/renderers/navigation/sidebar.d.ts +31 -0
- package/dist/ui/badge.d.ts +1 -1
- package/dist/ui/button.d.ts +1 -1
- package/dist/ui/calendar.d.ts +2 -1
- package/dist/ui/command.d.ts +7 -7
- package/dist/ui/index.d.ts +0 -1
- package/dist/ui/input-otp.d.ts +2 -2
- package/dist/ui/sheet.d.ts +1 -1
- package/dist/ui/sidebar.d.ts +2 -1
- package/package.json +14 -15
- package/dist/SchemaRenderer.d.ts +0 -4
- package/dist/custom/export-progress-dialog.d.ts +0 -43
- package/dist/hooks/use-export-job.d.ts +0 -34
- package/dist/ui/chart.d.ts +0 -56
- package/dist/ui/toast.d.ts +0 -22
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FilterBuilderCondition as AuthoredFilterBuilderCondition, FilterGroup as AuthoredFilterGroup } from '@object-ui/types';
|
|
1
2
|
/**
|
|
2
3
|
* ObjectUI
|
|
3
4
|
* Copyright (c) 2024-present ObjectStack Inc.
|
|
@@ -16,22 +17,53 @@ import * as React from "react";
|
|
|
16
17
|
* and `operator` here is the builder's own dropdown vocabulary
|
|
17
18
|
* (`FILTER_BUILDER_OPERATORS`), not the spec's `$`-tokens.
|
|
18
19
|
*
|
|
19
|
-
* `@object-ui/types`
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* DERIVED from `@object-ui/types`' `FilterBuilderCondition` (objectui#9306).
|
|
21
|
+
* That declaration is the one name authority for the row; this one takes every
|
|
22
|
+
* member from it (`id`, required since objectui#8415, and `field`) and restates
|
|
23
|
+
* exactly two, each a named extension:
|
|
24
|
+
*
|
|
25
|
+
* - `operator` — {@link FilterBuilderOperator}: the protocol's ids, which is
|
|
26
|
+
* what the authority declares, plus the opt-in `exists` / `notExists` the
|
|
27
|
+
* protocol has no member for (objectui#9559 ruling B keeps them opt-in and
|
|
28
|
+
* unfolded). It was `string`, which let a caller hand the builder an id no
|
|
29
|
+
* dropdown entry can hold.
|
|
30
|
+
* - `value` — REQUIRED and narrowed to the scalar-or-list union this builder
|
|
31
|
+
* edits, where the authority declares `value?: any`. Every exported helper
|
|
32
|
+
* below that takes a row's value (`reshapeFilterValue`, `retypeFilterValue`,
|
|
33
|
+
* `narrowFilterValueToOptions`, …) is typed on this member, so `any` here
|
|
34
|
+
* would switch their checking off in silence.
|
|
35
|
+
*
|
|
36
|
+
* Its own NAME, not the authority's (objectui#6349, batch 12). Under the
|
|
37
|
+
* authority's name this was a second declaration of `FilterBuilderCondition`
|
|
38
|
+
* with a different shape: the two are assignable in neither direction (the
|
|
39
|
+
* operator blocks one way, the value's requiredness the other), so an
|
|
40
|
+
* auto-import picked one of two rows by package. `FilterBuilderCondition` now
|
|
41
|
+
* means the authored row in `@object-ui/types` only, and this specialisation
|
|
42
|
+
* is named for the builder that edits it.
|
|
24
43
|
*/
|
|
25
|
-
export interface
|
|
26
|
-
|
|
27
|
-
field: string;
|
|
28
|
-
operator: string;
|
|
44
|
+
export interface FilterBuilderRow extends Omit<AuthoredFilterBuilderCondition, "operator" | "value"> {
|
|
45
|
+
operator: FilterBuilderOperator;
|
|
29
46
|
value: string | number | boolean | (string | number | boolean)[];
|
|
30
47
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The group the FilterBuilder edits: one `logic` over FLAT rows.
|
|
50
|
+
*
|
|
51
|
+
* DERIVED from `@object-ui/types`' `FilterGroup` like the row above
|
|
52
|
+
* (objectui#9306), and named apart from it for the same reason
|
|
53
|
+
* (objectui#6349, batch 12): `FilterGroup` means the authored group only. Only
|
|
54
|
+
* `conditions` is restated, to hold THIS package's row; `id` and `logic` are
|
|
55
|
+
* the authority's own. So `id` is OPTIONAL here, as it is there: nothing in
|
|
56
|
+
* this builder reads a group's `id`, `onChange` hands back whatever group the
|
|
57
|
+
* host passed (an id-less group comes back id-less), and only `EMPTY_GROUP`
|
|
58
|
+
* invents one. The `id: string` this package used to declare described a
|
|
59
|
+
* group the builder never guaranteed.
|
|
60
|
+
*
|
|
61
|
+
* `conditions` is flat because the builder is: it draws each entry as one row
|
|
62
|
+
* and has no control that creates a group. The authority retired nested
|
|
63
|
+
* sub-groups in the same change and its zod mirror refuses one by name.
|
|
64
|
+
*/
|
|
65
|
+
export interface FilterBuilderRowGroup extends Omit<AuthoredFilterGroup, "conditions"> {
|
|
66
|
+
conditions: FilterBuilderRow[];
|
|
35
67
|
}
|
|
36
68
|
export interface FilterBuilderProps {
|
|
37
69
|
fields?: Array<{
|
|
@@ -49,8 +81,8 @@ export interface FilterBuilderProps {
|
|
|
49
81
|
/** ID field on the referenced object (defaults to "id") */
|
|
50
82
|
idField?: string;
|
|
51
83
|
}>;
|
|
52
|
-
value?:
|
|
53
|
-
onChange?: (value:
|
|
84
|
+
value?: FilterBuilderRowGroup;
|
|
85
|
+
onChange?: (value: FilterBuilderRowGroup) => void;
|
|
54
86
|
className?: string;
|
|
55
87
|
showClearAll?: boolean;
|
|
56
88
|
/**
|
|
@@ -69,34 +101,34 @@ declare const defaultOperators: readonly [{
|
|
|
69
101
|
readonly value: "equals";
|
|
70
102
|
readonly label: "Equals";
|
|
71
103
|
}, {
|
|
72
|
-
readonly value: "
|
|
104
|
+
readonly value: "not_equals";
|
|
73
105
|
readonly label: "Does not equal";
|
|
74
106
|
}, {
|
|
75
107
|
readonly value: "contains";
|
|
76
108
|
readonly label: "Contains";
|
|
77
109
|
}, {
|
|
78
|
-
readonly value: "
|
|
110
|
+
readonly value: "icontains";
|
|
79
111
|
readonly label: "Contains (ignore case)";
|
|
80
112
|
}, {
|
|
81
|
-
readonly value: "
|
|
113
|
+
readonly value: "not_contains";
|
|
82
114
|
readonly label: "Does not contain";
|
|
83
115
|
}, {
|
|
84
|
-
readonly value: "
|
|
116
|
+
readonly value: "is_empty";
|
|
85
117
|
readonly label: "Is empty";
|
|
86
118
|
}, {
|
|
87
|
-
readonly value: "
|
|
119
|
+
readonly value: "is_not_empty";
|
|
88
120
|
readonly label: "Is not empty";
|
|
89
121
|
}, {
|
|
90
|
-
readonly value: "
|
|
122
|
+
readonly value: "greater_than";
|
|
91
123
|
readonly label: "Greater than";
|
|
92
124
|
}, {
|
|
93
|
-
readonly value: "
|
|
125
|
+
readonly value: "less_than";
|
|
94
126
|
readonly label: "Less than";
|
|
95
127
|
}, {
|
|
96
|
-
readonly value: "
|
|
128
|
+
readonly value: "greater_than_or_equal";
|
|
97
129
|
readonly label: "Greater than or equal";
|
|
98
130
|
}, {
|
|
99
|
-
readonly value: "
|
|
131
|
+
readonly value: "less_than_or_equal";
|
|
100
132
|
readonly label: "Less than or equal";
|
|
101
133
|
}, {
|
|
102
134
|
readonly value: "before";
|
|
@@ -111,19 +143,19 @@ declare const defaultOperators: readonly [{
|
|
|
111
143
|
readonly value: "in";
|
|
112
144
|
readonly label: "In";
|
|
113
145
|
}, {
|
|
114
|
-
readonly value: "
|
|
146
|
+
readonly value: "not_in";
|
|
115
147
|
readonly label: "Not in";
|
|
116
148
|
}, {
|
|
117
|
-
readonly value: "
|
|
149
|
+
readonly value: "starts_with";
|
|
118
150
|
readonly label: "Starts with";
|
|
119
151
|
}, {
|
|
120
|
-
readonly value: "
|
|
152
|
+
readonly value: "ends_with";
|
|
121
153
|
readonly label: "Ends with";
|
|
122
154
|
}, {
|
|
123
|
-
readonly value: "
|
|
155
|
+
readonly value: "is_null";
|
|
124
156
|
readonly label: "Is null";
|
|
125
157
|
}, {
|
|
126
|
-
readonly value: "
|
|
158
|
+
readonly value: "is_not_null";
|
|
127
159
|
readonly label: "Is not null";
|
|
128
160
|
}, {
|
|
129
161
|
readonly value: "exists";
|
|
@@ -137,30 +169,79 @@ declare const defaultOperators: readonly [{
|
|
|
137
169
|
* hold, derived from the operators it actually renders. Includes the opt-in
|
|
138
170
|
* ids: they are drawable, just not offered unconditionally.
|
|
139
171
|
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
172
|
+
* Since objectui#9306 these ARE the protocol's ids — the twenty members of the
|
|
173
|
+
* spec's `VIEW_FILTER_OPERATORS`, plus the opt-in `exists` / `notExists` the
|
|
174
|
+
* protocol has no member for — so a table that maps the spec's vocabulary onto
|
|
175
|
+
* this one is an identity over the twenty. It is still exported because those
|
|
176
|
+
* tables, and the parity pins over them, assert against this list rather than
|
|
177
|
+
* restating it: a value that is not in it produces a condition row whose
|
|
178
|
+
* operator select has nothing to select.
|
|
179
|
+
*/
|
|
180
|
+
export declare const FILTER_BUILDER_OPERATORS: ("in" | "starts_with" | "ends_with" | "contains" | "equals" | "not_equals" | "greater_than" | "greater_than_or_equal" | "less_than" | "less_than_or_equal" | "before" | "after" | "not_in" | "not_contains" | "icontains" | "between" | "is_null" | "is_not_null" | "is_empty" | "is_not_empty" | "exists" | "notExists")[];
|
|
181
|
+
/**
|
|
182
|
+
* An operator id the FilterBuilder can render: the spec's `ViewFilterOperator`
|
|
183
|
+
* plus the two opt-in existence ids (objectui#9306). A type-level pin in
|
|
184
|
+
* `filter-builder-protocol-ids-9306.test.tsx` holds it EQUAL to that union, so
|
|
185
|
+
* a protocol member added upstream fails to compile there until the dropdown
|
|
186
|
+
* offers it.
|
|
146
187
|
*/
|
|
147
|
-
export declare const FILTER_BUILDER_OPERATORS: ("endsWith" | "startsWith" | "in" | "after" | "equals" | "notEquals" | "contains" | "containsCaseInsensitive" | "notContains" | "isEmpty" | "isNotEmpty" | "greaterThan" | "lessThan" | "greaterOrEqual" | "lessOrEqual" | "before" | "between" | "notIn" | "isNull" | "isNotNull" | "exists" | "notExists")[];
|
|
148
|
-
/** An operator id the FilterBuilder can render. */
|
|
149
188
|
export type FilterBuilderOperator = (typeof defaultOperators)[number]['value'];
|
|
150
189
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
190
|
+
* The spelling a stored operator is READ as — the protocol id for every
|
|
191
|
+
* spelling the spec or this builder ever wrote (objectui#9306).
|
|
192
|
+
*
|
|
193
|
+
* The ruling this executes: camelCase is the deprecated alias form
|
|
194
|
+
* (objectui#7993), accepted on read and rewritten on write. So a filter stored
|
|
195
|
+
* as `{ operator: 'greaterOrEqual' }` keeps loading — it is folded here, through
|
|
196
|
+
* the spec's own `normalizeFilterOperator`, onto `greater_than_or_equal` — and
|
|
197
|
+
* the builder holds and emits that canonical id from then on, so the next write
|
|
198
|
+
* the author makes stores it. A lossless conversion on the read side, ⛔ not a
|
|
199
|
+
* second vocabulary: nothing this builder EMITS is ever a camelCase id.
|
|
200
|
+
*
|
|
201
|
+
* An id nothing folds (`exists`, `notExists`, a spelling from no vocabulary)
|
|
202
|
+
* comes back unchanged, exactly as the spec's normalizer returns it: inventing
|
|
203
|
+
* a mapping for a word the protocol does not contain would be a claim, not a
|
|
204
|
+
* repair.
|
|
205
|
+
*
|
|
206
|
+
* ⚠️ One guard on the spec's answer, and only because the builder now STORES
|
|
207
|
+
* what this returns (before objectui#9306 the fold was used for comparison
|
|
208
|
+
* only). `normalizeFilterOperator` is declared to return a string, but it
|
|
209
|
+
* looks the spelling up on a plain object, so an `Object.prototype` key comes
|
|
210
|
+
* back as whatever the prototype holds — `'constructor'` returns the `Object`
|
|
211
|
+
* function, measured on `@objectstack/spec` 17.4.0. Held in a row and written
|
|
212
|
+
* back, that would drop the row's operator on serialisation. A non-string
|
|
213
|
+
* answer is therefore treated as "nothing folds" and the spelling is kept;
|
|
214
|
+
* the defect itself belongs to the spec and is reported there, not patched
|
|
215
|
+
* around here in any other way.
|
|
216
|
+
*/
|
|
217
|
+
export declare function normalizeFilterBuilderOperator(operator: string): string;
|
|
218
|
+
/**
|
|
219
|
+
* Operator ids — this dropdown's own ids, which are the protocol's canonical
|
|
220
|
+
* spellings since objectui#9306 — for which this builder renders no value
|
|
221
|
+
* input, so "no value" is the row's FINISHED state, not an unfinished one
|
|
222
|
+
* (objectui#4744).
|
|
153
223
|
*
|
|
154
224
|
* This is the source of truth for that distinction, and it lives here because
|
|
155
|
-
* this component is the thing that decides it
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
225
|
+
* this component is the thing that decides it. But membership here is not the
|
|
226
|
+
* whole question: `needsValueInput` below asks it of the row's spelling AFTER
|
|
227
|
+
* {@link normalizeFilterBuilderOperator} (objectui#9302), so the gate answers
|
|
228
|
+
* "no value" for spellings that are NOT members — the deprecated camelCase ids
|
|
229
|
+
* a stored filter may still carry, and the alias rows the spec publishes for
|
|
230
|
+
* those same operators. A consumer holding a spelling that did not come from
|
|
231
|
+
* this dropdown must therefore fold it before asking, and fold this set's own
|
|
232
|
+
* members through the same normalizer too — the spec's `normalizeFilterOperator`
|
|
233
|
+
* is the identity on them, so that fold costs nothing and keeps the consumer
|
|
234
|
+
* correct whichever vocabulary this set is written in. How much wider the
|
|
235
|
+
* gate's preimage is is NOT restated here: the pin
|
|
236
|
+
* `filter-builder-valueless-canonical-spelling-9302.test.tsx` walks the
|
|
237
|
+
* spec's two published tables and names every row it measures, which is the
|
|
238
|
+
* only form of that answer that moves when those tables do (AGENTS.md #9).
|
|
239
|
+
*
|
|
240
|
+
* Every consumer that has to tell a complete value-less row from a half-filled
|
|
241
|
+
* one reads the membership FROM here rather than restating it:
|
|
159
242
|
*
|
|
160
243
|
* - `plugin-list`'s `convertFilterGroupToAST` — what the live grid QUERIES;
|
|
161
|
-
* - `app-shell`'s `foldFilterGroupToSpecRules` — what a saved view PERSISTS
|
|
162
|
-
* (its `VALUELESS_FILTER_OPERATORS` is this set plus the canonical spec
|
|
163
|
-
* spellings, which only that layer sees).
|
|
244
|
+
* - `app-shell`'s `foldFilterGroupToSpecRules` — what a saved view PERSISTS.
|
|
164
245
|
*
|
|
165
246
|
* Placement is forced by the dependency graph — `app-shell` depends on
|
|
166
247
|
* `plugin-list` depends on this package, so this is the only module all three
|
|
@@ -168,11 +249,12 @@ export type FilterBuilderOperator = (typeof defaultOperators)[number]['value'];
|
|
|
168
249
|
* states is a fact about what this dropdown draws.
|
|
169
250
|
*
|
|
170
251
|
* Why it exists at all: each consumer used to keep its own copy, and the
|
|
171
|
-
* live-grid copy listed only
|
|
172
|
-
* `{ operator: 'equals', value: '' }` and the operator dropdown
|
|
173
|
-
* `value`, so picking **Is null** as the first action left
|
|
174
|
-
* grid read that as an unfinished row, dropped it, and
|
|
175
|
-
* all while the panel showed one. Silent, and every
|
|
252
|
+
* live-grid copy listed only the two empty-string operators. A fresh row is
|
|
253
|
+
* seeded `{ operator: 'equals', value: '' }` and the operator dropdown
|
|
254
|
+
* preserves `value`, so picking **Is null** as the first action left
|
|
255
|
+
* `value: ''` — the grid read that as an unfinished row, dropped it, and
|
|
256
|
+
* applied NO filter at all while the panel showed one. Silent, and every
|
|
257
|
+
* record came back.
|
|
176
258
|
*
|
|
177
259
|
* `exists` / `notExists` stay listed even though `OPT_IN_OPERATORS` withholds
|
|
178
260
|
* them from most consumers (objectui#4736): the builder still draws them
|
|
@@ -193,13 +275,14 @@ export declare const VALUELESS_FILTER_BUILDER_OPERATORS: ReadonlySet<string>;
|
|
|
193
275
|
*/
|
|
194
276
|
export type FilterValueArity = "scalar" | "list" | "pair";
|
|
195
277
|
/**
|
|
196
|
-
* Which value shape `operator` takes,
|
|
278
|
+
* Which value shape `operator` takes, whichever spelling it arrives in.
|
|
197
279
|
*
|
|
198
|
-
* The argument is folded through
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
280
|
+
* The argument is folded through {@link normalizeFilterBuilderOperator} — the
|
|
281
|
+
* spec's own `normalizeFilterOperator` plus the builder's one unfolded legacy
|
|
282
|
+
* id — first, so the canonical id this dropdown emits (`not_in`) and the
|
|
283
|
+
* deprecated alias a stored filter may still carry (`notIn`) land on the same
|
|
284
|
+
* answer. That fold is the whole point: one vocabulary, declared upstream,
|
|
285
|
+
* consulted here — not a second local dialect kept in sync by hand.
|
|
203
286
|
*
|
|
204
287
|
* @internal exported for tests
|
|
205
288
|
*/
|
|
@@ -224,13 +307,13 @@ export declare function filterValueArity(operator: string): FilterValueArity;
|
|
|
224
307
|
*
|
|
225
308
|
* @internal exported for tests
|
|
226
309
|
*/
|
|
227
|
-
export declare function reshapeFilterValue(value:
|
|
310
|
+
export declare function reshapeFilterValue(value: FilterBuilderRow["value"], nextOperator: string): FilterBuilderRow["value"];
|
|
228
311
|
/**
|
|
229
312
|
* The operator a row keeps after its FIELD is changed, given the operators the
|
|
230
313
|
* NEW field offers (objectui#4768).
|
|
231
314
|
*
|
|
232
315
|
* Each field type has its own operator bucket, and the buckets are not nested:
|
|
233
|
-
* a `select` column offers `in` / `
|
|
316
|
+
* a `select` column offers `in` / `not_in`, a `text` column does not. Changing
|
|
234
317
|
* the field used to write `{ field }` alone, so the row's operator survived
|
|
235
318
|
* into a bucket that no longer contains it — `in` on a text column. The Radix
|
|
236
319
|
* trigger then had nothing to render (its `SelectValue` matches against the
|
|
@@ -243,22 +326,80 @@ export declare function reshapeFilterValue(value: FilterBuilderCondition["value"
|
|
|
243
326
|
* entry (`equals` for every bucket this builder draws), and the caller then
|
|
244
327
|
* re-shapes the value for that operator's family.
|
|
245
328
|
*
|
|
246
|
-
* Membership is decided CANONICALLY, through
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
* spellings differ. The fold is safe
|
|
252
|
-
* INJECTIVE over this builder's vocabulary —
|
|
253
|
-
* normalize to 22 distinct canonical
|
|
254
|
-
* `filter-builder-field-switch-operator.test.tsx` — so no
|
|
255
|
-
* operators can ever collapse onto one another.
|
|
329
|
+
* Membership is decided CANONICALLY, through
|
|
330
|
+
* {@link normalizeFilterBuilderOperator} — the same fold `filterValueArity`
|
|
331
|
+
* uses. A caller can hand this helper a row spelled with the deprecated alias
|
|
332
|
+
* `notIn` while the dropdown lists the protocol id `not_in`; those are one
|
|
333
|
+
* operator, so a select→lookup switch must not silently rewrite the author's
|
|
334
|
+
* operator to `equals` just because the two spellings differ. The fold is safe
|
|
335
|
+
* to compare through because it is INJECTIVE over this builder's vocabulary —
|
|
336
|
+
* all 22 ids in `defaultOperators` normalize to 22 distinct canonical
|
|
337
|
+
* operators, pinned in `filter-builder-field-switch-operator.test.tsx` — so no
|
|
338
|
+
* two OFFERED operators can ever collapse onto one another.
|
|
256
339
|
*
|
|
257
340
|
* @internal exported for tests
|
|
258
341
|
*/
|
|
259
342
|
export declare function reconcileOperatorForField(operator: string, offeredOperators: ReadonlyArray<{
|
|
260
343
|
value: string;
|
|
261
344
|
}>): string;
|
|
345
|
+
/**
|
|
346
|
+
* The offered id the operator trigger COMPARES against — the last site in this
|
|
347
|
+
* component that read the operator literally instead of through the spec's
|
|
348
|
+
* fold (objectui#7561).
|
|
349
|
+
*
|
|
350
|
+
* Radix matches `SelectValue` against the `SelectItem`s actually MOUNTED, and
|
|
351
|
+
* the mounted ids are this builder's own vocabulary — the protocol's canonical
|
|
352
|
+
* ids since objectui#9306 (they were camelCase when this helper was written). A
|
|
353
|
+
* row can hold the operator under another spelling of the SAME operator and
|
|
354
|
+
* still be perfectly valid:
|
|
355
|
+
*
|
|
356
|
+
* - a deprecated camelCase alias such as `greaterThan`, which a filter saved
|
|
357
|
+
* before objectui#9306 still carries;
|
|
358
|
+
* - the spec's alias table `gt` / `lt` / `eq`, which three schema-catalog
|
|
359
|
+
* entries author today.
|
|
360
|
+
*
|
|
361
|
+
* When this helper was written the mounted id was `greaterThan` and the stored
|
|
362
|
+
* spelling `greater_than`; neither matched the other literally, so the trigger
|
|
363
|
+
* drew BLANK over a row that filtered correctly — the user's own operator,
|
|
364
|
+
* invisible and unreachable.
|
|
365
|
+
* Everywhere the operator's MEANING matters this component already folds first
|
|
366
|
+
* ({@link filterValueArity}, {@link reconcileOperatorForField}); this was the
|
|
367
|
+
* one place it did not, and that omission — not the vocabulary divergence — is
|
|
368
|
+
* what produced the blank.
|
|
369
|
+
*
|
|
370
|
+
* So the comparison is made canonically and the MOUNTED spelling is handed to
|
|
371
|
+
* the trigger. Three things this deliberately does NOT do, each of them a
|
|
372
|
+
* separate ruling (objectui#7561):
|
|
373
|
+
*
|
|
374
|
+
* 1. it does not rewrite `condition.operator` — the row keeps the spelling it
|
|
375
|
+
* arrived with, exactly as {@link reconcileOperatorForField} keeps it, and
|
|
376
|
+
* nothing is written back on render. (Since objectui#9306 the BUILDER
|
|
377
|
+
* folds a row's spelling once, at its read boundary — see
|
|
378
|
+
* {@link normalizeFilterBuilderOperator} — so the rows it renders already
|
|
379
|
+
* hold protocol ids. This helper still folds both sides, because it is
|
|
380
|
+
* exported and its caller's rows need not have come through that
|
|
381
|
+
* boundary.)
|
|
382
|
+
* 2. it does not mount a new `SelectItem`, so the vocabulary the dropdown
|
|
383
|
+
* EMITS is byte-identical — contrast the value select above, where
|
|
384
|
+
* objectui#4874 ruling C mounts the outside-options value as its own
|
|
385
|
+
* option. That answer is right there and wrong here: the value's domain is
|
|
386
|
+
* the author's data, while the operator's domain is a declared vocabulary,
|
|
387
|
+
* and mounting a foreign spelling would admit a second one;
|
|
388
|
+
* 3. it does not widen what any schema ACCEPTS.
|
|
389
|
+
*
|
|
390
|
+
* Safe to compare through because the fold is INJECTIVE over this builder's
|
|
391
|
+
* vocabulary — all 22 ids in `defaultOperators` normalize to 22 distinct
|
|
392
|
+
* canonical operators, pinned in `filter-builder-field-switch-operator.test.tsx`
|
|
393
|
+
* — so no two OFFERED operators can collapse onto one another and the match is
|
|
394
|
+
* unambiguous. An operator no offered id folds onto falls through to the row's
|
|
395
|
+
* own spelling and still draws blank: inventing a label for a word this
|
|
396
|
+
* vocabulary does not contain would be a claim, not a repair.
|
|
397
|
+
*
|
|
398
|
+
* @internal exported for tests
|
|
399
|
+
*/
|
|
400
|
+
export declare function mountedOperatorValue(operator: string, offeredOperators: ReadonlyArray<{
|
|
401
|
+
value: string;
|
|
402
|
+
}>): string;
|
|
262
403
|
/**
|
|
263
404
|
* Re-TYPE a row's `value` for the field it is being changed TO — the type
|
|
264
405
|
* question, standing beside {@link reshapeFilterValue}'s shape question
|
|
@@ -285,7 +426,7 @@ export declare function reconcileOperatorForField(operator: string, offeredOpera
|
|
|
285
426
|
* - `scalar` — converted, or `""`.
|
|
286
427
|
* - `list` — converted ENTRY BY ENTRY, keeping the ones that carry:
|
|
287
428
|
* `["42", "acme"]` → `[42]`, and `[]` when none do. Reachable today only
|
|
288
|
-
* between the two buckets that offer `in`/`
|
|
429
|
+
* between the two buckets that offer `in`/`not_in` (`select` ↔ `lookup`),
|
|
289
430
|
* which are both text-family, so the conversion is the identity there; it
|
|
290
431
|
* is written for the family the operator lands in rather than for today's
|
|
291
432
|
* buckets, and pinned directly on this helper.
|
|
@@ -296,7 +437,7 @@ export declare function reconcileOperatorForField(operator: string, offeredOpera
|
|
|
296
437
|
*
|
|
297
438
|
* @internal exported for tests
|
|
298
439
|
*/
|
|
299
|
-
export declare function retypeFilterValue(value:
|
|
440
|
+
export declare function retypeFilterValue(value: FilterBuilderRow["value"], fieldType: string | undefined, operator: string): FilterBuilderRow["value"];
|
|
300
441
|
/** The shape of a `fields` entry that the option-domain helpers below read. */
|
|
301
442
|
type OptionBearingField = {
|
|
302
443
|
type?: string;
|
|
@@ -344,7 +485,7 @@ type OptionBearingField = {
|
|
|
344
485
|
*
|
|
345
486
|
* @internal exported for tests
|
|
346
487
|
*/
|
|
347
|
-
export declare function narrowFilterValueToOptions(value:
|
|
488
|
+
export declare function narrowFilterValueToOptions(value: FilterBuilderRow["value"], field: OptionBearingField | undefined, operator: string): FilterBuilderRow["value"];
|
|
348
489
|
/**
|
|
349
490
|
* Is this row's value FINISHED for the operator it carries — the arity-aware
|
|
350
491
|
* reading of "the user has filled this in" (objectstack#8815).
|
|
@@ -396,10 +537,17 @@ export declare function narrowFilterValueToOptions(value: FilterBuilderCondition
|
|
|
396
537
|
*
|
|
397
538
|
* @internal exported for tests
|
|
398
539
|
*/
|
|
399
|
-
export declare function isFilterValueComplete(operator: string, value:
|
|
540
|
+
export declare function isFilterValueComplete(operator: string, value: FilterBuilderRow["value"] | undefined | null): boolean;
|
|
400
541
|
/**
|
|
401
|
-
* The operators
|
|
402
|
-
*
|
|
542
|
+
* The operators a row on a field of `fieldType` can HOLD, given the opt-in ids
|
|
543
|
+
* this instance was granted — every operator the dropdown can draw for it.
|
|
544
|
+
*
|
|
545
|
+
* What the dropdown OFFERS a fresh choice is this set minus the nullness pair
|
|
546
|
+
* on a type that cannot tell "empty" from "null" (objectui#11810, see
|
|
547
|
+
* {@link offeredOperatorsForRow}). That narrowing is deliberately NOT applied
|
|
548
|
+
* here: callers outside this file (`app-shell`'s dataset read-back,
|
|
549
|
+
* `plugin-list`'s parity pin) ask "can the builder hold this row", and a
|
|
550
|
+
* stored `is_null` on a `select` column still can.
|
|
403
551
|
*
|
|
404
552
|
* A pure function rather than a closure so the selection rule — and above all
|
|
405
553
|
* the {@link OPT_IN_OPERATORS} gate, whose whole job is to keep an operator OFF
|
|
@@ -425,9 +573,9 @@ interface LookupValuePickerProps {
|
|
|
425
573
|
displayField?: string;
|
|
426
574
|
idField?: string;
|
|
427
575
|
};
|
|
428
|
-
value:
|
|
576
|
+
value: FilterBuilderRow["value"];
|
|
429
577
|
multiple: boolean;
|
|
430
|
-
onChange: (value:
|
|
578
|
+
onChange: (value: FilterBuilderRow["value"]) => void;
|
|
431
579
|
}
|
|
432
580
|
declare function LookupValuePicker({ field, value, multiple, onChange }: LookupValuePickerProps): React.JSX.Element;
|
|
433
581
|
export { FilterBuilder, LookupValuePicker };
|
|
@@ -47,5 +47,9 @@ export interface GroupingEditorProps {
|
|
|
47
47
|
* Field options are filtered per row so a field can only appear in one level
|
|
48
48
|
* at a time. The current row's selected field stays in its own dropdown so the
|
|
49
49
|
* user sees the active selection.
|
|
50
|
+
*
|
|
51
|
+
* The field selector is the shared `Select` primitive, the control the Filter
|
|
52
|
+
* and Sort panels beside this one pick a field with, so the three panels look
|
|
53
|
+
* and behave alike (objectui#11865). It used to be a browser-native `<select>`.
|
|
50
54
|
*/
|
|
51
55
|
export declare function GroupingEditor({ value, onChange, fieldOptions, maxLevels, className, labels, }: GroupingEditorProps): React.JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface HorizontalOverflowBoxProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
/**
|
|
4
|
+
* Where the shadow is drawn: `edge` (default) overlays the box's right edge;
|
|
5
|
+
* `pinned` leaves it to the right-pinned cells inside, which carry
|
|
6
|
+
* `PINNED_RIGHT_SEAM_SHADOW_CLASSES` (`./use-horizontal-overflow`).
|
|
7
|
+
*/
|
|
8
|
+
seam?: 'edge' | 'pinned';
|
|
9
|
+
/** Classes for the positioned wrapper around the scrolling box. */
|
|
10
|
+
outerClassName?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A horizontally scrolling box with the shared overflow affordance. The
|
|
14
|
+
* scrolling element is the inner `div` (`className`, the ref and every other
|
|
15
|
+
* prop land on it); the edge shadow is its sibling, so it never scrolls away
|
|
16
|
+
* with the content.
|
|
17
|
+
*/
|
|
18
|
+
export declare const HorizontalOverflowBox: React.ForwardRefExoticComponent<HorizontalOverflowBoxProps & React.RefAttributes<HTMLDivElement>>;
|
package/dist/custom/index.d.ts
CHANGED
|
@@ -24,5 +24,8 @@ export * from './shimmer-skeleton.js';
|
|
|
24
24
|
export * from './RecordTitleChip.js';
|
|
25
25
|
export * from './refresh-indicator.js';
|
|
26
26
|
export * from './view-states.js';
|
|
27
|
+
export * from './empty-state-link.js';
|
|
27
28
|
export * from './mobile-dialog-content.js';
|
|
28
|
-
export * from './
|
|
29
|
+
export * from './dialog-viewport-gutter.js';
|
|
30
|
+
export { HorizontalOverflowBox, type HorizontalOverflowBoxProps } from './horizontal-overflow.js';
|
|
31
|
+
export { PINNED_RIGHT_SEAM_SHADOW_CLASSES } from './use-horizontal-overflow.js';
|
package/dist/custom/item.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ declare function Item({ className, variant, size, asChild, ...props }: React.Com
|
|
|
18
18
|
asChild?: boolean;
|
|
19
19
|
}): React.JSX.Element;
|
|
20
20
|
declare const itemMediaVariants: (props?: ({
|
|
21
|
-
variant?: "
|
|
21
|
+
variant?: "default" | "icon" | "image" | null | undefined;
|
|
22
22
|
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
23
23
|
declare function ItemMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>): React.JSX.Element;
|
|
24
24
|
declare function ItemContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
package/dist/custom/kbd.d.ts
CHANGED
|
@@ -6,5 +6,5 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
declare function Kbd({ className, ...props }: React.ComponentProps<"kbd">): import("react").JSX.Element;
|
|
9
|
-
declare function KbdGroup({ className, ...props }: React.ComponentProps<"
|
|
9
|
+
declare function KbdGroup({ className, ...props }: React.ComponentProps<"kbd">): import("react").JSX.Element;
|
|
10
10
|
export { Kbd, KbdGroup };
|
|
@@ -43,5 +43,26 @@ type InteractOutsideHandler = NonNullable<React.ComponentPropsWithoutRef<typeof
|
|
|
43
43
|
* plain backdrop click with no flyout open.
|
|
44
44
|
*/
|
|
45
45
|
export declare function usePopperAwareInteractOutside(onInteractOutside?: InteractOutsideHandler): InteractOutsideHandler;
|
|
46
|
-
export
|
|
46
|
+
export type MobileDialogContentProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
|
47
|
+
/**
|
|
48
|
+
* Whether the dialog draws its own close (X) button. Defaults to `true`;
|
|
49
|
+
* `false` leaves it out of the DOM entirely (objectui#11061), the same
|
|
50
|
+
* switch upstream Shadcn's `DialogContent` names `showCloseButton`. The
|
|
51
|
+
* dialog stays dismissable without it: Escape and a backdrop click still
|
|
52
|
+
* reach the `Dialog`'s `onOpenChange(false)` through Radix, so a caller that
|
|
53
|
+
* hides the X only has to keep whatever explicit way out its body offers.
|
|
54
|
+
*/
|
|
55
|
+
showCloseButton?: boolean;
|
|
56
|
+
};
|
|
57
|
+
export declare const MobileDialogContent: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
58
|
+
/**
|
|
59
|
+
* Whether the dialog draws its own close (X) button. Defaults to `true`;
|
|
60
|
+
* `false` leaves it out of the DOM entirely (objectui#11061), the same
|
|
61
|
+
* switch upstream Shadcn's `DialogContent` names `showCloseButton`. The
|
|
62
|
+
* dialog stays dismissable without it: Escape and a backdrop click still
|
|
63
|
+
* reach the `Dialog`'s `onOpenChange(false)` through Radix, so a caller that
|
|
64
|
+
* hides the X only has to keep whatever explicit way out its body offers.
|
|
65
|
+
*/
|
|
66
|
+
showCloseButton?: boolean;
|
|
67
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
47
68
|
export {};
|