@gears-frontx/react 0.1.0 → 0.2.0-alpha.15
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/CLAUDE.md +247 -64
- package/dist/index.cjs +1338 -434
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +653 -146
- package/dist/index.d.ts +653 -146
- package/dist/index.js +1179 -276
- package/dist/index.js.map +1 -1
- package/dist/testing-Dlmfu6tE.d.cts +56 -0
- package/dist/testing-Dlmfu6tE.d.ts +56 -0
- package/dist/testing.cjs +77 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +4 -0
- package/dist/testing.d.ts +4 -0
- package/dist/testing.js +56 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-JtpziA_B.d.cts +224 -0
- package/dist/types-JtpziA_B.d.ts +224 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +2 -2
- package/dist/types.d.ts +2 -2
- package/llms.txt +49 -23
- package/package.json +40 -23
- package/commands/hai3-duplicate-screenset.md +0 -58
- package/commands/hai3-new-component.md +0 -48
- package/commands/hai3-new-mfe.md +0 -166
- package/commands/hai3-new-screen.md +0 -39
- package/commands/hai3-new-screenset.md +0 -47
- package/dist/types-Cp8Zm5s0.d.cts +0 -136
- package/dist/types-Cp8Zm5s0.d.ts +0 -136
package/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @gears-frontx/react
|
|
2
2
|
|
|
3
|
-
React bindings and hooks for
|
|
3
|
+
React bindings and hooks for FrontX applications. Provides the React integration layer with MFE (Microfrontend) support.
|
|
4
4
|
|
|
5
5
|
## React Layer
|
|
6
6
|
|
|
@@ -8,51 +8,180 @@ This package is part of the **React Layer (L3)** - it depends only on @gears-fro
|
|
|
8
8
|
|
|
9
9
|
## Core Concepts
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### FrontXProvider
|
|
12
12
|
|
|
13
|
-
Wrap your app with
|
|
13
|
+
Wrap your app with FrontXProvider to enable all hooks. A runtime builds exactly one app, once at module level; the provider never creates one. The three compositions below are alternatives: choose one per runtime.
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
|
-
import {
|
|
16
|
+
import { createFrontX, FrontXProvider, presets } from '@gears-frontx/react';
|
|
17
|
+
|
|
18
|
+
// Alternative 1: the full preset
|
|
19
|
+
const app = createFrontX({ devMode: true }).useAll(presets.full()).build();
|
|
17
20
|
|
|
18
21
|
function App() {
|
|
19
22
|
return (
|
|
20
|
-
<
|
|
23
|
+
<FrontXProvider app={app}>
|
|
21
24
|
<YourApp />
|
|
22
|
-
</
|
|
25
|
+
</FrontXProvider>
|
|
23
26
|
);
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Alternative 2: a host shell with a custom plugin set (a host typically uses `queryCache()`):
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
const app = createFrontX().use(effects()).use(queryCache()).build();
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Alternative 3: a child MFE app. The canonical bootstrap matches `src/mfe_packages/*/init.ts`: `apiRegistry.register` / `initialize` before `.build()`, `registerSlice` after `.build()` when slices exist:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
const app = createFrontX().use(effects()).use(queryCacheShared()).use(mock()).build();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The shared `QueryClient` is created and owned by the `queryCache()` framework plugin at L2.
|
|
44
|
+
`FrontXProvider` resolves that client from the app instance — it does not create its own `QueryClient`.
|
|
45
|
+
|
|
46
|
+
When the host uses `queryCache()` and the child MFE app uses `queryCacheShared()` (with `effects()` and `mock()` on the same chain as in repo MFE inits), both roots join the same shared `QueryClient` while keeping separate React trees. `ThemeAwareReactLifecycle` relies on that shared plugin-owned client through the app instance. If the shared client is missing for a mounted MFE, the lifecycle fails explicitly instead of silently falling back.
|
|
47
|
+
|
|
48
|
+
For separate roots, build each app with the appropriate query-cache plugin (`queryCache()` for the host, `queryCacheShared()` for child MFE shells) so every tree joins the same cache through plugin composition. Host apps should register domains/extensions during bootstrap; **`ExtensionDomainSlot`** is the preferred host-side renderer for screen slots while the framework wires `mount_ext`.
|
|
49
|
+
|
|
50
|
+
### Data Fetching with Endpoint Descriptors
|
|
51
|
+
|
|
52
|
+
Services define endpoints as descriptors. Components consume them via `useApiQuery` and `useApiMutation`. No manual query keys, no `queryOptions()` calls.
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { useApiQuery, useApiMutation, apiRegistry } from '@gears-frontx/react';
|
|
56
|
+
import { AccountsApiService } from '../api/AccountsApiService';
|
|
57
|
+
|
|
58
|
+
function ProfileScreen({ teamId }: { teamId?: string }) {
|
|
59
|
+
const service = apiRegistry.getService(AccountsApiService);
|
|
60
|
+
|
|
61
|
+
// Read — pass descriptor directly
|
|
62
|
+
const { data, isLoading, error } = useApiQuery(service.getCurrentUser);
|
|
63
|
+
|
|
64
|
+
// Read with params
|
|
65
|
+
const { data: user } = useApiQuery(service.getUser({ id: '123' }));
|
|
66
|
+
|
|
67
|
+
// Write with optimistic update
|
|
68
|
+
const { mutateAsync, isPending } = useApiMutation({
|
|
69
|
+
endpoint: service.updateProfile,
|
|
70
|
+
onMutate: async (variables, { queryCache }) => {
|
|
71
|
+
await queryCache.cancel(service.getCurrentUser);
|
|
72
|
+
const snapshot = queryCache.get(service.getCurrentUser);
|
|
73
|
+
queryCache.set(service.getCurrentUser, (old) => ({
|
|
74
|
+
...old, user: { ...old.user, ...variables }
|
|
75
|
+
}));
|
|
76
|
+
return { snapshot };
|
|
77
|
+
},
|
|
78
|
+
onError: (_err, _vars, context, { queryCache }) => {
|
|
79
|
+
if (context?.snapshot) {
|
|
80
|
+
queryCache.set(service.getCurrentUser, context.snapshot);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
onSettled: async (_data, _err, _vars, _ctx, { queryCache }) => {
|
|
84
|
+
await queryCache.invalidate(service.getCurrentUser);
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Per-endpoint cache override (rare)
|
|
89
|
+
const { data: config } = useApiQuery(service.getConfig, { staleTime: 0 });
|
|
30
90
|
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
91
|
+
// Conditional query: stays idle until enabled (not on the suspense hooks).
|
|
92
|
+
// The hook still needs a descriptor on every render, so one is built with a
|
|
93
|
+
// stand-in id; while enabled is false it is not fetched automatically, and
|
|
94
|
+
// refetch would still fetch it, so do not call refetch before teamId is set.
|
|
95
|
+
const { data: team } = useApiQuery(service.getTeam({ id: teamId ?? '' }), { enabled: Boolean(teamId) });
|
|
96
|
+
}
|
|
36
97
|
```
|
|
37
98
|
|
|
99
|
+
Cache keys are derived automatically by the service — `QueryCache` methods accept
|
|
100
|
+
endpoint descriptors directly (e.g., `queryCache.get(service.getCurrentUser)`).
|
|
101
|
+
|
|
102
|
+
The `queryCache` a mutation callback receives is bound to the cache scope (mock mode, tenant, session) the mutation started under: once that scope changes, its writes (`set`, `remove`, `invalidate`, `invalidateMany`, `cancel`) do nothing and reads still work, so a response or snapshot from the old scope never lands in the new cache. Nothing else is scope-bound: a `useQueryCache()` handle, the raw `QueryClient`, `cache/*` eventBus emits and per-call `mutate(vars, { onSuccess })` options write to whatever scope is current, so a write after an `await` or inside a mutation callback must go through the callback's `queryCache`.
|
|
103
|
+
|
|
104
|
+
### SSE Streaming with Stream Descriptors
|
|
105
|
+
|
|
106
|
+
Services declare SSE endpoints as stream descriptors. Components consume them via `useApiStream`, which manages the connection lifecycle automatically (connect on mount, disconnect on unmount).
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { useApiStream, apiRegistry } from '@gears-frontx/react';
|
|
110
|
+
import { ChatApiService } from '../api/ChatApiService';
|
|
111
|
+
|
|
112
|
+
function ChatStream() {
|
|
113
|
+
const service = apiRegistry.getService(ChatApiService);
|
|
114
|
+
|
|
115
|
+
// Latest event only (default mode)
|
|
116
|
+
const { data, status, error } = useApiStream(service.messageStream);
|
|
117
|
+
|
|
118
|
+
// Accumulate all events
|
|
119
|
+
const { events, status: streamStatus } = useApiStream(
|
|
120
|
+
service.messageStream,
|
|
121
|
+
{ mode: 'accumulate' }
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Deferred connection (enabled: false)
|
|
125
|
+
const [active, setActive] = useState(false);
|
|
126
|
+
const { data: msg, disconnect } = useApiStream(
|
|
127
|
+
service.messageStream,
|
|
128
|
+
{ enabled: active }
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (status === 'connecting') return <Loading />;
|
|
132
|
+
if (status === 'error') return <Error error={error} />;
|
|
133
|
+
|
|
134
|
+
return <div>{data?.text}</div>;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`useApiStream` returns `{ data, events, status, error, disconnect }`:
|
|
139
|
+
- `data` — latest event payload (set in both modes)
|
|
140
|
+
- `events` — all received events when `mode: 'accumulate'`; empty array in `'latest'` mode
|
|
141
|
+
- `status` — connection lifecycle state, `StreamStatus` (see below)
|
|
142
|
+
- `error` — the last connect attempt's error; retained until the next connect attempt resets it, so check `status` rather than `error` truthiness
|
|
143
|
+
- `disconnect()` — close the connection manually
|
|
144
|
+
|
|
145
|
+
#### Status lifecycle
|
|
146
|
+
|
|
147
|
+
`status` is a `StreamStatus`: `'idle' | 'connecting' | 'connected' | 'disconnected' | 'error'`.
|
|
148
|
+
|
|
149
|
+
The TSDoc block on `useApiStream` in `src/hooks/useApiStream.ts` is the detailed and authoritative state-machine reference, including teardown edge cases. This guide summarizes consumer-facing usage and gating.
|
|
150
|
+
|
|
151
|
+
`disconnect()` closes the connection and does not reconnect. There is no reconnect function: to open a new connection, change the descriptor key, change `mode`, or toggle `enabled` back to true.
|
|
152
|
+
|
|
153
|
+
#### The `enabled` option
|
|
154
|
+
|
|
155
|
+
`enabled` (default `true`) gates whether the hook connects at all. While it is false the hook never calls the descriptor's `connect()` and ordinarily holds `status: 'idle'` (calling `disconnect()` while disabled is the one exception — see the TSDoc). Flipping it to true re-runs the connect effect and starts a fresh connection; flipping it back to false tears the connection down and returns `status` to `'idle'`.
|
|
156
|
+
|
|
157
|
+
Tearing down via `enabled` does not clear `data` or `events` — a descriptor-key or `mode` change, or re-enabling, does. A component reading `data` while the stream is disabled still sees the last event from the previous connection.
|
|
158
|
+
|
|
159
|
+
Gating advice, since `'idle'` covers both "not started yet" and "deferred by `enabled`":
|
|
160
|
+
|
|
161
|
+
- Gate the loading state on `'connecting'` alone. Treating `'idle'` as loading renders a permanent spinner for a stream deliberately held at `enabled: false`.
|
|
162
|
+
- Handle `'idle'` as "not started / deferred". A component that both defers and shows loading should key its spinner off its own active flag, not off `'idle'`.
|
|
163
|
+
- Check `status === 'error'` rather than the truthiness of `error` to render failures.
|
|
164
|
+
|
|
38
165
|
### Available Hooks
|
|
39
166
|
|
|
40
|
-
####
|
|
167
|
+
#### useFrontX
|
|
41
168
|
|
|
42
|
-
Access the
|
|
169
|
+
Access the FrontX app instance:
|
|
43
170
|
|
|
44
171
|
```tsx
|
|
45
|
-
import {
|
|
172
|
+
import { useFrontX } from '@gears-frontx/react';
|
|
46
173
|
|
|
47
174
|
function MyComponent() {
|
|
48
|
-
const app =
|
|
175
|
+
const app = useFrontX();
|
|
49
176
|
|
|
50
177
|
// Access MFE-enabled registry
|
|
51
|
-
const extensions = app.
|
|
178
|
+
const extensions = app.mfeRegistry.getExtensionsForDomain('screen');
|
|
52
179
|
|
|
53
|
-
// Access MFE actions
|
|
54
|
-
|
|
55
|
-
await
|
|
180
|
+
// Access MFE actions — fire-and-forget: each dispatches an actions chain
|
|
181
|
+
// through the acceptance-only registry surface and returns nothing to
|
|
182
|
+
// await.
|
|
183
|
+
app.actions.loadExtension('home');
|
|
184
|
+
app.actions.mountExtension('home');
|
|
56
185
|
}
|
|
57
186
|
```
|
|
58
187
|
|
|
@@ -138,47 +267,78 @@ Access the MFE bridge for child MFEs:
|
|
|
138
267
|
|
|
139
268
|
```tsx
|
|
140
269
|
import { useMfeBridge } from '@gears-frontx/react';
|
|
141
|
-
import {
|
|
270
|
+
import { FRONTX_ACTION_LOAD_EXT, FRONTX_SHARED_PROPERTY_THEME } from '@gears-frontx/react';
|
|
142
271
|
|
|
143
272
|
function MyExtension() {
|
|
144
273
|
const bridge = useMfeBridge();
|
|
145
274
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
275
|
+
const handleLoad = () => {
|
|
276
|
+
// executeActionsChain is acceptance-only: it returns void, never
|
|
277
|
+
// throws, and never yields anything to await for the chain's own
|
|
278
|
+
// execution.
|
|
279
|
+
bridge.executeActionsChain({
|
|
280
|
+
action: { type: FRONTX_ACTION_LOAD_EXT, target: 'screen', payload: { subject: 'other' } }
|
|
281
|
+
});
|
|
282
|
+
};
|
|
150
283
|
|
|
151
284
|
// Get shared property
|
|
152
|
-
const theme = bridge.getProperty(
|
|
285
|
+
const theme = bridge.getProperty(FRONTX_SHARED_PROPERTY_THEME);
|
|
153
286
|
}
|
|
154
287
|
```
|
|
155
288
|
|
|
156
289
|
#### useSharedProperty
|
|
157
290
|
|
|
158
|
-
Subscribe to shared property changes:
|
|
291
|
+
Subscribe to shared property changes. Two forms: the context form reads the bridge from `MfeContext`, and the options form accepts an explicit bridge and a fallback.
|
|
292
|
+
|
|
293
|
+
**Context form** — `useSharedProperty(propertyTypeId)`. Reads the bridge from `MfeContext` and throws if no `MfeProvider` is mounted. Returns the value (or `undefined` if the host has not published it), updating on every host publish.
|
|
159
294
|
|
|
160
295
|
```tsx
|
|
161
|
-
import { useSharedProperty,
|
|
296
|
+
import { useSharedProperty, FRONTX_SHARED_PROPERTY_THEME } from '@gears-frontx/react';
|
|
162
297
|
|
|
163
298
|
function ThemedComponent() {
|
|
164
|
-
const theme = useSharedProperty(
|
|
299
|
+
const theme = useSharedProperty(FRONTX_SHARED_PROPERTY_THEME);
|
|
165
300
|
|
|
166
301
|
return <div style={{ backgroundColor: theme?.primaryColor }}>...</div>;
|
|
167
302
|
}
|
|
168
303
|
```
|
|
169
304
|
|
|
305
|
+
**Options form** — `useSharedProperty(propertyTypeId, { bridge, fallback })`. Use it for components that never mount `MfeProvider`, or to show a value until the host publishes one.
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
import { useSharedProperty } from '@gears-frontx/react';
|
|
309
|
+
import type { ChildMfeBridge } from '@gears-frontx/framework';
|
|
310
|
+
|
|
311
|
+
function StandaloneComponent({ bridge }: { bridge: ChildMfeBridge }) {
|
|
312
|
+
const label = useSharedProperty<string>(LABEL_PROPERTY_ID, {
|
|
313
|
+
bridge,
|
|
314
|
+
fallback: 'Untitled',
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
return <span>{label}</span>;
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
`UseSharedPropertyOptions<T>` fields:
|
|
322
|
+
|
|
323
|
+
- `bridge` — bridge to read the property from, bypassing `MfeContext`. Pass it when the calling component never mounts `MfeProvider` (for example, a component that receives its bridge as a prop or from a non-React entry point). When omitted, the hook falls back to the bridge from `MfeContext` and throws if no `MfeProvider` is mounted. Changing `bridge` or `propertyTypeId` moves the subscription to the new source and the returned value follows on the same render.
|
|
324
|
+
- `fallback` — value returned while the host has not published the property yet. Only `undefined` is substituted; a published `null` is a real value and comes through as-is. With `fallback` set the hook returns `T` rather than `T | undefined`. It may be passed inline on every render without affecting the subscription.
|
|
325
|
+
|
|
326
|
+
There is no consumer-side validation option on purpose: the host validates every published value against the property's schema before it reaches any MFE (`TypeSystemPlugin.register()` throws on a mismatch and the update is never stored or delivered). `T` is the caller's declaration of that schema, as with `useState<T>`.
|
|
327
|
+
|
|
328
|
+
Both forms read through `useSyncExternalStore`, so the first render shows the host's current value and the result is tearing-protected under concurrent rendering. The TSDoc block on `useSharedProperty` in `src/mfe/hooks/useSharedProperty.ts` is the authoritative reference; this guide summarizes consumer-facing usage.
|
|
329
|
+
|
|
170
330
|
#### useHostAction
|
|
171
331
|
|
|
172
332
|
Invoke actions on the host application:
|
|
173
333
|
|
|
174
334
|
```tsx
|
|
175
|
-
import { useHostAction,
|
|
335
|
+
import { useHostAction, FRONTX_ACTION_LOAD_EXT } from '@gears-frontx/react';
|
|
176
336
|
|
|
177
337
|
function MyExtension() {
|
|
178
|
-
const loadExtension = useHostAction(
|
|
338
|
+
const loadExtension = useHostAction(FRONTX_ACTION_LOAD_EXT);
|
|
179
339
|
|
|
180
340
|
const handleClick = () => {
|
|
181
|
-
loadExtension({
|
|
341
|
+
loadExtension({ subject: 'other' });
|
|
182
342
|
};
|
|
183
343
|
|
|
184
344
|
return <button onClick={handleClick}>Load Extension</button>;
|
|
@@ -254,7 +414,7 @@ import { MfeProvider } from '@gears-frontx/react';
|
|
|
254
414
|
|
|
255
415
|
function MfeHost() {
|
|
256
416
|
return (
|
|
257
|
-
<MfeProvider
|
|
417
|
+
<MfeProvider value={{ bridge: parentBridge, extensionId: 'home', domainId: 'screen' }}>
|
|
258
418
|
<ExtensionContainer />
|
|
259
419
|
</MfeProvider>
|
|
260
420
|
);
|
|
@@ -270,17 +430,27 @@ import { ExtensionDomainSlot } from '@gears-frontx/react';
|
|
|
270
430
|
|
|
271
431
|
function LayoutScreen() {
|
|
272
432
|
return (
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
</div>
|
|
433
|
+
<ExtensionDomainSlot
|
|
434
|
+
registry={registry}
|
|
435
|
+
domainId="screen"
|
|
436
|
+
extensionId="home"
|
|
437
|
+
loadingComponent={<Loading />}
|
|
438
|
+
/>
|
|
280
439
|
);
|
|
281
440
|
}
|
|
282
441
|
```
|
|
283
442
|
|
|
443
|
+
`ExtensionDomainSlot` is the preferred host-side renderer for screen MFEs. It
|
|
444
|
+
owns mount/unmount and loading/error UI while host bootstrap handles domain
|
|
445
|
+
registration and shared property setup before slot-driven `mount_ext`.
|
|
446
|
+
The host `QueryClient` is reused by MFE React trees through
|
|
447
|
+
`queryCacheShared()`, not by embedding a `QueryClient` on `MfeMountContext`
|
|
448
|
+
or expecting host React context inside Shadow DOM.
|
|
449
|
+
|
|
450
|
+
When the domain's `ContainerProvider` must point at the same DOM node rendered
|
|
451
|
+
by the slot, pass `containerRef` to `ExtensionDomainSlot` and share that ref
|
|
452
|
+
with `RefContainerProvider`.
|
|
453
|
+
|
|
284
454
|
#### RefContainerProvider
|
|
285
455
|
|
|
286
456
|
Provide container references for MFE mounting:
|
|
@@ -302,11 +472,14 @@ function Layout() {
|
|
|
302
472
|
|
|
303
473
|
## Key Rules
|
|
304
474
|
|
|
305
|
-
1. **Wrap with
|
|
475
|
+
1. **Wrap with FrontXProvider** - Required for all hooks to work
|
|
306
476
|
2. **Use hooks for state access** - Don't import selectors directly from @gears-frontx/framework
|
|
307
|
-
3. **
|
|
308
|
-
4. **
|
|
309
|
-
5. **
|
|
477
|
+
3. **Use endpoint descriptors for data** - `useApiQuery(service.endpoint)` for REST, `useApiStream(service.stream)` for SSE — not `queryOptions()` or manual key factories
|
|
478
|
+
4. **Service is the cache contract** - The service IS the data layer; cache keys are derived automatically
|
|
479
|
+
5. **QueryCache uses descriptors** - `queryCache.get(service.endpoint)`, not raw key arrays
|
|
480
|
+
6. **Lazy load translations** - Use `useScreenTranslations` for screen-level i18n
|
|
481
|
+
7. **Use MFE hooks for extensions** - `useMfeBridge`, `useSharedProperty`, `useHostAction`, `useDomainExtensions`
|
|
482
|
+
8. **NO Layout components here** - Layout and UI components belong in L4 (user's project via CLI scaffolding)
|
|
310
483
|
|
|
311
484
|
## Re-exports
|
|
312
485
|
|
|
@@ -323,34 +496,45 @@ This allows users to import everything from `@gears-frontx/react` without needin
|
|
|
323
496
|
## Exports
|
|
324
497
|
|
|
325
498
|
### Components
|
|
326
|
-
- `
|
|
499
|
+
- `FrontXProvider` - Main context provider
|
|
327
500
|
- `MfeProvider` - MFE context provider
|
|
328
501
|
- `ExtensionDomainSlot` - Domain slot renderer
|
|
329
502
|
- `RefContainerProvider` - Container reference provider
|
|
330
503
|
|
|
331
504
|
### Hooks
|
|
332
|
-
- `
|
|
505
|
+
- `useFrontX` - Access app instance
|
|
333
506
|
- `useAppDispatch` - Typed dispatch
|
|
334
507
|
- `useAppSelector` - Typed selector
|
|
508
|
+
- `useApiQuery` - Declarative data fetch from endpoint descriptor; returns `ApiQueryResult<TData>`
|
|
509
|
+
- `useApiMutation` - Declarative mutation with endpoint descriptor and optimistic update support; returns `ApiMutationResult<TData>`
|
|
510
|
+
- `useApiStream` - Declarative SSE streaming from stream descriptor; returns `ApiStreamResult<TEvent>`
|
|
511
|
+
- `useQueryCache` - Restricted query cache access (accepts descriptors or raw keys)
|
|
335
512
|
- `useTranslation` - Translation utilities
|
|
336
513
|
- `useScreenTranslations` - Screen translation loading
|
|
337
514
|
- `useTheme` - Theme utilities
|
|
338
515
|
- `useMfeBridge` - Access MFE bridge
|
|
339
|
-
- `useSharedProperty` - Subscribe to shared property
|
|
516
|
+
- `useSharedProperty` - Subscribe to shared property, via `MfeContext` or an explicit bridge
|
|
340
517
|
- `useHostAction` - Invoke host action
|
|
341
518
|
- `useDomainExtensions` - Subscribe to domain extensions
|
|
342
519
|
- `useRegisteredPackages` - Subscribe to registered GTS packages
|
|
343
520
|
- `useActivePackage` - Subscribe to active GTS package
|
|
344
521
|
|
|
345
522
|
### Context
|
|
346
|
-
- `
|
|
523
|
+
- `FrontXContext` - React context (for advanced use)
|
|
347
524
|
- `MfeContext` - MFE context (for advanced use)
|
|
348
525
|
|
|
349
526
|
### Types
|
|
350
|
-
- `
|
|
527
|
+
- `FrontXProviderProps`
|
|
528
|
+
- `ApiQueryResult<TData>` - Gears FrontX-owned query result type (data, error, isLoading, refetch, etc.)
|
|
529
|
+
- `ApiMutationResult<TData>` - Gears FrontX-owned mutation result type (mutateAsync, isPending, error, reset, etc.)
|
|
530
|
+
- `ApiStreamResult<TEvent>` - Gears FrontX-owned stream result type (data, events, status, error, disconnect)
|
|
531
|
+
- `ApiStreamOptions` - Stream hook options (mode, enabled)
|
|
532
|
+
- `QueryCache` - Restricted cache interface (accepts descriptors or raw keys)
|
|
533
|
+
- `MutationCallbackContext` - Context with queryCache injected into mutation callbacks
|
|
351
534
|
- `MfeProviderProps`, `ExtensionDomainSlotProps`
|
|
535
|
+
- `UseSharedPropertyOptions<T>` - Options for `useSharedProperty` (bridge, fallback)
|
|
352
536
|
- `UseTranslationReturn`, `UseThemeReturn`
|
|
353
|
-
- All types from @gears-frontx/framework
|
|
537
|
+
- All types from @gears-frontx/framework (including `EndpointDescriptor`, `MutationDescriptor`, `StreamDescriptor`, `StreamStatus`)
|
|
354
538
|
|
|
355
539
|
## Migration from Legacy API
|
|
356
540
|
|
|
@@ -378,19 +562,17 @@ function MyComponent() {
|
|
|
378
562
|
|
|
379
563
|
**NEW**: Mount extension using app actions
|
|
380
564
|
```tsx
|
|
381
|
-
import {
|
|
565
|
+
import { useFrontX } from '@gears-frontx/react';
|
|
382
566
|
|
|
383
567
|
function MyComponent() {
|
|
384
|
-
const app =
|
|
568
|
+
const app = useFrontX();
|
|
385
569
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
386
570
|
|
|
387
|
-
const handleNavigate =
|
|
571
|
+
const handleNavigate = () => {
|
|
388
572
|
if (containerRef.current) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
container: containerRef.current,
|
|
393
|
-
});
|
|
573
|
+
// Fire-and-forget: dispatches an actions chain through the
|
|
574
|
+
// acceptance-only registry surface and returns nothing to await.
|
|
575
|
+
app.actions.mountExtension('home');
|
|
394
576
|
}
|
|
395
577
|
};
|
|
396
578
|
|
|
@@ -403,16 +585,17 @@ function MyComponent() {
|
|
|
403
585
|
}
|
|
404
586
|
```
|
|
405
587
|
|
|
406
|
-
**NEW (
|
|
588
|
+
**NEW (Preferred for host screen slots)**: Use ExtensionDomainSlot
|
|
407
589
|
```tsx
|
|
408
590
|
import { ExtensionDomainSlot } from '@gears-frontx/react';
|
|
409
591
|
|
|
410
592
|
function MyComponent() {
|
|
411
593
|
return (
|
|
412
594
|
<ExtensionDomainSlot
|
|
595
|
+
registry={app.mfeRegistry}
|
|
413
596
|
domainId="screen"
|
|
414
|
-
|
|
415
|
-
|
|
597
|
+
extensionId="home"
|
|
598
|
+
loadingComponent={<Loading />}
|
|
416
599
|
/>
|
|
417
600
|
);
|
|
418
601
|
}
|