@object-ui/react 17.5.0 → 17.7.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 +4100 -0
- package/README.md +303 -46
- package/dist/LazyPluginLoader.d.ts +14 -7
- package/dist/LazyPluginLoader.js +14 -7
- package/dist/SchemaRenderer.d.ts +38 -7
- package/dist/SchemaRenderer.js +1603 -60
- package/dist/context/ActionContext.js +40 -1
- package/dist/context/DiscussionContext.d.ts +12 -0
- package/dist/context/DiscussionContext.js +2 -0
- package/dist/context/DrillNavigationContext.d.ts +13 -0
- package/dist/context/HostNavigationContext.d.ts +82 -0
- package/dist/context/HostNavigationContext.js +65 -0
- package/dist/context/InlineEditContext.d.ts +81 -1
- package/dist/context/InlineEditContext.js +8 -2
- package/dist/context/RecordContext.d.ts +48 -5
- package/dist/context/RecordContext.js +10 -1
- package/dist/context/RelatedRecordActionsContext.d.ts +20 -1
- package/dist/context/SchemaRendererContext.d.ts +54 -2
- package/dist/context/SchemaRendererContext.js +38 -5
- package/dist/context/ThemeContext.js +1 -1
- package/dist/context/actionRunnerTranslator.d.ts +27 -0
- package/dist/context/actionRunnerTranslator.js +37 -0
- package/dist/context/index.d.ts +13 -12
- package/dist/context/index.js +13 -12
- package/dist/element-data-source/ElementDataSourceGate.d.ts +163 -3
- package/dist/element-data-source/ElementDataSourceGate.js +407 -15
- package/dist/hooks/index.d.ts +37 -35
- package/dist/hooks/index.js +44 -35
- package/dist/hooks/useActionEngine.js +47 -4
- package/dist/hooks/useActionRunner.js +4 -0
- package/dist/hooks/useActionTextLocalizer.d.ts +21 -8
- package/dist/hooks/useActionTextLocalizer.js +33 -8
- package/dist/hooks/useCapabilityGate.js +6 -5
- package/dist/hooks/useConfigBagEvaluator.d.ts +30 -0
- package/dist/hooks/useConfigBagEvaluator.js +39 -0
- package/dist/hooks/useCrudShortcuts.js +1 -1
- package/dist/hooks/useDatasetDimensionLabels.js +1 -1
- package/dist/hooks/useDensityMode.d.ts +6 -2
- package/dist/hooks/useDensityMode.js +6 -2
- package/dist/hooks/useDiscovery.d.ts +1 -10
- package/dist/hooks/useDiscovery.js +1 -1
- package/dist/hooks/useETagCache.js +25 -4
- package/dist/hooks/useElementDataSource.d.ts +15 -2
- package/dist/hooks/useElementDataSource.js +29 -9
- package/dist/hooks/useExpression.d.ts +52 -38
- package/dist/hooks/useExpression.js +62 -42
- package/dist/hooks/useFilterScope.d.ts +22 -2
- package/dist/hooks/useFilterScope.js +29 -4
- package/dist/hooks/useGlobalUndo.d.ts +10 -0
- package/dist/hooks/useGlobalUndo.js +112 -46
- package/dist/hooks/useNavigationOverlay.d.ts +77 -12
- package/dist/hooks/useNavigationOverlay.js +119 -9
- package/dist/hooks/useOffline.js +65 -11
- package/dist/hooks/usePageAssignment.d.ts +8 -5
- package/dist/hooks/usePageAssignment.js +38 -17
- package/dist/hooks/usePageTransition.js +1 -1
- package/dist/hooks/usePageVariableActionBridge.js +2 -2
- package/dist/hooks/useRecordSearch.d.ts +34 -1
- package/dist/hooks/useRecordSearch.js +42 -7
- package/dist/hooks/useResolvedFilter.d.ts +46 -0
- package/dist/hooks/useResolvedFilter.js +130 -0
- package/dist/hooks/useSchemaPersistence.d.ts +7 -0
- package/dist/hooks/useSchemaPersistence.js +144 -5
- package/dist/hooks/useSettledSchema.d.ts +123 -0
- package/dist/hooks/useSettledSchema.js +186 -0
- package/dist/hooks/useViewData.d.ts +7 -2
- package/dist/hooks/useViewData.js +1 -1
- package/dist/hooks/useViewTransition.js +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.js +54 -10
- package/dist/schema-input.d.ts +55 -14
- package/dist/schema-input.js +55 -12
- package/dist/utils/configBag.d.ts +68 -0
- package/dist/utils/configBag.js +70 -0
- package/dist/utils/error-message.d.ts +59 -0
- package/dist/utils/error-message.js +116 -1
- package/dist/utils/inlineAria.d.ts +61 -0
- package/dist/utils/inlineAria.js +70 -0
- package/dist/utils/nonGridRowCeiling.d.ts +44 -0
- package/dist/utils/nonGridRowCeiling.js +78 -0
- package/dist/utils/paramsBag.d.ts +28 -0
- package/dist/utils/paramsBag.js +146 -0
- package/dist/utils/propsBagDiagnostic.d.ts +196 -0
- package/dist/utils/propsBagDiagnostic.js +421 -0
- package/dist/utils/refusedDataPropDiagnostic.d.ts +44 -0
- package/dist/utils/refusedDataPropDiagnostic.js +94 -0
- package/dist/utils/unevaluatedExpression.d.ts +110 -0
- package/dist/utils/unevaluatedExpression.js +257 -0
- package/dist/utils/visibilityDiagnostic.d.ts +371 -0
- package/dist/utils/visibilityDiagnostic.js +551 -0
- package/package.json +10 -10
- package/dist/hooks/useClientNotifications.d.ts +0 -47
- package/dist/hooks/useClientNotifications.js +0 -162
- package/dist/spec-bridge/SpecBridge.d.ts +0 -28
- package/dist/spec-bridge/SpecBridge.js +0 -56
- package/dist/spec-bridge/bridges/form-view.d.ts +0 -82
- package/dist/spec-bridge/bridges/form-view.js +0 -126
- package/dist/spec-bridge/bridges/list-view.d.ts +0 -20
- package/dist/spec-bridge/bridges/list-view.js +0 -241
- package/dist/spec-bridge/index.d.ts +0 -11
- package/dist/spec-bridge/index.js +0 -10
- package/dist/spec-bridge/types.d.ts +0 -55
- package/dist/spec-bridge/types.js +0 -8
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useContext, useMemo } from 'react';
|
|
3
|
+
import { usePredicateScope } from '../hooks/useExpression.js';
|
|
3
4
|
const SchemaRendererContext = createContext(null);
|
|
4
5
|
export { SchemaRendererContext };
|
|
5
6
|
export const SchemaRendererProvider = ({ children, dataSource, debug, debugFlags, apiFetch, }) => {
|
|
@@ -18,13 +19,45 @@ export const useSchemaContext = () => {
|
|
|
18
19
|
}
|
|
19
20
|
return context;
|
|
20
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a `bind` path against the ambient predicate scope.
|
|
24
|
+
*
|
|
25
|
+
* ## What it reads, and what it deliberately does not (objectui#9308)
|
|
26
|
+
*
|
|
27
|
+
* The scope a host publishes through `PredicateScopeProvider` — the same
|
|
28
|
+
* channel `useCondition` / `useExpression` merge under a locally-passed
|
|
29
|
+
* context, and the one app-shell's `ExpressionProvider` already feeds. It is
|
|
30
|
+
* NOT `SchemaRendererContext.dataSource`.
|
|
31
|
+
*
|
|
32
|
+
* `dataSource` is the host's injected ADAPTER, declared as the published
|
|
33
|
+
* `DataSource` contract (objectui#7912). An adapter has no `users` member, no
|
|
34
|
+
* `value` member, no member a `bind` path names — so walking it resolved
|
|
35
|
+
* `undefined` for every conformant host, and the nine production readers of
|
|
36
|
+
* this hook have all been running their fallback (`boundData || schema.items`,
|
|
37
|
+
* `|| schema.nodes`, or a fall-through to their own fetch chain) ever since.
|
|
38
|
+
* The only hosts it answered were ones injecting a data bag through a key the
|
|
39
|
+
* contract says is an adapter, which has been a compile error since
|
|
40
|
+
* objectui#7912.
|
|
41
|
+
*
|
|
42
|
+
* Maintainer ruling 2026-09-13 (option B) points it at the channel that can
|
|
43
|
+
* actually answer it. No published key is added: the provider, the hook and
|
|
44
|
+
* the host wiring all already exist.
|
|
45
|
+
*
|
|
46
|
+
* Returns `undefined` for an absent or empty path, and for any path the scope
|
|
47
|
+
* does not carry — the readers' fallbacks are what run then, exactly as
|
|
48
|
+
* before.
|
|
49
|
+
*/
|
|
21
50
|
export const useDataScope = (path) => {
|
|
22
|
-
const
|
|
23
|
-
const dataSource = context?.dataSource;
|
|
51
|
+
const scope = usePredicateScope();
|
|
24
52
|
if (!path)
|
|
25
53
|
return undefined;
|
|
26
|
-
if (!
|
|
54
|
+
if (!scope)
|
|
27
55
|
return undefined;
|
|
28
|
-
// Simple path resolution for now. In real app might be more complex
|
|
29
|
-
|
|
56
|
+
// Simple path resolution for now. In real app might be more complex.
|
|
57
|
+
//
|
|
58
|
+
// The accumulator is `any` BY DECLARATION: this walk addresses arbitrary
|
|
59
|
+
// member names on a host-published bag, and `Record<string, any>` declares
|
|
60
|
+
// none of them beyond the first segment. The hook's published return type is
|
|
61
|
+
// unchanged — `any` before and after — so no reader of `useDataScope` moves.
|
|
62
|
+
return path.split('.').reduce((acc, part) => acc && acc[part], scope);
|
|
30
63
|
};
|
|
@@ -131,7 +131,7 @@ export function ThemeProvider({ themes: themesInput = [], defaultTheme, defaultM
|
|
|
131
131
|
// Apply mode class
|
|
132
132
|
el.classList.remove('light', 'dark');
|
|
133
133
|
el.classList.add(resolvedMode);
|
|
134
|
-
// No favicon here: spec v17 (#3494) pruned `Theme.logo`, so the key is
|
|
134
|
+
// No favicon here: spec v17 (objectstack-ai/objectstack#3494) pruned `Theme.logo`, so the key is
|
|
135
135
|
// stripped at parse and could never arrive. The live favicon comes from
|
|
136
136
|
// operator branding (`getFaviconUrl()`), applied in the console's
|
|
137
137
|
// index.html, main.tsx, and on route change.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/** What `ActionRunner.setTranslator` takes. */
|
|
9
|
+
type ActionRunnerTranslate = (key: string, options: {
|
|
10
|
+
defaultValue: string;
|
|
11
|
+
}) => string;
|
|
12
|
+
/**
|
|
13
|
+
* The translator both React owners of an `ActionRunner` — `<ActionProvider>`
|
|
14
|
+
* and `useActionRunner` — install on the runner they build, so the text the
|
|
15
|
+
* runner writes itself (the generic success toast an action with no
|
|
16
|
+
* `successMessage` ends in) renders in the session's language instead of
|
|
17
|
+
* English. Internal to this package; not re-exported from its entry.
|
|
18
|
+
*
|
|
19
|
+
* The function is created once per mount and reads the latest `t` when it is
|
|
20
|
+
* CALLED, so a language switch reaches a runner that was built before it. Both
|
|
21
|
+
* owners rebuild their runner only when their `context` changes, and a
|
|
22
|
+
* translator captured at build time would keep answering in the language that
|
|
23
|
+
* was active then. The identity comes from `useState`'s initializer, not from a
|
|
24
|
+
* memo, so nothing depends on a `useMemo` result staying put (AGENTS.md #10).
|
|
25
|
+
*/
|
|
26
|
+
export declare function useActionRunnerTranslator(): ActionRunnerTranslate;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import { useEffect, useRef, useState } from 'react';
|
|
9
|
+
import { useObjectTranslation } from '@object-ui/i18n';
|
|
10
|
+
/**
|
|
11
|
+
* The translator both React owners of an `ActionRunner` — `<ActionProvider>`
|
|
12
|
+
* and `useActionRunner` — install on the runner they build, so the text the
|
|
13
|
+
* runner writes itself (the generic success toast an action with no
|
|
14
|
+
* `successMessage` ends in) renders in the session's language instead of
|
|
15
|
+
* English. Internal to this package; not re-exported from its entry.
|
|
16
|
+
*
|
|
17
|
+
* The function is created once per mount and reads the latest `t` when it is
|
|
18
|
+
* CALLED, so a language switch reaches a runner that was built before it. Both
|
|
19
|
+
* owners rebuild their runner only when their `context` changes, and a
|
|
20
|
+
* translator captured at build time would keep answering in the language that
|
|
21
|
+
* was active then. The identity comes from `useState`'s initializer, not from a
|
|
22
|
+
* memo, so nothing depends on a `useMemo` result staying put (AGENTS.md #10).
|
|
23
|
+
*/
|
|
24
|
+
export function useActionRunnerTranslator() {
|
|
25
|
+
const { t } = useObjectTranslation();
|
|
26
|
+
const latest = useRef(t);
|
|
27
|
+
// No dependency list: after every render, the ref holds that render's `t`.
|
|
28
|
+
// Actions run from user events, which arrive after the commit.
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
latest.current = t;
|
|
31
|
+
});
|
|
32
|
+
const [translate] = useState(() => {
|
|
33
|
+
const read = (key, options) => String(latest.current(key, options));
|
|
34
|
+
return read;
|
|
35
|
+
});
|
|
36
|
+
return translate;
|
|
37
|
+
}
|
package/dist/context/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
export * from './SchemaRendererContext';
|
|
2
|
-
export * from './PreviewModeContext';
|
|
3
|
-
export * from './ActionContext';
|
|
4
|
-
export * from './ThemeContext';
|
|
5
|
-
export * from './NotificationContext';
|
|
6
|
-
export * from './DndContext';
|
|
7
|
-
export * from './AppShellContext';
|
|
8
|
-
export * from './RecordContext';
|
|
9
|
-
export * from './InlineEditContext';
|
|
10
|
-
export * from './DiscussionContext';
|
|
11
|
-
export * from './DrillNavigationContext';
|
|
12
|
-
export * from './
|
|
1
|
+
export * from './SchemaRendererContext.js';
|
|
2
|
+
export * from './PreviewModeContext.js';
|
|
3
|
+
export * from './ActionContext.js';
|
|
4
|
+
export * from './ThemeContext.js';
|
|
5
|
+
export * from './NotificationContext.js';
|
|
6
|
+
export * from './DndContext.js';
|
|
7
|
+
export * from './AppShellContext.js';
|
|
8
|
+
export * from './RecordContext.js';
|
|
9
|
+
export * from './InlineEditContext.js';
|
|
10
|
+
export * from './DiscussionContext.js';
|
|
11
|
+
export * from './DrillNavigationContext.js';
|
|
12
|
+
export * from './HostNavigationContext.js';
|
|
13
|
+
export * from './RelatedRecordActionsContext.js';
|
package/dist/context/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
export * from './SchemaRendererContext';
|
|
2
|
-
export * from './PreviewModeContext';
|
|
3
|
-
export * from './ActionContext';
|
|
4
|
-
export * from './ThemeContext';
|
|
5
|
-
export * from './NotificationContext';
|
|
6
|
-
export * from './DndContext';
|
|
7
|
-
export * from './AppShellContext';
|
|
8
|
-
export * from './RecordContext';
|
|
9
|
-
export * from './InlineEditContext';
|
|
10
|
-
export * from './DiscussionContext';
|
|
11
|
-
export * from './DrillNavigationContext';
|
|
12
|
-
export * from './
|
|
1
|
+
export * from './SchemaRendererContext.js';
|
|
2
|
+
export * from './PreviewModeContext.js';
|
|
3
|
+
export * from './ActionContext.js';
|
|
4
|
+
export * from './ThemeContext.js';
|
|
5
|
+
export * from './NotificationContext.js';
|
|
6
|
+
export * from './DndContext.js';
|
|
7
|
+
export * from './AppShellContext.js';
|
|
8
|
+
export * from './RecordContext.js';
|
|
9
|
+
export * from './InlineEditContext.js';
|
|
10
|
+
export * from './DiscussionContext.js';
|
|
11
|
+
export * from './DrillNavigationContext.js';
|
|
12
|
+
export * from './HostNavigationContext.js';
|
|
13
|
+
export * from './RelatedRecordActionsContext.js';
|
|
@@ -50,6 +50,27 @@
|
|
|
50
50
|
* designer emits for an unconfigured column list, and supplying the columns is
|
|
51
51
|
* exactly why a view was named.
|
|
52
52
|
*
|
|
53
|
+
* The row cap answers "did the component author one?" the same way, and for the
|
|
54
|
+
* same reason (objectui#9899). A cap the contract REFUSES — `pageSize: 0`,
|
|
55
|
+
* a negative, a fraction — is not a cap this relay may treat as the author's
|
|
56
|
+
* intent, so it does not suppress the one the bound view supplies. Deciding
|
|
57
|
+
* that question by PRESENCE is how a view's legitimate cap was dropped in
|
|
58
|
+
* favour of the consuming renderer's own default: measured end to end on
|
|
59
|
+
* `list-view` before the repair, a component carrying `pagination.pageSize: 0`
|
|
60
|
+
* under a view supplying `7` put `$top: 100` on the wire — the view's cap never
|
|
61
|
+
* reached it, so the read was WIDER than the view asked for.
|
|
62
|
+
*
|
|
63
|
+
* The VIEW's own cap can be refused too, and `@object-ui/core` drops it before
|
|
64
|
+
* it reaches this relay (objectui#9928). The drop is right, but it left the
|
|
65
|
+
* consuming renderer nothing to refuse, so it went silent — and this relay
|
|
66
|
+
* reports the view's refusal instead (objectui#10015). See
|
|
67
|
+
* {@link describeRefusedViewRowLimit} for when that message applies.
|
|
68
|
+
*
|
|
69
|
+
* The BINDING's own cap follows the same rule (objectui#10016): a `limit` the
|
|
70
|
+
* contract refuses is not authored, so `@object-ui/core` lets the view's cap
|
|
71
|
+
* through in its place, and that cap is a baseline here like any other
|
|
72
|
+
* view-sourced value. See {@link describeRefusedBindingRowLimit}.
|
|
73
|
+
*
|
|
53
74
|
* ## What a mapping may NOT do
|
|
54
75
|
*
|
|
55
76
|
* {@link ElementDataSourceMapping} names only keys the target block genuinely
|
|
@@ -59,6 +80,17 @@
|
|
|
59
80
|
* therefore leaves `limit` unmapped rather than parking it somewhere plausible,
|
|
60
81
|
* and the gap is recorded at the call site instead of being papered over here.
|
|
61
82
|
*
|
|
83
|
+
* ## A block with no ADAPTER fails loudly too (objectui#5378)
|
|
84
|
+
*
|
|
85
|
+
* The section below is about an unresolvable view NAME. The coarser failure —
|
|
86
|
+
* no runtime adapter reached the block at all — used to render an empty shell
|
|
87
|
+
* in exactly the same silence, and that is what `requiresDataSource` +
|
|
88
|
+
* {@link NoDataSourcePanel} now report. Measured on the published
|
|
89
|
+
* getting-started guide: all five of its blocks resolved no adapter, fetched
|
|
90
|
+
* nothing, and said nothing. The two panels are deliberately the same shape;
|
|
91
|
+
* they answer "which view?" and "which data source?", and an author who sees
|
|
92
|
+
* either one is being told where to look.
|
|
93
|
+
*
|
|
62
94
|
* ## An unresolvable `view` fails loudly
|
|
63
95
|
*
|
|
64
96
|
* When the named view does not exist the gate renders a configuration error
|
|
@@ -68,8 +100,8 @@
|
|
|
68
100
|
* like it works.
|
|
69
101
|
*/
|
|
70
102
|
import * as React from 'react';
|
|
71
|
-
import { type ElementDataSourceConfig } from '@object-ui/core';
|
|
72
|
-
import { type ElementDataSourceStatus } from '../hooks/useElementDataSource';
|
|
103
|
+
import { type ElementDataSourceConfig, type FilterOperatorError } from '@object-ui/core';
|
|
104
|
+
import { type ElementDataSourceStatus } from '../hooks/useElementDataSource.js';
|
|
73
105
|
/**
|
|
74
106
|
* Where a block's row cap lives. Three spellings are real in this repo and each
|
|
75
107
|
* is the ONLY one its block reads: `list-view`/`object-grid` read
|
|
@@ -128,6 +160,15 @@ export interface UseElementDataSourceSchemaResult<S> {
|
|
|
128
160
|
config?: ElementDataSourceConfig;
|
|
129
161
|
/** Author-facing explanation, set only for `missing`. */
|
|
130
162
|
error?: string;
|
|
163
|
+
/**
|
|
164
|
+
* The refused filter that stopped the binding from applying — set only with
|
|
165
|
+
* `missing`, and `error` then carries its message (objectui#10789). Either
|
|
166
|
+
* merge can refuse: the view's filter with the binding's own
|
|
167
|
+
* ({@link useElementDataSource}), or the component's filter with that result
|
|
168
|
+
* (this hook). {@link ElementDataSourceGate} draws the malformed-filter
|
|
169
|
+
* notice from it.
|
|
170
|
+
*/
|
|
171
|
+
filterRefusal?: FilterOperatorError;
|
|
131
172
|
}
|
|
132
173
|
/**
|
|
133
174
|
* Resolve a block's `dataSource` binding and apply it to the block's own schema
|
|
@@ -169,6 +210,108 @@ export declare function ElementDataSourceErrorPanel({ testId, title, message, }:
|
|
|
169
210
|
* would flash a configuration error on every mount.
|
|
170
211
|
*/
|
|
171
212
|
export declare function ElementDataSourceLoadingPanel({ testId, }: Pick<ElementDataSourceStatusPanelProps, 'testId'>): React.ReactElement;
|
|
213
|
+
/**
|
|
214
|
+
* The adapter this block would use, resolved the one way every block in the
|
|
215
|
+
* family resolves it: an explicit value first, the `SchemaRendererProvider`
|
|
216
|
+
* context second.
|
|
217
|
+
*
|
|
218
|
+
* The `isElementDataSourceConfig` guard is the same one
|
|
219
|
+
* {@link useElementDataSourceSchema} applies — a host handing us the spec
|
|
220
|
+
* BINDING under this name is handing us metadata, not an adapter, and counting
|
|
221
|
+
* it as one is how "no data source" reads as "resolved".
|
|
222
|
+
*
|
|
223
|
+
* `T` is what the CALLER expects to have been injected, and the assertion is
|
|
224
|
+
* the caller's, not this hook's: an adapter arrives here as a `dataSource` prop
|
|
225
|
+
* or a context value that nothing in this package can narrow, so the type has
|
|
226
|
+
* to be declared by whoever knows which interface their block consumes. Leave
|
|
227
|
+
* it off and you get `unknown`, which is the honest default.
|
|
228
|
+
*/
|
|
229
|
+
export declare function useResolvedDataSource<T = unknown>(explicit?: unknown): T | undefined;
|
|
230
|
+
/**
|
|
231
|
+
* The author-facing sentence a block with no adapter says out loud.
|
|
232
|
+
*
|
|
233
|
+
* One wording for the whole object-bound family, because the reader's mistake
|
|
234
|
+
* is the same one every time and the fix is the same one every time: the
|
|
235
|
+
* adapter is injected by an ANCESTOR (`SchemaRendererProvider`), so nothing
|
|
236
|
+
* written on the block itself can supply it. Naming the block and the object
|
|
237
|
+
* it was about to read is what turns "nothing happened" into an address.
|
|
238
|
+
*/
|
|
239
|
+
export declare function noDataSourceMessage(blockKey: string, objectName?: unknown): string;
|
|
240
|
+
/**
|
|
241
|
+
* The "this block resolved no adapter" panel — objectui#5378 item 2, and the
|
|
242
|
+
* #5349 shape it belongs to.
|
|
243
|
+
*
|
|
244
|
+
* Until this existed, a block that resolved no adapter rendered an EMPTY SHELL:
|
|
245
|
+
* `object-grid` painted a header-only table, `object-form` a field-less card,
|
|
246
|
+
* `detail-view` nothing at all — no error, no warning, no empty state that
|
|
247
|
+
* explained itself. Measured on the published getting-started guide
|
|
248
|
+
* (`content/docs/guide/building-crud-app.md`), every one of its five blocks was
|
|
249
|
+
* in that state and the page reported success while fetching nothing.
|
|
250
|
+
*
|
|
251
|
+
* The empty shell is the defect, not a side effect of it: it is indistinguishable
|
|
252
|
+
* from "the query ran and matched no rows", which is the reading an author (very
|
|
253
|
+
* often an AI author) takes, and it points at the DATA when the fault is in the
|
|
254
|
+
* WIRING one level up. Same posture as {@link ElementDataSourceErrorPanel}: the
|
|
255
|
+
* metadata is answerable, so the answer is rendered where the author can see it.
|
|
256
|
+
*/
|
|
257
|
+
export declare function NoDataSourcePanel({ testId, title, message, }: ElementDataSourceStatusPanelProps): React.ReactElement;
|
|
258
|
+
/**
|
|
259
|
+
* The wrapping seam — mark `renderer` as one that wraps {@link
|
|
260
|
+
* ElementDataSourceGate}, so its registrations DECLARE the `dataSource` key this
|
|
261
|
+
* gate READS (objectui#6678).
|
|
262
|
+
*
|
|
263
|
+
* ```tsx
|
|
264
|
+
* export const ObjectMapRenderer = elementDataSourceBlock<React.FC<any>>(({ schema }) => (
|
|
265
|
+
* <ElementDataSourceGate schema={schema} testId="object-map" …>
|
|
266
|
+
* {(bound) => <ObjectMap schema={bound} />}
|
|
267
|
+
* </ElementDataSourceGate>
|
|
268
|
+
* ));
|
|
269
|
+
* ```
|
|
270
|
+
*
|
|
271
|
+
* ## What this closes
|
|
272
|
+
*
|
|
273
|
+
* `PageComponentSchema.dataSource` is the one spelling that resolves a saved
|
|
274
|
+
* view for an object-bound block. It works — and because no registration
|
|
275
|
+
* declared it, `sdui-parser`'s `validateTree` reported it with the SAME
|
|
276
|
+
* `unknown-prop` warning it gives the spellings that do nothing. On the tier
|
|
277
|
+
* built to accept AI-authored pages the diagnostic IS the contract, so the
|
|
278
|
+
* tier's only signal pointed away from the one key that works.
|
|
279
|
+
*
|
|
280
|
+
* ## Why a seam and not nine declarations
|
|
281
|
+
*
|
|
282
|
+
* Maintainer ruling, 2026-08-29: option B **in the injection form**. Nine
|
|
283
|
+
* hand-written copies across nine packages is the shape that ruling refused —
|
|
284
|
+
* they drift, and the tenth block forgets. Passing through here is the only
|
|
285
|
+
* thing a block does; `Registry.register` emits the declaration
|
|
286
|
+
* (`withElementDataSourceInput`), and `ELEMENT_DATA_SOURCE_INPUT` in
|
|
287
|
+
* `@object-ui/core` is its single copy, beside the binding's own semantics.
|
|
288
|
+
*
|
|
289
|
+
* ## And it cannot be forgotten
|
|
290
|
+
*
|
|
291
|
+
* `scripts/check-element-data-source-declaration.mjs` fails any source that
|
|
292
|
+
* renders `ElementDataSourceGate` for a registration without passing that
|
|
293
|
+
* registration's renderer through this function. That is the mechanical half of
|
|
294
|
+
* "a tenth block gets it automatically"; this function is the seam it enforces.
|
|
295
|
+
*
|
|
296
|
+
* Returns the renderer UNCHANGED (the mark is held in a `WeakSet`), so it is safe
|
|
297
|
+
* over a `React.forwardRef` object, over `React.memo`, and over a component that
|
|
298
|
+
* something else already re-exports by reference.
|
|
299
|
+
*
|
|
300
|
+
* ⚠️ Re-exported from `@object-ui/core` — where the marker and the declaration
|
|
301
|
+
* live — rather than wrapped here: ONE function under ONE name. This export
|
|
302
|
+
* exists for DISCOVERABILITY, so the seam is findable beside the gate it is
|
|
303
|
+
* about; **call sites must import it from `@object-ui/core`**, and
|
|
304
|
+
* `check:element-data-source-declaration` enforces that.
|
|
305
|
+
*
|
|
306
|
+
* The rule is measured, not stylistic. A registration runs at MODULE SCOPE, 101
|
|
307
|
+
* suites in this repo partially mock `@object-ui/react` by hand-listing the
|
|
308
|
+
* exports they return, and a module-scope read of a name absent from such a list
|
|
309
|
+
* throws at COLLECTION time — the importing test file dies before running one
|
|
310
|
+
* assertion. Taking the seam from here reddened 17 files across all four CI
|
|
311
|
+
* shards with zero failed assertions among them. Nothing mocks `@object-ui/core`,
|
|
312
|
+
* and every registration module already imports `ComponentRegistry` from it.
|
|
313
|
+
*/
|
|
314
|
+
export { elementDataSourceBlock } from '@object-ui/core';
|
|
172
315
|
export interface ElementDataSourceGateProps<S> {
|
|
173
316
|
/** The block's schema node. */
|
|
174
317
|
schema: S;
|
|
@@ -180,6 +323,23 @@ export interface ElementDataSourceGateProps<S> {
|
|
|
180
323
|
testId: string;
|
|
181
324
|
/** Heading for the unresolvable-view panel. */
|
|
182
325
|
errorTitle?: string;
|
|
326
|
+
/**
|
|
327
|
+
* Whether THIS placement cannot do its job without a runtime adapter — when
|
|
328
|
+
* true and none resolves, the gate renders {@link NoDataSourcePanel} instead
|
|
329
|
+
* of the block (objectui#5378 item 2).
|
|
330
|
+
*
|
|
331
|
+
* The gate cannot compute this and does not try. "Needs an adapter" is a
|
|
332
|
+
* statement about the block's own fallbacks, and every block in the family
|
|
333
|
+
* has different ones: an `object-grid` carrying inline `data` rows needs no
|
|
334
|
+
* adapter, an `object-form` with inline `customFields` needs none, a
|
|
335
|
+
* `detail-view` handed a `data` record needs none. A predicate guessed HERE
|
|
336
|
+
* would paint a configuration error over a block that is working, which is a
|
|
337
|
+
* worse failure than the silence this replaces — so the call site, which
|
|
338
|
+
* knows its own fallbacks, states it.
|
|
339
|
+
*/
|
|
340
|
+
requiresDataSource?: boolean;
|
|
341
|
+
/** Explanation for the no-adapter panel; see {@link noDataSourceMessage}. */
|
|
342
|
+
noDataSourceMessage?: string;
|
|
183
343
|
/**
|
|
184
344
|
* Renders the block with the bound schema. Called during the gate's own
|
|
185
345
|
* render, so it must RETURN AN ELEMENT and never call hooks itself — the
|
|
@@ -196,4 +356,4 @@ export interface ElementDataSourceGateProps<S> {
|
|
|
196
356
|
* against a half-resolved query is how a page shows a wider answer than the one
|
|
197
357
|
* that was authored.
|
|
198
358
|
*/
|
|
199
|
-
export declare function ElementDataSourceGate<S>({ schema, mapping, dataSource, testId, errorTitle, children, }: ElementDataSourceGateProps<S>): React.ReactElement | null;
|
|
359
|
+
export declare function ElementDataSourceGate<S>({ schema, mapping, dataSource, testId, errorTitle, requiresDataSource, noDataSourceMessage: noDataSourceText, children, }: ElementDataSourceGateProps<S>): React.ReactElement | null;
|