@gears-frontx/react 0.1.0 → 0.2.0-alpha.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/CLAUDE.md +171 -45
- package/commands/{hai3-duplicate-screenset.md → frontx-duplicate-screenset.md} +3 -3
- package/commands/{hai3-new-component.md → frontx-new-component.md} +14 -5
- package/commands/{hai3-new-mfe.md → frontx-new-mfe.md} +8 -21
- package/commands/{hai3-new-screen.md → frontx-new-screen.md} +12 -6
- package/commands/frontx-new-screenset.md +57 -0
- package/dist/index.cjs +1110 -387
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +360 -118
- package/dist/index.d.ts +360 -118
- package/dist/index.js +956 -237
- 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 +74 -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 +51 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-Cjd20AT-.d.cts +231 -0
- package/dist/types-Cjd20AT-.d.ts +231 -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 +20 -20
- package/package.json +28 -16
- 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,44 +8,146 @@ 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
|
+
### Gears FrontXProvider
|
|
12
12
|
|
|
13
|
-
Wrap your app with
|
|
13
|
+
Wrap your app with Gears FrontXProvider to enable all hooks:
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
|
-
import {
|
|
16
|
+
import { Gears FrontXProvider } from '@gears-frontx/react';
|
|
17
17
|
|
|
18
18
|
function App() {
|
|
19
19
|
return (
|
|
20
|
-
<
|
|
20
|
+
<Gears FrontXProvider>
|
|
21
21
|
<YourApp />
|
|
22
|
-
</
|
|
22
|
+
</Gears FrontXProvider>
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// With configuration
|
|
27
|
-
<
|
|
27
|
+
<Gears FrontXProvider config={{ devMode: true }}>
|
|
28
28
|
<YourApp />
|
|
29
|
-
</
|
|
29
|
+
</Gears FrontXProvider>
|
|
30
30
|
|
|
31
|
-
// With pre-built app
|
|
32
|
-
const app =
|
|
33
|
-
<
|
|
31
|
+
// With pre-built app (host-style shell; host typically also uses queryCache() — see REACT.md)
|
|
32
|
+
const app = createGears FrontX().use(screensets()).build();
|
|
33
|
+
<Gears FrontXProvider app={app}>
|
|
34
34
|
<YourApp />
|
|
35
|
-
</
|
|
35
|
+
</Gears FrontXProvider>
|
|
36
|
+
|
|
37
|
+
// Child MFE app — canonical bootstrap matches src/mfe_packages/*/init.ts and .ai/targets/SCREENSETS.md:
|
|
38
|
+
// apiRegistry.register / initialize before .build; createGears FrontX().use(effects()).use(queryCacheShared()).use(mock()).build();
|
|
39
|
+
// registerSlice after .build when slices exist.
|
|
40
|
+
const mfeApp = createGears FrontX().use(effects()).use(queryCacheShared()).use(mock()).build();
|
|
41
|
+
<Gears FrontXProvider app={mfeApp}>
|
|
42
|
+
<YourApp />
|
|
43
|
+
</Gears FrontXProvider>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The shared `QueryClient` is created and owned by the `queryCache()` framework plugin at L2.
|
|
47
|
+
`Gears FrontXProvider` resolves that client from the app instance — it does not create its own `QueryClient`.
|
|
48
|
+
|
|
49
|
+
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 now fails explicitly instead of silently falling back.
|
|
50
|
+
|
|
51
|
+
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. MFE package ordering and forbidden bootstrap pieces are defined in SCREENSETS.md. Host apps should register domains/extensions during bootstrap; **`ExtensionDomainSlot`** is the preferred host-side renderer for screen slots while the framework wires `mount_ext`.
|
|
52
|
+
|
|
53
|
+
### Data Fetching with Endpoint Descriptors
|
|
54
|
+
|
|
55
|
+
Services define endpoints as descriptors. Components consume them via `useApiQuery` and `useApiMutation`. No manual query keys, no `queryOptions()` calls.
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { useApiQuery, useApiMutation, apiRegistry } from '@gears-frontx/react';
|
|
59
|
+
import { AccountsApiService } from '../api/AccountsApiService';
|
|
60
|
+
|
|
61
|
+
function ProfileScreen() {
|
|
62
|
+
const service = apiRegistry.getService(AccountsApiService);
|
|
63
|
+
|
|
64
|
+
// Read — pass descriptor directly
|
|
65
|
+
const { data, isLoading, error } = useApiQuery(service.getCurrentUser);
|
|
66
|
+
|
|
67
|
+
// Read with params
|
|
68
|
+
const { data: user } = useApiQuery(service.getUser({ id: '123' }));
|
|
69
|
+
|
|
70
|
+
// Write with optimistic update
|
|
71
|
+
const { mutateAsync, isPending } = useApiMutation({
|
|
72
|
+
endpoint: service.updateProfile,
|
|
73
|
+
onMutate: async (variables, { queryCache }) => {
|
|
74
|
+
await queryCache.cancel(service.getCurrentUser);
|
|
75
|
+
const snapshot = queryCache.get(service.getCurrentUser);
|
|
76
|
+
queryCache.set(service.getCurrentUser, (old) => ({
|
|
77
|
+
...old, user: { ...old.user, ...variables }
|
|
78
|
+
}));
|
|
79
|
+
return { snapshot };
|
|
80
|
+
},
|
|
81
|
+
onError: (_err, _vars, context, { queryCache }) => {
|
|
82
|
+
if (context?.snapshot) {
|
|
83
|
+
queryCache.set(service.getCurrentUser, context.snapshot);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
onSettled: async (_data, _err, _vars, _ctx, { queryCache }) => {
|
|
87
|
+
await queryCache.invalidate(service.getCurrentUser);
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Per-endpoint cache override (rare)
|
|
92
|
+
const { data: config } = useApiQuery(service.getConfig, { staleTime: 0 });
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Cache keys are derived automatically by the service — `QueryCache` methods accept
|
|
97
|
+
endpoint descriptors directly (e.g., `queryCache.get(service.getCurrentUser)`).
|
|
98
|
+
|
|
99
|
+
### SSE Streaming with Stream Descriptors
|
|
100
|
+
|
|
101
|
+
Services declare SSE endpoints as stream descriptors. Components consume them via `useApiStream`, which manages the EventSource lifecycle automatically (connect on mount, disconnect on unmount).
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { useApiStream, apiRegistry } from '@gears-frontx/react';
|
|
105
|
+
import { ChatApiService } from '../api/ChatApiService';
|
|
106
|
+
|
|
107
|
+
function ChatStream() {
|
|
108
|
+
const service = apiRegistry.getService(ChatApiService);
|
|
109
|
+
|
|
110
|
+
// Latest event only (default mode)
|
|
111
|
+
const { data, status, error } = useApiStream(service.messageStream);
|
|
112
|
+
|
|
113
|
+
// Accumulate all events
|
|
114
|
+
const { events, status: streamStatus } = useApiStream(
|
|
115
|
+
service.messageStream,
|
|
116
|
+
{ mode: 'accumulate' }
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Deferred connection (enabled: false)
|
|
120
|
+
const [active, setActive] = useState(false);
|
|
121
|
+
const { data: msg, disconnect } = useApiStream(
|
|
122
|
+
service.messageStream,
|
|
123
|
+
{ enabled: active }
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
if (status === 'connecting') return <Loading />;
|
|
127
|
+
if (error) return <Error error={error} />;
|
|
128
|
+
|
|
129
|
+
return <div>{data?.text}</div>;
|
|
130
|
+
}
|
|
36
131
|
```
|
|
37
132
|
|
|
133
|
+
`useApiStream` returns `{ data, events, status, error, disconnect }`:
|
|
134
|
+
- `data` — latest event payload (always set in both modes)
|
|
135
|
+
- `events` — all received events when `mode: 'accumulate'`; empty array in `'latest'` mode
|
|
136
|
+
- `status` — `'idle' | 'connecting' | 'connected' | 'disconnected' | 'error'`
|
|
137
|
+
- `error` — connection error if any
|
|
138
|
+
- `disconnect()` — manually close the connection
|
|
139
|
+
|
|
38
140
|
### Available Hooks
|
|
39
141
|
|
|
40
|
-
####
|
|
142
|
+
#### useFrontX
|
|
41
143
|
|
|
42
|
-
Access the
|
|
144
|
+
Access the FrontX app instance:
|
|
43
145
|
|
|
44
146
|
```tsx
|
|
45
|
-
import {
|
|
147
|
+
import { useFrontX } from '@gears-frontx/react';
|
|
46
148
|
|
|
47
149
|
function MyComponent() {
|
|
48
|
-
const app =
|
|
150
|
+
const app = useFrontX();
|
|
49
151
|
|
|
50
152
|
// Access MFE-enabled registry
|
|
51
153
|
const extensions = app.screensetsRegistry.getRegisteredExtensions();
|
|
@@ -138,18 +240,18 @@ Access the MFE bridge for child MFEs:
|
|
|
138
240
|
|
|
139
241
|
```tsx
|
|
140
242
|
import { useMfeBridge } from '@gears-frontx/react';
|
|
141
|
-
import {
|
|
243
|
+
import { Gears FrontX_ACTION_LOAD_EXT, Gears FrontX_SHARED_PROPERTY_THEME } from '@gears-frontx/react';
|
|
142
244
|
|
|
143
245
|
function MyExtension() {
|
|
144
246
|
const bridge = useMfeBridge();
|
|
145
247
|
|
|
146
248
|
// Execute actions chain on parent
|
|
147
249
|
await bridge.executeActionsChain({
|
|
148
|
-
action: { type:
|
|
250
|
+
action: { type: Gears FrontX_ACTION_LOAD_EXT, target: 'screen', payload: { extensionId: 'other' } }
|
|
149
251
|
});
|
|
150
252
|
|
|
151
253
|
// Get shared property
|
|
152
|
-
const theme = bridge.getProperty(
|
|
254
|
+
const theme = bridge.getProperty(Gears FrontX_SHARED_PROPERTY_THEME);
|
|
153
255
|
}
|
|
154
256
|
```
|
|
155
257
|
|
|
@@ -158,10 +260,10 @@ function MyExtension() {
|
|
|
158
260
|
Subscribe to shared property changes:
|
|
159
261
|
|
|
160
262
|
```tsx
|
|
161
|
-
import { useSharedProperty,
|
|
263
|
+
import { useSharedProperty, Gears FrontX_SHARED_PROPERTY_THEME } from '@gears-frontx/react';
|
|
162
264
|
|
|
163
265
|
function ThemedComponent() {
|
|
164
|
-
const theme = useSharedProperty(
|
|
266
|
+
const theme = useSharedProperty(Gears FrontX_SHARED_PROPERTY_THEME);
|
|
165
267
|
|
|
166
268
|
return <div style={{ backgroundColor: theme?.primaryColor }}>...</div>;
|
|
167
269
|
}
|
|
@@ -172,10 +274,10 @@ function ThemedComponent() {
|
|
|
172
274
|
Invoke actions on the host application:
|
|
173
275
|
|
|
174
276
|
```tsx
|
|
175
|
-
import { useHostAction,
|
|
277
|
+
import { useHostAction, Gears FrontX_ACTION_LOAD_EXT } from '@gears-frontx/react';
|
|
176
278
|
|
|
177
279
|
function MyExtension() {
|
|
178
|
-
const loadExtension = useHostAction(
|
|
280
|
+
const loadExtension = useHostAction(Gears FrontX_ACTION_LOAD_EXT);
|
|
179
281
|
|
|
180
282
|
const handleClick = () => {
|
|
181
283
|
loadExtension({ extensionId: 'other' });
|
|
@@ -254,7 +356,7 @@ import { MfeProvider } from '@gears-frontx/react';
|
|
|
254
356
|
|
|
255
357
|
function MfeHost() {
|
|
256
358
|
return (
|
|
257
|
-
<MfeProvider
|
|
359
|
+
<MfeProvider value={{ bridge: parentBridge, extensionId: 'home', domainId: 'screen' }}>
|
|
258
360
|
<ExtensionContainer />
|
|
259
361
|
</MfeProvider>
|
|
260
362
|
);
|
|
@@ -270,17 +372,27 @@ import { ExtensionDomainSlot } from '@gears-frontx/react';
|
|
|
270
372
|
|
|
271
373
|
function LayoutScreen() {
|
|
272
374
|
return (
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
</div>
|
|
375
|
+
<ExtensionDomainSlot
|
|
376
|
+
registry={registry}
|
|
377
|
+
domainId="screen"
|
|
378
|
+
extensionId="home"
|
|
379
|
+
loadingComponent={<Loading />}
|
|
380
|
+
/>
|
|
280
381
|
);
|
|
281
382
|
}
|
|
282
383
|
```
|
|
283
384
|
|
|
385
|
+
`ExtensionDomainSlot` is the preferred host-side renderer for screen MFEs. It
|
|
386
|
+
owns mount/unmount and loading/error UI while host bootstrap handles domain
|
|
387
|
+
registration and shared property setup before slot-driven `mount_ext`.
|
|
388
|
+
The host `QueryClient` is reused by MFE React trees through
|
|
389
|
+
`queryCacheShared()`, not by embedding a `QueryClient` on `MfeMountContext`
|
|
390
|
+
or expecting host React context inside Shadow DOM.
|
|
391
|
+
|
|
392
|
+
When the domain's `ContainerProvider` must point at the same DOM node rendered
|
|
393
|
+
by the slot, pass `containerRef` to `ExtensionDomainSlot` and share that ref
|
|
394
|
+
with `RefContainerProvider`.
|
|
395
|
+
|
|
284
396
|
#### RefContainerProvider
|
|
285
397
|
|
|
286
398
|
Provide container references for MFE mounting:
|
|
@@ -302,11 +414,14 @@ function Layout() {
|
|
|
302
414
|
|
|
303
415
|
## Key Rules
|
|
304
416
|
|
|
305
|
-
1. **Wrap with
|
|
417
|
+
1. **Wrap with Gears FrontXProvider** - Required for all hooks to work
|
|
306
418
|
2. **Use hooks for state access** - Don't import selectors directly from @gears-frontx/framework
|
|
307
|
-
3. **
|
|
308
|
-
4. **
|
|
309
|
-
5. **
|
|
419
|
+
3. **Use endpoint descriptors for data** - `useApiQuery(service.endpoint)` for REST, `useApiStream(service.stream)` for SSE — not `queryOptions()` or manual key factories
|
|
420
|
+
4. **Service is the cache contract** - The service IS the data layer; cache keys are derived automatically
|
|
421
|
+
5. **QueryCache uses descriptors** - `queryCache.get(service.endpoint)`, not raw key arrays
|
|
422
|
+
6. **Lazy load translations** - Use `useScreenTranslations` for screen-level i18n
|
|
423
|
+
7. **Use MFE hooks for extensions** - `useMfeBridge`, `useSharedProperty`, `useHostAction`, `useDomainExtensions`
|
|
424
|
+
8. **NO Layout components here** - Layout and UI components belong in L4 (user's project via CLI scaffolding)
|
|
310
425
|
|
|
311
426
|
## Re-exports
|
|
312
427
|
|
|
@@ -323,15 +438,19 @@ This allows users to import everything from `@gears-frontx/react` without needin
|
|
|
323
438
|
## Exports
|
|
324
439
|
|
|
325
440
|
### Components
|
|
326
|
-
- `
|
|
441
|
+
- `Gears FrontXProvider` - Main context provider
|
|
327
442
|
- `MfeProvider` - MFE context provider
|
|
328
443
|
- `ExtensionDomainSlot` - Domain slot renderer
|
|
329
444
|
- `RefContainerProvider` - Container reference provider
|
|
330
445
|
|
|
331
446
|
### Hooks
|
|
332
|
-
- `
|
|
447
|
+
- `useFrontX` - Access app instance
|
|
333
448
|
- `useAppDispatch` - Typed dispatch
|
|
334
449
|
- `useAppSelector` - Typed selector
|
|
450
|
+
- `useApiQuery` - Declarative data fetch from endpoint descriptor; returns `ApiQueryResult<TData>`
|
|
451
|
+
- `useApiMutation` - Declarative mutation with endpoint descriptor and optimistic update support; returns `ApiMutationResult<TData>`
|
|
452
|
+
- `useApiStream` - Declarative SSE streaming from stream descriptor; returns `ApiStreamResult<TEvent>`
|
|
453
|
+
- `useQueryCache` - Restricted query cache access (accepts descriptors or raw keys)
|
|
335
454
|
- `useTranslation` - Translation utilities
|
|
336
455
|
- `useScreenTranslations` - Screen translation loading
|
|
337
456
|
- `useTheme` - Theme utilities
|
|
@@ -343,14 +462,20 @@ This allows users to import everything from `@gears-frontx/react` without needin
|
|
|
343
462
|
- `useActivePackage` - Subscribe to active GTS package
|
|
344
463
|
|
|
345
464
|
### Context
|
|
346
|
-
- `
|
|
465
|
+
- `Gears FrontXContext` - React context (for advanced use)
|
|
347
466
|
- `MfeContext` - MFE context (for advanced use)
|
|
348
467
|
|
|
349
468
|
### Types
|
|
350
|
-
- `
|
|
469
|
+
- `Gears FrontXProviderProps`
|
|
470
|
+
- `ApiQueryResult<TData>` - Gears FrontX-owned query result type (data, error, isLoading, refetch, etc.)
|
|
471
|
+
- `ApiMutationResult<TData>` - Gears FrontX-owned mutation result type (mutateAsync, isPending, error, reset, etc.)
|
|
472
|
+
- `ApiStreamResult<TEvent>` - Gears FrontX-owned stream result type (data, events, status, error, disconnect)
|
|
473
|
+
- `ApiStreamOptions` - Stream hook options (mode, enabled)
|
|
474
|
+
- `QueryCache` - Restricted cache interface (accepts descriptors or raw keys)
|
|
475
|
+
- `MutationCallbackContext` - Context with queryCache injected into mutation callbacks
|
|
351
476
|
- `MfeProviderProps`, `ExtensionDomainSlotProps`
|
|
352
477
|
- `UseTranslationReturn`, `UseThemeReturn`
|
|
353
|
-
- All types from @gears-frontx/framework
|
|
478
|
+
- All types from @gears-frontx/framework (including `EndpointDescriptor`, `MutationDescriptor`, `StreamDescriptor`, `StreamStatus`)
|
|
354
479
|
|
|
355
480
|
## Migration from Legacy API
|
|
356
481
|
|
|
@@ -378,10 +503,10 @@ function MyComponent() {
|
|
|
378
503
|
|
|
379
504
|
**NEW**: Mount extension using app actions
|
|
380
505
|
```tsx
|
|
381
|
-
import {
|
|
506
|
+
import { useFrontX } from '@gears-frontx/react';
|
|
382
507
|
|
|
383
508
|
function MyComponent() {
|
|
384
|
-
const app =
|
|
509
|
+
const app = useFrontX();
|
|
385
510
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
386
511
|
|
|
387
512
|
const handleNavigate = async () => {
|
|
@@ -403,16 +528,17 @@ function MyComponent() {
|
|
|
403
528
|
}
|
|
404
529
|
```
|
|
405
530
|
|
|
406
|
-
**NEW (
|
|
531
|
+
**NEW (Preferred for host screen slots)**: Use ExtensionDomainSlot
|
|
407
532
|
```tsx
|
|
408
533
|
import { ExtensionDomainSlot } from '@gears-frontx/react';
|
|
409
534
|
|
|
410
535
|
function MyComponent() {
|
|
411
536
|
return (
|
|
412
537
|
<ExtensionDomainSlot
|
|
538
|
+
registry={app.screensetsRegistry}
|
|
413
539
|
domainId="screen"
|
|
414
|
-
|
|
415
|
-
|
|
540
|
+
extensionId="home"
|
|
541
|
+
loadingComponent={<Loading />}
|
|
416
542
|
/>
|
|
417
543
|
);
|
|
418
544
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- @standalone -->
|
|
2
|
-
#
|
|
2
|
+
# frontx:duplicate-screenset - Duplicate Screenset
|
|
3
3
|
|
|
4
4
|
## AI WORKFLOW (REQUIRED)
|
|
5
5
|
1) Read .ai/targets/SCREENSETS.md before starting.
|
|
@@ -18,7 +18,7 @@ Ask user for:
|
|
|
18
18
|
|
|
19
19
|
## STEP 1: Copy Screenset via CLI
|
|
20
20
|
```bash
|
|
21
|
-
|
|
21
|
+
frontx screenset copy SOURCE TARGET --category={category}
|
|
22
22
|
```
|
|
23
23
|
The CLI automatically:
|
|
24
24
|
- Copies all files (screens, slices, actions, events, effects, API, icons, i18n).
|
|
@@ -50,7 +50,7 @@ STOP: If MCP connection is broken, fix it first. NEVER skip testing.
|
|
|
50
50
|
|
|
51
51
|
## CHECKLIST
|
|
52
52
|
- [ ] Gather requirements (source, target name, category).
|
|
53
|
-
- [ ] Run `
|
|
53
|
+
- [ ] Run `frontx screenset copy SOURCE TARGET --category={category}`.
|
|
54
54
|
- [ ] Run type-check (MUST pass).
|
|
55
55
|
- [ ] Run arch:check (MUST pass).
|
|
56
56
|
- [ ] Run lint (MUST pass).
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<!-- @standalone -->
|
|
2
|
-
#
|
|
2
|
+
# frontx:new-component - Add New UI Component
|
|
3
3
|
|
|
4
4
|
## AI WORKFLOW (REQUIRED)
|
|
5
|
-
1)
|
|
6
|
-
2)
|
|
7
|
-
3)
|
|
5
|
+
1) Read `.ai/project/GUIDELINES.md` and `.ai/project/targets/UNIT_TESTING.md` when they exist **before** any unit-test, validation, or testing steps in this command (project-owned overrides take precedence over defaults here).
|
|
6
|
+
2) Check for existing equivalent in project (e.g. components/ui/) and configured UI library first.
|
|
7
|
+
3) Gather requirements from user.
|
|
8
|
+
4) Implement.
|
|
8
9
|
|
|
9
10
|
## CHECK EXISTING COMPONENTS FIRST
|
|
10
11
|
- REQUIRED: Read `frontx.config.json` to find the `uikit` value.
|
|
@@ -38,11 +39,19 @@ File: src/components/ui/{ComponentName}.tsx (base primitives)
|
|
|
38
39
|
Export from local index if needed.
|
|
39
40
|
|
|
40
41
|
#### 1.3 Validation
|
|
41
|
-
|
|
42
|
+
<!-- @cpt-begin:cpt-frontx-flow-unit-test-generation-and-agent-verification-agent-verify:p1:inst-agent-implement-and-test -->
|
|
43
|
+
If creating a shared composite in `src/components/`, add or update a component test for its stable behavior.
|
|
44
|
+
Run `npm run test:unit`, `npm run type-check`, `npm run arch:check`, and `npm run dev` (or the equivalent commands for this project's configured package manager) and apply any stricter triggers or conventions from `.ai/project/targets/UNIT_TESTING.md`. Apply constraints from workflow step 1.
|
|
45
|
+
<!-- @cpt-end:cpt-frontx-flow-unit-test-generation-and-agent-verification-agent-verify:p1:inst-agent-implement-and-test -->
|
|
42
46
|
Test component in UI.
|
|
43
47
|
|
|
48
|
+
## TESTING
|
|
49
|
+
- REQUIRED: Load `.ai/project/GUIDELINES.md` and `.ai/project/targets/UNIT_TESTING.md` when they exist **before** interpreting unit-test requirements elsewhere in this command.
|
|
50
|
+
- REQUIRED: Follow `.ai/project/targets/UNIT_TESTING.md` for `__test-utils__/` placement and durable, non-placeholder assertions when adding or updating tests.
|
|
51
|
+
|
|
44
52
|
## RULES
|
|
45
53
|
- REQUIRED: Check existing project UI components first; create new only if missing.
|
|
46
54
|
- FORBIDDEN: Redux, business logic, side effects in components.
|
|
47
55
|
- FORBIDDEN: Inline styles outside components/ui/.
|
|
48
56
|
- REQUIRED: Accept value/onChange pattern for state.
|
|
57
|
+
- REQUIRED: New shared composite components in `src/components/` include a colocated or nearby unit test when the behavior is stable.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<!-- @standalone -->
|
|
2
|
-
#
|
|
2
|
+
# frontx:new-mfe - Create New Microfrontend Package
|
|
3
3
|
|
|
4
4
|
## PREREQUISITES (CRITICAL - STOP IF FAILED)
|
|
5
5
|
|
|
6
6
|
1. MFE must be associated with a screenset
|
|
7
|
-
2. Screenset must exist (run `
|
|
7
|
+
2. Screenset must exist (run `frontx-new-screenset` first if needed)
|
|
8
8
|
3. Vite and Module Federation must be configured
|
|
9
9
|
|
|
10
10
|
## QUICK START
|
|
@@ -61,30 +61,17 @@ Create `src/lifecycle.tsx`:
|
|
|
61
61
|
```typescript
|
|
62
62
|
import React from 'react';
|
|
63
63
|
import type { ChildMfeBridge } from '@gears-frontx/react';
|
|
64
|
-
import { ThemeAwareReactLifecycle } from '@gears-frontx/
|
|
64
|
+
import { ThemeAwareReactLifecycle } from '@gears-frontx/react';
|
|
65
|
+
import { mfeApp } from './init';
|
|
65
66
|
import { YourScreen } from './screens/YourScreen';
|
|
66
67
|
|
|
67
68
|
class Lifecycle extends ThemeAwareReactLifecycle {
|
|
68
69
|
constructor() {
|
|
69
|
-
super(
|
|
70
|
-
name: '{screensetName}',
|
|
71
|
-
version: '1.0.0',
|
|
72
|
-
});
|
|
70
|
+
super(mfeApp);
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
shadowRoot.appendChild(div);
|
|
78
|
-
|
|
79
|
-
const style = document.createElement('style');
|
|
80
|
-
style.textContent = tailwindStyles;
|
|
81
|
-
shadowRoot.appendChild(style);
|
|
82
|
-
|
|
83
|
-
// Render component
|
|
84
|
-
const root = ReactDOM.createRoot(div);
|
|
85
|
-
root.render(<YourScreen bridge={bridge} />);
|
|
86
|
-
|
|
87
|
-
return { root, div };
|
|
73
|
+
protected renderContent(bridge: ChildMfeBridge): React.ReactNode {
|
|
74
|
+
return <YourScreen bridge={bridge} />;
|
|
88
75
|
}
|
|
89
76
|
}
|
|
90
77
|
|
|
@@ -163,4 +150,4 @@ npm run dev:all
|
|
|
163
150
|
|
|
164
151
|
See also:
|
|
165
152
|
- `/packages/cli/template-sources/mfe-package/` for templates
|
|
166
|
-
- `
|
|
153
|
+
- `frontx-new-screenset.md` for screenset creation
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<!-- @standalone -->
|
|
2
|
-
#
|
|
2
|
+
# frontx:new-screen - Add New Screen
|
|
3
3
|
|
|
4
4
|
## AI WORKFLOW (REQUIRED)
|
|
5
5
|
1) Read .ai/targets/SCREENSETS.md and .ai/targets/EVENTS.md before starting.
|
|
6
|
-
2)
|
|
7
|
-
3)
|
|
6
|
+
2) Read `.ai/project/GUIDELINES.md` and `.ai/project/targets/UNIT_TESTING.md` when they exist **before** planning unit tests, validation, or any test-related tasks in this command (project-owned overrides take precedence over defaults here).
|
|
7
|
+
3) Gather requirements from user (including UI sections).
|
|
8
|
+
4) Implement.
|
|
8
9
|
|
|
9
10
|
## GATHER REQUIREMENTS
|
|
10
11
|
Ask user for:
|
|
@@ -20,15 +21,20 @@ Ask user for:
|
|
|
20
21
|
- Use actions to trigger state changes
|
|
21
22
|
- FORBIDDEN: Direct slice dispatch from screen
|
|
22
23
|
4) Add i18n with useScreenTranslations(). Export default.
|
|
23
|
-
5) Add
|
|
24
|
-
6)
|
|
25
|
-
7)
|
|
24
|
+
5) Add or update a screen test that covers stable render or behavior for the new screen and place any test-only helpers in a sibling `__test-utils__/` folder.
|
|
25
|
+
6) Add to menu if requested.
|
|
26
|
+
7) Validate: run `test:unit`, `type-check`, and `arch:check` via this project's package manager per `.ai/project/targets/UNIT_TESTING.md` (which defines the exact commands). Apply constraints from workflow step 2.
|
|
27
|
+
8) Test via Chrome DevTools MCP (REQUIRED):
|
|
26
28
|
- Navigate to new screen
|
|
27
29
|
- Verify screen renders without console errors
|
|
28
30
|
- Test UI interactions and data flow
|
|
29
31
|
- Verify translations load correctly
|
|
30
32
|
- STOP if MCP connection fails
|
|
31
33
|
|
|
34
|
+
## TESTING
|
|
35
|
+
- REQUIRED: Load `.ai/project/GUIDELINES.md` and `.ai/project/targets/UNIT_TESTING.md` when they exist **before** interpreting unit-test requirements elsewhere in this command.
|
|
36
|
+
- REQUIRED: Use neutral fixtures, translation mocks, and stable keys, roles, or IDs instead of placeholder-derived copy when adding or updating generated screen tests.
|
|
37
|
+
|
|
32
38
|
## COMPONENT PLAN
|
|
33
39
|
- REQUIRED: Use local components (e.g. `components/ui/`) — no shared UI kit package.
|
|
34
40
|
- components/ui/: base UI primitives (shadcn components or custom)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!-- @standalone -->
|
|
2
|
+
# frontx:new-screenset - Create New Screenset
|
|
3
|
+
|
|
4
|
+
## PREREQUISITES (CRITICAL - STOP IF FAILED)
|
|
5
|
+
Run `frontx --version`.
|
|
6
|
+
STOP: If fails, tell user to install.
|
|
7
|
+
FORBIDDEN: Creating screenset manually or by copying peers.
|
|
8
|
+
|
|
9
|
+
## AI WORKFLOW (REQUIRED)
|
|
10
|
+
1) Check prerequisites above.
|
|
11
|
+
2) Read .ai/targets/SCREENSETS.md and .ai/targets/EVENTS.md before starting.
|
|
12
|
+
3) Read `.ai/project/GUIDELINES.md` and `.ai/project/targets/UNIT_TESTING.md` when they exist **before** planning unit tests, validation, or any test-related tasks in this command (project-owned overrides take precedence over defaults here).
|
|
13
|
+
4) Gather requirements from user (including UI sections).
|
|
14
|
+
5) Implement.
|
|
15
|
+
|
|
16
|
+
## GATHER REQUIREMENTS
|
|
17
|
+
Ask user for:
|
|
18
|
+
- Screenset name (camelCase).
|
|
19
|
+
- Category: Drafts | Mockups | Production.
|
|
20
|
+
- Initial screens.
|
|
21
|
+
- UI sections per screen (e.g., "stats cards, charts, activity feed").
|
|
22
|
+
|
|
23
|
+
## STEP 1: Implementation
|
|
24
|
+
1) Create screenset via `frontx screenset create` (REQUIRED).
|
|
25
|
+
2) Create components BEFORE screen file per Component Plan.
|
|
26
|
+
3) Implement data flow per .ai/targets/EVENTS.md:
|
|
27
|
+
- Actions emit events via eventBus.emit()
|
|
28
|
+
- Effects subscribe and update slices
|
|
29
|
+
- FORBIDDEN: Direct slice dispatch from components
|
|
30
|
+
4) Add API service with mocks and endpoint descriptors:
|
|
31
|
+
- Read endpoints: `readonly prop = this.protocol(RestEndpointProtocol).query<T>('/path')`
|
|
32
|
+
- Write endpoints: `readonly prop = this.protocol(RestEndpointProtocol).mutation<T, V>('PUT', '/path')`
|
|
33
|
+
- NO queryOptions, NO manual query key factories outside the service
|
|
34
|
+
- Screens use `useApiQuery(service.prop)` and `useApiMutation({ endpoint: service.prop })`
|
|
35
|
+
5) Add or update starter unit tests for stable generated behavior.
|
|
36
|
+
6) Validate: run `test:unit`, `type-check`, `arch:check`, and `lint` via this project's package manager per `.ai/project/targets/UNIT_TESTING.md` (which defines the exact commands). Apply constraints from workflow step 3.
|
|
37
|
+
7) Test via Chrome DevTools MCP (REQUIRED):
|
|
38
|
+
- Navigate to new screenset
|
|
39
|
+
- Verify screen renders without console errors
|
|
40
|
+
- Test user interactions trigger correct events
|
|
41
|
+
- Verify state updates via Redux DevTools
|
|
42
|
+
- STOP if MCP connection fails
|
|
43
|
+
|
|
44
|
+
## COMPONENT PLAN
|
|
45
|
+
- REQUIRED: Use local components (e.g. `components/ui/`) — no shared UI kit package.
|
|
46
|
+
- components/ui/: base UI primitives (shadcn components or custom)
|
|
47
|
+
- components/: multi-screen shared components
|
|
48
|
+
- screens/{screen}/components/: screen-specific components
|
|
49
|
+
|
|
50
|
+
## DATA FLOW
|
|
51
|
+
- Events: {domain events per EVENTS.md}
|
|
52
|
+
- State: slices/, events/, effects/, actions/
|
|
53
|
+
- API: api/{Name}ApiService.ts with mocks and endpoint descriptors
|
|
54
|
+
|
|
55
|
+
## TESTING
|
|
56
|
+
- REQUIRED: Load `.ai/project/GUIDELINES.md` and `.ai/project/targets/UNIT_TESTING.md` when they exist **before** interpreting unit-test requirements elsewhere in this command.
|
|
57
|
+
- REQUIRED: Preserve the generated API-contract test and `HomeScreen` smoke test unless the new behavior replaces that baseline intentionally.
|