@object-ui/react 17.5.0 → 17.6.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 +334 -0
- package/README.md +9 -8
- package/dist/LazyPluginLoader.d.ts +14 -7
- package/dist/LazyPluginLoader.js +14 -7
- package/dist/SchemaRenderer.js +434 -22
- package/dist/context/HostNavigationContext.d.ts +82 -0
- package/dist/context/HostNavigationContext.js +65 -0
- package/dist/context/RelatedRecordActionsContext.d.ts +15 -0
- package/dist/context/index.d.ts +13 -12
- package/dist/context/index.js +13 -12
- package/dist/element-data-source/ElementDataSourceGate.d.ts +75 -2
- package/dist/element-data-source/ElementDataSourceGate.js +81 -2
- package/dist/hooks/index.d.ts +35 -35
- package/dist/hooks/index.js +35 -35
- package/dist/hooks/useActionEngine.js +1 -1
- package/dist/hooks/useCapabilityGate.js +6 -5
- package/dist/hooks/useClientNotifications.js +2 -2
- package/dist/hooks/useCrudShortcuts.js +1 -1
- package/dist/hooks/useDatasetDimensionLabels.js +1 -1
- package/dist/hooks/useDiscovery.js +1 -1
- package/dist/hooks/useElementDataSource.js +5 -2
- package/dist/hooks/useExpression.d.ts +24 -3
- package/dist/hooks/useExpression.js +56 -4
- package/dist/hooks/useNavigationOverlay.d.ts +1 -1
- package/dist/hooks/usePageAssignment.js +1 -1
- package/dist/hooks/usePageTransition.js +1 -1
- package/dist/hooks/usePageVariableActionBridge.js +2 -2
- package/dist/hooks/useViewData.js +1 -1
- package/dist/hooks/useViewTransition.js +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +10 -10
- package/dist/schema-input.d.ts +16 -5
- package/dist/schema-input.js +15 -4
- package/dist/spec-bridge/SpecBridge.d.ts +1 -1
- package/dist/spec-bridge/SpecBridge.js +2 -2
- package/dist/spec-bridge/bridges/form-view.d.ts +99 -23
- package/dist/spec-bridge/bridges/form-view.js +51 -7
- package/dist/spec-bridge/bridges/list-view.d.ts +1 -1
- package/dist/spec-bridge/bridges/list-view.js +37 -10
- package/dist/spec-bridge/index.d.ts +4 -4
- package/dist/spec-bridge/index.js +3 -3
- package/dist/utils/error-message.d.ts +59 -0
- package/dist/utils/error-message.js +116 -1
- package/dist/utils/unevaluatedExpression.d.ts +69 -0
- package/dist/utils/unevaluatedExpression.js +194 -0
- package/dist/utils/visibilityDiagnostic.d.ts +119 -0
- package/dist/utils/visibilityDiagnostic.js +284 -0
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,339 @@
|
|
|
1
1
|
# @object-ui/react
|
|
2
2
|
|
|
3
|
+
## 17.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f1d4748: Remove the retired `striped` / `bordered` / `virtualScroll` list-view surface
|
|
8
|
+
|
|
9
|
+
objectstack#7176 retired `list.striped`, `list.bordered` and `list.virtualScroll`
|
|
10
|
+
from the spec after measuring every objectui reader as pass-through: each one
|
|
11
|
+
copied the key onward and no renderer ever applied it. objectui stops declaring,
|
|
12
|
+
typing and forwarding them.
|
|
13
|
+
|
|
14
|
+
Off the chain: the `@objectstack/spec` list-view bridge in `@object-ui/react`,
|
|
15
|
+
`ListView`'s child-view props in `@object-ui/plugin-list`, both `ObjectView`
|
|
16
|
+
relays (`@object-ui/plugin-view` and `@object-ui/app-shell`), the `ObjectGridSchema`
|
|
17
|
+
and `NamedListView` declarations in `@object-ui/types` (interface and zod),
|
|
18
|
+
`ObjectGrid.component.yml` in `@object-ui/components`, and the page-block
|
|
19
|
+
inspector's `striped` / `bordered` toggles in the metadata-admin designer.
|
|
20
|
+
|
|
21
|
+
Behaviour is unchanged: nothing read these keys, so nothing rendered differently
|
|
22
|
+
for them. Stored view metadata that still carries one keeps validating — the keys
|
|
23
|
+
are simply no longer relayed. `ListViewSchema` continues to take the spec's
|
|
24
|
+
list-view fields by reference, so the protocol's own retirement tombstones
|
|
25
|
+
arrive with the next `@objectstack/spec` bump and reject the keys at the
|
|
26
|
+
authoring boundary. Restoring any of the three as live surface requires an
|
|
27
|
+
implementation card filed first, per the ruling.
|
|
28
|
+
- 8c0d52e: A form's ruled `submitBehavior.url` redirect can now be performed by the HOST, so a destination stays inside a console mounted at a sub-path (objectui#4989 defect 4).
|
|
29
|
+
|
|
30
|
+
`ObjectForm` and `WizardForm` accept a relative in-app path and used to travel to it with `window.location.assign`. A rooted path resolves against the ORIGIN there, so under a mounted host — `<BrowserRouter basename="/_console">`, which the framework CLI configures for every embedded deployment — an authored `/thanks` left the application. The destination was correct and the navigation was wrong, and a published renderer cannot fix that alone: only the host knows its mount.
|
|
31
|
+
|
|
32
|
+
**New: `HostNavigationContext` (`@object-ui/react`).** A host offers its own navigate; a renderer uses it when it is there:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { HostNavigationProvider } from '@object-ui/react';
|
|
36
|
+
import { useNavigate } from 'react-router-dom';
|
|
37
|
+
|
|
38
|
+
function Bridge({ children }) {
|
|
39
|
+
const navigate = useNavigate();
|
|
40
|
+
return (
|
|
41
|
+
<HostNavigationProvider value={{ navigate: (to, o) => navigate(to, { replace: o?.replace ?? false }) }}>
|
|
42
|
+
{children}
|
|
43
|
+
</HostNavigationProvider>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`@object-ui/app-shell`'s `ConsoleShell` now mounts that bridge above every console route, so the console's own routes, and its basename, are what a post-submit redirect resolves against — and the redirect becomes an SPA transition instead of a full page load.
|
|
49
|
+
|
|
50
|
+
**Nothing changes for a host that wires nothing.** With no provider the behaviour is byte-for-byte what it was: one `window.location.assign` of the resolved path after the declared `delayMs`. A host with no router has no basename, so origin-rooted resolution is already right there — the seam changes what a MOUNTED host gets and nothing else. `useHostNavigation()` outside a provider answers `{ navigate: undefined }` and never throws.
|
|
51
|
+
|
|
52
|
+
Two mechanisms were weighed and rejected by the ruling, recorded so they are not re-proposed. **Reading React Router's context when a router happens to be present** is implicit, and unavailable anyway: a React context is a module-instance object, so reading the host's means importing `react-router` into the renderer — which `@object-ui/plugin-form` declares in none of its dependency fields, whose published build externalises every bare specifier, and which two real consumers (`apps/site`, `packages/plugin-view`) do not install. **Requiring `react-router` as a peer** is the honest version of the same thing and costs the package its property of dropping into any React application.
|
|
53
|
+
|
|
54
|
+
What the host takes on by supplying a navigate: the destination becomes a client-side transition, so an in-app path with no matching route renders the host's not-found instead of a full page load. That is the host's routing table to answer for, which is why the choice is the host's. The contract verdict is unchanged either way — a destination `@objectstack/spec` refuses is refused identically with or without a seam, so an injected navigate can never launder a value the authoring door rejects.
|
|
55
|
+
|
|
56
|
+
`navigateOnSuccess` is a different declared key with its own open contract question (objectui#5034) and is deliberately untouched here.
|
|
57
|
+
- dbbd38a: fix(react): `bridgeListView` emits the column spelling the spec declares
|
|
58
|
+
|
|
59
|
+
`mapColumn` took a spec-canonical `ListColumn` — whose columns are **already**
|
|
60
|
+
spelled `field` / `label` — and down-translated every one of them to
|
|
61
|
+
`{ accessorKey, header }` before emitting the `object-grid` node, which
|
|
62
|
+
`ObjectGrid` then translated back. A round trip through a spelling
|
|
63
|
+
`ListColumnSchema` refuses by name, on a value that arrived canonical. The
|
|
64
|
+
bridge now forwards the declared shape, and the tolerance branch on the other
|
|
65
|
+
side retires in the same release (see `@object-ui/plugin-grid`).
|
|
66
|
+
|
|
67
|
+
**Output shape.** `bridgeListView` / `SpecBridge.transformListView` emit
|
|
68
|
+
`columns: [{ field, label?, … }]`. Code reading `node.columns[i].accessorKey`
|
|
69
|
+
off a bridged node reads `field` instead; `header` becomes `label`. The bare
|
|
70
|
+
string shorthand `columns: ['name']` now maps to `{ field: 'name' }`.
|
|
71
|
+
|
|
72
|
+
**No label is invented any more.** `header: col.label ?? col.field` turned "the
|
|
73
|
+
author declared no label" into "the author declared the machine name", and that
|
|
74
|
+
synthesized value pre-empted `ObjectGrid`'s own header chain — the column's
|
|
75
|
+
label, then the **object field's** label, then the prettified machine name —
|
|
76
|
+
whose middle step exists so a localized field label wins on a non-English app.
|
|
77
|
+
A bridged view therefore rendered raw machine names where a directly authored
|
|
78
|
+
`object-grid` rendered the field's real label. A bare `{ field }` column now
|
|
79
|
+
reaches that chain intact.
|
|
80
|
+
|
|
81
|
+
Speaking the declared spelling also routes bridged views through the renderer's
|
|
82
|
+
full ListColumn path rather than its type-inference-only one: object-schema
|
|
83
|
+
field enrichment, `hidden` filtering, primary-field auto-linking, and per-column
|
|
84
|
+
`link` / `action` handling now apply to a bridged `ListView` exactly as they do
|
|
85
|
+
to an authored grid.
|
|
86
|
+
|
|
87
|
+
### Patch Changes
|
|
88
|
+
|
|
89
|
+
- 516663d: RecordAttachmentsPanel no longer offers a Retry for an api-disabled `sys_attachment` read.
|
|
90
|
+
|
|
91
|
+
`OBJECT_API_DISABLED` (404, `enable.apiEnabled: false`) and its sibling
|
|
92
|
+
`OBJECT_API_METHOD_NOT_ALLOWED` (405, the operation is absent from
|
|
93
|
+
`enable.apiMethods`) are pure functions of the object's metadata — no user, no
|
|
94
|
+
session, no request body — so every retry of every persona re-fetches the
|
|
95
|
+
identical refusal. Before this change both landed in `RecordAttachmentsPanel`'s
|
|
96
|
+
`unavailable` state and offered a Retry that was guaranteed to change nothing,
|
|
97
|
+
the same wrong advice `ListView`'s error panel already stops giving for list
|
|
98
|
+
reads.
|
|
99
|
+
|
|
100
|
+
The panel gains a fifth status, `api-unavailable`: no Retry button, and honest
|
|
101
|
+
copy ("The attachments list is not available on this object.", new
|
|
102
|
+
`detail.attachmentsApiUnavailable` key in all ten locale packs) instead of
|
|
103
|
+
"We couldn't load the attachments for this record." The pre-existing `denied`
|
|
104
|
+
(authorization) and `unavailable` (network/5xx/expired-session) states and
|
|
105
|
+
their affordances are unchanged.
|
|
106
|
+
|
|
107
|
+
`ListView.classifyLoadError` — the classifier that already separated this case
|
|
108
|
+
into its own `api-disabled` kind for list views — is lifted out of
|
|
109
|
+
`packages/plugin-list/src/ListView.tsx`'s module scope into
|
|
110
|
+
`@object-ui/react` (`classifyLoadError`, `LoadErrorKind`), so both surfaces
|
|
111
|
+
consume one classification instead of `RecordAttachmentsPanel` re-deriving it.
|
|
112
|
+
`ListView`'s own behavior is unchanged — it now imports the function it
|
|
113
|
+
previously defined locally. The classifier delegates its api-disabled check to
|
|
114
|
+
`isApiAccessDeniedError` (`@object-ui/data-objectstack`), removing a second,
|
|
115
|
+
independently-maintained copy of the same code list.
|
|
116
|
+
- d374caf: SpecBridge's form-view bridge stops reading `defaultSort` and `aria`, two keys spec 17
|
|
117
|
+
retired on the FormView carrier (`retiredKey()` tombstones — authoring either is a parse
|
|
118
|
+
error). Both guards were unreachable for any FormView that passed validation, and both
|
|
119
|
+
ends were measured dead before removal: no form renderer reads either off the node
|
|
120
|
+
(`plugin-form` reads neither, and `SchemaRenderer`'s ARIA injection resolves flat
|
|
121
|
+
`ariaLabel`/`ariaDescribedBy`/`role`, never a nested `aria` object). Behaviour for
|
|
122
|
+
spec-valid metadata is unchanged; a host that fed the exported bridge a raw pre-17
|
|
123
|
+
document no longer gets these two keys copied onto a node slot nothing consumed. The
|
|
124
|
+
LIST view's `aria` pass-through is untouched — that carrier stayed live and is applied by
|
|
125
|
+
`ListView`.
|
|
126
|
+
- af5e292: Emit explicit file extensions on relative import specifiers, so the published
|
|
127
|
+
entries can be imported by Node's own ESM resolver.
|
|
128
|
+
|
|
129
|
+
`@object-ui/react`'s built entry re-exported through extensionless relative
|
|
130
|
+
specifiers (`export * from './SchemaRenderer'`). Node does not extension-search
|
|
131
|
+
relative specifiers, so `import('@object-ui/react')` under plain Node — an SSR
|
|
132
|
+
host, or any consumer without a bundler — failed with `ERR_MODULE_NOT_FOUND`.
|
|
133
|
+
Bundled consumers were never affected and are unchanged by this.
|
|
134
|
+
|
|
135
|
+
`@object-ui/types`, `@object-ui/core` and `@object-ui/i18n` carried the same
|
|
136
|
+
emission; `@object-ui/react`'s entry stayed unloadable until they were fixed
|
|
137
|
+
too, because evaluation crosses into them. No exported API changed.
|
|
138
|
+
- 0046d8f: Evaluate expressions written under a node's `properties`, not just under `props`
|
|
139
|
+
|
|
140
|
+
`properties` is the spec spelling of a node's config bag and `props` is the
|
|
141
|
+
legacy alias, but `SchemaRenderer`'s evaluation memo only ran the expression
|
|
142
|
+
evaluator over `props`. Renderers in the `element:*` namespace read
|
|
143
|
+
`schema.properties` first, so a node written the canonical way handed the
|
|
144
|
+
renderer the raw `${…}` source and rendered it verbatim, while the same node
|
|
145
|
+
written with the alias evaluated correctly — writing the spec-compliant form
|
|
146
|
+
was the way to lose your expressions.
|
|
147
|
+
|
|
148
|
+
`schema.properties` values are now evaluated per value, exactly as `props`
|
|
149
|
+
already was, and the evaluation runs before the existing
|
|
150
|
+
`properties`-to-top-level hoist so a key means the same thing whether it is read
|
|
151
|
+
as `schema.properties.x`, as `schema.x`, or as the spread `x` React prop.
|
|
152
|
+
Evaluation stays shallow on both spellings (nested objects and arrays are passed
|
|
153
|
+
through, not walked), and `properties` keeps its precedence over `props`.
|
|
154
|
+
- 70a774b: A node writing both `properties` and `props` now gets ONE answer per key, and it is the canonical `properties` one — on both read channels.
|
|
155
|
+
|
|
156
|
+
`properties` is the spec spelling of a node's config bag and `props` is the
|
|
157
|
+
annotated legacy alias, but which one actually reached the screen depended on
|
|
158
|
+
how the receiving renderer happened to read it — and the two channels disagreed
|
|
159
|
+
in opposite directions:
|
|
160
|
+
|
|
161
|
+
- **config bag** (`schema.properties.x`) — the `element:*` family's
|
|
162
|
+
`readProps()` merges `{ ...schema.props, ...schema.properties }`, so
|
|
163
|
+
`properties` won.
|
|
164
|
+
- **React prop** (`x` arriving as a prop) — `SchemaRenderer`'s `createElement`
|
|
165
|
+
spread the hoisted `properties.*` values first and then
|
|
166
|
+
`...(evaluatedSchema.props || {})` last, which overwrote them, so `props` won.
|
|
167
|
+
|
|
168
|
+
Measured on one render of one such node: the bag read `FROM_PROPERTIES` while
|
|
169
|
+
the same key read as a React prop gave `FROM_PROPS`. Which value rendered was
|
|
170
|
+
decided by nothing an author can see — only by whether their chosen component
|
|
171
|
+
belonged to the `readProps()` family.
|
|
172
|
+
|
|
173
|
+
The React-prop channel now declines to let the legacy alias override a key the
|
|
174
|
+
canonical bag also declares; the config-bag order was already correct and is
|
|
175
|
+
unchanged. Scope is co-occurrence only: a key that only `props` declares still
|
|
176
|
+
works exactly as before, and a node that writes one spelling is untouched. The
|
|
177
|
+
`props` alias is not retired here — only its precedence against a co-present
|
|
178
|
+
canonical spelling is settled.
|
|
179
|
+
- dfc6975: Related-list "+ New" now honours `userActions.create` predicates, and the grid
|
|
180
|
+
toolbar's inline-edit affordance is gated on `update` permission (objectui#4646,
|
|
181
|
+
objectui#4647).
|
|
182
|
+
|
|
183
|
+
Two declared-but-unenforced gaps on the same toolbar surface.
|
|
184
|
+
|
|
185
|
+
**#4646 — `createPredicates` had a producer and no consumer.**
|
|
186
|
+
`@objectstack/spec@17.0.0` widened `userActions.create` to
|
|
187
|
+
`z.union([z.boolean(), RowCrudActionOverrideSchema])`, so `resolveCrudAffordances`
|
|
188
|
+
emits `createPredicates` — and nothing in objectui read them, against roughly
|
|
189
|
+
fifteen consumption sites apiece for `editPredicates` / `deletePredicates`. The
|
|
190
|
+
symptom: a parent record entering a frozen state correctly greyed its children's
|
|
191
|
+
row Edit/Delete while the related list's "+ New" stayed fully live, so the user
|
|
192
|
+
filled in the whole child form to earn a server 409. The related-list toolbar now
|
|
193
|
+
evaluates `visibleWhen` / `disabledWhen` **once against the host parent record**,
|
|
194
|
+
per the spec docblock's binding for this key, on top of the existing
|
|
195
|
+
`o.create ∧ can(child, 'create')` check. `visibleWhen` hides "+ New" and fails
|
|
196
|
+
CLOSED; `disabledWhen` greys it and fails SOFT — the same evaluator, fail
|
|
197
|
+
directions and hidden-vs-disabled split the record header already uses for
|
|
198
|
+
edit/delete (objectui#4419 / PR #4515). A bare-boolean `userActions.create` is
|
|
199
|
+
untouched: with no predicates there is nothing to evaluate.
|
|
200
|
+
|
|
201
|
+
**#4647 — the inline-edit toggle was the one ungated affordance on its toolbar.**
|
|
202
|
+
It rendered on "grid view ∧ the host wired `onInlineEditChange` ∧ not the compact
|
|
203
|
+
toolbar", and every host wires that callback unconditionally. New and Import are
|
|
204
|
+
hidden for an account without the grant and the bulk-delete entry on the same
|
|
205
|
+
toolbar ANDs `can(obj, 'delete')`, but a read-only principal could flip inline
|
|
206
|
+
edit, modify cells and press "Save all" to earn a server 403. It is now gated on
|
|
207
|
+
the object's resolved edit affordance ∧ `can(object, 'update')`, mirroring that
|
|
208
|
+
bulk-delete gate. The gate is applied at all three sites that carry this
|
|
209
|
+
affordance — the wide toolbar's toggle, the compact toolbar's settings-popover
|
|
210
|
+
entry (which previously had no gate at all, not even the callback), and the
|
|
211
|
+
`editable` mode handed to the grid, so a stored view carrying `inlineEdit: true`
|
|
212
|
+
can no longer drop a read-only principal into editable cells with no toggle to
|
|
213
|
+
press.
|
|
214
|
+
|
|
215
|
+
`ListViewSchema.userActions.editInline` is also consumed now: an explicit `false`
|
|
216
|
+
withholds the affordance wholesale, which authors previously could not do.
|
|
217
|
+
|
|
218
|
+
**Behaviour change for read-only users, stated plainly.** Where the UI used to
|
|
219
|
+
offer inline editing and let the server refuse it, it now declines to offer the
|
|
220
|
+
entry point at all. No data access changes — the server gate was and remains the
|
|
221
|
+
enforcement boundary; this only stops the UI walking users into round-trips
|
|
222
|
+
guaranteed to fail. Accounts *with* the grant see no change, and hosts with no
|
|
223
|
+
`PermissionProvider` mounted (standalone embeds, the Studio designer) keep
|
|
224
|
+
today's behaviour, since `can()` answers `true` there by design.
|
|
225
|
+
|
|
226
|
+
One deliberate non-change: the absent case of `userActions.editInline` defers to
|
|
227
|
+
the host's existing `inlineEdit` channel rather than enforcing the spec's
|
|
228
|
+
`.default(false)`. Enforcing that default would remove the toggle from every
|
|
229
|
+
stored console list view in one release, since nothing folds a legacy key into
|
|
230
|
+
`editInline` and no existing view declares it. This follows the rule the
|
|
231
|
+
surrounding toolbar-flag block already states for itself — defaults chosen to
|
|
232
|
+
match what the flags have always done. `InterfaceListPage`, the key's other
|
|
233
|
+
consumer, reads the absent case as OFF, because the ADR-0047 interface page has
|
|
234
|
+
no such host channel to defer to.
|
|
235
|
+
- 144ef9b: Dev builds now shout when an unevaluated `${…}` expression reaches the DOM.
|
|
236
|
+
|
|
237
|
+
A value only reaches the user if `SchemaRenderer` EVALUATES it and the renderer
|
|
238
|
+
READS IT BACK, and those two sets do not fully overlap. Where they miss, the
|
|
239
|
+
failure was silent. Measured on a real render with `dataSource: { n: 99 }`:
|
|
240
|
+
`{ type: 'ui:statistic', value: '${data.n}' }` puts the literal text `${data.n}`
|
|
241
|
+
on screen, because the evaluation memo covers `content`, the `properties` /
|
|
242
|
+
`props` bags and the predicate keys and passes every other top-level key through
|
|
243
|
+
untouched. An author — increasingly, an AI authoring metadata — got no signal at
|
|
244
|
+
all: a literal `${data.n}` in front of a user reads like a data problem rather
|
|
245
|
+
than a contract violation.
|
|
246
|
+
|
|
247
|
+
`SchemaRenderer` now reports such a value once per node via `console.error`,
|
|
248
|
+
naming the node type and id, the key the raw source survived on (spelled the way
|
|
249
|
+
it was authored — `properties.value`, not the hoisted top-level copy), the
|
|
250
|
+
expression source verbatim, and the channels that do work today. It also catches
|
|
251
|
+
the second, harder shape: an expression that WAS evaluated but THREW, which
|
|
252
|
+
`ExpressionEvaluator` returns as its source text — indistinguishable on screen
|
|
253
|
+
from a key that was never evaluated.
|
|
254
|
+
|
|
255
|
+
Diagnostic only. No evaluation behaviour changes, no DOM attribute is added, and
|
|
256
|
+
the whole module is behind the module-load `NODE_ENV` constant a bundler folds
|
|
257
|
+
away, so production pays nothing.
|
|
258
|
+
|
|
259
|
+
Two boundaries are deliberate. The scan is exactly as deep as evaluation is —
|
|
260
|
+
shallow — because a nested `aria: { label: '${…}' }` keeps its raw source today
|
|
261
|
+
by decision (objectui#4799 pinned that shallowness on both bags), and a deeper
|
|
262
|
+
scan would report a shape the engine has not yet decided to change. And schema
|
|
263
|
+
METADATA is never reported: `visible` / `visibleWhen` / `hidden` / `disabled` /
|
|
264
|
+
… hold raw predicate source by design, and the diagnostic reads the set of
|
|
265
|
+
values that actually leaves for the DOM, after those keys have been stripped.
|
|
266
|
+
|
|
267
|
+
Part of objectui#4795 (Direction 3, per the maintainer's 2026-08-17 ruling).
|
|
268
|
+
Widening the set of evaluated text keys is Direction 1 and stays deferred behind
|
|
269
|
+
its named restart condition; this change deliberately does not pre-empt it.
|
|
270
|
+
- Updated dependencies [88085e3]
|
|
271
|
+
- Updated dependencies [69251bf]
|
|
272
|
+
- Updated dependencies [57e668f]
|
|
273
|
+
- Updated dependencies [516663d]
|
|
274
|
+
- Updated dependencies [41ac1b7]
|
|
275
|
+
- Updated dependencies [1eaf0a1]
|
|
276
|
+
- Updated dependencies [2533ec5]
|
|
277
|
+
- Updated dependencies [bbe8b86]
|
|
278
|
+
- Updated dependencies [8477be5]
|
|
279
|
+
- Updated dependencies [279fb13]
|
|
280
|
+
- Updated dependencies [2e82ab2]
|
|
281
|
+
- Updated dependencies [ad07b65]
|
|
282
|
+
- Updated dependencies [41f498b]
|
|
283
|
+
- Updated dependencies [ef0d150]
|
|
284
|
+
- Updated dependencies [1ef236e]
|
|
285
|
+
- Updated dependencies [f34226e]
|
|
286
|
+
- Updated dependencies [564b605]
|
|
287
|
+
- Updated dependencies [e1d4251]
|
|
288
|
+
- Updated dependencies [1184192]
|
|
289
|
+
- Updated dependencies [a2a9747]
|
|
290
|
+
- Updated dependencies [a1609a6]
|
|
291
|
+
- Updated dependencies [37f6844]
|
|
292
|
+
- Updated dependencies [2b50261]
|
|
293
|
+
- Updated dependencies [ac600e5]
|
|
294
|
+
- Updated dependencies [c1ef923]
|
|
295
|
+
- Updated dependencies [af5e292]
|
|
296
|
+
- Updated dependencies [7f96b10]
|
|
297
|
+
- Updated dependencies [167ec42]
|
|
298
|
+
- Updated dependencies [cf4f8a6]
|
|
299
|
+
- Updated dependencies [f1d4748]
|
|
300
|
+
- Updated dependencies [bea374e]
|
|
301
|
+
- Updated dependencies [b1119ec]
|
|
302
|
+
- Updated dependencies [9f23d2b]
|
|
303
|
+
- Updated dependencies [578e025]
|
|
304
|
+
- Updated dependencies [af025ee]
|
|
305
|
+
- Updated dependencies [d109a4d]
|
|
306
|
+
- Updated dependencies [3d053bb]
|
|
307
|
+
- Updated dependencies [598c89a]
|
|
308
|
+
- Updated dependencies [b8b9af4]
|
|
309
|
+
- Updated dependencies [31676be]
|
|
310
|
+
- Updated dependencies [9ce096f]
|
|
311
|
+
- Updated dependencies [e05db88]
|
|
312
|
+
- Updated dependencies [ad13d63]
|
|
313
|
+
- Updated dependencies [5ffcc14]
|
|
314
|
+
- Updated dependencies [d971e51]
|
|
315
|
+
- Updated dependencies [97abb24]
|
|
316
|
+
- Updated dependencies [deb157a]
|
|
317
|
+
- Updated dependencies [9c60144]
|
|
318
|
+
- Updated dependencies [d2ce342]
|
|
319
|
+
- Updated dependencies [a8411ad]
|
|
320
|
+
- Updated dependencies [9695da7]
|
|
321
|
+
- Updated dependencies [58b8346]
|
|
322
|
+
- Updated dependencies [a9e17b4]
|
|
323
|
+
- Updated dependencies [b8ce7dc]
|
|
324
|
+
- Updated dependencies [8871c14]
|
|
325
|
+
- Updated dependencies [dfc6975]
|
|
326
|
+
- Updated dependencies [3cf4de0]
|
|
327
|
+
- Updated dependencies [c9dc811]
|
|
328
|
+
- Updated dependencies [d871f8e]
|
|
329
|
+
- Updated dependencies [a0b9e91]
|
|
330
|
+
- Updated dependencies [99bd015]
|
|
331
|
+
- Updated dependencies [21e4585]
|
|
332
|
+
- @object-ui/types@17.6.0
|
|
333
|
+
- @object-ui/i18n@17.6.0
|
|
334
|
+
- @object-ui/core@17.6.0
|
|
335
|
+
- @object-ui/data-objectstack@17.6.0
|
|
336
|
+
|
|
3
337
|
## 17.5.0
|
|
4
338
|
|
|
5
339
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -158,18 +158,19 @@ falling back to the object's full scope. Use `useElementDataSourceSchema` (plus
|
|
|
158
158
|
the exported `ElementDataSourceErrorPanel` / `ElementDataSourceLoadingPanel`) when
|
|
159
159
|
a block cannot be wrapped — a renderer whose hooks must run before the panels.
|
|
160
160
|
|
|
161
|
-
###
|
|
161
|
+
### ComponentRegistry
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
There is no registry hook: the registry is a process-level singleton exported
|
|
164
|
+
by `@object-ui/core`, so read it directly. Subscribe to it only when a lazily
|
|
165
|
+
registered plugin must trigger a re-render.
|
|
164
166
|
|
|
165
167
|
```tsx
|
|
166
|
-
import {
|
|
168
|
+
import { ComponentRegistry } from '@object-ui/core'
|
|
167
169
|
|
|
168
|
-
function MyComponent() {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return <Component {...props} />
|
|
170
|
+
function MyComponent(props: Record<string, unknown>) {
|
|
171
|
+
const Component = ComponentRegistry.get('button')
|
|
172
|
+
|
|
173
|
+
return Component ? <Component {...props} /> : null
|
|
173
174
|
}
|
|
174
175
|
```
|
|
175
176
|
|
|
@@ -30,26 +30,33 @@ export interface LazyPluginOptions {
|
|
|
30
30
|
/**
|
|
31
31
|
* Create a lazy-loaded plugin component with Suspense wrapper
|
|
32
32
|
*
|
|
33
|
-
* @param importFn - Dynamic import function
|
|
33
|
+
* @param importFn - Dynamic import function resolving to a module whose
|
|
34
|
+
* `default` is the component to render. ObjectUI plugin packages export
|
|
35
|
+
* their components by NAME and have no `default`, so a bare
|
|
36
|
+
* `() => import('@object-ui/plugin-<x>')` does NOT satisfy this — it hands
|
|
37
|
+
* over the module namespace object, which is neither a component at runtime
|
|
38
|
+
* nor assignable here. Name the component you want, as the examples do.
|
|
34
39
|
* @param options - Configuration options for the lazy plugin
|
|
35
40
|
* @returns A component that lazy loads the plugin
|
|
36
41
|
*
|
|
37
42
|
* @example
|
|
38
43
|
* ```tsx
|
|
39
|
-
* // Basic usage
|
|
44
|
+
* // Basic usage. `@object-ui/plugin-grid` has no default export, so unwrap the
|
|
45
|
+
* // named component. Use the `async` form: the `.then((m) => ({ default: m.X }))`
|
|
46
|
+
* // spelling infers `P` as `never` on one branch of the `then` overload.
|
|
40
47
|
* const ObjectGrid = createLazyPlugin(
|
|
41
|
-
* () => import('@object-ui/plugin-grid')
|
|
48
|
+
* async () => ({ default: (await import('@object-ui/plugin-grid')).ObjectGrid })
|
|
42
49
|
* );
|
|
43
50
|
*
|
|
44
51
|
* // With custom fallback
|
|
45
|
-
* const
|
|
46
|
-
* () => import('@object-ui/plugin-grid'),
|
|
52
|
+
* const ObjectGridWithFallback = createLazyPlugin(
|
|
53
|
+
* async () => ({ default: (await import('@object-ui/plugin-grid')).ObjectGrid }),
|
|
47
54
|
* { fallback: <div>Loading grid...</div> }
|
|
48
55
|
* );
|
|
49
56
|
*
|
|
50
57
|
* // With retry and error handling
|
|
51
|
-
* const
|
|
52
|
-
* () => import('@object-ui/plugin-grid'),
|
|
58
|
+
* const ObjectGridWithRetry = createLazyPlugin(
|
|
59
|
+
* async () => ({ default: (await import('@object-ui/plugin-grid')).ObjectGrid }),
|
|
53
60
|
* {
|
|
54
61
|
* retries: 3,
|
|
55
62
|
* errorFallback: ({ error, retry }) => (
|
package/dist/LazyPluginLoader.js
CHANGED
|
@@ -58,26 +58,33 @@ function createRetryImport(importFn, retries, retryDelay) {
|
|
|
58
58
|
/**
|
|
59
59
|
* Create a lazy-loaded plugin component with Suspense wrapper
|
|
60
60
|
*
|
|
61
|
-
* @param importFn - Dynamic import function
|
|
61
|
+
* @param importFn - Dynamic import function resolving to a module whose
|
|
62
|
+
* `default` is the component to render. ObjectUI plugin packages export
|
|
63
|
+
* their components by NAME and have no `default`, so a bare
|
|
64
|
+
* `() => import('@object-ui/plugin-<x>')` does NOT satisfy this — it hands
|
|
65
|
+
* over the module namespace object, which is neither a component at runtime
|
|
66
|
+
* nor assignable here. Name the component you want, as the examples do.
|
|
62
67
|
* @param options - Configuration options for the lazy plugin
|
|
63
68
|
* @returns A component that lazy loads the plugin
|
|
64
69
|
*
|
|
65
70
|
* @example
|
|
66
71
|
* ```tsx
|
|
67
|
-
* // Basic usage
|
|
72
|
+
* // Basic usage. `@object-ui/plugin-grid` has no default export, so unwrap the
|
|
73
|
+
* // named component. Use the `async` form: the `.then((m) => ({ default: m.X }))`
|
|
74
|
+
* // spelling infers `P` as `never` on one branch of the `then` overload.
|
|
68
75
|
* const ObjectGrid = createLazyPlugin(
|
|
69
|
-
* () => import('@object-ui/plugin-grid')
|
|
76
|
+
* async () => ({ default: (await import('@object-ui/plugin-grid')).ObjectGrid })
|
|
70
77
|
* );
|
|
71
78
|
*
|
|
72
79
|
* // With custom fallback
|
|
73
|
-
* const
|
|
74
|
-
* () => import('@object-ui/plugin-grid'),
|
|
80
|
+
* const ObjectGridWithFallback = createLazyPlugin(
|
|
81
|
+
* async () => ({ default: (await import('@object-ui/plugin-grid')).ObjectGrid }),
|
|
75
82
|
* { fallback: <div>Loading grid...</div> }
|
|
76
83
|
* );
|
|
77
84
|
*
|
|
78
85
|
* // With retry and error handling
|
|
79
|
-
* const
|
|
80
|
-
* () => import('@object-ui/plugin-grid'),
|
|
86
|
+
* const ObjectGridWithRetry = createLazyPlugin(
|
|
87
|
+
* async () => ({ default: (await import('@object-ui/plugin-grid')).ObjectGrid }),
|
|
81
88
|
* {
|
|
82
89
|
* retries: 3,
|
|
83
90
|
* errorFallback: ({ error, retry }) => (
|