@object-ui/react 17.3.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 +1242 -0
- package/README.md +48 -21
- package/dist/LazyPluginLoader.d.ts +14 -7
- package/dist/LazyPluginLoader.js +14 -7
- package/dist/SchemaRenderer.d.ts +78 -5
- package/dist/SchemaRenderer.js +572 -34
- package/dist/context/AppShellContext.d.ts +21 -2
- package/dist/context/HostNavigationContext.d.ts +82 -0
- package/dist/context/HostNavigationContext.js +65 -0
- package/dist/context/RecordContext.d.ts +0 -4
- package/dist/context/RecordContext.js +0 -2
- package/dist/context/RelatedRecordActionsContext.d.ts +44 -0
- package/dist/context/RelatedRecordActionsContext.js +6 -0
- package/dist/context/index.d.ts +13 -12
- package/dist/context/index.js +13 -12
- package/dist/element-data-source/ElementDataSourceGate.d.ts +272 -0
- package/dist/element-data-source/ElementDataSourceGate.js +274 -0
- package/dist/hooks/index.d.ts +35 -32
- package/dist/hooks/index.js +42 -32
- package/dist/hooks/useActionEngine.js +1 -1
- package/dist/hooks/useActionTextLocalizer.d.ts +69 -0
- package/dist/hooks/useActionTextLocalizer.js +91 -0
- 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.d.ts +104 -0
- package/dist/hooks/useDatasetDimensionLabels.js +154 -0
- package/dist/hooks/useDiscovery.js +1 -1
- package/dist/hooks/useElementDataSource.d.ts +68 -0
- package/dist/hooks/useElementDataSource.js +141 -0
- package/dist/hooks/useExpression.d.ts +82 -3
- package/dist/hooks/useExpression.js +121 -4
- package/dist/hooks/useNavigationOverlay.d.ts +59 -11
- package/dist/hooks/useOffline.d.ts +62 -36
- package/dist/hooks/useOffline.js +2 -2
- package/dist/hooks/usePageAssignment.js +5 -5
- 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 -9
- package/dist/index.js +12 -8
- package/dist/schema-input.d.ts +42 -0
- package/dist/schema-input.js +42 -0
- package/dist/spec-bridge/SpecBridge.d.ts +12 -6
- package/dist/spec-bridge/SpecBridge.js +9 -3
- 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 +143 -24
- package/dist/spec-bridge/index.d.ts +4 -4
- package/dist/spec-bridge/index.js +3 -3
- package/dist/spec-bridge/types.d.ts +24 -3
- package/dist/utils/error-message.d.ts +59 -0
- package/dist/utils/error-message.js +116 -1
- package/dist/utils/i18n.d.ts +43 -8
- package/dist/utils/i18n.js +42 -4
- 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 +8 -8
package/README.md
CHANGED
|
@@ -121,18 +121,56 @@ function MyComponent() {
|
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
###
|
|
124
|
+
### useElementDataSourceSchema / ElementDataSourceGate
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
Consume `PageComponentSchema.dataSource` — the spec's per-element data binding
|
|
127
|
+
(`{ object, view?, filter?, sort?, limit? }`) — in a block that has its own key
|
|
128
|
+
names. `useElementDataSource` resolves the binding (fetching the object's saved
|
|
129
|
+
views so `view` can be matched); these two apply the composed result to the
|
|
130
|
+
block's schema and render the two non-final states.
|
|
127
131
|
|
|
128
132
|
```tsx
|
|
129
|
-
import {
|
|
133
|
+
import { ElementDataSourceGate } from '@object-ui/react'
|
|
134
|
+
|
|
135
|
+
// `mapping` names ONLY the keys this block reads. A composed value written onto
|
|
136
|
+
// a key the block ignores would be accepted and silently dropped — the defect
|
|
137
|
+
// the binding exists to remove.
|
|
138
|
+
const OBJECT_GRID_BINDING = {
|
|
139
|
+
columns: true, // the view's FIELD list may fill `schema.columns`
|
|
140
|
+
filter: true, // AND-combined, never replaced ("additional criteria")
|
|
141
|
+
sort: true,
|
|
142
|
+
limit: 'pagination.pageSize' as const,
|
|
143
|
+
}
|
|
130
144
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
145
|
+
const ObjectGridRenderer = ({ schema, ...props }) => (
|
|
146
|
+
<ElementDataSourceGate schema={schema} mapping={OBJECT_GRID_BINDING} testId="object-grid">
|
|
147
|
+
{(bound) => <ObjectGrid schema={bound} {...props} />}
|
|
148
|
+
</ElementDataSourceGate>
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`object` lands on `objectName` by default (pass `object: 'apiName'` for another
|
|
153
|
+
key, or `object: false` for a block that reads the composed binding itself).
|
|
154
|
+
Precedence: binding keys beat the component's own, view-sourced values are only a
|
|
155
|
+
baseline the component's own key overrides, and `filter` AND-combines all three.
|
|
156
|
+
A `view` name that does not resolve renders a configuration error rather than
|
|
157
|
+
falling back to the object's full scope. Use `useElementDataSourceSchema` (plus
|
|
158
|
+
the exported `ElementDataSourceErrorPanel` / `ElementDataSourceLoadingPanel`) when
|
|
159
|
+
a block cannot be wrapped — a renderer whose hooks must run before the panels.
|
|
160
|
+
|
|
161
|
+
### ComponentRegistry
|
|
162
|
+
|
|
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.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { ComponentRegistry } from '@object-ui/core'
|
|
169
|
+
|
|
170
|
+
function MyComponent(props: Record<string, unknown>) {
|
|
171
|
+
const Component = ComponentRegistry.get('button')
|
|
172
|
+
|
|
173
|
+
return Component ? <Component {...props} /> : null
|
|
136
174
|
}
|
|
137
175
|
```
|
|
138
176
|
|
|
@@ -225,22 +263,11 @@ leaves the surface on its own anchor), `visibleNotificationStack` (`maxVisible`
|
|
|
225
263
|
|
|
226
264
|
## API Reference
|
|
227
265
|
|
|
228
|
-
See [full documentation](https://objectui.org/
|
|
229
|
-
|
|
230
|
-
<!-- release-metadata:v3.3.0 -->
|
|
231
|
-
|
|
232
|
-
## Compatibility
|
|
233
|
-
|
|
234
|
-
- **React:** 18.x or 19.x
|
|
235
|
-
- **Node.js:** ≥ 18
|
|
236
|
-
- **TypeScript:** ≥ 5.0 (strict mode)
|
|
237
|
-
- **`@objectstack/spec`:** ^3.3.0
|
|
238
|
-
- **`@objectstack/client`:** ^3.3.0
|
|
239
|
-
- **Tailwind CSS:** ≥ 3.4 (for packages with UI)
|
|
266
|
+
See [full documentation](https://objectui.org/docs/core/schema-renderer) for detailed API reference.
|
|
240
267
|
|
|
241
268
|
## Links
|
|
242
269
|
|
|
243
|
-
- 📚 [Documentation](https://www.objectui.org/docs/
|
|
270
|
+
- 📚 [Documentation](https://www.objectui.org/docs/core/schema-renderer)
|
|
244
271
|
- 📦 [npm package](https://www.npmjs.com/package/@object-ui/react)
|
|
245
272
|
- 📝 [Changelog](./CHANGELOG.md)
|
|
246
273
|
- 🐛 [Report an issue](https://github.com/objectstack-ai/objectui/issues)
|
|
@@ -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 }) => (
|
package/dist/SchemaRenderer.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
|
-
import React, { Component } from 'react';
|
|
9
|
-
import {
|
|
8
|
+
import React, { Component, type ForwardRefExoticComponent, type RefAttributes } from 'react';
|
|
9
|
+
import type { BaseSchema } from '@object-ui/types';
|
|
10
10
|
/**
|
|
11
11
|
* Per-component Error Boundary for SchemaRenderer.
|
|
12
12
|
* Catches render errors in individual components, preventing one broken
|
|
@@ -30,7 +30,80 @@ export declare class SchemaErrorBoundary extends Component<{
|
|
|
30
30
|
handleRetry: () => void;
|
|
31
31
|
render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
/**
|
|
34
|
+
* The props `SchemaRenderer` DECLARES and reads itself (objectui#4548).
|
|
35
|
+
*
|
|
36
|
+
* ## Why `schema` is spelled as this union and not as a `SchemaNode`
|
|
37
|
+
*
|
|
38
|
+
* The repo carries two competing `SchemaNode` types: `@object-ui/core`'s
|
|
39
|
+
* interface (which requires `type: string`) and `@object-ui/types`' union
|
|
40
|
+
* (`BaseSchema | string | number | boolean | null | undefined`). This component
|
|
41
|
+
* matched NEITHER. It declared core's — narrower than what it accepts, so every
|
|
42
|
+
* caller holding the types union was wrong and could not be told — while its
|
|
43
|
+
* runtime returns early for strings and nullish, which core's interface forbids.
|
|
44
|
+
* The erasure below hid the mismatch completely: with props collapsed to an
|
|
45
|
+
* index signature, `schema` resolved to `any` and no call site was ever checked.
|
|
46
|
+
*
|
|
47
|
+
* So the contract is STATED HERE, by this component, as what it actually
|
|
48
|
+
* handles: an object schema, a bare string (rendered as text), or nothing at
|
|
49
|
+
* all. `number` / `boolean` are deliberately excluded — the runtime tolerates
|
|
50
|
+
* them defensively (see the primitive guard in the evaluation memo) but no
|
|
51
|
+
* author should be invited to pass them. Reconciling the two repo-wide
|
|
52
|
+
* `SchemaNode` spellings is a separate concern and deliberately not done here.
|
|
53
|
+
*/
|
|
54
|
+
export interface SchemaRendererProps {
|
|
55
|
+
schema: BaseSchema | string | null | undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The open forwarding surface, named once so it reads as the decision it is.
|
|
59
|
+
*
|
|
60
|
+
* `SchemaRenderer` passes every prop it does not itself read straight through to
|
|
61
|
+
* the component the schema names, which is resolved at RUNTIME from a
|
|
62
|
+
* plugin-extensible registry — so the set of valid keys is not knowable here,
|
|
63
|
+
* and `packages/react/README.md` documents callers relying on it. The `any` is
|
|
64
|
+
* the point: this is a pass-through channel, not a typed prop.
|
|
65
|
+
*/
|
|
66
|
+
type ForwardedProps = Record<string, any>;
|
|
67
|
+
/**
|
|
68
|
+
* The renderer loop.
|
|
69
|
+
*
|
|
70
|
+
* ## The explicit type annotation is the contract, and it is deliberate
|
|
71
|
+
*
|
|
72
|
+
* `forwardRef< T, P >` routes `P` through React's `PropsWithoutRef`:
|
|
73
|
+
*
|
|
74
|
+
* Props extends any ? ('ref' extends keyof Props ? Omit< Props, 'ref' > : Props) : Props
|
|
75
|
+
*
|
|
76
|
+
* A string index signature on `P` puts `string` into `keyof Props`, so
|
|
77
|
+
* `'ref' extends keyof Props` is ALWAYS true, the `Omit` branch always runs, and
|
|
78
|
+
* `Omit` over a type carrying a string index signature keeps ONLY the index
|
|
79
|
+
* signature. Every declared prop is erased — on both sides. This component used
|
|
80
|
+
* to hand `forwardRef` a props type of `{ schema: SchemaNode } & Record< string,
|
|
81
|
+
* any >`, so its own `schema` resolved to `any` at every one of the ~376 call
|
|
82
|
+
* sites in this repo, and was not even REQUIRED: `< SchemaRenderer / >` with no
|
|
83
|
+
* schema at all type-checked (objectui#4548, measured).
|
|
84
|
+
*
|
|
85
|
+
* The fix is NOT to close the surface. This is the renderer loop: it forwards
|
|
86
|
+
* every prop it does not read to the component the schema names, resolved at
|
|
87
|
+
* RUNTIME from a plugin-extensible `ComponentRegistry`. That forwarding is a
|
|
88
|
+
* documented, load-bearing feature — `packages/react/README.md` shows
|
|
89
|
+
* `< SchemaRenderer schema={formSchema} onSubmit={handleSubmit} / >`, and
|
|
90
|
+
* `@object-ui/components`' form renderer consumes that `onSubmit` as a React
|
|
91
|
+
* prop. A closed props type would state a FALSE contract and would force every
|
|
92
|
+
* leaf plugin's props into this package to stay usable.
|
|
93
|
+
*
|
|
94
|
+
* So the two halves are separated deliberately:
|
|
95
|
+
*
|
|
96
|
+
* * the `forwardRef` TYPE ARGUMENT is the honest `SchemaRendererProps`, with
|
|
97
|
+
* no index signature — nothing for `PropsWithoutRef` to collapse, so
|
|
98
|
+
* `schema` survives to the call site typed and required; and
|
|
99
|
+
* * the open forwarding surface is stated ONCE, here, in this export
|
|
100
|
+
* annotation. Because the annotation is applied to the already-built
|
|
101
|
+
* component, `PropsWithoutRef` never runs over it, so `Record< string, any >`
|
|
102
|
+
* widens the surface WITHOUT erasing anything.
|
|
103
|
+
*
|
|
104
|
+
* The repo-wide guard (`scripts/__tests__/forwardref-props-erasure.guard.test.ts`)
|
|
105
|
+
* judges the TYPE ARGUMENT only, for exactly this reason: an index signature
|
|
106
|
+
* there is an accidental eraser, whereas one here is a stated contract.
|
|
107
|
+
*/
|
|
108
|
+
export declare const SchemaRenderer: ForwardRefExoticComponent<SchemaRendererProps & ForwardedProps & RefAttributes<unknown>>;
|
|
36
109
|
export {};
|